diff --git a/CONTRIBUTING.md b/.github/CONTRIBUTING.md similarity index 100% rename from CONTRIBUTING.md rename to .github/CONTRIBUTING.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 000000000000..66b3745da986 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,30 @@ +## Steps to Reproduce + +1. +2. +3. + +## Current Behavior + +What is the current behavior? + +## Expected Behavior + +Please describe the behavior you are expecting + +### On which platforms did you notice this + +- [ ] macOS +- [ ] Linux +- [ ] Windows + +**Version Used**: + +You can use `mono --version` or About dialog to obtain this information + +### Stacktrace + +``` +Please copy paste the Stacktrace here if available +``` + diff --git a/README.md b/README.md index d5ba68624ba6..7dacb42632b3 100644 --- a/README.md +++ b/README.md @@ -224,8 +224,7 @@ section. Reporting bugs ============== -To submit bug reports, please use [Xamarin's -Bugzilla](https://bugzilla.xamarin.com/) +To submit bug reports, please [open an issue on the mono GitHub repo](https://github.com/mono/mono/issues/new). Please use the search facility to ensure the same bug hasn't already been submitted and follow our @@ -358,16 +357,6 @@ should be used. * Or you can specify a path to a libgdiplus. -* `--disable-shared-memory` - - * Use this option to disable the use of shared memory in -Mono (this is equivalent to setting the MONO_DISABLE_SHM -environment variable, although this removes the feature -completely). - - * Disabling the shared memory support will disable certain -features like cross-process named mutexes. - * `--enable-minimal=LIST` * Use this feature to specify optional runtime diff --git a/acceptance-tests/profiler-stress/runner.cs b/acceptance-tests/profiler-stress/runner.cs index e4a609b995f2..71295fc9b562 100644 --- a/acceptance-tests/profiler-stress/runner.cs +++ b/acceptance-tests/profiler-stress/runner.cs @@ -60,18 +60,16 @@ static class Program { static readonly TimeSpan _timeout = TimeSpan.FromHours (9); static readonly Dictionary> _filters = new Dictionary> { - { "ironjs-v8", FilterArmArchitecture }, + { "ironjs-v8", FilterNotOnArm }, + { "msbiology", FilterNever }, }; - static readonly Dictionary> _processors = new Dictionary> { - { "msbiology", Process32BitOutOfMemory }, - }; - - static string FilterInvalidXmlChars (string text) { - return Regex.Replace (text, @"[^\x09\x0A\x0D\x20-\uD7FF\uE000-\uFFFD\u10000-\u10FFFF]", string.Empty); + static bool FilterNever (Benchmark benchmark) + { + return false; } - static bool FilterArmArchitecture (Benchmark benchmark) + static bool FilterNotOnArm (Benchmark benchmark) { #if ARCH_arm || ARCH_arm64 return false; @@ -80,23 +78,15 @@ static bool FilterArmArchitecture (Benchmark benchmark) #endif } - static void Process32BitOutOfMemory (TestResult result) - { - if (Environment.Is64BitProcess) - return; - - if (result.ExitCode == null || result.ExitCode == 0) - return; - - if (result.StandardError.Contains ("OutOfMemoryException")) - result.ExitCode = 0; - } - static bool IsSupported (Benchmark benchmark) { return _filters.TryGetValue (benchmark.Name, out var filter) ? filter (benchmark) : true; } + static string ReplaceInvalidXmlChars (string text) { + return Regex.Replace (text, @"[^\x09\x0A\x0D\x20-\uD7FF\uE000-\uFFFD\u10000-\u10FFFF]", string.Empty); + } + static int Main () { var depDir = Path.Combine ("..", "external", "benchmarker"); @@ -227,9 +217,6 @@ static int Main () Console.WriteLine (result.StandardError); } - if (_processors.TryGetValue (bench.Name, out var processor)) - processor (result); - results.Add (result); } @@ -307,11 +294,11 @@ static int Main () writer.WriteStartElement ("failure"); writer.WriteStartElement ("message"); - writer.WriteCData (FilterInvalidXmlChars (result.StandardOutput)); + writer.WriteCData (ReplaceInvalidXmlChars (result.StandardOutput)); writer.WriteEndElement (); writer.WriteStartElement ("stack-trace"); - writer.WriteCData (FilterInvalidXmlChars (result.StandardError)); + writer.WriteCData (ReplaceInvalidXmlChars (result.StandardError)); writer.WriteEndElement (); writer.WriteEndElement (); diff --git a/configure.ac b/configure.ac index a68421e90d04..53c48fdf65b3 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ # Process this file with autoconf to produce a configure script. #AC_PREREQ([2.62]) -AC_INIT(mono, [5.9.0], +AC_INIT(mono, [5.11.0], [http://bugzilla.xamarin.com/enter_bug.cgi?classification=Mono]) AC_CONFIG_SRCDIR([README.md]) @@ -123,6 +123,7 @@ CFLAGS="$CFLAGS -D_REENTRANT -D_GNU_SOURCE -DNO_UNALIGNED_ACCESS -s WASM=1" CPPFLAGS="$CPPFLAGS -D_REENTRANT -DUSE_MMAP -D_GNU_SOURCE -DNO_UNALIGNED_ACCESS -s WASM=1" libdl="-ldl" libgc_threads=pthreads +platform_wasm=yes else @@ -368,8 +369,6 @@ case "$host" in AC_DEFINE(PTHREAD_POINTER_ID) dnl Haiku does not support static TLS with __thread with_tls=pthread - dnl Boehm is too much work to backport Haiku support for - support_boehm=no libgc_threads=pthreads use_sigposix=yes ;; @@ -413,6 +412,7 @@ AM_CONDITIONAL(HOST_SIGPOSIX, test x$use_sigposix = xyes) AM_CONDITIONAL(HOST_ANDROID, test x$platform_android = xyes) AM_CONDITIONAL(HOST_TIZEN, test x$platform_tizen = xyes) AM_CONDITIONAL(HOST_IOS, test x$platform_ios = xyes) +AM_CONDITIONAL(HOST_WASM, test x$platform_wasm = xyes) if test -z "$HOST_DARWIN_TRUE"; then : PLATFORM_AOT_SUFFIX=.dylib diff --git a/external/api-snapshot b/external/api-snapshot index f01089a251d5..8482d12f298a 160000 --- a/external/api-snapshot +++ b/external/api-snapshot @@ -1 +1 @@ -Subproject commit f01089a251d583510161dbc627eeff730c16c57e +Subproject commit 8482d12f298a01284c2d54921ae21b4487997a54 diff --git a/external/binary-reference-assemblies b/external/binary-reference-assemblies index e5d94c4fc91a..9f07d0746d94 160000 --- a/external/binary-reference-assemblies +++ b/external/binary-reference-assemblies @@ -1 +1 @@ -Subproject commit e5d94c4fc91a9977a149aa69cf22cd0c3cb98e57 +Subproject commit 9f07d0746d94d2c2b055e3e689814ca07431e5fd diff --git a/external/bockbuild b/external/bockbuild index 0d42e13de25c..694c7ecabf8b 160000 --- a/external/bockbuild +++ b/external/bockbuild @@ -1 +1 @@ -Subproject commit 0d42e13de25cbd03db00e07c4e7ffb3841926865 +Subproject commit 694c7ecabf8b352685896903162f6f0da77074a6 diff --git a/external/corefx b/external/corefx index 5eba95b97930..e1f502de7f55 160000 --- a/external/corefx +++ b/external/corefx @@ -1 +1 @@ -Subproject commit 5eba95b97930be62ad28b02eb75936bf31361e15 +Subproject commit e1f502de7f556407c124e88a4a8bcde962e7ccc7 diff --git a/external/roslyn-binaries b/external/roslyn-binaries index 85d026c98a49..00da53c47462 160000 --- a/external/roslyn-binaries +++ b/external/roslyn-binaries @@ -1 +1 @@ -Subproject commit 85d026c98a4972e38611dcc90c88b29550a87382 +Subproject commit 00da53c4746250988a92055ef3ac653ccf84fc40 diff --git a/libgc/configure.ac b/libgc/configure.ac index 7f5aa03148da..628144d3a16d 100644 --- a/libgc/configure.ac +++ b/libgc/configure.ac @@ -104,6 +104,10 @@ case "$THREADS" in AC_DEFINE(GC_AIX_THREADS) AC_DEFINE(_REENTRANT) ;; + *-*-haiku*) + AC_DEFINE(GC_HAIKU_THREADS) + AC_DEFINE(_REENTRANT) + ;; *-*-hpux*) AC_MSG_WARN("Only HP/UX 11 threads are supported.") AC_DEFINE(GC_HPUX_THREADS) diff --git a/libgc/dyn_load.c b/libgc/dyn_load.c index 5db3503aacba..963f6e954279 100644 --- a/libgc/dyn_load.c +++ b/libgc/dyn_load.c @@ -59,7 +59,7 @@ !(defined(FREEBSD) && defined(__ELF__)) && \ !(defined(OPENBSD) && (defined(__ELF__) || defined(M68K))) && \ !(defined(NETBSD) && defined(__ELF__)) && !defined(HURD) && \ - !defined(DARWIN) + !defined(DARWIN) && !defined(HAIKU) --> We only know how to find data segments of dynamic libraries for the --> above. Additional SVR4 variants might not be too --> hard to add. @@ -1258,6 +1258,23 @@ GC_bool GC_register_main_static_data() #endif /* DARWIN */ +#if defined(HAIKU) + +#include + +void GC_register_dynamic_libraries() +{ + image_info info; + int32 cookie = 0; + while (get_next_image_info(0, &cookie, &info) == B_OK) + { + void *data = info.data; + GC_add_roots_inner(data, data + info.data_size, TRUE); + } +} + +#endif /* HAIKU */ + #else /* !DYNAMIC_LOADING */ #ifdef PCR diff --git a/libgc/include/gc_config_macros.h b/libgc/include/gc_config_macros.h index caf8de527c32..55519b8ce384 100644 --- a/libgc/include/gc_config_macros.h +++ b/libgc/include/gc_config_macros.h @@ -57,7 +57,7 @@ defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS) || \ defined(GC_DGUX386_THREADS) || defined(GC_DARWIN_THREADS) || \ defined(GC_AIX_THREADS) || defined(GC_NETBSD_THREADS) || \ - defined(GC_OPENBSD_THREADS) || \ + defined(GC_OPENBSD_THREADS) || defined(GC_HAIKU_THREADS) ||\ (defined(GC_WIN32_THREADS) && defined(__CYGWIN32__)) # define GC_PTHREADS # endif diff --git a/libgc/include/private/gcconfig.h b/libgc/include/private/gcconfig.h index 03305b61de01..e2bdf13ac3e8 100644 --- a/libgc/include/private/gcconfig.h +++ b/libgc/include/private/gcconfig.h @@ -238,6 +238,16 @@ # define BEOS # define mach_type_known # endif +# if defined(__HAIKU__) && defined(_X86_) +# define I386 +# define HAIKU +# define mach_type_known +# endif +# if defined(__HAIKU__) && defined(__amd64__) +# define X86_64 +# define HAIKU +# define mach_type_known +# endif # if defined(LINUX) && (defined(i386) || defined(__i386__)) # define I386 # define mach_type_known @@ -1164,6 +1174,15 @@ extern int etext[]; # define DATASTART ((ptr_t)((((word) (etext)) + 0xfff) & ~0xfff)) # endif +# ifdef HAIKU +# define OS_TYPE "HAIKU" +# include +# define GETPAGESIZE() B_PAGE_SIZE + extern int etext[]; +# define DATASTART ((ptr_t)((((word) (etext)) + 0xfff) & ~0xfff)) +# define DYNAMIC_LOADING +# define MPROTECT_VDB +# endif # ifdef SUNOS5 # define OS_TYPE "SUNOS5" extern int _etext[], _end[]; @@ -2134,6 +2153,15 @@ /* There seems to be some issues with trylock hanging on darwin. This should be looked into some more */ # endif +# ifdef HAIKU +# define OS_TYPE "HAIKU" +# include +# define GETPAGESIZE() B_PAGE_SIZE + extern int etext[]; +# define DATASTART ((ptr_t)((((word) (etext)) + 0xfff) & ~0xfff)) +# define DYNAMIC_LOADING +# define MPROTECT_VDB +# endif # ifdef FREEBSD # define OS_TYPE "FREEBSD" # ifndef GC_FREEBSD_THREADS @@ -2251,7 +2279,7 @@ # if defined(SVR4) || defined(LINUX) || defined(IRIX5) || defined(HPUX) \ || defined(OPENBSD) || defined(NETBSD) || defined(FREEBSD) \ || defined(DGUX) || defined(BSD) || defined(SUNOS4) \ - || defined(_AIX) || defined(DARWIN) || defined(OSF1) + || defined(_AIX) || defined(DARWIN) || defined(OSF1) || defined(HAIKU) # define UNIX_LIKE /* Basic Unix-like system calls work. */ # endif @@ -2507,6 +2535,9 @@ # if defined(SN_TARGET_PS3) extern void *ps3_get_mem (size_t size); # define GET_MEM(bytes) (struct hblk*) ps3_get_mem (bytes) +# elif defined(HAIKU) + ptr_t GC_haiku_get_mem(GC_word bytes); +# define GET_MEM(bytes) (struct hblk*)GC_haiku_get_mem(bytes) # else extern ptr_t GC_unix_get_mem(word size); # define GET_MEM(bytes) (struct hblk *)GC_unix_get_mem(bytes) diff --git a/libgc/os_dep.c b/libgc/os_dep.c index 191e4b4ed7d0..dca798507540 100644 --- a/libgc/os_dep.c +++ b/libgc/os_dep.c @@ -609,7 +609,7 @@ void GC_enable_signals(void) && !defined(MACOS) && !defined(DJGPP) && !defined(DOS4GW) \ && !defined(NOSYS) && !defined(ECOS) && !defined(SN_TARGET_PS3) -# if defined(sigmask) && !defined(UTS4) && !defined(HURD) +# if defined(sigmask) && !defined(UTS4) && !defined(HURD) && !defined(HAIKU) /* Use the traditional BSD interface */ # define SIGSET_T int # define SIG_DEL(set, signal) (set) &= ~(sigmask(signal)) @@ -764,14 +764,14 @@ ptr_t GC_get_stack_base() # endif /* MS Windows */ -# ifdef BEOS +# ifdef HAIKU # include ptr_t GC_get_stack_base(){ thread_info th; get_thread_info(find_thread(NULL),&th); return th.stack_end; } -# endif /* BEOS */ +# endif /* HAIKU */ # ifdef OS2 @@ -1122,7 +1122,7 @@ void *GC_set_stackbottom = NULL; #endif /* FREEBSD_STACKBOTTOM */ -#if !defined(BEOS) && !defined(AMIGA) && !defined(MSWIN32) \ +#if !defined(HAIKU) && !defined(AMIGA) && !defined(MSWIN32) \ && !defined(MSWINCE) && !defined(OS2) && !defined(NOSYS) && !defined(ECOS) \ && !defined(GC_OPENBSD_THREADS) @@ -1182,7 +1182,7 @@ ptr_t GC_get_stack_base() # endif /* STACKBOTTOM */ } -# endif /* ! AMIGA, !OS 2, ! MS Windows, !BEOS, !NOSYS, !ECOS */ +# endif /* ! AMIGA, !OS 2, ! MS Windows, !HAIKU, !NOSYS, !ECOS */ #if defined(GC_OPENBSD_THREADS) @@ -1957,6 +1957,19 @@ word bytes; } # endif +#if defined(HAIKU) +#include + +ptr_t GC_haiku_get_mem(word bytes) +{ + void* mem; + if (posix_memalign(&mem, GC_page_size, bytes) == 0) + return mem; + else + return NULL; +} +#endif + #ifdef USE_MUNMAP /* For now, this only works on Win32/WinCE and some Unix-like */ @@ -2393,7 +2406,9 @@ GC_bool is_ptrfree; # include # include -# include +# if !defined(HAIKU) +# include +# endif # define PROTECT(addr, len) \ if (mprotect((caddr_t)(addr), (size_t)(len), \ @@ -2450,13 +2465,13 @@ GC_bool is_ptrfree; #endif /* SUNOS4 || (FREEBSD && !SUNOS5SIGS) */ #if defined(SUNOS5SIGS) || defined(OSF1) || defined(LINUX) \ - || defined(HURD) + || defined(HURD) || defined(HAIKU) # ifdef __STDC__ typedef void (* SIG_PF)(int); # else typedef void (* SIG_PF)(); # endif -#endif /* SUNOS5SIGS || OSF1 || LINUX || HURD */ +#endif /* SUNOS5SIGS || OSF1 || LINUX || HURD || HAIKU */ #if defined(MSWIN32) typedef LPTOP_LEVEL_EXCEPTION_FILTER SIG_PF; @@ -2634,6 +2649,13 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ /* architectures. */ # endif /* LINUX */ +# if defined(HAIKU) +# include +# define CODE_OK TRUE +# define SIG_OK (sig == SIGSEGV) + void GC_write_failt_handler(int sig, siginfo_t *scp, void * context) +#endif /* HAIKU */ + # if defined(SUNOS5SIGS) # ifdef __STDC__ void GC_write_fault_handler(int sig, SIGINFO_T *scp, void * context) @@ -2679,7 +2701,7 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ # if defined(OSF1) && defined(ALPHA) char * addr = (char *) (scp -> sc_traparg_a0); # endif -# ifdef SUNOS5SIGS +# if defined(SUNOS5SIGS) || defined(HAIKU) char * addr = (char *) (scp -> si_addr); # endif # ifdef LINUX diff --git a/libgc/pthread_support.c b/libgc/pthread_support.c index 097d588a7b55..6d240f65f0ee 100644 --- a/libgc/pthread_support.c +++ b/libgc/pthread_support.c @@ -1135,7 +1135,7 @@ void GC_thr_init() # if defined(GC_HPUX_THREADS) GC_nprocs = pthread_num_processors_np(); # endif -# if defined(GC_OSF1_THREADS) || defined(GC_AIX_THREADS) +# if defined(GC_OSF1_THREADS) || defined(GC_AIX_THREADS) || defined(GC_HAIKU_THREADS) GC_nprocs = sysconf(_SC_NPROCESSORS_ONLN); if (GC_nprocs <= 0) GC_nprocs = 1; # endif diff --git a/man/mono-profilers.1 b/man/mono-profilers.1 index 97b1aced7e1e..8ce00dade9a4 100644 --- a/man/mono-profilers.1 +++ b/man/mono-profilers.1 @@ -167,7 +167,7 @@ Enable heap snapshots. \fImode\fR, if given, can be one of: .TP \fBondemand\fR Only perform a heapshot when receiving a command via the command -server. +server or when triggered through the managed library. .TP \fInum\fR\fBgc\fR Perform a heapshot on every \fInum\fR collections of the major @@ -190,11 +190,11 @@ Print detailed debugging information. Most users should not use this option. .SS Command server The log profiler features a simple command server that currently is -only used to trigger heapshots when using the on-demand mode. A -random port will be used to listen for connections unless the -\fBport\fR option is used. To trigger a heapshot, open a TCP -connection to the command server and send the C string -\fB"heapshot\\n"\fR. +only used to trigger manual heapshots (typcally when using the +on-demand mode, but also usable with the other modes). A random port +will be used to listen for connections unless the \fBport\fR option +is used. To trigger a heapshot, open a TCP connection to the command +server and send the C string \fB"heapshot\\n"\fR. .PP The command server supports multiple simultaneous connections. .SS Managed library @@ -210,7 +210,7 @@ tools (e.g., \fBmprof\-report\fR(1)). The \fBLogProfiler\fR class allows users to reconfigure profiler settings at run-time. For example, certain event types can be toggled on or off, the mode and frequency of heapshots and sampling can be -changed, etc. +changed, etc. Heapshots can also be triggered manually. .PP To use this library, simply pass \fB\-r:Mono.Profiler.Log\fR when compiling your code. diff --git a/man/mono-service.1 b/man/mono-service.1 index 8a1a99caf1c9..84c37fdd0191 100644 --- a/man/mono-service.1 +++ b/man/mono-service.1 @@ -26,11 +26,6 @@ and execution can be resumed by sending the SIGUSR2 signal. The service can be cleanly shutdown by sending the SIGTERM signal to the process. .PP -Mono programs started with mono-service run with the -.B MONO_DISABLE_SHM -variable set. This means that certain Mono features that depend on -it are not available to services. -.PP The following options can be used to control the service: .TP .I "-d:DIRECTORY" diff --git a/man/mono.1 b/man/mono.1 index b38acfd314d0..5cac78c20ae7 100644 --- a/man/mono.1 +++ b/man/mono.1 @@ -950,8 +950,10 @@ If set, the log mask is changed to the set value. Possible values are "asm" (assembly loader), "type", "dll" (native library loader), "gc" (garbage collector), "cfg" (config file loader), "aot" (precompiler), "security" (e.g. Moonlight CoreCLR support), "threadpool" (thread pool generic), -"io-threadpool" (thread pool I/O), "io-layer" (I/O layer - sockets, handles, shared memory etc) -and "all". +"io-selector" (async socket operations), "io-layer" (I/O layer - processes, files, +sockets, events, semaphores, mutexes and handles), "io-layer-process", +"io-layer-file", "io-layer-socket", "io-layer-event", "io-layer-semaphore", +"io-layer-mutex", "io-layer-handle" and "all". The default value is "all". Changing the mask value allows you to display only messages for a certain component. You can use multiple masks by comma separating them. For example to see config file messages and assembly loader @@ -1101,18 +1103,6 @@ internally disables managed collation functionality invoked via the members of System.Globalization.CompareInfo class. Collation is enabled by default. .TP -\fBMONO_DISABLE_SHM\fR -Unix only: If set, disables the shared memory files used for -cross-process handles: process have only private handles. This means -that process and thread handles are not available to other processes, -and named mutexes, named events and named semaphores are not visible -between processes. -.Sp -This is can also be enabled by default by passing the -"--disable-shared-handles" option to configure. -.Sp -This is the default from mono 2.8 onwards. -.TP \fBMONO_DISABLE_SHARED_AREA\fR Unix only: If set, disable usage of shared memory for exposing performance counters. This means it will not be possible to both diff --git a/mcs/build/library.make b/mcs/build/library.make index 1e9dd8275714..43f97e42a0f7 100644 --- a/mcs/build/library.make +++ b/mcs/build/library.make @@ -37,7 +37,7 @@ LIB_MCS_FLAGS += $(patsubst %,-r:%.dll, $(subst =,=$(topdir)/class/lib/$(PROFILE else ifdef API_BIN_REFS -LIB_MCS_FLAGS += $(patsubst %,-r:$(topdir)/../external/api-snapshot/profiles/$(API_BIN_PROFILE)/%.dll,$(API_BIN_REFS)) +LIB_MCS_FLAGS += $(patsubst %,-r:$(topdir)/../external/binary-reference-assemblies/$(API_BIN_PROFILE)/%.dll,$(API_BIN_REFS)) endif LIB_MCS_FLAGS += $(patsubst %,-r:$(topdir)/class/lib/$(PROFILE_DIRECTORY)/%.dll,$(LIB_REFS_FULL)) diff --git a/mcs/build/profiles/basic.make b/mcs/build/profiles/basic.make index 199effb19ad4..347b313308c2 100644 --- a/mcs/build/profiles/basic.make +++ b/mcs/build/profiles/basic.make @@ -31,7 +31,7 @@ MCS = $(BOOTSTRAP_MCS) DEFAULT_REFERENCES = -r:$(topdir)/class/lib/$(PROFILE)/mscorlib.dll PROFILE_MCS_FLAGS = -d:NET_4_0 -d:NET_4_5 -d:MONO -d:WIN_PLATFORM -d:BOOTSTRAP_BASIC -nowarn:1699 -nostdlib $(DEFAULT_REFERENCES) -API_BIN_PROFILE = net_4_x +API_BIN_PROFILE = v4.7.1 NO_SIGN_ASSEMBLY = yes NO_TEST = yes diff --git a/mcs/build/profiles/build.make b/mcs/build/profiles/build.make index b8dd755fcae1..d757d10b1c80 100644 --- a/mcs/build/profiles/build.make +++ b/mcs/build/profiles/build.make @@ -15,7 +15,7 @@ profile-check: DEFAULT_REFERENCES = -r:$(topdir)/class/lib/$(PROFILE_DIRECTORY)/mscorlib.dll PROFILE_MCS_FLAGS = -d:NET_4_0 -d:NET_4_5 -d:MONO -d:WIN_PLATFORM -nowarn:1699 -nostdlib $(DEFAULT_REFERENCES) -API_BIN_PROFILE = net_4_x +API_BIN_PROFILE = v4.7.1 NO_SIGN_ASSEMBLY = yes NO_TEST = yes diff --git a/mcs/build/profiles/monodroid.make b/mcs/build/profiles/monodroid.make index 8f00109816b2..572bf609c1f5 100644 --- a/mcs/build/profiles/monodroid.make +++ b/mcs/build/profiles/monodroid.make @@ -27,7 +27,7 @@ PROFILE_MCS_FLAGS = \ $(DEFAULT_REFERENCES) \ $(PLATFORM_DEBUG_FLAGS) -API_BIN_PROFILE = monodroid +API_BIN_PROFILE = build/monodroid FRAMEWORK_VERSION = 2.1 # the tuner takes care of the install diff --git a/mcs/build/profiles/monotouch_runtime.make b/mcs/build/profiles/monotouch_runtime.make index a34563b276ab..1c29216802d5 100644 --- a/mcs/build/profiles/monotouch_runtime.make +++ b/mcs/build/profiles/monotouch_runtime.make @@ -28,7 +28,7 @@ PROFILE_MCS_FLAGS = \ $(PLATFORM_DEBUG_FLAGS) \ $(MONOTOUCH_MCS_FLAGS) -API_BIN_PROFILE = monotouch +API_BIN_PROFILE = build/monotouch FRAMEWORK_VERSION = 2.1 # This is utility build only diff --git a/mcs/build/profiles/net_4_x.make b/mcs/build/profiles/net_4_x.make index 24992f1dbabf..a7cc2e81dc1f 100644 --- a/mcs/build/profiles/net_4_x.make +++ b/mcs/build/profiles/net_4_x.make @@ -13,8 +13,8 @@ profile-check: @: DEFAULT_REFERENCES = -r:$(topdir)/class/lib/$(PROFILE_DIRECTORY)/mscorlib.dll -PROFILE_MCS_FLAGS = -d:NET_4_0 -d:NET_4_5 -d:NET_4_6 -d:MONO -d:UNITY_AOT -d:UNITY -d:WIN_PLATFORM -d:MULTIPLEX_OS -nowarn:1699 -nostdlib $(DEFAULT_REFERENCES) $(PLATFORM_DEBUG_FLAGS) -API_BIN_PROFILE = net_4_x +PROFILE_MCS_FLAGS = -d:NET_4_0 -d:NET_4_5 -d:NET_4_6 -d:MONO -d:UNITY_AOT -d:UNITY -d:WIN_PLATFORM -d:MULTIPLEX_OS -nowarn:1699 -nostdlib $(DEFAULT_REFERENCES) $(PLATFORM_DEBUG_FLAGS) +API_BIN_PROFILE = v4.7.1 FRAMEWORK_VERSION = 4.5 XBUILD_VERSION = 4.0 diff --git a/mcs/build/profiles/orbis.make b/mcs/build/profiles/orbis.make index 25037556f831..20493d503748 100644 --- a/mcs/build/profiles/orbis.make +++ b/mcs/build/profiles/orbis.make @@ -29,7 +29,7 @@ PROFILE_MCS_FLAGS = \ $(DEFAULT_REFERENCES) \ $(PLATFORM_DEBUG_FLAGS) -API_BIN_PROFILE = monotouch +API_BIN_PROFILE = build/monotouch FRAMEWORK_VERSION = 2.1 # the tuner takes care of the install diff --git a/mcs/build/profiles/testing_aot_full.make b/mcs/build/profiles/testing_aot_full.make index 246dc369e873..17974225781d 100644 --- a/mcs/build/profiles/testing_aot_full.make +++ b/mcs/build/profiles/testing_aot_full.make @@ -28,7 +28,7 @@ PROFILE_MCS_FLAGS = \ $(DEFAULT_REFERENCES) \ $(PLATFORM_DEBUG_FLAGS) -API_BIN_PROFILE = monotouch +API_BIN_PROFILE = build/monotouch FRAMEWORK_VERSION = 2.1 # the tuner takes care of the install diff --git a/mcs/build/profiles/testing_aot_hybrid.make b/mcs/build/profiles/testing_aot_hybrid.make index fba8892f440e..6b7dff61245c 100644 --- a/mcs/build/profiles/testing_aot_hybrid.make +++ b/mcs/build/profiles/testing_aot_hybrid.make @@ -25,7 +25,7 @@ PROFILE_MCS_FLAGS = \ $(DEFAULT_REFERENCES) \ $(PLATFORM_DEBUG_FLAGS) -API_BIN_PROFILE = monotouch +API_BIN_PROFILE = build/monotouch FRAMEWORK_VERSION = 2.1 NO_INSTALL = yes diff --git a/mcs/build/profiles/unityaot.make b/mcs/build/profiles/unityaot.make index 53440db35621..9b69620953c1 100644 --- a/mcs/build/profiles/unityaot.make +++ b/mcs/build/profiles/unityaot.make @@ -29,7 +29,7 @@ PROFILE_MCS_FLAGS = \ -nostdlib \ $(DEFAULT_REFERENCES) \ $(PLATFORM_DEBUG_FLAGS) -API_BIN_PROFILE = net_4_x +API_BIN_PROFILE = v4.7.1 FRAMEWORK_VERSION = 2.1 diff --git a/mcs/build/profiles/unityjit.make b/mcs/build/profiles/unityjit.make index 8186213f0f35..b943ecf40f99 100644 --- a/mcs/build/profiles/unityjit.make +++ b/mcs/build/profiles/unityjit.make @@ -11,7 +11,7 @@ profile-check: DEFAULT_REFERENCES = -r:$(topdir)/class/lib/$(PROFILE)/mscorlib.dll PROFILE_MCS_FLAGS = -d:NET_4_0 -d:NET_4_5 -d:NET_4_6 -d:MONO -d:UNITY_JIT -d:UNITY -d:WIN_PLATFORM -nowarn:1699 -nostdlib $(DEFAULT_REFERENCES) $(PLATFORM_DEBUG_FLAGS) -API_BIN_PROFILE = net_4_x +API_BIN_PROFILE = v4.7.1 FRAMEWORK_VERSION = 4.5 XBUILD_VERSION = 4.0 diff --git a/mcs/build/profiles/unreal.make b/mcs/build/profiles/unreal.make index c8a9abcb2b04..18a77474bdfe 100644 --- a/mcs/build/profiles/unreal.make +++ b/mcs/build/profiles/unreal.make @@ -25,7 +25,7 @@ PROFILE_MCS_FLAGS = \ $(DEFAULT_REFERENCES) \ $(PLATFORM_DEBUG_FLAGS) -API_BIN_PROFILE = monotouch +API_BIN_PROFILE = build/monotouch FRAMEWORK_VERSION = 2.1 NO_INSTALL = yes diff --git a/mcs/build/profiles/wasm.make b/mcs/build/profiles/wasm.make index d2a35ed98037..eca2019ea817 100644 --- a/mcs/build/profiles/wasm.make +++ b/mcs/build/profiles/wasm.make @@ -29,7 +29,7 @@ PROFILE_MCS_FLAGS = \ $(DEFAULT_REFERENCES) \ $(PLATFORM_DEBUG_FLAGS) -API_BIN_PROFILE = monotouch +API_BIN_PROFILE = build/monotouch FRAMEWORK_VERSION = 2.1 # the tuner takes care of the install diff --git a/mcs/build/profiles/winaot.make b/mcs/build/profiles/winaot.make index 77352ccf43a8..30cf6733156c 100644 --- a/mcs/build/profiles/winaot.make +++ b/mcs/build/profiles/winaot.make @@ -29,7 +29,7 @@ PROFILE_MCS_FLAGS = \ $(DEFAULT_REFERENCES) \ $(PLATFORM_DEBUG_FLAGS) -API_BIN_PROFILE = monotouch +API_BIN_PROFILE = build/monotouch FRAMEWORK_VERSION = 2.1 # the tuner takes care of the install diff --git a/mcs/build/profiles/xammac.make b/mcs/build/profiles/xammac.make index a790d44f0f4d..e3d007ecb335 100644 --- a/mcs/build/profiles/xammac.make +++ b/mcs/build/profiles/xammac.make @@ -27,7 +27,7 @@ PROFILE_MCS_FLAGS = \ $(PLATFORM_DEBUG_FLAGS) \ $(XAMMAC_MCS_FLAGS) -API_BIN_PROFILE = monotouch +API_BIN_PROFILE = build/monotouch FRAMEWORK_VERSION = 2.1 NO_TEST = yes diff --git a/mcs/build/tests.make b/mcs/build/tests.make index 288cfcae5647..f98dcd3846cb 100644 --- a/mcs/build/tests.make +++ b/mcs/build/tests.make @@ -108,7 +108,7 @@ run-test-local: run-test-lib run-test-ondotnet-local: run-test-ondotnet-lib ifdef TEST_WITH_INTERPRETER -TEST_HARNESS_EXCLUDES = -exclude=$(PLATFORM_TEST_HARNESS_EXCLUDES)$(PROFILE_TEST_HARNESS_EXCLUDES)NotWorking,InterpreterNotWorking,CAS +TEST_HARNESS_EXCLUDES = -exclude=$(PLATFORM_TEST_HARNESS_EXCLUDES)$(PROFILE_TEST_HARNESS_EXCLUDES)NotWorking,NotWorkingRuntimeInterpreter,CAS else TEST_HARNESS_EXCLUDES = -exclude=$(PLATFORM_TEST_HARNESS_EXCLUDES)$(PROFILE_TEST_HARNESS_EXCLUDES)NotWorking,CAS endif diff --git a/mcs/class/Makefile b/mcs/class/Makefile index d9702eca8732..64beb024a76b 100644 --- a/mcs/class/Makefile +++ b/mcs/class/Makefile @@ -86,7 +86,8 @@ mobile_common_dirs := \ Mono.CSharp \ Microsoft.CSharp \ System.Reflection.Context \ - System.Net.Http.WinHttpHandler + System.Net.Http.WinHttpHandler \ + System.Runtime.CompilerServices.Unsafe testing_aot_full_dirs := \ $(mobile_common_dirs) \ @@ -195,6 +196,7 @@ xammac_4_5_dirs := \ System.Net.Http.WebRequest \ System.Reflection.Context \ System.Net.Http.WinHttpHandler \ + System.Runtime.CompilerServices.Unsafe \ $(pcl_facade_dirs) net_4_x_dirs := \ @@ -336,6 +338,7 @@ net_4_x_parallel_dirs := \ System.Reflection.Context \ Mono.Profiler.Log \ Mono.Runtime.Tests \ + System.Runtime.CompilerServices.Unsafe \ legacy/Mono.Cecil \ $(pcl_facade_dirs) @@ -355,7 +358,8 @@ unityaot_dirs := \ System.Web.Services \ System.Reflection.Context \ System.Windows \ - System.Xml.Serialization, $(mobile_common_dirs)) \ + System.Xml.Serialization \ + System.Runtime.CompilerServices.Unsafe, $(mobile_common_dirs)) \ System.Drawing \ $(pcl_facade_dirs) diff --git a/mcs/class/Mono.Profiler.Log/Makefile b/mcs/class/Mono.Profiler.Log/Makefile index d8f11017c521..84d4ed93a85d 100644 --- a/mcs/class/Mono.Profiler.Log/Makefile +++ b/mcs/class/Mono.Profiler.Log/Makefile @@ -6,7 +6,7 @@ LIBRARY_SNK = ../mono.snk LIB_REFS = System System.Core KEYFILE = $(LIBRARY_SNK) -LIB_MCS_FLAGS = /unsafe /publicsign +LIB_MCS_FLAGS = /unsafe /publicsign /nowarn:0618 LIBRARY_WARN_AS_ERROR = yes diff --git a/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log-net_4_x.csproj b/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log-net_4_x.csproj index 3e8e16f0cea6..d2a6bf7ffdaf 100644 --- a/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log-net_4_x.csproj +++ b/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log-net_4_x.csproj @@ -8,7 +8,7 @@ 2.0 {58A188CE-DED8-48B0-98B7-065A260D21DF} Library - 1699 + 1699,618 latest win32 darwin @@ -32,7 +32,7 @@ true full - 1699 + 1699,618 false TRACE;NET_4_0;NET_4_5;NET_4_6;MONO;WIN_PLATFORM;MULTIPLEX_OS prompt @@ -40,7 +40,7 @@ pdbonly - 1699 + 1699,618 true NET_4_0;NET_4_5;NET_4_6;MONO;WIN_PLATFORM;MULTIPLEX_OS prompt diff --git a/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogEnums.cs b/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogEnums.cs index 711f948fa260..22cd832e8699 100644 --- a/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogEnums.cs +++ b/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogEnums.cs @@ -54,6 +54,8 @@ enum LogEventType { HeapEnd = 1 << 4, HeapObject = 2 << 4, HeapRoots = 3 << 4, + HeapRootRegister = 4 << 4, + HeapRootUnregister = 5 << 4, SampleHit = 0 << 4, SampleUnmanagedSymbol = 1 << 4, @@ -74,6 +76,7 @@ enum LogMetadataType { AppDomain = 4, Thread = 5, Context = 6, + VTable = 7, } // mono/utils/mono-counters.h : MONO_COUNTER_* @@ -119,21 +122,21 @@ public enum LogCounterVariance { // mono/metadata/profiler.h : MonoProfilerCodeBufferType public enum LogJitHelper { - Unknown = 0, - Method = 1, - MethodTrampoline = 2, - UnboxTrampoline = 3, - ImtTrampoline = 4, - GenericsTrampoline = 5, - SpecificTrampoline = 6, - Helper = 7, - Monitor = 8, - DelegateInvoke = 9, - ExceptionHandling = 10, + Method = 0, + MethodTrampoline = 1, + UnboxTrampoline = 2, + ImtTrampoline = 3, + GenericsTrampoline = 4, + SpecificTrampoline = 5, + Helper = 6, + Monitor = 7, + DelegateInvoke = 8, + ExceptionHandling = 9, } // mono/metadata/profiler.h : MonoProfilerGCRootType [Flags] + [Obsolete ("The event field using this enum is no longer produced.")] public enum LogHeapRootAttributes { Pinning = 1 << 8, WeakReference = 2 << 8, @@ -148,6 +151,25 @@ public enum LogHeapRootAttributes { TypeMask = 0xff, } + // mono/metadata/mono-gc.h : MonoGCRootSource + public enum LogHeapRootSource { + External = 0, + Stack = 1, + FinalizerQueue = 2, + Static = 3, + ThreadStatic = 4, + ContextStatic = 5, + GCHandle = 6, + Jit = 7, + Threading = 8, + AppDomain = 9, + Reflection = 10, + Marshal = 11, + ThreadPool = 12, + Debugger = 13, + Handle = 14, + } + // mono/profiler/log.h : MonoProfilerMonitorEvent public enum LogMonitorEvent { Contention = 1, diff --git a/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogEventVisitor.cs b/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogEventVisitor.cs index b49416cd2c1f..79d614052361 100644 --- a/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogEventVisitor.cs +++ b/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogEventVisitor.cs @@ -66,6 +66,10 @@ public virtual void Visit (ClassLoadEvent ev) { } + public virtual void Visit (VTableLoadEvent ev) + { + } + public virtual void Visit (JitEvent ev) { } @@ -94,6 +98,14 @@ public virtual void Visit (HeapRootsEvent ev) { } + public virtual void Visit (HeapRootRegisterEvent ev) + { + } + + public virtual void Visit (HeapRootUnregisterEvent ev) + { + } + public virtual void Visit (GCEvent ev) { } diff --git a/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogEvents.cs b/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogEvents.cs index 113bf3edc114..faae978cd968 100644 --- a/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogEvents.cs +++ b/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogEvents.cs @@ -161,6 +161,20 @@ internal override void Accept (LogEventVisitor visitor) } } + public sealed class VTableLoadEvent : LogEvent { + + public long VTablePointer { get; internal set; } + + public long AppDomainId { get; internal set; } + + public long ClassPointer { get; internal set; } + + internal override void Accept (LogEventVisitor visitor) + { + visitor.Visit (this); + } + } + public sealed class JitEvent : LogEvent { public long MethodPointer { get; internal set; } @@ -195,8 +209,11 @@ internal override void Accept (LogEventVisitor visitor) public sealed class AllocationEvent : LogEvent { + [Obsolete ("This field is no longer produced.")] public long ClassPointer { get; internal set; } + public long VTablePointer { get; internal set; } + public long ObjectPointer { get; internal set; } public long ObjectSize { get; internal set; } @@ -236,8 +253,11 @@ public struct HeapObjectReference { public long ObjectPointer { get; internal set; } + [Obsolete ("This field is no longer produced.")] public long ClassPointer { get; internal set; } + public long VTablePointer { get; internal set; } + public long ObjectSize { get; internal set; } public IReadOnlyList References { get; internal set; } @@ -252,13 +272,18 @@ public sealed class HeapRootsEvent : LogEvent { public struct HeapRoot { + public long AddressPointer { get; internal set; } + public long ObjectPointer { get; internal set; } + [Obsolete ("This field is no longer produced.")] public LogHeapRootAttributes Attributes { get; internal set; } + [Obsolete ("This field is no longer produced.")] public long ExtraInfo { get; internal set; } } + [Obsolete ("This field is no longer produced.")] public long MaxGenerationCollectionCount { get; internal set; } public IReadOnlyList Roots { get; internal set; } @@ -269,6 +294,34 @@ internal override void Accept (LogEventVisitor visitor) } } + public sealed class HeapRootRegisterEvent : LogEvent { + + public long RootPointer { get; internal set; } + + public long RootSize { get; internal set; } + + public LogHeapRootSource Source { get; internal set; } + + public long Key { get; internal set; } + + public string Name { get; internal set; } + + internal override void Accept (LogEventVisitor visitor) + { + visitor.Visit (this); + } + } + + public sealed class HeapRootUnregisterEvent : LogEvent { + + public long RootPointer { get; internal set; } + + internal override void Accept (LogEventVisitor visitor) + { + visitor.Visit (this); + } + } + public sealed class GCEvent : LogEvent { public LogGCEvent Type { get; internal set; } diff --git a/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogProcessor.cs b/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogProcessor.cs index d40897c3a7e6..6e26d22786cb 100644 --- a/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogProcessor.cs +++ b/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogProcessor.cs @@ -127,7 +127,8 @@ LogEvent ReadEvent () case LogEventType.AllocationBacktrace: case LogEventType.AllocationNoBacktrace: ev = new AllocationEvent { - ClassPointer = ReadPointer (), + ClassPointer = StreamHeader.FormatVersion < 15 ? ReadPointer () : 0, + VTablePointer = StreamHeader.FormatVersion >= 15 ? ReadPointer () : 0, ObjectPointer = ReadObject (), ObjectSize = (long) _reader.ReadULeb128 (), Backtrace = ReadBacktrace (extType == LogEventType.AllocationBacktrace), @@ -305,6 +306,16 @@ LogEvent ReadEvent () } else throw new LogException ("Invalid context metadata event."); break; + case LogMetadataType.VTable: + if (load) { + ev = new VTableLoadEvent { + VTablePointer = ReadPointer (), + AppDomainId = ReadPointer (), + ClassPointer = ReadPointer (), + }; + } else + throw new LogException ("Invalid VTable metadata event."); + break; default: throw new LogException ($"Invalid metadata type ({metadataType})."); } @@ -373,8 +384,8 @@ LogEvent ReadEvent () case LogEventType.MonitorBacktrace: ev = new MonitorEvent { Event = StreamHeader.FormatVersion >= 14 ? - (LogMonitorEvent) _reader.ReadByte () : - (LogMonitorEvent) ((((byte) type & 0xf0) >> 4) & 0x3), + (LogMonitorEvent) _reader.ReadByte () : + (LogMonitorEvent) ((((byte) type & 0xf0) >> 4) & 0x3), ObjectPointer = ReadObject (), Backtrace = ReadBacktrace (extType == LogEventType.MonitorBacktrace), }; @@ -394,7 +405,8 @@ LogEvent ReadEvent () case LogEventType.HeapObject: { HeapObjectEvent hoe = new HeapObjectEvent { ObjectPointer = ReadObject (), - ClassPointer = ReadPointer (), + ClassPointer = StreamHeader.FormatVersion < 15 ? ReadPointer () : 0, + VTablePointer = StreamHeader.FormatVersion >= 15 ? ReadPointer () : 0, ObjectSize = (long) _reader.ReadULeb128 (), }; @@ -414,17 +426,22 @@ LogEvent ReadEvent () } case LogEventType.HeapRoots: { - // TODO: This entire event makes no sense. var hre = new HeapRootsEvent (); var list = new HeapRootsEvent.HeapRoot [(int) _reader.ReadULeb128 ()]; - hre.MaxGenerationCollectionCount = (long) _reader.ReadULeb128 (); + if (StreamHeader.FormatVersion < 15) + hre.MaxGenerationCollectionCount = (long) _reader.ReadULeb128 (); for (var i = 0; i < list.Length; i++) { list [i] = new HeapRootsEvent.HeapRoot { + AddressPointer = StreamHeader.FormatVersion >= 15 ? ReadPointer () : 0, ObjectPointer = ReadObject (), - Attributes = StreamHeader.FormatVersion == 13 ? (LogHeapRootAttributes) _reader.ReadByte () : (LogHeapRootAttributes) _reader.ReadULeb128 (), - ExtraInfo = (long) _reader.ReadULeb128 (), + Attributes = StreamHeader.FormatVersion < 15 ? + (StreamHeader.FormatVersion == 13 ? + (LogHeapRootAttributes) _reader.ReadByte () : + (LogHeapRootAttributes) _reader.ReadULeb128 ()) : + 0, + ExtraInfo = StreamHeader.FormatVersion < 15 ? (long) _reader.ReadULeb128 () : 0, }; } @@ -433,6 +450,20 @@ LogEvent ReadEvent () break; } + case LogEventType.HeapRootRegister: + ev = new HeapRootRegisterEvent { + RootPointer = ReadPointer (), + RootSize = (long) _reader.ReadULeb128 (), + Source = (LogHeapRootSource) _reader.ReadByte (), + Key = ReadPointer (), + Name = _reader.ReadCString (), + }; + break; + case LogEventType.HeapRootUnregister: + ev = new HeapRootUnregisterEvent { + RootPointer = ReadPointer (), + }; + break; default: throw new LogException ($"Invalid extended event type ({extType})."); } @@ -476,9 +507,9 @@ LogEvent ReadEvent () Section = section, SectionName = section == LogCounterSection.User ? _reader.ReadCString () : null, CounterName = _reader.ReadCString (), - Type = (LogCounterType) _reader.ReadByte (), - Unit = (LogCounterUnit) _reader.ReadByte (), - Variance = (LogCounterVariance) _reader.ReadByte (), + Type = StreamHeader.FormatVersion < 15 ? (LogCounterType) _reader.ReadByte () : (LogCounterType) _reader.ReadULeb128 (), + Unit = StreamHeader.FormatVersion < 15 ? (LogCounterUnit) _reader.ReadByte () : (LogCounterUnit) _reader.ReadULeb128 (), + Variance = StreamHeader.FormatVersion < 15 ? (LogCounterVariance) _reader.ReadByte () : (LogCounterVariance) _reader.ReadULeb128 (), Index = (long) _reader.ReadULeb128 (), }; } @@ -498,7 +529,7 @@ LogEvent ReadEvent () if (index == 0) break; - var counterType = (LogCounterType) _reader.ReadByte (); + var counterType = StreamHeader.FormatVersion < 15 ? (LogCounterType) _reader.ReadByte () : (LogCounterType) _reader.ReadULeb128 (); object value = null; @@ -544,6 +575,9 @@ LogEvent ReadEvent () case LogEventType.RuntimeJitHelper: { var helperType = (LogJitHelper) _reader.ReadByte (); + if (StreamHeader.FormatVersion < 14) + helperType--; + ev = new JitHelperEvent { Type = helperType, BufferPointer = ReadPointer (), diff --git a/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogProfiler.cs b/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogProfiler.cs index 688a84b98648..4f3e19d73579 100644 --- a/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogProfiler.cs +++ b/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogProfiler.cs @@ -100,6 +100,9 @@ public static int HeapshotCollectionsFrequency { } } + [MethodImpl (MethodImplOptions.InternalCall)] + public extern static void TriggerHeapshot (); + [MethodImpl (MethodImplOptions.InternalCall)] extern static int GetCallDepth (); diff --git a/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogStreamHeader.cs b/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogStreamHeader.cs index 44575028a7a3..aa86b75444a1 100644 --- a/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogStreamHeader.cs +++ b/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogStreamHeader.cs @@ -9,7 +9,7 @@ namespace Mono.Profiler.Log { public sealed class LogStreamHeader { const int MinVersion = 13; - const int MaxVersion = 14; + const int MaxVersion = 15; const int Id = 0x4d505a01; diff --git a/mcs/class/System.Core/Makefile b/mcs/class/System.Core/Makefile index 566c5fb57901..d0c6453a9901 100644 --- a/mcs/class/System.Core/Makefile +++ b/mcs/class/System.Core/Makefile @@ -25,7 +25,7 @@ LIB_MCS_FLAGS += -d:NET_3_5 endif ifdef AOT_FRIENDLY_PROFILE -extra_test_flags := -exclude:NotWorkingInterpreter +extra_test_flags := -exclude:NotWorkingLinqInterpreter LIB_MCS_FLAGS += -d:NO_FEATURE_STATIC_DELEGATE,FEATURE_MAKE_RUN_METHODS else LIB_MCS_FLAGS += -d:FEATURE_COMPILE,FEATURE_COMPILE_TO_METHODBUILDER,FEATURE_PDB_GENERATOR diff --git a/mcs/class/System.Core/Test/System.Linq.Expressions/ExpressionTest_Call.cs b/mcs/class/System.Core/Test/System.Linq.Expressions/ExpressionTest_Call.cs index 7757ca9d881b..6a01d8f34267 100644 --- a/mcs/class/System.Core/Test/System.Linq.Expressions/ExpressionTest_Call.cs +++ b/mcs/class/System.Core/Test/System.Linq.Expressions/ExpressionTest_Call.cs @@ -403,7 +403,7 @@ public void Connect297597 () [Test] [Category ("NotDotNet")] // https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=319190 - [Category ("NotWorkingInterpreter")] + [Category ("NotWorkingLinqInterpreter")] public void Connect319190 () { var lambda = Expression.Lambda> ( diff --git a/mcs/class/System.Core/Test/System.Linq.Expressions/ExpressionTest_Equal.cs b/mcs/class/System.Core/Test/System.Linq.Expressions/ExpressionTest_Equal.cs index d483cf778b69..105ec20027d9 100644 --- a/mcs/class/System.Core/Test/System.Linq.Expressions/ExpressionTest_Equal.cs +++ b/mcs/class/System.Core/Test/System.Linq.Expressions/ExpressionTest_Equal.cs @@ -472,7 +472,7 @@ public void LiftedEnumEqual () } [Test] - [Category ("NotWorkingInterpreter")] + [Category ("NotWorkingLinqInterpreter")] public void NullableNullEqual () { var param = Expression.Parameter (typeof (DateTime?), "x"); diff --git a/mcs/class/System.Core/Test/System.Linq/EnumerableAsQueryableTest.cs b/mcs/class/System.Core/Test/System.Linq/EnumerableAsQueryableTest.cs index 7269f376c2ba..aee3bff9ee3e 100644 --- a/mcs/class/System.Core/Test/System.Linq/EnumerableAsQueryableTest.cs +++ b/mcs/class/System.Core/Test/System.Linq/EnumerableAsQueryableTest.cs @@ -324,7 +324,7 @@ public void Where () } [Test] - [Category ("NotWorkingInterpreter")] + [Category ("NotWorkingLinqInterpreter")] public void UserExtensionMethod () { BindingFlags extensionFlags = BindingFlags.Static | BindingFlags.Public; diff --git a/mcs/class/System.IdentityModel/System.IdentityModel.Tokens/InMemorySymmetricSecurityKey.cs b/mcs/class/System.IdentityModel/System.IdentityModel.Tokens/InMemorySymmetricSecurityKey.cs index 014d8a70f7f2..d0fe6750af77 100644 --- a/mcs/class/System.IdentityModel/System.IdentityModel.Tokens/InMemorySymmetricSecurityKey.cs +++ b/mcs/class/System.IdentityModel/System.IdentityModel.Tokens/InMemorySymmetricSecurityKey.cs @@ -123,8 +123,8 @@ public override KeyedHashAlgorithm GetKeyedHashAlgorithm ( { if (algorithm == SecurityAlgorithms.HmacSha1Signature) return new HMACSHA1 (key); - //if (algorithm == SecurityAlgorithms.HmacSha256Signature) - // return new HMACSHA256 (key); + if (algorithm == SecurityAlgorithms.HmacSha256Signature) + return new HMACSHA256 (key); throw new NotSupportedException (); } @@ -212,6 +212,7 @@ public override bool IsSupportedAlgorithm (string algorithm) { switch (algorithm) { case SecurityAlgorithms.HmacSha1Signature: + case SecurityAlgorithms.HmacSha256Signature: case SecurityAlgorithms.Psha1KeyDerivation: case SecurityAlgorithms.Aes128Encryption: case SecurityAlgorithms.Aes128KeyWrap: diff --git a/mcs/class/System.IdentityModel/Test/System.IdentityModel.Tokens/InMemorySymmetricSecurityKeyTest.cs b/mcs/class/System.IdentityModel/Test/System.IdentityModel.Tokens/InMemorySymmetricSecurityKeyTest.cs index 7fa81a95abd8..995301071c17 100644 --- a/mcs/class/System.IdentityModel/Test/System.IdentityModel.Tokens/InMemorySymmetricSecurityKeyTest.cs +++ b/mcs/class/System.IdentityModel/Test/System.IdentityModel.Tokens/InMemorySymmetricSecurityKeyTest.cs @@ -275,5 +275,22 @@ public void IsSymmetricAlgorithm () Assert.IsFalse (key.IsSymmetricAlgorithm (SecurityAlgorithms.RsaOaepKeyWrap), "#3"); Assert.IsTrue (key.IsSymmetricAlgorithm (SecurityAlgorithms.Psha1KeyDerivation), "#4"); } + + [Test] + public void GetKeyedHashAlgorithm() + { + InMemorySymmetricSecurityKey key = new InMemorySymmetricSecurityKey(new byte[0]); + + Assert.That(() => key.GetKeyedHashAlgorithm(SecurityAlgorithms.HmacSha256Signature), Throws.Nothing); + } + + [Test] + public void IsSupportedAlgorithm() + { + InMemorySymmetricSecurityKey key = new InMemorySymmetricSecurityKey(new byte[0]); + + Assert.That(() => key.IsSupportedAlgorithm(SecurityAlgorithms.HmacSha256Signature), Is.True); + } + } } diff --git a/mcs/class/System.Runtime.CompilerServices.Unsafe/AssemblyInfo.il b/mcs/class/System.Runtime.CompilerServices.Unsafe/AssemblyInfo.il new file mode 100644 index 000000000000..af111b736d51 --- /dev/null +++ b/mcs/class/System.Runtime.CompilerServices.Unsafe/AssemblyInfo.il @@ -0,0 +1,18 @@ +.assembly extern mscorlib +{ +} + +.assembly System.Runtime.CompilerServices.Unsafe +{ + .custom instance void [mscorlib]System.Reflection.AssemblyFileVersionAttribute::.ctor(string) = ( 01 00 07 34 2E 30 2E 30 2E 30 00 00 ) // ...4.0.0.0.. + .custom instance void [mscorlib]System.Reflection.AssemblyInformationalVersionAttribute::.ctor(string) = ( 01 00 07 34 2E 30 2E 30 2E 30 00 00 ) // ...4.0.0.0.. + + .hash algorithm 0x00008004 + .ver 4:0:4:0 +} +.module System.Runtime.CompilerServices.Unsafe.dll +.imagebase 0x00400000 +.file alignment 0x00000200 +.stackreserve 0x00100000 +.subsystem 0x0003 // WINDOWS_CUI +.corflags 0x00000001 // ILONLY diff --git a/mcs/class/System.Runtime.CompilerServices.Unsafe/Makefile b/mcs/class/System.Runtime.CompilerServices.Unsafe/Makefile new file mode 100644 index 000000000000..207310ec0732 --- /dev/null +++ b/mcs/class/System.Runtime.CompilerServices.Unsafe/Makefile @@ -0,0 +1,18 @@ +thisdir = class/System.Runtime.CompilerServices.Unsafe +SUBDIRS = +include ../../build/rules.make + +LIBRARY = System.Runtime.CompilerServices.Unsafe.dll + +XTEST_LIB_FLAGS = -unsafe + +#NO_BUILD = yes +NO_INSTALL = yes + +EXTRA_DISTFILES = AssemblyInfo.il + +include ../../build/library.make + +$(build_lib): AssemblyInfo.il ../corlib/System.Runtime.CompilerServices/Unsafe.il + $(ILASM) AssemblyInfo.il ../corlib/System.Runtime.CompilerServices/Unsafe.il /dll /out:$(build_lib) + diff --git a/mcs/class/System.Runtime.CompilerServices.Unsafe/System.Runtime.CompilerServices.Unsafe-net_4_x.csproj b/mcs/class/System.Runtime.CompilerServices.Unsafe/System.Runtime.CompilerServices.Unsafe-net_4_x.csproj new file mode 100644 index 000000000000..3f40a09a78d5 --- /dev/null +++ b/mcs/class/System.Runtime.CompilerServices.Unsafe/System.Runtime.CompilerServices.Unsafe-net_4_x.csproj @@ -0,0 +1,88 @@ + + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {6C50BF24-90AB-4654-B295-16A1C717643C} + Library + 1699 + latest + win32 + darwin + linux + ./../../class/lib/net_4_x-$(HostPlatform) + obj-net_4_x-$(HostPlatform) + false + True + + True + + Properties + + + System.Runtime.CompilerServices.Unsafe + v4.5 + 512 + + + + true + full + 1699 + false + TRACE;NET_4_0;NET_4_5;NET_4_6;MONO;WIN_PLATFORM;MULTIPLEX_OS + prompt + 4 + + + pdbonly + 1699 + true + NET_4_0;NET_4_5;NET_4_6;MONO;WIN_PLATFORM;MULTIPLEX_OS + prompt + 4 + + + + false + + + + + + + + + + + + + + + + + + + + + + {2CA6026B-2DC8-4C4C-A12C-1E8234049DB7} + corlib-net_4_x + + + + + + + diff --git a/mcs/class/System.Runtime.CompilerServices.Unsafe/System.Runtime.CompilerServices.Unsafe.dll.sources b/mcs/class/System.Runtime.CompilerServices.Unsafe/System.Runtime.CompilerServices.Unsafe.dll.sources new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/mcs/class/System.Runtime.CompilerServices.Unsafe/System.Runtime.CompilerServices.Unsafe_xtest.dll.sources b/mcs/class/System.Runtime.CompilerServices.Unsafe/System.Runtime.CompilerServices.Unsafe_xtest.dll.sources new file mode 100644 index 000000000000..180257f53e74 --- /dev/null +++ b/mcs/class/System.Runtime.CompilerServices.Unsafe/System.Runtime.CompilerServices.Unsafe_xtest.dll.sources @@ -0,0 +1 @@ +../../../external/corefx/src/System.Runtime.CompilerServices.Unsafe/tests/*.cs diff --git a/mcs/class/System.Web/System.Web.SessionState_2.0/SessionStateModule.cs b/mcs/class/System.Web/System.Web.SessionState_2.0/SessionStateModule.cs index 8d85d6482f07..8d9dac0c312b 100644 --- a/mcs/class/System.Web/System.Web.SessionState_2.0/SessionStateModule.cs +++ b/mcs/class/System.Web/System.Web.SessionState_2.0/SessionStateModule.cs @@ -46,21 +46,6 @@ namespace System.Web.SessionState [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] public sealed class SessionStateModule : IHttpModule { - class CallbackState - { - public readonly HttpContext Context; - public readonly AutoResetEvent AutoEvent; - public readonly string SessionId; - public readonly bool IsReadOnly; - - public CallbackState (HttpContext context, AutoResetEvent e, string sessionId, bool isReadOnly) { - this.Context = context; - this.AutoEvent = e; - this.SessionId = sessionId; - this.IsReadOnly = isReadOnly; - } - } - internal const string HeaderName = "AspFilterSessionId"; internal const string CookielessFlagName = "_SessionIDManager_IsCookieLess"; @@ -342,36 +327,22 @@ SessionStateStoreData GetStoreData (HttpContext context, string sessionId, bool return item; } - void WaitForStoreUnlock (HttpContext context, string sessionId, bool isReadonly) { - AutoResetEvent are = new AutoResetEvent (false); - TimerCallback tc = new TimerCallback (StoreUnlockWaitCallback); - CallbackState cs = new CallbackState (context, are, sessionId, isReadonly); - using (Timer timer = new Timer (tc, cs, 500, 500)) { - try { - are.WaitOne (executionTimeout, false); + void WaitForStoreUnlock (HttpContext context, string sessionId, bool isReadOnly) { + DateTime dt = DateTime.Now; + while ((DateTime.Now - dt) < executionTimeout) { + Thread.Sleep(500); + storeData = GetStoreData (context, sessionId, isReadOnly); + if (storeData == null && storeLocked && (storeLockAge > executionTimeout)) { + handler.ReleaseItemExclusive (context, sessionId, storeLockId); + return; } - catch { - storeData = null; + else if (storeData != null && !storeLocked) { + //we have the session + return; } } } - void StoreUnlockWaitCallback (object s) { - CallbackState state = (CallbackState) s; - - SessionStateStoreData item = GetStoreData (state.Context, state.SessionId, state.IsReadOnly); - - if (item == null && storeLocked && (storeLockAge > executionTimeout)) { - handler.ReleaseItemExclusive (state.Context, state.SessionId, storeLockId); - storeData = null; // Create new state - state.AutoEvent.Set (); - } - else if (item != null && !storeLocked) { - storeData = item; - state.AutoEvent.Set (); - } - } - HttpSessionStateContainer CreateContainer (string sessionId, SessionStateStoreData data, bool isNew, bool isReadOnly) { if (data == null) return new HttpSessionStateContainer ( diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/DataGridView.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/DataGridView.cs index 3ce4ab7b5741..a4a747537c31 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/DataGridView.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/DataGridView.cs @@ -512,6 +512,8 @@ public DataGridViewCellBorderStyle CellBorderStyle { border.All = DataGridViewAdvancedCellBorderStyle.Single; break; case DataGridViewCellBorderStyle.Raised: + border.All = DataGridViewAdvancedCellBorderStyle.Outset; + break; case DataGridViewCellBorderStyle.RaisedVertical: border.Bottom = DataGridViewAdvancedCellBorderStyle.None; border.Top = DataGridViewAdvancedCellBorderStyle.None; @@ -537,6 +539,9 @@ public DataGridViewCellBorderStyle CellBorderStyle { border.Right = DataGridViewAdvancedCellBorderStyle.Inset; break; case DataGridViewCellBorderStyle.SingleHorizontal: + border.All = DataGridViewAdvancedCellBorderStyle.None; + border.Bottom = DataGridViewAdvancedCellBorderStyle.Single; + break; case DataGridViewCellBorderStyle.SunkenHorizontal: border.Bottom = DataGridViewAdvancedCellBorderStyle.Inset; border.Top = DataGridViewAdvancedCellBorderStyle.Inset; diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/DataGridViewCell.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/DataGridViewCell.cs index c34973ec4c78..7feb1d471b2d 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/DataGridViewCell.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/DataGridViewCell.cs @@ -432,6 +432,32 @@ internal override void SetState (DataGridViewElementStates state) { [EditorBrowsable (EditorBrowsableState.Advanced)] public virtual DataGridViewAdvancedBorderStyle AdjustCellBorderStyle (DataGridViewAdvancedBorderStyle dataGridViewAdvancedBorderStyleInput, DataGridViewAdvancedBorderStyle dataGridViewAdvancedBorderStylePlaceholder, bool singleVerticalBorderAdded, bool singleHorizontalBorderAdded, bool isFirstDisplayedColumn, bool isFirstDisplayedRow) { + if (dataGridViewAdvancedBorderStyleInput.All == DataGridViewAdvancedCellBorderStyle.Single) { + + dataGridViewAdvancedBorderStylePlaceholder.Left = (isFirstDisplayedColumn && singleVerticalBorderAdded) ? DataGridViewAdvancedCellBorderStyle.Single : DataGridViewAdvancedCellBorderStyle.None; + dataGridViewAdvancedBorderStylePlaceholder.Right = DataGridViewAdvancedCellBorderStyle.Single; + dataGridViewAdvancedBorderStylePlaceholder.Top = (isFirstDisplayedRow && singleHorizontalBorderAdded)? DataGridViewAdvancedCellBorderStyle.Single : DataGridViewAdvancedCellBorderStyle.None; + dataGridViewAdvancedBorderStylePlaceholder.Bottom = DataGridViewAdvancedCellBorderStyle.Single; + return dataGridViewAdvancedBorderStylePlaceholder; + } + + if ((dataGridViewAdvancedBorderStyleInput.All == DataGridViewAdvancedCellBorderStyle.NotSet) && (DataGridView != null) && (DataGridView.AdvancedCellBorderStyle == dataGridViewAdvancedBorderStyleInput)) { + if (DataGridView.CellBorderStyle == DataGridViewCellBorderStyle.SingleVertical) { + dataGridViewAdvancedBorderStylePlaceholder.Left = (isFirstDisplayedColumn && singleVerticalBorderAdded) ? DataGridViewAdvancedCellBorderStyle.Single : DataGridViewAdvancedCellBorderStyle.None; + dataGridViewAdvancedBorderStylePlaceholder.Right = DataGridViewAdvancedCellBorderStyle.Single; + dataGridViewAdvancedBorderStylePlaceholder.Top = DataGridViewAdvancedCellBorderStyle.None; + dataGridViewAdvancedBorderStylePlaceholder.Bottom = DataGridViewAdvancedCellBorderStyle.None; + return dataGridViewAdvancedBorderStylePlaceholder; + } + if (DataGridView.CellBorderStyle == DataGridViewCellBorderStyle.SingleHorizontal) { + dataGridViewAdvancedBorderStylePlaceholder.Left = DataGridViewAdvancedCellBorderStyle.None; + dataGridViewAdvancedBorderStylePlaceholder.Right = DataGridViewAdvancedCellBorderStyle.None; + dataGridViewAdvancedBorderStylePlaceholder.Top = (isFirstDisplayedRow && singleHorizontalBorderAdded)? DataGridViewAdvancedCellBorderStyle.Single : DataGridViewAdvancedCellBorderStyle.None; + dataGridViewAdvancedBorderStylePlaceholder.Bottom = DataGridViewAdvancedCellBorderStyle.Single; + return dataGridViewAdvancedBorderStylePlaceholder; + } + } + return dataGridViewAdvancedBorderStyleInput; } @@ -1166,62 +1192,167 @@ protected virtual void Paint (Graphics graphics, Rectangle clipBounds, Rectangle PaintErrorIcon (graphics, clipBounds, cellBounds, ErrorText); } + private void PaintDividers (Graphics graphics, ref Rectangle bounds, DataGridViewAdvancedBorderStyle advancedBorderStyle) + { + // Paint the vertical divider + int dividerWidth = OwningColumn != null ? OwningColumn.DividerWidth : 0; + if (dividerWidth > 0) { + if (dividerWidth > bounds.Width) + dividerWidth = bounds.Width; + Color color; + switch (advancedBorderStyle.Right) { + case DataGridViewAdvancedCellBorderStyle.Single: + color = DataGridView.GridColor; + break; + case DataGridViewAdvancedCellBorderStyle.Inset: + color = SystemColors.ControlLightLight; + break; + default: + color = SystemColors.ControlDark; + break; + } + + graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (color), bounds.Right - dividerWidth, bounds.Y, dividerWidth, bounds.Height); + bounds.Width -= dividerWidth; + if (bounds.Width <= 0) + return; + } + + dividerWidth = OwningRow != null ? OwningRow.DividerHeight : 0; + if (dividerWidth > 0) { + if (dividerWidth > bounds.Height) + dividerWidth = bounds.Height; + Color color; + switch (advancedBorderStyle.Bottom) { + case DataGridViewAdvancedCellBorderStyle.Single: + color = DataGridView.GridColor; + break; + case DataGridViewAdvancedCellBorderStyle.Inset: + color = SystemColors.ControlLightLight; + break; + default: + color = SystemColors.ControlDark; + break; + } + + graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (color), bounds.X, bounds.Bottom - dividerWidth, bounds.Width, dividerWidth); + bounds.Height -= dividerWidth; + } + } + protected virtual void PaintBorder (Graphics graphics, Rectangle clipBounds, Rectangle bounds, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle) { - Pen pen = new Pen (DataGridView.GridColor); + PaintDividers(graphics, ref bounds, advancedBorderStyle); + if (bounds.Height <= 0 || bounds.Width <= 0) + return; + + if (advancedBorderStyle.All == DataGridViewAdvancedCellBorderStyle.None) + return; + + Pen penGrid = ThemeEngine.Current.ResPool.GetPen (DataGridView.GridColor); + CPColor cpColor = ThemeEngine.Current.ResPool.GetCPColor (cellStyle.BackColor); + Pen penDark = ThemeEngine.Current.ResPool.GetPen (cpColor.Dark); + Pen penLight = ThemeEngine.Current.ResPool.GetPen (cpColor.LightLight); + + int left = bounds.X; + int right = bounds.Right - 1; + int top = bounds.Y; + int bottom = bounds.Bottom - 1; // Paint the left border, if any switch (advancedBorderStyle.Left) { case DataGridViewAdvancedCellBorderStyle.Single: - if (DataGridView.CellBorderStyle != DataGridViewCellBorderStyle.Single) - graphics.DrawLine (pen, bounds.X, bounds.Y, bounds.X, bounds.Y + bounds.Height - 1); + graphics.DrawLine (penGrid, left, top, left, bottom); break; + case DataGridViewAdvancedCellBorderStyle.Outset: + graphics.DrawLine (penLight, left, top, left, bottom); + break; + case DataGridViewAdvancedCellBorderStyle.Inset: - graphics.DrawLine(pen, bounds.X, bounds.Y, bounds.X, bounds.Y + bounds.Height - 1); + graphics.DrawLine (penDark, left, top, left, bottom); break; + case DataGridViewAdvancedCellBorderStyle.InsetDouble: + graphics.DrawLine(penLight, left, top, left, bottom); + graphics.DrawLine(penDark, left + 1, (advancedBorderStyle.Top != DataGridViewAdvancedCellBorderStyle.None)? top + 1 : top, left + 1, bottom); + break; + case DataGridViewAdvancedCellBorderStyle.OutsetDouble: - graphics.DrawLine(pen, bounds.X, bounds.Y, bounds.X, bounds.Y + bounds.Height - 1); - graphics.DrawLine(pen, bounds.X + 2, bounds.Y, bounds.X + 2, bounds.Y + bounds.Height - 1); + graphics.DrawLine(penDark, left, top, left, bottom); + graphics.DrawLine(penLight, left + 1, (advancedBorderStyle.Top != DataGridViewAdvancedCellBorderStyle.None)? top + 1 : top, left + 1, bottom); break; } - + // Paint the right border, if any switch (advancedBorderStyle.Right) { case DataGridViewAdvancedCellBorderStyle.Single: - graphics.DrawLine(pen, bounds.X + bounds.Width - 1, bounds.Y, bounds.X + bounds.Width - 1, bounds.Y + bounds.Height - 1); + graphics.DrawLine(penGrid, right, top, right, bottom); break; + case DataGridViewAdvancedCellBorderStyle.Outset: + graphics.DrawLine (penDark, right, top, right, bottom); + break; + case DataGridViewAdvancedCellBorderStyle.Inset: + graphics.DrawLine (penLight, right, top, right, bottom); + break; + case DataGridViewAdvancedCellBorderStyle.InsetDouble: + graphics.DrawLine (penLight, right - 1, top, right - 1, bottom); + graphics.DrawLine (penDark, right, (advancedBorderStyle.Top != DataGridViewAdvancedCellBorderStyle.None)? top + 1 : top, right, bottom); + break; + case DataGridViewAdvancedCellBorderStyle.OutsetDouble: - graphics.DrawLine(pen, bounds.X + bounds.Width, bounds.Y, bounds.X + bounds.Width, bounds.Y + bounds.Height - 1); + graphics.DrawLine (penDark, right - 1, top, right - 1, bottom); + graphics.DrawLine (penLight, right, (advancedBorderStyle.Top != DataGridViewAdvancedCellBorderStyle.None)? top + 1 : top, right, bottom); break; } - + // Paint the top border, if any switch (advancedBorderStyle.Top) { case DataGridViewAdvancedCellBorderStyle.Single: - if (DataGridView.CellBorderStyle != DataGridViewCellBorderStyle.Single) - graphics.DrawLine(pen, bounds.X, bounds.Y, bounds.X + bounds.Width - 1, bounds.Y); + graphics.DrawLine(penGrid, left, top, right, top); break; - case DataGridViewAdvancedCellBorderStyle.Outset: - case DataGridViewAdvancedCellBorderStyle.Inset: + + case DataGridViewAdvancedCellBorderStyle.Outset: { + int _left = (advancedBorderStyle.Left == DataGridViewAdvancedCellBorderStyle.InsetDouble) || (advancedBorderStyle.Left == DataGridViewAdvancedCellBorderStyle.OutsetDouble) ? left + 1 : left; + int _right = (advancedBorderStyle.Right == DataGridViewAdvancedCellBorderStyle.Inset) || (advancedBorderStyle.Right == DataGridViewAdvancedCellBorderStyle.Outset) ? right - 1 : right; + graphics.DrawLine (penLight, _left, top, _right, top); + } break; + + case DataGridViewAdvancedCellBorderStyle.Inset: { + int _left = (advancedBorderStyle.Left == DataGridViewAdvancedCellBorderStyle.InsetDouble) || (advancedBorderStyle.Left == DataGridViewAdvancedCellBorderStyle.OutsetDouble) ? left + 1 : left; + int _right = (advancedBorderStyle.Right == DataGridViewAdvancedCellBorderStyle.Inset) || (advancedBorderStyle.Right == DataGridViewAdvancedCellBorderStyle.Outset) ? right - 1 : right; + graphics.DrawLine (penDark, _left, top, _right, top); + } break; + case DataGridViewAdvancedCellBorderStyle.InsetDouble: + graphics.DrawLine(penLight, left, top, right, top); + graphics.DrawLine(penDark, (advancedBorderStyle.Left != DataGridViewAdvancedCellBorderStyle.None)? left + 1 : left, top + 1, + (advancedBorderStyle.Right != DataGridViewAdvancedCellBorderStyle.None)? right -1 : right, top + 1); + break; + case DataGridViewAdvancedCellBorderStyle.OutsetDouble: - graphics.DrawLine(pen, bounds.X, bounds.Y, bounds.X + bounds.Width - 1, bounds.Y); + graphics.DrawLine(penDark, left, top, right, top); + graphics.DrawLine(penLight, (advancedBorderStyle.Left != DataGridViewAdvancedCellBorderStyle.None)? left + 1 : left, top + 1, + (advancedBorderStyle.Right != DataGridViewAdvancedCellBorderStyle.None)? right - 1 : right, top + 1); break; } - + // Paint the bottom border, if any switch (advancedBorderStyle.Bottom) { - case DataGridViewAdvancedCellBorderStyle.Outset: - case DataGridViewAdvancedCellBorderStyle.Inset: case DataGridViewAdvancedCellBorderStyle.Single: - case DataGridViewAdvancedCellBorderStyle.InsetDouble: - case DataGridViewAdvancedCellBorderStyle.OutsetDouble: - graphics.DrawLine(pen, bounds.X, bounds.Y + bounds.Height - 1, bounds.X + bounds.Width - 1, bounds.Y + bounds.Height - 1); + graphics.DrawLine(penGrid, left, bottom, right, bottom); + break; + + case DataGridViewAdvancedCellBorderStyle.Outset: { + int _right = (advancedBorderStyle.Right == DataGridViewAdvancedCellBorderStyle.InsetDouble) || (advancedBorderStyle.Right == DataGridViewAdvancedCellBorderStyle.OutsetDouble) ? right - 1 : right; + graphics.DrawLine (penDark, left, bottom, _right, bottom); + } break; + + case DataGridViewAdvancedCellBorderStyle.Inset: + graphics.DrawLine(penLight, left, bottom, (advancedBorderStyle.Right == DataGridViewAdvancedCellBorderStyle.InsetDouble)? right - 1: right, bottom); break; } } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/DataGridViewRow.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/DataGridViewRow.cs index 300ed426ec83..ac7d7029cd15 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/DataGridViewRow.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/DataGridViewRow.cs @@ -557,6 +557,9 @@ protected internal virtual void PaintCells (Graphics graphics, Rectangle clipBou bounds.X += DataGridView.RowHeadersWidth; bounds.Width -= DataGridView.RowHeadersWidth; } + + bool singleVerticalBorderAdded = !DataGridView.RowHeadersVisible; + bool singleHorizontalBorderAdded = !DataGridView.ColumnHeadersVisible; for (int i = DataGridView.first_col_index; i < sortedColumns.Count; i++) { DataGridViewColumn col = sortedColumns[i]; @@ -593,7 +596,7 @@ protected internal virtual void PaintCells (Graphics graphics, Rectangle clipBou } DataGridViewAdvancedBorderStyle intermediateBorderStyle = (DataGridViewAdvancedBorderStyle)((ICloneable)DataGridView.AdvancedCellBorderStyle).Clone (); - DataGridViewAdvancedBorderStyle borderStyle = cell.AdjustCellBorderStyle (DataGridView.AdvancedCellBorderStyle, intermediateBorderStyle, true, true, cell.ColumnIndex == 0, cell.RowIndex == 0); + DataGridViewAdvancedBorderStyle borderStyle = cell.AdjustCellBorderStyle (DataGridView.AdvancedCellBorderStyle, intermediateBorderStyle, singleVerticalBorderAdded, singleHorizontalBorderAdded, cell.ColumnIndex == 0, cell.RowIndex == 0); DataGridView.OnCellFormattingInternal (new DataGridViewCellFormattingEventArgs (cell.ColumnIndex, cell.RowIndex, value, cell.FormattedValueType, style)); diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/DataGridViewTextBoxCell.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/DataGridViewTextBoxCell.cs index db41c6b306f8..23f493d6e3df 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/DataGridViewTextBoxCell.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/DataGridViewTextBoxCell.cs @@ -226,7 +226,15 @@ protected override void Paint (Graphics graphics, Rectangle clipBounds, Rectangl contentbounds.Height -= cellStyle.Padding.Vertical; } - if (formattedValue != null) + const int textTopAdditionalPadding = 1; + const int textBottomAdditionalPadding = 2; + const int textLeftAdditionalPadding = 0; + const int textRightAdditionalPadding = 2; + contentbounds.Offset (textLeftAdditionalPadding, textTopAdditionalPadding); + contentbounds.Width -= textLeftAdditionalPadding + textRightAdditionalPadding; + contentbounds.Height -= textTopAdditionalPadding + textBottomAdditionalPadding; + + if (formattedValue != null && contentbounds.Width > 0 && contentbounds.Height > 0) TextRenderer.DrawText (graphics, formattedValue.ToString (), cellStyle.Font, contentbounds, color, flags); } diff --git a/mcs/class/System/Makefile b/mcs/class/System/Makefile index 48fdcfff4013..cd44f53cecb7 100644 --- a/mcs/class/System/Makefile +++ b/mcs/class/System/Makefile @@ -27,6 +27,7 @@ TEST_RESOURCES = \ Test/System/test-uri-props-manual.txt \ Test/System/test-uri-relative-props.txt +XTEST_LIB_REFS = System System.Core Facades/System.Threading.Tasks Facades/System.Runtime.InteropServices.RuntimeInformation LIB_MCS_FLAGS = -d:CONFIGURATION_2_0 $(REFERENCE_SOURCES_FLAGS) -unsafe $(RESOURCE_FILES:%=-resource:%) -nowarn:436 ifndef NO_MONO_SECURITY diff --git a/mcs/class/System/System_xtest.dll.sources b/mcs/class/System/System_xtest.dll.sources new file mode 100644 index 000000000000..db680e389d14 --- /dev/null +++ b/mcs/class/System/System_xtest.dll.sources @@ -0,0 +1,18 @@ +../../../external/corefx/src/CoreFx.Private.TestUtilities/src/System/AssertExtensions.cs + +../../../external/corefx/src/Common/tests/System/Collections/ICollection.NonGeneric.Tests.cs +../../../external/corefx/src/Common/tests/System/Collections/IEnumerable.NonGeneric.Tests.cs +../../../external/corefx/src/Common/tests/System/Collections/IList.NonGeneric.Tests.cs +../../../external/corefx/src/Common/tests/System/Collections/TestBase.NonGeneric.cs +../../../external/corefx/src/Common/tests/System/Runtime/Serialization/Formatters/BinaryFormatterHelpers.cs + +../../../external/corefx/src/System.CodeDom/tests/CodeCollections/*.cs +../../../external/corefx/src/System.CodeDom/tests/CodeExpressions/*.cs +../../../external/corefx/src/System.CodeDom/tests/CodeObjects/*.cs +../../../external/corefx/src/System.CodeDom/tests/CodeStatements/*.cs +../../../external/corefx/src/System.CodeDom/tests/CodeTypeMembers/*.cs +../../../external/corefx/src/System.CodeDom/tests/Compiler/*.cs +../../../external/corefx/src/System.CodeDom/tests/Other/*.cs +../../../external/corefx/src/System.CodeDom/tests/Microsoft/CSharp/*.cs +../../../external/corefx/src/System.CodeDom/tests/Microsoft/VisualBasic/*.cs +../../../external/corefx/src/System.CodeDom/tests/*.cs:CodeGenerationTests.cs,CSharpCodeGenerationTests.cs,VBCodeGenerationTests.cs diff --git a/mcs/class/corlib/Makefile b/mcs/class/corlib/Makefile index 9a25f2aa2c94..910f7b672f4c 100644 --- a/mcs/class/corlib/Makefile +++ b/mcs/class/corlib/Makefile @@ -94,13 +94,13 @@ LIB_MCS_FLAGS += -d:MONO_FEATURE_APPLE_X509 endif WARNING_ABOUT_DISABLED_WARNING=1635 -LOCAL_MCS_FLAGS = -unsafe -nostdlib -nowarn:612,618,3001,3003,$(WARNING_ABOUT_DISABLED_WARNING) -d:INSIDE_CORLIB,MONO_CULTURE_DATA -d:LIBC $(REFERENCE_SOURCES_FLAGS) +LOCAL_MCS_FLAGS = -unsafe -nostdlib -nowarn:612,618,3001,3002,3003,$(WARNING_ABOUT_DISABLED_WARNING) -d:INSIDE_CORLIB,MONO_CULTURE_DATA -d:LIBC $(REFERENCE_SOURCES_FLAGS) DEFAULT_REFERENCES = TEST_LIB_REFS = System.Core System -XTEST_LIB_REFS = System System.Core Facades/System.Threading.Tasks Facades/System.Runtime.InteropServices.RuntimeInformation -XTEST_LIB_FLAGS = -d:netcoreapp +XTEST_LIB_REFS = System System.Core Facades/System.Threading.Tasks Facades/System.Runtime.InteropServices.RuntimeInformation System.Numerics.Vectors System.Runtime.CompilerServices.Unsafe +XTEST_LIB_FLAGS = -d:netcoreapp -publicsign -keyfile:../mono.snk ifndef AOT_FRIENDLY_PROFILE ifneq ($(PROFILE),testing_aot_hybrid) diff --git a/mcs/class/corlib/System.Reflection.Emit/CustomAttributeBuilder.cs b/mcs/class/corlib/System.Reflection.Emit/CustomAttributeBuilder.cs index 0bb724ad8c48..a0f11bd20cdf 100644 --- a/mcs/class/corlib/System.Reflection.Emit/CustomAttributeBuilder.cs +++ b/mcs/class/corlib/System.Reflection.Emit/CustomAttributeBuilder.cs @@ -46,6 +46,11 @@ namespace System.Reflection.Emit { public class CustomAttributeBuilder : _CustomAttributeBuilder { ConstructorInfo ctor; byte[] data; + object [] args; + PropertyInfo [] namedProperties; + object [] propertyValues; + FieldInfo [] namedFields; + object [] fieldValues; internal ConstructorInfo Ctor { get {return ctor;} @@ -57,7 +62,20 @@ internal byte[] Data { [MethodImplAttribute(MethodImplOptions.InternalCall)] static extern byte[] GetBlob(Assembly asmb, ConstructorInfo con, object[] constructorArgs, PropertyInfo[] namedProperties, object[] propertyValues, FieldInfo[] namedFields, object[] fieldValues); - + + internal object Invoke () + { + object result = ctor.Invoke (args); + + for (int i=0; i < namedFields.Length; i++) + namedFields [i].SetValue (result, fieldValues [i]); + + for (int i=0; i < namedProperties.Length; i++) + namedProperties [i].SetValue (result, propertyValues [i]); + + return result; + } + internal CustomAttributeBuilder( ConstructorInfo con, byte[] binaryAttribute) { if (con == null) throw new ArgumentNullException ("con"); @@ -140,6 +158,12 @@ private void Initialize (ConstructorInfo con, object [] constructorArgs, FieldInfo [] namedFields, object [] fieldValues) { ctor = con; + args = constructorArgs; + this.namedProperties = namedProperties; + this.propertyValues = propertyValues; + this.namedFields = namedFields; + this.fieldValues = fieldValues; + if (con == null) throw new ArgumentNullException ("con"); if (constructorArgs == null) diff --git a/mcs/class/corlib/System.Reflection.Emit/ModuleBuilder.cs b/mcs/class/corlib/System.Reflection.Emit/ModuleBuilder.cs index f629f8a3861d..8744b4a45810 100644 --- a/mcs/class/corlib/System.Reflection.Emit/ModuleBuilder.cs +++ b/mcs/class/corlib/System.Reflection.Emit/ModuleBuilder.cs @@ -1169,32 +1169,55 @@ public override bool IsDefined (Type attributeType, bool inherit) public override object[] GetCustomAttributes (bool inherit) { - return base.GetCustomAttributes (inherit); + return GetCustomAttributes (null, inherit); } public override object[] GetCustomAttributes (Type attributeType, bool inherit) { - return base.GetCustomAttributes (attributeType, inherit); + if (cattrs == null || cattrs.Length == 0) + return Array.Empty (); + + if (attributeType is TypeBuilder) + throw new InvalidOperationException ("First argument to GetCustomAttributes can't be a TypeBuilder"); + + List results = new List (); + for (int i=0; i < cattrs.Length; i++) { + Type t = cattrs [i].Ctor.GetType (); + + if (t is TypeBuilder) + throw new InvalidOperationException ("Can't construct custom attribute for TypeBuilder type"); + + if (attributeType == null || attributeType.IsAssignableFrom (t)) + results.Add (cattrs [i].Invoke ()); + } + + return results.ToArray (); } public override FieldInfo GetField (string name, BindingFlags bindingAttr) { - return base.GetField (name, bindingAttr); + if (global_type_created == null) + throw new InvalidOperationException ("Module-level fields cannot be retrieved until after the CreateGlobalFunctions method has been called for the module."); + return global_type_created.GetField (name, bindingAttr); } public override FieldInfo[] GetFields (BindingFlags bindingFlags) { - return base.GetFields (bindingFlags); + if (global_type_created == null) + throw new InvalidOperationException ("Module-level fields cannot be retrieved until after the CreateGlobalFunctions method has been called for the module."); + return global_type_created.GetFields (bindingFlags); } public override MethodInfo[] GetMethods (BindingFlags bindingFlags) { - return base.GetMethods (bindingFlags); + if (global_type_created == null) + throw new InvalidOperationException ("Module-level methods cannot be retrieved until after the CreateGlobalFunctions method has been called for the module."); + return global_type_created.GetMethods (bindingFlags); } public override int MetadataToken { get { - return base.MetadataToken; + return get_MetadataToken (this); } } } diff --git a/mcs/class/corlib/System.Runtime.CompilerServices/Unsafe.cs b/mcs/class/corlib/System.Runtime.CompilerServices/Unsafe.cs index b33937a961c5..f80893f8c356 100644 --- a/mcs/class/corlib/System.Runtime.CompilerServices/Unsafe.cs +++ b/mcs/class/corlib/System.Runtime.CompilerServices/Unsafe.cs @@ -95,9 +95,24 @@ public unsafe static T Read (void* source) throw new NotImplementedException (); } + public static T ReadUnaligned (ref byte source) + { + throw new NotImplementedException (); + } + public static int SizeOf () { throw new NotImplementedException (); } + + public static ref T Subtract (ref T source, int elementOffset) + { + throw new NotImplementedException (); + } + + public static void WriteUnaligned (ref byte destination, T value) + { + throw new NotImplementedException (); + } } } diff --git a/mcs/class/corlib/System.Runtime.CompilerServices/Unsafe.il b/mcs/class/corlib/System.Runtime.CompilerServices/Unsafe.il index c002459a7ef6..957a2be4c45f 100644 --- a/mcs/class/corlib/System.Runtime.CompilerServices/Unsafe.il +++ b/mcs/class/corlib/System.Runtime.CompilerServices/Unsafe.il @@ -210,12 +210,17 @@ .method public hidebysig static !!T& AsRef(void* source) cil managed aggressiveinlining { - .locals (int32&) .maxstack 1 ldarg.0 - // Roundtrip via a local to avoid type mismatch on return that the JIT inliner chokes on. - stloc.0 - ldloc.0 + ret + } + + .method public hidebysig static !!T& AsRef(!!T& source) cil managed aggressiveinlining + { + .param [1] + .custom instance void [mscorlib]System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = ( 01 00 00 00 ) + .maxstack 1 + ldarg.0 ret } diff --git a/mcs/class/corlib/System/TimeZone.cs b/mcs/class/corlib/System/TimeZone.cs index 1cfa2ee9bcc3..ba24b44788fa 100644 --- a/mcs/class/corlib/System/TimeZone.cs +++ b/mcs/class/corlib/System/TimeZone.cs @@ -210,5 +210,18 @@ public override bool IsDaylightSavingTime (DateTime dateTime) return LocalTimeZone.IsDaylightSavingTime (dateTime); } + + + // Internal method to get timezone data. + // data[0]: start of daylight saving time (in DateTime ticks). + // data[1]: end of daylight saving time (in DateTime ticks). + // data[2]: utcoffset (in TimeSpan ticks). + // data[3]: additional offset when daylight saving (in TimeSpan ticks). + // name[0]: name of this timezone when not daylight saving. + // name[1]: name of this timezone when daylight saving. +#if UNITY + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern bool GetTimeZoneData (int year, out Int64[] data, out string[] names); +#endif } } diff --git a/mcs/class/corlib/System/TimeZoneInfo.Unity.cs b/mcs/class/corlib/System/TimeZoneInfo.Unity.cs new file mode 100644 index 000000000000..934dde9490b3 --- /dev/null +++ b/mcs/class/corlib/System/TimeZoneInfo.Unity.cs @@ -0,0 +1,136 @@ +// +// System.TimeZoneInfo helper for MonoTouch +// because the devices cannot access the file system to read the data +// +// Authors: +// Sebastien Pouliot +// +// Copyright 2011-2013 Xamarin Inc. +// +// The class can be either constructed from a string (from user code) +// or from a handle (from iphone-sharp.dll internal calls). This +// delays the creation of the actual managed string until actually +// required +// +// 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 UNITY + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Globalization; +using System.IO; + +namespace System { + + public partial class TimeZoneInfo { + enum TimeZoneData + { + DaylightSavingStartIdx, + DaylightSavingEndIdx, + UtcOffsetIdx, + AdditionalDaylightOffsetIdx + }; + + enum TimeZoneNames + { + StandardNameIdx, + DaylightNameIdx + }; + static TimeZoneInfo CreateLocalUnity () + { + Int64[] data; + string[] names; + if (!System.CurrentSystemTimeZone.GetTimeZoneData (1973, out data, out names)) + throw new NotSupportedException ("Can't get timezone name."); + + TimeSpan utcOffsetTS = TimeSpan.FromTicks(data[(int)TimeZoneData.UtcOffsetIdx]); + char utcOffsetSign = (utcOffsetTS >= TimeSpan.Zero) ? '+' : '-'; + string displayName = "(GMT" + utcOffsetSign + utcOffsetTS.ToString(@"hh\:mm") + ") Local Time"; + string standardDisplayName = names[(int)TimeZoneNames.StandardNameIdx]; + string daylightDisplayName = names[(int)TimeZoneNames.DaylightNameIdx]; + + //Create The Adjustment Rules For This TimeZoneInfo. + var adjustmentList = new List(); + for(int year = 1973; year <= 2037; year++) + { + if (!System.CurrentSystemTimeZone.GetTimeZoneData (year, out data, out names)) + continue; + + DaylightTime dlt = new DaylightTime (new DateTime (data[(int)TimeZoneData.DaylightSavingStartIdx]), + new DateTime (data[(int)TimeZoneData.DaylightSavingEndIdx]), + new TimeSpan (data[(int)TimeZoneData.AdditionalDaylightOffsetIdx])); + + DateTime dltStartTime = new DateTime(1, 1, 1).Add(dlt.Start.TimeOfDay); + DateTime dltEndTime = new DateTime(1, 1, 1).Add(dlt.End.TimeOfDay); + + if (dlt.Start == dlt.End) + continue; + + TimeZoneInfo.TransitionTime startTime = TimeZoneInfo.TransitionTime.CreateFixedDateRule(dltStartTime, dlt.Start.Month, dlt.Start.Day); + TimeZoneInfo.TransitionTime endTime = TimeZoneInfo.TransitionTime.CreateFixedDateRule(dltEndTime, dlt.End.Month, dlt.End.Day); + + + //mktime only supports dates starting in 1973, so create an adjustment rule for years before 1973 following 1973s rules + if (year == 1973) + { + TimeZoneInfo.AdjustmentRule firstRule = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(DateTime.MinValue, + new DateTime(1969, 12, 31), + dlt.Delta, + startTime, + endTime); + adjustmentList.Add(firstRule); + } + + TimeZoneInfo.AdjustmentRule rule = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(year, 1, 1), + new DateTime(year, 12, 31), + dlt.Delta, + startTime, + endTime); + adjustmentList.Add(rule); + + //mktime only supports dates up to 2037, so create an adjustment rule for years after 2037 following 2037s rules + if (year == 2037) + { + // create a max date that does not include any time of day offset to make CreateAdjustmentRule happy + var maxDate = new DateTime(DateTime.MaxValue.Year, DateTime.MaxValue.Month, DateTime.MaxValue.Day); + TimeZoneInfo.AdjustmentRule lastRule = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(2038, 1, 1), + maxDate, + dlt.Delta, + startTime, + endTime); + adjustmentList.Add(lastRule); + } + } + + return TimeZoneInfo.CreateCustomTimeZone("local", + utcOffsetTS, + displayName, + standardDisplayName, + daylightDisplayName, + adjustmentList.ToArray(), + false); + } + } +} + +#endif diff --git a/mcs/class/corlib/System/TimeZoneInfo.cs b/mcs/class/corlib/System/TimeZoneInfo.cs index a1eaf2a7cf37..b69139680789 100644 --- a/mcs/class/corlib/System/TimeZoneInfo.cs +++ b/mcs/class/corlib/System/TimeZoneInfo.cs @@ -1,5 +1,4 @@ - -/* + /* * System.TimeZoneInfo * * Author(s) @@ -122,6 +121,11 @@ private static string readlink (string path) private static bool TryGetNameFromPath (string path, out string name) { name = null; +#if UNITY + //Avoids calling readlink on webgl, which causes abort due to dlopen + if(!File.Exists(path)) + return false; +#endif var linkPath = readlink (path); if (linkPath != null) { if (Path.IsPathRooted(linkPath)) @@ -165,14 +169,28 @@ static TimeZoneInfo CreateLocal () } #endif +#if UNITY + var localTimeZoneFallback = CreateLocalUnity(); + if(localTimeZoneFallback == null) + localTimeZoneFallback = Utc; +#endif + var tz = Environment.GetEnvironmentVariable ("TZ"); if (tz != null) { if (tz == String.Empty) +#if UNITY + return localTimeZoneFallback; +#else return Utc; +#endif try { return FindSystemTimeZoneByFileName (tz, Path.Combine (TimeZoneDirectory, tz)); } catch { +#if UNITY + return localTimeZoneFallback; +#else return Utc; +#endif } } @@ -191,7 +209,11 @@ static TimeZoneInfo CreateLocal () } } +#if UNITY + return localTimeZoneFallback; +#else return Utc; +#endif } static TimeZoneInfo FindSystemTimeZoneByIdCore (string id) diff --git a/mcs/class/corlib/System/WeakAttribute.cs b/mcs/class/corlib/System/WeakAttribute.cs new file mode 100644 index 000000000000..b7a377935d1a --- /dev/null +++ b/mcs/class/corlib/System/WeakAttribute.cs @@ -0,0 +1,12 @@ +using System; + +#if MOBILE && !UNITY +namespace System { + +[AttributeUsage(AttributeTargets.Field)] +public sealed class WeakAttribute : Attribute +{ +} + +} +#endif diff --git a/mcs/class/corlib/Test/Microsoft.Win32/RegistryKeyTest.cs b/mcs/class/corlib/Test/Microsoft.Win32/RegistryKeyTest.cs index a038b6c7fdad..ea5e716e2706 100755 --- a/mcs/class/corlib/Test/Microsoft.Win32/RegistryKeyTest.cs +++ b/mcs/class/corlib/Test/Microsoft.Win32/RegistryKeyTest.cs @@ -3189,7 +3189,7 @@ public void bug79051 () // Bug Xamarin 3632 [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void TypeCastTests () { string subKeyName = Guid.NewGuid ().ToString (); diff --git a/mcs/class/corlib/Test/System.Collections.Concurrent/ConcurrentDictionaryTests.cs b/mcs/class/corlib/Test/System.Collections.Concurrent/ConcurrentDictionaryTests.cs index 75b2de89aac8..8a301bc5b147 100644 --- a/mcs/class/corlib/Test/System.Collections.Concurrent/ConcurrentDictionaryTests.cs +++ b/mcs/class/corlib/Test/System.Collections.Concurrent/ConcurrentDictionaryTests.cs @@ -67,6 +67,7 @@ public void AddWithoutDuplicateTest () } [Test] + [Category ("MultiThreaded")] public void AddParallelWithoutDuplicateTest () { ParallelTestHelper.Repeat (delegate { @@ -98,6 +99,7 @@ public void AddParallelWithoutDuplicateTest () } [Test] + [Category ("MultiThreaded")] public void RemoveParallelTest () { ParallelTestHelper.Repeat (delegate { diff --git a/mcs/class/corlib/Test/System.Collections.Concurrent/ConcurrentQueueTests.cs b/mcs/class/corlib/Test/System.Collections.Concurrent/ConcurrentQueueTests.cs index a6351e511f3a..ff92589f58ad 100644 --- a/mcs/class/corlib/Test/System.Collections.Concurrent/ConcurrentQueueTests.cs +++ b/mcs/class/corlib/Test/System.Collections.Concurrent/ConcurrentQueueTests.cs @@ -50,6 +50,7 @@ public void Setup() } [Test] + [Category ("MultiThreaded")] public void StressEnqueueTestCase () { /*ParallelTestHelper.Repeat (delegate { @@ -79,6 +80,7 @@ public void StressEnqueueTestCase () } [Test] + [Category ("MultiThreaded")] public void StressDequeueTestCase () { /*ParallelTestHelper.Repeat (delegate { @@ -116,6 +118,7 @@ public void StressDequeueTestCase () } [Test] + [Category ("MultiThreaded")] public void StressTryPeekTestCase () { ParallelTestHelper.Repeat (delegate { diff --git a/mcs/class/corlib/Test/System.Collections.Concurrent/ConcurrentStackTests.cs b/mcs/class/corlib/Test/System.Collections.Concurrent/ConcurrentStackTests.cs index 4086ede09d1b..0bc60089b355 100644 --- a/mcs/class/corlib/Test/System.Collections.Concurrent/ConcurrentStackTests.cs +++ b/mcs/class/corlib/Test/System.Collections.Concurrent/ConcurrentStackTests.cs @@ -46,6 +46,7 @@ public void Setup() } [Test] + [Category ("MultiThreaded")] public void StressPushTestCase () { /*ParallelTestHelper.Repeat (delegate { @@ -74,6 +75,7 @@ public void StressPushTestCase () } [Test] + [Category ("MultiThreaded")] public void StressPopTestCase () { /*ParallelTestHelper.Repeat (delegate { diff --git a/mcs/class/corlib/Test/System.Collections.Concurrent/ParallelConcurrentQueueTests.cs b/mcs/class/corlib/Test/System.Collections.Concurrent/ParallelConcurrentQueueTests.cs index 5f5abb60de01..59eeeb95b033 100644 --- a/mcs/class/corlib/Test/System.Collections.Concurrent/ParallelConcurrentQueueTests.cs +++ b/mcs/class/corlib/Test/System.Collections.Concurrent/ParallelConcurrentQueueTests.cs @@ -43,6 +43,7 @@ public void Setup() } [Test] + [Category ("MultiThreaded")] public void CountTestCase() { const int numThread = 5; diff --git a/mcs/class/corlib/Test/System.Collections.Concurrent/ParallelConcurrentStackTests.cs b/mcs/class/corlib/Test/System.Collections.Concurrent/ParallelConcurrentStackTests.cs index ef7758c244d8..7568a5da1768 100644 --- a/mcs/class/corlib/Test/System.Collections.Concurrent/ParallelConcurrentStackTests.cs +++ b/mcs/class/corlib/Test/System.Collections.Concurrent/ParallelConcurrentStackTests.cs @@ -43,6 +43,7 @@ public void Setup() } [Test] + [Category ("MultiThreaded")] public void CountTestCase() { const int numThread = 5; diff --git a/mcs/class/corlib/Test/System.Collections.Concurrent/PartitionerTests.cs b/mcs/class/corlib/Test/System.Collections.Concurrent/PartitionerTests.cs index e46dd7e31f57..11851a216eac 100644 --- a/mcs/class/corlib/Test/System.Collections.Concurrent/PartitionerTests.cs +++ b/mcs/class/corlib/Test/System.Collections.Concurrent/PartitionerTests.cs @@ -37,7 +37,7 @@ namespace MonoTests.System.Collections.Concurrent public class PartitionerTests { [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void PartitionerCreateIntegerWithExplicitRange () { OrderablePartitioner> partitioner = Partitioner.Create (1, 20, 5); @@ -59,7 +59,7 @@ public void PartitionerCreateIntegerWithExplicitRange () } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void PartitionerCreateLongWithExplicitRange () { OrderablePartitioner> partitioner = Partitioner.Create ((long)1, (long)20, (long)5); diff --git a/mcs/class/corlib/Test/System.Globalization/CultureInfoTest.cs b/mcs/class/corlib/Test/System.Globalization/CultureInfoTest.cs index 188fc33b5e8c..50aad5364578 100644 --- a/mcs/class/corlib/Test/System.Globalization/CultureInfoTest.cs +++ b/mcs/class/corlib/Test/System.Globalization/CultureInfoTest.cs @@ -725,6 +725,7 @@ public void DefaultThreadCurrentCulture () { } [Test] + [Category ("MultiThreaded")] public void DefaultThreadCurrentCultureIsIgnoredWhenCultureFlowsToThread () { string us_str = null; diff --git a/mcs/class/corlib/Test/System.IO/DriveInfoTest.cs b/mcs/class/corlib/Test/System.IO/DriveInfoTest.cs index e23b087a08c4..777aaad2bb1a 100644 --- a/mcs/class/corlib/Test/System.IO/DriveInfoTest.cs +++ b/mcs/class/corlib/Test/System.IO/DriveInfoTest.cs @@ -65,7 +65,7 @@ public void GetDrivesNotEmpty () } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void GetDrivesValidInfo () { var drives = DriveInfo.GetDrives (); diff --git a/mcs/class/corlib/Test/System.Reflection.Emit/DynamicMethodTest.cs b/mcs/class/corlib/Test/System.Reflection.Emit/DynamicMethodTest.cs index 4ac4f6d78f18..da29af0f406c 100644 --- a/mcs/class/corlib/Test/System.Reflection.Emit/DynamicMethodTest.cs +++ b/mcs/class/corlib/Test/System.Reflection.Emit/DynamicMethodTest.cs @@ -470,7 +470,7 @@ public void GetCustomAttributes () public delegate object RetObj(); [Test] //#640702 - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void GetCurrentMethodWorksWithDynamicMethods () { DynamicMethod dm = new DynamicMethod("Foo", typeof(object), null); @@ -527,7 +527,7 @@ public static void Handler (Exception e) } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void ExceptionHandling () { var method = new DynamicMethod ("", typeof(void), new[] { typeof(int) }, typeof (DynamicMethodTest)); @@ -594,7 +594,7 @@ public static void Handler (Exception e) } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void ExceptionHandlingWithExceptionDispatchInfo () { var method = new DynamicMethod ("", typeof(void), new[] { typeof(int) }, typeof (DynamicMethodTest)); @@ -652,7 +652,7 @@ static Func EmitDelegate (DynamicMethod dm) { } [Test] //see bxc #59334 - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void ExceptionWrapping () { AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly (new AssemblyName ("ehatevfheiw"), AssemblyBuilderAccess.Run); diff --git a/mcs/class/corlib/Test/System.Reflection.Emit/MethodBuilderTest.cs b/mcs/class/corlib/Test/System.Reflection.Emit/MethodBuilderTest.cs index 5d0a4978351c..51739a306ec0 100644 --- a/mcs/class/corlib/Test/System.Reflection.Emit/MethodBuilderTest.cs +++ b/mcs/class/corlib/Test/System.Reflection.Emit/MethodBuilderTest.cs @@ -1024,7 +1024,7 @@ public static void VarargMethod (string headline, __arglist) { } [Test]//bug #626441 - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void CanCallVarargMethods () { var tb = module.DefineType ("foo"); diff --git a/mcs/class/corlib/Test/System.Reflection.Emit/ModuleBuilderTest.cs b/mcs/class/corlib/Test/System.Reflection.Emit/ModuleBuilderTest.cs index e2574908f457..c1ae91971f91 100644 --- a/mcs/class/corlib/Test/System.Reflection.Emit/ModuleBuilderTest.cs +++ b/mcs/class/corlib/Test/System.Reflection.Emit/ModuleBuilderTest.cs @@ -116,7 +116,6 @@ public void TestGlobalData () } [Test] - [Category("NotWorking")] public void TestGlobalMethods () { AssemblyBuilder builder = genAssembly (); @@ -859,5 +858,209 @@ public void GetType () Assert.AreEqual ("t1&", module.GetType ("t1&").FullName); Assert.AreEqual ("t1[]&", module.GetType ("t1[]&").FullName); } + + [AttributeUsage(AttributeTargets.All)] + public class MyAttribute : Attribute { + public String Contents; + public MyAttribute (String contents) + { + this.Contents = contents; + } + } + + [Test] + public void GetMethodsBeforeInstantiation () + { + AssemblyBuilder assm = AssemblyBuilder.DefineDynamicAssembly (new AssemblyName ("Name"), AssemblyBuilderAccess.Run); + ModuleBuilder module = assm.DefineDynamicModule ("Module"); + + // Added to make sure fields and methods not mixed up by getters + FieldBuilder fieldBuilder = module.DefineInitializedData ("GlobalField", new byte[4], FieldAttributes.Public); + + MethodBuilder method = module.DefinePInvokeMethod ("printf", "libc.so", + MethodAttributes.PinvokeImpl | MethodAttributes.Static | MethodAttributes.Public, + CallingConventions.Standard, typeof (void), new Type [] { typeof (string) }, CallingConvention.Winapi, + CharSet.Auto); + method.SetImplementationFlags (MethodImplAttributes.PreserveSig | + method.GetMethodImplementationFlags ()); + + module.CreateGlobalFunctions (); + + // Make sure method is defined, but field is not + Assert.AreEqual (1, module.GetMethods (BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance).Length); + } + + [Test] + public void GetFieldsBeforeInstantiation () + { + AssemblyBuilder assm = AssemblyBuilder.DefineDynamicAssembly (new AssemblyName ("Name"), AssemblyBuilderAccess.Run); + ModuleBuilder module = assm.DefineDynamicModule ("Module"); + FieldBuilder fieldBuilder = module.DefineInitializedData ("GlobalField", new byte[4], FieldAttributes.Public); + module.CreateGlobalFunctions (); + + var fieldG = module.GetField (fieldBuilder.Name); + Assert.IsNotNull (fieldG); + Assert.AreEqual (1, module.GetFields (BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance).Length); + } + + [Test] + public void GetCustomAttributesBeforeInstantiation () + { + AssemblyBuilder assm = AssemblyBuilder.DefineDynamicAssembly (new AssemblyName ("Name"), AssemblyBuilderAccess.Run); + ModuleBuilder module = assm.DefineDynamicModule ("Module"); + module.CreateGlobalFunctions (); + + ConstructorInfo ctor = typeof(MyAttribute).GetConstructor (new Type [] {typeof(String)}); + ctor.GetHashCode (); + CustomAttributeBuilder cab = new CustomAttributeBuilder (ctor, new object [] {"hi"}); + module.SetCustomAttribute (cab); + + Assert.AreEqual (1, module.GetCustomAttributes (false).Length); + Assert.AreEqual (typeof (MyAttribute), ((MyAttribute) module.GetCustomAttributes (false)[0]).GetType ()); + Assert.AreEqual ("hi", ((MyAttribute) module.GetCustomAttributes (false)[0]).Contents); + } + + [Test] + public void GetCustomAttributesIgnoresArg () + { + AssemblyBuilder assm = AssemblyBuilder.DefineDynamicAssembly (new AssemblyName ("Name"), AssemblyBuilderAccess.Run); + ModuleBuilder module = assm.DefineDynamicModule ("Module"); + module.CreateGlobalFunctions (); + + ConstructorInfo ctor = typeof(MyAttribute).GetConstructor (new Type [] {typeof(String)}); + ctor.GetHashCode (); + CustomAttributeBuilder cab = new CustomAttributeBuilder (ctor, new object [] {"hi"}); + module.SetCustomAttribute (cab); + + var first = module.GetCustomAttributes (false); + var second = module.GetCustomAttributes (true); + + Assert.AreEqual (first.Length, second.Length); + + for (int i=0; i < first.Length; i++) + Assert.AreEqual (first [i].GetType (), second [i].GetType ()); + + Assert.AreEqual ("hi", ((MyAttribute) first [0]).Contents); + Assert.AreEqual ("hi", ((MyAttribute) second [0]).Contents); + } + + [Test] + public void GetCustomAttributesThrowsUnbakedAttributeType () + { + AssemblyBuilder assm = AssemblyBuilder.DefineDynamicAssembly (new AssemblyName ("Name"), AssemblyBuilderAccess.Run); + ModuleBuilder module = assm.DefineDynamicModule ("Module"); + TypeBuilder tb = module.DefineType ("foo"); + module.CreateGlobalFunctions (); + + ConstructorInfo ctor = typeof(MyAttribute).GetConstructor (new Type [] {typeof(String)}); + ctor.GetHashCode (); + CustomAttributeBuilder cab = new CustomAttributeBuilder (ctor, new object [] {"hi"}); + module.SetCustomAttribute (cab); + + try { + module.GetCustomAttributes (tb, false); + } + catch (InvalidOperationException e) { + // Correct behavior + return; + } + + Assert.Fail ("Supposed to throw"); + } + + [Test] + public void GetExternalTypeBuilderCAttr () + { + AssemblyBuilder assm = AssemblyBuilder.DefineDynamicAssembly (new AssemblyName ("Name"), AssemblyBuilderAccess.Run); + ModuleBuilder module = assm.DefineDynamicModule ("Module"); + + ModuleBuilder module_two = assm.DefineDynamicModule ("ModuleTwo"); + TypeBuilder tb = module_two.DefineType ("foo"); + + ConstructorInfo ctor = tb.DefineConstructor (MethodAttributes.Public, CallingConventions.Standard, Type.EmptyTypes); + CustomAttributeBuilder cab = new CustomAttributeBuilder (ctor, Array.Empty ()); + + // Set the custom attribute to have a type builder from another module + module.SetCustomAttribute (cab); + + module.CreateGlobalFunctions (); + + try { + module.GetCustomAttributes (false); + } + catch (NotSupportedException e) { + // Correct behavior + return; + } + Assert.Fail ("Supposed to throw"); + } + + [Test] + public void GetFieldsNoGlobalType () + { + AssemblyBuilder assm = AssemblyBuilder.DefineDynamicAssembly (new AssemblyName ("Name"), AssemblyBuilderAccess.Run); + ModuleBuilder module = assm.DefineDynamicModule ("Module"); + FieldBuilder fieldBuilder = module.DefineInitializedData ("GlobalField", new byte[4], FieldAttributes.Public); + + try { + module.GetFields (BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance); + } + catch (InvalidOperationException e) { + // Correct behavior + return; + } + Assert.Fail ("Supposed to throw"); + } + + [Test] + public void GetFieldNoGlobalType () + { + AssemblyBuilder assm = AssemblyBuilder.DefineDynamicAssembly (new AssemblyName ("Name"), AssemblyBuilderAccess.Run); + ModuleBuilder module = assm.DefineDynamicModule ("Module"); + FieldBuilder fieldBuilder = module.DefineInitializedData ("GlobalField", new byte[4], FieldAttributes.Public); + + try { + module.GetField (fieldBuilder.Name); + } + catch (InvalidOperationException e) { + // Correct behavior + return; + } + Assert.Fail ("Supposed to throw"); + } + + [Test] + public void GetMethodsNoGlobalType () + { + AssemblyBuilder assm = AssemblyBuilder.DefineDynamicAssembly (new AssemblyName ("Name"), AssemblyBuilderAccess.Run); + ModuleBuilder module = assm.DefineDynamicModule ("Module"); + FieldBuilder fieldBuilder = module.DefineInitializedData ("GlobalField", new byte[4], FieldAttributes.Public); + + MethodBuilder method = module.DefinePInvokeMethod ("printf", "libc.so", + MethodAttributes.PinvokeImpl | MethodAttributes.Static | MethodAttributes.Public, + CallingConventions.Standard, typeof (void), new Type [] { typeof (string) }, CallingConvention.Winapi, + CharSet.Auto); + method.SetImplementationFlags (MethodImplAttributes.PreserveSig | + method.GetMethodImplementationFlags ()); + + try { + module.GetMethods (BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance); + } + catch (InvalidOperationException e) { + // Correct behavior + return; + } + Assert.Fail ("Supposed to throw"); + } + + [Test] + public void GetMetadataToken () + { + AssemblyBuilder assm = AssemblyBuilder.DefineDynamicAssembly (new AssemblyName ("Name"), AssemblyBuilderAccess.Run); + ModuleBuilder module = assm.DefineDynamicModule ("Module"); + module.CreateGlobalFunctions (); + Assert.AreEqual (0, module.MetadataToken); + } + } } diff --git a/mcs/class/corlib/Test/System.Reflection.Emit/TypeBuilderTest.cs b/mcs/class/corlib/Test/System.Reflection.Emit/TypeBuilderTest.cs index ebc7cb573f57..ecf68042d94f 100644 --- a/mcs/class/corlib/Test/System.Reflection.Emit/TypeBuilderTest.cs +++ b/mcs/class/corlib/Test/System.Reflection.Emit/TypeBuilderTest.cs @@ -1212,7 +1212,7 @@ public void DefineDefaultConstructor () } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void DefineDefaultConstructor_Parent_DefaultCtorInaccessible () { TypeBuilder tb; diff --git a/mcs/class/corlib/Test/System.Runtime.CompilerServices/ConditionalWeakTableTest.cs b/mcs/class/corlib/Test/System.Runtime.CompilerServices/ConditionalWeakTableTest.cs index 5483974809be..a7a8a55fcb89 100644 --- a/mcs/class/corlib/Test/System.Runtime.CompilerServices/ConditionalWeakTableTest.cs +++ b/mcs/class/corlib/Test/System.Runtime.CompilerServices/ConditionalWeakTableTest.cs @@ -192,6 +192,7 @@ static void FillStuff (ConditionalWeakTable cwt, } [Test] + [Category ("MultiThreaded")] public void Reachability () { if (GC.MaxGeneration == 0) /*Boehm doesn't handle ephemerons */ Assert.Ignore ("Not working on Boehm."); @@ -241,6 +242,7 @@ static List FillWithNetwork (ConditionalWeakTable } [Test] + [Category ("MultiThreaded")] public void InsertStress () { if (GC.MaxGeneration == 0) /*Boehm doesn't handle ephemerons */ Assert.Ignore ("Not working on Boehm."); @@ -289,6 +291,7 @@ static List FillReachable (ConditionalWeakTable [] cwt) } [Test] + [Category ("MultiThreaded")] public void OldGenStress () { if (GC.MaxGeneration == 0) /*Boehm doesn't handle ephemerons */ Assert.Ignore ("Not working on Boehm."); @@ -431,6 +434,7 @@ static void FillWithFinalizable (ConditionalWeakTable cwt) } [Test] + [Category ("MultiThreaded")] public void FinalizableObjectsThatRetainDeadKeys () { if (GC.MaxGeneration == 0) /*Boehm doesn't handle ephemerons */ diff --git a/mcs/class/corlib/Test/System.Runtime.CompilerServices/RuntimeHelpersTest.cs b/mcs/class/corlib/Test/System.Runtime.CompilerServices/RuntimeHelpersTest.cs index 108680d10ad1..badc2a6501c4 100644 --- a/mcs/class/corlib/Test/System.Runtime.CompilerServices/RuntimeHelpersTest.cs +++ b/mcs/class/corlib/Test/System.Runtime.CompilerServices/RuntimeHelpersTest.cs @@ -205,6 +205,7 @@ public void TestEquals () } [Test] + [Category ("MultiThreaded")] public void TestEnsureSufficientExecutionStack () { var t = new Thread (() => { diff --git a/mcs/class/corlib/Test/System.Runtime.ExceptionServices/ExceptionDispatchInfoTest.cs b/mcs/class/corlib/Test/System.Runtime.ExceptionServices/ExceptionDispatchInfoTest.cs index 1e1c308bdbb2..c17199476c56 100644 --- a/mcs/class/corlib/Test/System.Runtime.ExceptionServices/ExceptionDispatchInfoTest.cs +++ b/mcs/class/corlib/Test/System.Runtime.ExceptionServices/ExceptionDispatchInfoTest.cs @@ -66,7 +66,7 @@ public void Capture () } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void Throw () { Exception orig = null; @@ -93,7 +93,7 @@ public void Throw () } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void ThrowWithEmptyFrames () { var edi = ExceptionDispatchInfo.Capture (new OperationCanceledException ()); @@ -108,7 +108,7 @@ public void ThrowWithEmptyFrames () } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void LastThrowWins () { Exception e; @@ -140,7 +140,7 @@ public void LastThrowWins () } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void ThrowMultipleCaptures () { Exception e; @@ -169,7 +169,7 @@ public void ThrowMultipleCaptures () } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void StackTraceUserCopy () { try { diff --git a/mcs/class/corlib/Test/System.Runtime.InteropServices/MarshalTest.cs b/mcs/class/corlib/Test/System.Runtime.InteropServices/MarshalTest.cs index a59293153be3..055f6bdaa5a5 100644 --- a/mcs/class/corlib/Test/System.Runtime.InteropServices/MarshalTest.cs +++ b/mcs/class/corlib/Test/System.Runtime.InteropServices/MarshalTest.cs @@ -963,7 +963,7 @@ public class Derived : Base } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void CheckPtrToStructureWithFixedArrayAndBaseClassFields() { const int arraySize = 6; diff --git a/mcs/class/corlib/Test/System.Runtime.Remoting.Proxies/RealProxyTest.cs b/mcs/class/corlib/Test/System.Runtime.Remoting.Proxies/RealProxyTest.cs index 6ac508c97300..6f2a158a0ac4 100644 --- a/mcs/class/corlib/Test/System.Runtime.Remoting.Proxies/RealProxyTest.cs +++ b/mcs/class/corlib/Test/System.Runtime.Remoting.Proxies/RealProxyTest.cs @@ -28,7 +28,7 @@ public override IMessage Invoke (IMessage msg) } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void InterfaceProxyGetTypeOkay () { // Regression test for #17325 diff --git a/mcs/class/corlib/Test/System.Runtime.Remoting/ContextTest.cs b/mcs/class/corlib/Test/System.Runtime.Remoting/ContextTest.cs index 2fcf05d0367c..1ed6d8fee792 100644 --- a/mcs/class/corlib/Test/System.Runtime.Remoting/ContextTest.cs +++ b/mcs/class/corlib/Test/System.Runtime.Remoting/ContextTest.cs @@ -40,7 +40,7 @@ public class ContextTest LocalDataStoreSlot slot; [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void TestDoCallback () { otherCtx = cbo.GetContext (); @@ -55,7 +55,7 @@ void DelegateTarget () } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void TestDatastore () { otherCtx = cbo.GetContext (); diff --git a/mcs/class/corlib/Test/System.Runtime.Remoting/SynchronizationAttributeTest.cs b/mcs/class/corlib/Test/System.Runtime.Remoting/SynchronizationAttributeTest.cs index 0c4bee45e889..2f2c02881611 100644 --- a/mcs/class/corlib/Test/System.Runtime.Remoting/SynchronizationAttributeTest.cs +++ b/mcs/class/corlib/Test/System.Runtime.Remoting/SynchronizationAttributeTest.cs @@ -146,7 +146,7 @@ public class SynchronizationAttributeTest bool otResult; [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void TestSynchronization () { Thread tr = new Thread (new ThreadStart (FirstSyncThread)); @@ -170,7 +170,7 @@ void SecondSyncThread () } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void TestSupported () { SincroRequiresNew ob = new SincroRequiresNew (); @@ -183,7 +183,7 @@ public void TestSupported () } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void TestRequired () { SincroRequiresNew ob = new SincroRequiresNew (); @@ -196,7 +196,7 @@ public void TestRequired () } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void TestRequiresNew () { SincroRequiresNew ob = new SincroRequiresNew (); @@ -209,7 +209,7 @@ public void TestRequiresNew () } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void TestNotSupported () { SincroRequiresNew ob = new SincroRequiresNew (); @@ -222,7 +222,7 @@ public void TestNotSupported () } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void TestLocked1 () { sincob.Lock (false); @@ -237,7 +237,7 @@ public void TestLocked1 () } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void TestLocked2 () { Thread tr = new Thread (new ThreadStart (FirstNotSyncThread)); @@ -261,7 +261,7 @@ void SecondNotSyncThread () } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void TestLocked3 () { Thread tr = new Thread (new ThreadStart (Lock1Thread)); @@ -281,7 +281,7 @@ void Lock2Thread () } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void TestReentry () { Thread tr = new Thread (new ThreadStart (FirstReentryThread)); @@ -305,7 +305,7 @@ void SecondReentryThread () } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void TestNoReentry () { Thread tr = new Thread (new ThreadStart (FirstNoReentryThread)); @@ -329,7 +329,7 @@ void SecondNoReentryThread () } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void TestCallback () { Thread tr = new Thread (new ThreadStart (CallbackThread)); @@ -344,7 +344,7 @@ public void TestCallback () } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void TestSynchronizationReleasedOnMultipleAcquire () { @@ -367,7 +367,7 @@ void CallbackThread () [Test] [Category("NotDotNet")] [Category ("MobileNotWorking")] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void TestMonitorWait () { Thread tr = new Thread (new ThreadStart (DoMonitorPulse)); diff --git a/mcs/class/corlib/Test/System.Runtime.Serialization/SerializationTest.cs b/mcs/class/corlib/Test/System.Runtime.Serialization/SerializationTest.cs index 8bfd75d15696..aa677741266d 100644 --- a/mcs/class/corlib/Test/System.Runtime.Serialization/SerializationTest.cs +++ b/mcs/class/corlib/Test/System.Runtime.Serialization/SerializationTest.cs @@ -30,7 +30,7 @@ public class SerializationTest #if FEATURE_REMOTING [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void TestSerialization () { MethodTester mt = new MethodTester(); diff --git a/mcs/class/corlib/Test/System.Threading.Tasks/TaskTest.cs b/mcs/class/corlib/Test/System.Threading.Tasks/TaskTest.cs index 2bc45681cebc..987016b0f092 100644 --- a/mcs/class/corlib/Test/System.Threading.Tasks/TaskTest.cs +++ b/mcs/class/corlib/Test/System.Threading.Tasks/TaskTest.cs @@ -984,6 +984,7 @@ public void RunSynchronouslyOnContinuation () } [Test] + [Category ("MultiThreaded")] public void UnobservedExceptionOnFinalizerThreadTest () { bool wasCalled = false; diff --git a/mcs/class/corlib/Test/System.Threading/CountdownEventTests.cs b/mcs/class/corlib/Test/System.Threading/CountdownEventTests.cs index 9f1d87cc0d0b..1f98c17f1f1a 100644 --- a/mcs/class/corlib/Test/System.Threading/CountdownEventTests.cs +++ b/mcs/class/corlib/Test/System.Threading/CountdownEventTests.cs @@ -101,6 +101,7 @@ public void AddCount_HasBeenSet () } [Test] + [Category ("MultiThreaded")] public void AddCountSignalStressTestCase () { var evt = new CountdownEvent (5); @@ -352,6 +353,7 @@ public void TryAddCount_HasBeenSet () } [Test] + [Category ("MultiThreaded")] public void WaitTestCase() { var evt = new CountdownEvent (5); diff --git a/mcs/class/corlib/Test/System.Threading/InterlockedTest.cs b/mcs/class/corlib/Test/System.Threading/InterlockedTest.cs index e98980d85745..45cb62157058 100644 --- a/mcs/class/corlib/Test/System.Threading/InterlockedTest.cs +++ b/mcs/class/corlib/Test/System.Threading/InterlockedTest.cs @@ -99,7 +99,7 @@ public void TestCompareExchange_Int32 () } [Test] - [Category ("InterpreterNotWorking")] /* crashes on linux/armv7 */ + [Category ("NotWorkingRuntimeInterpreter")] /* crashes on linux/armv7 */ public void TestCompareExchange_Flt () { flt = flt_1; diff --git a/mcs/class/corlib/Test/System.Threading/ManualResetEventSlimTests.cs b/mcs/class/corlib/Test/System.Threading/ManualResetEventSlimTests.cs index b1cb401ef470..b96903485f48 100644 --- a/mcs/class/corlib/Test/System.Threading/ManualResetEventSlimTests.cs +++ b/mcs/class/corlib/Test/System.Threading/ManualResetEventSlimTests.cs @@ -83,6 +83,7 @@ public void IsSetTestCase() } [Test] + [Category ("MultiThreaded")] public void WaitTest() { int count = 0; diff --git a/mcs/class/corlib/Test/System.Threading/MutexTest.cs b/mcs/class/corlib/Test/System.Threading/MutexTest.cs index ee3e58860494..f7d421ae411e 100644 --- a/mcs/class/corlib/Test/System.Threading/MutexTest.cs +++ b/mcs/class/corlib/Test/System.Threading/MutexTest.cs @@ -124,6 +124,7 @@ public void TestCtorCtor3() */ [Test] + [Category ("MultiThreaded")] public void TestWaitAndSignal1() { Mutex Sem = new Mutex (false); @@ -143,6 +144,7 @@ public void TestWaitAndSignal1() } [Test] + [Category ("MultiThreaded")] public void TestWaitAndForget1() { Mutex Sem = new Mutex(false); diff --git a/mcs/class/corlib/Test/System.Threading/ReaderWriterLockTest.cs b/mcs/class/corlib/Test/System.Threading/ReaderWriterLockTest.cs index ef398486a2ab..3253868dca0b 100644 --- a/mcs/class/corlib/Test/System.Threading/ReaderWriterLockTest.cs +++ b/mcs/class/corlib/Test/System.Threading/ReaderWriterLockTest.cs @@ -60,6 +60,7 @@ ThreadRunner StartThread (ThreadStart ts) } [Test] + [Category ("MultiThreaded")] public void TestIsReaderLockHeld () { rwlock = new ReaderWriterLock (); @@ -76,6 +77,7 @@ private void IsReaderLockHeld_2 () } [Test] + [Category ("MultiThreaded")] public void TestIsWriterLockHeld () { rwlock = new ReaderWriterLock (); @@ -92,6 +94,7 @@ private void IsWriterLockHeld_2 () } [Test] + [Category ("MultiThreaded")] public void TestAcquireLocks () { rwlock = new ReaderWriterLock (); @@ -157,6 +160,7 @@ void AcquireLock_readerFails () } [Test] + [Category ("MultiThreaded")] public void TestReleaseRestoreReaderLock () { rwlock = new ReaderWriterLock (); @@ -177,6 +181,7 @@ public void TestReleaseRestoreReaderLock () } [Test] + [Category ("MultiThreaded")] public void TestReleaseRestoreWriterLock () { rwlock = new ReaderWriterLock (); @@ -197,6 +202,7 @@ public void TestReleaseRestoreWriterLock () } [Test] + [Category ("MultiThreaded")] public void TestUpgradeDowngradeLock () { rwlock = new ReaderWriterLock (); @@ -244,6 +250,7 @@ public void TestReaderInsideWriter () } [Test] + [Category ("MultiThreaded")] public void TestReaderMustWaitWriter () { // A thread cannot get the reader lock if there are other threads @@ -286,6 +293,7 @@ public void TestBug_55911 () } [Test] + [Category ("MultiThreaded")] public void TestBug_55909 () { rwlock = new ReaderWriterLock (); @@ -313,6 +321,7 @@ public void Bug_55909_Thread2 () } [Test] + [Category ("MultiThreaded")] public void TestBug_55909_bis () { rwlock = new ReaderWriterLock (); diff --git a/mcs/class/corlib/Test/System.Threading/SemaphoreSlimTests.cs b/mcs/class/corlib/Test/System.Threading/SemaphoreSlimTests.cs index eb07f467fd04..613f8cad0ef3 100644 --- a/mcs/class/corlib/Test/System.Threading/SemaphoreSlimTests.cs +++ b/mcs/class/corlib/Test/System.Threading/SemaphoreSlimTests.cs @@ -65,6 +65,7 @@ public void CurrentCountTestCase() } [Test] + [Category ("MultiThreaded")] public void WaitStressTest() { int count = -1; diff --git a/mcs/class/corlib/Test/System.Threading/SpinLockTests.cs b/mcs/class/corlib/Test/System.Threading/SpinLockTests.cs index 80865e5eb067..82ca039a0590 100644 --- a/mcs/class/corlib/Test/System.Threading/SpinLockTests.cs +++ b/mcs/class/corlib/Test/System.Threading/SpinLockTests.cs @@ -111,6 +111,7 @@ internal class SpinLockWrapper } [Test] + [Category ("MultiThreaded")] public void LockUnicityTest () { ParallelTestHelper.Repeat (delegate { diff --git a/mcs/class/corlib/Test/System.Threading/ThreadLocalTests.cs b/mcs/class/corlib/Test/System.Threading/ThreadLocalTests.cs index b65d150bb581..bbd1a6f280a4 100644 --- a/mcs/class/corlib/Test/System.Threading/ThreadLocalTests.cs +++ b/mcs/class/corlib/Test/System.Threading/ThreadLocalTests.cs @@ -52,6 +52,7 @@ public void SingleThreadTest () } [Test] + [Category ("MultiThreaded")] public void ThreadedTest () { AssertThreadLocal (); @@ -134,6 +135,7 @@ public void DisposedOnIsValueCreatedTest () } [Test] + [Category ("MultiThreaded")] public void PerThreadException () { int callTime = 0; diff --git a/mcs/class/corlib/Test/System.Threading/ThreadTest.cs b/mcs/class/corlib/Test/System.Threading/ThreadTest.cs index 854cea5d7d8a..73fccd712bcd 100644 --- a/mcs/class/corlib/Test/System.Threading/ThreadTest.cs +++ b/mcs/class/corlib/Test/System.Threading/ThreadTest.cs @@ -252,6 +252,7 @@ public void CultureInfo_Shared_Across_Threads () } [Test] // bug #325566 + [Category ("MultiThreaded")] public void GetHashCodeTest () { C1Test test1 = new C1Test (); @@ -281,6 +282,7 @@ public void GetHashCodeTest () } [Test] // bug #82700 + [Category ("MultiThreaded")] public void ManagedThreadId () { C1Test test1 = new C1Test (); @@ -307,7 +309,7 @@ public void ManagedThreadId () [Test] [Category ("NotDotNet")] // it hangs. - [Category ("InterpreterNotWorking")] /* crashes on linux/arm64 */ + [Category ("NotWorkingRuntimeInterpreter")] /* crashes on linux/arm64 */ public void TestStart() { { @@ -349,6 +351,7 @@ public void TestStart() } [Test] + [Category ("MultiThreaded")] public void TestApartmentState () { C2Test test1 = new C2Test(); @@ -450,7 +453,7 @@ public void TestPriority3() } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void TestUndivisibleByPageSizeMaxStackSize () { const int undivisible_stacksize = 1048573; @@ -461,6 +464,7 @@ public void TestUndivisibleByPageSizeMaxStackSize () } [Test] + [Category ("MultiThreaded")] public void TestIsBackground1 () { C2Test test1 = new C2Test(); @@ -480,6 +484,7 @@ public void TestIsBackground1 () } [Test] + [Category ("MultiThreaded")] public void TestIsBackground2 () { C2Test test1 = new C2Test(); @@ -505,6 +510,7 @@ public void TestIsBackground2 () } [Test] + [Category ("MultiThreaded")] public void TestName() { C2Test test1 = new C2Test(); @@ -545,6 +551,7 @@ public void Rename () } [Test] + [Category ("MultiThreaded")] public void TestNestedThreads1() { C3Test test1 = new C3Test(); @@ -562,6 +569,7 @@ public void TestNestedThreads1() } [Test] + [Category ("MultiThreaded")] public void TestNestedThreads2() { C4Test test1 = new C4Test(); @@ -578,6 +586,7 @@ public void TestNestedThreads2() } [Test] + [Category ("MultiThreaded")] public void TestJoin1() { C1Test test1 = new C1Test(); @@ -664,6 +673,7 @@ public void SpinWait () } [Test] + [Category ("MultiThreaded")] public void TestThreadState () { //TODO: Test The rest of the possible transitions @@ -768,6 +778,7 @@ public void IPrincipal_CopyOnNewThread () #if MONO_FEATURE_THREAD_SUSPEND_RESUME [Test] + [Category ("MultiThreaded")] public void TestSuspend () { Thread t = new Thread (new ThreadStart (DoCount)); @@ -795,6 +806,7 @@ public void TestSuspend () #if MONO_FEATURE_THREAD_SUSPEND_RESUME && MONO_FEATURE_THREAD_ABORT [Test] [Category("NotDotNet")] // On MS, ThreadStateException is thrown on Abort: "Thread is suspended; attempting to abort" + [Category ("MultiThreaded")] public void TestSuspendAbort () { Thread t = new Thread (new ThreadStart (DoCount)); @@ -982,6 +994,7 @@ void Start () } [Test] // bug #81720 + [Category ("MultiThreaded")] public void IsBackGround () { Thread t1 = new Thread (new ThreadStart (Start)); @@ -1020,6 +1033,7 @@ public void IsBackGround () } [Test] // bug #60031 + [Category ("MultiThreaded")] public void StoppedThreadsThrowThreadStateException () { var t = new Thread (() => { }); @@ -1148,6 +1162,7 @@ void Start () } [Test] // bug #81658 + [Category ("MultiThreaded")] public void ApartmentState_StoppedThread () { Thread t1 = new Thread (new ThreadStart (Start)); @@ -1187,6 +1202,7 @@ public void ApartmentState_BackGround () } [Test] + [Category ("MultiThreaded")] public void TestApartmentState () { Thread t1 = new Thread (new ThreadStart (Start)); @@ -1251,6 +1267,7 @@ public void TestSetApartmentStateDiffState () } [Test] + [Category ("MultiThreaded")] public void TestTrySetApartmentState () { Thread t1 = new Thread (new ThreadStart (Start)); @@ -1265,6 +1282,7 @@ public void TestTrySetApartmentState () } [Test] + [Category ("MultiThreaded")] public void TestTrySetApartmentStateRunning () { Thread t1 = new Thread (new ThreadStart (Start)); @@ -1301,6 +1319,7 @@ public void Culture () } [Test] + [Category ("MultiThreaded")] public void ThreadStartSimple () { int i = 0; @@ -1314,6 +1333,7 @@ public void ThreadStartSimple () } [Test] + [Category ("MultiThreaded")] public void ParametrizedThreadStart () { int i = 0; diff --git a/mcs/class/corlib/Test/System.Threading/WaitHandleTest.cs b/mcs/class/corlib/Test/System.Threading/WaitHandleTest.cs index 723da25bebfb..8f5692efef6b 100644 --- a/mcs/class/corlib/Test/System.Threading/WaitHandleTest.cs +++ b/mcs/class/corlib/Test/System.Threading/WaitHandleTest.cs @@ -317,6 +317,7 @@ public void WaitAny_Empty () } [Test] + [Category ("MultiThreaded")] public void InterrupedWaitAny () { using (var m1 = new Mutex (true)) { @@ -345,6 +346,7 @@ public void InterrupedWaitAny () } [Test] + [Category ("MultiThreaded")] public void InterrupedWaitAll () { using (var m1 = new Mutex (true)) { @@ -373,6 +375,7 @@ public void InterrupedWaitAll () } [Test] + [Category ("MultiThreaded")] public void InterrupedWaitOne () { using (var m1 = new Mutex (true)) { @@ -398,6 +401,7 @@ public void InterrupedWaitOne () } [Test] + [Category ("MultiThreaded")] public void WaitOneWithAbandonedMutex () { using (var m = new Mutex (false)) { @@ -432,6 +436,7 @@ public void WaitOneWithAbandonedMutex () } [Test] + [Category ("MultiThreaded")] public void WaitOneWithAbandonedMutexAndMultipleThreads () { using (var m = new Mutex (true)) { @@ -465,6 +470,7 @@ public void WaitOneWithAbandonedMutexAndMultipleThreads () } [Test] + [Category ("MultiThreaded")] public void WaitAnyWithSecondMutexAbandoned () { using (var m1 = new Mutex (false)) { @@ -525,6 +531,7 @@ public void WaitAnyWithSecondMutexAbandoned () [Test] [ExpectedException (typeof (AbandonedMutexException))] + [Category ("MultiThreaded")] public void WaitAllWithOneAbandonedMutex () { using (var m1 = new Mutex (false)) { @@ -541,6 +548,7 @@ public void WaitAllWithOneAbandonedMutex () #if MONO_FEATURE_THREAD_SUSPEND_RESUME [Test] + [Category ("MultiThreaded")] public void WaitOneWithTimeoutAndSpuriousWake () { /* This is to test that WaitEvent.WaitOne is not going to wait largely @@ -570,6 +578,7 @@ public void WaitOneWithTimeoutAndSpuriousWake () } [Test] + [Category ("MultiThreaded")] public void WaitAnyWithTimeoutAndSpuriousWake () { /* This is to test that WaitEvent.WaitAny is not going to wait largely @@ -600,6 +609,7 @@ public void WaitAnyWithTimeoutAndSpuriousWake () } [Test] + [Category ("MultiThreaded")] public void WaitAllWithTimeoutAndSpuriousWake () { /* This is to test that WaitEvent.WaitAll is not going to wait largely diff --git a/mcs/class/corlib/Test/System/ConvertTest.cs b/mcs/class/corlib/Test/System/ConvertTest.cs index 8f9fe1c0099a..7dddddb510af 100644 --- a/mcs/class/corlib/Test/System/ConvertTest.cs +++ b/mcs/class/corlib/Test/System/ConvertTest.cs @@ -1295,7 +1295,7 @@ public void TestToInt16() { } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void TestToInt32() { long tryMax = long.MaxValue; long tryMin = long.MinValue; @@ -1474,7 +1474,7 @@ public void TestToInt32() { } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void TestToInt64() { decimal longMax = long.MaxValue; longMax += 1000000; @@ -1869,7 +1869,7 @@ public void TestToSByte() { } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void TestToSingle() { int iTest = 1; try { @@ -4919,7 +4919,7 @@ public void ToInt32_NaN () } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void ChangeTypeFromInvalidDouble () { // types which should generate OverflowException from double.NaN, etc. diff --git a/mcs/class/corlib/Test/System/DecimalTest-Microsoft.cs b/mcs/class/corlib/Test/System/DecimalTest-Microsoft.cs index a29ba7ae7bdc..a96478e53af9 100644 --- a/mcs/class/corlib/Test/System/DecimalTest-Microsoft.cs +++ b/mcs/class/corlib/Test/System/DecimalTest-Microsoft.cs @@ -708,7 +708,7 @@ public void TestGetHashCode() } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void TestToSingle() { // Single Decimal.ToSingle(Decimal) @@ -726,7 +726,7 @@ public void TestToSingle() } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void TestToDouble() { Double d = Decimal.ToDouble(new Decimal(0, 0, 1, false, 0)); diff --git a/mcs/class/corlib/Test/System/DecimalTest.cs b/mcs/class/corlib/Test/System/DecimalTest.cs index ac164e8c939c..00f1cf9ec3bc 100644 --- a/mcs/class/corlib/Test/System/DecimalTest.cs +++ b/mcs/class/corlib/Test/System/DecimalTest.cs @@ -507,7 +507,7 @@ public void TestConstructUInt64 () } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void TestConstructSingle () { Decimal d; @@ -630,7 +630,7 @@ public void TestConstructSingleRounding () [Test] [SetCulture("en-US")] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void TestConstructDouble () { Decimal d; @@ -729,7 +729,7 @@ public void TestConstructDouble () } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void TestConstructDoubleRound () { decimal d; @@ -982,7 +982,7 @@ public void ToUInt16 () } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void ToInt32 () { Decimal d = 254.9m; @@ -1045,7 +1045,7 @@ public void ToUInt64 () } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void ToSingle () { Decimal d = 254.9m; @@ -1059,7 +1059,7 @@ public void ToSingle () } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void ToDouble () { Decimal d = 254.9m; diff --git a/mcs/class/corlib/Test/System/DelegateTest.cs b/mcs/class/corlib/Test/System/DelegateTest.cs index d84fa2c89858..26c449615b30 100644 --- a/mcs/class/corlib/Test/System/DelegateTest.cs +++ b/mcs/class/corlib/Test/System/DelegateTest.cs @@ -851,7 +851,7 @@ static object Box (object o) delegate object Boxer (); [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void BoxingCovariance () { var boxer = (Boxer) Delegate.CreateDelegate ( @@ -913,7 +913,7 @@ static object Target (Closure c) } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void NullFirstArgumentOnStaticMethod () { CallTarget call = (CallTarget) Delegate.CreateDelegate ( @@ -927,7 +927,7 @@ public void NullFirstArgumentOnStaticMethod () } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] #if MONOTOUCH || FULL_AOT_RUNTIME [Category ("NotWorking")] // #10539 #endif @@ -1027,7 +1027,7 @@ public void HasTarget_Static () #if MONOTOUCH || FULL_AOT_RUNTIME [Category ("NotWorking")] // #10539 #endif - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void ClosedOverNullReferenceStaticMethod () { var del = (Func) Delegate.CreateDelegate ( @@ -1105,7 +1105,7 @@ public void Bar () event Action bar_handler; [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] [ExpectedException (typeof (ArgumentException))] // #635349, #605936 public void NewDelegateClosedOverNullReferenceInstanceMethod () { @@ -1149,7 +1149,7 @@ public static int DynamicInvokeClosedStaticDelegate_CB (string instance) } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void DynamicInvokeOpenInstanceDelegate () { var d1 = Delegate.CreateDelegate (typeof (Func), typeof(DelegateTest).GetMethod ("DynamicInvokeOpenInstanceDelegate_CB")); @@ -1287,7 +1287,7 @@ public interface Iface } #if !MONOTOUCH && !FULL_AOT_RUNTIME [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void CreateDelegateWithLdFtnAndAbstractMethod () { AssemblyName assemblyName = new AssemblyName (); diff --git a/mcs/class/corlib/Test/System/ExceptionTest.cs b/mcs/class/corlib/Test/System/ExceptionTest.cs index 9793ab3ba46f..d383e62452f0 100644 --- a/mcs/class/corlib/Test/System/ExceptionTest.cs +++ b/mcs/class/corlib/Test/System/ExceptionTest.cs @@ -262,7 +262,7 @@ private static void ThrowAfterFinally() } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void GetObjectData () { string msg = "MESSAGE"; @@ -380,7 +380,7 @@ public void HResult () } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void Source () { Exception ex1 = new Exception ("MSG"); diff --git a/mcs/class/corlib/Test/System/GCTest.cs b/mcs/class/corlib/Test/System/GCTest.cs index 52c8c8cb0c43..b1027340f963 100644 --- a/mcs/class/corlib/Test/System/GCTest.cs +++ b/mcs/class/corlib/Test/System/GCTest.cs @@ -56,7 +56,7 @@ static void Run_ReRegisterForFinalizeTest () } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void ReRegisterForFinalizeTest () { var thread = new Thread (Run_ReRegisterForFinalizeTest); diff --git a/mcs/class/corlib/Test/System/LazyTest.cs b/mcs/class/corlib/Test/System/LazyTest.cs index 0b3e042e3097..2e461128ee4c 100644 --- a/mcs/class/corlib/Test/System/LazyTest.cs +++ b/mcs/class/corlib/Test/System/LazyTest.cs @@ -111,6 +111,7 @@ public void NotThreadSafe () { static int counter; [Test] + [Category ("MultiThreaded")] public void EnsureSingleThreadSafeExecution () { counter = 42; @@ -279,6 +280,7 @@ public void Trivial_Lazy () { } [Test] + [Category ("MultiThreaded")] public void ConcurrentInitialization () { var init = new AutoResetEvent (false); diff --git a/mcs/class/corlib/Test/System/NumberFormatterTest.cs b/mcs/class/corlib/Test/System/NumberFormatterTest.cs index c0dce0e1d544..be7c06e492f1 100644 --- a/mcs/class/corlib/Test/System/NumberFormatterTest.cs +++ b/mcs/class/corlib/Test/System/NumberFormatterTest.cs @@ -4380,6 +4380,7 @@ public void Test18000 () } [Test] + [Category ("MultiThreaded")] public void TestInvariantThreading () { Thread[] th = new Thread[4]; diff --git a/mcs/class/corlib/Test/System/TimeZoneTest.cs b/mcs/class/corlib/Test/System/TimeZoneTest.cs index d5861e175beb..5f73383f8826 100644 --- a/mcs/class/corlib/Test/System/TimeZoneTest.cs +++ b/mcs/class/corlib/Test/System/TimeZoneTest.cs @@ -313,7 +313,7 @@ public void GetUTCNowAtDSTBoundaries () } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void GetUtcOffsetAtDSTBoundary () { /* diff --git a/mcs/class/corlib/Test/System/TypedReferenceCas.cs b/mcs/class/corlib/Test/System/TypedReferenceCas.cs index 2b0ee5e2835a..29f4226dcb3e 100644 --- a/mcs/class/corlib/Test/System/TypedReferenceCas.cs +++ b/mcs/class/corlib/Test/System/TypedReferenceCas.cs @@ -51,7 +51,7 @@ public void SetUp () // when reflection is used (i.e. it gets testable). [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] [ReflectionPermission (SecurityAction.Deny, MemberAccess = true)] [ExpectedException (typeof (SecurityException))] public void MakeTypedReference () diff --git a/mcs/class/corlib/Test/System/TypedReferenceTest.cs b/mcs/class/corlib/Test/System/TypedReferenceTest.cs index 9c28041c8ba4..5eeaeb242897 100644 --- a/mcs/class/corlib/Test/System/TypedReferenceTest.cs +++ b/mcs/class/corlib/Test/System/TypedReferenceTest.cs @@ -59,7 +59,7 @@ class CClass { } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void MakeTypedReference () { var o = new CClass () { a = new AStruct () { b = "5" }}; diff --git a/mcs/class/corlib/Test/System/ValueTypeTest.cs b/mcs/class/corlib/Test/System/ValueTypeTest.cs index c820f9f6687a..476dfbb2852b 100644 --- a/mcs/class/corlib/Test/System/ValueTypeTest.cs +++ b/mcs/class/corlib/Test/System/ValueTypeTest.cs @@ -52,7 +52,7 @@ public void TestEquals () } [Test] - [Category ("InterpreterNotWorking")] + [Category ("NotWorkingRuntimeInterpreter")] public void TestEquals_Nullable () { NullableStruct f1 = new NullableStruct { f = 5 }; diff --git a/mcs/class/corlib/corlib-net_4_x.csproj b/mcs/class/corlib/corlib-net_4_x.csproj index 943872765cf2..f0e0c847d895 100644 --- a/mcs/class/corlib/corlib-net_4_x.csproj +++ b/mcs/class/corlib/corlib-net_4_x.csproj @@ -8,7 +8,7 @@ 2.0 {2CA6026B-2DC8-4C4C-A12C-1E8234049DB7} Library - 612,618,3001,3003,1635,1699 + 612,618,3001,3002,3003,1635,1699 latest win32 darwin @@ -31,7 +31,7 @@ true full - 612,618,3001,3003,1635,1699 + 612,618,3001,3002,3003,1635,1699 false TRACE;INSIDE_CORLIB;MONO_CULTURE_DATA;LIBC;FEATURE_PAL;GENERICS_WORK;FEATURE_LIST_PREDICATES;FEATURE_SERIALIZATION;FEATURE_ENCODINGNLS;FEATURE_ASCII;FEATURE_LATIN1;FEATURE_UTF7;FEATURE_UTF32;MONO_HYBRID_ENCODING_SUPPORT;FEATURE_ASYNC_IO;NEW_EXPERIMENTAL_ASYNC_IO;FEATURE_UTF32;FEATURE_EXCEPTIONDISPATCHINFO;FEATURE_CORRUPTING_EXCEPTIONS;FEATURE_EXCEPTION_NOTIFICATIONS;FEATURE_STRONGNAME_MIGRATION;FEATURE_USE_LCID;FEATURE_FUSION;FEATURE_CRYPTO;FEATURE_X509_SECURESTRINGS;FEATURE_SYNCHRONIZATIONCONTEXT;FEATURE_SYNCHRONIZATIONCONTEXT_WAIT;HAS_CORLIB_CONTRACTS;FEATURE_MACL;FEATURE_REMOTING;MONO_COM;FEATURE_COMINTEROP;FEATURE_ROLE_BASED_SECURITY;MONO_FEATURE_THREAD_ABORT;MONO_FEATURE_THREAD_SUSPEND_RESUME;MONO_FEATURE_MULTIPLE_APPDOMAINS;NET_4_0;NET_4_5;NET_4_6;MONO;WIN_PLATFORM;MULTIPLEX_OS;FEATURE_PAL;GENERICS_WORK;FEATURE_LIST_PREDICATES;FEATURE_SERIALIZATION;FEATURE_ENCODINGNLS;FEATURE_ASCII;FEATURE_LATIN1;FEATURE_UTF7;FEATURE_UTF32;MONO_HYBRID_ENCODING_SUPPORT;FEATURE_ASYNC_IO;NEW_EXPERIMENTAL_ASYNC_IO;FEATURE_UTF32;FEATURE_EXCEPTIONDISPATCHINFO;FEATURE_CORRUPTING_EXCEPTIONS;FEATURE_EXCEPTION_NOTIFICATIONS;FEATURE_STRONGNAME_MIGRATION;FEATURE_USE_LCID;FEATURE_FUSION;FEATURE_CRYPTO;FEATURE_X509_SECURESTRINGS;FEATURE_SYNCHRONIZATIONCONTEXT;FEATURE_SYNCHRONIZATIONCONTEXT_WAIT;HAS_CORLIB_CONTRACTS;FEATURE_MACL;FEATURE_REMOTING;MONO_COM;FEATURE_COMINTEROP;FEATURE_ROLE_BASED_SECURITY;MONO_FEATURE_THREAD_ABORT;MONO_FEATURE_THREAD_SUSPEND_RESUME;MONO_FEATURE_MULTIPLE_APPDOMAINS;MONO_FEATURE_CONSOLE;MONO_FEATURE_APPLETLS prompt @@ -39,7 +39,7 @@ pdbonly - 612,618,3001,3003,1635,1699 + 612,618,3001,3002,3003,1635,1699 true INSIDE_CORLIB;MONO_CULTURE_DATA;LIBC;FEATURE_PAL;GENERICS_WORK;FEATURE_LIST_PREDICATES;FEATURE_SERIALIZATION;FEATURE_ENCODINGNLS;FEATURE_ASCII;FEATURE_LATIN1;FEATURE_UTF7;FEATURE_UTF32;MONO_HYBRID_ENCODING_SUPPORT;FEATURE_ASYNC_IO;NEW_EXPERIMENTAL_ASYNC_IO;FEATURE_UTF32;FEATURE_EXCEPTIONDISPATCHINFO;FEATURE_CORRUPTING_EXCEPTIONS;FEATURE_EXCEPTION_NOTIFICATIONS;FEATURE_STRONGNAME_MIGRATION;FEATURE_USE_LCID;FEATURE_FUSION;FEATURE_CRYPTO;FEATURE_X509_SECURESTRINGS;FEATURE_SYNCHRONIZATIONCONTEXT;FEATURE_SYNCHRONIZATIONCONTEXT_WAIT;HAS_CORLIB_CONTRACTS;FEATURE_MACL;FEATURE_REMOTING;MONO_COM;FEATURE_COMINTEROP;FEATURE_ROLE_BASED_SECURITY;MONO_FEATURE_THREAD_ABORT;MONO_FEATURE_THREAD_SUSPEND_RESUME;MONO_FEATURE_MULTIPLE_APPDOMAINS;NET_4_0;NET_4_5;NET_4_6;MONO;WIN_PLATFORM;MULTIPLEX_OS;FEATURE_PAL;GENERICS_WORK;FEATURE_LIST_PREDICATES;FEATURE_SERIALIZATION;FEATURE_ENCODINGNLS;FEATURE_ASCII;FEATURE_LATIN1;FEATURE_UTF7;FEATURE_UTF32;MONO_HYBRID_ENCODING_SUPPORT;FEATURE_ASYNC_IO;NEW_EXPERIMENTAL_ASYNC_IO;FEATURE_UTF32;FEATURE_EXCEPTIONDISPATCHINFO;FEATURE_CORRUPTING_EXCEPTIONS;FEATURE_EXCEPTION_NOTIFICATIONS;FEATURE_STRONGNAME_MIGRATION;FEATURE_USE_LCID;FEATURE_FUSION;FEATURE_CRYPTO;FEATURE_X509_SECURESTRINGS;FEATURE_SYNCHRONIZATIONCONTEXT;FEATURE_SYNCHRONIZATIONCONTEXT_WAIT;HAS_CORLIB_CONTRACTS;FEATURE_MACL;FEATURE_REMOTING;MONO_COM;FEATURE_COMINTEROP;FEATURE_ROLE_BASED_SECURITY;MONO_FEATURE_THREAD_ABORT;MONO_FEATURE_THREAD_SUSPEND_RESUME;MONO_FEATURE_MULTIPLE_APPDOMAINS;MONO_FEATURE_CONSOLE;MONO_FEATURE_APPLETLS prompt @@ -63,6 +63,12 @@ + + + + + + @@ -73,8 +79,12 @@ + + + + @@ -1708,6 +1718,7 @@ + diff --git a/mcs/class/corlib/corlib.dll.sources b/mcs/class/corlib/corlib.dll.sources index abfe4d1537d8..ec1c6983e422 100644 --- a/mcs/class/corlib/corlib.dll.sources +++ b/mcs/class/corlib/corlib.dll.sources @@ -142,6 +142,7 @@ System/TimeZoneInfo.cs System/TimeZoneInfo.Android.cs System/TimeZoneInfo.MonoTouch.cs System/TimeZoneInfo.Serialization.cs +System/TimeZoneInfo.Unity.cs System/TimeZoneInfo.WinRT.cs ../../build/common/MonoTODOAttribute.cs System/TypeIdentifier.cs @@ -151,6 +152,7 @@ System/UIntPtr.cs System/ValueType.cs System/Variant.cs System/Void.cs +System/WeakAttribute.cs System/WeakReference.cs System/WeakReference_T.cs System/WindowsConsoleDriver.cs @@ -1686,10 +1688,15 @@ corefx/SR.cs ../../../external/corefx/src/System.Memory/src/System/ReadOnlySpan.cs ../../../external/corefx/src/System.Memory/src/System/Span.cs ../../../external/corefx/src/System.Memory/src/System/SpanDebugView.cs +../../../external/corefx/src/System.Memory/src/System/SpanExtensions.cs +../../../external/corefx/src/System.Memory/src/System/SpanExtensions.Portable.cs ../../../external/corefx/src/System.Memory/src/System/SpanHelpers.cs ../../../external/corefx/src/System.Memory/src/System/SpanHelpers.Clear.cs +../../../external/corefx/src/System.Memory/src/System/SpanHelpers.byte.cs +../../../external/corefx/src/System.Memory/src/System/SpanHelpers.T.cs ../../../external/corefx/src/System.Memory/src/System/ThrowHelper.cs ../../../external/corefx/src/System.Memory/src/System/Buffers/*.cs +../../../external/corefx/src/System.Memory/src/System/Buffers/Binary/*.cs ../../../external/corefx/src/System.Runtime.InteropServices.RuntimeInformation/src/System/Runtime/InteropServices/RuntimeInformation/OSPlatform.cs ../../../external/corefx/src/System.Runtime.InteropServices.RuntimeInformation/src/System/Runtime/InteropServices/RuntimeInformation/Architecture.cs diff --git a/mcs/class/corlib/corlib_xtest.dll.sources b/mcs/class/corlib/corlib_xtest.dll.sources index f86a4ae5f025..ffe1a73b9d46 100644 --- a/mcs/class/corlib/corlib_xtest.dll.sources +++ b/mcs/class/corlib/corlib_xtest.dll.sources @@ -173,3 +173,10 @@ # System.Text.RegularExpressions ../../../external/corefx/src/System.Text.RegularExpressions/tests/*.cs:CaptureCollectionTests.netcoreapp.cs,GroupCollectionTests.netcoreapp.cs,MatchCollectionTests.netcoreapp.cs,PrecompiledRegexScenarioTest.cs,RegexCompilationInfoTests.cs,RegexGroupNameTests.cs,Regex.Groups.Tests.cs,Regex.Match.Tests.cs,Regex.Serialization.cs,MatchCollectionTests.cs,Regex.Ctor.Tests.cs,GroupCollectionTests2.cs,MatchCollectionTests2.cs,CaptureCollectionTests2.cs + +../../../external/corefx/src/System.Memory/tests/*.cs +../../../external/corefx/src/System.Memory/tests/Binary/*.cs +../../../external/corefx/src/System.Memory/tests/Memory/*.cs +../../../external/corefx/src/System.Memory/tests/ReadOnlyMemory/*.cs +../../../external/corefx/src/System.Memory/tests/ReadOnlySpan/*.cs +../../../external/corefx/src/System.Memory/tests/Span/*.cs diff --git a/mcs/class/corlib/wasm_corlib_test.dll.exclude.sources b/mcs/class/corlib/wasm_corlib_test.dll.exclude.sources new file mode 100644 index 000000000000..8b08b22c32e0 --- /dev/null +++ b/mcs/class/corlib/wasm_corlib_test.dll.exclude.sources @@ -0,0 +1,132 @@ +Microsoft.Win32/RegistryKeyTest.cs +System.Diagnostics.Contracts/ContractAssertTest.cs +System.Diagnostics.Contracts/ContractAssumeTest.cs +System.Diagnostics.Contracts/ContractCollectionMethodsTest.cs +System.Diagnostics.Contracts/ContractHelperTest.cs +System.Diagnostics.Contracts/ContractMarkerMethodsTest.cs +System.Diagnostics.Contracts/ContractMustUseRewriterTest.cs +System.Diagnostics.Contracts/Helpers/RunAgainstReferenceAttribute.cs +System.Diagnostics.Contracts/Helpers/TestContractBase.cs +System.Reflection.Emit/AssemblyBuilderAccessTest.cs +System.Reflection.Emit/AssemblyBuilderTest.cs +System.Reflection.Emit/ConstructorBuilderTest.cs +System.Reflection.Emit/ConstructorOnTypeBuilderInstTest.cs +System.Reflection.Emit/CustomAttributeBuilderTest.cs +System.Reflection.Emit/DerivedTypesTest.cs +System.Reflection.Emit/DynamicILInfoTest.cs +System.Reflection.Emit/DynamicMethodTest.cs +System.Reflection.Emit/EnumBuilderTest.cs +System.Reflection.Emit/EventBuilderTest.cs +System.Reflection.Emit/FieldBuilderTest.cs +System.Reflection.Emit/GenericTypeParameterBuilderTest.cs +System.Reflection.Emit/ILGeneratorTest.cs +System.Reflection.Emit/MethodBuilderTest.cs +System.Reflection.Emit/MethodBuilderTestIL.cs +System.Reflection.Emit/MethodOnTypeBuilderInstTest.cs +System.Reflection.Emit/MethodRentalCas.cs +System.Reflection.Emit/MethodRentalTest.cs +System.Reflection.Emit/ModuleBuilderTest.cs +System.Reflection.Emit/ParameterBuilderTest.cs +System.Reflection.Emit/PropertyBuilderTest.cs +System.Reflection.Emit/SignatureHelperTest.cs +System.Reflection.Emit/TypeBuilderTest.cs +System.Reflection.Emit/SaveTest.cs +System.Runtime.Remoting/ContextTest.cs +System.Runtime.Remoting/RemotingConfigurationTest.cs +System.Runtime.Remoting/SoapServicesTest.cs +System.Runtime.Remoting/SynchronizationAttributeTest.cs +System.Runtime.Remoting.Channels/ChannelServicesTest.cs +System.Runtime.Remoting.Contexts/SynchronizationAttributeTest.cs +System.Runtime.Remoting.Messaging/CallContextTest.cs +System.Runtime.Remoting.Metadata.W3cXsd2001/SoapHexBinaryTest.cs +System.Runtime.Remoting.Proxies/RealProxyTest.cs +System.Security.AccessControl/AuthorizationRuleTest.cs +System.Security.AccessControl/CommonAceTest.cs +System.Security.AccessControl/CommonAclTest.cs +System.Security.AccessControl/CommonObjectSecurityTest.cs +System.Security.AccessControl/CommonSecurityDescriptorTest.cs +System.Security.AccessControl/CryptoKeyAccessRuleTest.cs +System.Security.AccessControl/DirectoryObjectSecurityTest.cs +System.Security.AccessControl/DirectorySecurityTest.cs +System.Security.AccessControl/DiscretionaryAclTest.cs +System.Security.AccessControl/EventWaitHandleSecurityTest.cs +System.Security.AccessControl/FileSecurityTest.cs +System.Security.AccessControl/MutexAccessRuleTest.cs +System.Security.AccessControl/MutexSecurityTest.cs +System.Security.AccessControl/ObjectAceTest.cs +System.Security.AccessControl/ObjectSecurity_TTest.cs +System.Security.AccessControl/ObjectSecurityTest.cs +System.Security.AccessControl/RawAclTest.cs +System.Security.AccessControl/RawSecurityDescriptorTest.cs +System.Security.AccessControl/RegistrySecurityTest.cs +System.Security.AccessControl/SystemAclTest.cs +System.Security.Permissions/CodeAccessSecurityAttributeTest.cs +System.Security.Permissions/EnvironmentPermissionAttributeTest.cs +System.Security.Permissions/EnvironmentPermissionTest.cs +System.Security.Permissions/FileDialogPermissionAttributeTest.cs +System.Security.Permissions/FileDialogPermissionTest.cs +System.Security.Permissions/FileIOPermissionAttributeTest.cs +System.Security.Permissions/FileIOPermissionTest.cs +System.Security.Permissions/GacIdentityPermissionAttributeTest.cs +System.Security.Permissions/GacIdentityPermissionTest.cs +System.Security.Permissions/HostProtectionAttributeTest.cs +System.Security.Permissions/IBuiltInPermissionTest.cs +System.Security.Permissions/IsolatedStorageFilePermissionAttributeTest.cs +System.Security.Permissions/IsolatedStorageFilePermissionTest.cs +System.Security.Permissions/IsolatedStoragePermissionAttributeTest.cs +System.Security.Permissions/KeyContainerPermissionAttributeTest.cs +System.Security.Permissions/PermissionSetAttributeTest.cs +System.Security.Permissions/PrincipalPermissionAttributeTest.cs +System.Security.Permissions/PrincipalPermissionTest.cs +System.Security.Permissions/PublisherIdentityPermissionAttributeTest.cs +System.Security.Permissions/PublisherIdentityPermissionTest.cs +System.Security.Permissions/ReflectionPermissionAttributeTest.cs +System.Security.Permissions/ReflectionPermissionTest.cs +System.Security.Permissions/RegistryPermissionAttributeTest.cs +System.Security.Permissions/RegistryPermissionTest.cs +System.Security.Permissions/SecurityAttributeTest.cs +System.Security.Permissions/SecurityPermissionAttributeTest.cs +System.Security.Permissions/SecurityPermissionTest.cs +System.Security.Permissions/SiteIdentityPermissionAttributeTest.cs +System.Security.Permissions/SiteIdentityPermissionTest.cs +System.Security.Permissions/StrongNameIdentityPermissionAttributeTest.cs +System.Security.Permissions/StrongNameIdentityPermissionTest.cs +System.Security.Permissions/StrongNamePublicKeyBlobTest.cs +System.Security.Permissions/UIPermissionAttributeTest.cs +System.Security.Permissions/UIPermissionTest.cs +System.Security.Permissions/UrlIdentityPermissionAttributeTest.cs +System.Security.Permissions/UrlIdentityPermissionTest.cs +System.Security.Permissions/ZoneIdentityPermissionAttributeTest.cs +System.Security.Permissions/ZoneIdentityPermissionTest.cs +System.Security.Policy/AllMembershipConditionTest.cs +System.Security.Policy/ApplicationDirectoryMembershipConditionTest.cs +System.Security.Policy/ApplicationDirectoryTest.cs +System.Security.Policy/ApplicationMembershipConditionTest.cs +System.Security.Policy/ApplicationSecurityManagerCas.cs +System.Security.Policy/ApplicationSecurityManagerTest.cs +System.Security.Policy/ApplicationTrustTest.cs +System.Security.Policy/CodeGroupTest.cs +System.Security.Policy/DomainApplicationMembershipConditionTest.cs +System.Security.Policy/EvidenceTest.cs +System.Security.Policy/FileCodeGroupTest.cs +System.Security.Policy/FirstMatchCodeGroupTest.cs +System.Security.Policy/GacMembershipConditionTest.cs +System.Security.Policy/GacTest.cs +System.Security.Policy/HashMembershipConditionTest.cs +System.Security.Policy/HashTest.cs +System.Security.Policy/IBuiltInEvidenceTest.cs +System.Security.Policy/NetCodeGroupTest.cs +System.Security.Policy/PermissionRequestEvidenceTest.cs +System.Security.Policy/PolicyLevelTest.cs +System.Security.Policy/PolicyStatementTest.cs +System.Security.Policy/PublisherMembershipConditionTest.cs +System.Security.Policy/PublisherTest.cs +System.Security.Policy/SiteMembershipConditionTest.cs +System.Security.Policy/SiteTest.cs +System.Security.Policy/StrongNameMembershipConditionTest.cs +System.Security.Policy/StrongNameTest.cs +System.Security.Policy/UnionCodeGroupTest.cs +System.Security.Policy/UrlMembershipConditionTest.cs +System.Security.Policy/UrlTest.cs +System.Security.Policy/ZoneMembershipConditionTest.cs +System.Security.Policy/ZoneTest.cs diff --git a/mcs/class/corlib/wasm_corlib_test.dll.sources b/mcs/class/corlib/wasm_corlib_test.dll.sources new file mode 100644 index 000000000000..011effe162c5 --- /dev/null +++ b/mcs/class/corlib/wasm_corlib_test.dll.sources @@ -0,0 +1 @@ +#include corlib_test.dll.sources diff --git a/mcs/class/referencesource/mscorlib/system/throwhelper.cs b/mcs/class/referencesource/mscorlib/system/throwhelper.cs index 80c4d7f750de..0eea324a9605 100644 --- a/mcs/class/referencesource/mscorlib/system/throwhelper.cs +++ b/mcs/class/referencesource/mscorlib/system/throwhelper.cs @@ -473,7 +473,8 @@ internal enum ExceptionArgument { #if MONO start, pointer, - ownedMemory + ownedMemory, + text, #endif } diff --git a/mcs/errors/cs0023-30.cs b/mcs/errors/cs0023-30.cs new file mode 100644 index 000000000000..fc19cc24e3e9 --- /dev/null +++ b/mcs/errors/cs0023-30.cs @@ -0,0 +1,11 @@ +// CS0023: The `is' operator cannot be applied to operand of type `default' +// Line: 9 +// Compiler options: -langversion:latest + +class C +{ + static void Main () + { + bool d = default is C; + } +} \ No newline at end of file diff --git a/mcs/errors/cs0133-2.cs b/mcs/errors/cs0133-2.cs index b7a37182d737..48488876f7e8 100644 --- a/mcs/errors/cs0133-2.cs +++ b/mcs/errors/cs0133-2.cs @@ -1,4 +1,4 @@ -// CS0133: The expression being assigned to `c' must be constant +// CS0133: The expression being assigned to `c' must be a constant or default value // Line: 10 class C diff --git a/mcs/errors/cs0133-3.cs b/mcs/errors/cs0133-3.cs index caae3bde68c5..2f7dac6880d0 100644 --- a/mcs/errors/cs0133-3.cs +++ b/mcs/errors/cs0133-3.cs @@ -1,5 +1,5 @@ -// CS0133: The expression being assigned to `Foo' must be constant -// Line: 12 +// CS0133: The expression being assigned to `Foo' must be a constant or default value +// Line: 8 class T { diff --git a/mcs/errors/cs0133-4.cs b/mcs/errors/cs0133-4.cs index 41fe639b4462..54162d544ca2 100644 --- a/mcs/errors/cs0133-4.cs +++ b/mcs/errors/cs0133-4.cs @@ -1,4 +1,4 @@ -// CS0133: The expression being assigned to `S.pathName' must be constant +// CS0133: The expression being assigned to `S.pathName' must be a constant or default value // Line: 12 // Compiler options: -unsafe diff --git a/mcs/errors/cs0133-5.cs b/mcs/errors/cs0133-5.cs index a49f265c6901..32e6bfdf416e 100644 --- a/mcs/errors/cs0133-5.cs +++ b/mcs/errors/cs0133-5.cs @@ -1,4 +1,4 @@ -// CS0133: The expression being assigned to `b' must be constant +// CS0133: The expression being assigned to `b' must be a constant or default value // Line: 8 class X diff --git a/mcs/errors/cs0133-6.cs b/mcs/errors/cs0133-6.cs index a523169cdbda..28448dd6de88 100644 --- a/mcs/errors/cs0133-6.cs +++ b/mcs/errors/cs0133-6.cs @@ -1,4 +1,4 @@ -// CS0133: The expression being assigned to `o' must be constant +// CS0133: The expression being assigned to `o' must be a constant or default value // Line: 8 class X diff --git a/mcs/errors/cs0133-7.cs b/mcs/errors/cs0133-7.cs index 10d82d9fe5e0..024bc1482298 100644 --- a/mcs/errors/cs0133-7.cs +++ b/mcs/errors/cs0133-7.cs @@ -1,4 +1,4 @@ -// CS0133: The expression being assigned to `o' must be constant +// CS0133: The expression being assigned to `o' must be a constant or default value // Line: 8 class X diff --git a/mcs/errors/cs0133.cs b/mcs/errors/cs0133.cs index 094194deabb2..f0dda9ee3cb3 100644 --- a/mcs/errors/cs0133.cs +++ b/mcs/errors/cs0133.cs @@ -1,5 +1,6 @@ -// CS0133: The expression being assigned to `x' must be constant -// Line: 6 +// CS0133: The expression being assigned to `x' must be a constant or default value +// Line: 7 + class X { X (int arg) { diff --git a/mcs/errors/cs0815-9.cs b/mcs/errors/cs0815-9.cs new file mode 100644 index 000000000000..f54703349beb --- /dev/null +++ b/mcs/errors/cs0815-9.cs @@ -0,0 +1,11 @@ +// CS0815: An implicitly typed local variable declaration cannot be initialized with `default' +// Line: 9 +// Compiler options: -langversion:latest + +static class X +{ + public static void Main () + { + var x = default; + } +} \ No newline at end of file diff --git a/mcs/errors/cs1644-58.cs b/mcs/errors/cs1644-58.cs new file mode 100644 index 000000000000..e994cf338bdd --- /dev/null +++ b/mcs/errors/cs1644-58.cs @@ -0,0 +1,8 @@ +// CS1644: Feature `default literal' cannot be used because it is not part of the C# 7.0 language specification +// Line: 7 +// Compiler options: -langversion:7 + +class X +{ + int i = default; +} diff --git a/mcs/errors/cs8310.cs b/mcs/errors/cs8310.cs new file mode 100644 index 000000000000..134624c03b70 --- /dev/null +++ b/mcs/errors/cs8310.cs @@ -0,0 +1,11 @@ +// CS8310: Operator `+' cannot be applied to operand `default' +// Line: 9 +// Compiler options: -langversion:latest + +class C +{ + static void Main () + { + int h = 1 + default; + } +} \ No newline at end of file diff --git a/mcs/errors/cs8311.cs b/mcs/errors/cs8311.cs new file mode 100644 index 000000000000..5b35229442d9 --- /dev/null +++ b/mcs/errors/cs8311.cs @@ -0,0 +1,12 @@ +// CS8311: Cannot use a default literal as an argument to a dynamically dispatched operation +// Line: 10 +// Compiler options: -langversion:latest + +class C +{ + static void Main () + { + dynamic d = null; + d.M2 (default); + } +} \ No newline at end of file diff --git a/mcs/errors/cs8312.cs b/mcs/errors/cs8312.cs new file mode 100644 index 000000000000..d2ad3f52f024 --- /dev/null +++ b/mcs/errors/cs8312.cs @@ -0,0 +1,12 @@ +// CS8312: Use of default literal is not valid in this context +// Line: 9 +// Compiler options: -langversion:latest + +class C +{ + static void Main () + { + foreach (var x in default) { + } + } +} \ No newline at end of file diff --git a/mcs/errors/cs8315.cs b/mcs/errors/cs8315.cs new file mode 100644 index 000000000000..c40bf8613b43 --- /dev/null +++ b/mcs/errors/cs8315.cs @@ -0,0 +1,11 @@ +// CS8315: Operator `==' is ambiguous on operands `default' and `default' +// Line: 9 +// Compiler options: -langversion:latest + +class C +{ + static void Main () + { + bool d = default == default; + } +} \ No newline at end of file diff --git a/mcs/mcs/class.cs b/mcs/mcs/class.cs index 3fd615907d5d..da3ec32d6fb0 100644 --- a/mcs/mcs/class.cs +++ b/mcs/mcs/class.cs @@ -2189,7 +2189,7 @@ public override void VerifyMembers () public override void Emit () { - if (Interfaces != null) { + if (Interfaces != null && (ModFlags & Modifiers.PRIVATE) == 0) { foreach (var iface in Interfaces) { if (iface.HasNamedTupleElement) { throw new NotImplementedException ("named tuples for .interfaceimpl"); diff --git a/mcs/mcs/const.cs b/mcs/mcs/const.cs index 046aec24c1b1..658f15ec57a9 100644 --- a/mcs/mcs/const.cs +++ b/mcs/mcs/const.cs @@ -206,7 +206,9 @@ protected virtual Expression DoResolveInitializer (ResolveContext rc) c = field.ConvertInitializer (rc, c); if (c == null) { - if (TypeSpec.IsReferenceType (field.MemberType)) + if (expr is DefaultLiteralExpression) { + // It's handled bellow in New.Constantify + } else if (TypeSpec.IsReferenceType (field.MemberType)) Error_ConstantCanBeInitializedWithNullOnly (rc, field.MemberType, expr.Location, GetSignatureForError ()); else if (!(expr is Constant)) Error_ExpressionMustBeConstant (rc, expr.Location, GetSignatureForError ()); diff --git a/mcs/mcs/convert.cs b/mcs/mcs/convert.cs index 46989cd2757a..f4012fbd2223 100644 --- a/mcs/mcs/convert.cs +++ b/mcs/mcs/convert.cs @@ -1481,6 +1481,10 @@ static Expression ImplicitConversionStandard (ResolveContext ec, Expression expr return target_type.Kind == MemberKind.InternalCompilerType ? null : EmptyCast.Create (expr, target_type); } + if (expr_type == InternalType.DefaultType) { + return new DefaultValueExpression (new TypeExpression (target_type, expr.Location), expr.Location).Resolve (ec); + } + if (target_type.IsNullableType) return ImplicitNulableConversion (ec, expr, target_type); diff --git a/mcs/mcs/cs-parser.jay b/mcs/mcs/cs-parser.jay index db7e06b2f8c4..72b09b138953 100644 --- a/mcs/mcs/cs-parser.jay +++ b/mcs/mcs/cs-parser.jay @@ -169,7 +169,8 @@ namespace Mono.CSharp %token CONST %token CONTINUE %token DECIMAL -%token DEFAULT +%token DEFAULT +%token DEFAULT_VALUE %token DELEGATE %token DO %token DOUBLE @@ -3466,6 +3467,7 @@ primary_expression | anonymous_method_expression | undocumented_expressions | interpolated_string + | default_literal ; type_name_expression @@ -4404,7 +4406,7 @@ anonymous_method_signature ; default_value_expression - : DEFAULT open_parens_any type CLOSE_PARENS + : DEFAULT_VALUE open_parens_any type CLOSE_PARENS { if (lang_version < LanguageVersion.ISO_2) FeatureIsNotAvailable (GetLocation ($1), "default value expression"); @@ -4414,6 +4416,16 @@ default_value_expression } ; +default_literal + : DEFAULT + { + if (lang_version < LanguageVersion.V_7_1) + FeatureIsNotAvailable (GetLocation ($1), "default literal"); + + $$ = new DefaultLiteralExpression (GetLocation ($1)); + } + ; + unary_expression : primary_expression | BANG prefixed_unary_expression @@ -8273,6 +8285,7 @@ static string GetTokenName (int token) case Token.CONTINUE: return "continue"; case Token.DEFAULT: + case Token.DEFAULT_VALUE: return "default"; case Token.DELEGATE: return "delegate"; diff --git a/mcs/mcs/cs-tokenizer.cs b/mcs/mcs/cs-tokenizer.cs index 97fcbc70ee3c..5872a762467e 100644 --- a/mcs/mcs/cs-tokenizer.cs +++ b/mcs/mcs/cs-tokenizer.cs @@ -716,9 +716,15 @@ int GetKeyword (char[] id, int id_len) res = Token.EXTERN_ALIAS; break; case Token.DEFAULT: - if (peek_token () == Token.COLON) { + switch (peek_token ()) { + case Token.COLON: token (); res = Token.DEFAULT_COLON; + break; + case Token.OPEN_PARENS: + case Token.OPEN_PARENS_CAST: + res = Token.DEFAULT_VALUE; + break; } break; case Token.WHEN: @@ -1102,6 +1108,7 @@ int TokenizeOpenParens () case Token.UNCHECKED: case Token.UNSAFE: case Token.DEFAULT: + case Token.DEFAULT_VALUE: case Token.AWAIT: // @@ -3517,6 +3524,7 @@ public int xtoken () case Token.SWITCH: case Token.USING: case Token.DEFAULT: + case Token.DEFAULT_VALUE: case Token.DELEGATE: case Token.OP_GENERICS_GT: case Token.REFVALUE: diff --git a/mcs/mcs/dynamic.cs b/mcs/mcs/dynamic.cs index fd4662b2fed3..32f361ba96ab 100644 --- a/mcs/mcs/dynamic.cs +++ b/mcs/mcs/dynamic.cs @@ -283,6 +283,8 @@ protected bool DoResolveCore (ResolveContext rc) if (arg.Type == InternalType.VarOutType) { // Should be special error message about dynamic dispatch rc.Report.Error (8197, arg.Expr.Location, "Cannot infer the type of implicitly-typed out variable `{0}'", ((DeclarationExpression) arg.Expr).Variable.Name); + } else if (arg.Type == InternalType.DefaultType) { + rc.Report.Error (8311, arg.Expr.Location, "Cannot use a default literal as an argument to a dynamically dispatched operation"); } } diff --git a/mcs/mcs/ecore.cs b/mcs/mcs/ecore.cs index 20484fe6e9fc..8d3a7243b24f 100644 --- a/mcs/mcs/ecore.cs +++ b/mcs/mcs/ecore.cs @@ -255,7 +255,7 @@ public static void ErrorIsInaccesible (IMemberContext rc, string member, Locatio public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name) { - rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name); + rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be a constant or default value", e_name); } public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name) diff --git a/mcs/mcs/expression.cs b/mcs/mcs/expression.cs index 7c115ecfb774..74d15942be86 100644 --- a/mcs/mcs/expression.cs +++ b/mcs/mcs/expression.cs @@ -1220,6 +1220,7 @@ protected Expression DoResolveOperation (ResolveContext ec) expr = expr.ResolveLValue (ec, expr); } else { ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer"); + return null; } // @@ -1477,6 +1478,11 @@ protected Expression ResolveCommon (ResolveContext rc) return null; } + if (expr.Type == InternalType.DefaultType) { + Error_OperatorCannotBeApplied (rc, loc, OperatorName, expr.Type); + return null; + } + return this; } @@ -3458,6 +3464,11 @@ public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression l = left.Type.GetSignatureForError (); r = right.Type.GetSignatureForError (); + if (left.Type == InternalType.DefaultType || right.Type == InternalType.DefaultType) { + ec.Report.Error (8310, loc, "Operator `{0}' cannot be applied to operand `default'", oper); + return; + } + ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'", oper, l, r); } @@ -4304,9 +4315,27 @@ protected override Expression DoResolve (ResolveContext ec) CheckOutOfRangeComparison (ec, rc, left.Type); } - if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) + var ltype = left.Type; + var rtype = right.Type; + if (ltype.BuiltinType == BuiltinTypeSpec.Type.Dynamic || rtype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) return DoResolveDynamic (ec); + // + // Only default with == and != is explicitly allowed + // + if (((Oper & Operator.EqualityMask) != 0) && (ltype == InternalType.DefaultType || rtype == InternalType.DefaultType)) { + if (ltype == rtype) { + ec.Report.Error (8315, loc, "Operator `{0}' is ambiguous on operands `default' and `default'", OperName (Oper)); + return null; + } + + if (rtype == InternalType.DefaultType) { + right = new DefaultValueExpression (new TypeExpression (ltype, right.Location), right.Location).Resolve (ec); + } else { + left = new DefaultValueExpression (new TypeExpression (rtype, left.Location), left.Location).Resolve (ec); + } + } + return DoResolveCore (ec, left, right); } @@ -13157,4 +13186,29 @@ public override object Accept (StructuralVisitor visitor) return visitor.Visit (this); } } + + class DefaultLiteralExpression : Expression + { + public DefaultLiteralExpression (Location loc) + { + this.loc = loc; + } + + public override Expression CreateExpressionTree (ResolveContext ec) + { + throw new NotImplementedException (); + } + + protected override Expression DoResolve (ResolveContext rc) + { + type = InternalType.DefaultType; + eclass = ExprClass.Value; + return this; + } + + public override void Emit (EmitContext ec) + { + throw new NotSupportedException (); + } + } } diff --git a/mcs/mcs/generic.cs b/mcs/mcs/generic.cs index 6bc036581f64..82b2d6775eb4 100644 --- a/mcs/mcs/generic.cs +++ b/mcs/mcs/generic.cs @@ -3110,6 +3110,9 @@ void AddToBounds (BoundInfo bound, int index, bool voidAllowed) if (bound.Type.IsTupleType && TupleLiteral.ContainsNoTypeElement (bound.Type)) return; + if (bound.Type == InternalType.DefaultType) + return; + var a = bounds [index]; if (a == null) { a = new List (2); diff --git a/mcs/mcs/import.cs b/mcs/mcs/import.cs index 81cb469171a0..d7e1f383ad67 100644 --- a/mcs/mcs/import.cs +++ b/mcs/mcs/import.cs @@ -1446,7 +1446,14 @@ public static AttributesBag Read (MemberInfo mi, MetadataImporter importer) if (args.Count == 1) { bag.Obsolete = new ObsoleteAttribute ((string) args[0].Value); } else if (args.Count == 2) { - bag.Obsolete = new ObsoleteAttribute ((string) args[0].Value, (bool) args[1].Value); + const string ByRefLikeMarker = "Types with embedded references are not supported in this version of your compiler."; + + var msg = (string)args[0].Value; + + if (msg == ByRefLikeMarker) + continue; + + bag.Obsolete = new ObsoleteAttribute (msg, (bool) args[1].Value); } else { bag.Obsolete = new ObsoleteAttribute (); } diff --git a/mcs/mcs/parameter.cs b/mcs/mcs/parameter.cs index 2bd2a498a919..cc10eee162b0 100644 --- a/mcs/mcs/parameter.cs +++ b/mcs/mcs/parameter.cs @@ -1447,7 +1447,7 @@ public void Resolve (ResolveContext rc, Parameter p) expr = Child; - if (!(expr is Constant || expr is DefaultValueExpression || (expr is New && ((New) expr).IsGeneratedStructConstructor))) { + if (!(expr is Constant || expr is DefaultValueExpression || expr is DefaultLiteralExpression || (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", diff --git a/mcs/mcs/statement.cs b/mcs/mcs/statement.cs index 58ba2795e4b9..78cc7661ddc8 100644 --- a/mcs/mcs/statement.cs +++ b/mcs/mcs/statement.cs @@ -2368,7 +2368,12 @@ protected override Expression ResolveInitializer (BlockContext bc, LocalVariable if (initializer == null) return null; - var c = initializer as Constant; + Constant c; + if (initializer.Type == InternalType.DefaultType) + c = New.Constantify (li.Type, initializer.Location); + else + c = initializer as Constant; + if (c == null) { initializer.Error_ExpressionMustBeConstant (bc, initializer.Location, li.Name); return null; @@ -8191,7 +8196,9 @@ MethodGroupExpr ResolveGetEnumerator (ResolveContext rc) } if (iface_candidate == null) { - if (expr.Type != InternalType.ErrorType) { + if (expr.Type == InternalType.DefaultType) { + rc.Report.Error (8312, loc, "Use of default literal is not valid in this context"); + } else if (expr.Type != InternalType.ErrorType) { rc.Report.Error (1579, loc, "foreach statement cannot operate on variables of type `{0}' because it does not contain a definition for `{1}' or is inaccessible", expr.Type.GetSignatureForError (), "GetEnumerator"); diff --git a/mcs/mcs/tuples.cs b/mcs/mcs/tuples.cs index bb7faf734df2..71175acf5405 100644 --- a/mcs/mcs/tuples.cs +++ b/mcs/mcs/tuples.cs @@ -557,6 +557,7 @@ public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool public override void FlowAnalysis (FlowAnalysisContext fc) { + source.FlowAnalysis (fc); foreach (var expr in targetExprs) expr.FlowAnalysis (fc); } diff --git a/mcs/mcs/typespec.cs b/mcs/mcs/typespec.cs index 08ffba569ab5..4627af210321 100644 --- a/mcs/mcs/typespec.cs +++ b/mcs/mcs/typespec.cs @@ -1472,6 +1472,7 @@ class InternalType : TypeSpec, ITypeDefinition public static readonly InternalType ErrorType = new InternalType (""); public static readonly InternalType VarOutType = new InternalType ("var out"); public static readonly InternalType ThrowExpr = new InternalType ("throw expression"); + public static readonly InternalType DefaultType = new InternalType ("default"); readonly string name; @@ -1616,7 +1617,7 @@ void IMemberDefinition.SetIsUsed () public static bool HasNoType (TypeSpec type) { - return type == AnonymousMethod || type == MethodGroup || type == NullLiteral || type == ThrowExpr; + return type == AnonymousMethod || type == MethodGroup || type == NullLiteral || type == ThrowExpr || type == DefaultType; } } diff --git a/mcs/packages/Makefile b/mcs/packages/Makefile index 696039fc383d..8eb7c3a5e6c3 100644 --- a/mcs/packages/Makefile +++ b/mcs/packages/Makefile @@ -10,6 +10,9 @@ ROSLYN_FILES_FOR_MONO = \ $(ROSLYN_CSC_DIR)/csi.exe \ $(ROSLYN_CSC_DIR)/csi.exe.config \ $(ROSLYN_CSC_DIR)/csi.rsp \ + $(ROSLYN_CSC_DIR)/vbc.exe \ + $(ROSLYN_CSC_DIR)/vbc.exe.config \ + $(ROSLYN_CSC_DIR)/vbc.rsp \ $(ROSLYN_CSC_DIR)/Microsoft.CodeAnalysis.CSharp.dll \ $(ROSLYN_CSC_DIR)/Microsoft.CodeAnalysis.CSharp.Scripting.dll \ $(ROSLYN_CSC_DIR)/Microsoft.CodeAnalysis.VisualBasic.dll \ diff --git a/mcs/tests/test-default-01.cs b/mcs/tests/test-default-01.cs new file mode 100644 index 000000000000..823e33c451b9 --- /dev/null +++ b/mcs/tests/test-default-01.cs @@ -0,0 +1,52 @@ +// Compiler options: -langversion:latest + +static class X +{ + const int c1 = default; + const int c2 = default (int); + + public static void Main () + { + int a = default; + var b = (int) default; + const int c = default; + var d = new[] { 1, default }; + dynamic e = default; + int f = checked (default); + (int a, int b) g = (1, default); + var h = 1 != default; + var i = default == M4 (); + } + + static int M1 () + { + return default; + } + + static void M2 () + { + try { + throw new System.Exception (); + } catch (System.Exception) when (default) { + } + + if (default) { + } + } + + static void M3 (int x = default) + { + } + + static System.Func M4 () + { + return () => default; + } +} +/* +enum E +{ + A = default, + B = default + 1 +} +*/ \ No newline at end of file diff --git a/mcs/tests/test-default-02.cs b/mcs/tests/test-default-02.cs new file mode 100644 index 000000000000..225da9b6d2b0 --- /dev/null +++ b/mcs/tests/test-default-02.cs @@ -0,0 +1,21 @@ +// Compiler options: -langversion:latest + +class C +{ + static void Main() + { + M (default, 1); + + M2 (default); + M2 (null); + } + + + static void M (T x, T y) + { + } + + static void M2 (params object[] x) + { + } +} \ No newline at end of file diff --git a/mcs/tests/test-tuple-08.cs b/mcs/tests/test-tuple-08.cs new file mode 100644 index 000000000000..fd3375b4df66 --- /dev/null +++ b/mcs/tests/test-tuple-08.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +class X +{ + public static void Main () + { + var x = new X (); + x.Test ().Wait (); + } + + int a, b; + + async Task Test () + { + (a, b) = await Waiting (); + } + + Task<(int, int)> Waiting () + { + return Task.FromResult ((1, 3)); + } +} \ No newline at end of file diff --git a/mcs/tests/ver-il-net_4_x.xml b/mcs/tests/ver-il-net_4_x.xml index c69461ef76b2..3d4d271f3db2 100644 --- a/mcs/tests/ver-il-net_4_x.xml +++ b/mcs/tests/ver-il-net_4_x.xml @@ -68527,6 +68527,44 @@ + + + + 53 + + + 10 + + + 31 + + + 2 + + + 38 + + + 9 + + + + + + + 8 + + + 2 + + + 2 + + + 7 + + + @@ -73461,6 +73499,30 @@ + + + + 19 + + + 41 + + + 21 + + + 7 + + + + + 212 + + + 13 + + + diff --git a/mcs/tools/linker-analyzer/ConsoleDependencyGraph.cs b/mcs/tools/linker-analyzer/ConsoleDependencyGraph.cs index a778ffd85987..f733b1efdeee 100644 --- a/mcs/tools/linker-analyzer/ConsoleDependencyGraph.cs +++ b/mcs/tools/linker-analyzer/ConsoleDependencyGraph.cs @@ -16,6 +16,7 @@ namespace LinkerAnalyzer public class ConsoleDependencyGraph : DependencyGraph { public bool Tree = false; + public bool FlatDeps; public void ShowDependencies (string raw, List verticesList, string searchString) { @@ -39,8 +40,32 @@ public void ShowDependencies (string raw, List verticesList, string ShowDependencies (vertex); } + void ShowFlatDependencies (VertexData vertex) + { + bool first = true; + var flatDeps = GetAllDependencies (vertex); + + Console.WriteLine (); + + foreach (var d in flatDeps) { + if (first) { + Console.WriteLine ($"Distance | {d.Item1.value} [total deps: {flatDeps.Count}]"); + Line (); + first = false; + continue; + } + Console.WriteLine ($"{string.Format ("{0,8}", d.Item2)} | {d.Item1.value}"); + } + } + public void ShowDependencies (VertexData vertex) { + if (FlatDeps) { + ShowFlatDependencies (vertex); + + return; + } + Header ("{0} dependencies", vertex.value); if (vertex.parentIndexes == null) { Console.WriteLine ("Root dependency"); @@ -133,14 +158,19 @@ public void ShowTypeDependencies (string raw) ShowDependencies ("TypeDef:" + raw, Types, raw); } + static readonly string line = new string ('-', 72); + + void Line () + { + Console.Write (line); + Console.WriteLine (); + } + void Header (string header, params object[] values) { string formatted = string.Format (header, values); Console.WriteLine (); - Console.Write ("--- {0} ", formatted); - for (int i=0; i< Math.Max (3, 64 - formatted.Length); i++) - Console.Write ('-'); - Console.WriteLine (); + Console.WriteLine ($"--- {formatted} {new string ('-', Math.Max (3, 67 - formatted.Length))}"); } } } diff --git a/mcs/tools/linker-analyzer/LinkerAnalyzerCore/DependencyGraph.cs b/mcs/tools/linker-analyzer/LinkerAnalyzerCore/DependencyGraph.cs index e488209b1092..3ab825d2b13f 100644 --- a/mcs/tools/linker-analyzer/LinkerAnalyzerCore/DependencyGraph.cs +++ b/mcs/tools/linker-analyzer/LinkerAnalyzerCore/DependencyGraph.cs @@ -39,14 +39,14 @@ public void Load (string filename) { Console.WriteLine ("Loading dependency tree from: {0}", filename); - using (var fileStream = File.OpenRead (filename)) - using (var zipStream = new GZipStream (fileStream, CompressionMode.Decompress)) { - try { + try { + using (var fileStream = File.OpenRead (filename)) + using (var zipStream = new GZipStream (fileStream, CompressionMode.Decompress)) { Load (zipStream); - } catch (Exception) { - Console.WriteLine ("Unable to open and read the dependecies."); - Environment.Exit (1); } + } catch (Exception) { + Console.WriteLine ("Unable to open and read the dependecies."); + Environment.Exit (1); } } @@ -114,5 +114,28 @@ public VertexData Vertex (int index) { return vertices [index]; } + + IEnumerable> AddDependencies (VertexData vertex, HashSet reachedVertices, int depth) + { + reachedVertices.Add (vertex.index); + yield return new Tuple (vertex, depth); + + if (vertex.parentIndexes == null) + yield break; + + foreach (var pi in vertex.parentIndexes) { + var parent = Vertex (pi); + if (reachedVertices.Contains (parent.index)) + continue; + + foreach (var d in AddDependencies (parent, reachedVertices, depth + 1)) + yield return d; + } + } + + public List> GetAllDependencies (VertexData vertex) + { + return new List> (AddDependencies (vertex, new HashSet (), 0)); + } } } diff --git a/mcs/tools/linker-analyzer/Main.cs b/mcs/tools/linker-analyzer/Main.cs index 5c75ba5c8633..df726f639c77 100644 --- a/mcs/tools/linker-analyzer/Main.cs +++ b/mcs/tools/linker-analyzer/Main.cs @@ -28,6 +28,7 @@ static void Main (string[] args) bool showTypes = false; bool reduceToTree = false; bool verbose = false; + bool flatDeps = false; var optionsParser = new OptionSet () { { "a|alldeps", "show all dependencies", v => { showAllDeps = v != null; } }, @@ -39,6 +40,7 @@ static void Main (string[] args) { "types", "show all types dependencies.", v => showTypes = v != null }, { "t|typedeps=", "show type dependencies. The VALUE can be regular expression", v => { showTypeDeps = v != null; typeName = v; } }, //{ "u|spaceusage", "show space analysis.", v => showSpaceUsage = v != null }, + { "f|flat", "show all dependencies per vertex and their distance", v => flatDeps = v != null }, { "v|verbose", "be more verbose. Enables stat and roots options.", v => verbose = v != null }, }; @@ -56,7 +58,7 @@ static void Main (string[] args) string dependencyFile = args [args.Length - 1]; - ConsoleDependencyGraph deps = new ConsoleDependencyGraph () { Tree = reduceToTree }; + ConsoleDependencyGraph deps = new ConsoleDependencyGraph () { Tree = reduceToTree, FlatDeps = flatDeps }; deps.Load (dependencyFile); if (showSpaceUsage) { diff --git a/mcs/tools/linker-analyzer/Makefile b/mcs/tools/linker-analyzer/Makefile index 08a3fdc093a7..7b928a9f63e5 100644 --- a/mcs/tools/linker-analyzer/Makefile +++ b/mcs/tools/linker-analyzer/Makefile @@ -4,7 +4,7 @@ include ../../build/rules.make PROGRAM = linkeranalyzer.exe -LIB_REFS = System System.Xml +LIB_REFS = System System.Xml System.Core LOCAL_MCS_FLAGS = include ../../build/executable.make diff --git a/mcs/tools/linker-analyzer/README.md b/mcs/tools/linker-analyzer/README.md index a848021c526f..c5bb11868bde 100644 --- a/mcs/tools/linker-analyzer/README.md +++ b/mcs/tools/linker-analyzer/README.md @@ -121,5 +121,6 @@ Options: --types show all types dependencies. -t, --typedeps=VALUE show type dependencies. The VALUE can be regular expression + -f, --flat show all dependencies per vertex and their distance -v, --verbose be more verbose. Enables stat and roots options. ``` diff --git a/mcs/tools/linker-analyzer/linkeranalyzer-net_4_x.csproj b/mcs/tools/linker-analyzer/linkeranalyzer-net_4_x.csproj index 6751055bfdf9..e02a89eb639b 100644 --- a/mcs/tools/linker-analyzer/linkeranalyzer-net_4_x.csproj +++ b/mcs/tools/linker-analyzer/linkeranalyzer-net_4_x.csproj @@ -91,6 +91,10 @@ {87FD2F0F-5222-4AE6-BD63-2D4975E11E5B} System.Xml-net_4_x + + {359142A1-D80F-401E-AA64-7167C9317649} + System.Core-net_4_x + diff --git a/mono/metadata/Makefile.am b/mono/metadata/Makefile.am index 056188e53400..c0e5065842f9 100644 --- a/mono/metadata/Makefile.am +++ b/mono/metadata/Makefile.am @@ -63,6 +63,13 @@ if HOST_ANDROID platform_sources += ../../support/libm/complex.c endif +if HOST_WASM +platform_sources += threadpool-worker-wasm.c +else +platform_sources += threadpool-worker-default.c +endif + + # # libtool is not capable of creating static/shared versions of the same # convenience lib, so we have to do it ourselves @@ -140,7 +147,8 @@ unity_sources = \ unity-memory-info.c \ unity-memory-info.h \ unity-utils.c \ - unity-utils.h + unity-utils.h \ + unity-icall.c common_sources = \ $(platform_sources) \ @@ -264,7 +272,6 @@ common_sources = \ threads-types.h \ threadpool.c \ threadpool.h \ - threadpool-worker-default.c \ threadpool-worker.h \ threadpool-io.c \ threadpool-io.h \ diff --git a/mono/metadata/boehm-gc.c b/mono/metadata/boehm-gc.c index f312607de343..32481b1510d2 100644 --- a/mono/metadata/boehm-gc.c +++ b/mono/metadata/boehm-gc.c @@ -560,21 +560,21 @@ register_root (gpointer arg) } int -mono_gc_register_root (char *start, size_t size, void *descr, MonoGCRootSource source, const char *msg) +mono_gc_register_root (char *start, size_t size, void *descr, MonoGCRootSource source, void *key, const char *msg) { RootData root_data; root_data.start = start; /* Boehm root processing requires one byte past end of region to be scanned */ root_data.end = start + size + 1; GC_call_with_alloc_lock (register_root, &root_data); - + MONO_PROFILER_RAISE (gc_root_register, ((const mono_byte *) start, size, source, key, msg)); return TRUE; } int -mono_gc_register_root_wbarrier (char *start, size_t size, MonoGCDescriptor descr, MonoGCRootSource source, const char *msg) +mono_gc_register_root_wbarrier (char *start, size_t size, MonoGCDescriptor descr, MonoGCRootSource source, void *key, const char *msg) { - return mono_gc_register_root (start, size, descr, source, msg); + return mono_gc_register_root (start, size, descr, source, key, msg); } static gpointer @@ -589,6 +589,7 @@ void mono_gc_deregister_root (char* addr) { GC_call_with_alloc_lock (deregister_root, addr); + MONO_PROFILER_RAISE (gc_root_unregister, ((const mono_byte *) addr)); } static void @@ -707,14 +708,17 @@ mono_gc_make_root_descr_all_refs (int numbits) } void* -mono_gc_alloc_fixed (size_t size, void *descr, MonoGCRootSource source, const char *msg) +mono_gc_alloc_fixed (size_t size, void *descr, MonoGCRootSource source, void *key, const char *msg) { - return GC_MALLOC_UNCOLLECTABLE (size); + void *start = GC_MALLOC_UNCOLLECTABLE (size); + MONO_PROFILER_RAISE (gc_root_register, ((const mono_byte *) start, size, source, key, msg)); + return start; } void mono_gc_free_fixed (void* addr) { + MONO_PROFILER_RAISE (gc_root_unregister, ((const mono_byte *) addr)); GC_FREE (addr); } @@ -1522,10 +1526,19 @@ BOOL APIENTRY mono_gc_dllmain (HMODULE module_handle, DWORD reason, LPVOID reser { #ifdef GC_INSIDE_DLL return GC_DllMain (module_handle, reason, reserved); +#else + return TRUE; #endif } #endif +MonoVTable * +mono_gc_get_vtable (MonoObject *obj) +{ + // No pointer tagging. + return obj->vtable; +} + guint mono_gc_get_vtable_bits (MonoClass *klass) { @@ -1693,7 +1706,7 @@ handle_data_alloc_entries (HandleData *handles) handles->entries = (void **)g_malloc0 (sizeof (*handles->entries) * handles->size); handles->domain_ids = (guint16 *)g_malloc0 (sizeof (*handles->domain_ids) * handles->size); } else { - handles->entries = (void **)mono_gc_alloc_fixed (sizeof (*handles->entries) * handles->size, NULL, MONO_ROOT_SOURCE_GC_HANDLE, "gc handles table"); + handles->entries = (void **)mono_gc_alloc_fixed (sizeof (*handles->entries) * handles->size, NULL, MONO_ROOT_SOURCE_GC_HANDLE, NULL, "GC Handle Table (Boehm)"); } handles->bitmap = (guint32 *)g_malloc0 (handles->size / CHAR_BIT); } @@ -1760,7 +1773,7 @@ handle_data_grow (HandleData *handles, gboolean track) handles->domain_ids = domain_ids; } else { gpointer *entries; - entries = (void **)mono_gc_alloc_fixed (sizeof (*handles->entries) * new_size, NULL, MONO_ROOT_SOURCE_GC_HANDLE, "gc handles table"); + entries = (void **)mono_gc_alloc_fixed (sizeof (*handles->entries) * new_size, NULL, MONO_ROOT_SOURCE_GC_HANDLE, NULL, "GC Handle Table (Boehm)"); mono_gc_memmove_aligned (entries, handles->entries, sizeof (*handles->entries) * handles->size); mono_gc_free_fixed (handles->entries); handles->entries = entries; @@ -2038,6 +2051,13 @@ mono_gchandle_free_domain (MonoDomain *domain) } } + +void +mono_gc_register_obj_with_weak_fields (void *obj) +{ + g_error ("Weak fields not supported by boehm gc"); +} + #else MONO_EMPTY_SOURCE_FILE (boehm_gc); diff --git a/mono/metadata/class-accessors.c b/mono/metadata/class-accessors.c index cb13369b44fc..189cfbba3fb3 100644 --- a/mono/metadata/class-accessors.c +++ b/mono/metadata/class-accessors.c @@ -16,7 +16,8 @@ typedef enum { PROP_PROPERTY_INFO = 5, /* MonoClassPropertyInfo* */ PROP_EVENT_INFO = 6, /* MonoClassEventInfo* */ PROP_FIELD_DEF_VALUES = 7, /* MonoFieldDefaultValue* */ - PROP_DECLSEC_FLAGS = 8 /* guint32 */ + PROP_DECLSEC_FLAGS = 8, /* guint32 */ + PROP_WEAK_BITMAP = 9 } InfrequentDataKind; /* Accessors based on class kind*/ @@ -390,3 +391,31 @@ mono_class_gtd_get_canonical_inst (MonoClass *klass) g_assert (mono_class_is_gtd (klass)); return &((MonoClassGtd*)klass)->canonical_inst; } + +typedef struct { + MonoPropertyBagItem head; + + int nbits; + gsize *bits; +} WeakBitmapData; + +void +mono_class_set_weak_bitmap (MonoClass *klass, int nbits, gsize *bits) +{ + WeakBitmapData *info = mono_class_alloc (klass, sizeof (WeakBitmapData)); + info->nbits = nbits; + info->bits = bits; + + info->head.tag = PROP_WEAK_BITMAP; + mono_property_bag_add (&klass->infrequent_data, info); +} + +gsize* +mono_class_get_weak_bitmap (MonoClass *klass, int *nbits) +{ + WeakBitmapData *prop = mono_property_bag_get (&klass->infrequent_data, PROP_WEAK_BITMAP); + + g_assert (prop); + *nbits = prop->nbits; + return prop->bits; +} diff --git a/mono/metadata/class-internals.h b/mono/metadata/class-internals.h index 441b67777d12..b07662b78517 100644 --- a/mono/metadata/class-internals.h +++ b/mono/metadata/class-internals.h @@ -332,6 +332,7 @@ struct _MonoClass { guint has_finalize_inited : 1; /* has_finalize is initialized */ guint fields_inited : 1; /* setup_fields () has finished */ guint has_failure : 1; /* See mono_class_get_exception_data () for a MonoErrorBoxed with the details */ + guint has_weak_fields : 1; /* class has weak reference fields */ MonoClass *parent; MonoClass *nested_in; @@ -706,6 +707,7 @@ typedef struct MonoCachedClassInfo { guint has_static_refs : 1; guint no_special_static_fields : 1; guint is_generic_container : 1; + guint has_weak_fields : 1; guint32 cctor_token; MonoImage *finalize_image; guint32 finalize_token; @@ -960,9 +962,8 @@ mono_class_get_vtable_size (MonoClass *klass); gboolean mono_class_is_open_constructed_type (MonoType *t); -gboolean -mono_class_get_overrides_full (MonoImage *image, guint32 type_token, MonoMethod ***overrides, gint32 *num_overrides, - MonoGenericContext *generic_context); +void +mono_class_get_overrides_full (MonoImage *image, guint32 type_token, MonoMethod ***overrides, gint32 *num_overrides, MonoGenericContext *generic_context, MonoError *error); MonoMethod* mono_class_get_cctor (MonoClass *klass) MONO_LLVM_INTERNAL; @@ -1535,6 +1536,12 @@ mono_class_set_declsec_flags (MonoClass *klass, guint32 value); void mono_class_set_is_com_object (MonoClass *klass); +void +mono_class_set_weak_bitmap (MonoClass *klass, int nbits, gsize *bits); + +gsize* +mono_class_get_weak_bitmap (MonoClass *klass, int *nbits); + /*Now that everything has been defined, let's include the inline functions */ #include diff --git a/mono/metadata/class.c b/mono/metadata/class.c index 3107638466fd..ccdae030ef9b 100644 --- a/mono/metadata/class.c +++ b/mono/metadata/class.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -1667,6 +1668,7 @@ init_sizes_with_info (MonoClass *klass, MonoCachedClassInfo *cached_info) klass->has_references = cached_info->has_references; klass->has_static_refs = cached_info->has_static_refs; klass->no_special_static_fields = cached_info->no_special_static_fields; + klass->has_weak_fields = cached_info->has_weak_fields; mono_loader_unlock (); } else { @@ -2210,18 +2212,40 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_ mono_class_set_type_load_failure (klass, "Value type instance size (%d) cannot be zero, negative, or bigger than 1Mb", klass->instance_size); } + // Weak field support + // + // FIXME: + // - generic instances + // - Disallow on structs/static fields/nonref fields + gboolean has_weak_fields = FALSE; + + if (mono_class_has_static_metadata (klass)) { + for (MonoClass *p = klass; p != NULL; p = p->parent) { + gpointer iter = NULL; + guint32 first_field_idx = mono_class_get_first_field_idx (p); + + while ((field = mono_class_get_fields (p, &iter))) { + guint32 field_idx = first_field_idx + (field - p->fields); + if (MONO_TYPE_IS_REFERENCE (field->type) && mono_assembly_is_weak_field (p->image, field_idx + 1)) { + has_weak_fields = TRUE; + mono_trace_message (MONO_TRACE_TYPE, "Field %s:%s at offset %x is weak.", field->parent->name, field->name, field->offset); + } + } + } + } + /* Publish the data */ mono_loader_lock (); if (!klass->rank) klass->sizes.class_size = class_size; klass->has_static_refs = has_static_refs; + klass->has_weak_fields = has_weak_fields; for (i = 0; i < top; ++i) { field = &klass->fields [i]; if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) field->offset = field_offsets [i]; } - mono_memory_barrier (); klass->fields_inited = 1; mono_loader_unlock (); @@ -3574,11 +3598,10 @@ static void mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup) { MonoError error; - MonoMethod **overrides; + MonoMethod **overrides = NULL; MonoGenericContext *context; guint32 type_token; int onum = 0; - gboolean ok = TRUE; if (klass->vtable) return; @@ -3626,24 +3649,24 @@ mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup) */ mono_reflection_get_dynamic_overrides (klass, &overrides, &onum, &error); if (!is_ok (&error)) { - mono_loader_unlock (); - g_list_remove (in_setup, klass); mono_class_set_type_load_failure (klass, "Could not load list of method overrides due to %s", mono_error_get_message (&error)); - mono_error_cleanup (&error); - return; + goto done; } } else { /* The following call fails if there are missing methods in the type */ /* FIXME it's probably a good idea to avoid this for generic instances. */ - ok = mono_class_get_overrides_full (klass->image, type_token, &overrides, &onum, context); + mono_class_get_overrides_full (klass->image, type_token, &overrides, &onum, context, &error); + if (!is_ok (&error)) { + mono_class_set_type_load_failure (klass, "Could not load list of method overrides due to %s", mono_error_get_message (&error)); + goto done; + } } - if (ok) - mono_class_setup_vtable_general (klass, overrides, onum, in_setup); - else - mono_class_set_type_load_failure (klass, "Could not load list of method overrides"); - + mono_class_setup_vtable_general (klass, overrides, onum, in_setup); + +done: g_free (overrides); + mono_error_cleanup (&error); mono_loader_unlock (); g_list_remove (in_setup, klass); @@ -4118,6 +4141,8 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o GSList *virt_methods = NULL, *l; int stelemref_slot = 0; + error_init (&error); + if (klass->vtable) return; @@ -4184,11 +4209,7 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o for (i = 0; i < gklass->vtable_size; ++i) if (gklass->vtable [i]) { MonoMethod *inflated = mono_class_inflate_generic_method_full_checked (gklass->vtable [i], klass, mono_class_get_context (klass), &error); - if (!mono_error_ok (&error)) { - mono_class_set_type_load_failure (klass, "Could not inflate method due to %s", mono_error_get_message (&error)); - mono_error_cleanup (&error); - return; - } + goto_if_nok (&error, fail); tmp [i] = inflated; tmp [i]->slot = gklass->vtable [i]->slot; } @@ -4267,20 +4288,19 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o MonoMethod **iface_overrides; int iface_onum; - gboolean ok = mono_class_get_overrides_full (ic->image, ic->type_token, &iface_overrides, &iface_onum, mono_class_get_context (ic)); - if (ok) { - for (int i = 0; i < iface_onum; i++) { - MonoMethod *decl = iface_overrides [i*2]; - MonoMethod *override = iface_overrides [i*2 + 1]; - if (!apply_override (klass, vtable, decl, override)) - goto fail; + mono_class_get_overrides_full (ic->image, ic->type_token, &iface_overrides, &iface_onum, mono_class_get_context (ic), &error); + goto_if_nok (&error, fail); + for (int i = 0; i < iface_onum; i++) { + MonoMethod *decl = iface_overrides [i*2]; + MonoMethod *override = iface_overrides [i*2 + 1]; + if (!apply_override (klass, vtable, decl, override)) + goto fail; - if (!override_map) - override_map = g_hash_table_new (mono_aligned_addr_hash, NULL); - g_hash_table_insert (override_map, decl, override); - } - g_free (iface_overrides); + if (!override_map) + override_map = g_hash_table_new (mono_aligned_addr_hash, NULL); + g_hash_table_insert (override_map, decl, override); } + g_free (iface_overrides); } /* override interface methods */ @@ -4466,11 +4486,8 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o cmsig = mono_method_signature (cm); m1sig = mono_method_signature (m1); - if (!cmsig || !m1sig) { - /* FIXME proper error message */ - mono_class_set_type_load_failure (klass, ""); - return; - } + if (!cmsig || !m1sig) /* FIXME proper error message, use signature_checked? */ + goto fail; if (!strcmp(cm->name, m1->name) && mono_metadata_signature_equal (cmsig, m1sig)) { @@ -4659,7 +4676,11 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o fail: { char *name = mono_type_get_full_name (klass); - mono_class_set_type_load_failure (klass, "VTable setup of type %s failed", name); + if (!is_ok (&error)) + mono_class_set_type_load_failure (klass, "VTable setup of type %s failed due to: %s", name, mono_error_get_message (&error)); + else + mono_class_set_type_load_failure (klass, "VTable setup of type %s failed", name); + mono_error_cleanup (&error); g_free (name); g_free (vtable); if (override_map) diff --git a/mono/metadata/custom-attrs-internals.h b/mono/metadata/custom-attrs-internals.h index 1f9150c33e36..a848c0b0e376 100644 --- a/mono/metadata/custom-attrs-internals.h +++ b/mono/metadata/custom-attrs-internals.h @@ -16,4 +16,10 @@ typedef gboolean (*MonoAssemblyMetadataCustomAttrIterFunc) (MonoImage *image, gu void mono_assembly_metadata_foreach_custom_attr (MonoAssembly *assembly, MonoAssemblyMetadataCustomAttrIterFunc func, gpointer user_data); +gboolean +mono_assembly_is_weak_field (MonoImage *image, guint32 field_idx); + +void +mono_assembly_init_weak_fields (MonoImage *image); + #endif /* __MONO_METADATA_REFLECTION_CUSTOM_ATTRS_INTERNALS_H__ */ diff --git a/mono/metadata/custom-attrs.c b/mono/metadata/custom-attrs.c index 7c160a848671..ffd4d4a43e19 100644 --- a/mono/metadata/custom-attrs.c +++ b/mono/metadata/custom-attrs.c @@ -761,7 +761,7 @@ create_custom_attr (MonoImage *image, MonoMethod *method, const guchar *data, gu memset (params, 0, sizeof (void*) * sig->param_count); } else { /* Allocate using GC so it gets GC tracking */ - params = (void **)mono_gc_alloc_fixed (sig->param_count * sizeof (void*), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_REFLECTION, "custom attribute parameters"); + params = (void **)mono_gc_alloc_fixed (sig->param_count * sizeof (void*), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_REFLECTION, NULL, "Reflection Custom Attribute Parameters"); } /* skip prolog */ @@ -2155,3 +2155,181 @@ mono_assembly_metadata_foreach_custom_attr (MonoAssembly *assembly, MonoAssembly stop_iterating = func (image, assembly_token, nspace, name, mtoken, user_data); } } + +static void +init_weak_fields_inner (MonoImage *image, GHashTable *indexes) +{ + MonoTableInfo *tdef; + MonoError error; + MonoClass *klass = NULL; + guint32 memberref_index = -1; + int first_method_idx = -1; + int method_count = -1; + + if (image == mono_get_corlib ()) { + /* Typedef */ + klass = mono_class_from_name_checked (image, "System", "WeakAttribute", &error); + if (!is_ok (&error)) { + mono_error_cleanup (&error); + return; + } + if (!klass) + return; + first_method_idx = mono_class_get_first_method_idx (klass); + method_count = mono_class_get_method_count (klass); + + tdef = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE]; + guint32 parent, field_idx, col, mtoken, idx; + for (int i = 0; i < tdef->rows; ++i) { + parent = mono_metadata_decode_row_col (tdef, i, MONO_CUSTOM_ATTR_PARENT); + if ((parent & MONO_CUSTOM_ATTR_MASK) != MONO_CUSTOM_ATTR_FIELDDEF) + continue; + + col = mono_metadata_decode_row_col (tdef, i, MONO_CUSTOM_ATTR_TYPE); + mtoken = col >> MONO_CUSTOM_ATTR_TYPE_BITS; + /* 1 based index */ + idx = mtoken - 1; + if ((col & MONO_CUSTOM_ATTR_TYPE_MASK) == MONO_CUSTOM_ATTR_TYPE_METHODDEF) { + field_idx = parent >> MONO_CUSTOM_ATTR_BITS; + if (idx >= first_method_idx && idx < first_method_idx + method_count) + g_hash_table_insert (indexes, GUINT_TO_POINTER (field_idx), GUINT_TO_POINTER (1)); + } + } + } else { + /* Memberref pointing to a typeref */ + tdef = &image->tables [MONO_TABLE_MEMBERREF]; + + /* Check whenever the assembly references the WeakAttribute type */ + gboolean found = FALSE; + tdef = &image->tables [MONO_TABLE_TYPEREF]; + for (int i = 0; i < tdef->rows; ++i) { + guint32 string_offset = mono_metadata_decode_row_col (tdef, i, MONO_TYPEREF_NAME); + const char *name = mono_metadata_string_heap (image, string_offset); + if (!strcmp (name, "WeakAttribute")) { + found = TRUE; + break; + } + } + + if (!found) + return; + + /* Find the memberref pointing to a typeref */ + tdef = &image->tables [MONO_TABLE_MEMBERREF]; + for (int i = 0; i < tdef->rows; ++i) { + guint32 cols [MONO_MEMBERREF_SIZE]; + const char *sig; + + mono_metadata_decode_row (tdef, i, cols, MONO_MEMBERREF_SIZE); + sig = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]); + mono_metadata_decode_blob_size (sig, &sig); + + guint32 nindex = cols [MONO_MEMBERREF_CLASS] >> MONO_MEMBERREF_PARENT_BITS; + guint32 class_index = cols [MONO_MEMBERREF_CLASS] & MONO_MEMBERREF_PARENT_MASK; + const char *fname = mono_metadata_string_heap (image, cols [MONO_MEMBERREF_NAME]); + + if (!strcmp (fname, ".ctor") && class_index == MONO_MEMBERREF_PARENT_TYPEREF) { + MonoTableInfo *typeref_table = &image->tables [MONO_TABLE_TYPEREF]; + guint32 cols [MONO_TYPEREF_SIZE]; + + mono_metadata_decode_row (typeref_table, nindex - 1, cols, MONO_TYPEREF_SIZE); + + const char *name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]); + const char *nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]); + + if (!strcmp (nspace, "System") && !strcmp (name, "WeakAttribute")) { + MonoClass *klass = mono_class_from_typeref (image, MONO_TOKEN_TYPE_REF | nindex); + g_assert (!strcmp (klass->name, "WeakAttribute")); + /* Allow a testing dll as well since some profiles don't have WeakAttribute */ + if (klass && (klass->image == mono_get_corlib () || strstr (klass->image->name, "Mono.Runtime.Testing"))) { + /* Sanity check that it only has 1 ctor */ + gpointer iter = NULL; + int count = 0; + MonoMethod *method; + while ((method = mono_class_get_methods (klass, &iter))) { + if (!strcmp (method->name, ".ctor")) + count ++; + } + count ++; + memberref_index = i; + break; + } + } + } + } + if (memberref_index == -1) + return; + + tdef = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE]; + guint32 parent, field_idx, col, mtoken, idx; + for (int i = 0; i < tdef->rows; ++i) { + parent = mono_metadata_decode_row_col (tdef, i, MONO_CUSTOM_ATTR_PARENT); + if ((parent & MONO_CUSTOM_ATTR_MASK) != MONO_CUSTOM_ATTR_FIELDDEF) + continue; + + col = mono_metadata_decode_row_col (tdef, i, MONO_CUSTOM_ATTR_TYPE); + mtoken = col >> MONO_CUSTOM_ATTR_TYPE_BITS; + /* 1 based index */ + idx = mtoken - 1; + field_idx = parent >> MONO_CUSTOM_ATTR_BITS; + if ((col & MONO_CUSTOM_ATTR_TYPE_MASK) == MONO_CUSTOM_ATTR_TYPE_MEMBERREF) { + if (idx == memberref_index) + g_hash_table_insert (indexes, GUINT_TO_POINTER (field_idx), GUINT_TO_POINTER (1)); + } + } + } +} + +/* + * mono_assembly_init_weak_fields: + * + * Initialize the image->weak_field_indexes hash. + */ +void +mono_assembly_init_weak_fields (MonoImage *image) +{ + if (image->weak_fields_inited) + return; + + GHashTable *indexes = NULL; + + if (mono_get_runtime_callbacks ()->get_weak_field_indexes) + indexes = mono_get_runtime_callbacks ()->get_weak_field_indexes (image); + if (!indexes) { + indexes = g_hash_table_new (NULL, NULL); + + /* + * To avoid lookups for every field, we scan the customattr table for entries whose + * parent is a field and whose type is WeakAttribute. + */ + init_weak_fields_inner (image, indexes); + } + + mono_image_lock (image); + if (!image->weak_fields_inited) { + image->weak_field_indexes = indexes; + mono_memory_barrier (); + image->weak_fields_inited = TRUE; + } else { + g_hash_table_destroy (indexes); + } + mono_image_unlock (image); +} + +/* + * mono_assembly_is_weak_field: + * + * Return whenever the FIELD table entry with the 1-based index FIELD_IDX has + * a [Weak] attribute. + */ +gboolean +mono_assembly_is_weak_field (MonoImage *image, guint32 field_idx) +{ + if (image->dynamic) + return FALSE; + + mono_assembly_init_weak_fields (image); + + /* The hash is not mutated, no need to lock */ + return g_hash_table_lookup (image->weak_field_indexes, GINT_TO_POINTER (field_idx)) != NULL; +} diff --git a/mono/metadata/domain.c b/mono/metadata/domain.c index c0386177ce54..2947589dbb76 100644 --- a/mono/metadata/domain.c +++ b/mono/metadata/domain.c @@ -292,6 +292,24 @@ mono_ptrarray_hash (gpointer *s) return hash; } +//g_malloc on sgen and mono_gc_alloc_fixed on boehm +static void* +gc_alloc_fixed_non_heap_list (size_t size) +{ + if (mono_gc_is_moving ()) + return g_malloc0 (size); + else + return mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_DOMAIN, NULL, "Domain List"); +} + +static void +gc_free_fixed_non_heap_list (void *ptr) +{ + if (mono_gc_is_moving ()) + return g_free (ptr); + else + return mono_gc_free_fixed (ptr); +} /* * Allocate an id for domain and set domain->domain_id. * LOCKING: must be called while holding appdomains_mutex. @@ -306,7 +324,8 @@ domain_id_alloc (MonoDomain *domain) int id = -1, i; if (!appdomains_list) { appdomain_list_size = 2; - appdomains_list = (MonoDomain **)mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_DOMAIN, "domains list"); + appdomains_list = (MonoDomain **)gc_alloc_fixed_non_heap_list (appdomain_list_size * sizeof (void*)); + } for (i = appdomain_next; i < appdomain_list_size; ++i) { if (!appdomains_list [i]) { @@ -328,9 +347,9 @@ domain_id_alloc (MonoDomain *domain) if (new_size >= (1 << 16)) g_assert_not_reached (); id = appdomain_list_size; - new_list = (MonoDomain **)mono_gc_alloc_fixed (new_size * sizeof (void*), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_DOMAIN, "domains list"); + new_list = (MonoDomain **)gc_alloc_fixed_non_heap_list (new_size * sizeof (void*)); memcpy (new_list, appdomains_list, appdomain_list_size * sizeof (void*)); - mono_gc_free_fixed (appdomains_list); + gc_free_fixed_non_heap_list (appdomains_list); appdomains_list = new_list; appdomain_list_size = new_size; } @@ -386,12 +405,11 @@ mono_domain_create (void) } mono_appdomains_unlock (); - if (!mono_gc_is_moving ()) { - domain = (MonoDomain *)mono_gc_alloc_fixed (sizeof (MonoDomain), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_DOMAIN, "domain object"); - } else { - domain = (MonoDomain *)mono_gc_alloc_fixed (sizeof (MonoDomain), domain_gc_desc, MONO_ROOT_SOURCE_DOMAIN, "domain object"); - mono_gc_register_root ((char*)&(domain->MONO_DOMAIN_FIRST_GC_TRACKED), G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_LAST_GC_TRACKED) - G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_GC_TRACKED), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_DOMAIN, "misc domain fields"); - } + if (!mono_gc_is_moving ()) + domain = (MonoDomain *)mono_gc_alloc_fixed (sizeof (MonoDomain), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_DOMAIN, NULL, "Domain Structure"); + else + domain = (MonoDomain *)mono_gc_alloc_fixed (sizeof (MonoDomain), domain_gc_desc, MONO_ROOT_SOURCE_DOMAIN, NULL, "Domain Structure"); + domain->shadow_serial = shadow_serial; domain->domain = NULL; domain->setup = NULL; @@ -403,14 +421,14 @@ mono_domain_create (void) domain->mp = mono_mempool_new (); domain->code_mp = mono_code_manager_new (); domain->lock_free_mp = lock_free_mempool_new (); - domain->env = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, "domain environment variables table"); + domain->env = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, domain, "Domain Environment Variable Table"); domain->domain_assemblies = NULL; domain->assembly_bindings = NULL; domain->assembly_bindings_parsed = FALSE; domain->class_vtable_array = g_ptr_array_new (); domain->proxy_vtable_hash = g_hash_table_new ((GHashFunc)mono_ptrarray_hash, (GCompareFunc)mono_ptrarray_equal); 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, MONO_ROOT_SOURCE_DOMAIN, "domain string constants table"); + domain->ldstr_table = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, domain, "Domain String Pool Table"); domain->num_jit_info_tables = 1; domain->jit_info_table = mono_jit_info_table_new (domain); domain->jit_info_free_queue = NULL; @@ -952,7 +970,7 @@ mono_domain_foreach (MonoDomainFunc func, gpointer user_data) */ mono_appdomains_lock (); size = appdomain_list_size; - copy = (MonoDomain **)mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_DOMAIN, "temporary domains list"); + copy = (MonoDomain **)gc_alloc_fixed_non_heap_list (appdomain_list_size * sizeof (void*)); memcpy (copy, appdomains_list, appdomain_list_size * sizeof (void*)); mono_appdomains_unlock (); @@ -961,7 +979,7 @@ mono_domain_foreach (MonoDomainFunc func, gpointer user_data) func (copy [i], user_data); } - mono_gc_free_fixed (copy); + gc_free_fixed_non_heap_list (copy); } /* FIXME: maybe we should integrate this with mono_assembly_open? */ diff --git a/mono/metadata/dynamic-image.c b/mono/metadata/dynamic-image.c index 9c69791245cb..e386fbbe73d5 100644 --- a/mono/metadata/dynamic-image.c +++ b/mono/metadata/dynamic-image.c @@ -352,19 +352,19 @@ mono_dynamic_image_create (MonoDynamicAssembly *assembly, char *assembly_name, c mono_image_init (&image->image); - image->token_fixups = mono_g_hash_table_new_type ((GHashFunc)mono_object_hash, NULL, MONO_HASH_KEY_GC, MONO_ROOT_SOURCE_REFLECTION, "dynamic module token fixups table"); + image->token_fixups = mono_g_hash_table_new_type ((GHashFunc)mono_object_hash, NULL, MONO_HASH_KEY_GC, MONO_ROOT_SOURCE_REFLECTION, NULL, "Reflection Dynamic Image Token Fixup Table"); image->method_to_table_idx = g_hash_table_new (NULL, NULL); image->field_to_table_idx = g_hash_table_new (NULL, NULL); image->method_aux_hash = g_hash_table_new (NULL, NULL); image->vararg_aux_hash = g_hash_table_new (NULL, NULL); image->handleref = g_hash_table_new (NULL, NULL); - image->tokens = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_REFLECTION, "dynamic module tokens table"); - image->generic_def_objects = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_REFLECTION, "dynamic module generic definitions table"); + image->tokens = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_REFLECTION, NULL, "Reflection Dynamic Image Token Table"); + image->generic_def_objects = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_REFLECTION, NULL, "Reflection Dynamic Image Generic Definition Table"); image->typespec = g_hash_table_new ((GHashFunc)mono_metadata_type_hash, (GCompareFunc)mono_metadata_type_equal); image->typeref = g_hash_table_new ((GHashFunc)mono_metadata_type_hash, (GCompareFunc)mono_metadata_type_equal); image->blob_cache = g_hash_table_new ((GHashFunc)mono_blob_entry_hash, (GCompareFunc)mono_blob_entry_equal); image->gen_params = g_ptr_array_new (); - image->remapped_tokens = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_REFLECTION, "dynamic module remapped tokens table"); + image->remapped_tokens = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_REFLECTION, NULL, "Reflection Dynamic Image Remapped Token Table"); /*g_print ("string heap create for image %p (%s)\n", image, module_name);*/ string_heap_init (&image->sheap); diff --git a/mono/metadata/gc-internals.h b/mono/metadata/gc-internals.h index eac1107ad1cb..c40fbae71fc0 100644 --- a/mono/metadata/gc-internals.h +++ b/mono/metadata/gc-internals.h @@ -22,7 +22,7 @@ #define mono_domain_finalizers_unlock(domain) mono_os_mutex_unlock (&(domain)->finalizable_objects_hash_lock); /* Register a memory area as a conservatively scanned GC root */ -#define MONO_GC_REGISTER_ROOT_PINNING(x,src,msg) mono_gc_register_root ((char*)&(x), sizeof(x), MONO_GC_DESCRIPTOR_NULL, (src), (msg)) +#define MONO_GC_REGISTER_ROOT_PINNING(x,src,key,msg) mono_gc_register_root ((char*)&(x), sizeof(x), MONO_GC_DESCRIPTOR_NULL, (src), (key), (msg)) #define MONO_GC_UNREGISTER_ROOT(x) mono_gc_deregister_root ((char*)&(x)) @@ -34,18 +34,18 @@ #define MONO_GC_ROOT_DESCR_FOR_FIXED(n) (mono_gc_is_moving () ? mono_gc_make_root_descr_all_refs (0) : MONO_GC_DESCRIPTOR_NULL) /* Register a memory location holding a single object reference as a GC root */ -#define MONO_GC_REGISTER_ROOT_SINGLE(x,src,msg) do { \ +#define MONO_GC_REGISTER_ROOT_SINGLE(x,src,key,msg) do { \ g_assert (sizeof (x) == sizeof (MonoObject*)); \ - mono_gc_register_root ((char*)&(x), sizeof(MonoObject*), mono_gc_make_root_descr_all_refs (1), (src), (msg)); \ + mono_gc_register_root ((char*)&(x), sizeof(MonoObject*), mono_gc_make_root_descr_all_refs (1), (src), (key),(msg)); \ } while (0) /* * This is used for fields which point to objects which are kept alive by other references * when using Boehm. */ -#define MONO_GC_REGISTER_ROOT_IF_MOVING(x,src,msg) do { \ +#define MONO_GC_REGISTER_ROOT_IF_MOVING(x,src,key,msg) do { \ if (mono_gc_is_moving ()) \ - MONO_GC_REGISTER_ROOT_SINGLE(x,src,msg); \ + MONO_GC_REGISTER_ROOT_SINGLE(x,src,key,msg); \ } while (0) #define MONO_GC_UNREGISTER_ROOT_IF_MOVING(x) do { \ @@ -121,7 +121,7 @@ gboolean mono_gc_user_markers_supported (void); * size bytes will be available from the returned address (ie, descr * must not be stored in the returned memory) */ -void* mono_gc_alloc_fixed (size_t size, MonoGCDescriptor descr, MonoGCRootSource source, const char *msg); +void* mono_gc_alloc_fixed (size_t size, MonoGCDescriptor descr, MonoGCRootSource source, void *key, const char *msg); void mono_gc_free_fixed (void* addr); /* make sure the gchandle was allocated for an object in domain */ @@ -138,9 +138,11 @@ void* mono_gc_alloc_string (MonoVTable *vtable, size_t size, gint32 len); void* mono_gc_alloc_mature (MonoVTable *vtable, size_t size); MonoGCDescriptor mono_gc_make_descr_for_string (gsize *bitmap, int numbits); +void mono_gc_register_obj_with_weak_fields (void *obj); + void mono_gc_register_for_finalization (MonoObject *obj, void *user_data); void mono_gc_add_memory_pressure (gint64 value); -MONO_API int mono_gc_register_root (char *start, size_t size, MonoGCDescriptor descr, MonoGCRootSource source, const char *msg); +MONO_API int mono_gc_register_root (char *start, size_t size, MonoGCDescriptor descr, MonoGCRootSource source, void *key, const char *msg); void mono_gc_deregister_root (char* addr); void mono_gc_finalize_domain (MonoDomain *domain); void mono_gc_run_finalize (void *obj, void *data); @@ -159,7 +161,7 @@ void mono_gc_suspend_finalizers (void); * FIXME: Add an API for clearing remset entries if a root with a user defined * mark routine is deleted. */ -int mono_gc_register_root_wbarrier (char *start, size_t size, MonoGCDescriptor descr, MonoGCRootSource source, const char *msg); +int mono_gc_register_root_wbarrier (char *start, size_t size, MonoGCDescriptor descr, MonoGCRootSource source, void *key, const char *msg); void mono_gc_wbarrier_set_root (gpointer ptr, MonoObject *value); @@ -346,6 +348,8 @@ MONO_API void mono_gc_register_finalizer_callbacks (MonoGCFinalizerCallbacks *ca BOOL APIENTRY mono_gc_dllmain (HMODULE module_handle, DWORD reason, LPVOID reserved); #endif +MonoVTable *mono_gc_get_vtable (MonoObject *obj); + guint mono_gc_get_vtable_bits (MonoClass *klass); void mono_gc_register_altstack (gpointer stack, gint32 stack_size, gpointer altstack, gint32 altstack_size); diff --git a/mono/metadata/gc.c b/mono/metadata/gc.c index 2f0a82113ca8..99ba7244fce6 100644 --- a/mono/metadata/gc.c +++ b/mono/metadata/gc.c @@ -92,6 +92,7 @@ static void object_register_finalizer (MonoObject *obj, void (*callback)(void *, static void reference_queue_proccess_all (void); static void mono_reference_queue_cleanup (void); static void reference_queue_clear_for_domain (MonoDomain *domain); +static void mono_runtime_do_background_work (void); static MonoThreadInfoWaitRet @@ -176,7 +177,6 @@ mono_gc_run_finalize (void *obj, void *data) MonoMethod* finalizer = NULL; MonoDomain *caller_domain = mono_domain_get (); MonoDomain *domain; - RuntimeInvokeFunction runtime_invoke; // This function is called from the innards of the GC, so our best alternative for now is to do polling here mono_threads_safepoint (); @@ -287,6 +287,7 @@ mono_gc_run_finalize (void *obj, void *data) if (log_finalizers) g_log ("mono-gc-finalizers", G_LOG_LEVEL_MESSAGE, "<%s at %p> Compiling finalizer.", o->vtable->klass->name, o); +#ifndef HOST_WASM if (!domain->finalize_runtime_invoke) { MonoMethod *invoke = mono_marshal_get_runtime_invoke (mono_class_get_method_from_name_flags (mono_defaults.object_class, "Finalize", 0, 0), TRUE); @@ -294,7 +295,8 @@ mono_gc_run_finalize (void *obj, void *data) mono_error_assert_ok (&error); /* expect this not to fail */ } - runtime_invoke = (RuntimeInvokeFunction)domain->finalize_runtime_invoke; + RuntimeInvokeFunction runtime_invoke = (RuntimeInvokeFunction)domain->finalize_runtime_invoke; +#endif mono_runtime_class_init_full (o->vtable, &error); goto_if_nok (&error, unhandled_error); @@ -309,7 +311,12 @@ mono_gc_run_finalize (void *obj, void *data) MONO_PROFILER_RAISE (gc_finalizing_object, (o)); +#ifdef HOST_WASM + gpointer params[] = { NULL }; + mono_runtime_try_invoke (finalizer, o, params, &exc, &error); +#else runtime_invoke (o, NULL, &exc, NULL); +#endif MONO_PROFILER_RAISE (gc_finalized_object, (o)); @@ -708,7 +715,11 @@ mono_gc_finalize_notify (void) if (mono_gc_is_null ()) return; +#ifdef HOST_WASM + mono_threads_schedule_background_job (mono_runtime_do_background_work); +#else mono_coop_sem_post (&finalizer_sem); +#endif } /* @@ -825,6 +836,36 @@ finalize_domain_objects (void) } } + +static void +mono_runtime_do_background_work (void) +{ + mono_threads_perform_thread_dump (); + + mono_console_handle_async_ops (); + + mono_attach_maybe_start (); + + finalize_domain_objects (); + + MONO_PROFILER_RAISE (gc_finalizing, ()); + + /* If finished == TRUE, mono_gc_cleanup has been called (from mono_runtime_cleanup), + * before the domain is unloaded. + */ + mono_gc_invoke_finalizers (); + + MONO_PROFILER_RAISE (gc_finalized, ()); + + mono_threads_join_threads (); + + reference_queue_proccess_all (); + + mono_w32process_signal_finished (); + + hazard_free_queue_pump (); +} + static gsize WINAPI finalizer_thread (gpointer unused) { @@ -855,30 +896,7 @@ finalizer_thread (gpointer unused) mono_gc_set_skip_thread (FALSE); - mono_threads_perform_thread_dump (); - - mono_console_handle_async_ops (); - - mono_attach_maybe_start (); - - finalize_domain_objects (); - - MONO_PROFILER_RAISE (gc_finalizing, ()); - - /* If finished == TRUE, mono_gc_cleanup has been called (from mono_runtime_cleanup), - * before the domain is unloaded. - */ - mono_gc_invoke_finalizers (); - - MONO_PROFILER_RAISE (gc_finalized, ()); - - mono_threads_join_threads (); - - reference_queue_proccess_all (); - - mono_w32process_signal_finished (); - - hazard_free_queue_pump (); + mono_runtime_do_background_work (); /* Avoid posting the pending done event until there are pending finalizers */ if (mono_coop_sem_timedwait (&finalizer_sem, 0, MONO_SEM_FLAGS_NONE) == MONO_SEM_TIMEDWAIT_RET_SUCCESS) { diff --git a/mono/metadata/handle.c b/mono/metadata/handle.c index 9208cd285e00..3a88b076365d 100644 --- a/mono/metadata/handle.c +++ b/mono/metadata/handle.c @@ -35,7 +35,6 @@ Add counters for: Actually do something in mono_handle_verify Shrink the handles stack in mono_handle_stack_scan -Properly report it to the profiler. Add a boehm implementation TODO (things to explore): @@ -382,10 +381,11 @@ check_handle_stack_monotonic (HandleStack *stack) } void -mono_handle_stack_scan (HandleStack *stack, GcScanFunc func, gpointer gc_data, gboolean precise) +mono_handle_stack_scan (HandleStack *stack, GcScanFunc func, gpointer gc_data, gboolean precise, gboolean check) { - if (precise) /* run just once (per handle stack) per GC */ + if (check) /* run just once (per handle stack) per GC */ check_handle_stack_monotonic (stack); + /* We're called twice - on the imprecise pass we call func to pin the objects where the handle points to its interior. On the precise diff --git a/mono/metadata/handle.h b/mono/metadata/handle.h index 96f1f9bf4b4b..a83618d6b152 100644 --- a/mono/metadata/handle.h +++ b/mono/metadata/handle.h @@ -132,7 +132,7 @@ MonoRawHandle mono_handle_new_full (gpointer rawptr, gboolean interior, const ch MonoRawHandle mono_handle_new_interior (gpointer rawptr, const char *owner); #endif -void mono_handle_stack_scan (HandleStack *stack, GcScanFunc func, gpointer gc_data, gboolean precise); +void mono_handle_stack_scan (HandleStack *stack, GcScanFunc func, gpointer gc_data, gboolean precise, gboolean check); gboolean mono_handle_stack_is_empty (HandleStack *stack); HandleStack* mono_handle_stack_alloc (void); void mono_handle_stack_free (HandleStack *handlestack); diff --git a/mono/metadata/icall-def.h b/mono/metadata/icall-def.h index 6bc2d9b2a27d..ed8ef0dd2a96 100644 --- a/mono/metadata/icall-def.h +++ b/mono/metadata/icall-def.h @@ -186,6 +186,9 @@ ICALL(CONSOLE_3, "SetBreak", ves_icall_System_ConsoleDriver_SetBreak ) ICALL(CONSOLE_4, "SetEcho", ves_icall_System_ConsoleDriver_SetEcho ) ICALL(CONSOLE_5, "TtySetup", ves_icall_System_ConsoleDriver_TtySetup ) +ICALL_TYPE(TZONE, "System.CurrentSystemTimeZone", TZONE_1) +ICALL(TZONE_1, "GetTimeZoneData", ves_icall_System_CurrentSystemTimeZone_GetTimeZoneData) + ICALL_TYPE(DTIME, "System.DateTime", DTIME_1) ICALL(DTIME_1, "GetSystemTimeAsFileTime", mono_100ns_datetime) @@ -908,7 +911,7 @@ ICALL_TYPE(ITHREAD, "System.Threading.InternalThread", ITHREAD_1) ICALL(ITHREAD_1, "Thread_free_internal", ves_icall_System_Threading_InternalThread_Thread_free_internal) ICALL_TYPE(MONIT, "System.Threading.Monitor", MONIT_8) -ICALL(MONIT_8, "Enter", mono_monitor_enter_internal) +ICALL(MONIT_8, "Enter", ves_icall_System_Threading_Monitor_Monitor_Enter) ICALL(MONIT_1, "Exit", mono_monitor_exit) ICALL(MONIT_2, "Monitor_pulse", ves_icall_System_Threading_Monitor_Monitor_pulse) ICALL(MONIT_3, "Monitor_pulse_all", ves_icall_System_Threading_Monitor_Monitor_pulse_all) diff --git a/mono/metadata/icall-internals.h b/mono/metadata/icall-internals.h index c172b8404bcb..c3ee79d03999 100644 --- a/mono/metadata/icall-internals.h +++ b/mono/metadata/icall-internals.h @@ -10,6 +10,10 @@ #include #include +// UNITY +guint32 +ves_icall_System_CurrentSystemTimeZone_GetTimeZoneData (guint32 year, MonoArray **data, MonoArray **names); + // On Windows platform implementation of bellow methods are hosted in separate source file // icall-windows.c or icall-windows-*.c. On other platforms the implementation is still keept // in icall.c still declared as static and in some places even inlined. diff --git a/mono/metadata/icall.c b/mono/metadata/icall.c index d88c1ce6243c..1741e78cf38e 100644 --- a/mono/metadata/icall.c +++ b/mono/metadata/icall.c @@ -8533,6 +8533,8 @@ type_from_typename (char *type_name) if (!strcmp (type_name, "int")) klass = mono_defaults.int_class; + else if (!strcmp (type_name, "ptr&")) + return mono_class_get_byref_type (mono_defaults.int_class); else if (!strcmp (type_name, "ptr")) klass = mono_defaults.int_class; else if (!strcmp (type_name, "void")) diff --git a/mono/metadata/image.c b/mono/metadata/image.c index 69b2105ec270..6a0601d02e8f 100644 --- a/mono/metadata/image.c +++ b/mono/metadata/image.c @@ -2093,6 +2093,7 @@ mono_image_close_except_pools (MonoImage *image) free_hash (image->pinvoke_scope_filenames); free_hash (image->native_func_wrapper_cache); mono_conc_hashtable_destroy (image->typespec_cache); + free_hash (image->weak_field_indexes); mono_wrapper_caches_free (&image->wrapper_caches); diff --git a/mono/metadata/loader.c b/mono/metadata/loader.c index 73733e49318a..45bfceac6b37 100644 --- a/mono/metadata/loader.c +++ b/mono/metadata/loader.c @@ -1917,6 +1917,10 @@ get_method_constrained (MonoImage *image, MonoMethod *method, MonoClass *constra g_assert (vtable_slot >= 0); MonoMethod *res = mono_class_get_vtable_entry (constrained_class, vtable_slot); + if (res == NULL && mono_class_is_abstract (constrained_class) ) { + /* Constraining class is abstract, there may not be a refined method. */ + return method; + } g_assert (res != NULL); if (inflated_generic_method) { g_assert (res->is_generic); diff --git a/mono/metadata/marshal.c b/mono/metadata/marshal.c index 0d047053f50b..d2859202fbe6 100644 --- a/mono/metadata/marshal.c +++ b/mono/metadata/marshal.c @@ -4022,7 +4022,7 @@ emit_invoke_call (MonoMethodBuilder *mb, MonoMethod *method, /* to make it work with our special string constructors */ if (!string_dummy) { MonoError error; - MONO_GC_REGISTER_ROOT_SINGLE (string_dummy, MONO_ROOT_SOURCE_MARSHAL, "dummy marshal string"); + MONO_GC_REGISTER_ROOT_SINGLE (string_dummy, MONO_ROOT_SOURCE_MARSHAL, NULL, "Marshal Dummy String"); string_dummy = mono_string_new_checked (mono_get_root_domain (), "dummy", &error); mono_error_assert_ok (&error); } diff --git a/mono/metadata/metadata-internals.h b/mono/metadata/metadata-internals.h index 2b2e414f01e2..e849706e19e9 100644 --- a/mono/metadata/metadata-internals.h +++ b/mono/metadata/metadata-internals.h @@ -416,6 +416,10 @@ struct _MonoImage { MonoGenericContainer *anonymous_generic_class_container; MonoGenericContainer *anonymous_generic_method_container; + gboolean weak_fields_inited; + /* Contains 1 based indexes */ + GHashTable *weak_field_indexes; + /* * No other runtime locks must be taken while holding this lock. * It's meant to be used only to mutate and query structures part of this image. diff --git a/mono/metadata/metadata.c b/mono/metadata/metadata.c index 93c9bbae15eb..b8cad0f3d584 100644 --- a/mono/metadata/metadata.c +++ b/mono/metadata/metadata.c @@ -6264,37 +6264,34 @@ method_from_method_def_or_ref (MonoImage *m, guint32 tok, MonoGenericContext *co /* * mono_class_get_overrides_full: * - * Return the method overrides belonging to class @type_token in @overrides, and - * the number of overrides in @num_overrides. + * Compute the method overrides belonging to class @type_token in @overrides, and the number of overrides in @num_overrides. * - * Returns: TRUE on success, FALSE on failure. */ -gboolean -mono_class_get_overrides_full (MonoImage *image, guint32 type_token, MonoMethod ***overrides, gint32 *num_overrides, - MonoGenericContext *generic_context) +void +mono_class_get_overrides_full (MonoImage *image, guint32 type_token, MonoMethod ***overrides, gint32 *num_overrides, MonoGenericContext *generic_context, MonoError *error) { - MonoError error; locator_t loc; MonoTableInfo *tdef = &image->tables [MONO_TABLE_METHODIMPL]; guint32 start, end; gint32 i, num; guint32 cols [MONO_METHODIMPL_SIZE]; MonoMethod **result; - gint32 ok = TRUE; + error_init (error) + *overrides = NULL; if (num_overrides) *num_overrides = 0; if (!tdef->base) - return TRUE; + return; loc.t = tdef; loc.col_idx = MONO_METHODIMPL_CLASS; loc.idx = mono_metadata_token_index (type_token); if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator)) - return TRUE; + return; start = loc.result; end = start + 1; @@ -6318,33 +6315,32 @@ mono_class_get_overrides_full (MonoImage *image, guint32 type_token, MonoMethod for (i = 0; i < num; ++i) { MonoMethod *method; - if (!mono_verifier_verify_methodimpl_row (image, start + i, &error)) { - mono_error_cleanup (&error); /* FIXME don't swallow the error */ - ok = FALSE; + if (!mono_verifier_verify_methodimpl_row (image, start + i, error)) break; - } mono_metadata_decode_row (tdef, start + i, cols, MONO_METHODIMPL_SIZE); - method = method_from_method_def_or_ref ( - image, cols [MONO_METHODIMPL_DECLARATION], generic_context, &error); - if (method == NULL) { - mono_error_cleanup (&error); /* FIXME don't swallow the error */ - ok = FALSE; - } + method = method_from_method_def_or_ref (image, cols [MONO_METHODIMPL_DECLARATION], generic_context, error); + if (!method) + break; + result [i * 2] = method; - method = method_from_method_def_or_ref ( - image, cols [MONO_METHODIMPL_BODY], generic_context, &error); - if (method == NULL) { - mono_error_cleanup (&error); /* FIXME don't swallow the error */ - ok = FALSE; - } + method = method_from_method_def_or_ref (image, cols [MONO_METHODIMPL_BODY], generic_context, error); + if (!method) + break; + result [i * 2 + 1] = method; } - *overrides = result; - if (num_overrides) - *num_overrides = num; - return ok; + if (!is_ok (error)) { + g_free (result); + *overrides = NULL; + if (num_overrides) + *num_overrides = 0; + } else { + *overrides = result; + if (num_overrides) + *num_overrides = num; + } } /** diff --git a/mono/metadata/monitor.c b/mono/metadata/monitor.c index f632cf205e5a..6642edbf712c 100644 --- a/mono/metadata/monitor.c +++ b/mono/metadata/monitor.c @@ -1386,13 +1386,13 @@ ves_icall_System_Threading_Monitor_Monitor_wait (MonoObject *obj, guint32 ms) * is private to this thread. Therefore even if the event was * signalled before we wait, we still succeed. */ - MONO_ENTER_GC_SAFE; #ifdef HOST_WIN32 + MONO_ENTER_GC_SAFE; ret = mono_w32handle_convert_wait_ret (mono_win32_wait_for_single_object_ex (event, ms, TRUE), 1); + MONO_EXIT_GC_SAFE; #else ret = mono_w32handle_wait_one (event, ms, TRUE); #endif /* HOST_WIN32 */ - MONO_EXIT_GC_SAFE; /* Reset the thread state fairly early, so we don't have to worry * about the monitor error checking @@ -1415,13 +1415,13 @@ ves_icall_System_Threading_Monitor_Monitor_wait (MonoObject *obj, guint32 ms) /* Poll the event again, just in case it was signalled * while we were trying to regain the monitor lock */ - MONO_ENTER_GC_SAFE; #ifdef HOST_WIN32 + MONO_ENTER_GC_SAFE; ret = mono_w32handle_convert_wait_ret (mono_win32_wait_for_single_object_ex (event, 0, FALSE), 1); + MONO_EXIT_GC_SAFE; #else ret = mono_w32handle_wait_one (event, 0, FALSE); #endif /* HOST_WIN32 */ - MONO_EXIT_GC_SAFE; } /* Pulse will have popped our event from the queue if it signalled @@ -1449,3 +1449,8 @@ ves_icall_System_Threading_Monitor_Monitor_wait (MonoObject *obj, guint32 ms) return success; } +void +ves_icall_System_Threading_Monitor_Monitor_Enter (MonoObject *obj) +{ + mono_monitor_enter_internal (obj); +} \ No newline at end of file diff --git a/mono/metadata/monitor.h b/mono/metadata/monitor.h index f0babcc7396e..0abf849a9654 100644 --- a/mono/metadata/monitor.h +++ b/mono/metadata/monitor.h @@ -125,7 +125,7 @@ extern void ves_icall_System_Threading_Monitor_Monitor_pulse(MonoObject *obj); extern void ves_icall_System_Threading_Monitor_Monitor_pulse_all(MonoObject *obj); extern MonoBoolean ves_icall_System_Threading_Monitor_Monitor_wait(MonoObject *obj, guint32 ms); extern void ves_icall_System_Threading_Monitor_Monitor_try_enter_with_atomic_var (MonoObject *obj, guint32 ms, MonoBoolean *lockTaken); - +extern void ves_icall_System_Threading_Monitor_Monitor_Enter (MonoObject *obj); G_END_DECLS #endif /* _MONO_METADATA_MONITOR_H_ */ diff --git a/mono/metadata/mono-conc-hash.c b/mono/metadata/mono-conc-hash.c index f7a50b905cfd..2aa1fe225b6f 100644 --- a/mono/metadata/mono-conc-hash.c +++ b/mono/metadata/mono-conc-hash.c @@ -38,6 +38,7 @@ struct _MonoConcGHashTable { GDestroyNotify value_destroy_func; MonoGHashGCType gc_type; MonoGCRootSource source; + void *key; const char *msg; }; @@ -46,16 +47,16 @@ static conc_table* conc_table_new (MonoConcGHashTable *hash, int size) { conc_table *table = g_new0 (conc_table, 1); - + table->keys = g_new0 (void*, size); table->values = g_new0 (void*, size); table->table_size = size; table->gc_type = hash->gc_type; if (hash->gc_type & MONO_HASH_KEY_GC) - mono_gc_register_root_wbarrier ((char*)table->keys, sizeof (MonoObject*) * size, mono_gc_make_vector_descr (), hash->source, hash->msg); + mono_gc_register_root_wbarrier ((char*)table->keys, sizeof (MonoObject*) * size, mono_gc_make_vector_descr (), hash->source, hash->key, hash->msg); if (hash->gc_type & MONO_HASH_VALUE_GC) - mono_gc_register_root_wbarrier ((char*)table->values, sizeof (MonoObject*) * size, mono_gc_make_vector_descr (), hash->source, hash->msg); + mono_gc_register_root_wbarrier ((char*)table->values, sizeof (MonoObject*) * size, mono_gc_make_vector_descr (), hash->source, hash->key, hash->msg); return table; } @@ -168,7 +169,7 @@ expand_table (MonoConcGHashTable *hash_table) MonoConcGHashTable * -mono_conc_g_hash_table_new_type (GHashFunc hash_func, GEqualFunc key_equal_func, MonoGHashGCType type, MonoGCRootSource source, const char *msg) +mono_conc_g_hash_table_new_type (GHashFunc hash_func, GEqualFunc key_equal_func, MonoGHashGCType type, MonoGCRootSource source, void *key, const char *msg) { MonoConcGHashTable *hash; @@ -183,6 +184,7 @@ mono_conc_g_hash_table_new_type (GHashFunc hash_func, GEqualFunc key_equal_func, hash->overflow_count = (int)(INITIAL_SIZE * LOAD_FACTOR); hash->gc_type = type; hash->source = source; + hash->key = key; hash->msg = msg; hash->table = conc_table_new (hash, INITIAL_SIZE); @@ -429,4 +431,4 @@ mono_conc_g_hash_table_remove (MonoConcGHashTable *hash_table, gconstpointer key i = (i + 1) & table_mask; } } -} \ No newline at end of file +} diff --git a/mono/metadata/mono-conc-hash.h b/mono/metadata/mono-conc-hash.h index 67b77ef2ca34..e15629c309bf 100644 --- a/mono/metadata/mono-conc-hash.h +++ b/mono/metadata/mono-conc-hash.h @@ -11,7 +11,7 @@ typedef struct _MonoConcGHashTable MonoConcGHashTable; -MonoConcGHashTable * mono_conc_g_hash_table_new_type (GHashFunc hash_func, GEqualFunc key_equal_func, MonoGHashGCType type, MonoGCRootSource source, const char *msg); +MonoConcGHashTable * mono_conc_g_hash_table_new_type (GHashFunc hash_func, GEqualFunc key_equal_func, MonoGHashGCType type, MonoGCRootSource source, void *key, const char *msg); gpointer mono_conc_g_hash_table_lookup (MonoConcGHashTable *hash, gconstpointer key); gboolean mono_conc_g_hash_table_lookup_extended (MonoConcGHashTable *hash, gconstpointer key, gpointer *orig_key, gpointer *value); void mono_conc_g_hash_table_foreach (MonoConcGHashTable *hash, GHFunc func, gpointer user_data); diff --git a/mono/metadata/mono-gc.h b/mono/metadata/mono-gc.h index bd1262a67b8b..455209aa8dc3 100644 --- a/mono/metadata/mono-gc.h +++ b/mono/metadata/mono-gc.h @@ -12,36 +12,85 @@ MONO_BEGIN_DECLS typedef int (*MonoGCReferences) (MonoObject *obj, MonoClass *klass, uintptr_t size, uintptr_t num, MonoObject **refs, uintptr_t *offsets, void *data); +/** + * This enum is used by the profiler API when reporting root registration. + */ typedef enum { - // Roots external to Mono. Embedders may only use this value. + /** + * Roots external to Mono. Embedders may only use this value. + */ MONO_ROOT_SOURCE_EXTERNAL = 0, - // Thread stack. Must not be used to register roots. + /** + * Thread call stack. + * + * The \c key parameter is a thread ID as a \c uintptr_t. + */ MONO_ROOT_SOURCE_STACK = 1, - // Roots in the finalizer queue. Must not be used to register roots. + /** + * Roots in the finalizer queue. This is a pseudo-root. + */ MONO_ROOT_SOURCE_FINALIZER_QUEUE = 2, - // Managed static variables. + /** + * Managed \c static variables. + * + * The \c key parameter is a \c MonoVTable pointer. + */ MONO_ROOT_SOURCE_STATIC = 3, - // Static variables with ThreadStaticAttribute. + /** + * Managed \c static variables with \c ThreadStaticAttribute. + * + * The \c key parameter is a thread ID as a \c uintptr_t. + */ MONO_ROOT_SOURCE_THREAD_STATIC = 4, - // Static variables with ContextStaticAttribute. + /** + * Managed \c static variables with \c ContextStaticAttribute. + * + * The \c key parameter is a \c MonoAppContext pointer. + */ MONO_ROOT_SOURCE_CONTEXT_STATIC = 5, - // GCHandle structures. + /** + * \c GCHandle structures. + */ MONO_ROOT_SOURCE_GC_HANDLE = 6, - // Roots in the just-in-time compiler. + /** + * Roots in the just-in-time compiler. + */ MONO_ROOT_SOURCE_JIT = 7, - // Roots in the threading subsystem. + /** + * Roots in the threading subsystem. + * + * The \c key parameter, if not \c NULL, is a thread ID as a \c uintptr_t. + */ MONO_ROOT_SOURCE_THREADING = 8, - // Roots in application domains. + /** + * Roots in application domains. + * + * The \c key parameter, if not \c NULL, is a \c MonoDomain pointer. + */ MONO_ROOT_SOURCE_DOMAIN = 9, - // Roots in reflection code. + /** + * Roots in reflection code. + * + * The \c key parameter, if not \c NULL, is a \c MonoVTable pointer. + */ MONO_ROOT_SOURCE_REFLECTION = 10, - // Roots from P/Invoke or other marshaling. + /** + * Roots from P/Invoke or other marshaling infrastructure. + */ MONO_ROOT_SOURCE_MARSHAL = 11, - // Roots in the thread pool data structures. + /** + * Roots in the thread pool data structures. + */ MONO_ROOT_SOURCE_THREAD_POOL = 12, - // Roots in the debugger agent. + /** + * Roots in the debugger agent. + */ MONO_ROOT_SOURCE_DEBUGGER = 13, - // Handle structures, used for object passed to internal functions + /** + * Roots in the runtime handle stack. This is a pseudo-root. + * + * The \c key parameter is a thread ID as a \c uintptr_t. + */ MONO_ROOT_SOURCE_HANDLE = 14, } MonoGCRootSource; diff --git a/mono/metadata/mono-hash.c b/mono/metadata/mono-hash.c index a116ba5d04d8..bf099f653497 100644 --- a/mono/metadata/mono-hash.c +++ b/mono/metadata/mono-hash.c @@ -50,6 +50,7 @@ struct _MonoGHashTable { GDestroyNotify value_destroy_func, key_destroy_func; MonoGHashGCType gc_type; MonoGCRootSource source; + void *key; const char *msg; }; @@ -139,7 +140,7 @@ static inline int mono_g_hash_table_find_slot (MonoGHashTable *hash, const MonoO MonoGHashTable * -mono_g_hash_table_new_type (GHashFunc hash_func, GEqualFunc key_equal_func, MonoGHashGCType type, MonoGCRootSource source, const char *msg) +mono_g_hash_table_new_type (GHashFunc hash_func, GEqualFunc key_equal_func, MonoGHashGCType type, MonoGCRootSource source, void *key, const char *msg) { MonoGHashTable *hash; @@ -157,15 +158,16 @@ mono_g_hash_table_new_type (GHashFunc hash_func, GEqualFunc key_equal_func, Mono hash->gc_type = type; hash->source = source; + hash->key = key; hash->msg = msg; if (type > MONO_HASH_KEY_VALUE_GC) g_error ("wrong type for gc hashtable"); if (hash->gc_type & MONO_HASH_KEY_GC) - mono_gc_register_root_wbarrier ((char*)hash->keys, sizeof (MonoObject*) * hash->table_size, mono_gc_make_vector_descr (), hash->source, hash->msg); + mono_gc_register_root_wbarrier ((char*)hash->keys, sizeof (MonoObject*) * hash->table_size, mono_gc_make_vector_descr (), hash->source, hash->key, hash->msg); if (hash->gc_type & MONO_HASH_VALUE_GC) - mono_gc_register_root_wbarrier ((char*)hash->values, sizeof (MonoObject*) * hash->table_size, mono_gc_make_vector_descr (), hash->source, hash->msg); + mono_gc_register_root_wbarrier ((char*)hash->values, sizeof (MonoObject*) * hash->table_size, mono_gc_make_vector_descr (), hash->source, hash->key, hash->msg); return hash; } @@ -222,9 +224,9 @@ rehash (MonoGHashTable *hash) data.values = g_new0 (MonoObject*, data.new_size); if (hash->gc_type & MONO_HASH_KEY_GC) - mono_gc_register_root_wbarrier ((char*)data.keys, sizeof (MonoObject*) * data.new_size, mono_gc_make_vector_descr (), hash->source, hash->msg); + mono_gc_register_root_wbarrier ((char*)data.keys, sizeof (MonoObject*) * data.new_size, mono_gc_make_vector_descr (), hash->source, hash->key, hash->msg); if (hash->gc_type & MONO_HASH_VALUE_GC) - mono_gc_register_root_wbarrier ((char*)data.values, sizeof (MonoObject*) * data.new_size, mono_gc_make_vector_descr (), hash->source, hash->msg); + mono_gc_register_root_wbarrier ((char*)data.values, sizeof (MonoObject*) * data.new_size, mono_gc_make_vector_descr (), hash->source, hash->key, hash->msg); if (!mono_threads_is_coop_enabled ()) { mono_gc_invoke_with_gc_lock (do_rehash, &data); diff --git a/mono/metadata/mono-hash.h b/mono/metadata/mono-hash.h index 10e3ca390eda..4e945a04e7b8 100644 --- a/mono/metadata/mono-hash.h +++ b/mono/metadata/mono-hash.h @@ -26,7 +26,7 @@ extern gint32 mono_g_hash_table_max_chain_length; typedef struct _MonoGHashTable MonoGHashTable; -MONO_API MonoGHashTable *mono_g_hash_table_new_type (GHashFunc hash_func, GEqualFunc key_equal_func, MonoGHashGCType type, MonoGCRootSource source, const char *msg); +MONO_API MonoGHashTable *mono_g_hash_table_new_type (GHashFunc hash_func, GEqualFunc key_equal_func, MonoGHashGCType type, MonoGCRootSource source, void *key, const char *msg); MONO_API guint mono_g_hash_table_size (MonoGHashTable *hash); MONO_API gpointer mono_g_hash_table_lookup (MonoGHashTable *hash, gconstpointer key); MONO_API gboolean mono_g_hash_table_lookup_extended (MonoGHashTable *hash, gconstpointer key, gpointer *orig_key, gpointer *value); diff --git a/mono/metadata/mono-ptr-array.h b/mono/metadata/mono-ptr-array.h index 61589f3bbbde..70694eff8f22 100644 --- a/mono/metadata/mono-ptr-array.h +++ b/mono/metadata/mono-ptr-array.h @@ -25,18 +25,20 @@ typedef struct { int size; int capacity; MonoGCRootSource source; + void *key; const char *msg; } MonoPtrArray; #define MONO_PTR_ARRAY_MAX_ON_STACK (16) -#define mono_ptr_array_init(ARRAY, INITIAL_SIZE, SOURCE, MSG) do {\ +#define mono_ptr_array_init(ARRAY, INITIAL_SIZE, SOURCE, KEY, MSG) do {\ (ARRAY).size = 0; \ (ARRAY).capacity = MAX (INITIAL_SIZE, MONO_PTR_ARRAY_MAX_ON_STACK); \ (ARRAY).source = SOURCE; \ + (ARRAY).key = KEY; \ (ARRAY).msg = MSG; \ (ARRAY).data = INITIAL_SIZE > MONO_PTR_ARRAY_MAX_ON_STACK \ - ? (void **)mono_gc_alloc_fixed (sizeof (void*) * INITIAL_SIZE, mono_gc_make_root_descr_all_refs (INITIAL_SIZE), SOURCE, MSG) \ + ? (void **)mono_gc_alloc_fixed (sizeof (void*) * INITIAL_SIZE, mono_gc_make_root_descr_all_refs (INITIAL_SIZE), SOURCE, NULL, MSG) \ : g_newa (void*, MONO_PTR_ARRAY_MAX_ON_STACK); \ } while (0) @@ -47,7 +49,7 @@ typedef struct { #define mono_ptr_array_append(ARRAY, VALUE) do { \ if ((ARRAY).size >= (ARRAY).capacity) {\ - void **__tmp = (void **)mono_gc_alloc_fixed (sizeof (void*) * (ARRAY).capacity * 2, mono_gc_make_root_descr_all_refs ((ARRAY).capacity * 2), (ARRAY).source, (ARRAY).msg); \ + void **__tmp = (void **)mono_gc_alloc_fixed (sizeof (void*) * (ARRAY).capacity * 2, mono_gc_make_root_descr_all_refs ((ARRAY).capacity * 2), (ARRAY).source, (ARRAY).key, (ARRAY).msg); \ mono_gc_memmove_aligned ((void *)__tmp, (ARRAY).data, (ARRAY).capacity * sizeof (void*)); \ if ((ARRAY).capacity > MONO_PTR_ARRAY_MAX_ON_STACK) \ mono_gc_free_fixed ((ARRAY).data); \ diff --git a/mono/metadata/mono-security.c b/mono/metadata/mono-security.c index e3b82bcd6112..52c8efcf691e 100644 --- a/mono/metadata/mono-security.c +++ b/mono/metadata/mono-security.c @@ -275,7 +275,7 @@ ves_icall_System_Security_Principal_WindowsIdentity_GetUserToken (MonoStringHand gpointer token = (gpointer)-2; error_init (error); -#ifdef HAVE_PWD_H +#if defined (HAVE_PWD_H) && !defined (HOST_WASM) #ifdef HAVE_GETPWNAM_R struct passwd pwd; diff --git a/mono/metadata/null-gc-handles.c b/mono/metadata/null-gc-handles.c index f038a0e8a937..60e372bd6e98 100644 --- a/mono/metadata/null-gc-handles.c +++ b/mono/metadata/null-gc-handles.c @@ -116,7 +116,7 @@ handle_data_alloc_entries (HandleData *handles) handles->entries = (void **)g_malloc0 (sizeof (*handles->entries) * handles->size); handles->domain_ids = (guint16 *)g_malloc0 (sizeof (*handles->domain_ids) * handles->size); } else { - handles->entries = (void **)mono_gc_alloc_fixed (sizeof (*handles->entries) * handles->size, NULL, MONO_ROOT_SOURCE_GC_HANDLE, "gc handles table"); + handles->entries = (void **)mono_gc_alloc_fixed (sizeof (*handles->entries) * handles->size, NULL, MONO_ROOT_SOURCE_GC_HANDLE, "GC Handle Table (Null)"); } handles->bitmap = (guint32 *)g_malloc0 (handles->size / CHAR_BIT); } @@ -183,7 +183,7 @@ handle_data_grow (HandleData *handles, gboolean track) handles->domain_ids = domain_ids; } else { gpointer *entries; - entries = (void **)mono_gc_alloc_fixed (sizeof (*handles->entries) * new_size, NULL, MONO_ROOT_SOURCE_GC_HANDLE, "gc handles table"); + entries = (void **)mono_gc_alloc_fixed (sizeof (*handles->entries) * new_size, NULL, MONO_ROOT_SOURCE_GC_HANDLE, "GC Handle Table (Null)"); mono_gc_memmove_aligned (entries, handles->entries, sizeof (*handles->entries) * handles->size); mono_gc_free_fixed (handles->entries); handles->entries = entries; diff --git a/mono/metadata/null-gc.c b/mono/metadata/null-gc.c index 54f185182e6c..88ab715cf5ec 100644 --- a/mono/metadata/null-gc.c +++ b/mono/metadata/null-gc.c @@ -110,11 +110,18 @@ mono_object_is_alive (MonoObject* o) } int -mono_gc_register_root (char *start, size_t size, void *descr, MonoGCRootSource source, const char *msg) +mono_gc_register_root (char *start, size_t size, void *descr, MonoGCRootSource source, void *key, const char *msg) { return TRUE; } +int +mono_gc_register_root_wbarrier (char *start, size_t size, MonoGCDescriptor descr, MonoGCRootSource source, void *key, const char *msg) +{ + return TRUE; +} + + void mono_gc_deregister_root (char* addr) { @@ -157,7 +164,7 @@ mono_gc_make_root_descr_all_refs (int numbits) } void* -mono_gc_alloc_fixed (size_t size, void *descr, MonoGCRootSource source, const char *msg) +mono_gc_alloc_fixed (size_t size, void *descr, MonoGCRootSource source, void *key, const char *msg) { return g_malloc0 (size); } @@ -529,6 +536,13 @@ BOOL APIENTRY mono_gc_dllmain (HMODULE module_handle, DWORD reason, LPVOID reser } #endif +MonoVTable * +mono_gc_get_vtable (MonoObject *obj) +{ + // No pointer tagging. + return obj->vtable; +} + guint mono_gc_get_vtable_bits (MonoClass *klass) { diff --git a/mono/metadata/object-internals.h b/mono/metadata/object-internals.h index 524bdf5967f2..ed7bdd3f1888 100644 --- a/mono/metadata/object-internals.h +++ b/mono/metadata/object-internals.h @@ -630,6 +630,7 @@ typedef struct { gpointer (*create_remoting_trampoline) (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error); gpointer (*create_delegate_trampoline) (MonoDomain *domain, MonoClass *klass); gpointer (*interp_get_remoting_invoke) (gpointer imethod, MonoError *error); + GHashTable *(*get_weak_field_indexes) (MonoImage *image); } MonoRuntimeCallbacks; typedef gboolean (*MonoInternalStackWalk) (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data); diff --git a/mono/metadata/object.c b/mono/metadata/object.c index e23a3f9b6e67..3d69dca594e3 100644 --- a/mono/metadata/object.c +++ b/mono/metadata/object.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -47,6 +48,7 @@ #include #include #include +#include #include "cominterop.h" #include #include @@ -215,7 +217,8 @@ mono_thread_set_main (MonoThread *thread) static gboolean registered = FALSE; if (!registered) { - MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object"); + void *key = thread->internal_thread ? (void *) MONO_UINT_TO_NATIVE_THREAD_ID (thread->internal_thread->tid) : NULL; + MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, key, "Thread Main Object"); registered = TRUE; } @@ -505,7 +508,7 @@ mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error) */ mono_domain_lock (domain); if (!domain->type_init_exception_hash) - domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, "type initialization exceptions table"); + domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, domain, "Domain Type Initialization Exception Table"); mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw); mono_domain_unlock (domain); } @@ -557,6 +560,18 @@ mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error) return TRUE; } +MonoDomain * +mono_vtable_domain (MonoVTable *vtable) +{ + return vtable->domain; +} + +MonoClass * +mono_vtable_class (MonoVTable *vtable) +{ + return vtable->klass; +} + static gboolean release_type_locks (gpointer key, gpointer value, gpointer user) { @@ -1001,7 +1016,14 @@ ves_icall_string_alloc (int length) return str; } +#define BITMAP_EL_SIZE (sizeof (gsize) * 8) + /* LOCKING: Acquires the loader lock */ +/* + * Sets the following fields in KLASS: + * - gc_desc + * - gc_descr_inited + */ void mono_class_compute_gc_descriptor (MonoClass *klass) { @@ -1034,24 +1056,59 @@ mono_class_compute_gc_descriptor (MonoClass *klass) gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, bitmap, mono_array_element_size (klass) / sizeof (gpointer), mono_array_element_size (klass)); /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr, class->name_space, class->name);*/ - if (bitmap != default_bitmap) - g_free (bitmap); } } else { /*static int count = 0; if (count++ > 58) return;*/ bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE); - gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size); /* if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL) g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name); */ /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/ - if (bitmap != default_bitmap) - g_free (bitmap); + + if (klass->has_weak_fields) { + gsize *weak_bitmap = NULL; + int weak_bitmap_nbits = 0; + + weak_bitmap = (gsize *)mono_class_alloc0 (klass, klass->instance_size / sizeof (gsize)); + if (mono_class_has_static_metadata (klass)) { + for (MonoClass *p = klass; p != NULL; p = p->parent) { + gpointer iter = NULL; + guint32 first_field_idx = mono_class_get_first_field_idx (p); + MonoClassField *field; + + while ((field = mono_class_get_fields (p, &iter))) { + guint32 field_idx = first_field_idx + (field - p->fields); + if (MONO_TYPE_IS_REFERENCE (field->type) && mono_assembly_is_weak_field (p->image, field_idx + 1)) { + int pos = field->offset / sizeof (gpointer); + if (pos + 1 > weak_bitmap_nbits) + weak_bitmap_nbits = pos + 1; + weak_bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE); + } + } + } + } + + for (int pos = 0; pos < weak_bitmap_nbits; ++pos) { + if (weak_bitmap [pos / BITMAP_EL_SIZE] & ((gsize)1) << (pos % BITMAP_EL_SIZE)) { + /* Clear the normal bitmap so these refs don't keep an object alive */ + bitmap [pos / BITMAP_EL_SIZE] &= ~((gsize)1) << (pos % BITMAP_EL_SIZE); + } + } + + mono_loader_lock (); + mono_class_set_weak_bitmap (klass, weak_bitmap_nbits, weak_bitmap); + mono_loader_unlock (); + } + + gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size); } + if (bitmap != default_bitmap) + g_free (bitmap); + /* Publish the data */ mono_loader_lock (); klass->gc_descr = gc_descr; @@ -1920,6 +1977,8 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoErro vt->rank = klass->rank; vt->domain = domain; + MONO_PROFILER_RAISE (vtable_loading, (vt)); + mono_class_compute_gc_descriptor (klass); /* * For Boehm: @@ -1955,7 +2014,8 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoErro bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE); /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/ statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1); - vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables"); + vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, vt, "Static Fields"); + if (bitmap != default_bitmap) g_free (bitmap); } else { @@ -2053,6 +2113,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoErro if (!is_ok (error)) { mono_domain_unlock (domain); mono_loader_unlock (); + MONO_PROFILER_RAISE (vtable_failed, (vt)); return NULL; } } @@ -2075,6 +2136,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoErro if (!is_ok (error)) { mono_domain_unlock (domain); mono_loader_unlock (); + MONO_PROFILER_RAISE (vtable_failed, (vt)); return NULL; } @@ -2082,7 +2144,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoErro /* This is unregistered in unregister_vtable_reflection_type() in domain.c. */ - MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type"); + MONO_GC_REGISTER_ROOT_IF_MOVING (vt->type, MONO_ROOT_SOURCE_REFLECTION, vt, "Reflection Type Object"); } mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass)); @@ -2134,6 +2196,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoErro if (!is_ok (error)) { mono_domain_unlock (domain); mono_loader_unlock (); + MONO_PROFILER_RAISE (vtable_failed, (vt)); return NULL; } @@ -2141,7 +2204,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoErro /* This is unregistered in unregister_vtable_reflection_type() in domain.c. */ - MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type"); + MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, vt, "Reflection Type Object"); } mono_domain_unlock (domain); @@ -2152,6 +2215,8 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoErro if (klass->parent) mono_class_vtable_full (domain, klass->parent, error); + MONO_PROFILER_RAISE (vtable_loaded, (vt)); + return vt; } @@ -2262,6 +2327,9 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer)); pvt->klass = mono_defaults.transparent_proxy_class; + + MONO_PROFILER_RAISE (vtable_loading, (pvt)); + /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */ pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr; @@ -2352,6 +2420,7 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono #else pvt->interface_bitmap = bitmap; #endif + MONO_PROFILER_RAISE (vtable_loaded, (pvt)); return pvt; failure: if (extra_interfaces) @@ -2359,6 +2428,7 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono #ifdef COMPRESSED_INTERFACE_BITMAP g_free (bitmap); #endif + MONO_PROFILER_RAISE (vtable_failed, (pvt)); return NULL; } @@ -5435,8 +5505,12 @@ mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error) if (G_UNLIKELY (!o)) mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size); - else if (G_UNLIKELY (vtable->klass->has_finalize)) - mono_object_register_finalizer (o); + else if (G_UNLIKELY (vtable->klass->has_finalize || vtable->klass->has_weak_fields)) { + if (vtable->klass->has_finalize) + mono_object_register_finalizer (o); + if (vtable->klass->has_weak_fields) + mono_gc_register_obj_with_weak_fields (o); + } return o; } @@ -6424,6 +6498,13 @@ mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count) mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class); } +MonoVTable * +mono_object_get_vtable (MonoObject *obj) +{ + // This could be called during STW, so untag the vtable if needed. + return mono_gc_get_vtable (obj); +} + /** * mono_object_get_domain: * \param obj object to query diff --git a/mono/metadata/object.h b/mono/metadata/object.h index 9608cfc07620..4956577b43a1 100644 --- a/mono/metadata/object.h +++ b/mono/metadata/object.h @@ -200,6 +200,9 @@ mono_value_copy (void* dest, void* src, MonoClass *klass); MONO_API void mono_value_copy_array (MonoArray *dest, int dest_idx, void* src, int count); +MONO_API MonoVTable * +mono_object_get_vtable (MonoObject *obj); + MONO_API MonoDomain* mono_object_get_domain (MonoObject *obj); @@ -256,6 +259,12 @@ MONO_RT_EXTERNAL_ONLY MONO_API void mono_runtime_class_init (MonoVTable *vtable); +MONO_API MonoDomain * +mono_vtable_domain (MonoVTable *vtable); + +MONO_API MonoClass * +mono_vtable_class (MonoVTable *vtable); + MONO_API MonoMethod* mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method); diff --git a/mono/metadata/profiler-events.h b/mono/metadata/profiler-events.h index 6c270f0cf814..5e933d0c9fbf 100644 --- a/mono/metadata/profiler-events.h +++ b/mono/metadata/profiler-events.h @@ -12,6 +12,7 @@ * MONO_PROFILER_EVENT_2(name, type, arg1_type, arg1_name, arg2_type, arg2_name) * MONO_PROFILER_EVENT_3(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name) * MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) + * MONO_PROFILER_EVENT_5(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name, arg5_type, arg5_name) * * To add new callbacks to the API, simply add a line in this file and use * MONO_PROFILER_RAISE to raise the event wherever. @@ -22,11 +23,15 @@ * to prevent errors in existing code, you must add something like this at the * beginning of this file: * - * #ifndef MONO_PROFILER_EVENT_5 - * #define MONO_PROFILER_EVENT_5(...) # Do nothing. + * #ifndef MONO_PROFILER_EVENT_6 + * #define MONO_PROFILER_EVENT_6(...) # Do nothing. * #endif */ +#ifndef MONO_PROFILER_EVENT_5 +#define MONO_PROFILER_EVENT_5(...) +#endif + MONO_PROFILER_EVENT_0(runtime_initialized, RuntimeInitialized) MONO_PROFILER_EVENT_0(runtime_shutdown_begin, RuntimeShutdownBegin) MONO_PROFILER_EVENT_0(runtime_shutdown_end, RuntimeShutdownEnd) @@ -51,6 +56,10 @@ MONO_PROFILER_EVENT_1(class_loading, ClassLoading, MonoClass *, klass) MONO_PROFILER_EVENT_1(class_failed, ClassFailed, MonoClass *, klass) MONO_PROFILER_EVENT_1(class_loaded, ClassLoaded, MonoClass *, klass) +MONO_PROFILER_EVENT_1(vtable_loading, VTableLoading, MonoVTable *, vtable) +MONO_PROFILER_EVENT_1(vtable_failed, VTableFailed, MonoVTable *, vtable) +MONO_PROFILER_EVENT_1(vtable_loaded, VTableLoaded, MonoVTable *, vtable) + MONO_PROFILER_EVENT_1(image_loading, ModuleLoading, MonoImage *, image) MONO_PROFILER_EVENT_1(image_failed, ModuleFailed, MonoImage *, image) MONO_PROFILER_EVENT_1(image_loaded, ModuleLoaded, MonoImage *, image) @@ -83,25 +92,18 @@ MONO_PROFILER_EVENT_0(gc_finalizing, GCFinalizing) MONO_PROFILER_EVENT_0(gc_finalized, GCFinalized) MONO_PROFILER_EVENT_1(gc_finalizing_object, GCFinalizingObject, MonoObject *, object) MONO_PROFILER_EVENT_1(gc_finalized_object, GCFinalizedObject, MonoObject *, object) - -/* - * This callback provides very low quality data and doesn't really match how - * roots are actually handled in the runtime. It will be replaced with a more - * sensible callback in the future. **This will be a breaking change.** - * - * In the meantime, you must define MONO_PROFILER_UNSTABLE_GC_ROOTS to be able - * to use this interface. - */ -#ifdef MONO_PROFILER_UNSTABLE_GC_ROOTS -MONO_PROFILER_EVENT_4(gc_roots, GCRoots, MonoObject *const *, roots, const MonoProfilerGCRootType *, types, const uintptr_t *, extra, uint64_t, count) -#endif +MONO_PROFILER_EVENT_5(gc_root_register, RootRegister, const mono_byte *, start, uintptr_t, size, MonoGCRootSource, source, const void *, key, const char *, name) +MONO_PROFILER_EVENT_1(gc_root_unregister, RootUnregister, const mono_byte *, start) +MONO_PROFILER_EVENT_3(gc_roots, GCRoots, uint64_t, count, const mono_byte *const *, addresses, MonoObject *const *, objects) MONO_PROFILER_EVENT_1(monitor_contention, MonitorContention, MonoObject *, object) MONO_PROFILER_EVENT_1(monitor_failed, MonitorFailed, MonoObject *, object) MONO_PROFILER_EVENT_1(monitor_acquired, MonitorAcquired, MonoObject *, object) MONO_PROFILER_EVENT_1(thread_started, ThreadStarted, uintptr_t, tid) +MONO_PROFILER_EVENT_1(thread_stopping, ThreadStopping, uintptr_t, tid) MONO_PROFILER_EVENT_1(thread_stopped, ThreadStopped, uintptr_t, tid) +MONO_PROFILER_EVENT_1(thread_exited, ThreadExited, uintptr_t, tid) MONO_PROFILER_EVENT_2(thread_name, ThreadName, uintptr_t, tid, const char *, name) MONO_PROFILER_EVENT_2(sample_hit, SampleHit, const mono_byte *, ip, const void *, context) diff --git a/mono/metadata/profiler-private.h b/mono/metadata/profiler-private.h index 0a46667ca450..3c0fe896c4ff 100644 --- a/mono/metadata/profiler-private.h +++ b/mono/metadata/profiler-private.h @@ -8,7 +8,6 @@ #define __MONO_PROFILER_PRIVATE_H__ #include -#define MONO_PROFILER_UNSTABLE_GC_ROOTS #include #include #include @@ -33,12 +32,15 @@ struct _MonoProfilerDesc { _MONO_PROFILER_EVENT(name) #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \ _MONO_PROFILER_EVENT(name) +#define MONO_PROFILER_EVENT_5(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name, arg5_type, arg5_name) \ + _MONO_PROFILER_EVENT(name) #include #undef MONO_PROFILER_EVENT_0 #undef MONO_PROFILER_EVENT_1 #undef MONO_PROFILER_EVENT_2 #undef MONO_PROFILER_EVENT_3 #undef MONO_PROFILER_EVENT_4 +#undef MONO_PROFILER_EVENT_5 #undef _MONO_PROFILER_EVENT }; @@ -78,12 +80,15 @@ typedef struct { _MONO_PROFILER_EVENT(name) #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \ _MONO_PROFILER_EVENT(name) +#define MONO_PROFILER_EVENT_5(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name, arg5_type, arg5_name) \ + _MONO_PROFILER_EVENT(name) #include #undef MONO_PROFILER_EVENT_0 #undef MONO_PROFILER_EVENT_1 #undef MONO_PROFILER_EVENT_2 #undef MONO_PROFILER_EVENT_3 #undef MONO_PROFILER_EVENT_4 +#undef MONO_PROFILER_EVENT_5 #undef _MONO_PROFILER_EVENT } MonoProfilerState; @@ -150,12 +155,15 @@ mono_profiler_allocations_enabled (void) _MONO_PROFILER_EVENT(name, arg1_type arg1_name, arg2_type arg2_name, arg3_type arg3_name) #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \ _MONO_PROFILER_EVENT(name, arg1_type arg1_name, arg2_type arg2_name, arg3_type arg3_name, arg4_type arg4_name) +#define MONO_PROFILER_EVENT_5(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name, arg5_type, arg5_name) \ + _MONO_PROFILER_EVENT(name, arg1_type arg1_name, arg2_type arg2_name, arg3_type arg3_name, arg4_type arg4_name, arg5_type arg5_name) #include #undef MONO_PROFILER_EVENT_0 #undef MONO_PROFILER_EVENT_1 #undef MONO_PROFILER_EVENT_2 #undef MONO_PROFILER_EVENT_3 #undef MONO_PROFILER_EVENT_4 +#undef MONO_PROFILER_EVENT_5 #undef _MONO_PROFILER_EVENT /* These are the macros the rest of the runtime should use. */ diff --git a/mono/metadata/profiler.c b/mono/metadata/profiler.c index 7951abab675f..cb05578eebe8 100644 --- a/mono/metadata/profiler.c +++ b/mono/metadata/profiler.c @@ -780,12 +780,15 @@ mono_profiler_cleanup (void) _MONO_PROFILER_EVENT(name) #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \ _MONO_PROFILER_EVENT(name) +#define MONO_PROFILER_EVENT_5(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name, arg5_type, arg5_name) \ + _MONO_PROFILER_EVENT(name) #include #undef MONO_PROFILER_EVENT_0 #undef MONO_PROFILER_EVENT_1 #undef MONO_PROFILER_EVENT_2 #undef MONO_PROFILER_EVENT_3 #undef MONO_PROFILER_EVENT_4 +#undef MONO_PROFILER_EVENT_5 #undef _MONO_PROFILER_EVENT } @@ -801,12 +804,15 @@ mono_profiler_cleanup (void) _MONO_PROFILER_EVENT(name, type) #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \ _MONO_PROFILER_EVENT(name, type) +#define MONO_PROFILER_EVENT_5(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name, arg5_type, arg5_name) \ + _MONO_PROFILER_EVENT(name, type) #include #undef MONO_PROFILER_EVENT_0 #undef MONO_PROFILER_EVENT_1 #undef MONO_PROFILER_EVENT_2 #undef MONO_PROFILER_EVENT_3 #undef MONO_PROFILER_EVENT_4 +#undef MONO_PROFILER_EVENT_5 #undef _MONO_PROFILER_EVENT MonoProfilerHandle head = mono_profiler_state.profilers; @@ -883,12 +889,15 @@ update_callback (volatile gpointer *location, gpointer new_, volatile gint32 *co _MONO_PROFILER_EVENT(name, type) #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \ _MONO_PROFILER_EVENT(name, type) +#define MONO_PROFILER_EVENT_5(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name, arg5_type, arg5_name) \ + _MONO_PROFILER_EVENT(name, type) #include #undef MONO_PROFILER_EVENT_0 #undef MONO_PROFILER_EVENT_1 #undef MONO_PROFILER_EVENT_2 #undef MONO_PROFILER_EVENT_3 #undef MONO_PROFILER_EVENT_4 +#undef MONO_PROFILER_EVENT_5 #undef _MONO_PROFILER_EVENT #define _MONO_PROFILER_EVENT(name, type, params, args) \ @@ -911,12 +920,15 @@ update_callback (volatile gpointer *location, gpointer new_, volatile gint32 *co _MONO_PROFILER_EVENT(name, type, (arg1_type arg1_name, arg2_type arg2_name, arg3_type arg3_name), (h->prof, arg1_name, arg2_name, arg3_name)) #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \ _MONO_PROFILER_EVENT(name, type, (arg1_type arg1_name, arg2_type arg2_name, arg3_type arg3_name, arg4_type arg4_name), (h->prof, arg1_name, arg2_name, arg3_name, arg4_name)) +#define MONO_PROFILER_EVENT_5(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name, arg5_type, arg5_name) \ + _MONO_PROFILER_EVENT(name, type, (arg1_type arg1_name, arg2_type arg2_name, arg3_type arg3_name, arg4_type arg4_name, arg5_type arg5_name), (h->prof, arg1_name, arg2_name, arg3_name, arg4_name, arg5_name)) #include #undef MONO_PROFILER_EVENT_0 #undef MONO_PROFILER_EVENT_1 #undef MONO_PROFILER_EVENT_2 #undef MONO_PROFILER_EVENT_3 #undef MONO_PROFILER_EVENT_4 +#undef MONO_PROFILER_EVENT_5 #undef _MONO_PROFILER_EVENT /* diff --git a/mono/metadata/profiler.h b/mono/metadata/profiler.h index 56e2d2133c86..a2110902296e 100644 --- a/mono/metadata/profiler.h +++ b/mono/metadata/profiler.h @@ -114,24 +114,6 @@ MONO_API void *mono_profiler_call_context_get_local (MonoProfilerCallContext *co MONO_API void *mono_profiler_call_context_get_result (MonoProfilerCallContext *context); MONO_API void mono_profiler_call_context_free_buffer (void *buffer); -#ifdef MONO_PROFILER_UNSTABLE_GC_ROOTS -typedef enum { - /* Upper 2 bytes. */ - MONO_PROFILER_GC_ROOT_PINNING = 1 << 8, - MONO_PROFILER_GC_ROOT_WEAKREF = 2 << 8, - MONO_PROFILER_GC_ROOT_INTERIOR = 4 << 8, - - /* Lower 2 bytes (flags). */ - MONO_PROFILER_GC_ROOT_STACK = 1 << 0, - MONO_PROFILER_GC_ROOT_FINALIZER = 1 << 1, - MONO_PROFILER_GC_ROOT_HANDLE = 1 << 2, - MONO_PROFILER_GC_ROOT_OTHER = 1 << 3, - MONO_PROFILER_GC_ROOT_MISC = 1 << 4, - - MONO_PROFILER_GC_ROOT_TYPEMASK = 0xff, -} MonoProfilerGCRootType; -#endif - typedef enum { /** * The \c data parameter is a \c MonoMethod pointer. @@ -207,12 +189,15 @@ typedef enum { _MONO_PROFILER_EVENT(type, MonoProfiler *prof, arg1_type arg1_name, arg2_type arg2_name, arg3_type arg3_name) #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \ _MONO_PROFILER_EVENT(type, MonoProfiler *prof, arg1_type arg1_name, arg2_type arg2_name, arg3_type arg3_name, arg4_type arg4_name) +#define MONO_PROFILER_EVENT_5(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name, arg5_type, arg5_name) \ + _MONO_PROFILER_EVENT(type, MonoProfiler *prof, arg1_type arg1_name, arg2_type arg2_name, arg3_type arg3_name, arg4_type arg4_name, arg5_type arg5_name) #include #undef MONO_PROFILER_EVENT_0 #undef MONO_PROFILER_EVENT_1 #undef MONO_PROFILER_EVENT_2 #undef MONO_PROFILER_EVENT_3 #undef MONO_PROFILER_EVENT_4 +#undef MONO_PROFILER_EVENT_5 #undef _MONO_PROFILER_EVENT #define _MONO_PROFILER_EVENT(name, type) \ @@ -227,12 +212,15 @@ typedef enum { _MONO_PROFILER_EVENT(name, type) #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \ _MONO_PROFILER_EVENT(name, type) +#define MONO_PROFILER_EVENT_5(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name, arg5_type, arg5_name) \ + _MONO_PROFILER_EVENT(name, type) #include #undef MONO_PROFILER_EVENT_0 #undef MONO_PROFILER_EVENT_1 #undef MONO_PROFILER_EVENT_2 #undef MONO_PROFILER_EVENT_3 #undef MONO_PROFILER_EVENT_4 +#undef MONO_PROFILER_EVENT_5 #undef _MONO_PROFILER_EVENT MONO_END_DECLS diff --git a/mono/metadata/reflection-cache.h b/mono/metadata/reflection-cache.h index bba3cda2d1cf..9fd05486f247 100644 --- a/mono/metadata/reflection-cache.h +++ b/mono/metadata/reflection-cache.h @@ -56,7 +56,7 @@ cache_object (MonoDomain *domain, MonoClass *klass, gpointer item, MonoObject* o mono_domain_lock (domain); if (!domain->refobject_hash) - domain->refobject_hash = mono_conc_g_hash_table_new_type (reflected_hash, reflected_equal, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, "domain reflection objects table"); + domain->refobject_hash = mono_conc_g_hash_table_new_type (reflected_hash, reflected_equal, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, domain, "Domain Reflection Object Table"); obj = (MonoObject*) mono_conc_g_hash_table_lookup (domain->refobject_hash, &pe); if (obj == NULL) { @@ -80,7 +80,7 @@ cache_object_handle (MonoDomain *domain, MonoClass *klass, gpointer item, MonoOb mono_domain_lock (domain); if (!domain->refobject_hash) - domain->refobject_hash = mono_conc_g_hash_table_new_type (reflected_hash, reflected_equal, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, "domain reflection objects table"); + domain->refobject_hash = mono_conc_g_hash_table_new_type (reflected_hash, reflected_equal, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, domain, "Domain Reflection Object Table"); MonoObjectHandle obj = MONO_HANDLE_NEW (MonoObject, mono_conc_g_hash_table_lookup (domain->refobject_hash, &pe)); if (MONO_HANDLE_IS_NULL (obj)) { diff --git a/mono/metadata/reflection.c b/mono/metadata/reflection.c index 3f7ca677da7a..6ee435419744 100644 --- a/mono/metadata/reflection.c +++ b/mono/metadata/reflection.c @@ -472,7 +472,7 @@ mono_type_get_object_checked (MonoDomain *domain, MonoType *type, MonoError *err mono_domain_lock (domain); if (!domain->type_hash) domain->type_hash = mono_g_hash_table_new_type ((GHashFunc)mono_metadata_type_hash, - (GCompareFunc)mono_metadata_type_equal, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, "domain reflection types table"); + (GCompareFunc)mono_metadata_type_equal, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, domain, "Domain Reflection Type Table"); if ((res = (MonoReflectionType *)mono_g_hash_table_lookup (domain->type_hash, type))) { mono_domain_unlock (domain); mono_loader_unlock (); @@ -2322,7 +2322,7 @@ mono_reflection_get_token_checked (MonoObjectHandle obj, MonoError *error) MonoMethod *method = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoReflectionMethod, member_impl), method); token = mono_method_get_param_token (method, MONO_HANDLE_GETVAL (p, PositionImpl)); - } else if (strcmp (klass->name, "Module") == 0 || strcmp (klass->name, "MonoModule") == 0) { + } else if (strcmp (klass->name, "Module") == 0 || strcmp (klass->name, "MonoModule") == 0 || strcmp (klass->name, "ModuleBuilder") == 0) { MonoReflectionModuleHandle m = MONO_HANDLE_CAST (MonoReflectionModule, obj); token = MONO_HANDLE_GETVAL (m, token); diff --git a/mono/metadata/sgen-client-mono.h b/mono/metadata/sgen-client-mono.h index a01890cf339d..981e6e9a974b 100644 --- a/mono/metadata/sgen-client-mono.h +++ b/mono/metadata/sgen-client-mono.h @@ -288,28 +288,11 @@ sgen_client_binary_protocol_collection_requested (int generation, size_t request MONO_GC_REQUESTED (generation, requested_size, force); } -static void G_GNUC_UNUSED -sgen_client_binary_protocol_collection_begin (int minor_gc_count, int generation) -{ - MONO_GC_BEGIN (generation); - - MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_START, generation)); +void +sgen_client_binary_protocol_collection_begin (int minor_gc_count, int generation); -#ifndef DISABLE_PERFCOUNTERS - if (generation == GENERATION_NURSERY) - mono_atomic_inc_i32 (&mono_perfcounters->gc_collections0); - else - mono_atomic_inc_i32 (&mono_perfcounters->gc_collections1); -#endif -} - -static void G_GNUC_UNUSED -sgen_client_binary_protocol_collection_end (int minor_gc_count, int generation, long long num_objects_scanned, long long num_unique_objects_scanned) -{ - MONO_GC_END (generation); - - MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_END, generation)); -} +void +sgen_client_binary_protocol_collection_end (int minor_gc_count, int generation, long long num_objects_scanned, long long num_unique_objects_scanned); static void G_GNUC_UNUSED sgen_client_binary_protocol_concurrent_start (void) @@ -686,6 +669,18 @@ sgen_client_binary_protocol_pin_stats (int objects_pinned_in_nursery, size_t byt { } +static void G_GNUC_UNUSED +sgen_client_root_registered (char *start, size_t size, int source, void *key, const char *msg) +{ + MONO_PROFILER_RAISE (gc_root_register, ((const mono_byte *) start, size, source, key, msg)); +} + +static void G_GNUC_UNUSED +sgen_client_root_deregistered (char *start) +{ + MONO_PROFILER_RAISE (gc_root_unregister, ((const mono_byte *) start)); +} + static void G_GNUC_UNUSED sgen_client_binary_protocol_worker_finish_stats (int worker_index, int generation, gboolean forced, long long major_scan, long long los_scan, long long work_time) { diff --git a/mono/metadata/sgen-mono.c b/mono/metadata/sgen-mono.c index 5da2bb288b92..1477057d27b0 100644 --- a/mono/metadata/sgen-mono.c +++ b/mono/metadata/sgen-mono.c @@ -443,6 +443,13 @@ sgen_client_zero_array_fill_header (void *p, size_t size) } } +MonoVTable * +mono_gc_get_vtable (MonoObject *obj) +{ + // See sgen/sgen-tagged-pointer.h. + return SGEN_LOAD_VTABLE (obj); +} + /* * Finalization */ @@ -979,13 +986,13 @@ mono_gc_alloc_mature (MonoVTable *vtable, size_t size) * mono_gc_alloc_fixed: */ void* -mono_gc_alloc_fixed (size_t size, MonoGCDescriptor descr, MonoGCRootSource source, const char *msg) +mono_gc_alloc_fixed (size_t size, MonoGCDescriptor descr, MonoGCRootSource source, void *key, const char *msg) { /* FIXME: do a single allocation */ void *res = g_calloc (1, size); if (!res) return NULL; - if (!mono_gc_register_root ((char *)res, size, descr, source, msg)) { + if (!mono_gc_register_root ((char *)res, size, descr, source, key, msg)) { g_free (res); res = NULL; } @@ -1501,7 +1508,7 @@ mono_gc_get_managed_allocator (MonoClass *klass, gboolean for_box, gboolean know return NULL; if (known_instance_size && ALIGN_TO (klass->instance_size, SGEN_ALLOC_ALIGN) >= SGEN_MAX_SMALL_OBJ_SIZE) return NULL; - if (mono_class_has_finalizer (klass) || mono_class_is_marshalbyref (klass)) + if (mono_class_has_finalizer (klass) || mono_class_is_marshalbyref (klass) || klass->has_weak_fields) return NULL; if (klass->rank) return NULL; @@ -1875,11 +1882,13 @@ mono_gc_set_string_length (MonoString *str, gint32 new_length) */ #define GC_ROOT_NUM 32 +#define SPECIAL_ADDRESS_FIN_QUEUE ((void*)1) +#define SPECIAL_ADDRESS_CRIT_FIN_QUEUE ((void*)2) + typedef struct { int count; /* must be the first field */ + void *addresses [GC_ROOT_NUM]; void *objects [GC_ROOT_NUM]; - int root_types [GC_ROOT_NUM]; - uintptr_t extra_info [GC_ROOT_NUM]; } GCRootReport; static void @@ -1887,63 +1896,34 @@ notify_gc_roots (GCRootReport *report) { if (!report->count) return; - MONO_PROFILER_RAISE (gc_roots, ((MonoObject **) report->objects, (MonoProfilerGCRootType *) report->root_types, report->extra_info, report->count)); + MONO_PROFILER_RAISE (gc_roots, (report->count, (const mono_byte *const *)report->addresses, (MonoObject *const *) report->objects)); report->count = 0; } static void -add_profile_gc_root (GCRootReport *report, void *object, int rtype, uintptr_t extra_info) +report_gc_root (GCRootReport *report, void *address, void *object) { if (report->count == GC_ROOT_NUM) notify_gc_roots (report); + report->addresses [report->count] = address; report->objects [report->count] = object; - report->root_types [report->count] = rtype; - report->extra_info [report->count++] = (uintptr_t)SGEN_LOAD_VTABLE (object)->klass; -} - -void -sgen_client_nursery_objects_pinned (void **definitely_pinned, int count) -{ - if (MONO_PROFILER_ENABLED (gc_roots)) { - GCRootReport report; - int idx; - report.count = 0; - for (idx = 0; idx < count; ++idx) - add_profile_gc_root (&report, definitely_pinned [idx], MONO_PROFILER_GC_ROOT_PINNING | MONO_PROFILER_GC_ROOT_MISC, 0); - notify_gc_roots (&report); - } + report->count++; } static void -report_finalizer_roots_from_queue (SgenPointerQueue *queue) +single_arg_report_root (MonoObject **obj, void *gc_data) { - GCRootReport report; - size_t i; - - report.count = 0; - for (i = 0; i < queue->next_slot; ++i) { - void *obj = queue->data [i]; - if (!obj) - continue; - add_profile_gc_root (&report, obj, MONO_PROFILER_GC_ROOT_FINALIZER, 0); - } - notify_gc_roots (&report); + GCRootReport *report = gc_data; + if (*obj) + report_gc_root (report, obj, *obj); } static void -report_finalizer_roots (SgenPointerQueue *fin_ready_queue, SgenPointerQueue *critical_fin_queue) +two_args_report_root (void *address, MonoObject *obj, void *gc_data) { - report_finalizer_roots_from_queue (fin_ready_queue); - report_finalizer_roots_from_queue (critical_fin_queue); -} - -static GCRootReport *root_report; - -static void -single_arg_report_root (MonoObject **obj, void *gc_data) -{ - if (*obj) - add_profile_gc_root (root_report, *obj, MONO_PROFILER_GC_ROOT_OTHER, 0); + GCRootReport *report = gc_data; + if (obj) + report_gc_root (report, address, obj); } static void @@ -1953,9 +1933,8 @@ precisely_report_roots_from (GCRootReport *report, void** start_root, void** end case ROOT_DESC_BITMAP: desc >>= ROOT_DESC_TYPE_SHIFT; while (desc) { - if ((desc & 1) && *start_root) { - add_profile_gc_root (report, *start_root, MONO_PROFILER_GC_ROOT_OTHER, 0); - } + if ((desc & 1) && *start_root) + report_gc_root (report, start_root, *start_root); desc >>= 1; start_root++; } @@ -1969,9 +1948,8 @@ precisely_report_roots_from (GCRootReport *report, void** start_root, void** end gsize bmap = *bitmap_data++; void **objptr = start_run; while (bmap) { - if ((bmap & 1) && *objptr) { - add_profile_gc_root (report, *objptr, MONO_PROFILER_GC_ROOT_OTHER, 0); - } + if ((bmap & 1) && *objptr) + report_gc_root (report, objptr, *objptr); bmap >>= 1; ++objptr; } @@ -1984,14 +1962,17 @@ precisely_report_roots_from (GCRootReport *report, void** start_root, void** end for (p = start_root; p < end_root; p++) { if (*p) - add_profile_gc_root (report, *p, MONO_PROFILER_GC_ROOT_OTHER, 0); + report_gc_root (report, p, *p); } break; } case ROOT_DESC_USER: { MonoGCRootMarkFunc marker = (MonoGCRootMarkFunc)sgen_get_user_descriptor_func (desc); - root_report = report; - marker ((MonoObject**)start_root, single_arg_report_root, NULL); + + if ((void*)marker == (void*)sgen_mark_normal_gc_handles) + sgen_gc_handles_report_roots (two_args_report_root, report); + else + marker ((MonoObject**)start_root, single_arg_report_root, report); break; } case ROOT_DESC_RUN_LEN: @@ -2002,15 +1983,194 @@ precisely_report_roots_from (GCRootReport *report, void** start_root, void** end } static void -report_registered_roots_by_type (int root_type) +report_pinning_roots (GCRootReport *report, void **start, void **end) +{ + while (start < end) { + mword addr = (mword)*start; + addr &= ~(SGEN_ALLOC_ALIGN - 1); + if (addr) + report_gc_root (report, start, (void*)addr); + + start++; + } +} + +static SgenPointerQueue pinned_objects = SGEN_POINTER_QUEUE_INIT (INTERNAL_MEM_MOVED_OBJECT); +static mword lower_bound, upper_bound; + +static GCObject* +find_pinned_obj (char *addr) +{ + size_t idx = sgen_pointer_queue_search (&pinned_objects, addr); + + if (idx != pinned_objects.next_slot) { + if (pinned_objects.data [idx] == addr) + return pinned_objects.data [idx]; + if (idx == 0) + return NULL; + } + + GCObject *obj = pinned_objects.data [idx - 1]; + if (addr > (char*)obj && addr < ((char*)obj + sgen_safe_object_get_size (obj))) + return obj; + return NULL; +} + + +/* + * We pass @root_report_address so register are properly accounted towards their thread +*/ +static void +report_conservative_roots (GCRootReport *report, char *root_report_address, void **start, void **end) +{ + while (start < end) { + mword addr = (mword)*start; + addr &= ~(SGEN_ALLOC_ALIGN - 1); + + if (addr < lower_bound || addr > upper_bound) { + ++start; + continue; + } + + GCObject *obj = find_pinned_obj ((char*)addr); + if (obj) + report_gc_root (report, root_report_address, obj); + start++; + } +} + +typedef struct { + gboolean precise; + GCRootReport *report; + SgenThreadInfo *info; +} ReportHandleStackRoot; + +static void +report_handle_stack_root (gpointer *ptr, gpointer user_data) +{ + ReportHandleStackRoot *ud = user_data; + GCRootReport *report = ud->report; + gpointer addr = ud->info->client_info.info.handle_stack; + + // Note: We know that *ptr != NULL. + if (ud->precise) + report_gc_root (report, addr, *ptr); + else + report_conservative_roots (report, addr, ptr, ptr + 1); +} + +static void +report_handle_stack_roots (GCRootReport *report, SgenThreadInfo *info, gboolean precise) +{ + ReportHandleStackRoot ud = { + .precise = precise, + .report = report, + .info = info, + }; + + mono_handle_stack_scan ((HandleStack *) info->client_info.info.handle_stack, report_handle_stack_root, &ud, ud.precise, FALSE); +} + +static void +report_stack_roots (void) +{ + GCRootReport report = {0}; + FOREACH_THREAD (info) { + void *aligned_stack_start; + + if (info->client_info.skip) { + continue; + } else if (info->client_info.gc_disabled) { + continue; + } else if (!mono_thread_info_is_live (info)) { + continue; + } else if (!info->client_info.stack_start) { + continue; + } + + g_assert (info->client_info.stack_start); + g_assert (info->client_info.info.stack_end); + + aligned_stack_start = (void*)(mword) ALIGN_TO ((mword)info->client_info.stack_start, SIZEOF_VOID_P); +#ifdef HOST_WIN32 + /* Windows uses a guard page before the committed stack memory pages to detect when the + stack needs to be grown. If we suspend a thread just after a function prolog has + decremented the stack pointer to point into the guard page but before the thread has + been able to read or write to that page, starting the stack scan at aligned_stack_start + will raise a STATUS_GUARD_PAGE_VIOLATION and the process will crash. This code uses + VirtualQuery() to determine whether stack_start points into the guard page and then + updates aligned_stack_start to point at the next non-guard page. */ + MEMORY_BASIC_INFORMATION mem_info; + SIZE_T result = VirtualQuery (info->client_info.stack_start, &mem_info, sizeof(mem_info)); + g_assert (result != 0); + if (mem_info.Protect & PAGE_GUARD) { + aligned_stack_start = ((char*) mem_info.BaseAddress) + mem_info.RegionSize; + } +#endif + + g_assert (info->client_info.suspend_done); + + report_conservative_roots (&report, aligned_stack_start, (void **)aligned_stack_start, (void **)info->client_info.info.stack_end); + report_conservative_roots (&report, aligned_stack_start, (void**)&info->client_info.ctx, (void**)(&info->client_info.ctx + 1)); + + report_handle_stack_roots (&report, info, FALSE); + report_handle_stack_roots (&report, info, TRUE); + } FOREACH_THREAD_END + + notify_gc_roots (&report); +} + +static void +report_pin_queue (void) +{ + lower_bound = SIZE_MAX; + upper_bound = 0; + + //sort the addresses + sgen_pointer_queue_sort_uniq (&pinned_objects); + + for (int i = 0; i < pinned_objects.next_slot; ++i) { + GCObject *obj = pinned_objects.data [i]; + ssize_t size = sgen_safe_object_get_size (obj); + + ssize_t addr = (ssize_t)obj; + lower_bound = MIN (lower_bound, addr); + upper_bound = MAX (upper_bound, addr + size); + } + + report_stack_roots (); + sgen_pointer_queue_clear (&pinned_objects); +} + +static void +report_finalizer_roots_from_queue (SgenPointerQueue *queue, void* queue_address) { GCRootReport report; + size_t i; + + report.count = 0; + for (i = 0; i < queue->next_slot; ++i) { + void *obj = queue->data [i]; + if (!obj) + continue; + report_gc_root (&report, queue_address, obj); + } + notify_gc_roots (&report); +} + +static void +report_registered_roots_by_type (int root_type) +{ + GCRootReport report = { 0 }; void **start_root; RootRecord *root; report.count = 0; SGEN_HASH_TABLE_FOREACH (&roots_hash [root_type], void **, start_root, RootRecord *, root) { - SGEN_LOG (6, "Precise root scan %p-%p (desc: %p)", start_root, root->end_root, (void*)root->root_desc); - precisely_report_roots_from (&report, start_root, (void**)root->end_root, root->root_desc); + SGEN_LOG (6, "Profiler root scan %p-%p (desc: %p)", start_root, root->end_root, (void*)root->root_desc); + if (root_type == ROOT_TYPE_PINNED) + report_pinning_roots (&report, start_root, (void**)root->end_root); + else + precisely_report_roots_from (&report, start_root, (void**)root->end_root, root->root_desc); } SGEN_HASH_TABLE_FOREACH_END; notify_gc_roots (&report); } @@ -2018,52 +2178,85 @@ report_registered_roots_by_type (int root_type) static void report_registered_roots (void) { - report_registered_roots_by_type (ROOT_TYPE_NORMAL); - report_registered_roots_by_type (ROOT_TYPE_WBARRIER); + for (int i = 0; i < ROOT_TYPE_NUM; ++i) + report_registered_roots_by_type (i); +} + +static void +sgen_report_all_roots (SgenPointerQueue *fin_ready_queue, SgenPointerQueue *critical_fin_queue) +{ + if (!MONO_PROFILER_ENABLED (gc_roots)) + return; + + report_registered_roots (); + report_pin_queue (); + report_finalizer_roots_from_queue (fin_ready_queue, SPECIAL_ADDRESS_FIN_QUEUE); + report_finalizer_roots_from_queue (critical_fin_queue, SPECIAL_ADDRESS_CRIT_FIN_QUEUE); } void -sgen_client_collecting_minor (SgenPointerQueue *fin_ready_queue, SgenPointerQueue *critical_fin_queue) +sgen_client_pinning_start (void) { - if (MONO_PROFILER_ENABLED (gc_roots)) - report_registered_roots (); + if (!MONO_PROFILER_ENABLED (gc_roots)) + return; - if (MONO_PROFILER_ENABLED (gc_roots)) - report_finalizer_roots (fin_ready_queue, critical_fin_queue); + sgen_pointer_queue_clear (&pinned_objects); } -static GCRootReport major_root_report; -static gboolean profile_roots; +void +sgen_client_pinning_end (void) +{ + if (!MONO_PROFILER_ENABLED (gc_roots)) + return; +} void -sgen_client_collecting_major_1 (void) +sgen_client_nursery_objects_pinned (void **definitely_pinned, int count) { - profile_roots = MONO_PROFILER_ENABLED (gc_roots); - memset (&major_root_report, 0, sizeof (GCRootReport)); + if (!MONO_PROFILER_ENABLED (gc_roots)) + return; + + for (int i = 0; i < count; ++i) + sgen_pointer_queue_add (&pinned_objects, definitely_pinned [i]); } void sgen_client_pinned_los_object (GCObject *obj) { - if (profile_roots) - add_profile_gc_root (&major_root_report, (char*)obj, MONO_PROFILER_GC_ROOT_PINNING | MONO_PROFILER_GC_ROOT_MISC, 0); + if (!MONO_PROFILER_ENABLED (gc_roots)) + return; + + sgen_pointer_queue_add (&pinned_objects, obj); } void -sgen_client_collecting_major_2 (void) +sgen_client_pinned_cemented_object (GCObject *obj) { - if (profile_roots) - notify_gc_roots (&major_root_report); + if (!MONO_PROFILER_ENABLED (gc_roots)) + return; - if (MONO_PROFILER_ENABLED (gc_roots)) - report_registered_roots (); + // TODO: How do we report this in a way that makes sense? } void -sgen_client_collecting_major_3 (SgenPointerQueue *fin_ready_queue, SgenPointerQueue *critical_fin_queue) +sgen_client_pinned_major_heap_object (GCObject *obj) { - if (MONO_PROFILER_ENABLED (gc_roots)) - report_finalizer_roots (fin_ready_queue, critical_fin_queue); + if (!MONO_PROFILER_ENABLED (gc_roots)) + return; + + sgen_pointer_queue_add (&pinned_objects, obj); +} + +void +sgen_client_collecting_minor_report_roots (SgenPointerQueue *fin_ready_queue, SgenPointerQueue *critical_fin_queue) +{ + sgen_report_all_roots (fin_ready_queue, critical_fin_queue); +} + +void +sgen_client_collecting_major_report_roots (SgenPointerQueue *fin_ready_queue, SgenPointerQueue *critical_fin_queue) +{ + sgen_report_all_roots (fin_ready_queue, critical_fin_queue); } #define MOVED_OBJECTS_NUM 64 @@ -2459,12 +2652,12 @@ sgen_client_scan_thread_data (void *start_nursery, void *end_nursery, gboolean p beginning of the object. */ if (precise) - mono_handle_stack_scan ((HandleStack*)info->client_info.info.handle_stack, (GcScanFunc)ctx.ops->copy_or_mark_object, ctx.queue, precise); + mono_handle_stack_scan ((HandleStack*)info->client_info.info.handle_stack, (GcScanFunc)ctx.ops->copy_or_mark_object, ctx.queue, precise, TRUE); else { PinHandleStackInteriorPtrData ud = { .start_nursery = start_nursery, .end_nursery = end_nursery, }; - mono_handle_stack_scan ((HandleStack*)info->client_info.info.handle_stack, pin_handle_stack_interior_ptrs, &ud, precise); + mono_handle_stack_scan ((HandleStack*)info->client_info.info.handle_stack, pin_handle_stack_interior_ptrs, &ud, precise, FALSE); } } } FOREACH_THREAD_END @@ -2495,15 +2688,15 @@ mono_gc_set_stack_end (void *stack_end) */ int -mono_gc_register_root (char *start, size_t size, MonoGCDescriptor descr, MonoGCRootSource source, const char *msg) +mono_gc_register_root (char *start, size_t size, MonoGCDescriptor descr, MonoGCRootSource source, void *key, const char *msg) { - return sgen_register_root (start, size, descr, descr ? ROOT_TYPE_NORMAL : ROOT_TYPE_PINNED, source, msg); + return sgen_register_root (start, size, descr, descr ? ROOT_TYPE_NORMAL : ROOT_TYPE_PINNED, source, key, msg); } int -mono_gc_register_root_wbarrier (char *start, size_t size, MonoGCDescriptor descr, MonoGCRootSource source, const char *msg) +mono_gc_register_root_wbarrier (char *start, size_t size, MonoGCDescriptor descr, MonoGCRootSource source, void *key, const char *msg) { - return sgen_register_root (start, size, descr, ROOT_TYPE_WBARRIER, source, msg); + return sgen_register_root (start, size, descr, ROOT_TYPE_WBARRIER, source, key, msg); } void @@ -2537,6 +2730,8 @@ mono_gc_pthread_create (pthread_t *new_thread, const pthread_attr_t *attr, void void sgen_client_total_allocated_heap_changed (size_t allocated_heap) { + MONO_PROFILER_RAISE (gc_resize, (allocated_heap)); + mono_runtime_resource_check_limit (MONO_RESOURCE_GC_HEAP, allocated_heap); } @@ -2648,6 +2843,12 @@ mono_gc_make_descr_for_string (gsize *bitmap, int numbits) return SGEN_DESC_STRING; } +void +mono_gc_register_obj_with_weak_fields (void *obj) +{ + return sgen_register_obj_with_weak_fields (obj); +} + void* mono_gc_get_nursery (int *shift_bits, size_t *size) { @@ -3100,4 +3301,52 @@ mono_gc_is_null (void) return FALSE; } +gsize * +sgen_client_get_weak_bitmap (MonoVTable *vt, int *nbits) +{ + MonoClass *klass = vt->klass; + + return mono_class_get_weak_bitmap (klass, nbits); +} + +void +sgen_client_binary_protocol_collection_begin (int minor_gc_count, int generation) +{ + static gboolean pseudo_roots_registered; + + MONO_GC_BEGIN (generation); + + MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_START, generation)); + + if (!pseudo_roots_registered) { + pseudo_roots_registered = TRUE; + MONO_PROFILER_RAISE (gc_root_register, (SPECIAL_ADDRESS_FIN_QUEUE, 1, MONO_ROOT_SOURCE_FINALIZER_QUEUE, NULL, "Finalizer Queue")); + MONO_PROFILER_RAISE (gc_root_register, (SPECIAL_ADDRESS_CRIT_FIN_QUEUE, 1, MONO_ROOT_SOURCE_FINALIZER_QUEUE, NULL, "Finalizer Queue (Critical)")); + } + +#ifndef DISABLE_PERFCOUNTERS + if (generation == GENERATION_NURSERY) + mono_atomic_inc_i32 (&mono_perfcounters->gc_collections0); + else + mono_atomic_inc_i32 (&mono_perfcounters->gc_collections1); +#endif +} + +void +sgen_client_binary_protocol_collection_end (int minor_gc_count, int generation, long long num_objects_scanned, long long num_unique_objects_scanned) +{ + MONO_GC_END (generation); + + MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_END, generation)); +} + +#ifdef HOST_WASM +void +sgen_client_schedule_background_job (void (*cb)(void)) +{ + mono_threads_schedule_background_job (cb); +} + +#endif + #endif diff --git a/mono/metadata/sre-save.c b/mono/metadata/sre-save.c index 710d9bde53cb..227fc504bb9e 100644 --- a/mono/metadata/sre-save.c +++ b/mono/metadata/sre-save.c @@ -966,7 +966,7 @@ mono_image_get_generic_param_info (MonoReflectionGenericParam *gparam, guint32 o entry = g_new0 (GenericParamTableEntry, 1); entry->owner = owner; /* FIXME: track where gen_params should be freed and remove the GC root as well */ - MONO_GC_REGISTER_ROOT_IF_MOVING (entry->gparam, MONO_ROOT_SOURCE_REFLECTION, "reflection generic parameter"); + MONO_GC_REGISTER_ROOT_IF_MOVING (entry->gparam, MONO_ROOT_SOURCE_REFLECTION, NULL, "Reflection Generic Parameter"); entry->gparam = gparam; g_ptr_array_add (assembly->gen_params, entry); @@ -2380,7 +2380,7 @@ mono_image_build_metadata (MonoReflectionModuleBuilder *moduleb, MonoError *erro goto_if_nok (error, leave); /* Collect all types into a list sorted by their table_idx */ - mono_ptr_array_init (types, moduleb->num_types, MONO_ROOT_SOURCE_REFLECTION, "dynamic module types list"); + mono_ptr_array_init (types, moduleb->num_types, MONO_ROOT_SOURCE_REFLECTION, NULL, "Reflection Dynamic Image Type List"); if (moduleb->types) for (i = 0; i < moduleb->num_types; ++i) { diff --git a/mono/metadata/threadpool-io.c b/mono/metadata/threadpool-io.c index a40ed6de5ea1..b3153db22345 100644 --- a/mono/metadata/threadpool-io.c +++ b/mono/metadata/threadpool-io.c @@ -253,7 +253,7 @@ wait_callback (gint fd, gint events, gpointer user_data) return; if (fd == threadpool_io->wakeup_pipes [0]) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_THREADPOOL, "io threadpool: wke"); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_SELECTOR, "io threadpool: wke"); selector_thread_wakeup_drain_pipes (); } else { MonoGHashTable *states; @@ -265,7 +265,7 @@ wait_callback (gint fd, gint events, gpointer user_data) g_assert (user_data); states = (MonoGHashTable *)user_data; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_THREADPOOL, "io threadpool: cal fd %3d, events = %2s | %2s | %3s", + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_SELECTOR, "io threadpool: cal fd %3d, events = %2s | %2s | %3s", fd, (events & EVENT_IN) ? "RD" : "..", (events & EVENT_OUT) ? "WR" : "..", (events & EVENT_ERR) ? "ERR" : "..."); if (!mono_g_hash_table_lookup_extended (states, GINT_TO_POINTER (fd), &k, (gpointer*) &list)) @@ -293,12 +293,12 @@ wait_callback (gint fd, gint events, gpointer user_data) operations = get_operations_for_jobs (list); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_THREADPOOL, "io threadpool: res fd %3d, events = %2s | %2s | %3s", + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_SELECTOR, "io threadpool: res fd %3d, events = %2s | %2s | %3s", fd, (operations & EVENT_IN) ? "RD" : "..", (operations & EVENT_OUT) ? "WR" : "..", (operations & EVENT_ERR) ? "ERR" : "..."); threadpool_io->backend.register_fd (fd, operations, FALSE); } else { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_THREADPOOL, "io threadpool: err fd %d", fd); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_SELECTOR, "io threadpool: err fd %d", fd); mono_g_hash_table_remove (states, GINT_TO_POINTER (fd)); @@ -319,12 +319,17 @@ selector_thread (gpointer data) MonoError error; MonoGHashTable *states; + MonoString *thread_name = mono_string_new_checked (mono_get_root_domain (), "Thread Pool I/O Selector", &error); + mono_error_assert_ok (&error); + mono_thread_set_name_internal (mono_thread_internal_current (), thread_name, FALSE, TRUE, &error); + mono_error_assert_ok (&error); + if (mono_runtime_is_shutting_down ()) { io_selector_running = FALSE; return 0; } - states = mono_g_hash_table_new_type (g_direct_hash, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_THREAD_POOL, "i/o thread pool states table"); + states = mono_g_hash_table_new_type (g_direct_hash, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_THREAD_POOL, NULL, "Thread Pool I/O State Table"); while (!mono_runtime_is_shutting_down ()) { gint i, j; @@ -363,7 +368,7 @@ selector_thread (gpointer data) operations = get_operations_for_jobs (list); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_THREADPOOL, "io threadpool: %3s fd %3d, operations = %2s | %2s | %3s", + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_SELECTOR, "io threadpool: %3s fd %3d, operations = %2s | %2s | %3s", exists ? "mod" : "add", fd, (operations & EVENT_IN) ? "RD" : "..", (operations & EVENT_OUT) ? "WR" : "..", (operations & EVENT_ERR) ? "ERR" : "..."); threadpool_io->backend.register_fd (fd, operations, !exists); @@ -392,7 +397,7 @@ selector_thread (gpointer data) mono_error_assert_ok (&error); } - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_THREADPOOL, "io threadpool: del fd %3d", fd); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_SELECTOR, "io threadpool: del fd %3d", fd); threadpool_io->backend.remove_fd (fd); } @@ -429,7 +434,7 @@ selector_thread (gpointer data) mono_coop_mutex_unlock (&threadpool_io->updates_lock); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_THREADPOOL, "io threadpool: wai"); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_SELECTOR, "io threadpool: wai"); mono_thread_info_install_interrupt (selector_thread_interrupt, NULL, &interrupted); if (interrupted) @@ -541,7 +546,7 @@ initialize (void) mono_coop_mutex_init (&threadpool_io->updates_lock); mono_coop_cond_init (&threadpool_io->updates_cond); - mono_gc_register_root ((char *)&threadpool_io->updates [0], sizeof (threadpool_io->updates), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_THREAD_POOL, "i/o thread pool updates list"); + mono_gc_register_root ((char *)&threadpool_io->updates [0], sizeof (threadpool_io->updates), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_THREAD_POOL, NULL, "Thread Pool I/O Update List"); threadpool_io->updates_size = 0; diff --git a/mono/metadata/threadpool-worker-wasm.c b/mono/metadata/threadpool-worker-wasm.c new file mode 100644 index 000000000000..8877df96025b --- /dev/null +++ b/mono/metadata/threadpool-worker-wasm.c @@ -0,0 +1,77 @@ +/** + * \file + * native threadpool worker + * + * Author: + * Ludovic Henry (ludovic.henry@xamarin.com) + * + * Licensed under the MIT license. See LICENSE file in the project root for full license information. + */ + +#include +#define _USE_MATH_DEFINES // needed by MSVC to define math constants +#include +#include +#include + +#include +#include + +static MonoThreadPoolWorkerCallback tp_cb; +static gboolean cb_scheduled; + +void +mono_threadpool_worker_init (MonoThreadPoolWorkerCallback callback) +{ + tp_cb = callback; +} + +void +mono_threadpool_worker_cleanup (void) +{ +} + +gint32 +mono_threadpool_worker_get_min (void) +{ + return 1; +} + +gboolean +mono_threadpool_worker_set_min (gint32 value) +{ + return value == 1; +} + +gint32 +mono_threadpool_worker_get_max (void) +{ + return 1; +} + +gboolean +mono_threadpool_worker_set_max (gint32 value) +{ + return value == 1; +} + +static void +fire_tp_callback (void) +{ + cb_scheduled = FALSE; + tp_cb (); +} + +void +mono_threadpool_worker_request (void) +{ + if (!cb_scheduled) + mono_threads_schedule_background_job (fire_tp_callback); + cb_scheduled = TRUE; +} + +gboolean +mono_threadpool_worker_notify_completed (void) +{ + return FALSE; +} diff --git a/mono/metadata/threadpool.c b/mono/metadata/threadpool.c index 696ae83d6ea0..7bf9a28edaf7 100644 --- a/mono/metadata/threadpool.c +++ b/mono/metadata/threadpool.c @@ -350,7 +350,7 @@ worker_callback (void) domains_unlock (); - MonoString *thread_name = mono_string_new_checked (mono_get_root_domain (), "Threadpool worker", &error); + MonoString *thread_name = mono_string_new_checked (mono_get_root_domain (), "Thread Pool Worker", &error); mono_error_assert_ok (&error); mono_thread_set_name_internal (thread, thread_name, FALSE, TRUE, &error); mono_error_assert_ok (&error); @@ -497,13 +497,13 @@ mono_threadpool_end_invoke (MonoAsyncResult *ares, MonoArray **out_args, MonoObj MONO_OBJECT_SETREF (ares, handle, (MonoObject*) wait_handle); } mono_monitor_exit ((MonoObject*) ares); - MONO_ENTER_GC_SAFE; #ifdef HOST_WIN32 + MONO_ENTER_GC_SAFE; mono_win32_wait_for_single_object_ex (wait_event, INFINITE, TRUE); + MONO_EXIT_GC_SAFE; #else mono_w32handle_wait_one (wait_event, MONO_INFINITE_WAIT, TRUE); #endif - MONO_EXIT_GC_SAFE; } ac = (MonoAsyncCall*) ares->object_data; diff --git a/mono/metadata/threads.c b/mono/metadata/threads.c index fc8ec298885b..b2d2bdd66e05 100644 --- a/mono/metadata/threads.c +++ b/mono/metadata/threads.c @@ -38,7 +38,6 @@ #include #include #include -#include #include #include #include @@ -562,7 +561,7 @@ create_internal_thread_object (void) thread->managed_id = get_next_managed_thread_id (); if (mono_gc_is_moving ()) { thread->thread_pinning_ref = thread; - MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref, MONO_ROOT_SOURCE_THREADING, "thread pinning reference"); + MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref, MONO_ROOT_SOURCE_THREADING, NULL, "Thread Pinning Reference"); } thread->priority = MONO_THREAD_PRIORITY_NORMAL; @@ -649,7 +648,7 @@ mono_thread_internal_set_priority (MonoInternalThread *internal, MonoThreadPrior } static void -mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal); +mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, void *alloc_key, gboolean threadlocal); static gboolean mono_thread_attach_internal (MonoThread *thread, gboolean force_attach, gboolean force_domain) @@ -705,7 +704,7 @@ mono_thread_attach_internal (MonoThread *thread, gboolean force_attach, gboolean } if (!threads) { - threads = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "threads table"); + threads = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_THREADING, NULL, "Thread Table"); } /* We don't need to duplicate thread->handle, because it is @@ -717,7 +716,7 @@ mono_thread_attach_internal (MonoThread *thread, gboolean force_attach, gboolean if (thread_static_info.offset || thread_static_info.idx > 0) { /* get the current allocated size */ guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (thread_static_info.idx, thread_static_info.offset, 0); - mono_alloc_static_data (&internal->static_data, offset, TRUE); + mono_alloc_static_data (&internal->static_data, offset, (void *) MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid), TRUE); } mono_threads_unlock (); @@ -743,13 +742,20 @@ mono_thread_attach_internal (MonoThread *thread, gboolean force_attach, gboolean static void mono_thread_detach_internal (MonoInternalThread *thread) { + MonoThreadInfo *info; gboolean removed; + guint32 gchandle; g_assert (thread != NULL); SET_CURRENT_OBJECT (thread); + info = (MonoThreadInfo*) thread->thread_info; + g_assert (info); + THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid)); + MONO_PROFILER_RAISE (thread_stopping, (thread->tid)); + #ifndef HOST_WIN32 mono_w32mutex_abandon (); #endif @@ -770,7 +776,7 @@ mono_thread_detach_internal (MonoInternalThread *thread) * race with runtime shutdown. */ #ifdef HOST_WIN32 - mono_threads_add_joinable_runtime_thread (thread->thread_info); + mono_threads_add_joinable_runtime_thread (info); #endif /* @@ -846,11 +852,9 @@ mono_thread_detach_internal (MonoInternalThread *thread) mono_release_type_locks (thread); - /* Can happen when we attach the profiler helper thread in order to heapshot. */ - if (!mono_thread_info_lookup (MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid))->tools_thread) - MONO_PROFILER_RAISE (thread_stopped, (thread->tid)); - - mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1); + MONO_PROFILER_RAISE (thread_stopped, (thread->tid)); + MONO_PROFILER_RAISE (gc_root_unregister, (info->stack_start_limit)); + MONO_PROFILER_RAISE (gc_root_unregister, (info->handle_stack)); /* * This will signal async signal handlers that the thread has exited. @@ -886,7 +890,14 @@ mono_thread_detach_internal (MonoInternalThread *thread) SET_CURRENT_OBJECT (NULL); mono_domain_unset (); - mono_thread_info_unset_internal_thread_gchandle ((MonoThreadInfo*) thread->thread_info); + if (!mono_thread_info_try_get_internal_thread_gchandle (info, &gchandle)) + g_error ("%s: failed to get gchandle, info = %p", __func__, info); + + mono_gchandle_free (gchandle); + + mono_thread_info_unset_internal_thread_gchandle (info); + + MONO_PROFILER_RAISE (thread_exited, (thread->tid)); /* Don't need to close the handle to this thread, even though we took a * reference in mono_thread_attach (), because the GC will do it @@ -906,6 +917,29 @@ typedef struct { MonoCoopSem registered; } StartInfo; +static void +fire_attach_profiler_events (MonoNativeThreadId tid) +{ + MONO_PROFILER_RAISE (thread_started, ((uintptr_t) tid)); + + MonoThreadInfo *info = mono_thread_info_current (); + + MONO_PROFILER_RAISE (gc_root_register, ( + info->stack_start_limit, + (char *) info->stack_end - (char *) info->stack_start_limit, + MONO_ROOT_SOURCE_STACK, + (void *) tid, + "Thread Stack")); + + // The handle stack is a pseudo-root similar to the finalizer queues. + MONO_PROFILER_RAISE (gc_root_register, ( + info->handle_stack, + 1, + MONO_ROOT_SOURCE_HANDLE, + (void *) tid, + "Handle Stack")); +} + static guint32 WINAPI start_wrapper_internal(StartInfo *start_info, gsize *stack_ptr) { MonoError error; @@ -981,7 +1015,7 @@ static guint32 WINAPI start_wrapper_internal(StartInfo *start_info, gsize *stack * to lock the thread, and the lock is held by thread_start () which waits for * start_notify. */ - MONO_PROFILER_RAISE (thread_started, (tid)); + fire_attach_profiler_events ((MonoNativeThreadId) tid); /* if the name was set before starting, we didn't invoke the profiler callback */ if (internal->name) { @@ -1103,7 +1137,7 @@ create_thread (MonoThread *thread, MonoInternalThread *internal, MonoObject *sta return FALSE; } if (threads_starting_up == NULL) { - threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "starting threads table"); + threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_THREADING, NULL, "Thread Starting Table"); } mono_g_hash_table_insert (threads_starting_up, thread, thread); mono_threads_unlock (); @@ -1277,9 +1311,7 @@ mono_thread_attach_full (MonoDomain *domain, gboolean force_attach) if (mono_thread_attach_cb) mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), info->stack_end); - /* Can happen when we attach the profiler helper thread in order to heapshot. */ - if (!mono_thread_info_current ()->tools_thread) - MONO_PROFILER_RAISE (thread_started, (MONO_NATIVE_THREAD_ID_TO_UINT (tid))); + fire_attach_profiler_events (tid); return thread; } @@ -1913,17 +1945,17 @@ ves_icall_System_Threading_WaitHandle_Wait_internal (gpointer *handles, gint32 n timeoutLeft = timeout; for (;;) { - MONO_ENTER_GC_SAFE; #ifdef HOST_WIN32 + MONO_ENTER_GC_SAFE; if (numhandles != 1) ret = mono_w32handle_convert_wait_ret (mono_win32_wait_for_multiple_objects_ex(numhandles, handles, waitall, timeoutLeft, TRUE), numhandles); else ret = mono_w32handle_convert_wait_ret (mono_win32_wait_for_single_object_ex (handles [0], timeoutLeft, TRUE), 1); + MONO_EXIT_GC_SAFE; #else /* mono_w32handle_wait_multiple optimizes the case for numhandles == 1 */ ret = mono_w32handle_wait_multiple (handles, numhandles, waitall, timeoutLeft, TRUE); #endif /* HOST_WIN32 */ - MONO_EXIT_GC_SAFE; if (ret != MONO_W32HANDLE_WAIT_RET_ALERTED) break; @@ -4065,7 +4097,7 @@ mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data) * Allocate memory blocks for storing threads or context static data */ static void -mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal) +mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, void *alloc_key, gboolean threadlocal) { guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index); int i; @@ -4085,7 +4117,8 @@ mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean thr static_data = (void **)mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc, threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC, - threadlocal ? "managed thread-static variables" : "managed context-static variables"); + alloc_key, + threadlocal ? "ThreadStatic Fields" : "ContextStatic Fields"); *static_data_ptr = static_data; static_data [0] = static_data; } @@ -4099,7 +4132,8 @@ mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean thr else static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL, threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC, - threadlocal ? "managed thread-static variables" : "managed context-static variables"); + alloc_key, + threadlocal ? "ThreadStatic Fields" : "ContextStatic Fields"); } } @@ -4177,7 +4211,7 @@ context_adjust_static_data (MonoAppContext *ctx) { if (context_static_info.offset || context_static_info.idx > 0) { guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0); - mono_alloc_static_data (&ctx->static_data, offset, FALSE); + mono_alloc_static_data (&ctx->static_data, offset, ctx, FALSE); ctx->data->static_data = ctx->static_data; } } @@ -4191,7 +4225,7 @@ alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user) MonoInternalThread *thread = (MonoInternalThread *)value; guint32 offset = GPOINTER_TO_UINT (user); - mono_alloc_static_data (&(thread->static_data), offset, TRUE); + mono_alloc_static_data (&(thread->static_data), offset, (void *) MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid), TRUE); } /* @@ -4206,7 +4240,7 @@ alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user) return; guint32 offset = GPOINTER_TO_UINT (user); - mono_alloc_static_data (&ctx->static_data, offset, FALSE); + mono_alloc_static_data (&ctx->static_data, offset, ctx, FALSE); ctx->data->static_data = ctx->static_data; } @@ -4462,7 +4496,9 @@ mono_thread_execute_interruption (void) /* this will consume pending APC calls */ #ifdef HOST_WIN32 + MONO_ENTER_GC_SAFE; mono_win32_wait_for_single_object_ex (GetCurrentThread (), 0, TRUE); + MONO_EXIT_GC_SAFE; #endif /* Clear the interrupted flag of the thread so it can wait again */ diff --git a/mono/metadata/unity-icall.c b/mono/metadata/unity-icall.c new file mode 100644 index 000000000000..1de9b6be406d --- /dev/null +++ b/mono/metadata/unity-icall.c @@ -0,0 +1,259 @@ +/** + * \file + * Unity icall support for Mono. + * + * Copyright 2016 Unity + * Licensed under the MIT license. See LICENSE file in the project root for full license information. +*/ +#include +#include +#include "mono/utils/mono-compiler.h" +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +/* + * Magic number to convert a time which is relative to + * Jan 1, 1970 into a value which is relative to Jan 1, 0001. + */ +#define EPOCH_ADJUST ((guint64)62135596800LL) + +/* + * Magic number to convert FILETIME base Jan 1, 1601 to DateTime - base Jan, 1, 0001 + */ +#define FILETIME_ADJUST ((guint64)504911232000000000LL) + +#ifdef PLATFORM_WIN32 +/* convert a SYSTEMTIME which is of the form "last thursday in october" to a real date */ +static void +convert_to_absolute_date(SYSTEMTIME *date) +{ +#define IS_LEAP(y) ((y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0)) + static int days_in_month[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + static int leap_days_in_month[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + /* from the calendar FAQ */ + int a = (14 - date->wMonth) / 12; + int y = date->wYear - a; + int m = date->wMonth + 12 * a - 2; + int d = (1 + y + y/4 - y/100 + y/400 + (31*m)/12) % 7; + + /* d is now the day of the week for the first of the month (0 == Sunday) */ + + int day_of_week = date->wDayOfWeek; + + /* set day_in_month to the first day in the month which falls on day_of_week */ + int day_in_month = 1 + (day_of_week - d); + if (day_in_month <= 0) + day_in_month += 7; + + /* wDay is 1 for first weekday in month, 2 for 2nd ... 5 means last - so work that out allowing for days in the month */ + date->wDay = day_in_month + (date->wDay - 1) * 7; + if (date->wDay > (IS_LEAP(date->wYear) ? leap_days_in_month[date->wMonth - 1] : days_in_month[date->wMonth - 1])) + date->wDay -= 7; +} +#endif + +#ifndef PLATFORM_WIN32 +/* + * Return's the offset from GMT of a local time. + * + * tm is a local time + * t is the same local time as seconds. + */ +static int +gmt_offset(struct tm *tm, time_t t) +{ +#if defined (HAVE_TM_GMTOFF) + return tm->tm_gmtoff; +#else + struct tm g; + time_t t2; + g = *gmtime(&t); + g.tm_isdst = tm->tm_isdst; + t2 = mktime(&g); + return (int)difftime(t, t2); +#endif +} +#endif +/* + * This is heavily based on zdump.c from glibc 2.2. + * + * * data[0]: start of daylight saving time (in DateTime ticks). + * * data[1]: end of daylight saving time (in DateTime ticks). + * * data[2]: utcoffset (in TimeSpan ticks). + * * data[3]: additional offset when daylight saving (in TimeSpan ticks). + * * name[0]: name of this timezone when not daylight saving. + * * name[1]: name of this timezone when daylight saving. + * + * FIXME: This only works with "standard" Unix dates (years between 1900 and 2100) while + * the class library allows years between 1 and 9999. + * + * Returns true on success and zero on failure. + */ +guint32 +ves_icall_System_CurrentSystemTimeZone_GetTimeZoneData (guint32 year, MonoArray **data, MonoArray **names) +{ + MonoError error; +#ifndef PLATFORM_WIN32 + MonoDomain *domain = mono_domain_get (); + struct tm start, tt; + time_t t; + + long int gmtoff; + int is_daylight = 0, day; + char tzone [64]; + + MONO_CHECK_ARG_NULL (data, FALSE); + MONO_CHECK_ARG_NULL (names, FALSE); + + mono_gc_wbarrier_generic_store (data, (MonoObject*) mono_array_new_checked (domain, mono_defaults.int64_class, 4, &error)); + mono_gc_wbarrier_generic_store (names, (MonoObject*) mono_array_new_checked (domain, mono_defaults.string_class, 2, &error)); + + /* + * no info is better than crashing: we'll need our own tz data + * to make this work properly, anyway. The range is probably + * reduced to 1970 .. 2037 because that is what mktime is + * guaranteed to support (we get into an infinite loop + * otherwise). + */ + + memset (&start, 0, sizeof (start)); + + start.tm_mday = 1; + start.tm_year = year-1900; + + t = mktime (&start); + + if ((year < 1970) || (year > 2037) || (t == -1)) { + t = time (NULL); + tt = *localtime (&t); + strftime (tzone, sizeof (tzone), "%Z", &tt); + mono_array_setref ((*names), 0, mono_string_new_checked (domain, tzone, &error)); + mono_array_setref ((*names), 1, mono_string_new_checked (domain, tzone, &error)); + return 1; + } + + gmtoff = gmt_offset (&start, t); + + /* For each day of the year, calculate the tm_gmtoff. */ + for (day = 0; day < 365; day++) { + + t += 3600*24; + tt = *localtime (&t); + + /* Daylight saving starts or ends here. */ + if (gmt_offset (&tt, t) != gmtoff) { + struct tm tt1; + time_t t1; + + /* Try to find the exact hour when daylight saving starts/ends. */ + t1 = t; + do { + t1 -= 3600; + tt1 = *localtime (&t1); + } while (gmt_offset (&tt1, t1) != gmtoff); + + /* Try to find the exact minute when daylight saving starts/ends. */ + do { + t1 += 60; + tt1 = *localtime (&t1); + } while (gmt_offset (&tt1, t1) == gmtoff); + t1+=gmtoff; + strftime (tzone, sizeof (tzone), "%Z", &tt); + + /* Write data, if we're already in daylight saving, we're done. */ + if (is_daylight) { + mono_array_setref ((*names), 0, mono_string_new_checked (domain, tzone, &error)); + mono_array_set ((*data), gint64, 1, ((gint64)t1 + EPOCH_ADJUST) * 10000000L); + return 1; + } else { + mono_array_setref ((*names), 1, mono_string_new_checked (domain, tzone, &error)); + mono_array_set ((*data), gint64, 0, ((gint64)t1 + EPOCH_ADJUST) * 10000000L); + is_daylight = 1; + } + + /* This is only set once when we enter daylight saving. */ + mono_array_set ((*data), gint64, 2, (gint64)gmtoff * 10000000L); + mono_array_set ((*data), gint64, 3, (gint64)(gmt_offset (&tt, t) - gmtoff) * 10000000L); + + gmtoff = gmt_offset (&tt, t); + } + } + + if (!is_daylight) { + strftime (tzone, sizeof (tzone), "%Z", &tt); + mono_array_setref ((*names), 0, mono_string_new_checked (domain, tzone, &error)); + mono_array_setref ((*names), 1, mono_string_new_checked (domain, tzone, &error)); + mono_array_set ((*data), gint64, 0, 0); + mono_array_set ((*data), gint64, 1, 0); + mono_array_set ((*data), gint64, 2, (gint64) gmtoff * 10000000L); + mono_array_set ((*data), gint64, 3, 0); + } + + return 1; +#else + MonoDomain *domain = mono_domain_get (); + TIME_ZONE_INFORMATION tz_info; + FILETIME ft; + int i; + int err, tz_id; + + tz_id = GetTimeZoneInformation (&tz_info); + if (tz_id == TIME_ZONE_ID_INVALID) + return 0; + + MONO_CHECK_ARG_NULL (data); + MONO_CHECK_ARG_NULL (names); + + mono_gc_wbarrier_generic_store (data, mono_array_new (domain, mono_defaults.int64_class, 4)); + mono_gc_wbarrier_generic_store (names, mono_array_new (domain, mono_defaults.string_class, 2)); + + for (i = 0; i < 32; ++i) + if (!tz_info.DaylightName [i]) + break; + mono_array_setref ((*names), 1, mono_string_new_utf16 (domain, tz_info.DaylightName, i)); + for (i = 0; i < 32; ++i) + if (!tz_info.StandardName [i]) + break; + mono_array_setref ((*names), 0, mono_string_new_utf16 (domain, tz_info.StandardName, i)); + + if ((year <= 1601) || (year > 30827)) { + /* + * According to MSDN, the MS time functions can't handle dates outside + * this interval. + */ + return 1; + } + + /* even if the timezone has no daylight savings it may have Bias (e.g. GMT+13 it seems) */ + if (tz_id != TIME_ZONE_ID_UNKNOWN) { + tz_info.StandardDate.wYear = year; + convert_to_absolute_date(&tz_info.StandardDate); + err = SystemTimeToFileTime (&tz_info.StandardDate, &ft); + //g_assert(err); + if (err == 0) + return 0; + + mono_array_set ((*data), gint64, 1, FILETIME_ADJUST + (((guint64)ft.dwHighDateTime<<32) | ft.dwLowDateTime)); + tz_info.DaylightDate.wYear = year; + convert_to_absolute_date(&tz_info.DaylightDate); + err = SystemTimeToFileTime (&tz_info.DaylightDate, &ft); + //g_assert(err); + if (err == 0) + return 0; + + mono_array_set ((*data), gint64, 0, FILETIME_ADJUST + (((guint64)ft.dwHighDateTime<<32) | ft.dwLowDateTime)); + } + mono_array_set ((*data), gint64, 2, (tz_info.Bias + tz_info.StandardBias) * -600000000LL); + mono_array_set ((*data), gint64, 3, (tz_info.DaylightBias - tz_info.StandardBias) * -600000000LL); + + return 1; +#endif +} diff --git a/mono/metadata/w32event-unix.c b/mono/metadata/w32event-unix.c index 37ec577a6b02..93c595abf211 100644 --- a/mono/metadata/w32event-unix.c +++ b/mono/metadata/w32event-unix.c @@ -36,78 +36,55 @@ struct MonoW32HandleNamedEvent { MonoW32HandleNamespace sharedns; }; -static void event_handle_signal (gpointer handle, MonoW32HandleType type, MonoW32HandleEvent *event_handle) +static void event_handle_signal (MonoW32Handle *handle_data) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: signalling %s handle %p", - __func__, mono_w32handle_get_typename (type), handle); + MonoW32HandleEvent *event_handle; + + event_handle = (MonoW32HandleEvent*) handle_data->specific; + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_EVENT, "%s: signalling %s handle %p", + __func__, mono_w32handle_get_typename (handle_data->type), handle_data); if (!event_handle->manual) { event_handle->set_count = 1; - mono_w32handle_set_signal_state (handle, TRUE, FALSE); + mono_w32handle_set_signal_state (handle_data, TRUE, FALSE); } else { - mono_w32handle_set_signal_state (handle, TRUE, TRUE); + mono_w32handle_set_signal_state (handle_data, TRUE, TRUE); } } -static gboolean event_handle_own (gpointer handle, MonoW32HandleType type, gboolean *abandoned) +static gboolean event_handle_own (MonoW32Handle *handle_data, gboolean *abandoned) { MonoW32HandleEvent *event_handle; - gboolean ok; *abandoned = FALSE; - ok = mono_w32handle_lookup (handle, type, (gpointer *)&event_handle); - if (!ok) { - g_warning ("%s: error looking up %s handle %p", - __func__, mono_w32handle_get_typename (type), handle); - return FALSE; - } + event_handle = (MonoW32HandleEvent*) handle_data->specific; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: owning %s handle %p", - __func__, mono_w32handle_get_typename (type), handle); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_EVENT, "%s: owning %s handle %p", + __func__, mono_w32handle_get_typename (handle_data->type), handle_data); if (!event_handle->manual) { g_assert (event_handle->set_count > 0); event_handle->set_count --; if (event_handle->set_count == 0) - mono_w32handle_set_signal_state (handle, FALSE, FALSE); + mono_w32handle_set_signal_state (handle_data, FALSE, FALSE); } return TRUE; } -static void event_signal(gpointer handle, gpointer handle_specific) -{ - event_handle_signal (handle, MONO_W32HANDLE_EVENT, (MonoW32HandleEvent*) handle_specific); -} - -static gboolean event_own (gpointer handle, gboolean *abandoned) -{ - return event_handle_own (handle, MONO_W32HANDLE_EVENT, abandoned); -} - -static void namedevent_signal (gpointer handle, gpointer handle_specific) -{ - event_handle_signal (handle, MONO_W32HANDLE_NAMEDEVENT, (MonoW32HandleEvent*) handle_specific); -} - -/* NB, always called with the shared handle lock held */ -static gboolean namedevent_own (gpointer handle, gboolean *abandoned) -{ - return event_handle_own (handle, MONO_W32HANDLE_NAMEDEVENT, abandoned); -} - -static void event_details (gpointer data) +static void event_details (MonoW32Handle *handle_data) { - MonoW32HandleEvent *event = (MonoW32HandleEvent *)data; + MonoW32HandleEvent *event = (MonoW32HandleEvent *)handle_data->specific; g_print ("manual: %s, set_count: %d", event->manual ? "TRUE" : "FALSE", event->set_count); } -static void namedevent_details (gpointer data) +static void namedevent_details (MonoW32Handle *handle_data) { - MonoW32HandleNamedEvent *namedevent = (MonoW32HandleNamedEvent *)data; + MonoW32HandleNamedEvent *namedevent = (MonoW32HandleNamedEvent *)handle_data->specific; g_print ("manual: %s, set_count: %d, name: \"%s\"", namedevent->e.manual ? "TRUE" : "FALSE", namedevent->e.set_count, namedevent->sharedns.name); } @@ -137,8 +114,8 @@ mono_w32event_init (void) { static MonoW32HandleOps event_ops = { NULL, /* close */ - event_signal, /* signal */ - event_own, /* own */ + event_handle_signal, /* signal */ + event_handle_own, /* own */ NULL, /* is_owned */ NULL, /* special_wait */ NULL, /* prewait */ @@ -149,8 +126,8 @@ mono_w32event_init (void) static MonoW32HandleOps namedevent_ops = { NULL, /* close */ - namedevent_signal, /* signal */ - namedevent_own, /* own */ + event_handle_signal, /* signal */ + event_handle_own, /* own */ NULL, /* is_owned */ NULL, /* special_wait */ NULL, /* prewait */ @@ -159,12 +136,12 @@ mono_w32event_init (void) namedevent_typesize, /* typesize */ }; - mono_w32handle_register_ops (MONO_W32HANDLE_EVENT, &event_ops); - mono_w32handle_register_ops (MONO_W32HANDLE_NAMEDEVENT, &namedevent_ops); + mono_w32handle_register_ops (MONO_W32TYPE_EVENT, &event_ops); + mono_w32handle_register_ops (MONO_W32TYPE_NAMEDEVENT, &namedevent_ops); - mono_w32handle_register_capabilities (MONO_W32HANDLE_EVENT, + mono_w32handle_register_capabilities (MONO_W32TYPE_EVENT, (MonoW32HandleCapability)(MONO_W32HANDLE_CAP_WAIT | MONO_W32HANDLE_CAP_SIGNAL)); - mono_w32handle_register_capabilities (MONO_W32HANDLE_NAMEDEVENT, + mono_w32handle_register_capabilities (MONO_W32TYPE_NAMEDEVENT, (MonoW32HandleCapability)(MONO_W32HANDLE_CAP_WAIT | MONO_W32HANDLE_CAP_SIGNAL)); } @@ -199,8 +176,9 @@ mono_w32event_reset (gpointer handle) ves_icall_System_Threading_Events_ResetEvent_internal (handle); } -static gpointer event_handle_create (MonoW32HandleEvent *event_handle, MonoW32HandleType type, gboolean manual, gboolean initial) +static gpointer event_handle_create (MonoW32HandleEvent *event_handle, MonoW32Type type, gboolean manual, gboolean initial) { + MonoW32Handle *handle_data; gpointer handle; event_handle->manual = manual; @@ -214,40 +192,48 @@ static gpointer event_handle_create (MonoW32HandleEvent *event_handle, MonoW32Ha return NULL; } - mono_w32handle_lock_handle (handle); + if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) + g_error ("%s: unkown handle %p", __func__, handle); + + if (handle_data->type != type) + g_error ("%s: unknown event handle %p", __func__, handle); + + mono_w32handle_lock (handle_data); if (initial) - mono_w32handle_set_signal_state (handle, TRUE, FALSE); + mono_w32handle_set_signal_state (handle_data, TRUE, FALSE); - mono_w32handle_unlock_handle (handle); + mono_w32handle_unlock (handle_data); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: created %s handle %p", + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_EVENT, "%s: created %s handle %p", __func__, mono_w32handle_get_typename (type), handle); + mono_w32handle_unref (handle_data); + return handle; } static gpointer event_create (gboolean manual, gboolean initial) { MonoW32HandleEvent event_handle; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: creating %s handle", - __func__, mono_w32handle_get_typename (MONO_W32HANDLE_EVENT)); - return event_handle_create (&event_handle, MONO_W32HANDLE_EVENT, manual, initial); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_EVENT, "%s: creating %s handle", + __func__, mono_w32handle_get_typename (MONO_W32TYPE_EVENT)); + return event_handle_create (&event_handle, MONO_W32TYPE_EVENT, manual, initial); } static gpointer namedevent_create (gboolean manual, gboolean initial, const gchar *utf8_name G_GNUC_UNUSED) { gpointer handle; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: creating %s handle", - __func__, mono_w32handle_get_typename (MONO_W32HANDLE_NAMEDEVENT)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_EVENT, "%s: creating %s handle", + __func__, mono_w32handle_get_typename (MONO_W32TYPE_NAMEDEVENT)); /* w32 seems to guarantee that opening named objects can't race each other */ mono_w32handle_namespace_lock (); glong utf8_len = strlen (utf8_name); - handle = mono_w32handle_namespace_search_handle (MONO_W32HANDLE_NAMEDEVENT, utf8_name); + handle = mono_w32handle_namespace_search_handle (MONO_W32TYPE_NAMEDEVENT, utf8_name); if (handle == INVALID_HANDLE_VALUE) { /* The name has already been used for a different object. */ handle = NULL; @@ -265,7 +251,7 @@ static gpointer namedevent_create (gboolean manual, gboolean initial, const gcha memcpy (&namedevent_handle.sharedns.name [0], utf8_name, len); namedevent_handle.sharedns.name [len] = '\0'; - handle = event_handle_create ((MonoW32HandleEvent*) &namedevent_handle, MONO_W32HANDLE_NAMEDEVENT, manual, initial); + handle = event_handle_create ((MonoW32HandleEvent*) &namedevent_handle, MONO_W32TYPE_NAMEDEVENT, manual, initial); } mono_w32handle_namespace_unlock (); @@ -304,93 +290,85 @@ ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, Mono gboolean ves_icall_System_Threading_Events_SetEvent_internal (gpointer handle) { - MonoW32HandleType type; + MonoW32Handle *handle_data; MonoW32HandleEvent *event_handle; - if (handle == NULL) { + if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) { + g_warning ("%s: unkown handle %p", __func__, handle); mono_w32error_set_last (ERROR_INVALID_HANDLE); - return(FALSE); + return FALSE; } - switch (type = mono_w32handle_get_type (handle)) { - case MONO_W32HANDLE_EVENT: - case MONO_W32HANDLE_NAMEDEVENT: - break; - default: + if (handle_data->type != MONO_W32TYPE_EVENT && handle_data->type != MONO_W32TYPE_NAMEDEVENT) { + g_warning ("%s: unkown event handle %p", __func__, handle); mono_w32error_set_last (ERROR_INVALID_HANDLE); + mono_w32handle_unref (handle_data); return FALSE; } - if (!mono_w32handle_lookup (handle, type, (gpointer *)&event_handle)) { - g_warning ("%s: error looking up %s handle %p", - __func__, mono_w32handle_get_typename (type), handle); - return FALSE; - } + event_handle = (MonoW32HandleEvent*) handle_data->specific; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: setting %s handle %p", - __func__, mono_w32handle_get_typename (type), handle); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_EVENT, "%s: setting %s handle %p", + __func__, mono_w32handle_get_typename (handle_data->type), handle); - mono_w32handle_lock_handle (handle); + mono_w32handle_lock (handle_data); if (!event_handle->manual) { event_handle->set_count = 1; - mono_w32handle_set_signal_state (handle, TRUE, FALSE); + mono_w32handle_set_signal_state (handle_data, TRUE, FALSE); } else { - mono_w32handle_set_signal_state (handle, TRUE, TRUE); + mono_w32handle_set_signal_state (handle_data, TRUE, TRUE); } - mono_w32handle_unlock_handle (handle); + mono_w32handle_unlock (handle_data); + mono_w32handle_unref (handle_data); return TRUE; } gboolean ves_icall_System_Threading_Events_ResetEvent_internal (gpointer handle) { - MonoW32HandleType type; + MonoW32Handle *handle_data; MonoW32HandleEvent *event_handle; mono_w32error_set_last (ERROR_SUCCESS); - if (handle == NULL) { + if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) { + g_warning ("%s: unkown handle %p", __func__, handle); mono_w32error_set_last (ERROR_INVALID_HANDLE); - return(FALSE); + return FALSE; } - switch (type = mono_w32handle_get_type (handle)) { - case MONO_W32HANDLE_EVENT: - case MONO_W32HANDLE_NAMEDEVENT: - break; - default: + if (handle_data->type != MONO_W32TYPE_EVENT && handle_data->type != MONO_W32TYPE_NAMEDEVENT) { + g_warning ("%s: unkown event handle %p", __func__, handle); mono_w32error_set_last (ERROR_INVALID_HANDLE); + mono_w32handle_unref (handle_data); return FALSE; } - if (!mono_w32handle_lookup (handle, type, (gpointer *)&event_handle)) { - g_warning ("%s: error looking up %s handle %p", - __func__, mono_w32handle_get_typename (type), handle); - return FALSE; - } + event_handle = (MonoW32HandleEvent*) handle_data->specific; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: resetting %s handle %p", - __func__, mono_w32handle_get_typename (type), handle); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_EVENT, "%s: resetting %s handle %p", + __func__, mono_w32handle_get_typename (handle_data->type), handle); - mono_w32handle_lock_handle (handle); + mono_w32handle_lock (handle_data); - if (!mono_w32handle_issignalled (handle)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: no need to reset %s handle %p", - __func__, mono_w32handle_get_typename (type), handle); + if (!mono_w32handle_issignalled (handle_data)) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_EVENT, "%s: no need to reset %s handle %p", + __func__, mono_w32handle_get_typename (handle_data->type), handle); } else { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: obtained write lock on %s handle %p", - __func__, mono_w32handle_get_typename (type), handle); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_EVENT, "%s: obtained write lock on %s handle %p", + __func__, mono_w32handle_get_typename (handle_data->type), handle); - mono_w32handle_set_signal_state (handle, FALSE, FALSE); + mono_w32handle_set_signal_state (handle_data, FALSE, FALSE); } event_handle->set_count = 0; - mono_w32handle_unlock_handle (handle); + mono_w32handle_unlock (handle_data); + mono_w32handle_unref (handle_data); return TRUE; } @@ -420,9 +398,9 @@ mono_w32event_open (const gchar *utf8_name, gint32 rights G_GNUC_UNUSED, gint32 /* w32 seems to guarantee that opening named objects can't race each other */ mono_w32handle_namespace_lock (); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Opening named event [%s]", __func__, utf8_name); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_EVENT, "%s: Opening named event [%s]", __func__, utf8_name); - handle = mono_w32handle_namespace_search_handle (MONO_W32HANDLE_NAMEDEVENT, utf8_name); + handle = mono_w32handle_namespace_search_handle (MONO_W32TYPE_NAMEDEVENT, utf8_name); if (handle == INVALID_HANDLE_VALUE) { /* The name has already been used for a different object. */ *error = ERROR_INVALID_HANDLE; @@ -433,7 +411,7 @@ mono_w32event_open (const gchar *utf8_name, gint32 rights G_GNUC_UNUSED, gint32 goto cleanup; } - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning named event handle %p", __func__, handle); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_EVENT, "%s: returning named event handle %p", __func__, handle); cleanup: mono_w32handle_namespace_unlock (); diff --git a/mono/metadata/w32file-unix.c b/mono/metadata/w32file-unix.c index 31927b5f5229..94d9b547da3a 100644 --- a/mono/metadata/w32file-unix.c +++ b/mono/metadata/w32file-unix.c @@ -38,7 +38,6 @@ #include "w32file-internals.h" #include "w32file-unix-glob.h" -#include "w32handle.h" #include "w32error.h" #include "fdhandle.h" #include "utils/mono-io-portability.h" @@ -47,6 +46,9 @@ #include "utils/mono-threads.h" #include "utils/mono-threads-api.h" #include "utils/strenc.h" +#include "utils/refcount.h" + +#define INVALID_HANDLE_VALUE (GINT_TO_POINTER (-1)) typedef struct { guint64 device; @@ -70,11 +72,13 @@ typedef struct { } FileHandle; typedef struct { + MonoRefCount ref; + MonoCoopMutex mutex; gchar **namelist; gchar *dir_part; gint num; gsize count; -} MonoW32HandleFind; +} FindHandle; /* * If SHM is disabled, this will point to a hash of FileShare structures, otherwise @@ -84,6 +88,9 @@ typedef struct { static GHashTable *file_share_table; static MonoCoopMutex file_share_mutex; +static GHashTable *finds; +static MonoCoopMutex finds_mutex; + static void time_t_to_filetime (time_t timeval, FILETIME *filetime) { @@ -119,7 +126,7 @@ file_data_close (MonoFDHandle *fdhandle) filehandle = (FileHandle*) fdhandle; g_assert (filehandle); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: closing fd %d", __func__, ((MonoFDHandle*) filehandle)->fd); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: closing fd %d", __func__, ((MonoFDHandle*) filehandle)->fd); if (((MonoFDHandle*) filehandle)->type == MONO_FDTYPE_FILE && (filehandle->attrs & FILE_FLAG_DELETE_ON_CLOSE)) { _wapi_unlink (filehandle->filename); @@ -798,7 +805,7 @@ _wapi_lock_file_region (gint fd, off_t offset, off_t length) ret = fcntl (fd, F_SETLK, &lock_data); } while(ret == -1 && errno == EINTR); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fcntl returns %d", __func__, ret); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fcntl returns %d", __func__, ret); if (ret == -1) { /* @@ -838,7 +845,7 @@ _wapi_unlock_file_region (gint fd, off_t offset, off_t length) ret = fcntl (fd, F_SETLK, &lock_data); } while(ret == -1 && errno == EINTR); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fcntl returns %d", __func__, ret); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fcntl returns %d", __func__, ret); if (ret == -1) { /* @@ -863,28 +870,6 @@ _wapi_unlock_file_region (gint fd, off_t offset, off_t length) return TRUE; } -static const gchar* find_typename (void) -{ - return "Find"; -} - -static gsize find_typesize (void) -{ - return sizeof (MonoW32HandleFind); -} - -static MonoW32HandleOps _wapi_find_ops = { - NULL, /* close */ - NULL, /* signal */ - NULL, /* own */ - NULL, /* is_owned */ - NULL, /* special_wait */ - NULL, /* prewait */ - NULL, /* details */ - find_typename, /* typename */ - find_typesize, /* typesize */ -}; - static gboolean lock_while_writing = FALSE; /* Some utility functions. @@ -1029,7 +1014,7 @@ file_read(FileHandle *filehandle, gpointer buffer, guint32 numbytes, guint32 *by } if(!(filehandle->fileaccess & (GENERIC_READ | GENERIC_ALL))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fd %d doesn't have GENERIC_READ access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_READ access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); mono_w32error_set_last (ERROR_ACCESS_DENIED); return(FALSE); @@ -1045,7 +1030,7 @@ file_read(FileHandle *filehandle, gpointer buffer, guint32 numbytes, guint32 *by if(ret==-1) { gint err = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: read of fd %d error: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(err)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: read of fd %d error: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(err)); mono_w32error_set_last (mono_w32error_unix_to_win32 (err)); return(FALSE); } @@ -1069,7 +1054,7 @@ file_write(FileHandle *filehandle, gconstpointer buffer, guint32 numbytes, guint } if(!(filehandle->fileaccess & GENERIC_WRITE) && !(filehandle->fileaccess & GENERIC_ALL)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fd %d doesn't have GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); mono_w32error_set_last (ERROR_ACCESS_DENIED); return(FALSE); @@ -1084,7 +1069,7 @@ file_write(FileHandle *filehandle, gconstpointer buffer, guint32 numbytes, guint current_pos = lseek (((MonoFDHandle*) filehandle)->fd, (off_t)0, SEEK_CUR); MONO_EXIT_GC_SAFE; if (current_pos == -1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fd %d lseek failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror (errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d lseek failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror (errno)); _wapi_set_last_error_from_errno (); return(FALSE); } @@ -1112,7 +1097,7 @@ file_write(FileHandle *filehandle, gconstpointer buffer, guint32 numbytes, guint } else { _wapi_set_last_error_from_errno (); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: write of fd %d error: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: write of fd %d error: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); return(FALSE); } @@ -1128,7 +1113,7 @@ static gboolean file_flush(FileHandle *filehandle) gint ret; if(!(filehandle->fileaccess & (GENERIC_WRITE | GENERIC_ALL))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fd %d doesn't have GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); mono_w32error_set_last (ERROR_ACCESS_DENIED); return(FALSE); @@ -1138,7 +1123,7 @@ static gboolean file_flush(FileHandle *filehandle) ret=fsync(((MonoFDHandle*) filehandle)->fd); MONO_EXIT_GC_SAFE; if (ret==-1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fsync of fd %d error: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fsync of fd %d error: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); _wapi_set_last_error_from_errno (); return(FALSE); @@ -1155,7 +1140,7 @@ static guint32 file_seek(FileHandle *filehandle, gint32 movedistance, guint32 ret; if(!(filehandle->fileaccess & (GENERIC_READ | GENERIC_WRITE | GENERIC_ALL))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fd %d doesn't have GENERIC_READ or GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_READ or GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); mono_w32error_set_last (ERROR_ACCESS_DENIED); return(INVALID_SET_FILE_POINTER); @@ -1172,7 +1157,7 @@ static guint32 file_seek(FileHandle *filehandle, gint32 movedistance, whence=SEEK_END; break; default: - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: invalid seek type %d", __func__, method); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: invalid seek type %d", __func__, method); mono_w32error_set_last (ERROR_INVALID_PARAMETER); return(INVALID_SET_FILE_POINTER); @@ -1181,19 +1166,19 @@ static guint32 file_seek(FileHandle *filehandle, gint32 movedistance, #ifdef HAVE_LARGE_FILE_SUPPORT if(highmovedistance==NULL) { offset=movedistance; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: setting offset to %" G_GINT64_FORMAT " (low %" G_GINT32_FORMAT ")", __func__, + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: setting offset to %" G_GINT64_FORMAT " (low %" G_GINT32_FORMAT ")", __func__, offset, movedistance); } else { offset=((gint64) *highmovedistance << 32) | (guint32)movedistance; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: setting offset to %" G_GINT64_FORMAT " 0x%" PRIx64 " (high %" G_GINT32_FORMAT " 0x%" PRIx32 ", low %" G_GINT32_FORMAT " 0x%" PRIx32 ")", + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: setting offset to %" G_GINT64_FORMAT " 0x%" PRIx64 " (high %" G_GINT32_FORMAT " 0x%" PRIx32 ", low %" G_GINT32_FORMAT " 0x%" PRIx32 ")", __func__, offset, offset, *highmovedistance, *highmovedistance, movedistance, movedistance); } #else offset=movedistance; #endif - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: moving fd %d by %" G_GINT64_FORMAT " bytes from %d", __func__, ((MonoFDHandle*) filehandle)->fd, offset, whence); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: moving fd %d by %" G_GINT64_FORMAT " bytes from %d", __func__, ((MonoFDHandle*) filehandle)->fd, offset, whence); #ifdef HOST_ANDROID /* bionic doesn't support -D_FILE_OFFSET_BITS=64 */ @@ -1206,13 +1191,13 @@ static guint32 file_seek(FileHandle *filehandle, gint32 movedistance, MONO_EXIT_GC_SAFE; #endif if(newpos==-1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: lseek on fd %d returned error %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: lseek on fd %d returned error %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); _wapi_set_last_error_from_errno (); return(INVALID_SET_FILE_POINTER); } - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: lseek returns %" G_GINT64_FORMAT, __func__, newpos); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: lseek returns %" G_GINT64_FORMAT, __func__, newpos); #ifdef HAVE_LARGE_FILE_SUPPORT ret=newpos & 0xFFFFFFFF; @@ -1227,7 +1212,7 @@ static guint32 file_seek(FileHandle *filehandle, gint32 movedistance, } #endif - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: move of fd %d returning %" G_GUINT32_FORMAT "/%" G_GINT32_FORMAT, __func__, ((MonoFDHandle*) filehandle)->fd, ret, highmovedistance==NULL?0:*highmovedistance); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: move of fd %d returning %" G_GUINT32_FORMAT "/%" G_GINT32_FORMAT, __func__, ((MonoFDHandle*) filehandle)->fd, ret, highmovedistance==NULL?0:*highmovedistance); return(ret); } @@ -1240,7 +1225,7 @@ static gboolean file_setendoffile(FileHandle *filehandle) MonoThreadInfo *info = mono_thread_info_current (); if(!(filehandle->fileaccess & (GENERIC_WRITE | GENERIC_ALL))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fd %d doesn't have GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); mono_w32error_set_last (ERROR_ACCESS_DENIED); return(FALSE); @@ -1256,7 +1241,7 @@ static gboolean file_setendoffile(FileHandle *filehandle) ret=fstat(((MonoFDHandle*) filehandle)->fd, &statbuf); MONO_EXIT_GC_SAFE; if(ret==-1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fd %d fstat failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d fstat failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); _wapi_set_last_error_from_errno (); return(FALSE); @@ -1266,7 +1251,7 @@ static gboolean file_setendoffile(FileHandle *filehandle) pos=lseek(((MonoFDHandle*) filehandle)->fd, (off_t)0, SEEK_CUR); MONO_EXIT_GC_SAFE; if(pos==-1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fd %d lseek failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d lseek failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); _wapi_set_last_error_from_errno (); return(FALSE); @@ -1294,7 +1279,7 @@ static gboolean file_setendoffile(FileHandle *filehandle) !mono_thread_info_is_interrupt_state (info)); if(ret==-1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fd %d extend write failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d extend write failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); _wapi_set_last_error_from_errno (); return(FALSE); @@ -1305,7 +1290,7 @@ static gboolean file_setendoffile(FileHandle *filehandle) ret = lseek (((MonoFDHandle*) filehandle)->fd, pos, SEEK_SET); MONO_EXIT_GC_SAFE; if (ret == -1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fd %d second lseek failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d second lseek failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); _wapi_set_last_error_from_errno (); return(FALSE); @@ -1323,7 +1308,7 @@ static gboolean file_setendoffile(FileHandle *filehandle) } while (ret==-1 && errno==EINTR && !mono_thread_info_is_interrupt_state (info)); if(ret==-1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fd %d ftruncate failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d ftruncate failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); _wapi_set_last_error_from_errno (); return(FALSE); @@ -1339,7 +1324,7 @@ static guint32 file_getfilesize(FileHandle *filehandle, guint32 *highsize) gint ret; if(!(filehandle->fileaccess & (GENERIC_READ | GENERIC_WRITE | GENERIC_ALL))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fd %d doesn't have GENERIC_READ or GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_READ or GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); mono_w32error_set_last (ERROR_ACCESS_DENIED); return(INVALID_FILE_SIZE); @@ -1355,7 +1340,7 @@ static guint32 file_getfilesize(FileHandle *filehandle, guint32 *highsize) ret = fstat(((MonoFDHandle*) filehandle)->fd, &statbuf); MONO_EXIT_GC_SAFE; if (ret == -1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fd %d fstat failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d fstat failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); _wapi_set_last_error_from_errno (); return(INVALID_FILE_SIZE); @@ -1370,7 +1355,7 @@ static guint32 file_getfilesize(FileHandle *filehandle, guint32 *highsize) res = ioctl (((MonoFDHandle*) filehandle)->fd, BLKGETSIZE64, &bigsize); MONO_EXIT_GC_SAFE; if (res < 0) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fd %d ioctl BLKGETSIZE64 failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d ioctl BLKGETSIZE64 failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); _wapi_set_last_error_from_errno (); return(INVALID_FILE_SIZE); @@ -1381,7 +1366,7 @@ static guint32 file_getfilesize(FileHandle *filehandle, guint32 *highsize) *highsize = bigsize>>32; } - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Returning block device size %" G_GUINT32_FORMAT "/%" G_GUINT32_FORMAT, + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Returning block device size %" G_GUINT32_FORMAT "/%" G_GUINT32_FORMAT, __func__, size, *highsize); return(size); @@ -1401,7 +1386,7 @@ static guint32 file_getfilesize(FileHandle *filehandle, guint32 *highsize) size = statbuf.st_size; #endif - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Returning size %" G_GUINT32_FORMAT "/%" G_GUINT32_FORMAT, __func__, size, *highsize); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Returning size %" G_GUINT32_FORMAT "/%" G_GUINT32_FORMAT, __func__, size, *highsize); return(size); } @@ -1415,7 +1400,7 @@ static gboolean file_getfiletime(FileHandle *filehandle, FILETIME *create_time, gint ret; if(!(filehandle->fileaccess & (GENERIC_READ | GENERIC_ALL))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fd %d doesn't have GENERIC_READ access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_READ access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); mono_w32error_set_last (ERROR_ACCESS_DENIED); return(FALSE); @@ -1425,13 +1410,13 @@ static gboolean file_getfiletime(FileHandle *filehandle, FILETIME *create_time, ret=fstat(((MonoFDHandle*) filehandle)->fd, &statbuf); MONO_EXIT_GC_SAFE; if(ret==-1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fd %d fstat failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d fstat failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); _wapi_set_last_error_from_errno (); return(FALSE); } - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: atime: %ld ctime: %ld mtime: %ld", __func__, + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: atime: %ld ctime: %ld mtime: %ld", __func__, statbuf.st_atime, statbuf.st_ctime, statbuf.st_mtime); @@ -1452,7 +1437,7 @@ static gboolean file_getfiletime(FileHandle *filehandle, FILETIME *create_time, access_ticks=((guint64)statbuf.st_atime*10000000)+116444736000000000ULL; write_ticks=((guint64)statbuf.st_mtime*10000000)+116444736000000000ULL; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: aticks: %" G_GUINT64_FORMAT " cticks: %" G_GUINT64_FORMAT " wticks: %" G_GUINT64_FORMAT, __func__, + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: aticks: %" G_GUINT64_FORMAT " cticks: %" G_GUINT64_FORMAT " wticks: %" G_GUINT64_FORMAT, __func__, access_ticks, create_ticks, write_ticks); if(create_time!=NULL) { @@ -1485,14 +1470,14 @@ static gboolean file_setfiletime(FileHandle *filehandle, if(!(filehandle->fileaccess & (GENERIC_WRITE | GENERIC_ALL))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fd %d doesn't have GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); mono_w32error_set_last (ERROR_ACCESS_DENIED); return(FALSE); } if(filehandle->filename == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fd %d unknown filename", __func__, ((MonoFDHandle*) filehandle)->fd); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d unknown filename", __func__, ((MonoFDHandle*) filehandle)->fd); mono_w32error_set_last (ERROR_INVALID_HANDLE); return(FALSE); @@ -1505,7 +1490,7 @@ static gboolean file_setfiletime(FileHandle *filehandle, ret=fstat (((MonoFDHandle*) filehandle)->fd, &statbuf); MONO_EXIT_GC_SAFE; if(ret==-1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fd %d fstat failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d fstat failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); mono_w32error_set_last (ERROR_INVALID_PARAMETER); return(FALSE); @@ -1518,14 +1503,14 @@ static gboolean file_setfiletime(FileHandle *filehandle, * but this will do for now. */ if (access_ticks < 116444736000000000ULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: attempt to set access time too early", + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: attempt to set access time too early", __func__); mono_w32error_set_last (ERROR_INVALID_PARAMETER); return(FALSE); } if (sizeof (utbuf.actime) == 4 && ((access_ticks - 116444736000000000ULL) / 10000000) > INT_MAX) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: attempt to set write time that is too big for a 32bits time_t", + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: attempt to set write time that is too big for a 32bits time_t", __func__); mono_w32error_set_last (ERROR_INVALID_PARAMETER); return(FALSE); @@ -1543,13 +1528,13 @@ static gboolean file_setfiletime(FileHandle *filehandle, * but this will do for now. */ if (write_ticks < 116444736000000000ULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: attempt to set write time too early", + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: attempt to set write time too early", __func__); mono_w32error_set_last (ERROR_INVALID_PARAMETER); return(FALSE); } if (sizeof (utbuf.modtime) == 4 && ((write_ticks - 116444736000000000ULL) / 10000000) > INT_MAX) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: attempt to set write time that is too big for a 32bits time_t", + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: attempt to set write time that is too big for a 32bits time_t", __func__); mono_w32error_set_last (ERROR_INVALID_PARAMETER); return(FALSE); @@ -1560,12 +1545,12 @@ static gboolean file_setfiletime(FileHandle *filehandle, utbuf.modtime=statbuf.st_mtime; } - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: setting fd %d access %ld write %ld", __func__, + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: setting fd %d access %ld write %ld", __func__, ((MonoFDHandle*) filehandle)->fd, utbuf.actime, utbuf.modtime); ret = _wapi_utime (filehandle->filename, &utbuf); if (ret == -1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fd %d [%s] utime failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->filename, g_strerror(errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d [%s] utime failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->filename, g_strerror(errno)); mono_w32error_set_last (ERROR_INVALID_PARAMETER); return(FALSE); @@ -1585,7 +1570,7 @@ console_read(FileHandle *filehandle, gpointer buffer, guint32 numbytes, guint32 } if(!(filehandle->fileaccess & (GENERIC_READ | GENERIC_ALL))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fd %d doesn't have GENERIC_READ access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_READ access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); mono_w32error_set_last (ERROR_ACCESS_DENIED); return(FALSE); @@ -1598,7 +1583,7 @@ console_read(FileHandle *filehandle, gpointer buffer, guint32 numbytes, guint32 } while (ret==-1 && errno==EINTR && !mono_thread_info_is_interrupt_state (info)); if(ret==-1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: read of fd %d error: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: read of fd %d error: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); _wapi_set_last_error_from_errno (); return(FALSE); @@ -1622,7 +1607,7 @@ console_write(FileHandle *filehandle, gconstpointer buffer, guint32 numbytes, gu } if(!(filehandle->fileaccess & (GENERIC_WRITE | GENERIC_ALL))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fd %d doesn't have GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); mono_w32error_set_last (ERROR_ACCESS_DENIED); return(FALSE); @@ -1641,7 +1626,7 @@ console_write(FileHandle *filehandle, gconstpointer buffer, guint32 numbytes, gu } else { _wapi_set_last_error_from_errno (); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: write of fd %d error: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: write of fd %d error: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); return(FALSE); } @@ -1664,13 +1649,13 @@ pipe_read (FileHandle *filehandle, gpointer buffer, guint32 numbytes, guint32 *b } if(!(filehandle->fileaccess & (GENERIC_READ | GENERIC_ALL))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fd %d doesn't have GENERIC_READ access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_READ access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); mono_w32error_set_last (ERROR_ACCESS_DENIED); return(FALSE); } - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: reading up to %" G_GUINT32_FORMAT " bytes from pipe %d", __func__, numbytes, ((MonoFDHandle*) filehandle)->fd); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: reading up to %" G_GUINT32_FORMAT " bytes from pipe %d", __func__, numbytes, ((MonoFDHandle*) filehandle)->fd); do { MONO_ENTER_GC_SAFE; @@ -1684,13 +1669,13 @@ pipe_read (FileHandle *filehandle, gpointer buffer, guint32 numbytes, guint32 *b } else { _wapi_set_last_error_from_errno (); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: read of fd %d error: %s", __func__,((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: read of fd %d error: %s", __func__,((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); return(FALSE); } } - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: read %d bytes from pipe %d", __func__, ret, ((MonoFDHandle*) filehandle)->fd); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: read %d bytes from pipe %d", __func__, ret, ((MonoFDHandle*) filehandle)->fd); if(bytesread!=NULL) { *bytesread=ret; @@ -1710,13 +1695,13 @@ pipe_write(FileHandle *filehandle, gconstpointer buffer, guint32 numbytes, guint } if(!(filehandle->fileaccess & (GENERIC_WRITE | GENERIC_ALL))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fd %d doesn't have GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); mono_w32error_set_last (ERROR_ACCESS_DENIED); return(FALSE); } - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: writing up to %" G_GUINT32_FORMAT " bytes to pipe %d", __func__, numbytes, ((MonoFDHandle*) filehandle)->fd); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: writing up to %" G_GUINT32_FORMAT " bytes to pipe %d", __func__, numbytes, ((MonoFDHandle*) filehandle)->fd); do { MONO_ENTER_GC_SAFE; @@ -1731,7 +1716,7 @@ pipe_write(FileHandle *filehandle, gconstpointer buffer, guint32 numbytes, guint } else { _wapi_set_last_error_from_errno (); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: write of fd %d error: %s", __func__,((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: write of fd %d error: %s", __func__,((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); return(FALSE); } @@ -1758,7 +1743,7 @@ static gint convert_flags(guint32 fileaccess, guint32 createmode) flags=O_RDWR; break; default: - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Unknown access type 0x%" PRIx32, __func__, + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Unknown access type 0x%" PRIx32, __func__, fileaccess); break; } @@ -1779,7 +1764,7 @@ static gint convert_flags(guint32 fileaccess, guint32 createmode) flags|=O_TRUNC; break; default: - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Unknown create mode 0x%" PRIx32, __func__, + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Unknown create mode 0x%" PRIx32, __func__, createmode); break; } @@ -1819,7 +1804,7 @@ static gboolean share_allows_open (struct stat *statbuf, guint32 sharemode, */ if (file_existing_share == 0) { /* Quick and easy, no possibility to share */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Share mode prevents open: requested access: 0x%" PRIx32 ", file has sharing = NONE", __func__, fileaccess); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Share mode prevents open: requested access: 0x%" PRIx32 ", file has sharing = NONE", __func__, fileaccess); file_share_release (*share_info); *share_info = NULL; @@ -1832,7 +1817,7 @@ static gboolean share_allows_open (struct stat *statbuf, guint32 sharemode, ((file_existing_share == FILE_SHARE_WRITE) && (fileaccess != GENERIC_WRITE))) { /* New access mode doesn't match up */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Share mode prevents open: requested access: 0x%" PRIx32 ", file has sharing: 0x%" PRIx32, __func__, fileaccess, file_existing_share); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Share mode prevents open: requested access: 0x%" PRIx32 ", file has sharing: 0x%" PRIx32, __func__, fileaccess, file_existing_share); file_share_release (*share_info); *share_info = NULL; @@ -1845,7 +1830,7 @@ static gboolean share_allows_open (struct stat *statbuf, guint32 sharemode, ((file_existing_access & GENERIC_WRITE) && !(sharemode & FILE_SHARE_WRITE))) { /* New share mode doesn't match up */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Access mode prevents open: requested share: 0x%" PRIx32 ", file has access: 0x%" PRIx32, __func__, sharemode, file_existing_access); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Access mode prevents open: requested share: 0x%" PRIx32 ", file has access: 0x%" PRIx32, __func__, sharemode, file_existing_access); file_share_release (*share_info); *share_info = NULL; @@ -1853,7 +1838,7 @@ static gboolean share_allows_open (struct stat *statbuf, guint32 sharemode, return(FALSE); } } else { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: New file!", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: New file!", __func__); } return(TRUE); @@ -1875,7 +1860,7 @@ share_allows_delete (struct stat *statbuf, FileShare **share_info) */ if (file_existing_share == 0) { /* Quick and easy, no possibility to share */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Share mode prevents open: requested access: 0x%" PRIx32 ", file has sharing = NONE", __func__, (*share_info)->access); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Share mode prevents open: requested access: 0x%" PRIx32 ", file has sharing = NONE", __func__, (*share_info)->access); file_share_release (*share_info); *share_info = NULL; @@ -1885,7 +1870,7 @@ share_allows_delete (struct stat *statbuf, FileShare **share_info) if (!(file_existing_share & FILE_SHARE_DELETE)) { /* New access mode doesn't match up */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Share mode prevents open: requested access: 0x%" PRIx32 ", file has sharing: 0x%" PRIx32, __func__, (*share_info)->access, file_existing_share); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Share mode prevents open: requested access: 0x%" PRIx32 ", file has sharing: 0x%" PRIx32, __func__, (*share_info)->access, file_existing_share); file_share_release (*share_info); *share_info = NULL; @@ -1893,7 +1878,7 @@ share_allows_delete (struct stat *statbuf, FileShare **share_info) return(FALSE); } } else { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: New file!", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: New file!", __func__); } return(TRUE); @@ -1925,7 +1910,7 @@ mono_w32file_create(const gunichar2 *name, guint32 fileaccess, guint32 sharemode } if (name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: name is NULL", __func__); mono_w32error_set_last (ERROR_INVALID_NAME); return(INVALID_HANDLE_VALUE); @@ -1933,13 +1918,13 @@ mono_w32file_create(const gunichar2 *name, guint32 fileaccess, guint32 sharemode filename = mono_unicode_to_external (name); if (filename == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL", __func__); mono_w32error_set_last (ERROR_INVALID_NAME); return(INVALID_HANDLE_VALUE); } - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Opening %s with share 0x%" PRIx32 " and access 0x%" PRIx32, __func__, + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Opening %s with share 0x%" PRIx32 " and access 0x%" PRIx32, __func__, filename, sharemode, fileaccess); fd = _wapi_open (filename, flags, perms); @@ -1959,7 +1944,7 @@ mono_w32file_create(const gunichar2 *name, guint32 fileaccess, guint32 sharemode } if (fd == -1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Error opening file %s: %s", __func__, filename, g_strerror(errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Error opening file %s: %s", __func__, filename, g_strerror(errno)); _wapi_set_last_path_error_from_errno (NULL, filename); g_free (filename); @@ -1970,7 +1955,7 @@ mono_w32file_create(const gunichar2 *name, guint32 fileaccess, guint32 sharemode ret = fstat (fd, &statbuf); MONO_EXIT_GC_SAFE; if (ret == -1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fstat error of file %s: %s", __func__, filename, g_strerror (errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fstat error of file %s: %s", __func__, filename, g_strerror (errno)); _wapi_set_last_error_from_errno (); MONO_ENTER_GC_SAFE; close (fd); @@ -2010,7 +1995,7 @@ mono_w32file_create(const gunichar2 *name, guint32 fileaccess, guint32 sharemode } if (!filehandle->share_info) { /* No space, so no more files can be opened */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: No space in the share table", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: No space in the share table", __func__); mono_w32error_set_last (ERROR_TOO_MANY_OPEN_FILES); MONO_ENTER_GC_SAFE; @@ -2044,7 +2029,7 @@ mono_w32file_create(const gunichar2 *name, guint32 fileaccess, guint32 sharemode mono_fdhandle_insert ((MonoFDHandle*) filehandle); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning handle %p", __func__, GINT_TO_POINTER(((MonoFDHandle*) filehandle)->fd)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: returning handle %p", __func__, GINT_TO_POINTER(((MonoFDHandle*) filehandle)->fd)); return GINT_TO_POINTER(((MonoFDHandle*) filehandle)->fd); } @@ -2071,7 +2056,7 @@ gboolean mono_w32file_delete(const gunichar2 *name) #endif if(name==NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: name is NULL", __func__); mono_w32error_set_last (ERROR_INVALID_NAME); return(FALSE); @@ -2079,7 +2064,7 @@ gboolean mono_w32file_delete(const gunichar2 *name) filename=mono_unicode_to_external(name); if(filename==NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL", __func__); mono_w32error_set_last (ERROR_INVALID_NAME); return(FALSE); @@ -2145,7 +2130,7 @@ MoveFile (const gunichar2 *name, const gunichar2 *dest_name) FileShare *shareinfo; if(name==NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: name is NULL", __func__); mono_w32error_set_last (ERROR_INVALID_NAME); return(FALSE); @@ -2153,14 +2138,14 @@ MoveFile (const gunichar2 *name, const gunichar2 *dest_name) utf8_name = mono_unicode_to_external (name); if (utf8_name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL", __func__); mono_w32error_set_last (ERROR_INVALID_NAME); return FALSE; } if(dest_name==NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: name is NULL", __func__); g_free (utf8_name); mono_w32error_set_last (ERROR_INVALID_NAME); @@ -2169,7 +2154,7 @@ MoveFile (const gunichar2 *name, const gunichar2 *dest_name) utf8_dest_name = mono_unicode_to_external (dest_name); if (utf8_dest_name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL", __func__); g_free (utf8_name); mono_w32error_set_last (ERROR_INVALID_NAME); @@ -2305,7 +2290,7 @@ write_file (gint src_fd, gint dest_fd, struct stat *st_src, gboolean report_erro if (report_errors) _wapi_set_last_error_from_errno (); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: write failed.", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: write failed.", __func__); g_free (buf); return FALSE; } @@ -2331,7 +2316,7 @@ CopyFile (const gunichar2 *name, const gunichar2 *dest_name, gboolean fail_if_ex gint syscall_res; if(name==NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: name is NULL", __func__); mono_w32error_set_last (ERROR_INVALID_NAME); return(FALSE); @@ -2339,7 +2324,7 @@ CopyFile (const gunichar2 *name, const gunichar2 *dest_name, gboolean fail_if_ex utf8_src = mono_unicode_to_external (name); if (utf8_src == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion of source returned NULL", + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion of source returned NULL", __func__); mono_w32error_set_last (ERROR_INVALID_PARAMETER); @@ -2347,7 +2332,7 @@ CopyFile (const gunichar2 *name, const gunichar2 *dest_name, gboolean fail_if_ex } if(dest_name==NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: dest is NULL", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: dest is NULL", __func__); g_free (utf8_src); mono_w32error_set_last (ERROR_INVALID_NAME); @@ -2356,7 +2341,7 @@ CopyFile (const gunichar2 *name, const gunichar2 *dest_name, gboolean fail_if_ex utf8_dest = mono_unicode_to_external (dest_name); if (utf8_dest == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion of dest returned NULL", + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion of dest returned NULL", __func__); mono_w32error_set_last (ERROR_INVALID_PARAMETER); @@ -2448,7 +2433,7 @@ CopyFile (const gunichar2 *name, const gunichar2 *dest_name, gboolean fail_if_ex ret_utime = utime (utf8_dest, &dest_time); MONO_EXIT_GC_SAFE; if (ret_utime == -1) - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: file [%s] utime failed: %s", __func__, utf8_dest, g_strerror(errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: file [%s] utime failed: %s", __func__, utf8_dest, g_strerror(errno)); g_free (utf8_src); g_free (utf8_dest); @@ -2462,14 +2447,14 @@ convert_arg_to_utf8 (const gunichar2 *arg, const gchar *arg_name) gchar *utf8_ret; if (arg == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %s is NULL", __func__, arg_name); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: %s is NULL", __func__, arg_name); mono_w32error_set_last (ERROR_INVALID_NAME); return NULL; } utf8_ret = mono_unicode_to_external (arg); if (utf8_ret == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion of %s returned NULL", + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion of %s returned NULL", __func__, arg_name); mono_w32error_set_last (ERROR_INVALID_PARAMETER); return NULL; @@ -2545,7 +2530,7 @@ _wapi_stdhandle_create (gint fd, const gchar *name) gint flags; FileHandle *filehandle; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: creating standard handle type %s, fd %d", __func__, name, fd); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: creating standard handle type %s, fd %d", __func__, name, fd); /* Check if fd is valid */ do { @@ -2556,7 +2541,7 @@ _wapi_stdhandle_create (gint fd, const gchar *name) /* Invalid fd. Not really much point checking for EBADF * specifically */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fcntl error on fd %d: %s", __func__, fd, g_strerror(errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fcntl error on fd %d: %s", __func__, fd, g_strerror(errno)); mono_w32error_set_last (mono_w32error_unix_to_win32 (errno)); return INVALID_HANDLE_VALUE; @@ -2576,7 +2561,7 @@ _wapi_stdhandle_create (gint fd, const gchar *name) filehandle->fileaccess = GENERIC_READ | GENERIC_WRITE; break; default: - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't figure out flags 0x%x", __func__, flags); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Can't figure out flags 0x%x", __func__, flags); filehandle->fileaccess = 0; break; } @@ -2599,7 +2584,7 @@ _wapi_stdhandle_create (gint fd, const gchar *name) return GINT_TO_POINTER(fd); } - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning handle %p", __func__, GINT_TO_POINTER(((MonoFDHandle*) filehandle)->fd)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: returning handle %p", __func__, GINT_TO_POINTER(((MonoFDHandle*) filehandle)->fd)); return GINT_TO_POINTER(((MonoFDHandle*) filehandle)->fd); } @@ -2917,7 +2902,7 @@ mono_w32file_filetime_to_systemtime(const FILETIME *file_time, SYSTEMTIME *syste const guint16 *ip; if(system_time==NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: system_time NULL", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: system_time NULL", __func__); mono_w32error_set_last (ERROR_INVALID_PARAMETER); return(FALSE); @@ -2931,7 +2916,7 @@ mono_w32file_filetime_to_systemtime(const FILETIME *file_time, SYSTEMTIME *syste * year and day calculation to work later */ if(file_ticks<0) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: file_time too big", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: file_time too big", __func__); mono_w32error_set_last (ERROR_INVALID_PARAMETER); return(FALSE); @@ -2939,31 +2924,31 @@ mono_w32file_filetime_to_systemtime(const FILETIME *file_time, SYSTEMTIME *syste totaldays=(file_ticks / TICKS_PER_DAY); rem = file_ticks % TICKS_PER_DAY; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: totaldays: %" G_GINT64_FORMAT " rem: %" G_GINT64_FORMAT, __func__, + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: totaldays: %" G_GINT64_FORMAT " rem: %" G_GINT64_FORMAT, __func__, totaldays, rem); system_time->wHour=rem/TICKS_PER_HOUR; rem %= TICKS_PER_HOUR; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Hour: %d rem: %" G_GINT64_FORMAT, __func__, + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Hour: %d rem: %" G_GINT64_FORMAT, __func__, system_time->wHour, rem); system_time->wMinute = rem / TICKS_PER_MINUTE; rem %= TICKS_PER_MINUTE; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Minute: %d rem: %" G_GINT64_FORMAT, __func__, + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Minute: %d rem: %" G_GINT64_FORMAT, __func__, system_time->wMinute, rem); system_time->wSecond = rem / TICKS_PER_SECOND; rem %= TICKS_PER_SECOND; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Second: %d rem: %" G_GINT64_FORMAT, __func__, + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Second: %d rem: %" G_GINT64_FORMAT, __func__, system_time->wSecond, rem); system_time->wMilliseconds = rem / TICKS_PER_MILLISECOND; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Milliseconds: %d", __func__, + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Milliseconds: %d", __func__, system_time->wMilliseconds); /* January 1, 1601 was a Monday, according to Emacs calendar */ system_time->wDayOfWeek = ((1 + totaldays) % 7) + 1; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Day of week: %d", __func__, system_time->wDayOfWeek); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Day of week: %d", __func__, system_time->wDayOfWeek); /* This algorithm to find year and month given days from epoch * from glibc @@ -2976,7 +2961,7 @@ mono_w32file_filetime_to_systemtime(const FILETIME *file_time, SYSTEMTIME *syste while(totaldays < 0 || totaldays >= (isleap(y)?366:365)) { /* Guess a corrected year, assuming 365 days per year */ gint64 yg = y + totaldays / 365 - (totaldays % 365 < 0); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: totaldays: %" G_GINT64_FORMAT " yg: %" G_GINT64_FORMAT " y: %" G_GINT64_FORMAT, __func__, + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: totaldays: %" G_GINT64_FORMAT " yg: %" G_GINT64_FORMAT " y: %" G_GINT64_FORMAT, __func__, totaldays, yg, y); g_message("%s: LEAPS(yg): %li LEAPS(y): %li", __func__, LEAPS_THRU_END_OF(yg-1), LEAPS_THRU_END_OF(y-1)); @@ -2985,14 +2970,14 @@ mono_w32file_filetime_to_systemtime(const FILETIME *file_time, SYSTEMTIME *syste totaldays -= ((yg - y) * 365 + LEAPS_THRU_END_OF (yg - 1) - LEAPS_THRU_END_OF (y - 1)); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: totaldays: %" G_GINT64_FORMAT, + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: totaldays: %" G_GINT64_FORMAT, __func__, totaldays); y = yg; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: y: %" G_GINT64_FORMAT, __func__, y); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: y: %" G_GINT64_FORMAT, __func__, y); } system_time->wYear = y; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Year: %d", __func__, system_time->wYear); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Year: %d", __func__, system_time->wYear); ip = mon_yday[isleap(y)]; @@ -3000,27 +2985,115 @@ mono_w32file_filetime_to_systemtime(const FILETIME *file_time, SYSTEMTIME *syste continue; } totaldays-=ip[y]; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: totaldays: %" G_GINT64_FORMAT, __func__, totaldays); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: totaldays: %" G_GINT64_FORMAT, __func__, totaldays); system_time->wMonth = y + 1; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Month: %d", __func__, system_time->wMonth); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Month: %d", __func__, system_time->wMonth); system_time->wDay = totaldays + 1; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Day: %d", __func__, system_time->wDay); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Day: %d", __func__, system_time->wDay); return(TRUE); } +static void +findhandle_destroy (gpointer data) +{ + FindHandle *findhandle; + + findhandle = (FindHandle*) data; + g_assert (findhandle); + + mono_coop_mutex_destroy (&findhandle->mutex); + + if (findhandle->namelist) + g_strfreev (findhandle->namelist); + if (findhandle->dir_part) + g_free (findhandle->dir_part); + + g_free (findhandle); +} + +static FindHandle* +findhandle_create (void) +{ + FindHandle* findhandle; + + findhandle = g_new0 (FindHandle, 1); + mono_refcount_init (findhandle, findhandle_destroy); + + mono_coop_mutex_init (&findhandle->mutex); + + return findhandle; +} + +static void +findhandle_insert (FindHandle *findhandle) +{ + mono_coop_mutex_lock (&finds_mutex); + + if (g_hash_table_lookup_extended (finds, (gpointer) findhandle, NULL, NULL)) + g_error("%s: duplicate Find handle %p", __func__, (gpointer) findhandle); + + g_hash_table_insert (finds, (gpointer) findhandle, findhandle); + + mono_coop_mutex_unlock (&finds_mutex); +} + +static gboolean +findhandle_lookup_and_ref (gpointer handle, FindHandle **findhandle) +{ + mono_coop_mutex_lock (&finds_mutex); + + if (!g_hash_table_lookup_extended (finds, handle, NULL, (gpointer*) findhandle)) { + mono_coop_mutex_unlock (&finds_mutex); + return FALSE; + } + + mono_refcount_inc (*findhandle); + + mono_coop_mutex_unlock (&finds_mutex); + + return TRUE; +} + +static void +findhandle_unref (FindHandle *findhandle) +{ + mono_refcount_dec (findhandle); +} + +static gboolean +findhandle_close (gpointer handle) +{ + FindHandle *findhandle; + gboolean removed; + + mono_coop_mutex_lock (&finds_mutex); + + if (!g_hash_table_lookup_extended (finds, handle, NULL, (gpointer*) &findhandle)) { + mono_coop_mutex_unlock (&finds_mutex); + + return FALSE; + } + + removed = g_hash_table_remove (finds, (gpointer) findhandle); + g_assert (removed); + + mono_coop_mutex_unlock (&finds_mutex); + + return TRUE; +} + gpointer mono_w32file_find_first (const gunichar2 *pattern, WIN32_FIND_DATA *find_data) { - MonoW32HandleFind find_handle = {0}; - gpointer handle; - gchar *utf8_pattern = NULL, *dir_part, *entry_part; + FindHandle *findhandle; + gchar *utf8_pattern = NULL, *dir_part, *entry_part, **namelist; gint result; if (pattern == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: pattern is NULL", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: pattern is NULL", __func__); mono_w32error_set_last (ERROR_PATH_NOT_FOUND); return(INVALID_HANDLE_VALUE); @@ -3028,13 +3101,13 @@ mono_w32file_find_first (const gunichar2 *pattern, WIN32_FIND_DATA *find_data) utf8_pattern = mono_unicode_to_external (pattern); if (utf8_pattern == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL", __func__); mono_w32error_set_last (ERROR_INVALID_NAME); return(INVALID_HANDLE_VALUE); } - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: looking for [%s]", __func__, utf8_pattern); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: looking for [%s]", __func__, utf8_pattern); /* Figure out which bit of the pattern is the directory */ dir_part = _wapi_dirname (utf8_pattern); @@ -3074,9 +3147,9 @@ mono_w32file_find_first (const gunichar2 *pattern, WIN32_FIND_DATA *find_data) * than mess around with regexes. */ - find_handle.namelist = NULL; + namelist = NULL; result = _wapi_io_scandir (dir_part, entry_part, - &find_handle.namelist); + &namelist); if (result == 0) { /* No files, which windows seems to call @@ -3086,53 +3159,46 @@ mono_w32file_find_first (const gunichar2 *pattern, WIN32_FIND_DATA *find_data) g_free (utf8_pattern); g_free (entry_part); g_free (dir_part); + g_strfreev (namelist); return (INVALID_HANDLE_VALUE); } if (result < 0) { _wapi_set_last_path_error_from_errno (dir_part, NULL); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: scandir error: %s", __func__, g_strerror (errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: scandir error: %s", __func__, g_strerror (errno)); g_free (utf8_pattern); g_free (entry_part); g_free (dir_part); + g_strfreev (namelist); return (INVALID_HANDLE_VALUE); } g_free (utf8_pattern); g_free (entry_part); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Got %d matches", __func__, result); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Got %d matches", __func__, result); - find_handle.dir_part = dir_part; - find_handle.num = result; - find_handle.count = 0; - - handle = mono_w32handle_new (MONO_W32HANDLE_FIND, &find_handle); - if (handle == INVALID_HANDLE_VALUE) { - g_warning ("%s: error creating find handle", __func__); - g_free (dir_part); - g_free (entry_part); - g_free (utf8_pattern); - mono_w32error_set_last (ERROR_GEN_FAILURE); - - return(INVALID_HANDLE_VALUE); - } + findhandle = findhandle_create (); + findhandle->namelist = namelist; + findhandle->dir_part = dir_part; + findhandle->num = result; + findhandle->count = 0; + + findhandle_insert (findhandle); - if (handle != INVALID_HANDLE_VALUE && - !mono_w32file_find_next (handle, find_data)) { - mono_w32file_find_close (handle); + if (!mono_w32file_find_next ((gpointer) findhandle, find_data)) { + mono_w32file_find_close ((gpointer) findhandle); mono_w32error_set_last (ERROR_NO_MORE_FILES); - handle = INVALID_HANDLE_VALUE; + return INVALID_HANDLE_VALUE; } - return (handle); + return (gpointer) findhandle; } gboolean mono_w32file_find_next (gpointer handle, WIN32_FIND_DATA *find_data) { - MonoW32HandleFind *find_handle; - gboolean ok; + FindHandle *findhandle; struct stat buf, linkbuf; gint result; gchar *filename; @@ -3141,27 +3207,23 @@ mono_w32file_find_next (gpointer handle, WIN32_FIND_DATA *find_data) time_t create_time; glong bytes; gboolean ret = FALSE; - - ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_FIND, - (gpointer *)&find_handle); - if(ok==FALSE) { - g_warning ("%s: error looking up find handle %p", __func__, - handle); + + if (!findhandle_lookup_and_ref (handle, &findhandle)) { mono_w32error_set_last (ERROR_INVALID_HANDLE); - return(FALSE); + return FALSE; } - mono_w32handle_lock_handle (handle); - + mono_coop_mutex_lock (&findhandle->mutex); + retry: - if (find_handle->count >= find_handle->num) { + if (findhandle->count >= findhandle->num) { mono_w32error_set_last (ERROR_NO_MORE_FILES); goto cleanup; } /* stat next match */ - filename = g_build_filename (find_handle->dir_part, find_handle->namelist[find_handle->count ++], NULL); + filename = g_build_filename (findhandle->dir_part, findhandle->namelist[findhandle->count ++], NULL); result = _wapi_stat (filename, &buf); if (result == -1 && errno == ENOENT) { @@ -3170,7 +3232,7 @@ mono_w32file_find_next (gpointer handle, WIN32_FIND_DATA *find_data) } if (result != 0) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: stat failed: %s", __func__, filename); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: stat failed: %s", __func__, filename); g_free (filename); goto retry; @@ -3178,7 +3240,7 @@ mono_w32file_find_next (gpointer handle, WIN32_FIND_DATA *find_data) result = _wapi_lstat (filename, &linkbuf); if (result != 0) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: lstat failed: %s", __func__, filename); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: lstat failed: %s", __func__, filename); g_free (filename); goto retry; @@ -3197,7 +3259,7 @@ mono_w32file_find_next (gpointer handle, WIN32_FIND_DATA *find_data) } g_free (filename); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Found [%s]", __func__, utf8_filename); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Found [%s]", __func__, utf8_filename); /* fill data block */ @@ -3251,7 +3313,9 @@ mono_w32file_find_next (gpointer handle, WIN32_FIND_DATA *find_data) g_free (utf16_basename); cleanup: - mono_w32handle_unlock_handle (handle); + mono_coop_mutex_unlock (&findhandle->mutex); + + findhandle_unref (findhandle); return(ret); } @@ -3259,35 +3323,12 @@ mono_w32file_find_next (gpointer handle, WIN32_FIND_DATA *find_data) gboolean mono_w32file_find_close (gpointer handle) { - MonoW32HandleFind *find_handle; - gboolean ok; - - if (handle == NULL) { - mono_w32error_set_last (ERROR_INVALID_HANDLE); - return(FALSE); - } - - ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_FIND, - (gpointer *)&find_handle); - if(ok==FALSE) { - g_warning ("%s: error looking up find handle %p", __func__, - handle); + if (!findhandle_close (handle)) { mono_w32error_set_last (ERROR_INVALID_HANDLE); - return(FALSE); + return FALSE; } - mono_w32handle_lock_handle (handle); - - g_strfreev (find_handle->namelist); - g_free (find_handle->dir_part); - - mono_w32handle_unlock_handle (handle); - - MONO_ENTER_GC_SAFE; - mono_w32handle_close (handle); - MONO_EXIT_GC_SAFE; - - return(TRUE); + return TRUE; } gboolean @@ -3297,7 +3338,7 @@ mono_w32file_create_directory (const gunichar2 *name) gint result; if (name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: name is NULL", __func__); mono_w32error_set_last (ERROR_INVALID_NAME); return(FALSE); @@ -3305,7 +3346,7 @@ mono_w32file_create_directory (const gunichar2 *name) utf8_name = mono_unicode_to_external (name); if (utf8_name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL", __func__); mono_w32error_set_last (ERROR_INVALID_NAME); return FALSE; @@ -3330,7 +3371,7 @@ mono_w32file_remove_directory (const gunichar2 *name) gint result; if (name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: name is NULL", __func__); mono_w32error_set_last (ERROR_INVALID_NAME); return(FALSE); @@ -3338,7 +3379,7 @@ mono_w32file_remove_directory (const gunichar2 *name) utf8_name = mono_unicode_to_external (name); if (utf8_name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL", __func__); mono_w32error_set_last (ERROR_INVALID_NAME); return FALSE; @@ -3365,7 +3406,7 @@ mono_w32file_get_attributes (const gunichar2 *name) guint32 ret; if (name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: name is NULL", __func__); mono_w32error_set_last (ERROR_INVALID_NAME); return(FALSE); @@ -3373,7 +3414,7 @@ mono_w32file_get_attributes (const gunichar2 *name) utf8_name = mono_unicode_to_external (name); if (utf8_name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL", __func__); mono_w32error_set_last (ERROR_INVALID_PARAMETER); return (INVALID_FILE_ATTRIBUTES); @@ -3414,7 +3455,7 @@ mono_w32file_get_attributes_ex (const gunichar2 *name, MonoIOStat *stat) gint result; if (name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: name is NULL", __func__); mono_w32error_set_last (ERROR_INVALID_NAME); return(FALSE); @@ -3422,7 +3463,7 @@ mono_w32file_get_attributes_ex (const gunichar2 *name, MonoIOStat *stat) utf8_name = mono_unicode_to_external (name); if (utf8_name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL", __func__); mono_w32error_set_last (ERROR_INVALID_PARAMETER); return FALSE; @@ -3473,7 +3514,7 @@ mono_w32file_set_attributes (const gunichar2 *name, guint32 attrs) */ if (name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: name is NULL", __func__); mono_w32error_set_last (ERROR_INVALID_NAME); return(FALSE); @@ -3481,7 +3522,7 @@ mono_w32file_set_attributes (const gunichar2 *name, guint32 attrs) utf8_name = mono_unicode_to_external (name); if (utf8_name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL", __func__); mono_w32error_set_last (ERROR_INVALID_NAME); return FALSE; @@ -3600,13 +3641,13 @@ mono_w32file_create_pipe (gpointer *readpipe, gpointer *writepipe, guint32 size) gint filedes[2]; gint ret; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Creating pipe", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Creating pipe", __func__); MONO_ENTER_GC_SAFE; ret=pipe (filedes); MONO_EXIT_GC_SAFE; if (ret==-1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Error creating pipe: (%d) %s", + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Error creating pipe: (%d) %s", __func__, errno, g_strerror (errno)); _wapi_set_last_error_from_errno (); @@ -3627,7 +3668,7 @@ mono_w32file_create_pipe (gpointer *readpipe, gpointer *writepipe, guint32 size) *readpipe = GINT_TO_POINTER(((MonoFDHandle*) read_filehandle)->fd); *writepipe = GINT_TO_POINTER(((MonoFDHandle*) write_filehandle)->fd); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Returning pipe: read handle %p, write handle %p", + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Returning pipe: read handle %p, write handle %p", __func__, GINT_TO_POINTER(((MonoFDHandle*) read_filehandle)->fd), GINT_TO_POINTER(((MonoFDHandle*) write_filehandle)->fd)); return(TRUE); @@ -4151,7 +4192,7 @@ mono_w32file_get_disk_free_space (const gunichar2 *path_name, guint64 *free_byte else { utf8_path_name = mono_unicode_to_external (path_name); if (utf8_path_name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL", __func__); mono_w32error_set_last (ERROR_INVALID_NAME); return(FALSE); @@ -4182,7 +4223,7 @@ mono_w32file_get_disk_free_space (const gunichar2 *path_name, guint64 *free_byte if (ret == -1) { _wapi_set_last_error_from_errno (); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: statvfs failed: %s", __func__, g_strerror (errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: statvfs failed: %s", __func__, g_strerror (errno)); return(FALSE); } @@ -4493,7 +4534,7 @@ mono_w32file_get_drive_type(const gunichar2 *root_path_name) else { utf8_root_path_name = mono_unicode_to_external (root_path_name); if (utf8_root_path_name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL", __func__); return(DRIVE_NO_ROOT_DIR); } @@ -4588,7 +4629,7 @@ LockFile (gpointer handle, guint32 offset_low, guint32 offset_high, guint32 leng } if (!(filehandle->fileaccess & (GENERIC_READ | GENERIC_WRITE | GENERIC_ALL))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fd %d doesn't have GENERIC_READ or GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_READ or GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); mono_w32error_set_last (ERROR_ACCESS_DENIED); mono_fdhandle_unref ((MonoFDHandle*) filehandle); return FALSE; @@ -4598,7 +4639,7 @@ LockFile (gpointer handle, guint32 offset_low, guint32 offset_high, guint32 leng offset = ((gint64)offset_high << 32) | offset_low; length = ((gint64)length_high << 32) | length_low; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Locking fd %d, offset %" G_GINT64_FORMAT ", length %" G_GINT64_FORMAT, __func__, ((MonoFDHandle*) filehandle)->fd, (gint64) offset, (gint64) length); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Locking fd %d, offset %" G_GINT64_FORMAT ", length %" G_GINT64_FORMAT, __func__, ((MonoFDHandle*) filehandle)->fd, (gint64) offset, (gint64) length); #else if (offset_high > 0 || length_high > 0) { mono_w32error_set_last (ERROR_INVALID_PARAMETER); @@ -4609,7 +4650,7 @@ LockFile (gpointer handle, guint32 offset_low, guint32 offset_high, guint32 leng offset = offset_low; length = length_low; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Locking fd %d, offset %" G_GINT64_FORMAT ", length %" G_GINT64_FORMAT, __func__, ((MonoFDHandle*) filehandle)->fd, (gint64) offset, (gint64) length); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Locking fd %d, offset %" G_GINT64_FORMAT ", length %" G_GINT64_FORMAT, __func__, ((MonoFDHandle*) filehandle)->fd, (gint64) offset, (gint64) length); #endif ret = _wapi_lock_file_region (((MonoFDHandle*) filehandle)->fd, offset, length); @@ -4637,7 +4678,7 @@ UnlockFile (gpointer handle, guint32 offset_low, guint32 offset_high, guint32 le } if (!(filehandle->fileaccess & (GENERIC_READ | GENERIC_WRITE | GENERIC_ALL))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fd %d doesn't have GENERIC_READ or GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_READ or GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); mono_w32error_set_last (ERROR_ACCESS_DENIED); mono_fdhandle_unref ((MonoFDHandle*) filehandle); return FALSE; @@ -4647,12 +4688,12 @@ UnlockFile (gpointer handle, guint32 offset_low, guint32 offset_high, guint32 le offset = ((gint64)offset_high << 32) | offset_low; length = ((gint64)length_high << 32) | length_low; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Unlocking fd %d, offset %" G_GINT64_FORMAT ", length %" G_GINT64_FORMAT, __func__, ((MonoFDHandle*) filehandle)->fd, (gint64) offset, (gint64) length); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Unlocking fd %d, offset %" G_GINT64_FORMAT ", length %" G_GINT64_FORMAT, __func__, ((MonoFDHandle*) filehandle)->fd, (gint64) offset, (gint64) length); #else offset = offset_low; length = length_low; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Unlocking fd %p, offset %" G_GINT64_FORMAT ", length %" G_GINT64_FORMAT, __func__, ((MonoFDHandle*) filehandle)->fd, (gint64) offset, (gint64) length); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Unlocking fd %p, offset %" G_GINT64_FORMAT ", length %" G_GINT64_FORMAT, __func__, ((MonoFDHandle*) filehandle)->fd, (gint64) offset, (gint64) length); #endif ret = _wapi_unlock_file_region (((MonoFDHandle*) filehandle)->fd, offset, length); @@ -4675,7 +4716,8 @@ mono_w32file_init (void) mono_coop_mutex_init (&file_share_mutex); - mono_w32handle_register_ops (MONO_W32HANDLE_FIND, &_wapi_find_ops); + finds = g_hash_table_new (g_direct_hash, g_direct_equal); + mono_coop_mutex_init (&finds_mutex); if (g_hasenv ("MONO_STRICT_IO_EMULATION")) lock_while_writing = TRUE; @@ -4688,6 +4730,9 @@ mono_w32file_cleanup (void) if (file_share_table) g_hash_table_destroy (file_share_table); + + g_hash_table_destroy (finds); + mono_coop_mutex_destroy (&finds_mutex); } gboolean diff --git a/mono/metadata/w32file.c b/mono/metadata/w32file.c index 9a9956323bcb..b9dfca997f30 100644 --- a/mono/metadata/w32file.c +++ b/mono/metadata/w32file.c @@ -751,7 +751,16 @@ ves_icall_System_IO_MonoIO_DuplicateHandle (HANDLE source_process_handle, HANDLE HANDLE target_process_handle, HANDLE *target_handle, gint32 access, gint32 inherit, gint32 options, gint32 *error) { #ifndef HOST_WIN32 - *target_handle = mono_w32handle_duplicate (source_handle); + MonoW32Handle *source_handle_data; + + if (!mono_w32handle_lookup_and_ref (source_handle, &source_handle_data)) { + *error = ERROR_INVALID_HANDLE; + return FALSE; + } + + *target_handle = mono_w32handle_duplicate (source_handle_data); + + mono_w32handle_unref (source_handle); #else gboolean ret; diff --git a/mono/metadata/w32handle-namespace.c b/mono/metadata/w32handle-namespace.c index f45d2efae532..ab24689c35ca 100644 --- a/mono/metadata/w32handle-namespace.c +++ b/mono/metadata/w32handle-namespace.c @@ -41,12 +41,12 @@ mono_w32handle_namespace_unlock (void) } static gboolean -has_namespace (MonoW32HandleType type) +has_namespace (MonoW32Type type) { switch (type) { - case MONO_W32HANDLE_NAMEDMUTEX: - case MONO_W32HANDLE_NAMEDSEM: - case MONO_W32HANDLE_NAMEDEVENT: + case MONO_W32TYPE_NAMEDMUTEX: + case MONO_W32TYPE_NAMEDSEM: + case MONO_W32TYPE_NAMEDEVENT: return TRUE; default: return FALSE; @@ -55,43 +55,41 @@ has_namespace (MonoW32HandleType type) typedef struct { gpointer ret; - MonoW32HandleType type; + MonoW32Type type; const gchar *name; } NamespaceSearchHandleData; static gboolean -mono_w32handle_namespace_search_handle_callback (gpointer handle, gpointer data, gpointer user_data) +mono_w32handle_namespace_search_handle_callback (MonoW32Handle *handle_data, gpointer user_data) { NamespaceSearchHandleData *search_data; - MonoW32HandleType type; MonoW32HandleNamespace *sharedns; - type = mono_w32handle_get_type (handle); - if (!has_namespace (type)) + if (!has_namespace (handle_data->type)) return FALSE; search_data = (NamespaceSearchHandleData*) user_data; - switch (type) { - case MONO_W32HANDLE_NAMEDMUTEX: sharedns = mono_w32mutex_get_namespace ((MonoW32HandleNamedMutex*) data); break; - case MONO_W32HANDLE_NAMEDSEM: sharedns = mono_w32semaphore_get_namespace ((MonoW32HandleNamedSemaphore*) data); break; - case MONO_W32HANDLE_NAMEDEVENT: sharedns = mono_w32event_get_namespace ((MonoW32HandleNamedEvent*) data); break; + switch (handle_data->type) { + case MONO_W32TYPE_NAMEDMUTEX: sharedns = mono_w32mutex_get_namespace ((MonoW32HandleNamedMutex*) handle_data->specific); break; + case MONO_W32TYPE_NAMEDSEM: sharedns = mono_w32semaphore_get_namespace ((MonoW32HandleNamedSemaphore*) handle_data->specific); break; + case MONO_W32TYPE_NAMEDEVENT: sharedns = mono_w32event_get_namespace ((MonoW32HandleNamedEvent*) handle_data->specific); break; default: g_assert_not_reached (); } if (strcmp (sharedns->name, search_data->name) == 0) { - if (type != search_data->type) { + if (handle_data->type != search_data->type) { /* Its the wrong type, so fail now */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p matches name but is wrong type: %s", - __func__, handle, mono_w32handle_get_typename (type)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_HANDLE, "%s: handle %p matches name but is wrong type: %s", + __func__, handle_data, mono_w32handle_get_typename (handle_data->type)); search_data->ret = INVALID_HANDLE_VALUE; } else { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p matches name and type", - __func__, handle); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_HANDLE, "%s: handle %p matches name and type", + __func__, handle_data); /* we do not want the handle to be destroyed before we return it */ - search_data->ret = mono_w32handle_duplicate (handle); + search_data->ret = mono_w32handle_duplicate (handle_data); } return TRUE; @@ -101,14 +99,14 @@ mono_w32handle_namespace_search_handle_callback (gpointer handle, gpointer data, } gpointer -mono_w32handle_namespace_search_handle (MonoW32HandleType type, const gchar *name) +mono_w32handle_namespace_search_handle (MonoW32Type type, const gchar *name) { NamespaceSearchHandleData search_data; if (!has_namespace (type)) g_error ("%s: type %s does not have a namespace", __func__, type); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Lookup for handle named [%s] type %s", + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_HANDLE, "%s: Lookup for handle named [%s] type %s", __func__, name, mono_w32handle_get_typename (type)); search_data.ret = NULL; diff --git a/mono/metadata/w32handle-namespace.h b/mono/metadata/w32handle-namespace.h index 5fcc99fc4002..db79fa5930a9 100644 --- a/mono/metadata/w32handle-namespace.h +++ b/mono/metadata/w32handle-namespace.h @@ -26,6 +26,6 @@ void mono_w32handle_namespace_unlock (void); gpointer -mono_w32handle_namespace_search_handle (MonoW32HandleType type, const gchar *name); +mono_w32handle_namespace_search_handle (MonoW32Type type, const gchar *name); #endif /* _MONO_METADATA_W32HANDLE_NAMESPACE_H_ */ diff --git a/mono/metadata/w32handle.c b/mono/metadata/w32handle.c index 3cc6ad65ad0e..5ba22cab55c4 100644 --- a/mono/metadata/w32handle.c +++ b/mono/metadata/w32handle.c @@ -18,7 +18,6 @@ #include "utils/atomic.h" #include "utils/mono-logger-internals.h" -#include "utils/mono-os-mutex.h" #include "utils/mono-proclib.h" #include "utils/mono-threads.h" #include "utils/mono-time.h" @@ -30,18 +29,8 @@ /* must be a power of 2 */ #define HANDLE_PER_SLOT (256) -typedef struct { - MonoW32HandleType type; - guint ref; - gboolean signalled; - gboolean in_use; - mono_mutex_t signal_mutex; - mono_cond_t signal_cond; - gpointer specific; -} MonoW32HandleBase; - -static MonoW32HandleCapability handle_caps [MONO_W32HANDLE_COUNT]; -static MonoW32HandleOps *handle_ops [MONO_W32HANDLE_COUNT]; +static MonoW32HandleCapability handle_caps [MONO_W32TYPE_COUNT]; +static MonoW32HandleOps *handle_ops [MONO_W32TYPE_COUNT]; /* * We can hold SLOT_MAX * HANDLE_PER_SLOT handles. @@ -50,7 +39,7 @@ static MonoW32HandleOps *handle_ops [MONO_W32HANDLE_COUNT]; #define SLOT_INDEX(x) (x / HANDLE_PER_SLOT) #define SLOT_OFFSET(x) (x % HANDLE_PER_SLOT) -static MonoW32HandleBase *private_handles [SLOT_MAX]; +static MonoW32Handle **private_handles; static guint32 private_handles_size = 0; /* @@ -58,118 +47,68 @@ static guint32 private_handles_size = 0; * Threads which wait for multiple handles wait on this one handle, and when a handle * is signalled, this handle is signalled too. */ -static mono_mutex_t global_signal_mutex; -static mono_cond_t global_signal_cond; +static MonoCoopMutex global_signal_mutex; +static MonoCoopCond global_signal_cond; -static mono_mutex_t scan_mutex; +static MonoCoopMutex scan_mutex; static gboolean shutting_down = FALSE; -static gboolean -mono_w32handle_lookup_data (gpointer handle, MonoW32HandleBase **handle_data) -{ - gsize index, offset; - - g_assert (handle_data); - - index = SLOT_INDEX ((gsize) handle); - if (index >= SLOT_MAX) - return FALSE; - if (!private_handles [index]) - return FALSE; - - offset = SLOT_OFFSET ((gsize) handle); - if (private_handles [index][offset].type == MONO_W32HANDLE_UNUSED) - return FALSE; - - *handle_data = &private_handles [index][offset]; - return TRUE; -} - -MonoW32HandleType -mono_w32handle_get_type (gpointer handle) -{ - MonoW32HandleBase *handle_data; - - if (!mono_w32handle_lookup_data (handle, &handle_data)) - return MONO_W32HANDLE_UNUSED; /* An impossible type */ - - return handle_data->type; -} - static const gchar* -mono_w32handle_ops_typename (MonoW32HandleType type); +mono_w32handle_ops_typename (MonoW32Type type); const gchar* -mono_w32handle_get_typename (MonoW32HandleType type) +mono_w32handle_get_typename (MonoW32Type type) { return mono_w32handle_ops_typename (type); } void -mono_w32handle_set_signal_state (gpointer handle, gboolean state, gboolean broadcast) +mono_w32handle_set_signal_state (MonoW32Handle *handle_data, gboolean state, gboolean broadcast) { - MonoW32HandleBase *handle_data; - - if (!mono_w32handle_lookup_data (handle, &handle_data)) { - return; - } - #ifdef DEBUG g_message ("%s: setting state of %p to %s (broadcast %s)", __func__, handle, state?"TRUE":"FALSE", broadcast?"TRUE":"FALSE"); #endif - if (state == TRUE) { + if (state) { /* Tell everyone blocking on a single handle */ /* The condition the global signal cond is waiting on is the signalling of * _any_ handle. So lock it before setting the signalled state. */ - mono_os_mutex_lock (&global_signal_mutex); + mono_coop_mutex_lock (&global_signal_mutex); /* This function _must_ be called with * handle->signal_mutex locked */ - handle_data->signalled=state; + handle_data->signalled = TRUE; - if (broadcast == TRUE) { - mono_os_cond_broadcast (&handle_data->signal_cond); - } else { - mono_os_cond_signal (&handle_data->signal_cond); - } + if (broadcast) + mono_coop_cond_broadcast (&handle_data->signal_cond); + else + mono_coop_cond_signal (&handle_data->signal_cond); /* Tell everyone blocking on multiple handles that something * was signalled */ - mono_os_cond_broadcast (&global_signal_cond); + mono_coop_cond_broadcast (&global_signal_cond); - mono_os_mutex_unlock (&global_signal_mutex); + mono_coop_mutex_unlock (&global_signal_mutex); } else { - handle_data->signalled=state; + handle_data->signalled = FALSE; } } gboolean -mono_w32handle_issignalled (gpointer handle) +mono_w32handle_issignalled (MonoW32Handle *handle_data) { - MonoW32HandleBase *handle_data; - - if (!mono_w32handle_lookup_data (handle, &handle_data)) { - return(FALSE); - } - return handle_data->signalled; } static void -mono_w32handle_set_in_use (gpointer handle, gboolean in_use) +mono_w32handle_set_in_use (MonoW32Handle *handle_data, gboolean in_use) { - MonoW32HandleBase *handle_data; - - if (!mono_w32handle_lookup_data (handle, &handle_data)) - g_assert_not_reached (); - handle_data->in_use = in_use; } @@ -180,7 +119,7 @@ mono_w32handle_lock_signal_mutex (void) g_message ("%s: lock global signal mutex", __func__); #endif - mono_os_mutex_lock (&global_signal_mutex); + mono_coop_mutex_lock (&global_signal_mutex); } static void @@ -190,65 +129,25 @@ mono_w32handle_unlock_signal_mutex (void) g_message ("%s: unlock global signal mutex", __func__); #endif - mono_os_mutex_unlock (&global_signal_mutex); + mono_coop_mutex_unlock (&global_signal_mutex); } -static void -mono_w32handle_ref (gpointer handle); - -static void -mono_w32handle_unref (gpointer handle); - void -mono_w32handle_lock_handle (gpointer handle) +mono_w32handle_lock (MonoW32Handle *handle_data) { - MonoW32HandleBase *handle_data; - - if (!mono_w32handle_lookup_data (handle, &handle_data)) - g_error ("%s: failed to lookup handle %p", __func__, handle); - - mono_w32handle_ref (handle); - - mono_os_mutex_lock (&handle_data->signal_mutex); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: lock handle %p", __func__, handle); + mono_coop_mutex_lock (&handle_data->signal_mutex); } gboolean -mono_w32handle_trylock_handle (gpointer handle) +mono_w32handle_trylock (MonoW32Handle *handle_data) { - MonoW32HandleBase *handle_data; - gboolean locked; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: trylock handle %p", __func__, handle); - - if (!mono_w32handle_lookup_data (handle, &handle_data)) - g_error ("%s: failed to lookup handle %p", __func__, handle); - - mono_w32handle_ref (handle); - - locked = mono_os_mutex_trylock (&handle_data->signal_mutex) == 0; - if (!locked) - mono_w32handle_unref (handle); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: trylock handle %p, locked: %s", __func__, handle, locked ? "true" : "false"); - - return locked; + return mono_coop_mutex_trylock (&handle_data->signal_mutex) == 0; } void -mono_w32handle_unlock_handle (gpointer handle) +mono_w32handle_unlock (MonoW32Handle *handle_data) { - MonoW32HandleBase *handle_data; - - if (!mono_w32handle_lookup_data (handle, &handle_data)) - g_error ("%s: failed to lookup handle %p", __func__, handle); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: unlock handle %p", __func__, handle); - - mono_os_mutex_unlock (&handle_data->signal_mutex); - - mono_w32handle_unref (handle); + mono_coop_mutex_unlock (&handle_data->signal_mutex); } void @@ -259,13 +158,12 @@ mono_w32handle_init (void) if (initialized) return; - g_assert ((sizeof (handle_ops) / sizeof (handle_ops[0])) - == MONO_W32HANDLE_COUNT); + mono_coop_mutex_init (&scan_mutex); - mono_os_mutex_init (&scan_mutex); + mono_coop_cond_init (&global_signal_cond); + mono_coop_mutex_init (&global_signal_mutex); - mono_os_cond_init (&global_signal_cond); - mono_os_mutex_init (&global_signal_mutex); + private_handles = g_new0 (MonoW32Handle*, SLOT_MAX); initialized = TRUE; } @@ -280,10 +178,12 @@ mono_w32handle_cleanup (void) for (i = 0; i < SLOT_MAX; ++i) g_free (private_handles [i]); + + g_free (private_handles); } static gsize -mono_w32handle_ops_typesize (MonoW32HandleType type); +mono_w32handle_ops_typesize (MonoW32Type type); /* * mono_w32handle_new_internal: @@ -293,8 +193,8 @@ mono_w32handle_ops_typesize (MonoW32HandleType type); * success and 0 on failure. This is only called from * mono_w32handle_new, and scan_mutex must be held. */ -static guint32 mono_w32handle_new_internal (MonoW32HandleType type, - gpointer handle_specific) +static MonoW32Handle* +mono_w32handle_new_internal (MonoW32Type type, gpointer handle_specific) { guint32 i, k, count; static guint32 last = 0; @@ -318,24 +218,24 @@ static guint32 mono_w32handle_new_internal (MonoW32HandleType type, for(i = SLOT_INDEX (count); i < private_handles_size; i++) { if (private_handles [i]) { for (k = SLOT_OFFSET (count); k < HANDLE_PER_SLOT; k++) { - MonoW32HandleBase *handle = &private_handles [i][k]; + MonoW32Handle *handle_data = &private_handles [i][k]; - if(handle->type == MONO_W32HANDLE_UNUSED) { + if (handle_data->type == MONO_W32TYPE_UNUSED) { last = count + 1; - g_assert (handle->ref == 0); + g_assert (handle_data->ref == 0); - handle->type = type; - handle->signalled = FALSE; - handle->ref = 1; + handle_data->type = type; + handle_data->signalled = FALSE; + handle_data->ref = 1; - mono_os_cond_init (&handle->signal_cond); - mono_os_mutex_init (&handle->signal_mutex); + mono_coop_cond_init (&handle_data->signal_cond); + mono_coop_mutex_init (&handle_data->signal_mutex); if (handle_specific) - handle->specific = g_memdup (handle_specific, mono_w32handle_ops_typesize (type)); + handle_data->specific = g_memdup (handle_specific, mono_w32handle_ops_typesize (type)); - return (count); + return handle_data; } count++; } @@ -351,141 +251,131 @@ static guint32 mono_w32handle_new_internal (MonoW32HandleType type, /* Will need to expand the array. The caller will sort it out */ - return G_MAXUINT32; + return GINT_TO_POINTER (-1); } gpointer -mono_w32handle_new (MonoW32HandleType type, gpointer handle_specific) +mono_w32handle_new (MonoW32Type type, gpointer handle_specific) { - guint32 handle_idx; - gpointer handle; + MonoW32Handle *handle_data; g_assert (!shutting_down); - mono_os_mutex_lock (&scan_mutex); + mono_coop_mutex_lock (&scan_mutex); - while ((handle_idx = mono_w32handle_new_internal (type, handle_specific)) == G_MAXUINT32) { + while ((handle_data = mono_w32handle_new_internal (type, handle_specific)) == GINT_TO_POINTER (-1)) { /* Try and expand the array, and have another go */ if (private_handles_size >= SLOT_MAX) { - mono_os_mutex_unlock (&scan_mutex); + mono_coop_mutex_unlock (&scan_mutex); /* We ran out of slots */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to create %s handle", __func__, mono_w32handle_ops_typename (type)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_HANDLE, "%s: failed to create %s handle", __func__, mono_w32handle_ops_typename (type)); return INVALID_HANDLE_VALUE; } - private_handles [private_handles_size ++] = g_new0 (MonoW32HandleBase, HANDLE_PER_SLOT); + private_handles [private_handles_size ++] = g_new0 (MonoW32Handle, HANDLE_PER_SLOT); } - mono_os_mutex_unlock (&scan_mutex); + mono_coop_mutex_unlock (&scan_mutex); - handle = GUINT_TO_POINTER (handle_idx); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_HANDLE, "%s: create %s handle %p", __func__, mono_w32handle_ops_typename (type), handle_data); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: create %s handle %p", __func__, mono_w32handle_ops_typename (type), handle); - - return(handle); + return (gpointer) handle_data; } static gboolean -mono_w32handle_ref_core (gpointer handle, MonoW32HandleBase *handle_data); +mono_w32handle_ref_core (MonoW32Handle *handle_data); static gboolean -mono_w32handle_unref_core (gpointer handle, MonoW32HandleBase *handle_data); +mono_w32handle_unref_core (MonoW32Handle *handle_data); static void -w32handle_destroy (gpointer handle); +w32handle_destroy (MonoW32Handle *handle_data); gpointer -mono_w32handle_duplicate (gpointer handle) +mono_w32handle_duplicate (MonoW32Handle *handle_data) { - MonoW32HandleBase *handle_data; - - if (handle == INVALID_HANDLE_VALUE) - return handle; - if (!mono_w32handle_lookup_data (handle, &handle_data)) - return INVALID_HANDLE_VALUE; + if (!mono_w32handle_ref_core (handle_data)) + g_error ("%s: unknown handle %p", __func__, handle_data); - if (!mono_w32handle_ref_core (handle, handle_data)) - g_error ("%s: failed to ref handle %p", __func__, handle); - - return handle; + return (gpointer) handle_data; } gboolean mono_w32handle_close (gpointer handle) { - MonoW32HandleBase *handle_data; + MonoW32Handle *handle_data; gboolean destroy; if (handle == INVALID_HANDLE_VALUE) return FALSE; - if (!mono_w32handle_lookup_data (handle, &handle_data)) + + handle_data = (MonoW32Handle*) handle; + + if (handle_data->type == MONO_W32TYPE_UNUSED) return FALSE; - destroy = mono_w32handle_unref_core (handle, handle_data); + destroy = mono_w32handle_unref_core (handle_data); if (destroy) - w32handle_destroy (handle); + w32handle_destroy (handle_data); return TRUE; } gboolean -mono_w32handle_lookup (gpointer handle, MonoW32HandleType type, - gpointer *handle_specific) +mono_w32handle_lookup_and_ref (gpointer handle, MonoW32Handle **handle_data) { - MonoW32HandleBase *handle_data; + g_assert (handle_data); - g_assert (handle_specific); + if (handle == INVALID_HANDLE_VALUE) + return FALSE; - if (!mono_w32handle_lookup_data (handle, &handle_data)) { - return(FALSE); - } + *handle_data = (MonoW32Handle*) handle; - if (handle_data->type != type) { - return(FALSE); - } + if (!mono_w32handle_ref_core (*handle_data)) + return FALSE; - *handle_specific = handle_data->specific; + if ((*handle_data)->type == MONO_W32TYPE_UNUSED) { + mono_w32handle_unref_core (*handle_data); + return FALSE; + } - return(TRUE); + return TRUE; } void -mono_w32handle_foreach (gboolean (*on_each)(gpointer handle, gpointer data, gpointer user_data), gpointer user_data) +mono_w32handle_foreach (gboolean (*on_each)(MonoW32Handle *handle_data, gpointer user_data), gpointer user_data) { GPtrArray *handles_to_destroy; guint32 i, k; handles_to_destroy = NULL; - mono_os_mutex_lock (&scan_mutex); + mono_coop_mutex_lock (&scan_mutex); for (i = SLOT_INDEX (0); i < private_handles_size; i++) { if (!private_handles [i]) continue; for (k = SLOT_OFFSET (0); k < HANDLE_PER_SLOT; k++) { - MonoW32HandleBase *handle_data = NULL; - gpointer handle; + MonoW32Handle *handle_data; gboolean destroy, finished; handle_data = &private_handles [i][k]; - if (handle_data->type == MONO_W32HANDLE_UNUSED) + if (handle_data->type == MONO_W32TYPE_UNUSED) continue; - handle = GUINT_TO_POINTER (i * HANDLE_PER_SLOT + k); - - if (!mono_w32handle_ref_core (handle, handle_data)) { + if (!mono_w32handle_ref_core (handle_data)) { /* we are racing with mono_w32handle_unref: * the handle ref has been decremented, but it * hasn't yet been destroyed. */ continue; } - finished = on_each (handle, handle_data->specific, user_data); + finished = on_each (handle_data, user_data); /* we might have to destroy the handle here, as * it could have been unrefed in another thread */ - destroy = mono_w32handle_unref_core (handle, handle_data); + destroy = mono_w32handle_unref_core (handle_data); if (destroy) { /* we do not destroy it while holding the scan_mutex * lock, because w32handle_destroy also needs to take @@ -493,7 +383,7 @@ mono_w32handle_foreach (gboolean (*on_each)(gpointer handle, gpointer data, gpoi * to a deadlock */ if (!handles_to_destroy) handles_to_destroy = g_ptr_array_sized_new (4); - g_ptr_array_add (handles_to_destroy, handle); + g_ptr_array_add (handles_to_destroy, (gpointer) handle_data); } if (finished) @@ -502,18 +392,18 @@ mono_w32handle_foreach (gboolean (*on_each)(gpointer handle, gpointer data, gpoi } done: - mono_os_mutex_unlock (&scan_mutex); + mono_coop_mutex_unlock (&scan_mutex); if (handles_to_destroy) { for (i = 0; i < handles_to_destroy->len; ++i) - w32handle_destroy (handles_to_destroy->pdata [i]); + w32handle_destroy ((MonoW32Handle*) handles_to_destroy->pdata [i]); g_ptr_array_free (handles_to_destroy, TRUE); } } static gboolean -mono_w32handle_ref_core (gpointer handle, MonoW32HandleBase *handle_data) +mono_w32handle_ref_core (MonoW32Handle *handle_data) { guint old, new; @@ -525,16 +415,16 @@ mono_w32handle_ref_core (gpointer handle, MonoW32HandleBase *handle_data) new = old + 1; } while (mono_atomic_cas_i32 ((gint32*) &handle_data->ref, (gint32)new, (gint32)old) != (gint32)old); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: ref %s handle %p, ref: %d -> %d", - __func__, mono_w32handle_ops_typename (handle_data->type), handle, old, new); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_HANDLE, "%s: ref %s handle %p, ref: %d -> %d", + __func__, mono_w32handle_ops_typename (handle_data->type), handle_data, old, new); return TRUE; } static gboolean -mono_w32handle_unref_core (gpointer handle, MonoW32HandleBase *handle_data) +mono_w32handle_unref_core (MonoW32Handle *handle_data) { - MonoW32HandleType type; + MonoW32Type type; guint old, new; type = handle_data->type; @@ -542,7 +432,7 @@ mono_w32handle_unref_core (gpointer handle, MonoW32HandleBase *handle_data) do { old = handle_data->ref; if (!(old >= 1)) - g_error ("%s: handle %p has ref %d, it should be >= 1", __func__, handle, old); + g_error ("%s: handle %p has ref %d, it should be >= 1", __func__, handle_data, old); new = old - 1; } while (mono_atomic_cas_i32 ((gint32*) &handle_data->ref, (gint32)new, (gint32)old) != (gint32)old); @@ -550,28 +440,16 @@ mono_w32handle_unref_core (gpointer handle, MonoW32HandleBase *handle_data) /* handle_data might contain invalid data from now on, if * another thread is unref'ing this handle at the same time */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: unref %s handle %p, ref: %d -> %d destroy: %s", - __func__, mono_w32handle_ops_typename (type), handle, old, new, new == 0 ? "true" : "false"); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_HANDLE, "%s: unref %s handle %p, ref: %d -> %d destroy: %s", + __func__, mono_w32handle_ops_typename (type), handle_data, old, new, new == 0 ? "true" : "false"); return new == 0; } -static void -mono_w32handle_ref (gpointer handle) -{ - MonoW32HandleBase *handle_data; - - if (!mono_w32handle_lookup_data (handle, &handle_data)) - g_error ("%s: failed to ref handle %p, unknown handle", __func__, handle); - - if (!mono_w32handle_ref_core (handle, handle_data)) - g_error ("%s: failed to ref handle %p", __func__, handle); -} - -static void (*_wapi_handle_ops_get_close_func (MonoW32HandleType type))(gpointer, gpointer); +static void (*_wapi_handle_ops_get_close_func (MonoW32Type type))(gpointer, gpointer); static void -w32handle_destroy (gpointer handle) +w32handle_destroy (MonoW32Handle *handle_data) { /* Need to copy the handle info, reset the slot in the * array, and _only then_ call the close function to @@ -579,33 +457,29 @@ w32handle_destroy (gpointer handle) * closed, and another file being opened getting the * same fd racing the memset()) */ - MonoW32HandleBase *handle_data; - MonoW32HandleType type; + MonoW32Type type; gpointer handle_specific; void (*close_func)(gpointer, gpointer); - if (!mono_w32handle_lookup_data (handle, &handle_data)) - g_error ("%s: unknown handle %p", __func__, handle); - g_assert (!handle_data->in_use); type = handle_data->type; handle_specific = handle_data->specific; - mono_os_mutex_lock (&scan_mutex); + mono_coop_mutex_lock (&scan_mutex); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: destroy %s handle %p", __func__, mono_w32handle_ops_typename (type), handle); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_HANDLE, "%s: destroy %s handle %p", __func__, mono_w32handle_ops_typename (type), handle_data); - mono_os_mutex_destroy (&handle_data->signal_mutex); - mono_os_cond_destroy (&handle_data->signal_cond); + mono_coop_mutex_destroy (&handle_data->signal_mutex); + mono_coop_cond_destroy (&handle_data->signal_cond); - memset (handle_data, 0, sizeof (MonoW32HandleBase)); + memset (handle_data, 0, sizeof (MonoW32Handle)); - mono_os_mutex_unlock (&scan_mutex); + mono_coop_mutex_unlock (&scan_mutex); close_func = _wapi_handle_ops_get_close_func (type); if (close_func != NULL) { - close_func (handle, handle_specific); + close_func (handle_data, handle_specific); } memset (handle_specific, 0, mono_w32handle_ops_typesize (type)); @@ -614,51 +488,38 @@ w32handle_destroy (gpointer handle) } /* The handle must not be locked on entry to this function */ -static void -mono_w32handle_unref (gpointer handle) +void +mono_w32handle_unref (MonoW32Handle *handle_data) { - MonoW32HandleBase *handle_data; gboolean destroy; - if (!mono_w32handle_lookup_data (handle, &handle_data)) - g_error ("%s: failed to unref handle %p, unknown handle", __func__, handle); - - destroy = mono_w32handle_unref_core (handle, handle_data); + destroy = mono_w32handle_unref_core (handle_data); if (destroy) - w32handle_destroy (handle); + w32handle_destroy (handle_data); } void -mono_w32handle_register_ops (MonoW32HandleType type, MonoW32HandleOps *ops) +mono_w32handle_register_ops (MonoW32Type type, MonoW32HandleOps *ops) { handle_ops [type] = ops; } -void mono_w32handle_register_capabilities (MonoW32HandleType type, - MonoW32HandleCapability caps) +void +mono_w32handle_register_capabilities (MonoW32Type type, MonoW32HandleCapability caps) { handle_caps[type] = caps; } -gboolean mono_w32handle_test_capabilities (gpointer handle, - MonoW32HandleCapability caps) +static gboolean +mono_w32handle_test_capabilities (MonoW32Handle *handle_data, MonoW32HandleCapability caps) { - MonoW32HandleBase *handle_data; - MonoW32HandleType type; - - if (!mono_w32handle_lookup_data (handle, &handle_data)) { - return(FALSE); - } - - type = handle_data->type; + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_HANDLE, "%s: testing 0x%x against 0x%x (%d)", __func__, + handle_caps[handle_data->type], caps, handle_caps[handle_data->type] & caps); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: testing 0x%x against 0x%x (%d)", __func__, - handle_caps[type], caps, handle_caps[type] & caps); - - return((handle_caps[type] & caps) != 0); + return (handle_caps [handle_data->type] & caps) != 0; } -static void (*_wapi_handle_ops_get_close_func (MonoW32HandleType type))(gpointer, gpointer) +static void (*_wapi_handle_ops_get_close_func (MonoW32Type type))(gpointer, gpointer) { if (handle_ops[type] != NULL && handle_ops[type]->close != NULL) { @@ -669,16 +530,14 @@ static void (*_wapi_handle_ops_get_close_func (MonoW32HandleType type))(gpointer } static void -mono_w32handle_ops_details (MonoW32HandleType type, gpointer data) +mono_w32handle_ops_details (MonoW32Handle *handle_data) { - if (handle_ops[type] != NULL && - handle_ops[type]->details != NULL) { - handle_ops[type]->details (data); - } + if (handle_ops [handle_data->type] && handle_ops [handle_data->type]->details != NULL) + handle_ops [handle_data->type]->details (handle_data); } static const gchar* -mono_w32handle_ops_typename (MonoW32HandleType type) +mono_w32handle_ops_typename (MonoW32Type type) { g_assert (handle_ops [type]); g_assert (handle_ops [type]->typename); @@ -686,7 +545,7 @@ mono_w32handle_ops_typename (MonoW32HandleType type) } static gsize -mono_w32handle_ops_typesize (MonoW32HandleType type) +mono_w32handle_ops_typesize (MonoW32Type type) { g_assert (handle_ops [type]); g_assert (handle_ops [type]->typesize); @@ -694,181 +553,103 @@ mono_w32handle_ops_typesize (MonoW32HandleType type) } static void -mono_w32handle_ops_signal (gpointer handle) +mono_w32handle_ops_signal (MonoW32Handle *handle_data) { - MonoW32HandleBase *handle_data; - MonoW32HandleType type; - - if (!mono_w32handle_lookup_data (handle, &handle_data)) { - return; - } - - type = handle_data->type; - - if (handle_ops[type] != NULL && handle_ops[type]->signal != NULL) { - handle_ops[type]->signal (handle, handle_data->specific); - } + if (handle_ops [handle_data->type] && handle_ops [handle_data->type]->signal) + handle_ops [handle_data->type]->signal (handle_data); } static gboolean -mono_w32handle_ops_own (gpointer handle, gboolean *abandoned) +mono_w32handle_ops_own (MonoW32Handle *handle_data, gboolean *abandoned) { - MonoW32HandleBase *handle_data; - MonoW32HandleType type; + if (handle_ops [handle_data->type] && handle_ops [handle_data->type]->own_handle) + return handle_ops [handle_data->type]->own_handle (handle_data, abandoned); - if (!mono_w32handle_lookup_data (handle, &handle_data)) { - return(FALSE); - } - - type = handle_data->type; - - if (handle_ops[type] != NULL && handle_ops[type]->own_handle != NULL) { - return(handle_ops[type]->own_handle (handle, abandoned)); - } else { - return(FALSE); - } + return FALSE; } static gboolean -mono_w32handle_ops_isowned (gpointer handle) +mono_w32handle_ops_isowned (MonoW32Handle *handle_data) { - MonoW32HandleBase *handle_data; - MonoW32HandleType type; - - if (!mono_w32handle_lookup_data (handle, &handle_data)) { - return(FALSE); - } + if (handle_ops [handle_data->type] && handle_ops [handle_data->type]->is_owned) + return handle_ops [handle_data->type]->is_owned (handle_data); - type = handle_data->type; - - if (handle_ops[type] != NULL && handle_ops[type]->is_owned != NULL) { - return(handle_ops[type]->is_owned (handle)); - } else { - return(FALSE); - } + return FALSE; } static MonoW32HandleWaitRet -mono_w32handle_ops_specialwait (gpointer handle, guint32 timeout, gboolean *alerted) +mono_w32handle_ops_specialwait (MonoW32Handle *handle_data, guint32 timeout, gboolean *alerted) { - MonoW32HandleBase *handle_data; - MonoW32HandleType type; - - if (!mono_w32handle_lookup_data (handle, &handle_data)) { - return MONO_W32HANDLE_WAIT_RET_FAILED; - } + if (handle_ops [handle_data->type] && handle_ops [handle_data->type]->special_wait) + return handle_ops [handle_data->type]->special_wait (handle_data, timeout, alerted); - type = handle_data->type; - - if (handle_ops[type] != NULL && - handle_ops[type]->special_wait != NULL) { - return(handle_ops[type]->special_wait (handle, timeout, alerted)); - } else { - return MONO_W32HANDLE_WAIT_RET_FAILED; - } + return MONO_W32HANDLE_WAIT_RET_FAILED; } static void -mono_w32handle_ops_prewait (gpointer handle) +mono_w32handle_ops_prewait (MonoW32Handle *handle_data) { - MonoW32HandleBase *handle_data; - MonoW32HandleType type; - - if (!mono_w32handle_lookup_data (handle, &handle_data)) { - return; - } - - type = handle_data->type; - - if (handle_ops[type] != NULL && - handle_ops[type]->prewait != NULL) { - handle_ops[type]->prewait (handle); - } + if (handle_ops [handle_data->type] && handle_ops [handle_data->type]->prewait) + handle_ops [handle_data->type]->prewait (handle_data); } static void -spin (guint32 ms) +mono_w32handle_lock_handles (MonoW32Handle **handles_data, gsize nhandles) { -#ifdef HOST_WIN32 - SleepEx (ms, TRUE); -#else + gint i, j, iter = 0; +#ifndef HOST_WIN32 struct timespec sleepytime; - - g_assert (ms < 1000); - - sleepytime.tv_sec = 0; - sleepytime.tv_nsec = ms * 1000000; - nanosleep (&sleepytime, NULL); -#endif /* HOST_WIN32 */ -} - -static void -mono_w32handle_lock_handles (gpointer *handles, gsize numhandles) -{ - guint32 i, iter=0; +#endif /* Lock all the handles, with backoff */ again: - for(i=0; i= 0; j--) + mono_w32handle_unlock (handles_data [j]); - while (i--) { - handle = handles[i]; + iter += 10; + if (iter == 1000) + iter = 10; - mono_w32handle_unlock_handle (handle); - } - - /* If iter ever reaches 100 the nanosleep will +#ifdef HOST_WIN32 + SleepEx (iter, TRUE); +#else + /* If iter ever reaches 1000 the nanosleep will * return EINVAL immediately, but we have a - * design flaw if that happens. - */ - iter++; - if(iter==100) { - g_warning ("%s: iteration overflow!", - __func__); - iter=1; - } + * design flaw if that happens. */ + g_assert (iter < 1000); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: Backing off for %d ms", __func__, - iter*10); - spin (10 * iter); + sleepytime.tv_sec = 0; + sleepytime.tv_nsec = iter * 1000000; + nanosleep (&sleepytime, NULL); +#endif /* HOST_WIN32 */ goto again; } } - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: Locked all handles", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_HANDLE, "%s: Locked all handles", __func__); } static void -mono_w32handle_unlock_handles (gpointer *handles, gsize numhandles) +mono_w32handle_unlock_handles (MonoW32Handle **handles_data, gsize nhandles) { - guint32 i; - - for(i=0; i= 0; i--) + mono_w32handle_unlock (handles_data [i]); } static int -mono_w32handle_timedwait_signal_naked (mono_cond_t *cond, mono_mutex_t *mutex, guint32 timeout, gboolean poll, gboolean *alerted) +mono_w32handle_timedwait_signal_naked (MonoCoopCond *cond, MonoCoopMutex *mutex, guint32 timeout, gboolean poll, gboolean *alerted) { int res; if (!poll) { - res = mono_os_cond_timedwait (cond, mutex, timeout); + res = mono_coop_cond_timedwait (cond, mutex, timeout); } else { /* This is needed when waiting for process handles */ if (!alerted) { @@ -879,13 +660,13 @@ mono_w32handle_timedwait_signal_naked (mono_cond_t *cond, mono_mutex_t *mutex, g * * http://pubs.opengroup.org/onlinepubs/007908775/xsh/pthread_cond_wait.html */ - res = mono_os_cond_timedwait (cond, mutex, timeout); + res = mono_coop_cond_timedwait (cond, mutex, timeout); } else { if (timeout < 100) { /* Real timeout is less than 100ms time */ - res = mono_os_cond_timedwait (cond, mutex, timeout); + res = mono_coop_cond_timedwait (cond, mutex, timeout); } else { - res = mono_os_cond_timedwait (cond, mutex, 100); + res = mono_coop_cond_timedwait (cond, mutex, 100); /* Mask the fake timeout, this will cause * another poll if the cond was not really signaled @@ -907,9 +688,9 @@ signal_global (gpointer unused) * - before the first CAS in timedwait, which means it won't enter the wait. * - it is after the first CAS, so it is already waiting, or it will enter * the wait, and it will be interrupted by the broadcast. */ - mono_os_mutex_lock (&global_signal_mutex); - mono_os_cond_broadcast (&global_signal_cond); - mono_os_mutex_unlock (&global_signal_mutex); + mono_coop_mutex_lock (&global_signal_mutex); + mono_coop_cond_broadcast (&global_signal_cond); + mono_coop_mutex_unlock (&global_signal_mutex); } static int @@ -917,7 +698,7 @@ mono_w32handle_timedwait_signal (guint32 timeout, gboolean poll, gboolean *alert { int res; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: waiting for global", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_HANDLE, "%s: waiting for global", __func__); if (alerted) *alerted = FALSE; @@ -937,14 +718,14 @@ mono_w32handle_timedwait_signal (guint32 timeout, gboolean poll, gboolean *alert } static void -signal_handle_and_unref (gpointer handle) +signal_handle_and_unref (gpointer handle_duplicate) { - MonoW32HandleBase *handle_data; - mono_cond_t *cond; - mono_mutex_t *mutex; + MonoW32Handle *handle_data; + MonoCoopCond *cond; + MonoCoopMutex *mutex; - if (!mono_w32handle_lookup_data (handle, &handle_data)) - g_error ("cannot signal unknown handle %p", handle); + if (!mono_w32handle_lookup_and_ref (handle_duplicate, &handle_data)) + g_error ("%s: unknown handle %p", __func__, handle_duplicate); /* If we reach here, then interrupt token is set to the flag value, which * means that the target thread is either @@ -954,31 +735,29 @@ signal_handle_and_unref (gpointer handle) cond = &handle_data->signal_cond; mutex = &handle_data->signal_mutex; - mono_os_mutex_lock (mutex); - mono_os_cond_broadcast (cond); - mono_os_mutex_unlock (mutex); + mono_coop_mutex_lock (mutex); + mono_coop_cond_broadcast (cond); + mono_coop_mutex_unlock (mutex); - mono_w32handle_close (handle); + mono_w32handle_unref (handle_data); + + mono_w32handle_close (handle_duplicate); } static int -mono_w32handle_timedwait_signal_handle (gpointer handle, guint32 timeout, gboolean poll, gboolean *alerted) +mono_w32handle_timedwait_signal_handle (MonoW32Handle *handle_data, guint32 timeout, gboolean poll, gboolean *alerted) { - MonoW32HandleBase *handle_data; gpointer handle_duplicate; int res; - if (!mono_w32handle_lookup_data (handle, &handle_data)) - g_error ("cannot wait on unknown handle %p", handle); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: waiting for %p (type %s)", __func__, handle, - mono_w32handle_ops_typename (mono_w32handle_get_type (handle))); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_HANDLE, "%s: waiting for %p (type %s)", __func__, handle_data, + mono_w32handle_ops_typename (handle_data->type)); if (alerted) *alerted = FALSE; if (alerted) { - mono_thread_info_install_interrupt (signal_handle_and_unref, handle_duplicate = mono_w32handle_duplicate (handle), alerted); + mono_thread_info_install_interrupt (signal_handle_and_unref, handle_duplicate = mono_w32handle_duplicate (handle_data), alerted); if (*alerted) { mono_w32handle_close (handle_duplicate); return 0; @@ -999,16 +778,11 @@ mono_w32handle_timedwait_signal_handle (gpointer handle, guint32 timeout, gboole } static gboolean -dump_callback (gpointer handle, gpointer handle_specific, gpointer user_data) +dump_callback (MonoW32Handle *handle_data, gpointer user_data) { - MonoW32HandleBase *handle_data; - - if (!mono_w32handle_lookup_data (handle, &handle_data)) - g_error ("cannot dump unknown handle %p", handle); - g_print ("%p [%7s] signalled: %5s ref: %3d ", - handle, mono_w32handle_ops_typename (handle_data->type), handle_data->signalled ? "true" : "false", handle_data->ref - 1 /* foreach increase ref by 1 */); - mono_w32handle_ops_details (handle_data->type, handle_data->specific); + handle_data, mono_w32handle_ops_typename (handle_data->type), handle_data->signalled ? "true" : "false", handle_data->ref - 1 /* foreach increase ref by 1 */); + mono_w32handle_ops_details (handle_data); g_print ("\n"); return FALSE; @@ -1020,30 +794,31 @@ void mono_w32handle_dump (void) } static gboolean -own_if_signalled (gpointer handle, gboolean *abandoned) +own_if_signalled (MonoW32Handle *handle_data, gboolean *abandoned) { - if (!mono_w32handle_issignalled (handle)) + if (!mono_w32handle_issignalled (handle_data)) return FALSE; *abandoned = FALSE; - mono_w32handle_ops_own (handle, abandoned); + mono_w32handle_ops_own (handle_data, abandoned); return TRUE; } static gboolean -own_if_owned( gpointer handle, gboolean *abandoned) +own_if_owned (MonoW32Handle *handle_data, gboolean *abandoned) { - if (!mono_w32handle_ops_isowned (handle)) + if (!mono_w32handle_ops_isowned (handle_data)) return FALSE; *abandoned = FALSE; - mono_w32handle_ops_own (handle, abandoned); + mono_w32handle_ops_own (handle_data, abandoned); return TRUE; } MonoW32HandleWaitRet mono_w32handle_wait_one (gpointer handle, guint32 timeout, gboolean alertable) { + MonoW32Handle *handle_data; MonoW32HandleWaitRet ret; gboolean alerted; gint64 start; @@ -1051,26 +826,28 @@ mono_w32handle_wait_one (gpointer handle, guint32 timeout, gboolean alertable) alerted = FALSE; - if (mono_w32handle_test_capabilities (handle, MONO_W32HANDLE_CAP_SPECIAL_WAIT)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p has special wait", - __func__, handle); + if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) + return MONO_W32HANDLE_WAIT_RET_FAILED; - return mono_w32handle_ops_specialwait (handle, timeout, alertable ? &alerted : NULL); + if (mono_w32handle_test_capabilities (handle_data, MONO_W32HANDLE_CAP_SPECIAL_WAIT)) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_HANDLE, "%s: handle %p has special wait", __func__, handle_data); + + mono_w32handle_unref (handle_data); + return mono_w32handle_ops_specialwait (handle_data, timeout, alertable ? &alerted : NULL); } - if (!mono_w32handle_test_capabilities (handle, MONO_W32HANDLE_CAP_WAIT)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p can't be waited for", - __func__, handle); + if (!mono_w32handle_test_capabilities (handle_data, MONO_W32HANDLE_CAP_WAIT)) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_HANDLE, "%s: handle %p can't be waited for", __func__, handle_data); + mono_w32handle_unref (handle_data); return MONO_W32HANDLE_WAIT_RET_FAILED; } - mono_w32handle_lock_handle (handle); + mono_w32handle_lock (handle_data); - if (mono_w32handle_test_capabilities (handle, MONO_W32HANDLE_CAP_OWN)) { - if (own_if_owned (handle, &abandoned)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p already owned", - __func__, handle); + if (mono_w32handle_test_capabilities (handle_data, MONO_W32HANDLE_CAP_OWN)) { + if (own_if_owned (handle_data, &abandoned)) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_HANDLE, "%s: handle %p already owned", __func__, handle_data); ret = abandoned ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0; goto done; @@ -1080,23 +857,22 @@ mono_w32handle_wait_one (gpointer handle, guint32 timeout, gboolean alertable) if (timeout != MONO_INFINITE_WAIT) start = mono_msec_ticks (); - mono_w32handle_set_in_use (handle, TRUE); + mono_w32handle_set_in_use (handle_data, TRUE); for (;;) { gint waited; - if (own_if_signalled (handle, &abandoned)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p signalled", - __func__, handle); + if (own_if_signalled (handle_data, &abandoned)) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_HANDLE, "%s: handle %p signalled", __func__, handle_data); ret = abandoned ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0; goto done; } - mono_w32handle_ops_prewait (handle); + mono_w32handle_ops_prewait (handle_data); if (timeout == MONO_INFINITE_WAIT) { - waited = mono_w32handle_timedwait_signal_handle (handle, MONO_INFINITE_WAIT, FALSE, alertable ? &alerted : NULL); + waited = mono_w32handle_timedwait_signal_handle (handle_data, MONO_INFINITE_WAIT, FALSE, alertable ? &alerted : NULL); } else { gint64 elapsed; @@ -1106,7 +882,7 @@ mono_w32handle_wait_one (gpointer handle, guint32 timeout, gboolean alertable) goto done; } - waited = mono_w32handle_timedwait_signal_handle (handle, timeout - elapsed, FALSE, alertable ? &alerted : NULL); + waited = mono_w32handle_timedwait_signal_handle (handle_data, timeout - elapsed, FALSE, alertable ? &alerted : NULL); } if (alerted) { @@ -1121,9 +897,11 @@ mono_w32handle_wait_one (gpointer handle, guint32 timeout, gboolean alertable) } done: - mono_w32handle_set_in_use (handle, FALSE); + mono_w32handle_set_in_use (handle_data, FALSE); + + mono_w32handle_unlock (handle_data); - mono_w32handle_unlock_handle (handle); + mono_w32handle_unref (handle_data); return ret; } @@ -1135,7 +913,7 @@ mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waital gboolean alerted, poll; gint i; gint64 start; - gpointer handles_sorted [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS]; + MonoW32Handle *handles_data [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS], *handles_data_sorted [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS]; gboolean abandoned [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS] = {0}; if (nhandles == 0) @@ -1147,30 +925,42 @@ mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waital alerted = FALSE; if (nhandles > MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: too many handles: %zd", + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_HANDLE, "%s: too many handles: %zd", __func__, nhandles); return MONO_W32HANDLE_WAIT_RET_FAILED; } for (i = 0; i < nhandles; ++i) { - if (!mono_w32handle_test_capabilities (handles[i], MONO_W32HANDLE_CAP_WAIT) - && !mono_w32handle_test_capabilities (handles[i], MONO_W32HANDLE_CAP_SPECIAL_WAIT)) + if (!mono_w32handle_lookup_and_ref (handles [i], &handles_data [i])) { + for (; i >= 0; --i) + mono_w32handle_unref (handles_data [i]); + return MONO_W32HANDLE_WAIT_RET_FAILED; + } + } + + for (i = 0; i < nhandles; ++i) { + if (!mono_w32handle_test_capabilities (handles_data[i], MONO_W32HANDLE_CAP_WAIT) + && !mono_w32handle_test_capabilities (handles_data[i], MONO_W32HANDLE_CAP_SPECIAL_WAIT)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p can't be waited for", - __func__, handles [i]); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_HANDLE, "%s: handle %p can't be waited for", __func__, handles_data [i]); + + for (i = nhandles - 1; i >= 0; --i) + mono_w32handle_unref (handles_data [i]); return MONO_W32HANDLE_WAIT_RET_FAILED; } - handles_sorted [i] = handles [i]; + handles_data_sorted [i] = handles_data [i]; } - qsort (handles_sorted, nhandles, sizeof (gpointer), g_direct_equal); + qsort (handles_data_sorted, nhandles, sizeof (gpointer), g_direct_equal); for (i = 1; i < nhandles; ++i) { - if (handles_sorted [i - 1] == handles_sorted [i]) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p is duplicated", - __func__, handles_sorted [i]); + if (handles_data_sorted [i - 1] == handles_data_sorted [i]) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_HANDLE, "%s: handle %p is duplicated", __func__, handles_data_sorted [i]); + + for (i = nhandles - 1; i >= 0; --i) + mono_w32handle_unref (handles_data [i]); return MONO_W32HANDLE_WAIT_RET_FAILED; } @@ -1178,7 +968,7 @@ mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waital poll = FALSE; for (i = 0; i < nhandles; ++i) { - if (mono_w32handle_get_type (handles [i]) == MONO_W32HANDLE_PROCESS) { + if (handles_data [i]->type == MONO_W32TYPE_PROCESS) { /* Can't wait for a process handle + another handle without polling */ poll = TRUE; } @@ -1187,13 +977,6 @@ mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waital if (timeout != MONO_INFINITE_WAIT) start = mono_msec_ticks (); - for (i = 0; i < nhandles; ++i) { - /* Add a reference, as we need to ensure the handle wont - * disappear from under us while we're waiting in the loop - * (not lock, as we don't want exclusive access here) */ - mono_w32handle_ref (handles [i]); - } - for (;;) { gsize count, lowest; gboolean signalled; @@ -1202,11 +985,11 @@ mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waital count = 0; lowest = nhandles; - mono_w32handle_lock_handles (handles, nhandles); + mono_w32handle_lock_handles (handles_data, nhandles); for (i = 0; i < nhandles; i++) { - if ((mono_w32handle_test_capabilities (handles [i], MONO_W32HANDLE_CAP_OWN) && mono_w32handle_ops_isowned (handles [i])) - || mono_w32handle_issignalled (handles [i])) + if ((mono_w32handle_test_capabilities (handles_data [i], MONO_W32HANDLE_CAP_OWN) && mono_w32handle_ops_isowned (handles_data [i])) + || mono_w32handle_issignalled (handles_data [i])) { count ++; @@ -1219,7 +1002,7 @@ mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waital if (signalled) { for (i = 0; i < nhandles; i++) { - if (own_if_signalled (handles [i], &abandoned [i]) && !waitall) { + if (own_if_signalled (handles_data [i], &abandoned [i]) && !waitall) { /* if we are calling WaitHandle.WaitAny, .NET only owns the first one; it matters for Mutex which * throw AbandonedMutexException in case we owned it but didn't release it */ break; @@ -1227,7 +1010,7 @@ mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waital } } - mono_w32handle_unlock_handles (handles, nhandles); + mono_w32handle_unlock_handles (handles_data, nhandles); if (signalled) { ret = MONO_W32HANDLE_WAIT_RET_SUCCESS_0 + lowest; @@ -1241,12 +1024,12 @@ mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waital } for (i = 0; i < nhandles; i++) { - mono_w32handle_ops_prewait (handles[i]); + mono_w32handle_ops_prewait (handles_data [i]); - if (mono_w32handle_test_capabilities (handles [i], MONO_W32HANDLE_CAP_SPECIAL_WAIT) - && !mono_w32handle_issignalled (handles [i])) + if (mono_w32handle_test_capabilities (handles_data [i], MONO_W32HANDLE_CAP_SPECIAL_WAIT) + && !mono_w32handle_issignalled (handles_data [i])) { - mono_w32handle_ops_specialwait (handles [i], 0, alertable ? &alerted : NULL); + mono_w32handle_ops_specialwait (handles_data [i], 0, alertable ? &alerted : NULL); } } @@ -1255,7 +1038,7 @@ mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waital if (waitall) { signalled = TRUE; for (i = 0; i < nhandles; ++i) { - if (!mono_w32handle_issignalled (handles [i])) { + if (!mono_w32handle_issignalled (handles_data [i])) { signalled = FALSE; break; } @@ -1263,7 +1046,7 @@ mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waital } else { signalled = FALSE; for (i = 0; i < nhandles; ++i) { - if (mono_w32handle_issignalled (handles [i])) { + if (mono_w32handle_issignalled (handles_data [i])) { signalled = TRUE; break; } @@ -1305,9 +1088,9 @@ mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waital } done: - for (i = 0; i < nhandles; i++) { + for (i = nhandles - 1; i >= 0; i--) { /* Unref everything we reffed above */ - mono_w32handle_unref (handles [i]); + mono_w32handle_unref (handles_data [i]); } return ret; @@ -1316,37 +1099,52 @@ mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waital MonoW32HandleWaitRet mono_w32handle_signal_and_wait (gpointer signal_handle, gpointer wait_handle, guint32 timeout, gboolean alertable) { + MonoW32Handle *signal_handle_data, *wait_handle_data, *handles_data [2]; MonoW32HandleWaitRet ret; gint64 start; gboolean alerted; gboolean abandoned = FALSE; - gpointer handles [2]; alerted = FALSE; - if (!mono_w32handle_test_capabilities (signal_handle, MONO_W32HANDLE_CAP_SIGNAL)) + if (!mono_w32handle_lookup_and_ref (signal_handle, &signal_handle_data)) { + return MONO_W32HANDLE_WAIT_RET_FAILED; + } + if (!mono_w32handle_lookup_and_ref (wait_handle, &wait_handle_data)) { + mono_w32handle_unref (signal_handle_data); + return MONO_W32HANDLE_WAIT_RET_FAILED; + } + + if (!mono_w32handle_test_capabilities (signal_handle_data, MONO_W32HANDLE_CAP_SIGNAL)) { + mono_w32handle_unref (wait_handle_data); + mono_w32handle_unref (signal_handle_data); return MONO_W32HANDLE_WAIT_RET_FAILED; - if (!mono_w32handle_test_capabilities (wait_handle, MONO_W32HANDLE_CAP_WAIT)) + } + if (!mono_w32handle_test_capabilities (wait_handle_data, MONO_W32HANDLE_CAP_WAIT)) { + mono_w32handle_unref (wait_handle_data); + mono_w32handle_unref (signal_handle_data); return MONO_W32HANDLE_WAIT_RET_FAILED; + } - if (mono_w32handle_test_capabilities (wait_handle, MONO_W32HANDLE_CAP_SPECIAL_WAIT)) { - g_warning ("%s: handle %p has special wait, implement me!!", __func__, wait_handle); + if (mono_w32handle_test_capabilities (wait_handle_data, MONO_W32HANDLE_CAP_SPECIAL_WAIT)) { + g_warning ("%s: handle %p has special wait, implement me!!", __func__, wait_handle_data); + mono_w32handle_unref (wait_handle_data); + mono_w32handle_unref (signal_handle_data); return MONO_W32HANDLE_WAIT_RET_FAILED; } - handles [0] = wait_handle; - handles [1] = signal_handle; + handles_data [0] = wait_handle_data; + handles_data [1] = signal_handle_data; - mono_w32handle_lock_handles (handles, 2); + mono_w32handle_lock_handles (handles_data, 2); - mono_w32handle_ops_signal (signal_handle); + mono_w32handle_ops_signal (signal_handle_data); - mono_w32handle_unlock_handle (signal_handle); + mono_w32handle_unlock (signal_handle_data); - if (mono_w32handle_test_capabilities (wait_handle, MONO_W32HANDLE_CAP_OWN)) { - if (own_if_owned (wait_handle, &abandoned)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p already owned", - __func__, wait_handle); + if (mono_w32handle_test_capabilities (wait_handle_data, MONO_W32HANDLE_CAP_OWN)) { + if (own_if_owned (wait_handle_data, &abandoned)) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_HANDLE, "%s: handle %p already owned", __func__, wait_handle_data); ret = abandoned ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0; goto done; @@ -1359,18 +1157,17 @@ mono_w32handle_signal_and_wait (gpointer signal_handle, gpointer wait_handle, gu for (;;) { gint waited; - if (own_if_signalled (wait_handle, &abandoned)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p signalled", - __func__, wait_handle); + if (own_if_signalled (wait_handle_data, &abandoned)) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_HANDLE, "%s: handle %p signalled", __func__, wait_handle_data); ret = abandoned ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0; goto done; } - mono_w32handle_ops_prewait (wait_handle); + mono_w32handle_ops_prewait (wait_handle_data); if (timeout == MONO_INFINITE_WAIT) { - waited = mono_w32handle_timedwait_signal_handle (wait_handle, MONO_INFINITE_WAIT, FALSE, alertable ? &alerted : NULL); + waited = mono_w32handle_timedwait_signal_handle (wait_handle_data, MONO_INFINITE_WAIT, FALSE, alertable ? &alerted : NULL); } else { gint64 elapsed; @@ -1380,7 +1177,7 @@ mono_w32handle_signal_and_wait (gpointer signal_handle, gpointer wait_handle, gu goto done; } - waited = mono_w32handle_timedwait_signal_handle (wait_handle, timeout - elapsed, FALSE, alertable ? &alerted : NULL); + waited = mono_w32handle_timedwait_signal_handle (wait_handle_data, timeout - elapsed, FALSE, alertable ? &alerted : NULL); } if (alerted) { @@ -1395,7 +1192,10 @@ mono_w32handle_signal_and_wait (gpointer signal_handle, gpointer wait_handle, gu } done: - mono_w32handle_unlock_handle (wait_handle); + mono_w32handle_unlock (wait_handle_data); + + mono_w32handle_unref (wait_handle_data); + mono_w32handle_unref (signal_handle_data); return ret; } diff --git a/mono/metadata/w32handle.h b/mono/metadata/w32handle.h index 24d547952f7c..13a1cb26bbb1 100644 --- a/mono/metadata/w32handle.h +++ b/mono/metadata/w32handle.h @@ -12,6 +12,8 @@ #include #endif +#include "mono/utils/mono-coop-mutex.h" + #ifndef INVALID_HANDLE_VALUE #define INVALID_HANDLE_VALUE (gpointer)-1 #endif @@ -23,17 +25,26 @@ #endif typedef enum { - MONO_W32HANDLE_UNUSED = 0, - MONO_W32HANDLE_SEM, - MONO_W32HANDLE_MUTEX, - MONO_W32HANDLE_EVENT, - MONO_W32HANDLE_FIND, - MONO_W32HANDLE_PROCESS, - MONO_W32HANDLE_NAMEDMUTEX, - MONO_W32HANDLE_NAMEDSEM, - MONO_W32HANDLE_NAMEDEVENT, - MONO_W32HANDLE_COUNT -} MonoW32HandleType; + MONO_W32TYPE_UNUSED = 0, + MONO_W32TYPE_SEM, + MONO_W32TYPE_MUTEX, + MONO_W32TYPE_EVENT, + MONO_W32TYPE_PROCESS, + MONO_W32TYPE_NAMEDMUTEX, + MONO_W32TYPE_NAMEDSEM, + MONO_W32TYPE_NAMEDEVENT, + MONO_W32TYPE_COUNT +} MonoW32Type; + +typedef struct { + MonoW32Type type; + guint ref; + gboolean signalled; + gboolean in_use; + MonoCoopMutex signal_mutex; + MonoCoopCond signal_cond; + gpointer specific; +} MonoW32Handle; typedef enum { MONO_W32HANDLE_WAIT_RET_SUCCESS_0 = 0, @@ -48,7 +59,7 @@ typedef struct void (*close)(gpointer handle, gpointer data); /* mono_w32handle_signal_and_wait */ - void (*signal)(gpointer signal, gpointer data); + void (*signal)(MonoW32Handle *handle_data); /* Called by mono_w32handle_wait_one and mono_w32handle_wait_multiple, * with the handle locked (shared handles aren't locked.) @@ -56,29 +67,29 @@ typedef struct * If TRUE, *abandoned contains a status code such as * WAIT_OBJECT_0 or WAIT_ABANDONED_0. */ - gboolean (*own_handle)(gpointer handle, gboolean *abandoned); + gboolean (*own_handle)(MonoW32Handle *handle_data, gboolean *abandoned); /* Called by mono_w32handle_wait_one and mono_w32handle_wait_multiple, if the * handle in question is "ownable" (ie mutexes), to see if the current * thread already owns this handle */ - gboolean (*is_owned)(gpointer handle); + gboolean (*is_owned)(MonoW32Handle *handle_data); /* Called by mono_w32handle_wait_one and mono_w32handle_wait_multiple, * if the handle in question needs a special wait function * instead of using the normal handle signal mechanism. * Returns the mono_w32handle_wait_one return code. */ - MonoW32HandleWaitRet (*special_wait)(gpointer handle, guint32 timeout, gboolean *alerted); + MonoW32HandleWaitRet (*special_wait)(MonoW32Handle *handle_data, guint32 timeout, gboolean *alerted); /* Called by mono_w32handle_wait_one and mono_w32handle_wait_multiple, * if the handle in question needs some preprocessing before the * signal wait. */ - void (*prewait)(gpointer handle); + void (*prewait)(MonoW32Handle *handle_data); /* Called when dumping the handles */ - void (*details)(gpointer data); + void (*details)(MonoW32Handle *handle_data); /* Called to get the name of the handle type */ const gchar* (*typename) (void); @@ -101,52 +112,49 @@ void mono_w32handle_cleanup (void); void -mono_w32handle_register_ops (MonoW32HandleType type, MonoW32HandleOps *ops); +mono_w32handle_register_ops (MonoW32Type type, MonoW32HandleOps *ops); gpointer -mono_w32handle_new (MonoW32HandleType type, gpointer handle_specific); +mono_w32handle_new (MonoW32Type type, gpointer handle_specific); gpointer -mono_w32handle_duplicate (gpointer handle); +mono_w32handle_duplicate (MonoW32Handle *handle_data); gboolean mono_w32handle_close (gpointer handle); -MonoW32HandleType -mono_w32handle_get_type (gpointer handle); - const gchar* -mono_w32handle_get_typename (MonoW32HandleType type); +mono_w32handle_get_typename (MonoW32Type type); gboolean -mono_w32handle_lookup (gpointer handle, MonoW32HandleType type, gpointer *handle_specific); +mono_w32handle_lookup_and_ref (gpointer handle, MonoW32Handle **handle_data); void -mono_w32handle_foreach (gboolean (*on_each)(gpointer handle, gpointer data, gpointer user_data), gpointer user_data); +mono_w32handle_unref (MonoW32Handle *handle_data); void -mono_w32handle_dump (void); +mono_w32handle_foreach (gboolean (*on_each)(MonoW32Handle *handle_data, gpointer user_data), gpointer user_data); void -mono_w32handle_register_capabilities (MonoW32HandleType type, MonoW32HandleCapability caps); +mono_w32handle_dump (void); -gboolean -mono_w32handle_test_capabilities (gpointer handle, MonoW32HandleCapability caps); +void +mono_w32handle_register_capabilities (MonoW32Type type, MonoW32HandleCapability caps); void -mono_w32handle_set_signal_state (gpointer handle, gboolean state, gboolean broadcast); +mono_w32handle_set_signal_state (MonoW32Handle *handle_data, gboolean state, gboolean broadcast); gboolean -mono_w32handle_issignalled (gpointer handle); +mono_w32handle_issignalled (MonoW32Handle *handle_data); void -mono_w32handle_lock_handle (gpointer handle); +mono_w32handle_lock (MonoW32Handle *handle_data); gboolean -mono_w32handle_trylock_handle (gpointer handle); +mono_w32handle_trylock (MonoW32Handle *handle_data); void -mono_w32handle_unlock_handle (gpointer handle); +mono_w32handle_unlock (MonoW32Handle *handle_data); MonoW32HandleWaitRet mono_w32handle_wait_one (gpointer handle, guint32 timeout, gboolean alertable); diff --git a/mono/metadata/w32mutex-unix.c b/mono/metadata/w32mutex-unix.c index ab2ef003ddf9..d0ede1ccb18d 100644 --- a/mono/metadata/w32mutex-unix.c +++ b/mono/metadata/w32mutex-unix.c @@ -36,7 +36,7 @@ gpointer mono_w32mutex_open (const gchar* utf8_name, gint32 right G_GNUC_UNUSED, gint32 *error); static void -thread_own_mutex (MonoInternalThread *internal, gpointer handle) +thread_own_mutex (MonoInternalThread *internal, gpointer handle, MonoW32Handle *handle_data) { /* if we are not on the current thread, there is a * race condition when allocating internal->owned_mutexes */ @@ -45,7 +45,7 @@ thread_own_mutex (MonoInternalThread *internal, gpointer handle) if (!internal->owned_mutexes) internal->owned_mutexes = g_ptr_array_new (); - g_ptr_array_add (internal->owned_mutexes, mono_w32handle_duplicate (handle)); + g_ptr_array_add (internal->owned_mutexes, mono_w32handle_duplicate (handle_data)); } static void @@ -63,51 +63,51 @@ thread_disown_mutex (MonoInternalThread *internal, gpointer handle) } static void -mutex_handle_signal (gpointer handle, MonoW32HandleType type, MonoW32HandleMutex *mutex_handle) +mutex_handle_signal (MonoW32Handle *handle_data) { + MonoW32HandleMutex *mutex_handle; pthread_t tid; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: signalling %s handle %p, tid: %p recursion: %d", - __func__, mono_w32handle_get_typename (type), handle, (gpointer) mutex_handle->tid, mutex_handle->recursion); + mutex_handle = (MonoW32HandleMutex*) handle_data->specific; + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: signalling %s handle %p, tid: %p recursion: %d", + __func__, mono_w32handle_get_typename (handle_data->type), handle_data, (gpointer) mutex_handle->tid, mutex_handle->recursion); tid = pthread_self (); if (mutex_handle->abandoned) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %s handle %p is abandoned", - __func__, mono_w32handle_get_typename (type), handle); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: %s handle %p is abandoned", + __func__, mono_w32handle_get_typename (handle_data->type), handle_data); } else if (!pthread_equal (mutex_handle->tid, tid)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: we don't own %s handle %p (owned by %ld, me %ld)", - __func__, mono_w32handle_get_typename (type), handle, (long)mutex_handle->tid, (long)tid); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: we don't own %s handle %p (owned by %ld, me %ld)", + __func__, mono_w32handle_get_typename (handle_data->type), handle_data, (long)mutex_handle->tid, (long)tid); } else { /* OK, we own this mutex */ mutex_handle->recursion--; if (mutex_handle->recursion == 0) { - thread_disown_mutex (mono_thread_internal_current (), handle); + thread_disown_mutex (mono_thread_internal_current (), handle_data); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unlocking %s handle %p, tid: %p recusion : %d", - __func__, mono_w32handle_get_typename (type), handle, (gpointer) mutex_handle->tid, mutex_handle->recursion); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: unlocking %s handle %p, tid: %p recusion : %d", + __func__, mono_w32handle_get_typename (handle_data->type), handle_data, (gpointer) mutex_handle->tid, mutex_handle->recursion); mutex_handle->tid = 0; - mono_w32handle_set_signal_state (handle, TRUE, FALSE); + mono_w32handle_set_signal_state (handle_data, TRUE, FALSE); } } } static gboolean -mutex_handle_own (gpointer handle, MonoW32HandleType type, gboolean *abandoned) +mutex_handle_own (MonoW32Handle *handle_data, gboolean *abandoned) { MonoW32HandleMutex *mutex_handle; *abandoned = FALSE; - if (!mono_w32handle_lookup (handle, type, (gpointer *)&mutex_handle)) { - g_warning ("%s: error looking up %s handle %p", __func__, mono_w32handle_get_typename (type), handle); - return FALSE; - } + mutex_handle = (MonoW32HandleMutex*) handle_data->specific; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: owning %s handle %p, before: [tid: %p, recursion: %d], after: [tid: %p, recursion: %d], abandoned: %s", - __func__, mono_w32handle_get_typename (type), handle, (gpointer) mutex_handle->tid, mutex_handle->recursion, (gpointer) pthread_self (), mutex_handle->recursion + 1, mutex_handle->abandoned ? "true" : "false"); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: owning %s handle %p, before: [tid: %p, recursion: %d], after: [tid: %p, recursion: %d], abandoned: %s", + __func__, mono_w32handle_get_typename (handle_data->type), handle_data, (gpointer) mutex_handle->tid, mutex_handle->recursion, (gpointer) pthread_self (), mutex_handle->recursion + 1, mutex_handle->abandoned ? "true" : "false"); if (mutex_handle->recursion != 0) { g_assert (pthread_equal (pthread_self (), mutex_handle->tid)); @@ -116,7 +116,7 @@ mutex_handle_own (gpointer handle, MonoW32HandleType type, gboolean *abandoned) mutex_handle->tid = pthread_self (); mutex_handle->recursion = 1; - thread_own_mutex (mono_thread_internal_current (), handle); + thread_own_mutex (mono_thread_internal_current (), handle_data, handle_data); } if (mutex_handle->abandoned) { @@ -124,67 +124,33 @@ mutex_handle_own (gpointer handle, MonoW32HandleType type, gboolean *abandoned) *abandoned = TRUE; } - mono_w32handle_set_signal_state (handle, FALSE, FALSE); + mono_w32handle_set_signal_state (handle_data, FALSE, FALSE); return TRUE; } static gboolean -mutex_handle_is_owned (gpointer handle, MonoW32HandleType type) +mutex_handle_is_owned (MonoW32Handle *handle_data) { MonoW32HandleMutex *mutex_handle; - if (!mono_w32handle_lookup (handle, type, (gpointer *)&mutex_handle)) { - g_warning ("%s: error looking up %s handle %p", __func__, mono_w32handle_get_typename (type), handle); - return FALSE; - } + mutex_handle = (MonoW32HandleMutex*) handle_data->specific; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: testing ownership %s handle %p", - __func__, mono_w32handle_get_typename (type), handle); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: testing ownership %s handle %p", + __func__, mono_w32handle_get_typename (handle_data->type), handle_data); if (mutex_handle->recursion > 0 && pthread_equal (mutex_handle->tid, pthread_self ())) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %s handle %p owned by %p", - __func__, mono_w32handle_get_typename (type), handle, (gpointer) pthread_self ()); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: %s handle %p owned by %p", + __func__, mono_w32handle_get_typename (handle_data->type), handle_data, (gpointer) pthread_self ()); return TRUE; } else { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %s handle %p not owned by %p, tid: %p recursion: %d", - __func__, mono_w32handle_get_typename (type), handle, (gpointer) pthread_self (), (gpointer) mutex_handle->tid, mutex_handle->recursion); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: %s handle %p not owned by %p, tid: %p recursion: %d", + __func__, mono_w32handle_get_typename (handle_data->type), handle_data, (gpointer) pthread_self (), (gpointer) mutex_handle->tid, mutex_handle->recursion); return FALSE; } } -static void mutex_signal(gpointer handle, gpointer handle_specific) -{ - mutex_handle_signal (handle, MONO_W32HANDLE_MUTEX, (MonoW32HandleMutex*) handle_specific); -} - -static gboolean mutex_own (gpointer handle, gboolean *abandoned) -{ - return mutex_handle_own (handle, MONO_W32HANDLE_MUTEX, abandoned); -} - -static gboolean mutex_is_owned (gpointer handle) -{ - return mutex_handle_is_owned (handle, MONO_W32HANDLE_MUTEX); -} - -static void namedmutex_signal (gpointer handle, gpointer handle_specific) -{ - mutex_handle_signal (handle, MONO_W32HANDLE_NAMEDMUTEX, (MonoW32HandleMutex*) handle_specific); -} - -/* NB, always called with the shared handle lock held */ -static gboolean namedmutex_own (gpointer handle, gboolean *abandoned) -{ - return mutex_handle_own (handle, MONO_W32HANDLE_NAMEDMUTEX, abandoned); -} - -static gboolean namedmutex_is_owned (gpointer handle) -{ - return mutex_handle_is_owned (handle, MONO_W32HANDLE_NAMEDMUTEX); -} - -static void mutex_handle_prewait (gpointer handle, MonoW32HandleType type) +static void mutex_handle_prewait (MonoW32Handle *handle_data) { /* If the mutex is not currently owned, do nothing and let the * usual wait carry on. If it is owned, check that the owner @@ -194,31 +160,15 @@ static void mutex_handle_prewait (gpointer handle, MonoW32HandleType type) */ MonoW32HandleMutex *mutex_handle; - if (!mono_w32handle_lookup (handle, type, (gpointer *)&mutex_handle)) { - g_warning ("%s: error looking up %s handle %p", - __func__, mono_w32handle_get_typename (type), handle); - return; - } + mutex_handle = (MonoW32HandleMutex*) handle_data->specific; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: pre-waiting %s handle %p, owned? %s", - __func__, mono_w32handle_get_typename (type), handle, mutex_handle->recursion != 0 ? "true" : "false"); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: pre-waiting %s handle %p, owned? %s", + __func__, mono_w32handle_get_typename (handle_data->type), handle_data, mutex_handle->recursion != 0 ? "true" : "false"); } -/* The shared state is not locked when prewait methods are called */ -static void mutex_prewait (gpointer handle) +static void mutex_details (MonoW32Handle *handle_data) { - mutex_handle_prewait (handle, MONO_W32HANDLE_MUTEX); -} - -/* The shared state is not locked when prewait methods are called */ -static void namedmutex_prewait (gpointer handle) -{ - mutex_handle_prewait (handle, MONO_W32HANDLE_NAMEDMUTEX); -} - -static void mutex_details (gpointer data) -{ - MonoW32HandleMutex *mut = (MonoW32HandleMutex *)data; + MonoW32HandleMutex *mut = (MonoW32HandleMutex *)handle_data->specific; #ifdef PTHREAD_POINTER_ID g_print ("own: %5p, count: %5u", mut->tid, mut->recursion); @@ -227,9 +177,9 @@ static void mutex_details (gpointer data) #endif } -static void namedmutex_details (gpointer data) +static void namedmutex_details (MonoW32Handle *handle_data) { - MonoW32HandleNamedMutex *namedmut = (MonoW32HandleNamedMutex *)data; + MonoW32HandleNamedMutex *namedmut = (MonoW32HandleNamedMutex *)handle_data->specific; #ifdef PTHREAD_POINTER_ID g_print ("own: %5p, count: %5u, name: \"%s\"", @@ -265,11 +215,11 @@ mono_w32mutex_init (void) { static MonoW32HandleOps mutex_ops = { NULL, /* close */ - mutex_signal, /* signal */ - mutex_own, /* own */ - mutex_is_owned, /* is_owned */ + mutex_handle_signal, /* signal */ + mutex_handle_own, /* own */ + mutex_handle_is_owned, /* is_owned */ NULL, /* special_wait */ - mutex_prewait, /* prewait */ + mutex_handle_prewait, /* prewait */ mutex_details, /* details */ mutex_typename, /* typename */ mutex_typesize, /* typesize */ @@ -277,27 +227,28 @@ mono_w32mutex_init (void) static MonoW32HandleOps namedmutex_ops = { NULL, /* close */ - namedmutex_signal, /* signal */ - namedmutex_own, /* own */ - namedmutex_is_owned, /* is_owned */ + mutex_handle_signal, /* signal */ + mutex_handle_own, /* own */ + mutex_handle_is_owned, /* is_owned */ NULL, /* special_wait */ - namedmutex_prewait, /* prewait */ + mutex_handle_prewait, /* prewait */ namedmutex_details, /* details */ namedmutex_typename, /* typename */ namedmutex_typesize, /* typesize */ }; - mono_w32handle_register_ops (MONO_W32HANDLE_MUTEX, &mutex_ops); - mono_w32handle_register_ops (MONO_W32HANDLE_NAMEDMUTEX, &namedmutex_ops); + mono_w32handle_register_ops (MONO_W32TYPE_MUTEX, &mutex_ops); + mono_w32handle_register_ops (MONO_W32TYPE_NAMEDMUTEX, &namedmutex_ops); - mono_w32handle_register_capabilities (MONO_W32HANDLE_MUTEX, + mono_w32handle_register_capabilities (MONO_W32TYPE_MUTEX, (MonoW32HandleCapability)(MONO_W32HANDLE_CAP_WAIT | MONO_W32HANDLE_CAP_SIGNAL | MONO_W32HANDLE_CAP_OWN)); - mono_w32handle_register_capabilities (MONO_W32HANDLE_NAMEDMUTEX, + mono_w32handle_register_capabilities (MONO_W32TYPE_NAMEDMUTEX, (MonoW32HandleCapability)(MONO_W32HANDLE_CAP_WAIT | MONO_W32HANDLE_CAP_SIGNAL | MONO_W32HANDLE_CAP_OWN)); } -static gpointer mutex_handle_create (MonoW32HandleMutex *mutex_handle, MonoW32HandleType type, gboolean owned) +static gpointer mutex_handle_create (MonoW32HandleMutex *mutex_handle, MonoW32Type type, gboolean owned) { + MonoW32Handle *handle_data; gpointer handle; gboolean abandoned; @@ -313,16 +264,25 @@ static gpointer mutex_handle_create (MonoW32HandleMutex *mutex_handle, MonoW32Ha return NULL; } - mono_w32handle_lock_handle (handle); + if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) + g_error ("%s: unkown handle %p", __func__, handle); + + if (handle_data->type != type) + g_error ("%s: unknown mutex handle %p", __func__, handle); + + mono_w32handle_lock (handle_data); if (owned) - mutex_handle_own (handle, type, &abandoned); + mutex_handle_own (handle_data, &abandoned); else - mono_w32handle_set_signal_state (handle, TRUE, FALSE); + mono_w32handle_set_signal_state (handle_data, TRUE, FALSE); + + mono_w32handle_unlock (handle_data); - mono_w32handle_unlock_handle (handle); + /* Balance mono_w32handle_lookup_and_ref */ + mono_w32handle_unref (handle_data); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: created %s handle %p", + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: created %s handle %p", __func__, mono_w32handle_get_typename (type), handle); return handle; @@ -331,24 +291,24 @@ static gpointer mutex_handle_create (MonoW32HandleMutex *mutex_handle, MonoW32Ha static gpointer mutex_create (gboolean owned) { MonoW32HandleMutex mutex_handle; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: creating %s handle", - __func__, mono_w32handle_get_typename (MONO_W32HANDLE_MUTEX)); - return mutex_handle_create (&mutex_handle, MONO_W32HANDLE_MUTEX, owned); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: creating %s handle", + __func__, mono_w32handle_get_typename (MONO_W32TYPE_MUTEX)); + return mutex_handle_create (&mutex_handle, MONO_W32TYPE_MUTEX, owned); } static gpointer namedmutex_create (gboolean owned, const gchar *utf8_name) { gpointer handle; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: creating %s handle", - __func__, mono_w32handle_get_typename (MONO_W32HANDLE_NAMEDMUTEX)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: creating %s handle", + __func__, mono_w32handle_get_typename (MONO_W32TYPE_NAMEDMUTEX)); /* w32 seems to guarantee that opening named objects can't race each other */ mono_w32handle_namespace_lock (); glong utf8_len = strlen (utf8_name); - handle = mono_w32handle_namespace_search_handle (MONO_W32HANDLE_NAMEDMUTEX, utf8_name); + handle = mono_w32handle_namespace_search_handle (MONO_W32TYPE_NAMEDMUTEX, utf8_name); if (handle == INVALID_HANDLE_VALUE) { /* The name has already been used for a different object. */ handle = NULL; @@ -366,7 +326,7 @@ static gpointer namedmutex_create (gboolean owned, const gchar *utf8_name) memcpy (&namedmutex_handle.sharedns.name [0], utf8_name, len); namedmutex_handle.sharedns.name [len] = '\0'; - handle = mutex_handle_create ((MonoW32HandleMutex*) &namedmutex_handle, MONO_W32HANDLE_NAMEDMUTEX, owned); + handle = mutex_handle_create ((MonoW32HandleMutex*) &namedmutex_handle, MONO_W32TYPE_NAMEDMUTEX, owned); } mono_w32handle_namespace_unlock (); @@ -406,35 +366,30 @@ ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoSt MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (gpointer handle) { - MonoW32HandleType type; + MonoW32Handle *handle_data; MonoW32HandleMutex *mutex_handle; pthread_t tid; gboolean ret; - if (handle == NULL) { + if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) { + g_warning ("%s: unkown handle %p", __func__, handle); mono_w32error_set_last (ERROR_INVALID_HANDLE); return FALSE; } - switch (type = mono_w32handle_get_type (handle)) { - case MONO_W32HANDLE_MUTEX: - case MONO_W32HANDLE_NAMEDMUTEX: - break; - default: + if (handle_data->type != MONO_W32TYPE_MUTEX && handle_data->type != MONO_W32TYPE_NAMEDMUTEX) { + g_warning ("%s: unknown mutex handle %p", __func__, handle); mono_w32error_set_last (ERROR_INVALID_HANDLE); + mono_w32handle_unref (handle_data); return FALSE; } - if (!mono_w32handle_lookup (handle, type, (gpointer *)&mutex_handle)) { - g_warning ("%s: error looking up %s handle %p", - __func__, mono_w32handle_get_typename (type), handle); - return FALSE; - } + mutex_handle = (MonoW32HandleMutex*) handle_data->specific; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: releasing %s handle %p, tid: %p recursion: %d", - __func__, mono_w32handle_get_typename (type), handle, (gpointer) mutex_handle->tid, mutex_handle->recursion); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: releasing %s handle %p, tid: %p recursion: %d", + __func__, mono_w32handle_get_typename (handle_data->type), handle, (gpointer) mutex_handle->tid, mutex_handle->recursion); - mono_w32handle_lock_handle (handle); + mono_w32handle_lock (handle_data); tid = pthread_self (); @@ -444,8 +399,8 @@ ves_icall_System_Threading_Mutex_ReleaseMutex_internal (gpointer handle) } else if (!pthread_equal (mutex_handle->tid, tid)) { ret = FALSE; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: we don't own %s handle %p (owned by %ld, me %ld)", - __func__, mono_w32handle_get_typename (type), handle, (long)mutex_handle->tid, (long)tid); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: we don't own %s handle %p (owned by %ld, me %ld)", + __func__, mono_w32handle_get_typename (handle_data->type), handle, (long)mutex_handle->tid, (long)tid); } else { ret = TRUE; @@ -455,15 +410,16 @@ ves_icall_System_Threading_Mutex_ReleaseMutex_internal (gpointer handle) if (mutex_handle->recursion == 0) { thread_disown_mutex (mono_thread_internal_current (), handle); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unlocking %s handle %p, tid: %p recusion : %d", - __func__, mono_w32handle_get_typename (type), handle, (gpointer) mutex_handle->tid, mutex_handle->recursion); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: unlocking %s handle %p, tid: %p recusion : %d", + __func__, mono_w32handle_get_typename (handle_data->type), handle, (gpointer) mutex_handle->tid, mutex_handle->recursion); mutex_handle->tid = 0; - mono_w32handle_set_signal_state (handle, TRUE, FALSE); + mono_w32handle_set_signal_state (handle_data, TRUE, FALSE); } } - mono_w32handle_unlock_handle (handle); + mono_w32handle_unlock (handle_data); + mono_w32handle_unref (handle_data); return ret; } @@ -489,10 +445,10 @@ mono_w32mutex_open (const gchar* utf8_name, gint32 right G_GNUC_UNUSED, gint32 * /* w32 seems to guarantee that opening named objects can't race each other */ mono_w32handle_namespace_lock (); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Opening named mutex [%s]", + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: Opening named mutex [%s]", __func__, utf8_name); - handle = mono_w32handle_namespace_search_handle (MONO_W32HANDLE_NAMEDMUTEX, utf8_name); + handle = mono_w32handle_namespace_search_handle (MONO_W32TYPE_NAMEDMUTEX, utf8_name); if (handle == INVALID_HANDLE_VALUE) { /* The name has already been used for a different object. */ *error = ERROR_INVALID_HANDLE; @@ -503,7 +459,7 @@ mono_w32mutex_open (const gchar* utf8_name, gint32 right G_GNUC_UNUSED, gint32 * goto cleanup; } - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning named mutex handle %p", + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: returning named mutex handle %p", __func__, handle); cleanup: @@ -526,28 +482,23 @@ mono_w32mutex_abandon (void) return; while (internal->owned_mutexes->len) { - MonoW32HandleType type; + MonoW32Handle *handle_data; MonoW32HandleMutex *mutex_handle; MonoNativeThreadId tid; gpointer handle; handle = g_ptr_array_index (internal->owned_mutexes, 0); - switch (type = mono_w32handle_get_type (handle)) { - case MONO_W32HANDLE_MUTEX: - case MONO_W32HANDLE_NAMEDMUTEX: - break; - default: - g_assert_not_reached (); - } + if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) + g_error ("%s: unkown handle %p", __func__, handle); - if (!mono_w32handle_lookup (handle, type, (gpointer *)&mutex_handle)) { - g_error ("%s: error looking up %s handle %p", - __func__, mono_w32handle_get_typename (type), handle); - } + if (handle_data->type != MONO_W32TYPE_MUTEX && handle_data->type != MONO_W32TYPE_NAMEDMUTEX) + g_error ("%s: unkown mutex handle %p", __func__, handle); + + mutex_handle = (MonoW32HandleMutex*) handle_data->specific; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: abandoning %s handle %p", - __func__, mono_w32handle_get_typename (type), handle); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: abandoning %s handle %p", + __func__, mono_w32handle_get_typename (handle_data->type), handle); tid = MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid); @@ -555,20 +506,21 @@ mono_w32mutex_abandon (void) g_error ("%s: trying to release mutex %p acquired by thread %p from thread %p", __func__, handle, (gpointer) mutex_handle->tid, (gpointer) tid); - mono_w32handle_lock_handle (handle); + mono_w32handle_lock (handle_data); mutex_handle->recursion = 0; mutex_handle->tid = 0; mutex_handle->abandoned = TRUE; - mono_w32handle_set_signal_state (handle, TRUE, FALSE); + mono_w32handle_set_signal_state (handle_data, TRUE, FALSE); thread_disown_mutex (internal, handle); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: abandoned %s handle %p", - __func__, mono_w32handle_get_typename (type), handle); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: abandoned %s handle %p", + __func__, mono_w32handle_get_typename (handle_data->type), handle); - mono_w32handle_unlock_handle (handle); + mono_w32handle_unlock (handle_data); + mono_w32handle_unref (handle_data); } g_ptr_array_free (internal->owned_mutexes, TRUE); diff --git a/mono/metadata/w32process-unix-bsd.c b/mono/metadata/w32process-unix-bsd.c index e67cec6b2d19..34eac0459e69 100644 --- a/mono/metadata/w32process-unix-bsd.c +++ b/mono/metadata/w32process-unix-bsd.c @@ -35,7 +35,7 @@ mono_w32process_get_name (pid_t pid) mib [2] = KERN_PROC_PID; mib [3] = pid; if (sysctl(mib, 4, NULL, &size, NULL, 0) < 0) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: sysctl() failed: %d", __func__, errno); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: sysctl() failed: %d", __func__, errno); return NULL; } @@ -45,7 +45,7 @@ mono_w32process_get_name (pid_t pid) if (sysctl (mib, 4, pi, &size, NULL, 0) < 0) { if (errno == ENOMEM) { g_free (pi); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Didn't allocate enough memory for kproc info", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Didn't allocate enough memory for kproc info", __func__); } return NULL; } @@ -63,7 +63,7 @@ mono_w32process_get_name (pid_t pid) retry: if (sysctl(mib, 6, NULL, &size, NULL, 0) < 0) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: sysctl() failed: %d", __func__, errno); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: sysctl() failed: %d", __func__, errno); return NULL; } @@ -134,7 +134,7 @@ mono_w32process_get_modules (pid_t pid) mod->inode = i; mod->filename = g_strdup (info->dlpi_name); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: inode=%d, filename=%s, address_start=%p, address_end=%p", + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: inode=%d, filename=%s, address_start=%p, address_end=%p", __func__, mod->inode, mod->filename, mod->address_start, mod->address_end); g_free (info); diff --git a/mono/metadata/w32process-unix-default.c b/mono/metadata/w32process-unix-default.c index 91e1d218ad5d..0ea952a0c1ba 100644 --- a/mono/metadata/w32process-unix-default.c +++ b/mono/metadata/w32process-unix-default.c @@ -153,7 +153,7 @@ mono_w32process_get_modules (pid_t pid) fp = open_process_map (pid, "r"); if (!fp) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't open process map file for pid %d", __func__, pid); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Can't open process map file for pid %d", __func__, pid); return NULL; } diff --git a/mono/metadata/w32process-unix-osx.c b/mono/metadata/w32process-unix-osx.c index 481d228dd204..790fd0283498 100644 --- a/mono/metadata/w32process-unix-osx.c +++ b/mono/metadata/w32process-unix-osx.c @@ -47,7 +47,7 @@ mono_w32process_get_name (pid_t pid) if (sysctl (mib, 4, pi, &size, NULL, 0) < 0) { if (errno == ENOMEM) { g_free (pi); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Didn't allocate enough memory for kproc info", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Didn't allocate enough memory for kproc info", __func__); } return(ret); } @@ -64,7 +64,7 @@ mono_w32process_get_name (pid_t pid) memset (buf, '\0', sizeof(buf)); res = proc_name (pid, buf, sizeof(buf)); if (res == 0) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: proc_name failed, error (%d) \"%s\"", __func__, errno, g_strerror (errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: proc_name failed, error (%d) \"%s\"", __func__, errno, g_strerror (errno)); return NULL; } diff --git a/mono/metadata/w32process-unix.c b/mono/metadata/w32process-unix.c index 9b3eec735f38..48d5e7af8465 100644 --- a/mono/metadata/w32process-unix.c +++ b/mono/metadata/w32process-unix.c @@ -134,7 +134,7 @@ typedef struct { */ typedef struct _Process { pid_t pid; /* the pid of the process. This value is only valid until the process has exited. */ - MonoSemType exit_sem; /* this semaphore will be released when the process exits */ + MonoCoopSem exit_sem; /* this semaphore will be released when the process exits */ int status; /* the exit status */ gint32 handle_count; /* the number of handles to this process instance */ /* we keep a ref to the creating _WapiHandle_process handle until @@ -528,7 +528,7 @@ static mono_lazy_init_t process_sig_chld_once = MONO_LAZY_INIT_STATUS_NOT_INITIA static gchar *cli_launcher; static Process *processes; -static mono_mutex_t processes_mutex; +static MonoCoopMutex processes_mutex; static pid_t current_pid; static gpointer current_process; @@ -566,9 +566,9 @@ process_is_alive (pid_t pid) } static void -process_details (gpointer data) +process_details (MonoW32Handle *handle_data) { - MonoW32HandleProcess *process_handle = (MonoW32HandleProcess *) data; + MonoW32HandleProcess *process_handle = (MonoW32HandleProcess *) handle_data->specific; g_print ("pid: %d, exited: %s, exitstatus: %d", process_handle->pid, process_handle->exited ? "true" : "false", process_handle->exitstatus); } @@ -586,55 +586,50 @@ process_typesize (void) } static MonoW32HandleWaitRet -process_wait (gpointer handle, guint32 timeout, gboolean *alerted) +process_wait (MonoW32Handle *handle_data, guint32 timeout, gboolean *alerted) { MonoW32HandleProcess *process_handle; pid_t pid G_GNUC_UNUSED, ret; int status; gint64 start, now; Process *process; - gboolean res; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %" G_GUINT32_FORMAT ")", __func__, handle, timeout); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s (%p, %" G_GUINT32_FORMAT ")", __func__, handle_data, timeout); if (alerted) *alerted = FALSE; - res = mono_w32handle_lookup (handle, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle); - if (!res) { - g_warning ("%s: error looking up process handle %p", __func__, handle); - return MONO_W32HANDLE_WAIT_RET_FAILED; - } + process_handle = (MonoW32HandleProcess*) handle_data->specific; if (process_handle->exited) { /* We've already done this one */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %" G_GUINT32_FORMAT "): Process already exited", __func__, handle, timeout); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s (%p, %" G_GUINT32_FORMAT "): Process already exited", __func__, handle_data, timeout); return MONO_W32HANDLE_WAIT_RET_SUCCESS_0; } pid = process_handle->pid; if (pid == mono_process_current_pid ()) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %" G_GUINT32_FORMAT "): waiting on current process", __func__, handle, timeout); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s (%p, %" G_GUINT32_FORMAT "): waiting on current process", __func__, handle_data, timeout); return MONO_W32HANDLE_WAIT_RET_TIMEOUT; } - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %" G_GUINT32_FORMAT "): PID: %d", __func__, handle, timeout, pid); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s (%p, %" G_GUINT32_FORMAT "): PID: %d", __func__, handle_data, timeout, pid); if (!process_handle->child) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %" G_GUINT32_FORMAT "): waiting on non-child process", __func__, handle, timeout); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s (%p, %" G_GUINT32_FORMAT "): waiting on non-child process", __func__, handle_data, timeout); if (!process_is_alive (pid)) { /* assume the process has exited */ process_handle->exited = TRUE; process_handle->exitstatus = -1; - mono_w32handle_set_signal_state (handle, TRUE, TRUE); + mono_w32handle_set_signal_state (handle_data, TRUE, TRUE); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %" G_GUINT32_FORMAT "): non-child process is not alive anymore (2)", __func__, handle, timeout); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s (%p, %" G_GUINT32_FORMAT "): non-child process is not alive anymore (2)", __func__, handle_data, timeout); return MONO_W32HANDLE_WAIT_RET_SUCCESS_0; } - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %" G_GUINT32_FORMAT "): non-child process wait failed, error : %s (%d))", __func__, handle, timeout, g_strerror (errno), errno); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s (%p, %" G_GUINT32_FORMAT "): non-child process wait failed, error : %s (%d))", __func__, handle_data, timeout, g_strerror (errno), errno); return MONO_W32HANDLE_WAIT_RET_FAILED; } @@ -648,41 +643,41 @@ process_wait (gpointer handle, guint32 timeout, gboolean *alerted) while (1) { if (timeout != MONO_INFINITE_WAIT) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %" G_GUINT32_FORMAT "): waiting on semaphore for %" G_GINT64_FORMAT " ms...", - __func__, handle, timeout, timeout - (now - start)); - ret = mono_os_sem_timedwait (&process->exit_sem, (timeout - (now - start)), alerted ? MONO_SEM_FLAGS_ALERTABLE : MONO_SEM_FLAGS_NONE); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s (%p, %" G_GUINT32_FORMAT "): waiting on semaphore for %" G_GINT64_FORMAT " ms...", + __func__, handle_data, timeout, timeout - (now - start)); + ret = mono_coop_sem_timedwait (&process->exit_sem, (timeout - (now - start)), alerted ? MONO_SEM_FLAGS_ALERTABLE : MONO_SEM_FLAGS_NONE); } else { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %" G_GUINT32_FORMAT "): waiting on semaphore forever...", - __func__, handle, timeout); - ret = mono_os_sem_wait (&process->exit_sem, alerted ? MONO_SEM_FLAGS_ALERTABLE : MONO_SEM_FLAGS_NONE); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s (%p, %" G_GUINT32_FORMAT "): waiting on semaphore forever...", + __func__, handle_data, timeout); + ret = mono_coop_sem_wait (&process->exit_sem, alerted ? MONO_SEM_FLAGS_ALERTABLE : MONO_SEM_FLAGS_NONE); } if (ret == MONO_SEM_TIMEDWAIT_RET_SUCCESS) { /* Success, process has exited */ - mono_os_sem_post (&process->exit_sem); + mono_coop_sem_post (&process->exit_sem); break; } if (ret == MONO_SEM_TIMEDWAIT_RET_TIMEDOUT) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %" G_GUINT32_FORMAT "): wait timeout (timeout = 0)", __func__, handle, timeout); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s (%p, %" G_GUINT32_FORMAT "): wait timeout (timeout = 0)", __func__, handle_data, timeout); return MONO_W32HANDLE_WAIT_RET_TIMEOUT; } now = mono_msec_ticks (); if (now - start >= timeout) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %" G_GUINT32_FORMAT "): wait timeout", __func__, handle, timeout); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s (%p, %" G_GUINT32_FORMAT "): wait timeout", __func__, handle_data, timeout); return MONO_W32HANDLE_WAIT_RET_TIMEOUT; } if (alerted && ret == MONO_SEM_TIMEDWAIT_RET_ALERTED) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %" G_GUINT32_FORMAT "): wait alerted", __func__, handle, timeout); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s (%p, %" G_GUINT32_FORMAT "): wait alerted", __func__, handle_data, timeout); *alerted = TRUE; return MONO_W32HANDLE_WAIT_RET_ALERTED; } } /* Process must have exited */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %" G_GUINT32_FORMAT "): Waited successfully", __func__, handle, timeout); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s (%p, %" G_GUINT32_FORMAT "): Waited successfully", __func__, handle_data, timeout); status = process->status; if (WIFSIGNALED (status)) @@ -694,10 +689,10 @@ process_wait (gpointer handle, guint32 timeout, gboolean *alerted) process_handle->exited = TRUE; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %" G_GUINT32_FORMAT "): Setting pid %d signalled, exit status %d", - __func__, handle, timeout, process_handle->pid, process_handle->exitstatus); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s (%p, %" G_GUINT32_FORMAT "): Setting pid %d signalled, exit status %d", + __func__, handle_data, timeout, process_handle->pid, process_handle->exitstatus); - mono_w32handle_set_signal_state (handle, TRUE, TRUE); + mono_w32handle_set_signal_state (handle_data, TRUE, TRUE); return MONO_W32HANDLE_WAIT_RET_SUCCESS_0; } @@ -709,7 +704,7 @@ processes_cleanup (void) Process *process; Process *prev = NULL; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s", __func__); /* Ensure we're not in here in multiple threads at once, nor recursive. */ if (mono_atomic_cas_i32 (&cleaning_up, 1, 0) != 0) @@ -727,7 +722,7 @@ processes_cleanup (void) } } - mono_os_mutex_lock (&processes_mutex); + mono_coop_mutex_lock (&processes_mutex); for (process = processes; process;) { Process *next = process->next; @@ -740,7 +735,7 @@ processes_cleanup (void) else prev->next = process->next; - mono_os_sem_destroy (&process->exit_sem); + mono_coop_sem_destroy (&process->exit_sem); g_free (process); } else { prev = process; @@ -748,9 +743,9 @@ processes_cleanup (void) process = next; } - mono_os_mutex_unlock (&processes_mutex); + mono_coop_mutex_unlock (&processes_mutex); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s done", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s done", __func__); mono_atomic_xchg_i32 (&cleaning_up, 0); } @@ -760,7 +755,7 @@ process_close (gpointer handle, gpointer data) { MonoW32HandleProcess *process_handle; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s", __func__); process_handle = (MonoW32HandleProcess *) data; g_free (process_handle->pname); @@ -800,7 +795,7 @@ process_set_name (MonoW32HandleProcess *process_handle) progname = g_get_prgname (); utf8_progname = mono_utf8_from_external (progname); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: using [%s] as prog name", __func__, progname); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: using [%s] as prog name", __func__, progname); if (utf8_progname) { slash = strrchr (utf8_progname, '/'); @@ -817,9 +812,9 @@ mono_w32process_init (void) { MonoW32HandleProcess process_handle; - mono_w32handle_register_ops (MONO_W32HANDLE_PROCESS, &process_ops); + mono_w32handle_register_ops (MONO_W32TYPE_PROCESS, &process_ops); - mono_w32handle_register_capabilities (MONO_W32HANDLE_PROCESS, + mono_w32handle_register_capabilities (MONO_W32TYPE_PROCESS, (MonoW32HandleCapability)(MONO_W32HANDLE_CAP_WAIT | MONO_W32HANDLE_CAP_SPECIAL_WAIT)); current_pid = getpid (); @@ -829,10 +824,10 @@ mono_w32process_init (void) process_set_defaults (&process_handle); process_set_name (&process_handle); - current_process = mono_w32handle_new (MONO_W32HANDLE_PROCESS, &process_handle); + current_process = mono_w32handle_new (MONO_W32TYPE_PROCESS, &process_handle); g_assert (current_process != INVALID_HANDLE_VALUE); - mono_os_mutex_init (&processes_mutex); + mono_coop_mutex_init (&processes_mutex); } void @@ -888,16 +883,27 @@ utf16_concat (const gunichar2 *first, ...) guint32 mono_w32process_get_pid (gpointer handle) { - MonoW32HandleProcess *process_handle; - gboolean res; + MonoW32Handle *handle_data; + guint32 ret; + + if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: unknown handle %p", __func__, handle); + mono_w32error_set_last (ERROR_INVALID_HANDLE); + return 0; + } - res = mono_w32handle_lookup (handle, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle); - if (!res) { + if (handle_data->type != MONO_W32TYPE_PROCESS) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: unknown process handle %p", __func__, handle); mono_w32error_set_last (ERROR_INVALID_HANDLE); + mono_w32handle_unref (handle_data); return 0; } - return process_handle->pid; + ret = ((MonoW32HandleProcess*) handle_data->specific)->pid; + + mono_w32handle_unref (handle_data); + + return ret; } typedef struct { @@ -906,34 +912,34 @@ typedef struct { } GetProcessForeachData; static gboolean -get_process_foreach_callback (gpointer handle, gpointer handle_specific, gpointer user_data) +get_process_foreach_callback (MonoW32Handle *handle_data, gpointer user_data) { GetProcessForeachData *foreach_data; MonoW32HandleProcess *process_handle; pid_t pid; - foreach_data = (GetProcessForeachData*) user_data; - - if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_PROCESS) + if (handle_data->type != MONO_W32TYPE_PROCESS) return FALSE; - process_handle = (MonoW32HandleProcess*) handle_specific; + process_handle = (MonoW32HandleProcess*) handle_data->specific; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: looking at process %d", __func__, process_handle->pid); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: looking at process %d", __func__, process_handle->pid); pid = process_handle->pid; if (pid == 0) return FALSE; + foreach_data = (GetProcessForeachData*) user_data; + /* It's possible to have more than one process handle with the * same pid, but only the one running process can be * unsignalled. */ if (foreach_data->pid != pid) return FALSE; - if (mono_w32handle_issignalled (handle)) + if (mono_w32handle_issignalled (handle_data)) return FALSE; - foreach_data->handle = mono_w32handle_duplicate (handle); + foreach_data->handle = mono_w32handle_duplicate (handle_data); return TRUE; } @@ -943,7 +949,7 @@ ves_icall_System_Diagnostics_Process_GetProcess_internal (guint32 pid) GetProcessForeachData foreach_data; gpointer handle; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: looking for process %d", __func__, pid); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: looking for process %d", __func__, pid); memset (&foreach_data, 0, sizeof (foreach_data)); foreach_data.pid = pid; @@ -962,7 +968,7 @@ ves_icall_System_Diagnostics_Process_GetProcess_internal (guint32 pid) process_handle.pid = pid; process_handle.pname = mono_w32process_get_name (pid); - handle = mono_w32handle_new (MONO_W32HANDLE_PROCESS, &process_handle); + handle = mono_w32handle_new (MONO_W32TYPE_PROCESS, &process_handle); if (handle == INVALID_HANDLE_VALUE) { g_warning ("%s: error creating process handle", __func__); @@ -973,7 +979,7 @@ ves_icall_System_Diagnostics_Process_GetProcess_internal (guint32 pid) return handle; } - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find pid %d", __func__, pid); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Can't find pid %d", __func__, pid); mono_w32error_set_last (ERROR_PROC_NOT_FOUND); return NULL; @@ -991,7 +997,7 @@ match_procname_to_modulename (char *procname, char *modulename) if (procname == NULL || modulename == NULL) return (FALSE); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: procname=\"%s\", modulename=\"%s\"", __func__, procname, modulename); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: procname=\"%s\", modulename=\"%s\"", __func__, procname, modulename); pname = mono_path_resolve_symlinks (procname); mname = mono_path_resolve_symlinks (modulename); @@ -1020,13 +1026,14 @@ match_procname_to_modulename (char *procname, char *modulename) g_free (pname); g_free (mname); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: result is %" G_GINT32_FORMAT, __func__, result); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: result is %" G_GINT32_FORMAT, __func__, result); return result; } gboolean -mono_w32process_try_get_modules (gpointer process, gpointer *modules, guint32 size, guint32 *needed) +mono_w32process_try_get_modules (gpointer handle, gpointer *modules, guint32 size, guint32 *needed) { + MonoW32Handle *handle_data; MonoW32HandleProcess *process_handle; GSList *mods = NULL, *mods_iter; MonoW32ProcessModule *module; @@ -1034,7 +1041,6 @@ mono_w32process_try_get_modules (gpointer process, gpointer *modules, guint32 si int i; pid_t pid; char *pname = NULL; - gboolean res; /* Store modules in an array of pointers (main module as * modules[0]), using the load address for each module as a @@ -1048,18 +1054,28 @@ mono_w32process_try_get_modules (gpointer process, gpointer *modules, guint32 si if (size < sizeof(gpointer)) return FALSE; - res = mono_w32handle_lookup (process, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle); - if (!res) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find process %p", __func__, process); + if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: unknown handle %p", __func__, handle); + mono_w32error_set_last (ERROR_INVALID_HANDLE); + return FALSE; + } + + if (handle_data->type != MONO_W32TYPE_PROCESS) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: unknown process handle %p", __func__, handle); + mono_w32error_set_last (ERROR_INVALID_HANDLE); + mono_w32handle_unref (handle_data); return FALSE; } + process_handle = (MonoW32HandleProcess*) handle_data->specific; + pid = process_handle->pid; pname = g_strdup (process_handle->pname); if (!pname) { modules[0] = NULL; *needed = sizeof(gpointer); + mono_w32handle_unref (handle_data); return TRUE; } @@ -1068,6 +1084,7 @@ mono_w32process_try_get_modules (gpointer process, gpointer *modules, guint32 si modules[0] = NULL; *needed = sizeof(gpointer); g_free (pname); + mono_w32handle_unref (handle_data); return TRUE; } @@ -1103,12 +1120,12 @@ mono_w32process_try_get_modules (gpointer process, gpointer *modules, guint32 si g_slist_free (mods); g_free (pname); - + mono_w32handle_unref (handle_data); return TRUE; } guint32 -mono_w32process_module_get_filename (gpointer process, gpointer module, gunichar2 *basename, guint32 size) +mono_w32process_module_get_filename (gpointer handle, gpointer module, gunichar2 *basename, guint32 size) { gint pid, len; gsize bytes; @@ -1120,7 +1137,7 @@ mono_w32process_module_get_filename (gpointer process, gpointer module, gunichar if (basename == NULL || size == 0) return 0; - pid = mono_w32process_get_pid (process); + pid = mono_w32process_get_pid (handle); path = mono_w32process_get_path (pid); if (path == NULL) @@ -1138,10 +1155,10 @@ mono_w32process_module_get_filename (gpointer process, gpointer module, gunichar bytes += 2; if (size < bytes) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Size %" G_GUINT32_FORMAT " smaller than needed (%zd); truncating", __func__, size, bytes); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Size %" G_GUINT32_FORMAT " smaller than needed (%zd); truncating", __func__, size, bytes); memcpy (basename, proc_path, size); } else { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Size %" G_GUINT32_FORMAT " larger than needed (%zd)", __func__, size, bytes); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Size %" G_GUINT32_FORMAT " larger than needed (%zd)", __func__, size, bytes); memcpy (basename, proc_path, bytes); } @@ -1151,8 +1168,9 @@ mono_w32process_module_get_filename (gpointer process, gpointer module, gunichar } guint32 -mono_w32process_module_get_name (gpointer process, gpointer module, gunichar2 *basename, guint32 size) +mono_w32process_module_get_name (gpointer handle, gpointer module, gunichar2 *basename, guint32 size) { + MonoW32Handle *handle_data; MonoW32HandleProcess *process_handle; pid_t pid; gunichar2 *procname; @@ -1162,29 +1180,38 @@ mono_w32process_module_get_name (gpointer process, gpointer module, gunichar2 *b GSList *mods = NULL, *mods_iter; MonoW32ProcessModule *found_module; char *pname = NULL; - gboolean res; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Getting module base name, process handle %p module %p basename %p size %" G_GUINT32_FORMAT, - __func__, process, module, basename, size); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Getting module base name, process handle %p module %p basename %p size %" G_GUINT32_FORMAT, + __func__, handle, module, basename, size); size = size * sizeof (gunichar2); /* adjust for unicode characters */ if (basename == NULL || size == 0) return 0; - res = mono_w32handle_lookup (process, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle); - if (!res) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find process %p", __func__, process); + if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: unknown handle %p", __func__, handle); + mono_w32error_set_last (ERROR_INVALID_HANDLE); return 0; } + if (handle_data->type != MONO_W32TYPE_PROCESS) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: unknown process handle %p", __func__, handle); + mono_w32error_set_last (ERROR_INVALID_HANDLE); + mono_w32handle_unref (handle_data); + return 0; + } + + process_handle = (MonoW32HandleProcess*) handle_data->specific; + pid = process_handle->pid; pname = g_strdup (process_handle->pname); mods = mono_w32process_get_modules (pid); if (!mods && module != NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't get modules %p", __func__, process); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Can't get modules %p", __func__, handle); g_free (pname); + mono_w32handle_unref (handle_data); return 0; } @@ -1204,28 +1231,29 @@ mono_w32process_module_get_name (gpointer process, gpointer module, gunichar2 *b } if (procname_ext == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find procname_ext from procmods %p", __func__, process); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Can't find procname_ext from procmods %p", __func__, handle); /* 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 = mono_w32process_get_name (pid); if (!procname_ext) - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find procname_ext from proc_get_name %p pid %d", __func__, process, pid); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Can't find procname_ext from proc_get_name %p pid %d", __func__, handle, pid); } g_slist_free (mods); g_free (pname); if (procname_ext) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Process name is [%s]", __func__, + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Process name is [%s]", __func__, procname_ext); procname = mono_unicode_from_external (procname_ext, &bytes); if (procname == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't get procname %p", __func__, process); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Can't get procname %p", __func__, handle); /* bugger */ g_free (procname_ext); + mono_w32handle_unref (handle_data); return 0; } @@ -1235,11 +1263,11 @@ mono_w32process_module_get_name (gpointer process, gpointer module, gunichar2 *b bytes += 2; if (size < bytes) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Size %" G_GUINT32_FORMAT " smaller than needed (%zd); truncating", __func__, size, bytes); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Size %" G_GUINT32_FORMAT " smaller than needed (%zd); truncating", __func__, size, bytes); memcpy (basename, procname, size); } else { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Size %" G_GUINT32_FORMAT " larger than needed (%zd)", + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Size %" G_GUINT32_FORMAT " larger than needed (%zd)", __func__, size, bytes); memcpy (basename, procname, bytes); @@ -1248,42 +1276,54 @@ mono_w32process_module_get_name (gpointer process, gpointer module, gunichar2 *b g_free (procname); g_free (procname_ext); + mono_w32handle_unref (handle_data); return len; } - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find procname_ext %p", __func__, process); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Can't find procname_ext %p", __func__, handle); + mono_w32handle_unref (handle_data); return 0; } gboolean -mono_w32process_module_get_information (gpointer process, gpointer module, MODULEINFO *modinfo, guint32 size) +mono_w32process_module_get_information (gpointer handle, gpointer module, MODULEINFO *modinfo, guint32 size) { + MonoW32Handle *handle_data; MonoW32HandleProcess *process_handle; pid_t pid; GSList *mods = NULL, *mods_iter; MonoW32ProcessModule *found_module; gboolean ret = FALSE; char *pname = NULL; - gboolean res; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Getting module info, process handle %p module %p", - __func__, process, module); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Getting module info, process handle %p module %p", + __func__, handle, module); if (modinfo == NULL || size < sizeof (MODULEINFO)) return FALSE; - res = mono_w32handle_lookup (process, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle); - if (!res) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find process %p", __func__, process); + if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: unknown handle %p", __func__, handle); + mono_w32error_set_last (ERROR_INVALID_HANDLE); + return FALSE; + } + + if (handle_data->type != MONO_W32TYPE_PROCESS) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: unknown process handle %p", __func__, handle); + mono_w32error_set_last (ERROR_INVALID_HANDLE); + mono_w32handle_unref (handle_data); return FALSE; } + process_handle = (MonoW32HandleProcess*) handle_data->specific; + pid = process_handle->pid; pname = g_strdup (process_handle->pname); mods = mono_w32process_get_modules (pid); if (!mods) { g_free (pname); + mono_w32handle_unref (handle_data); return FALSE; } @@ -1307,7 +1347,7 @@ mono_w32process_module_get_information (gpointer process, gpointer module, MODUL g_slist_free (mods); g_free (pname); - + mono_w32handle_unref (handle_data); return ret; } @@ -1348,7 +1388,7 @@ process_add_sigchld_handler (void) sigemptyset (&sa.sa_mask); sa.sa_flags = SA_NOCLDSTOP | SA_SIGINFO | SA_RESTART; g_assert (sigaction (SIGCHLD, &sa, NULL) != -1); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "Added SIGCHLD handler"); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "Added SIGCHLD handler"); } #endif @@ -1373,7 +1413,7 @@ mono_w32process_signal_finished (void) if (pid <= 0) break; - mono_os_mutex_lock (&processes_mutex); + mono_coop_mutex_lock (&processes_mutex); for (process = processes; process; process = process->next) { if (process->pid != pid) @@ -1383,11 +1423,11 @@ mono_w32process_signal_finished (void) process->signalled = TRUE; process->status = status; - mono_os_sem_post (&process->exit_sem); + mono_coop_sem_post (&process->exit_sem); break; } - mono_os_mutex_unlock (&processes_mutex); + mono_coop_mutex_unlock (&processes_mutex); } while (1); } @@ -1598,7 +1638,7 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline, if (appname != NULL) { cmd = mono_unicode_to_external (appname); if (cmd == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: unicode conversion returned NULL", __func__); mono_w32error_set_last (ERROR_PATH_NOT_FOUND); @@ -1611,7 +1651,7 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline, if (cmdline != NULL) { args = mono_unicode_to_external (cmdline); if (args == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: unicode conversion returned NULL", __func__); mono_w32error_set_last (ERROR_PATH_NOT_FOUND); goto free_strings; @@ -1621,7 +1661,7 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline, if (cwd != NULL) { dir = mono_unicode_to_external (cwd); if (dir == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: unicode conversion returned NULL", __func__); mono_w32error_set_last (ERROR_PATH_NOT_FOUND); goto free_strings; @@ -1651,7 +1691,7 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline, /* Executable existing ? */ if (!is_readable_or_executable (prog)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Couldn't find executable %s", + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Couldn't find executable %s", __func__, prog); g_free (unquoted); mono_w32error_set_last (ERROR_FILE_NOT_FOUND); @@ -1668,7 +1708,7 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline, /* And make sure it's readable */ if (!is_readable_or_executable (prog)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Couldn't find executable %s", + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Couldn't find executable %s", __func__, prog); g_free (unquoted); mono_w32error_set_last (ERROR_FILE_NOT_FOUND); @@ -1733,7 +1773,7 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline, if (token == NULL) { /* Give up */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Couldn't find what to exec", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Couldn't find what to exec", __func__); mono_w32error_set_last (ERROR_PATH_NOT_FOUND); goto free_strings; @@ -1759,7 +1799,7 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline, /* Executable existing ? */ if (!is_readable_or_executable (prog)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Couldn't find executable %s", + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Couldn't find executable %s", __func__, token); g_free (token); mono_w32error_set_last (ERROR_FILE_NOT_FOUND); @@ -1786,7 +1826,7 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline, g_free (prog); prog = g_find_program_in_path (token); if (prog == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Couldn't find executable %s", __func__, token); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Couldn't find executable %s", __func__, token); g_free (token); mono_w32error_set_last (ERROR_FILE_NOT_FOUND); @@ -1798,7 +1838,7 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline, g_free (token); } - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Exec prog [%s] args [%s]", + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Exec prog [%s] args [%s]", __func__, prog, args_after_prog); /* Check for CLR binaries; if found, we will try to invoke @@ -1827,7 +1867,7 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline, } } else { if (!is_executable (prog)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Executable permisson not set on %s", __func__, prog); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Executable permisson not set on %s", __func__, prog); mono_w32error_set_last (ERROR_ACCESS_DENIED); goto free_strings; } @@ -1919,7 +1959,7 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline, /* Could not create the pipe to synchroniz process startup. We'll just not synchronize. * This is just for a very hard to hit race condition in the first place */ startup_pipe [0] = startup_pipe [1] = -1; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: new process startup not synchronized. We may not notice if the newly created process exits immediately.", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: new process startup not synchronized. We may not notice if the newly created process exits immediately.", __func__); } switch (pid = fork ()) { @@ -1932,7 +1972,7 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline, if (startup_pipe [0] != -1) { /* Wait until the parent has updated it's internal data */ ssize_t _i G_GNUC_UNUSED = read (startup_pipe [0], &dummy, 1); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: child: parent has completed its setup", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: child: parent has completed its setup", __func__); close (startup_pipe [0]); close (startup_pipe [1]); } @@ -1949,7 +1989,7 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline, close (i); #ifdef DEBUG_ENABLED - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: exec()ing [%s] in dir [%s]", __func__, cmd, + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: exec()ing [%s] in dir [%s]", __func__, cmd, dir == NULL?".":dir); for (i = 0; argv[i] != NULL; i++) g_message ("arg %" G_GUINT32_FORMAT ": [%s]", i, argv[i]); @@ -1973,6 +2013,7 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline, break; } default: /* Parent */ { + MonoW32Handle *handle_data; MonoW32HandleProcess process_handle; memset (&process_handle, 0, sizeof (process_handle)); @@ -1985,15 +2026,15 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline, process = (Process *) g_malloc0 (sizeof (Process)); process->pid = pid; process->handle_count = 1; - mono_os_sem_init (&process->exit_sem, 0); + mono_coop_sem_init (&process->exit_sem, 0); process_handle.process = process; - handle = mono_w32handle_new (MONO_W32HANDLE_PROCESS, &process_handle); + handle = mono_w32handle_new (MONO_W32TYPE_PROCESS, &process_handle); if (handle == INVALID_HANDLE_VALUE) { g_warning ("%s: error creating process handle", __func__); - mono_os_sem_destroy (&process->exit_sem); + mono_coop_sem_destroy (&process->exit_sem); g_free (process); mono_w32error_set_last (ERROR_OUTOFMEMORY); @@ -2001,15 +2042,21 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline, break; } + if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) + g_error ("%s: unknown handle %p", __func__, handle); + + if (handle_data->type != MONO_W32TYPE_PROCESS) + g_error ("%s: unknown process handle %p", __func__, handle); + /* Keep the process handle artificially alive until the process * exits so that the information in the handle isn't lost. */ - process->handle = mono_w32handle_duplicate (handle); + process->handle = mono_w32handle_duplicate (handle_data); - mono_os_mutex_lock (&processes_mutex); + mono_coop_mutex_lock (&processes_mutex); process->next = processes; mono_memory_barrier (); processes = process; - mono_os_mutex_unlock (&processes_mutex); + mono_coop_mutex_unlock (&processes_mutex); if (process_info != NULL) { process_info->process_handle = handle; @@ -2020,6 +2067,8 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline, process_info->tid = 0; } + mono_w32handle_unref (handle_data); + break; } } @@ -2047,7 +2096,7 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline, if (argv) g_strfreev (argv); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning handle %p for pid %d", __func__, handle, pid); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: returning handle %p for pid %d", __func__, handle, pid); /* Check if something needs to be cleaned up. */ processes_cleanup (); @@ -2320,20 +2369,30 @@ ves_icall_Microsoft_Win32_NativeMethods_GetCurrentProcess (void) MonoBoolean ves_icall_Microsoft_Win32_NativeMethods_GetExitCodeProcess (gpointer handle, gint32 *exitcode) { + MonoW32Handle *handle_data; MonoW32HandleProcess *process_handle; - gboolean res; if (!exitcode) return FALSE; - res = mono_w32handle_lookup (handle, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle); - if (!res) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find process %p", __func__, handle); + if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: unknown handle %p", __func__, handle); + mono_w32error_set_last (ERROR_INVALID_HANDLE); + return FALSE; + } + + if (handle_data->type != MONO_W32TYPE_PROCESS) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: unknown process handle %p", __func__, handle); + mono_w32error_set_last (ERROR_INVALID_HANDLE); + mono_w32handle_unref (handle_data); return FALSE; } + process_handle = (MonoW32HandleProcess*) handle_data->specific; + if (process_handle->pid == current_pid) { *exitcode = STILL_ACTIVE; + mono_w32handle_unref (handle_data); return TRUE; } @@ -2343,7 +2402,10 @@ ves_icall_Microsoft_Win32_NativeMethods_GetExitCodeProcess (gpointer handle, gin * Fixes bug 325463. */ mono_w32handle_wait_one (handle, 0, TRUE); - *exitcode = mono_w32handle_issignalled (handle) ? process_handle->exitstatus : STILL_ACTIVE; + *exitcode = mono_w32handle_issignalled (handle_data) ? process_handle->exitstatus : STILL_ACTIVE; + + mono_w32handle_unref (handle_data); + return TRUE; } @@ -2357,23 +2419,30 @@ MonoBoolean ves_icall_Microsoft_Win32_NativeMethods_TerminateProcess (gpointer handle, gint32 exitcode) { #ifdef HAVE_KILL - MonoW32HandleProcess *process_handle; + MonoW32Handle *handle_data; int ret; pid_t pid; - gboolean res; - res = mono_w32handle_lookup (handle, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle); - if (!res) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find process %p", __func__, handle); + if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: unknown handle %p", __func__, handle); mono_w32error_set_last (ERROR_INVALID_HANDLE); return FALSE; } - pid = process_handle->pid; + if (handle_data->type != MONO_W32TYPE_PROCESS) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: unknown process handle %p", __func__, handle); + mono_w32error_set_last (ERROR_INVALID_HANDLE); + mono_w32handle_unref (handle_data); + return FALSE; + } + + pid = ((MonoW32HandleProcess*) handle_data->specific)->pid; ret = kill (pid, exitcode == -1 ? SIGKILL : SIGTERM); - if (ret == 0) + if (ret == 0) { + mono_w32handle_unref (handle_data); return TRUE; + } switch (errno) { case EINVAL: mono_w32error_set_last (ERROR_INVALID_PARAMETER); break; @@ -2382,6 +2451,7 @@ ves_icall_Microsoft_Win32_NativeMethods_TerminateProcess (gpointer handle, gint3 default: mono_w32error_set_last (ERROR_GEN_FAILURE); break; } + mono_w32handle_unref (handle_data); return FALSE; #else g_error ("kill() is not supported by this platform"); @@ -2391,43 +2461,69 @@ ves_icall_Microsoft_Win32_NativeMethods_TerminateProcess (gpointer handle, gint3 MonoBoolean ves_icall_Microsoft_Win32_NativeMethods_GetProcessWorkingSetSize (gpointer handle, gsize *min, gsize *max) { + MonoW32Handle *handle_data; MonoW32HandleProcess *process_handle; - gboolean res; if (!min || !max) return FALSE; - res = mono_w32handle_lookup (handle, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle); - if (!res) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find process %p", __func__, handle); + if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: unknown handle %p", __func__, handle); + mono_w32error_set_last (ERROR_INVALID_HANDLE); + return FALSE; + } + + if (handle_data->type != MONO_W32TYPE_PROCESS) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: unknown process handle %p", __func__, handle); + mono_w32error_set_last (ERROR_INVALID_HANDLE); + mono_w32handle_unref (handle_data); return FALSE; } - if (!process_handle->child) + process_handle = (MonoW32HandleProcess*) handle_data->specific; + + if (!process_handle->child) { + mono_w32handle_unref (handle_data); return FALSE; + } *min = process_handle->min_working_set; *max = process_handle->max_working_set; + + mono_w32handle_unref (handle_data); return TRUE; } MonoBoolean ves_icall_Microsoft_Win32_NativeMethods_SetProcessWorkingSetSize (gpointer handle, gsize min, gsize max) { + MonoW32Handle *handle_data; MonoW32HandleProcess *process_handle; - gboolean res; - res = mono_w32handle_lookup (handle, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle); - if (!res) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find process %p", __func__, handle); + if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: unknown handle %p", __func__, handle); + mono_w32error_set_last (ERROR_INVALID_HANDLE); + return FALSE; + } + + if (handle_data->type != MONO_W32TYPE_PROCESS) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: unknown process handle %p", __func__, handle); + mono_w32error_set_last (ERROR_INVALID_HANDLE); + mono_w32handle_unref (handle_data); return FALSE; } - if (!process_handle->child) + process_handle = (MonoW32HandleProcess*) handle_data->specific; + + if (!process_handle->child) { + mono_w32handle_unref (handle_data); return FALSE; + } process_handle->min_working_set = min; process_handle->max_working_set = max; + + mono_w32handle_unref (handle_data); return TRUE; } @@ -2435,22 +2531,29 @@ gint32 ves_icall_Microsoft_Win32_NativeMethods_GetPriorityClass (gpointer handle) { #ifdef HAVE_GETPRIORITY - MonoW32HandleProcess *process_handle; - gint ret; + MonoW32Handle *handle_data; + gint res; + gint32 ret; pid_t pid; - gboolean res; - res = mono_w32handle_lookup (handle, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle); - if (!res) { + if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: unknown handle %p", __func__, handle); mono_w32error_set_last (ERROR_INVALID_HANDLE); return 0; } - pid = process_handle->pid; + if (handle_data->type != MONO_W32TYPE_PROCESS) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: unknown process handle %p", __func__, handle); + mono_w32error_set_last (ERROR_INVALID_HANDLE); + mono_w32handle_unref (handle_data); + return 0; + } + + pid = ((MonoW32HandleProcess*) handle_data->specific)->pid; errno = 0; - ret = getpriority (PRIO_PROCESS, pid); - if (ret == -1 && errno != 0) { + res = getpriority (PRIO_PROCESS, pid); + if (res == -1 && errno != 0) { switch (errno) { case EPERM: case EACCES: @@ -2462,23 +2565,28 @@ ves_icall_Microsoft_Win32_NativeMethods_GetPriorityClass (gpointer handle) default: mono_w32error_set_last (ERROR_GEN_FAILURE); } + + mono_w32handle_unref (handle_data); return 0; } - if (ret == 0) - return MONO_W32PROCESS_PRIORITY_CLASS_NORMAL; - else if (ret < -15) - return MONO_W32PROCESS_PRIORITY_CLASS_REALTIME; - else if (ret < -10) - return MONO_W32PROCESS_PRIORITY_CLASS_HIGH; - else if (ret < 0) - return MONO_W32PROCESS_PRIORITY_CLASS_ABOVE_NORMAL; - else if (ret > 10) - return MONO_W32PROCESS_PRIORITY_CLASS_IDLE; - else if (ret > 0) - return MONO_W32PROCESS_PRIORITY_CLASS_BELOW_NORMAL; - - return MONO_W32PROCESS_PRIORITY_CLASS_NORMAL; + if (res == 0) + ret = MONO_W32PROCESS_PRIORITY_CLASS_NORMAL; + else if (res < -15) + ret = MONO_W32PROCESS_PRIORITY_CLASS_REALTIME; + else if (res < -10) + ret = MONO_W32PROCESS_PRIORITY_CLASS_HIGH; + else if (res < 0) + ret = MONO_W32PROCESS_PRIORITY_CLASS_ABOVE_NORMAL; + else if (res > 10) + ret = MONO_W32PROCESS_PRIORITY_CLASS_IDLE; + else if (res > 0) + ret = MONO_W32PROCESS_PRIORITY_CLASS_BELOW_NORMAL; + else + ret = MONO_W32PROCESS_PRIORITY_CLASS_NORMAL; + + mono_w32handle_unref (handle_data); + return ret; #else mono_w32error_set_last (ERROR_NOT_SUPPORTED); return 0; @@ -2489,19 +2597,25 @@ MonoBoolean ves_icall_Microsoft_Win32_NativeMethods_SetPriorityClass (gpointer handle, gint32 priorityClass) { #ifdef HAVE_SETPRIORITY - MonoW32HandleProcess *process_handle; + MonoW32Handle *handle_data; int ret; int prio; pid_t pid; - gboolean res; - res = mono_w32handle_lookup (handle, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle); - if (!res) { + if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: unknown handle %p", __func__, handle); mono_w32error_set_last (ERROR_INVALID_HANDLE); return FALSE; } - pid = process_handle->pid; + if (handle_data->type != MONO_W32TYPE_PROCESS) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: unknown process handle %p", __func__, handle); + mono_w32error_set_last (ERROR_INVALID_HANDLE); + mono_w32handle_unref (handle_data); + return FALSE; + } + + pid = ((MonoW32HandleProcess*) handle_data->specific)->pid; switch (priorityClass) { case MONO_W32PROCESS_PRIORITY_CLASS_IDLE: @@ -2524,6 +2638,7 @@ ves_icall_Microsoft_Win32_NativeMethods_SetPriorityClass (gpointer handle, gint3 break; default: mono_w32error_set_last (ERROR_INVALID_PARAMETER); + mono_w32handle_unref (handle_data); return FALSE; } @@ -2542,6 +2657,7 @@ ves_icall_Microsoft_Win32_NativeMethods_SetPriorityClass (gpointer handle, gint3 } } + mono_w32handle_unref (handle_data); return ret == 0; #else mono_w32error_set_last (ERROR_NOT_SUPPORTED); @@ -2559,9 +2675,9 @@ ticks_to_processtime (guint64 ticks, ProcessTime *processtime) MonoBoolean ves_icall_Microsoft_Win32_NativeMethods_GetProcessTimes (gpointer handle, gint64 *creation_time, gint64 *exit_time, gint64 *kernel_time, gint64 *user_time) { + MonoW32Handle *handle_data; MonoW32HandleProcess *process_handle; ProcessTime *creation_processtime, *exit_processtime, *kernel_processtime, *user_processtime; - gboolean res; if (!creation_time || !exit_time || !kernel_time || !user_time) { /* Not sure if w32 allows NULLs here or not */ @@ -2578,12 +2694,21 @@ ves_icall_Microsoft_Win32_NativeMethods_GetProcessTimes (gpointer handle, gint64 memset (kernel_processtime, 0, sizeof (ProcessTime)); memset (user_processtime, 0, sizeof (ProcessTime)); - res = mono_w32handle_lookup (handle, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle); - if (!res) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find process %p", __func__, handle); + if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: unknown handle %p", __func__, handle); + mono_w32error_set_last (ERROR_INVALID_HANDLE); return FALSE; } + if (handle_data->type != MONO_W32TYPE_PROCESS) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: unknown process handle %p", __func__, handle); + mono_w32error_set_last (ERROR_INVALID_HANDLE); + mono_w32handle_unref (handle_data); + return FALSE; + } + + process_handle = (MonoW32HandleProcess*) handle_data->specific; + if (!process_handle->child) { gint64 start_ticks, user_ticks, kernel_ticks; @@ -2593,6 +2718,8 @@ ves_icall_Microsoft_Win32_NativeMethods_GetProcessTimes (gpointer handle, gint64 ticks_to_processtime (start_ticks, creation_processtime); ticks_to_processtime (kernel_ticks, kernel_processtime); ticks_to_processtime (user_ticks, user_processtime); + + mono_w32handle_unref (handle_data); return TRUE; } @@ -2600,7 +2727,7 @@ ves_icall_Microsoft_Win32_NativeMethods_GetProcessTimes (gpointer handle, gint64 /* A process handle is only signalled if the process has * exited, otherwise exit_processtime isn't set */ - if (mono_w32handle_issignalled (handle)) + if (mono_w32handle_issignalled (handle_data)) ticks_to_processtime (process_handle->exit_time, exit_processtime); #ifdef HAVE_GETRUSAGE @@ -2613,6 +2740,7 @@ ves_icall_Microsoft_Win32_NativeMethods_GetProcessTimes (gpointer handle, gint64 } #endif + mono_w32handle_unref (handle_data); return TRUE; } @@ -2740,14 +2868,14 @@ find_pe_file_resources32 (gpointer file_map, guint32 map_size, guint32 res_id, g dos_header = (IMAGE_DOS_HEADER *)file_map; if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Bad dos signature 0x%x", __func__, dos_header->e_magic); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Bad dos signature 0x%x", __func__, dos_header->e_magic); mono_w32error_set_last (ERROR_INVALID_DATA); return(NULL); } if (map_size < sizeof(IMAGE_NT_HEADERS32) + GUINT32_FROM_LE (dos_header->e_lfanew)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: File is too small: %" G_GUINT32_FORMAT, __func__, map_size); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: File is too small: %" G_GUINT32_FORMAT, __func__, map_size); mono_w32error_set_last (ERROR_BAD_LENGTH); return(NULL); @@ -2755,7 +2883,7 @@ find_pe_file_resources32 (gpointer file_map, guint32 map_size, guint32 res_id, g nt_headers = (IMAGE_NT_HEADERS32 *)((guint8 *)file_map + GUINT32_FROM_LE (dos_header->e_lfanew)); if (nt_headers->Signature != IMAGE_NT_SIGNATURE) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Bad NT signature 0x%x", __func__, nt_headers->Signature); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Bad NT signature 0x%x", __func__, nt_headers->Signature); mono_w32error_set_last (ERROR_INVALID_DATA); return(NULL); @@ -2769,7 +2897,7 @@ find_pe_file_resources32 (gpointer file_map, guint32 map_size, guint32 res_id, g } if (resource_rva == 0) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: No resources in file!", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: No resources in file!", __func__); mono_w32error_set_last (ERROR_INVALID_DATA); return(NULL); @@ -2777,7 +2905,7 @@ find_pe_file_resources32 (gpointer file_map, guint32 map_size, guint32 res_id, g resource_dir = (IMAGE_RESOURCE_DIRECTORY *)get_ptr_from_rva (resource_rva, (IMAGE_NT_HEADERS32 *)nt_headers, file_map); if (resource_dir == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find resource directory", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Can't find resource directory", __func__); mono_w32error_set_last (ERROR_INVALID_DATA); return(NULL); @@ -2812,14 +2940,14 @@ find_pe_file_resources64 (gpointer file_map, guint32 map_size, guint32 res_id, g dos_header = (IMAGE_DOS_HEADER *)file_map; if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Bad dos signature 0x%x", __func__, dos_header->e_magic); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Bad dos signature 0x%x", __func__, dos_header->e_magic); mono_w32error_set_last (ERROR_INVALID_DATA); return(NULL); } if (map_size < sizeof(IMAGE_NT_HEADERS64) + GUINT32_FROM_LE (dos_header->e_lfanew)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: File is too small: %" G_GUINT32_FORMAT, __func__, map_size); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: File is too small: %" G_GUINT32_FORMAT, __func__, map_size); mono_w32error_set_last (ERROR_BAD_LENGTH); return(NULL); @@ -2827,7 +2955,7 @@ find_pe_file_resources64 (gpointer file_map, guint32 map_size, guint32 res_id, g nt_headers = (IMAGE_NT_HEADERS64 *)((guint8 *)file_map + GUINT32_FROM_LE (dos_header->e_lfanew)); if (nt_headers->Signature != IMAGE_NT_SIGNATURE) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Bad NT signature 0x%x", __func__, + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Bad NT signature 0x%x", __func__, nt_headers->Signature); mono_w32error_set_last (ERROR_INVALID_DATA); @@ -2842,7 +2970,7 @@ find_pe_file_resources64 (gpointer file_map, guint32 map_size, guint32 res_id, g } if (resource_rva == 0) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: No resources in file!", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: No resources in file!", __func__); mono_w32error_set_last (ERROR_INVALID_DATA); return(NULL); @@ -2850,7 +2978,7 @@ find_pe_file_resources64 (gpointer file_map, guint32 map_size, guint32 res_id, g resource_dir = (IMAGE_RESOURCE_DIRECTORY *)get_ptr_from_rva (resource_rva, (IMAGE_NT_HEADERS32 *)nt_headers, file_map); if (resource_dir == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find resource directory", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Can't find resource directory", __func__); mono_w32error_set_last (ERROR_INVALID_DATA); return(NULL); @@ -2901,7 +3029,7 @@ map_pe_file (gunichar2 *filename, gint32 *map_size, void **handle) filename_ext = mono_unicode_to_external (filename); if (filename_ext == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: unicode conversion returned NULL", __func__); mono_w32error_set_last (ERROR_INVALID_NAME); return(NULL); @@ -2918,7 +3046,7 @@ map_pe_file (gunichar2 *filename, gint32 *map_size, void **handle) if (!located_filename) { errno = saved_errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Error opening file %s (1): %s", __func__, filename_ext, strerror (errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Error opening file %s (1): %s", __func__, filename_ext, strerror (errno)); g_free (filename_ext); @@ -2928,7 +3056,7 @@ map_pe_file (gunichar2 *filename, gint32 *map_size, void **handle) fd = open (located_filename, O_RDONLY, 0); if (fd == -1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Error opening file %s (2): %s", __func__, filename_ext, strerror (errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Error opening file %s (2): %s", __func__, filename_ext, strerror (errno)); g_free (filename_ext); g_free (located_filename); @@ -2941,7 +3069,7 @@ map_pe_file (gunichar2 *filename, gint32 *map_size, void **handle) } if (fstat (fd, &statbuf) == -1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Error stat()ing file %s: %s", __func__, filename_ext, strerror (errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Error stat()ing file %s: %s", __func__, filename_ext, strerror (errno)); mono_w32error_set_last (mono_w32error_unix_to_win32 (errno)); g_free (filename_ext); @@ -2952,7 +3080,7 @@ map_pe_file (gunichar2 *filename, gint32 *map_size, void **handle) /* Check basic file size */ if (statbuf.st_size < sizeof(IMAGE_DOS_HEADER)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: File %s is too small: %lld", __func__, filename_ext, (long long) statbuf.st_size); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: File %s is too small: %lld", __func__, filename_ext, (long long) statbuf.st_size); mono_w32error_set_last (ERROR_BAD_LENGTH); g_free (filename_ext); @@ -2962,7 +3090,7 @@ map_pe_file (gunichar2 *filename, gint32 *map_size, void **handle) file_map = mono_file_map (statbuf.st_size, MONO_MMAP_READ | MONO_MMAP_PRIVATE, fd, 0, handle); if (file_map == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Error mmap()int file %s: %s", __func__, filename_ext, strerror (errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Error mmap()int file %s: %s", __func__, filename_ext, strerror (errno)); mono_w32error_set_last (mono_w32error_unix_to_win32 (errno)); g_free (filename_ext); @@ -3072,12 +3200,12 @@ get_fixedfileinfo_block (gconstpointer data, version_data *block) data_ptr = get_versioninfo_block (data, block); if (block->value_len != sizeof(VS_FIXEDFILEINFO)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: FIXEDFILEINFO size mismatch", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: FIXEDFILEINFO size mismatch", __func__); return(NULL); } if (!unicode_string_equals (block->key, "VS_VERSION_INFO")) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: VS_VERSION_INFO mismatch", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: VS_VERSION_INFO mismatch", __func__); return(NULL); } @@ -3085,7 +3213,7 @@ get_fixedfileinfo_block (gconstpointer data, version_data *block) ffi = ((VS_FIXEDFILEINFO *)data_ptr); if ((ffi->dwSignature != VS_FFI_SIGNATURE) || (ffi->dwStrucVersion != VS_FFI_STRUCVERSION)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: FIXEDFILEINFO bad signature", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: FIXEDFILEINFO bad signature", __func__); return(NULL); } @@ -3124,7 +3252,7 @@ get_string_block (gconstpointer data_ptr, const gunichar2 *string_key, gpointer /* We must have hit padding, so give up * processing now */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Hit 0-length block, giving up", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Hit 0-length block, giving up", __func__); return(NULL); } @@ -3176,7 +3304,7 @@ get_stringtable_block (gconstpointer data_ptr, gchar *lang, const gunichar2 *str /* We must have hit padding, so give up * processing now */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Hit 0-length block, giving up", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Hit 0-length block, giving up", __func__); return(NULL); } @@ -3184,7 +3312,7 @@ get_stringtable_block (gconstpointer data_ptr, gchar *lang, const gunichar2 *str found_lang = g_utf16_to_utf8 (block->key, 8, NULL, NULL, NULL); if (found_lang == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Didn't find a valid language key, giving up", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Didn't find a valid language key, giving up", __func__); return(NULL); } @@ -3207,7 +3335,7 @@ get_stringtable_block (gconstpointer data_ptr, gchar *lang, const gunichar2 *str if (data_ptr == NULL) { /* Child block hit padding */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Child block hit 0-length block, giving up", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Child block hit 0-length block, giving up", __func__); return(NULL); } } @@ -3237,7 +3365,7 @@ big_up_string_block (gconstpointer data_ptr, version_data *block) /* We must have hit padding, so give up * processing now */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Hit 0-length block, giving up", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Hit 0-length block, giving up", __func__); return(NULL); } @@ -3248,7 +3376,7 @@ big_up_string_block (gconstpointer data_ptr, version_data *block) "UTF-16BE", "UTF-16LE", NULL, NULL, NULL); if (big_value == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Didn't find a valid string, giving up", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Didn't find a valid string, giving up", __func__); return(NULL); } @@ -3265,7 +3393,7 @@ big_up_string_block (gconstpointer data_ptr, version_data *block) "UTF-16BE", "UTF-16LE", NULL, NULL, NULL); if (big_value == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Didn't find a valid data string, giving up", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Didn't find a valid data string, giving up", __func__); return(NULL); } memcpy ((gpointer)data_ptr, big_value, @@ -3304,7 +3432,7 @@ big_up_stringtable_block (gconstpointer data_ptr, version_data *block) /* We must have hit padding, so give up * processing now */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Hit 0-length block, giving up", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Hit 0-length block, giving up", __func__); return(NULL); } @@ -3313,7 +3441,7 @@ big_up_stringtable_block (gconstpointer data_ptr, version_data *block) big_value = g_convert ((gchar *)block->key, 16, "UTF-16BE", "UTF-16LE", NULL, NULL, NULL); if (big_value == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Didn't find a valid string, giving up", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Didn't find a valid string, giving up", __func__); return(NULL); } @@ -3324,7 +3452,7 @@ big_up_stringtable_block (gconstpointer data_ptr, version_data *block) if (data_ptr == NULL) { /* Child block hit padding */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Child block hit 0-length block, giving up", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Child block hit 0-length block, giving up", __func__); return(NULL); } } @@ -3376,7 +3504,7 @@ big_up (gconstpointer datablock, guint32 size) /* We must have hit padding, so give * up processing now */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Hit 0-length block, giving up", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Hit 0-length block, giving up", __func__); return; } @@ -3392,13 +3520,13 @@ big_up (gconstpointer datablock, guint32 size) &block); } else { /* Bogus data */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Not a valid VERSIONINFO child block", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Not a valid VERSIONINFO child block", __func__); return; } if (data_ptr == NULL) { /* Child block hit padding */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Child block hit 0-length block, giving up", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Child block hit 0-length block, giving up", __func__); return; } } @@ -3507,7 +3635,7 @@ mono_w32process_ver_query_value (gconstpointer datablock, const gunichar2 *subbl /* We must have hit padding, * so give up processing now */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Hit 0-length block, giving up", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Hit 0-length block, giving up", __func__); goto done; } @@ -3536,13 +3664,13 @@ mono_w32process_ver_query_value (gconstpointer datablock, const gunichar2 *subbl } } else { /* Bogus data */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Not a valid VERSIONINFO child block", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Not a valid VERSIONINFO child block", __func__); goto done; } if (data_ptr == NULL) { /* Child block hit padding */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Child block hit 0-length block, giving up", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Child block hit 0-length block, giving up", __func__); goto done; } } diff --git a/mono/metadata/w32semaphore-unix.c b/mono/metadata/w32semaphore-unix.c index 0db4d5946fdc..4a13b5694271 100644 --- a/mono/metadata/w32semaphore-unix.c +++ b/mono/metadata/w32semaphore-unix.c @@ -27,77 +27,56 @@ struct MonoW32HandleNamedSemaphore { MonoW32HandleNamespace sharedns; }; -static void sem_handle_signal (gpointer handle, MonoW32HandleType type, MonoW32HandleSemaphore *sem_handle) +static void sem_handle_signal (MonoW32Handle *handle_data) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: signalling %s handle %p", - __func__, mono_w32handle_get_typename (type), handle); + MonoW32HandleSemaphore *sem_handle; + + sem_handle = (MonoW32HandleSemaphore*) handle_data->specific; + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: signalling %s handle %p", + __func__, mono_w32handle_get_typename (handle_data->type), handle_data); /* No idea why max is signed, but thats the spec :-( */ if (sem_handle->val + 1 > (guint32)sem_handle->max) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %s handle %p val %d count %d max %d, max value would be exceeded", - __func__, mono_w32handle_get_typename (type), handle, sem_handle->val, 1, sem_handle->max); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: %s handle %p val %d count %d max %d, max value would be exceeded", + __func__, mono_w32handle_get_typename (handle_data->type), handle_data, sem_handle->val, 1, sem_handle->max); } else { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %s handle %p val %d count %d max %d", - __func__, mono_w32handle_get_typename (type), handle, sem_handle->val, 1, sem_handle->max); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: %s handle %p val %d count %d max %d", + __func__, mono_w32handle_get_typename (handle_data->type), handle_data, sem_handle->val, 1, sem_handle->max); sem_handle->val += 1; - mono_w32handle_set_signal_state (handle, TRUE, TRUE); + mono_w32handle_set_signal_state (handle_data, TRUE, TRUE); } } -static gboolean sem_handle_own (gpointer handle, MonoW32HandleType type, gboolean *abandoned) +static gboolean sem_handle_own (MonoW32Handle *handle_data, gboolean *abandoned) { MonoW32HandleSemaphore *sem_handle; *abandoned = FALSE; - if (!mono_w32handle_lookup (handle, type, (gpointer *)&sem_handle)) { - g_warning ("%s: error looking up %s handle %p", - __func__, mono_w32handle_get_typename (type), handle); - return FALSE; - } + sem_handle = (MonoW32HandleSemaphore*) handle_data->specific; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: owning %s handle %p", - __func__, mono_w32handle_get_typename (type), handle); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: owning %s handle %p", + __func__, mono_w32handle_get_typename (handle_data->type), handle_data); sem_handle->val--; if (sem_handle->val == 0) - mono_w32handle_set_signal_state (handle, FALSE, FALSE); + mono_w32handle_set_signal_state (handle_data, FALSE, FALSE); return TRUE; } -static void sema_signal(gpointer handle, gpointer handle_specific) -{ - sem_handle_signal (handle, MONO_W32HANDLE_SEM, (MonoW32HandleSemaphore*) handle_specific); -} - -static gboolean sema_own (gpointer handle, gboolean *abandoned) -{ - return sem_handle_own (handle, MONO_W32HANDLE_SEM, abandoned); -} - -static void namedsema_signal (gpointer handle, gpointer handle_specific) +static void sema_details (MonoW32Handle *handle_data) { - sem_handle_signal (handle, MONO_W32HANDLE_NAMEDSEM, (MonoW32HandleSemaphore*) handle_specific); -} - -/* NB, always called with the shared handle lock held */ -static gboolean namedsema_own (gpointer handle, gboolean *abandoned) -{ - return sem_handle_own (handle, MONO_W32HANDLE_NAMEDSEM, abandoned); -} - -static void sema_details (gpointer data) -{ - MonoW32HandleSemaphore *sem = (MonoW32HandleSemaphore *)data; + MonoW32HandleSemaphore *sem = (MonoW32HandleSemaphore *)handle_data->specific; g_print ("val: %5u, max: %5d", sem->val, sem->max); } -static void namedsema_details (gpointer data) +static void namedsema_details (MonoW32Handle *handle_data) { - MonoW32HandleNamedSemaphore *namedsem = (MonoW32HandleNamedSemaphore *)data; + MonoW32HandleNamedSemaphore *namedsem = (MonoW32HandleNamedSemaphore *)handle_data->specific; g_print ("val: %5u, max: %5d, name: \"%s\"", namedsem->s.val, namedsem->s.max, namedsem->sharedns.name); } @@ -126,8 +105,8 @@ mono_w32semaphore_init (void) { static MonoW32HandleOps sem_ops = { NULL, /* close */ - sema_signal, /* signal */ - sema_own, /* own */ + sem_handle_signal, /* signal */ + sem_handle_own, /* own */ NULL, /* is_owned */ NULL, /* special_wait */ NULL, /* prewait */ @@ -138,8 +117,8 @@ mono_w32semaphore_init (void) static MonoW32HandleOps namedsem_ops = { NULL, /* close */ - namedsema_signal, /* signal */ - namedsema_own, /* own */ + sem_handle_signal, /* signal */ + sem_handle_own, /* own */ NULL, /* is_owned */ NULL, /* special_wait */ NULL, /* prewait */ @@ -148,18 +127,19 @@ mono_w32semaphore_init (void) namedsema_typesize, /* typesize */ }; - mono_w32handle_register_ops (MONO_W32HANDLE_SEM, &sem_ops); - mono_w32handle_register_ops (MONO_W32HANDLE_NAMEDSEM, &namedsem_ops); + mono_w32handle_register_ops (MONO_W32TYPE_SEM, &sem_ops); + mono_w32handle_register_ops (MONO_W32TYPE_NAMEDSEM, &namedsem_ops); - mono_w32handle_register_capabilities (MONO_W32HANDLE_SEM, + mono_w32handle_register_capabilities (MONO_W32TYPE_SEM, (MonoW32HandleCapability)(MONO_W32HANDLE_CAP_WAIT | MONO_W32HANDLE_CAP_SIGNAL)); - mono_w32handle_register_capabilities (MONO_W32HANDLE_NAMEDSEM, + mono_w32handle_register_capabilities (MONO_W32TYPE_NAMEDSEM, (MonoW32HandleCapability)(MONO_W32HANDLE_CAP_WAIT | MONO_W32HANDLE_CAP_SIGNAL)); } static gpointer -sem_handle_create (MonoW32HandleSemaphore *sem_handle, MonoW32HandleType type, gint32 initial, gint32 max) +sem_handle_create (MonoW32HandleSemaphore *sem_handle, MonoW32Type type, gint32 initial, gint32 max) { + MonoW32Handle *handle_data; gpointer handle; sem_handle->val = initial; @@ -173,16 +153,24 @@ sem_handle_create (MonoW32HandleSemaphore *sem_handle, MonoW32HandleType type, g return NULL; } - mono_w32handle_lock_handle (handle); + if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) + g_error ("%s: unkown handle %p", __func__, handle); + + if (handle_data->type != type) + g_error ("%s: unknown semaphore handle %p", __func__, handle); + + mono_w32handle_lock (handle_data); if (initial != 0) - mono_w32handle_set_signal_state (handle, TRUE, FALSE); + mono_w32handle_set_signal_state (handle_data, TRUE, FALSE); - mono_w32handle_unlock_handle (handle); + mono_w32handle_unlock (handle_data); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: created %s handle %p", + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: created %s handle %p", __func__, mono_w32handle_get_typename (type), handle); + mono_w32handle_unref (handle_data); + return handle; } @@ -190,9 +178,9 @@ static gpointer sem_create (gint32 initial, gint32 max) { MonoW32HandleSemaphore sem_handle; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: creating %s handle, initial %d max %d", - __func__, mono_w32handle_get_typename (MONO_W32HANDLE_SEM), initial, max); - return sem_handle_create (&sem_handle, MONO_W32HANDLE_SEM, initial, max); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: creating %s handle, initial %d max %d", + __func__, mono_w32handle_get_typename (MONO_W32TYPE_SEM), initial, max); + return sem_handle_create (&sem_handle, MONO_W32TYPE_SEM, initial, max); } static gpointer @@ -201,8 +189,8 @@ namedsem_create (gint32 initial, gint32 max, const gunichar2 *name) gpointer handle; gchar *utf8_name; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: creating %s handle, initial %d max %d name \"%s\"", - __func__, mono_w32handle_get_typename (MONO_W32HANDLE_NAMEDSEM), initial, max, (const char*)name); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: creating %s handle, initial %d max %d name \"%s\"", + __func__, mono_w32handle_get_typename (MONO_W32TYPE_NAMEDSEM), initial, max, (const char*)name); /* w32 seems to guarantee that opening named objects can't race each other */ mono_w32handle_namespace_lock (); @@ -210,9 +198,9 @@ namedsem_create (gint32 initial, gint32 max, const gunichar2 *name) glong utf8_len = 0; utf8_name = g_utf16_to_utf8 (name, -1, NULL, &utf8_len, NULL); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Creating named sem name [%s] initial %d max %d", __func__, utf8_name, initial, max); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: Creating named sem name [%s] initial %d max %d", __func__, utf8_name, initial, max); - handle = mono_w32handle_namespace_search_handle (MONO_W32HANDLE_NAMEDSEM, utf8_name); + handle = mono_w32handle_namespace_search_handle (MONO_W32TYPE_NAMEDSEM, utf8_name); if (handle == INVALID_HANDLE_VALUE) { /* The name has already been used for a different object. */ handle = NULL; @@ -230,7 +218,7 @@ namedsem_create (gint32 initial, gint32 max, const gunichar2 *name) memcpy (&namedsem_handle.sharedns.name [0], utf8_name, len); namedsem_handle.sharedns.name [len] = '\0'; - handle = sem_handle_create ((MonoW32HandleSemaphore*) &namedsem_handle, MONO_W32HANDLE_NAMEDSEM, initial, max); + handle = sem_handle_create ((MonoW32HandleSemaphore*) &namedsem_handle, MONO_W32TYPE_NAMEDSEM, initial, max); } g_free (utf8_name); @@ -246,14 +234,14 @@ ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCou gpointer sem; if (maximumCount <= 0) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: maximumCount <= 0", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: maximumCount <= 0", __func__); *error = ERROR_INVALID_PARAMETER; return NULL; } if (initialCount > maximumCount || initialCount < 0) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: initialCount > maximumCount or < 0", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: initialCount > maximumCount or < 0", __func__); *error = ERROR_INVALID_PARAMETER; return NULL; @@ -278,33 +266,29 @@ ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCou MonoBoolean ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (gpointer handle, gint32 releaseCount, gint32 *prevcount) { - MonoW32HandleType type; + MonoW32Handle *handle_data; MonoW32HandleSemaphore *sem_handle; MonoBoolean ret; - if (!handle) { + if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) { + g_warning ("%s: unkown handle %p", __func__, handle); mono_w32error_set_last (ERROR_INVALID_HANDLE); return FALSE; } - switch (type = mono_w32handle_get_type (handle)) { - case MONO_W32HANDLE_SEM: - case MONO_W32HANDLE_NAMEDSEM: - break; - default: + if (handle_data->type != MONO_W32TYPE_SEM && handle_data->type != MONO_W32TYPE_NAMEDSEM) { + g_warning ("%s: unknown sem handle %p", __func__, handle); mono_w32error_set_last (ERROR_INVALID_HANDLE); + mono_w32handle_unref (handle_data); return FALSE; } - if (!mono_w32handle_lookup (handle, type, (gpointer *)&sem_handle)) { - g_warning ("%s: error looking up sem handle %p", __func__, handle); - return FALSE; - } + sem_handle = (MonoW32HandleSemaphore*) handle_data->specific; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: releasing %s handle %p", - __func__, mono_w32handle_get_typename (type), handle); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: releasing %s handle %p", + __func__, mono_w32handle_get_typename (handle_data->type), handle); - mono_w32handle_lock_handle (handle); + mono_w32handle_lock (handle_data); /* Do this before checking for count overflow, because overflowing * max is a listed technique for finding the current value */ @@ -313,21 +297,22 @@ ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (gpointer handle, /* No idea why max is signed, but thats the spec :-( */ if (sem_handle->val + releaseCount > (guint32)sem_handle->max) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %s handle %p val %d count %d max %d, max value would be exceeded", - __func__, mono_w32handle_get_typename (type), handle, sem_handle->val, releaseCount, sem_handle->max); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: %s handle %p val %d count %d max %d, max value would be exceeded", + __func__, mono_w32handle_get_typename (handle_data->type), handle, sem_handle->val, releaseCount, sem_handle->max); ret = FALSE; } else { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %s handle %p val %d count %d max %d", - __func__, mono_w32handle_get_typename (type), handle, sem_handle->val, releaseCount, sem_handle->max); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: %s handle %p val %d count %d max %d", + __func__, mono_w32handle_get_typename (handle_data->type), handle, sem_handle->val, releaseCount, sem_handle->max); sem_handle->val += releaseCount; - mono_w32handle_set_signal_state (handle, TRUE, TRUE); + mono_w32handle_set_signal_state (handle_data, TRUE, TRUE); ret = TRUE; } - mono_w32handle_unlock_handle (handle); + mono_w32handle_unlock (handle_data); + mono_w32handle_unref (handle_data); return ret; } @@ -345,9 +330,9 @@ ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, g utf8_name = g_utf16_to_utf8 (mono_string_chars (name), -1, NULL, NULL, NULL); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Opening named sem [%s]", __func__, utf8_name); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: Opening named sem [%s]", __func__, utf8_name); - handle = mono_w32handle_namespace_search_handle (MONO_W32HANDLE_NAMEDSEM, utf8_name); + handle = mono_w32handle_namespace_search_handle (MONO_W32TYPE_NAMEDSEM, utf8_name); if (handle == INVALID_HANDLE_VALUE) { /* The name has already been used for a different object. */ *error = ERROR_INVALID_HANDLE; @@ -358,7 +343,7 @@ ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, g goto cleanup; } - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning named sem handle %p", __func__, handle); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: returning named sem handle %p", __func__, handle); cleanup: g_free (utf8_name); diff --git a/mono/metadata/w32socket-unix.c b/mono/metadata/w32socket-unix.c index 28a5a63a5b42..d675b53e66a9 100644 --- a/mono/metadata/w32socket-unix.c +++ b/mono/metadata/w32socket-unix.c @@ -88,7 +88,7 @@ socket_data_close (MonoFDHandle *fdhandle) info = mono_thread_info_current (); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: closing fd %d", __func__, ((MonoFDHandle*) sockethandle)->fd); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: closing fd %d", __func__, ((MonoFDHandle*) sockethandle)->fd); /* Shutdown the socket for reading, to interrupt any potential * receives that may be blocking for data. See bug 75705. */ @@ -168,7 +168,7 @@ mono_w32socket_accept (SOCKET sock, struct sockaddr *addr, socklen_t *addrlen, g if (accepted_fd == -1) { gint error = mono_w32socket_convert_error (errno); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: accept error: %s", __func__, g_strerror(errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: accept error: %s", __func__, g_strerror(errno)); mono_w32socket_set_last_error (error); mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return INVALID_SOCKET; @@ -182,7 +182,7 @@ mono_w32socket_accept (SOCKET sock, struct sockaddr *addr, socklen_t *addrlen, g mono_fdhandle_insert ((MonoFDHandle*) accepted_socket_data); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning accepted handle %p", __func__, GINT_TO_POINTER(((MonoFDHandle*) accepted_socket_data)->fd)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: returning accepted handle %p", __func__, GINT_TO_POINTER(((MonoFDHandle*) accepted_socket_data)->fd)); mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return ((MonoFDHandle*) accepted_socket_data)->fd; @@ -217,7 +217,7 @@ mono_w32socket_connect (SOCKET sock, const struct sockaddr *addr, int addrlen, g errnum = errno; if (errno != EINTR) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: connect error: %s", __func__, + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: connect error: %s", __func__, g_strerror (errnum)); errnum = mono_w32socket_convert_error (errnum); @@ -254,7 +254,7 @@ mono_w32socket_connect (SOCKET sock, const struct sockaddr *addr, int addrlen, g if (errno != EINTR) { gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: connect poll error: %s", __func__, g_strerror (errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: connect poll error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; @@ -267,7 +267,7 @@ mono_w32socket_connect (SOCKET sock, const struct sockaddr *addr, int addrlen, g MONO_EXIT_GC_SAFE; if (ret == -1) { gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: connect getsockopt error: %s", __func__, g_strerror (errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: connect getsockopt error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; @@ -279,7 +279,7 @@ mono_w32socket_connect (SOCKET sock, const struct sockaddr *addr, int addrlen, g /* Need to save this socket error */ sockethandle->saved_error = errnum; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: connect getsockopt returned error: %s", + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: connect getsockopt returned error: %s", __func__, g_strerror (so_error)); mono_w32socket_set_last_error (errnum); @@ -351,7 +351,7 @@ mono_w32socket_recvfrom (SOCKET sock, char *buf, int len, int flags, struct sock if (ret == -1) { gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: recv error: %s", __func__, g_strerror(errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: recv error: %s", __func__, g_strerror(errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; @@ -424,7 +424,7 @@ mono_w32socket_recvbuffers (SOCKET sock, WSABUF *buffers, guint32 count, guint32 if (ret == -1) { gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: recvmsg error: %s", __func__, g_strerror(errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: recvmsg error: %s", __func__, g_strerror(errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; @@ -465,7 +465,7 @@ mono_w32socket_send (SOCKET sock, char *buf, int len, int flags, gboolean blocki if (ret == -1) { gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: send error: %s", __func__, g_strerror (errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: send error: %s", __func__, g_strerror (errno)); #ifdef O_NONBLOCK /* At least linux returns EAGAIN/EWOULDBLOCK when the timeout has been set on @@ -514,7 +514,7 @@ mono_w32socket_sendto (SOCKET sock, const char *buf, int len, int flags, const s if (ret == -1) { gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: send error: %s", __func__, g_strerror (errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: send error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; @@ -559,7 +559,7 @@ mono_w32socket_sendbuffers (SOCKET sock, WSABUF *buffers, guint32 count, guint32 if (ret == -1) { gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: sendmsg error: %s", __func__, g_strerror (errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: sendmsg error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; @@ -696,7 +696,7 @@ mono_w32socket_socket (int domain, int type, int protocol) } gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: socket error: %s", __func__, g_strerror (errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: socket error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); return INVALID_SOCKET; } @@ -730,7 +730,7 @@ mono_w32socket_socket (int domain, int type, int protocol) MONO_EXIT_GC_SAFE; if (ret == -1) { gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Error setting SO_REUSEADDR", __func__); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: Error setting SO_REUSEADDR", __func__); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); MONO_ENTER_GC_SAFE; @@ -744,7 +744,7 @@ mono_w32socket_socket (int domain, int type, int protocol) mono_fdhandle_insert ((MonoFDHandle*) sockethandle); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning socket handle %p", __func__, GINT_TO_POINTER(((MonoFDHandle*) sockethandle)->fd)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: returning socket handle %p", __func__, GINT_TO_POINTER(((MonoFDHandle*) sockethandle)->fd)); return ((MonoFDHandle*) sockethandle)->fd; } @@ -771,7 +771,7 @@ mono_w32socket_bind (SOCKET sock, struct sockaddr *addr, socklen_t addrlen) MONO_EXIT_GC_SAFE; if (ret == -1) { gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: bind error: %s", __func__, g_strerror(errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: bind error: %s", __func__, g_strerror(errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; @@ -803,7 +803,7 @@ mono_w32socket_getpeername (SOCKET sock, struct sockaddr *name, socklen_t *namel MONO_EXIT_GC_SAFE; if (ret == -1) { gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: getpeername error: %s", __func__, g_strerror (errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: getpeername error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; @@ -835,7 +835,7 @@ mono_w32socket_getsockname (SOCKET sock, struct sockaddr *name, socklen_t *namel MONO_EXIT_GC_SAFE; if (ret == -1) { gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: getsockname error: %s", __func__, g_strerror (errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: getsockname error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; @@ -876,7 +876,7 @@ mono_w32socket_getsockopt (SOCKET sock, gint level, gint optname, gpointer optva MONO_EXIT_GC_SAFE; if (ret == -1) { gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: getsockopt error: %s", __func__, g_strerror (errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: getsockopt error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; @@ -951,7 +951,7 @@ mono_w32socket_setsockopt (SOCKET sock, gint level, gint optname, const gpointer MONO_EXIT_GC_SAFE; if (ret == -1) { gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: setsockopt error: %s", __func__, g_strerror (errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: setsockopt error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; @@ -1002,7 +1002,7 @@ mono_w32socket_listen (SOCKET sock, gint backlog) MONO_EXIT_GC_SAFE; if (ret == -1) { gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: listen error: %s", __func__, g_strerror (errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: listen error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; @@ -1037,7 +1037,7 @@ mono_w32socket_shutdown (SOCKET sock, gint how) MONO_EXIT_GC_SAFE; if (ret == -1) { gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: shutdown error: %s", __func__, g_strerror (errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: shutdown error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; @@ -1054,7 +1054,7 @@ mono_w32socket_disconnect (SOCKET sock, gboolean reuse) SOCKET newsock; gint ret; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: called on socket %d!", __func__, sock); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: called on socket %d!", __func__, sock); /* We could check the socket type here and fail unless its * SOCK_STREAM, SOCK_SEQPACKET or SOCK_RDM (according to msdn) @@ -1076,7 +1076,7 @@ mono_w32socket_disconnect (SOCKET sock, gboolean reuse) MONO_EXIT_GC_SAFE; if (newsock == -1) { gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: socket error: %s", __func__, g_strerror (errnum)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: socket error: %s", __func__, g_strerror (errnum)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; @@ -1094,7 +1094,7 @@ mono_w32socket_disconnect (SOCKET sock, gboolean reuse) if (ret == -1) { gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: dup2 error: %s", __func__, g_strerror (errnum)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: dup2 error: %s", __func__, g_strerror (errnum)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; @@ -1267,7 +1267,7 @@ mono_w32socket_ioctl (SOCKET sock, gint32 command, gchar *input, gint inputlen, g_free (buffer); gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: WSAIoctl error: %s", __func__, g_strerror (errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: WSAIoctl error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; @@ -1332,7 +1332,7 @@ mono_w32socket_set_blocking (SOCKET sock, gboolean blocking) MONO_EXIT_GC_SAFE; if (ret == -1) { gint errnum = mono_w32socket_convert_error (errno); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fcntl(F_GETFL) error: %s", __func__, g_strerror (errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: fcntl(F_GETFL) error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (errnum); mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; @@ -1343,7 +1343,7 @@ mono_w32socket_set_blocking (SOCKET sock, gboolean blocking) MONO_EXIT_GC_SAFE; if (ret == -1) { gint errnum = mono_w32socket_convert_error (errno); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fcntl(F_SETFL) error: %s", __func__, g_strerror (errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: fcntl(F_SETFL) error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (errnum); mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; @@ -1391,7 +1391,7 @@ mono_w32socket_get_available (SOCKET sock, guint64 *amount) MONO_EXIT_GC_SAFE; if (ret == -1) { gint errnum = mono_w32socket_convert_error (errno); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: getsockopt error: %s", __func__, g_strerror (errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: getsockopt error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (errnum); mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; @@ -1402,7 +1402,7 @@ mono_w32socket_get_available (SOCKET sock, guint64 *amount) MONO_EXIT_GC_SAFE; if (ret == -1) { gint errnum = mono_w32socket_convert_error (errno); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: ioctl error: %s", __func__, g_strerror (errno)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: ioctl error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (errnum); mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; diff --git a/mono/mini/Makefile.am.in b/mono/mini/Makefile.am.in index c777a8369caf..a2b7cbd30227 100755 --- a/mono/mini/Makefile.am.in +++ b/mono/mini/Makefile.am.in @@ -93,9 +93,6 @@ export HOST_CC PLATFORM_CFLAGS = -O endif -# hack for automake to have the same source file in a library and a bin -genmdesc_CFLAGS = $(AM_CFLAGS) - monoldflags=$(export_ldflags) monobinldflags=$(export_ldflags) $(extra_runtime_ldflags) @@ -165,9 +162,9 @@ endif endif if DISABLE_EXECUTABLES -noinst_PROGRAMS = genmdesc +noinst_PROGRAMS = else -noinst_PROGRAMS = genmdesc mono +noinst_PROGRAMS = mono endif if DISABLE_EXECUTABLES @@ -361,18 +358,6 @@ monow_SOURCES = $(mono_sgen_SOURCES) endif endif -genmdesc_SOURCES = \ - mini.h \ - seq-points.h \ - genmdesc.c \ - helpers.c \ - ../metadata/opcodes.c - -# Don't link this against libmonoruntime to speed up rebuilds -genmdesc_LDADD = \ - $(monodir)/mono/utils/libmonoutils.la -lm \ - $(GLIB_LIBS) \ - $(LIBICONV) unity_sources = \ mini-unity.c @@ -469,8 +454,7 @@ endif if DISABLE_INTERPRETER interp_sources = \ - interp/interp.h \ - interp/interp-stubs.c + interp/interp.h else interp_sources = \ interp/hacks.h \ @@ -529,6 +513,7 @@ common_sources = \ aot-compiler.c \ aot-runtime.c \ aot-runtime-wasm.c \ + wasm_m2n_invoke.g.h \ graph.c \ mini-codegen.c \ mini-exceptions.c \ @@ -564,7 +549,10 @@ common_sources = \ mixed_callstack_plugin.h \ mixed_callstack_plugin.c \ memory-access.c \ - mini-profiler.c + mini-profiler.c \ + interp-stubs.c \ + aot-runtime.h \ + mini-runtime.h test_sources = \ basic-calls.cs \ @@ -624,18 +612,21 @@ if WASM arch_sources = $(wasm_sources) arch_built=cpu-wasm.h arch_define=__wasm__ +target_define=TARGET_WASM endif if X86 arch_sources = $(x86_sources) arch_built=cpu-x86.h arch_define=__i386__ +target_define=TARGET_X86 endif if AMD64 arch_sources = $(amd64_sources) arch_built=cpu-amd64.h arch_define=__x86_64__ +target_define=TARGET_AMD64 ARCH_FULLAOT_EXCLUDE= endif @@ -643,18 +634,21 @@ if POWERPC arch_sources = $(ppc_sources) arch_built=cpu-ppc.h arch_define=__ppc__ +target_define=TARGET_POWERPC endif if POWERPC64 arch_sources = $(ppc_sources) arch_built=cpu-ppc64.h arch_define=__ppc64__ +target_define=TARGET_POWERPC endif if MIPS arch_sources = $(mips_sources) arch_built=cpu-mips.h arch_define=__mips__ +target_define=TARGET_MIPS endif if ARM @@ -663,30 +657,35 @@ ARCH_CFLAGS = -I../arch/arm arch_sources = $(arm_sources) arch_built=cpu-arm.h arch_define=__arm__ +target_define=TARGET_ARM endif if ARM64 arch_sources = $(arm64_sources) arch_built=cpu-arm64.h arch_define=__aarch64__ +target_define=TARGET_ARM64 endif if SPARC arch_sources = $(sparc_sources) arch_built=cpu-sparc.h arch_define=__sparc__ +target_define=TARGET_SPARC endif if SPARC64 arch_sources = $(sparc_sources) arch_built=cpu-sparc.h arch_define=__sparc__ +target_define=TARGET_SPARC endif if S390X arch_sources = $(s390x_sources) arch_built=cpu-s390x.h arch_define=__s390__ +target_define=TARGET_S390X endif if HOST_WIN32 @@ -773,49 +772,36 @@ MemoryIntrinsics.dll: MemoryIntrinsics.il GENMDESC_OPTS= -# we don't always use the perl impl because it's an additional -# build dependency for the poor windows users -# $(arch_define) is the preprocessor symbol that enables all the opcodes -# for the specific platform in mini-ops.h - -if CROSS_COMPILING -GENMDESC_PRG=perl $(srcdir)/genmdesc.pl $(arch_define) $(srcdir) $(GENMDESC_OPTS) -else -if WASM -GENMDESC_PRG=perl $(srcdir)/genmdesc.pl $(arch_define) $(srcdir) $(GENMDESC_OPTS) -else -GENMDESC_PRG=./genmdesc $(GENMDESC_OPTS) -endif -endif !CROSS_COMPILING +GENMDESC_PRG=python $(srcdir)/genmdesc.py $(target_define) $(srcdir) -cpu-wasm.h: cpu-wasm.md genmdesc$(EXEEXT) +cpu-wasm.h: cpu-wasm.md $(GENMDESC_PRG) cpu-wasm.h wasm_desc $(srcdir)/cpu-wasm.md -cpu-x86.h: cpu-x86.md genmdesc$(EXEEXT) +cpu-x86.h: cpu-x86.md $(GENMDESC_PRG) cpu-x86.h x86_desc $(srcdir)/cpu-x86.md -cpu-amd64.h: cpu-amd64.md genmdesc$(EXEEXT) +cpu-amd64.h: cpu-amd64.md $(GENMDESC_PRG) cpu-amd64.h amd64_desc $(srcdir)/cpu-amd64.md -cpu-ppc.h: cpu-ppc.md genmdesc$(EXEEXT) +cpu-ppc.h: cpu-ppc.md $(GENMDESC_PRG) cpu-ppc.h ppcg4 $(srcdir)/cpu-ppc.md -cpu-ppc64.h: cpu-ppc64.md genmdesc$(EXEEXT) +cpu-ppc64.h: cpu-ppc64.md $(GENMDESC_PRG) cpu-ppc64.h ppc64_cpu_desc $(srcdir)/cpu-ppc64.md -cpu-arm.h: cpu-arm.md genmdesc$(EXEEXT) +cpu-arm.h: cpu-arm.md $(GENMDESC_PRG) cpu-arm.h arm_cpu_desc $(srcdir)/cpu-arm.md -cpu-arm64.h: cpu-arm64.md genmdesc$(EXEEXT) +cpu-arm64.h: cpu-arm64.md $(GENMDESC_PRG) cpu-arm64.h arm64_cpu_desc $(srcdir)/cpu-arm64.md -cpu-sparc.h: cpu-sparc.md genmdesc$(EXEEXT) +cpu-sparc.h: cpu-sparc.md $(GENMDESC_PRG) cpu-sparc.h sparc_desc $(srcdir)/cpu-sparc.md -cpu-s390x.h: cpu-s390x.md genmdesc$(EXEEXT) +cpu-s390x.h: cpu-s390x.md $(GENMDESC_PRG) cpu-s390x.h s390x_cpu_desc $(srcdir)/cpu-s390x.md -cpu-mips.h: cpu-mips.md genmdesc$(EXEEXT) +cpu-mips.h: cpu-mips.md $(GENMDESC_PRG) cpu-mips.h mips_desc $(srcdir)/cpu-mips.md testi: mono test.exe @@ -978,7 +964,7 @@ BUILT_SOURCES = version.h $(arch_built) CLEANFILES= $(BUILT_SOURCES) *.exe *.dll EXTRA_DIST = TestDriver.cs \ TestHelpers.cs \ - genmdesc.pl \ + genmdesc.py \ $(test_sources) \ $(wasm_sources) cpu-wasm.md \ $(x86_sources) cpu-x86.md \ diff --git a/mono/mini/aot-compiler.c b/mono/mini/aot-compiler.c index cf73585a3cfe..cd6627f9a22c 100644 --- a/mono/mini/aot-compiler.c +++ b/mono/mini/aot-compiler.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -60,11 +61,13 @@ #include #include "aot-compiler.h" +#include "aot-runtime.h" #include "seq-points.h" #include "image-writer.h" #include "dwarfwriter.h" #include "mini-gc.h" #include "mini-llvm.h" +#include "mini-runtime.h" #if !defined(DISABLE_AOT) && !defined(DISABLE_JIT) @@ -3303,6 +3306,8 @@ encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8 encode_method_ref (acfg, info->d.synchronized_inner.method, p, &p); else if (info->subtype == WRAPPER_SUBTYPE_ARRAY_ACCESSOR) encode_method_ref (acfg, info->d.array_accessor.method, p, &p); + else if (info->subtype == WRAPPER_SUBTYPE_INTERP_IN) + encode_signature (acfg, info->d.interp_in.sig, p, &p); else if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG) encode_signature (acfg, info->d.gsharedvt.sig, p, &p); else if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG) @@ -6539,7 +6544,7 @@ emit_klass_info (MonoAotCompile *acfg, guint32 token) } else { gboolean has_nested = mono_class_get_nested_classes_property (klass) != NULL; encode_value (klass->vtable_size, p, &p); - encode_value ((mono_class_is_gtd (klass) ? (1 << 8) : 0) | (no_special_static << 7) | (klass->has_static_refs << 6) | (klass->has_references << 5) | ((klass->blittable << 4) | (has_nested ? 1 : 0) << 3) | (klass->has_cctor << 2) | (klass->has_finalize << 1) | klass->ghcimpl, p, &p); + encode_value ((klass->has_weak_fields << 9) | (mono_class_is_gtd (klass) ? (1 << 8) : 0) | (no_special_static << 7) | (klass->has_static_refs << 6) | (klass->has_references << 5) | ((klass->blittable << 4) | (has_nested ? 1 : 0) << 3) | (klass->has_cctor << 2) | (klass->has_finalize << 1) | klass->ghcimpl, p, &p); if (klass->has_cctor) encode_method_ref (acfg, mono_class_get_cctor (klass), p, &p); if (klass->has_finalize) @@ -8435,6 +8440,9 @@ append_mangled_wrapper_subtype (GString *s, WrapperSubtype subtype) case WRAPPER_SUBTYPE_DELEGATE_INVOKE_BOUND: label = "del_inv_bound"; break; + case WRAPPER_SUBTYPE_INTERP_IN: + label = "interp_in"; + break; case WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG: label = "gsharedvt_in_sig"; break; @@ -8571,6 +8579,8 @@ append_mangled_wrapper (GString *s, MonoMethod *method) success = success && append_mangled_method (s, info->d.synchronized_inner.method); else if (info->subtype == WRAPPER_SUBTYPE_ARRAY_ACCESSOR) success = success && append_mangled_method (s, info->d.array_accessor.method); + else if (info->subtype == WRAPPER_SUBTYPE_INTERP_IN) + append_mangled_signature (s, info->d.interp_in.sig); else if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG) append_mangled_signature (s, info->d.gsharedvt.sig); else if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG) @@ -9879,6 +9889,32 @@ emit_image_table (MonoAotCompile *acfg) g_free (buf); } +static void +emit_weak_field_indexes (MonoAotCompile *acfg) +{ + char symbol [128]; + GHashTable *indexes; + GHashTableIter iter; + gpointer key, value; + + /* Emit a table of weak field indexes, since computing these at runtime is expensive */ + sprintf (symbol, "weak_field_indexes"); + emit_section_change (acfg, ".text", 0); + emit_alignment_code (acfg, 8); + emit_info_symbol (acfg, symbol); + + mono_assembly_init_weak_fields (acfg->image); + indexes = acfg->image->weak_field_indexes; + g_assert (indexes); + + emit_int32 (acfg, g_hash_table_size (indexes)); + g_hash_table_iter_init (&iter, indexes); + while (g_hash_table_iter_next (&iter, &key, &value)) { + guint32 index = GPOINTER_TO_UINT (key); + emit_int32 (acfg, index); + } +} + static void emit_got_info (MonoAotCompile *acfg, gboolean llvm) { @@ -10277,6 +10313,7 @@ emit_aot_file_info (MonoAotCompile *acfg, MonoAotFileInfo *info) symbols [sindex ++] = NULL; symbols [sindex ++] = NULL; } + symbols [sindex ++] = "weak_field_indexes"; g_assert (sindex == MONO_AOT_FILE_INFO_NUM_SYMBOLS); @@ -12322,6 +12359,35 @@ mono_compile_deferred_assemblies (guint32 opts, const char *aot_options, gpointe return res; } +static const char* interp_in_static_sigs[] = { + "bool ptr int32 ptr&", + "bool ptr ptr&", + "int32 int32 ptr&", + "int32 int32 ptr ptr&", + "int32 ptr int32 ptr", + "int32 ptr int32 ptr&", + "int32 ptr ptr&", + "object object ptr ptr ptr", + "ptr int32 ptr&", + "ptr ptr int32 ptr ptr ptr&", + "ptr ptr int32 ptr ptr&", + "ptr ptr int32 ptr&", + "ptr ptr ptr int32 ptr&", + "ptr ptr ptr ptr& ptr&", + "ptr ptr ptr ptr&", + "ptr ptr ptr&", + "ptr ptr uint32 ptr&", + "ptr uint32 ptr&", + "void object ptr ptr ptr", + "void ptr ptr int32 ptr ptr& ptr ptr&", + "void ptr ptr int32 ptr ptr&", + "void ptr ptr ptr&", + "void ptr ptr&", + "void ptr", + "void int32 ptr&", + "void uint32 ptr&", +}; + int mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options, gpointer **global_aot_state) { @@ -12585,23 +12651,11 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options, #endif if (mono_aot_mode_is_interp (&acfg->aot_opts)) { - MonoMethod *wrapper; - MonoMethodSignature *sig; - - /* object object:interp_in_static (object,intptr,intptr,intptr) */ - sig = mono_create_icall_signature ("object object ptr ptr ptr"); - wrapper = mini_get_interp_in_wrapper (sig); - add_method (acfg, wrapper); - - /* int object:interp_in_static (intptr,int,intptr) */ - sig = mono_create_icall_signature ("int32 ptr int32 ptr"); - wrapper = mini_get_interp_in_wrapper (sig); - add_method (acfg, wrapper); - - /* void object:interp_in_static (object,intptr,intptr,intptr) */ - sig = mono_create_icall_signature ("void object ptr ptr ptr"); - wrapper = mini_get_interp_in_wrapper (sig); - add_method (acfg, wrapper); + for (int i = 0; i < sizeof (interp_in_static_sigs) / sizeof (const char *); i++) { + MonoMethodSignature *sig = mono_create_icall_signature (interp_in_static_sigs [i]); + MonoMethod *wrapper = mini_get_interp_in_wrapper (sig); + add_method (acfg, wrapper); + } } TV_GETTIME (atv); @@ -12738,6 +12792,8 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options, emit_image_table (acfg); + emit_weak_field_indexes (acfg); + emit_got (acfg); { @@ -12885,4 +12941,11 @@ mono_aot_is_shared_got_offset (int offset) return FALSE; } +int +mono_compile_deferred_assemblies (guint32 opts, const char *aot_options, gpointer **aot_state) +{ + g_assert_not_reached (); + return 0; +} + #endif diff --git a/mono/mini/aot-runtime-wasm.c b/mono/mini/aot-runtime-wasm.c index b23f3b516587..fa9b7ad0bdd0 100644 --- a/mono/mini/aot-runtime-wasm.c +++ b/mono/mini/aot-runtime-wasm.c @@ -99,118 +99,6 @@ type_to_c (MonoType *t) #define FIDX(x) (x) #endif -static void -wasm_invoke_v (void *target_func, InterpMethodArguments *margs) -{ - void (*func)(void) = target_func; - func (); -} - -static void -wasm_invoke_vi (void *target_func, InterpMethodArguments *margs) -{ - void (*func)(gpointer a) = target_func; - func (margs->iargs [0]); -} - -static void -wasm_invoke_vii (void *target_func, InterpMethodArguments *margs) -{ - void (*func)(gpointer a, gpointer b) = target_func; - func (margs->iargs [0], margs->iargs [1]); -} - -static void -wasm_invoke_viii (void *target_func, InterpMethodArguments *margs) -{ - void (*func)(gpointer a, gpointer b, gpointer c) = target_func; - func (margs->iargs [0], margs->iargs [1], margs->iargs [2]); -} - -static void -wasm_invoke_viiii (void *target_func, InterpMethodArguments *margs) -{ - void (*func)(gpointer a, gpointer b, gpointer c, gpointer d) = target_func; - func (margs->iargs [0], margs->iargs [1], margs->iargs [2], margs->iargs [3]); -} - -static void -wasm_invoke_viiiii (void *target_func, InterpMethodArguments *margs) -{ - void (*func)(gpointer a, gpointer b, gpointer c, gpointer d, gpointer e) = target_func; - func (margs->iargs [0], margs->iargs [1], margs->iargs [2], margs->iargs [3], margs->iargs [4]); -} - -static void -wasm_invoke_viiiiii (void *target_func, InterpMethodArguments *margs) -{ - void (*func)(gpointer a, gpointer b, gpointer c, gpointer d, gpointer e, gpointer f) = target_func; - func (margs->iargs [0], margs->iargs [1], margs->iargs [2], margs->iargs [3], margs->iargs [4], margs->iargs [5]); -} - -static void -wasm_invoke_i (void *target_func, InterpMethodArguments *margs) -{ - int (*func)(void) = target_func; - int res = func (); - *(int*)margs->retval = res; -} - -static void -wasm_invoke_ii (void *target_func, InterpMethodArguments *margs) -{ - int (*func)(gpointer a) = target_func; - int res = func (margs->iargs [0]); - *(int*)margs->retval = res; -} - -static void -wasm_invoke_iii (void *target_func, InterpMethodArguments *margs) -{ - int (*func)(gpointer a, gpointer b) = target_func; - int res = func (margs->iargs [0], margs->iargs [1]); - *(int*)margs->retval = res; -} - -static void -wasm_invoke_iiii (void *target_func, InterpMethodArguments *margs) -{ - int (*func)(gpointer a, gpointer b, gpointer c) = target_func; - int res = func (margs->iargs [0], margs->iargs [1], margs->iargs [2]); - *(int*)margs->retval = res; -} - -static void -wasm_invoke_iiiii (void *target_func, InterpMethodArguments *margs) -{ - int (*func)(gpointer a, gpointer b, gpointer c, gpointer d) = target_func; - int res = func (margs->iargs [0], margs->iargs [1], margs->iargs [2], margs->iargs [3]); - *(int*)margs->retval = res; -} - -static void -wasm_invoke_iiiiii (void *target_func, InterpMethodArguments *margs) -{ - int (*func)(gpointer a, gpointer b, gpointer c, gpointer d, gpointer e) = target_func; - int res = func (margs->iargs [0], margs->iargs [1], margs->iargs [2], margs->iargs [3], margs->iargs [4]); - *(int*)margs->retval = res; -} - -static void -wasm_invoke_iiiiiii (void *target_func, InterpMethodArguments *margs) -{ - int (*func)(gpointer a, gpointer b, gpointer c, gpointer d, gpointer e, gpointer f) = target_func; - int res = func (margs->iargs [0], margs->iargs [1], margs->iargs [2], margs->iargs [3], margs->iargs [4], margs->iargs [5]); - *(int*)margs->retval = res; -} - -static void -wasm_invoke_iiiiiiiii (void *target_func, InterpMethodArguments *margs) -{ - int (*func)(gpointer a, gpointer b, gpointer c, gpointer d, gpointer e, gpointer f, gpointer g, gpointer h) = target_func; - int res = func (margs->iargs [0], margs->iargs [1], margs->iargs [2], margs->iargs [3], margs->iargs [4], margs->iargs [5], margs->iargs [6], margs->iargs [7]); - *(int*)margs->retval = res; -} typedef union { @@ -221,122 +109,16 @@ typedef union { } pair; } interp_pair; -static void -wasm_invoke_l (void *target_func, InterpMethodArguments *margs) -{ - gint64 (*func)(void) = target_func; - - gint64 res = func (); - *(gint64*)margs->retval = res; -} - -static void -wasm_invoke_ll (void *target_func, InterpMethodArguments *margs) +static inline gint64 +get_long_arg (InterpMethodArguments *margs, int idx) { - gint64 (*func)(gint64 a) = target_func; - interp_pair p; - p.pair.lo = (gint32)margs->iargs [0]; - p.pair.hi = (gint32)margs->iargs [1]; - - gint64 res = func (p.l); - *(gint64*)margs->retval = res; + p.pair.lo = (gint32)margs->iargs [idx]; + p.pair.hi = (gint32)margs->iargs [idx + 1]; + return p.l; } -static void -wasm_invoke_li (void *target_func, InterpMethodArguments *margs) -{ - gint64 (*func)(gpointer a) = target_func; - gint64 res = func (margs->iargs [0]); - *(gint64*)margs->retval = res; -} - -static void -wasm_invoke_lil (void *target_func, InterpMethodArguments *margs) -{ - gint64 (*func)(gpointer a, gint64 b) = target_func; - - interp_pair p; - p.pair.lo = (gint32)margs->iargs [1]; - p.pair.hi = (gint32)margs->iargs [2]; - - gint64 res = func (margs->iargs [0], p.l); - *(gint64*)margs->retval = res; -} - -static void -wasm_invoke_dd (void *target_func, InterpMethodArguments *margs) -{ - double (*func)(double a) = target_func; - - double res = func (margs->fargs [FIDX (0)]); - *(double*)margs->retval = res; -} - -static void -wasm_invoke_ddd (void *target_func, InterpMethodArguments *margs) -{ - double (*func)(double a, double b) = target_func; - - double res = func (margs->fargs [FIDX (0)], margs->fargs [FIDX (1)]); - *(double*)margs->retval = res; -} - - - -static void -wasm_invoke_vif (void *target_func, InterpMethodArguments *margs) -{ - void (*func)(gpointer a, float b) = target_func; - - func (margs->iargs [0], - *(float*)&margs->fargs [FIDX (0)]); -} - -static void -wasm_invoke_viff (void *target_func, InterpMethodArguments *margs) -{ - void (*func)(gpointer a, float b, float c) = target_func; - - func (margs->iargs [0], - *(float*)&margs->fargs [FIDX (0)], - *(float*)&margs->fargs [FIDX (1)]); -} - -static void -wasm_invoke_viffff (void *target_func, InterpMethodArguments *margs) -{ - void (*func)(gpointer a, float b, float c, float d, float e) = target_func; - - func (margs->iargs [0], - *(float*)&margs->fargs [FIDX (0)], - *(float*)&margs->fargs [FIDX (1)], - *(float*)&margs->fargs [FIDX (2)], - *(float*)&margs->fargs [FIDX (3)]); -} - -static void -wasm_invoke_vifffffi (void *target_func, InterpMethodArguments *margs) -{ - void (*func)(gpointer a, float b, float c, float d, float e, float f, int g) = target_func; - - func (margs->iargs [0], - *(float*)&margs->fargs [FIDX (0)], - *(float*)&margs->fargs [FIDX (1)], - *(float*)&margs->fargs [FIDX (2)], - *(float*)&margs->fargs [FIDX (3)], - *(float*)&margs->fargs [FIDX (4)], - *(float*)&margs->iargs [1]); -} - -static void -wasm_invoke_ff (void *target_func, InterpMethodArguments *margs) -{ - float (*func)(float a) = target_func; - - float res = func (*(float*)&margs->fargs [FIDX (0)]); - *(float*)margs->retval = res; -} +#include "wasm_m2n_invoke.g.h" static void wasm_enter_icall_trampoline (void *target_func, InterpMethodArguments *margs) @@ -354,62 +136,7 @@ wasm_enter_icall_trampoline (void *target_func, InterpMethodArguments *margs) cookie [1 + sig->hasthis + i ] = type_to_c (sig->params [i]); cookie [c_count] = 0; - if (!strcmp ("V", cookie)) - wasm_invoke_v (target_func, margs); - else if (!strcmp ("VI", cookie)) - wasm_invoke_vi (target_func, margs); - else if (!strcmp ("VII", cookie)) - wasm_invoke_vii (target_func, margs); - else if (!strcmp ("VIII", cookie)) - wasm_invoke_viii (target_func, margs); - else if (!strcmp ("VIIII", cookie)) - wasm_invoke_viiii (target_func, margs); - else if (!strcmp ("VIIIII", cookie)) - wasm_invoke_viiiii (target_func, margs); - else if (!strcmp ("VIIIIII", cookie)) - wasm_invoke_viiiiii (target_func, margs); - else if (!strcmp ("I", cookie)) - wasm_invoke_i (target_func, margs); - else if (!strcmp ("II", cookie)) - wasm_invoke_ii (target_func, margs); - else if (!strcmp ("III", cookie)) - wasm_invoke_iii (target_func, margs); - else if (!strcmp ("IIII", cookie)) - wasm_invoke_iiii (target_func, margs); - else if (!strcmp ("IIIII", cookie)) - wasm_invoke_iiiii (target_func, margs); - else if (!strcmp ("IIIIII", cookie)) - wasm_invoke_iiiiii (target_func, margs); - else if (!strcmp ("IIIIIII", cookie)) - wasm_invoke_iiiiiii (target_func, margs); - else if (!strcmp ("IIIIIIIII", cookie)) - wasm_invoke_iiiiiiiii (target_func, margs); - else if (!strcmp ("L", cookie)) - wasm_invoke_l (target_func, margs); - else if (!strcmp ("LL", cookie)) - wasm_invoke_ll (target_func, margs); - else if (!strcmp ("LI", cookie)) - wasm_invoke_li (target_func, margs); - else if (!strcmp ("LIL", cookie)) - wasm_invoke_lil (target_func, margs); - else if (!strcmp ("DD", cookie)) - wasm_invoke_dd (target_func, margs); - else if (!strcmp ("DDD", cookie)) - wasm_invoke_ddd (target_func, margs); - else if (!strcmp ("VIF", cookie)) - wasm_invoke_vif (target_func, margs); - else if (!strcmp ("VIFF", cookie)) - wasm_invoke_viff (target_func, margs); - else if (!strcmp ("VIFFFF", cookie)) - wasm_invoke_viffff (target_func, margs); - else if (!strcmp ("VIFFFFFI", cookie)) - wasm_invoke_vifffffi (target_func, margs); - else if (!strcmp ("FF", cookie)) - wasm_invoke_ff (target_func, margs); - else { - printf ("CANNOT HANDLE COOKIE %s\n", cookie); - g_assert (0); - } + icall_trampoline_dispatch (cookie, target_func, margs); } gpointer diff --git a/mono/mini/aot-runtime.c b/mono/mini/aot-runtime.c index 36d3035520dd..baa8be474684 100644 --- a/mono/mini/aot-runtime.c +++ b/mono/mini/aot-runtime.c @@ -65,7 +65,9 @@ #include "version.h" #include "debugger-agent.h" #include "aot-compiler.h" +#include "aot-runtime.h" #include "jit-icalls.h" +#include "mini-runtime.h" #ifndef DISABLE_AOT @@ -1026,7 +1028,10 @@ decode_method_ref_with_target (MonoAotModule *module, MethodRef *ref, MonoMethod } else if (subtype == WRAPPER_SUBTYPE_GSHAREDVT_OUT) { ref->method = mono_marshal_get_gsharedvt_out_wrapper (); } else if (subtype == WRAPPER_SUBTYPE_INTERP_IN) { - ref->method = mini_get_interp_in_wrapper (target->signature); + MonoMethodSignature *sig = decode_signature (module, p, &p); + if (!sig) + return FALSE; + ref->method = mini_get_interp_in_wrapper (sig); } else if (subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG) { MonoMethodSignature *sig = decode_signature (module, p, &p); if (!sig) @@ -2419,6 +2424,7 @@ decode_cached_class_info (MonoAotModule *module, MonoCachedClassInfo *info, guin info->has_static_refs = (flags >> 6) & 0x1; info->no_special_static_fields = (flags >> 7) & 0x1; info->is_generic_container = (flags >> 8) & 0x1; + info->has_weak_fields = (flags >> 9) & 0x1; if (info->has_cctor) { res = decode_method_ref (module, &ref, buf, &buf, &error); @@ -2621,6 +2627,23 @@ mono_aot_get_class_from_name (MonoImage *image, const char *name_space, const ch return TRUE; } +GHashTable * +mono_aot_get_weak_field_indexes (MonoImage *image) +{ + MonoAotModule *amodule = (MonoAotModule *)image->aot_module; + + if (!amodule) + return NULL; + + /* Initialize weak field indexes from the cached copy */ + guint32 *indexes = amodule->info.weak_field_indexes; + int len = indexes [0]; + GHashTable *indexes_hash = g_hash_table_new (NULL, NULL); + for (int i = 0; i < len; ++i) + g_hash_table_insert (indexes_hash, GUINT_TO_POINTER (indexes [i + 1]), GUINT_TO_POINTER (1)); + return indexes_hash; +} + /* Compute the boundaries of the LLVM code for AMODULE. */ static void compute_llvm_code_range (MonoAotModule *amodule, guint8 **code_start, guint8 **code_end) diff --git a/mono/mini/aot-runtime.h b/mono/mini/aot-runtime.h new file mode 100644 index 000000000000..8be8862058e9 --- /dev/null +++ b/mono/mini/aot-runtime.h @@ -0,0 +1,254 @@ +/** + * \file + * Copyright 2002-2003 Ximian Inc + * Copyright 2003-2011 Novell Inc + * Copyright 2011 Xamarin Inc + * Licensed under the MIT license. See LICENSE file in the project root for full license information. + */ +#ifndef __MONO_AOT_RUNTIME_H__ +#define __MONO_AOT_RUNTIME_H__ + +#include "mini.h" + +/* Version number of the AOT file format */ +#define MONO_AOT_FILE_VERSION 142 + +#define MONO_AOT_TRAMP_PAGE_SIZE 16384 + +/* Constants used to encode different types of methods in AOT */ +enum { + MONO_AOT_METHODREF_MIN = 240, + /* Image index bigger than METHODREF_MIN */ + MONO_AOT_METHODREF_LARGE_IMAGE_INDEX = 249, + /* Runtime provided methods on arrays */ + MONO_AOT_METHODREF_ARRAY = 250, + MONO_AOT_METHODREF_NO_AOT_TRAMPOLINE = 251, + /* Wrappers */ + MONO_AOT_METHODREF_WRAPPER = 252, + /* Methods on generic instances */ + MONO_AOT_METHODREF_GINST = 253, + /* Methods resolve using a METHODSPEC token */ + MONO_AOT_METHODREF_METHODSPEC = 254, +}; + +/* Constants used to encode different types of types in AOT */ +enum { + /* typedef index */ + MONO_AOT_TYPEREF_TYPEDEF_INDEX = 1, + /* typedef index + image index */ + MONO_AOT_TYPEREF_TYPEDEF_INDEX_IMAGE = 2, + /* typespec token */ + MONO_AOT_TYPEREF_TYPESPEC_TOKEN = 3, + /* generic inst */ + MONO_AOT_TYPEREF_GINST = 4, + /* type/method variable */ + MONO_AOT_TYPEREF_VAR = 5, + /* array */ + MONO_AOT_TYPEREF_ARRAY = 6, + /* blob index of the type encoding */ + MONO_AOT_TYPEREF_BLOB_INDEX = 7, + /* ptr */ + MONO_AOT_TYPEREF_PTR = 8 +}; + +/* Trampolines which we have a lot of */ +typedef enum { + MONO_AOT_TRAMP_SPECIFIC = 0, + MONO_AOT_TRAMP_STATIC_RGCTX = 1, + MONO_AOT_TRAMP_IMT = 2, + MONO_AOT_TRAMP_GSHAREDVT_ARG = 3, + MONO_AOT_TRAMP_NUM = 4 +} MonoAotTrampoline; + +typedef enum { + MONO_AOT_FILE_FLAG_WITH_LLVM = 1, + MONO_AOT_FILE_FLAG_FULL_AOT = 2, + MONO_AOT_FILE_FLAG_DEBUG = 4, + MONO_AOT_FILE_FLAG_LLVM_THUMB = 8, + MONO_AOT_FILE_FLAG_LLVM_ONLY = 16, + MONO_AOT_FILE_FLAG_SAFEPOINTS = 32, + MONO_AOT_FILE_FLAG_SEPARATE_DATA = 64, + MONO_AOT_FILE_FLAG_EAGER_LOAD = 128, +} MonoAotFileFlags; + +typedef enum { + MONO_AOT_TABLE_BLOB, + MONO_AOT_TABLE_IMAGE_TABLE, + MONO_AOT_TABLE_CLASS_NAME, + MONO_AOT_TABLE_METHOD_INFO_OFFSETS, + MONO_AOT_TABLE_EX_INFO_OFFSETS, + MONO_AOT_TABLE_CLASS_INFO_OFFSETS, + MONO_AOT_TABLE_GOT_INFO_OFFSETS, + MONO_AOT_TABLE_LLVM_GOT_INFO_OFFSETS, + MONO_AOT_TABLE_EXTRA_METHOD_INFO_OFFSETS, + MONO_AOT_TABLE_EXTRA_METHOD_TABLE, + MONO_AOT_TABLE_NUM +} MonoAotFileTable; + +/* This structure is stored in the AOT file */ +typedef struct MonoAotFileInfo +{ + /* The version number of the AOT file format, should match MONO_AOT_FILE_VERSION */ + guint32 version; + /* For alignment */ + guint32 dummy; + + /* All the pointers should be at the start to avoid alignment problems */ + /* Symbols */ +#define MONO_AOT_FILE_INFO_FIRST_SYMBOL jit_got + /* Global Offset Table for JITted code */ + gpointer jit_got; + /* Global Offset Table for LLVM code */ + gpointer llvm_got; + /* Mono EH Frame created by llc when using LLVM */ + gpointer mono_eh_frame; + /* Points to the get_method () function in the LLVM image or NULL */ + gpointer llvm_get_method; + /* Points to the get_unbox_tramp () function in the LLVM image or NULL */ + gpointer llvm_get_unbox_tramp; + gpointer jit_code_start; + gpointer jit_code_end; + gpointer method_addresses; + /* Data blob */ + gpointer blob; + gpointer class_name_table; + gpointer class_info_offsets; + gpointer method_info_offsets; + gpointer ex_info_offsets; + gpointer extra_method_info_offsets; + gpointer extra_method_table; + gpointer got_info_offsets; + gpointer llvm_got_info_offsets; + gpointer image_table; + gpointer mem_end; + /* The GUID of the assembly which the AOT image was generated from */ + gpointer assembly_guid; + /* + * The runtime version string for AOT images generated using 'bind-to-runtime-version', + * NULL otherwise. + */ + gpointer runtime_version; + /* Blocks of various kinds of trampolines */ + gpointer specific_trampolines; + gpointer static_rgctx_trampolines; + gpointer imt_trampolines; + gpointer gsharedvt_arg_trampolines; + /* In static mode, points to a table of global symbols for trampolines etc */ + gpointer globals; + /* Points to a string containing the assembly name*/ + gpointer assembly_name; + /* Start of Mono's Program Linkage Table */ + gpointer plt; + /* End of Mono's Program Linkage Table */ + gpointer plt_end; + gpointer unwind_info; + /* Points to a table mapping methods to their unbox trampolines */ + gpointer unbox_trampolines; + /* Points to the end of the previous table */ + gpointer unbox_trampolines_end; + /* Points to a table of unbox trampoline addresses/offsets */ + gpointer unbox_trampoline_addresses; + /* Points to an array of weak field indexes */ + gpointer weak_field_indexes; +#define MONO_AOT_FILE_INFO_LAST_SYMBOL weak_field_indexes + + /* Scalars */ + /* The index of the first GOT slot used by the PLT */ + guint32 plt_got_offset_base; + /* Number of entries in the GOT */ + guint32 got_size; + /* Number of entries in the PLT */ + guint32 plt_size; + /* Number of methods */ + guint32 nmethods; + /* A union of MonoAotFileFlags */ + guint32 flags; + /* Optimization flags used to compile the module */ + guint32 opts; + /* SIMD flags used to compile the module */ + guint32 simd_opts; + /* Index of the blob entry holding the GC used by this module */ + gint32 gc_name_index; + guint32 num_rgctx_fetch_trampolines; + /* These are used for sanity checking object layout problems when cross-compiling */ + guint32 double_align, long_align, generic_tramp_num; + /* The page size used by trampoline pages */ + guint32 tramp_page_size; + /* + * The number of GOT entries which need to be preinitialized when the + * module is loaded. + */ + guint32 nshared_got_entries; + /* The size of the data file, if MONO_AOT_FILE_FLAG_SEPARATE_DATA is set */ + guint32 datafile_size; + + /* Arrays */ + /* Offsets for tables inside the data file if MONO_AOT_FILE_FLAG_SEPARATE_DATA is set */ + // FIXME: Sync with AOT + guint32 table_offsets [MONO_AOT_TABLE_NUM]; + /* Number of trampolines */ + guint32 num_trampolines [MONO_AOT_TRAMP_NUM]; + /* The indexes of the first GOT slots used by the trampolines */ + guint32 trampoline_got_offset_base [MONO_AOT_TRAMP_NUM]; + /* The size of one trampoline */ + guint32 trampoline_size [MONO_AOT_TRAMP_NUM]; + /* The offset where the trampolines begin on a trampoline page */ + guint32 tramp_page_code_offsets [MONO_AOT_TRAMP_NUM]; + /* GUID of aot compilation */ + guint8 aotid[16]; +} MonoAotFileInfo; + +/* Number of symbols in the MonoAotFileInfo structure */ +#define MONO_AOT_FILE_INFO_NUM_SYMBOLS (((G_STRUCT_OFFSET (MonoAotFileInfo, MONO_AOT_FILE_INFO_LAST_SYMBOL) - G_STRUCT_OFFSET (MonoAotFileInfo, MONO_AOT_FILE_INFO_FIRST_SYMBOL)) / sizeof (gpointer)) + 1) + +void mono_aot_init (void); +void mono_aot_cleanup (void); +gpointer mono_aot_get_method_checked (MonoDomain *domain, + MonoMethod *method, MonoError *error); +gpointer mono_aot_get_method_from_token (MonoDomain *domain, MonoImage *image, guint32 token, MonoError *error); +gboolean mono_aot_is_got_entry (guint8 *code, guint8 *addr); +guint8* mono_aot_get_plt_entry (guint8 *code); +guint32 mono_aot_get_plt_info_offset (mgreg_t *regs, guint8 *code); +gboolean mono_aot_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res); +gboolean mono_aot_get_class_from_name (MonoImage *image, const char *name_space, const char *name, MonoClass **klass); +MonoJitInfo* mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr); +gpointer mono_aot_plt_resolve (gpointer aot_module, guint32 plt_info_offset, guint8 *code, MonoError *error); +void mono_aot_patch_plt_entry (guint8 *code, guint8 *plt_entry, gpointer *got, mgreg_t *regs, guint8 *addr); +gpointer mono_aot_get_method_from_vt_slot (MonoDomain *domain, MonoVTable *vtable, int slot, MonoError *error); +gpointer mono_aot_create_specific_trampoline (MonoImage *image, gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len); +gpointer mono_aot_get_trampoline (const char *name); +gpointer mono_aot_get_trampoline_full (const char *name, MonoTrampInfo **out_tinfo); +gpointer mono_aot_get_unbox_trampoline (MonoMethod *method); +gpointer mono_aot_get_lazy_fetch_trampoline (guint32 slot); +gpointer mono_aot_get_static_rgctx_trampoline (gpointer ctx, gpointer addr); +gpointer mono_aot_get_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count, gpointer fail_tramp); +gpointer mono_aot_get_gsharedvt_arg_trampoline(gpointer arg, gpointer addr); +guint8* mono_aot_get_unwind_info (MonoJitInfo *ji, guint32 *unwind_info_len); +guint32 mono_aot_method_hash (MonoMethod *method); +gboolean mono_aot_can_dedup (MonoMethod *method); +MonoMethod* mono_aot_get_array_helper_from_wrapper (MonoMethod *method); +void mono_aot_set_make_unreadable (gboolean unreadable); +gboolean mono_aot_is_pagefault (void *ptr); +void mono_aot_handle_pagefault (void *ptr); +void mono_aot_register_jit_icall (const char *name, gpointer addr); +guint32 mono_aot_find_method_index (MonoMethod *method); +void mono_aot_init_llvm_method (gpointer aot_module, guint32 method_index); +void mono_aot_init_gshared_method_this (gpointer aot_module, guint32 method_index, MonoObject *this_ins); +void mono_aot_init_gshared_method_mrgctx (gpointer aot_module, guint32 method_index, MonoMethodRuntimeGenericContext *rgctx); +void mono_aot_init_gshared_method_vtable (gpointer aot_module, guint32 method_index, MonoVTable *vtable); +GHashTable *mono_aot_get_weak_field_indexes (MonoImage *image); + +/* This is an exported function */ +MONO_API void mono_aot_register_module (gpointer *aot_info); + +/* These are used to load the AOT data for aot images compiled with MONO_AOT_FILE_FLAG_SEPARATE_DATA */ +/* + * Return the AOT data for ASSEMBLY. SIZE is the size of the data. OUT_HANDLE should be set to a handle which is later + * passed to the free function. + */ +typedef unsigned char* (*MonoLoadAotDataFunc) (MonoAssembly *assembly, int size, gpointer user_data, void **out_handle); +/* Not yet used */ +typedef void (*MonoFreeAotDataFunc) (MonoAssembly *assembly, int size, gpointer user_data, void *handle); +MONO_API void mono_install_load_aot_data_hook (MonoLoadAotDataFunc load_func, MonoFreeAotDataFunc free_func, gpointer user_data); + +#endif /* __MONO_AOT_RUNTIME_H__ */ diff --git a/mono/mini/aot-tests.cs b/mono/mini/aot-tests.cs index 176cbeac7484..7e718784acda 100644 --- a/mono/mini/aot-tests.cs +++ b/mono/mini/aot-tests.cs @@ -411,6 +411,7 @@ public static bool GetHasValue(T? value) where T : struct [Category ("DYNCALL")] [Category ("!FULLAOT-AMD64")] + [Category ("!WASM")] //Interp fails public static int test_0_large_nullable_invoke () { var s = new LargeStruct () { a = 1, b = 2, c = 3, d = 4 }; diff --git a/mono/mini/cpu-arm64.md b/mono/mini/cpu-arm64.md index 8b1cf4118cc3..840d26067adc 100644 --- a/mono/mini/cpu-arm64.md +++ b/mono/mini/cpu-arm64.md @@ -440,7 +440,7 @@ long_conv_to_u2: dest:i src1:i len:4 long_conv_to_r8: dest:f src1:i len:8 long_conv_to_r4: dest:f src1:i len:12 loadi8_membase: dest:i src1:b len:12 -storei8_membase_imm: dest:b len:20 +storei8_membase_imm: dest:b len:20 storei8_membase_reg: dest:b src1:i len:12 long_conv_to_r_un: dest:f src1:i len:8 arm_setfreg_r4: dest:f src1:f len:8 diff --git a/mono/mini/cpu-s390x.md b/mono/mini/cpu-s390x.md index e80fcdce42a0..f0a89c6fc3a7 100644 --- a/mono/mini/cpu-s390x.md +++ b/mono/mini/cpu-s390x.md @@ -88,8 +88,8 @@ cond_exc_nc: len:8 cond_exc_ne_un: len:8 cond_exc_no: len:8 cond_exc_ov: len:8 -div_imm: dest:i src1:i src2:i len:24 -div_un_imm: dest:i src1:i src2:i len:24 +div_imm: dest:i src1:i len:24 +div_un_imm: dest:i src1:i len:24 endfinally: len:8 fcall: dest:g len:26 clob:c fcall_membase: dest:g src1:b len:14 clob:c @@ -163,7 +163,7 @@ loadu2_membase: dest:i src1:b len:30 loadu4_mem: dest:i len:8 loadu4_membase: dest:i src1:b len:30 localloc: dest:i src1:i len:106 -memory_barrier: len: 10 +memory_barrier: len:10 move: dest:i src1:i len:4 mul_imm: dest:i src1:i len:24 nop: len:4 @@ -176,9 +176,9 @@ rethrow: src1:i len:26 or_imm: dest:i src1:i len:24 r4const: dest:f len:26 r8const: dest:f len:24 -rem_imm: dest:i src1:i src2:i len:24 -rem_un_imm: dest:i src1:i src2:i len:24 -s390_bkchain: len: 8 dest:i src1:i +rem_imm: dest:i src1:i len:24 +rem_un_imm: dest:i src1:i len:24 +s390_bkchain: len:8 dest:i src1:i s390_move: len:48 dest:b src1:b s390_setf4ret: dest:f src1:f len:4 sbb: dest:i src1:i src2:i len:6 @@ -303,7 +303,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_imm: dest:i src1: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 @@ -320,7 +320,7 @@ long_conv_to_i2: dest:i src1:i len:12 long_conv_to_i4: dest:i src1:i len:4 long_conv_to_i8: dest:i src1:i len:4 long_conv_to_i: dest:i src1:i len:4 -long_conv_to_ovf_i: dest:i src1:i src2:i len:44 +long_conv_to_ovf_i: dest:i src1:i len:44 long_conv_to_ovf_i4_un: dest:i src1:i len:50 long_conv_to_ovf_u4: dest:i src1:i len:48 long_conv_to_ovf_u8_un: dest:i src1:i len:4 @@ -412,7 +412,7 @@ s390_crj: src1:i src2:i len:24 s390_crj_un: src1:i src2:i len:24 s390_cgrj: src1:i src2:i len:24 s390_cgrj_un: src1:i src2:i len:24 -s390_cij: src1:i len:24 +s390_cij: len:24 s390_cij_un: src1:i len:24 -s390_cgij: src1:i len:24 -s390_cgij_un: src1:i len:24 +s390_cgij: len:24 +s390_cgij_un: len:24 diff --git a/mono/mini/cpu-x86.md b/mono/mini/cpu-x86.md index 870b10b23975..e0c9625f78a4 100644 --- a/mono/mini/cpu-x86.md +++ b/mono/mini/cpu-x86.md @@ -81,18 +81,18 @@ int_ble_un: len:6 int_blt_un: len:6 label: len:0 -template: name:ibalu dest:i src1:i src2:i clob:1 len:2 +#template: name:ibalu -int_add: template:ibalu -int_sub: template:ibalu -int_mul: template:ibalu len:3 +int_add: dest:i src1:i src2:i clob:1 len:2 +int_sub: dest:i src1:i src2:i clob:1 len:2 +int_mul: dest:i src1:i src2:i clob:1 len:3 int_div: dest:a src1:a src2:i len:15 clob:d int_div_un: dest:a src1:a src2:i len:15 clob:d int_rem: dest:d src1:a src2:i len:15 clob:a int_rem_un: dest:d src1:a src2:i len:15 clob:a -int_and: template:ibalu -int_or: template:ibalu -int_xor: template:ibalu +int_and: dest:i src1:i src2:i clob:1 len:2 +int_or: dest:i src1:i src2:i clob:1 len:2 +int_xor: dest:i src1:i src2:i clob:1 len:2 int_shl: dest:i src1:i src2:s clob:1 len:2 int_shr: dest:i src1:i src2:s clob:1 len:2 int_shr_un: dest:i src1:i src2:s clob:1 len:2 diff --git a/mono/mini/debugger-agent.c b/mono/mini/debugger-agent.c index 4e8d5cacb302..5cade0588401 100644 --- a/mono/mini/debugger-agent.c +++ b/mono/mini/debugger-agent.c @@ -76,6 +76,8 @@ #include #include "mini.h" #include "seq-points.h" +#include "aot-runtime.h" +#include "mini-runtime.h" #include "interp/interp.h" /* @@ -1050,11 +1052,11 @@ mono_debugger_agent_init (void) /* Needed by the hash_table_new_type () call below */ mono_gc_base_init (); - thread_to_tls = mono_g_hash_table_new_type ((GHashFunc)mono_object_hash, NULL, MONO_HASH_KEY_GC, MONO_ROOT_SOURCE_DEBUGGER, "thread-to-tls table"); + thread_to_tls = mono_g_hash_table_new_type ((GHashFunc)mono_object_hash, NULL, MONO_HASH_KEY_GC, MONO_ROOT_SOURCE_DEBUGGER, NULL, "Debugger TLS Table"); - tid_to_thread = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DEBUGGER, "tid-to-thread table"); + tid_to_thread = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DEBUGGER, NULL, "Debugger Thread Table"); - tid_to_thread_obj = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DEBUGGER, "tid-to-thread object table"); + tid_to_thread_obj = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DEBUGGER, NULL, "Debugger Thread Object Table"); pending_assembly_loads = g_ptr_array_new (); domains = g_hash_table_new (mono_aligned_addr_hash, NULL); @@ -2031,7 +2033,7 @@ objrefs_init (void) { objrefs = g_hash_table_new_full (NULL, NULL, NULL, free_objref); obj_to_objref = g_hash_table_new (NULL, NULL); - suspended_objs = mono_g_hash_table_new_type ((GHashFunc)mono_object_hash, NULL, MONO_HASH_KEY_GC, MONO_ROOT_SOURCE_DEBUGGER, "suspended objects table"); + suspended_objs = mono_g_hash_table_new_type ((GHashFunc)mono_object_hash, NULL, MONO_HASH_KEY_GC, MONO_ROOT_SOURCE_DEBUGGER, NULL, "Debugger Suspended Object Table"); } static void @@ -2611,11 +2613,11 @@ get_top_method_ji (gpointer ip, MonoDomain **domain, gpointer *out_ip) g_assert (ext->interp_exit); frame = ext->interp_exit_data; - ji = mono_interp_frame_get_jit_info (frame); + ji = mini_get_interp_callbacks ()->frame_get_jit_info (frame); if (domain) *domain = mono_domain_get (); if (out_ip) - *out_ip = mono_interp_frame_get_ip (frame); + *out_ip = mini_get_interp_callbacks ()->frame_get_ip (frame); } return ji; } @@ -4127,8 +4129,8 @@ thread_startup (MonoProfiler *prof, uintptr_t tid) tls = il2cpp_gc_alloc_fixed(sizeof(DebuggerTlsData)); #else tls = g_new0 (DebuggerTlsData, 1); - MONO_GC_REGISTER_ROOT_SINGLE (tls->thread, MONO_ROOT_SOURCE_DEBUGGER, "debugger thread reference"); #endif + MONO_GC_REGISTER_ROOT_SINGLE (tls->thread, MONO_ROOT_SOURCE_DEBUGGER, NULL, "Debugger Thread Reference"); tls->thread = thread; mono_native_tls_set_value (debugger_tls_id, tls); @@ -4527,7 +4529,7 @@ insert_breakpoint (MonoSeqPointInfo *seq_points, MonoDomain *domain, MonoJitInfo DEBUG_PRINTF (1, "[dbg] Attempting to insert seq point at dead IL offset %d, ignoring.\n", (int)bp->il_offset); } else if (count == 0) { if (ji->is_interp) { - mono_interp_set_breakpoint (ji, inst->ip); + mini_get_interp_callbacks ()->set_breakpoint (ji, inst->ip); } else { #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED mono_arch_set_breakpoint (ji, inst->ip); @@ -4559,7 +4561,7 @@ remove_breakpoint (BreakpointInstance *inst) if (count == 1 && inst->native_offset != SEQ_POINT_NATIVE_OFFSET_DEAD_CODE) { if (ji->is_interp) - mono_interp_clear_breakpoint (ji, ip); + mini_get_interp_callbacks ()->clear_breakpoint (ji, ip); else mono_arch_clear_breakpoint (ji, ip); DEBUG_PRINTF (1, "[dbg] Clear breakpoint at %s [%p].\n", mono_method_full_name (jinfo_get_method (ji), TRUE), ip); @@ -4691,7 +4693,7 @@ set_bp_in_method (MonoDomain *domain, MonoMethod *method, MonoSeqPointInfo *seq_ ji = mono_jit_info_table_find (domain, (char *)code); } else { /* Might be interpreted */ - ji = mono_interp_find_jit_info (domain, method); + ji = mini_get_interp_callbacks ()->find_jit_info (domain, method); } g_assert (ji); } @@ -4754,6 +4756,16 @@ set_breakpoint (MonoMethod *method, long il_offset, EventRequest *req, MonoError { if (bp_matches_method(bp, seqPoint->method) && seqPoint->ilOffset == bp->il_offset) { + if (req->event_kind == EVENT_KIND_BREAKPOINT && seqPoint->kind == kSequencePointKind_StepOut) + continue; + + if (req->event_kind == EVENT_KIND_STEP) + { + SingleStepReq *ssreq = (SingleStepReq*)req->info; + if (ssreq->depth == STEP_DEPTH_OUT && seqPoint->kind != kSequencePointKind_StepOut) + continue; + } + BreakpointInstance* inst = g_new0(BreakpointInstance, 1); inst->il_offset = bp->il_offset;// it.seq_point.il_offset; inst->native_offset = 0;// it.seq_point.native_offset; @@ -5171,7 +5183,7 @@ get_this_addr (StackFrame *frame) { #ifndef IL2CPP_MONO_DEBUGGER if (frame->ji->is_interp) - return mono_interp_frame_get_this (frame->interp_frame); + return mini_get_interp_callbacks ()->frame_get_this (frame->interp_frame); MonoDebugVarInfo *var = frame->jit->this_var; if ((var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS) != MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET) @@ -5346,8 +5358,8 @@ process_breakpoint (DebuggerTlsData *tls, gboolean from_signal) g_assert (ext->interp_exit); frame = ext->interp_exit_data; - ji = mono_interp_frame_get_jit_info (frame); - ip = mono_interp_frame_get_ip (frame); + ji = mini_get_interp_callbacks ()->frame_get_jit_info (frame); + ip = mini_get_interp_callbacks ()->frame_get_ip (frame); } #endif @@ -5919,7 +5931,7 @@ start_single_stepping (void) if (val == 1) { mono_arch_start_single_stepping (); #ifndef IL2CPP_MONO_DEBUGGER - mono_interp_start_single_stepping (); + mini_get_interp_callbacks ()->start_single_stepping (); #endif } #else @@ -5936,7 +5948,7 @@ stop_single_stepping (void) if (val == 0) { mono_arch_stop_single_stepping (); #ifndef IL2CPP_MONO_DEBUGGER - mono_interp_stop_single_stepping (); + mini_get_interp_callbacks ()->stop_single_stepping (); #endif } #else @@ -10280,10 +10292,25 @@ method_commands_internal (int command, MonoMethod *method, MonoDomain *domain, g buffer_add_string(buf, ""); } } - buffer_add_int(buf, sequencePoints->len); + + int numSeqPoints = 0; + + for (i = 0; i < sequencePoints->len; ++i) { + Il2CppSequencePoint* sequencePoint = g_ptr_array_index(sequencePoints, i); + if (sequencePoint->kind == kSequencePointKind_StepOut) + continue; + else + ++numSeqPoints; + } + + buffer_add_int(buf, numSeqPoints); DEBUG_PRINTF(10, "Line number table for method %s:\n", mono_method_full_name(method, TRUE)); for (i = 0; i < sequencePoints->len; ++i) { Il2CppSequencePoint* sequencePoint = g_ptr_array_index(sequencePoints, i); + + if (sequencePoint->kind == kSequencePointKind_StepOut) + continue; + DEBUG_PRINTF(10, "IL%x -> %s:%d %d %d %d\n", sequencePoint->ilOffset, sequencePoint->sourceFile, sequencePoint->lineStart, sequencePoint->columnStart, sequencePoint->lineEnd, sequencePoint->columnEnd); buffer_add_int(buf, sequencePoint->ilOffset); @@ -10864,7 +10891,7 @@ thread_commands (int command, guint8 *p, guint8 *end, Buffer *buf) if (tls->frames [0]->ji->is_interp) { MonoJitTlsData *jit_data = ((MonoThreadInfo*)thread->thread_info)->jit_data; - mono_interp_set_resume_state (jit_data, NULL, NULL, tls->frames [0]->interp_frame, (guint8*)tls->frames [0]->ji->code_start + sp.native_offset); + mini_get_interp_callbacks ()->set_resume_state (jit_data, NULL, NULL, tls->frames [0]->interp_frame, (guint8*)tls->frames [0]->ji->code_start + sp.native_offset); } else { MONO_CONTEXT_SET_IP (&tls->restore_state.ctx, (guint8*)tls->frames [0]->ji->code_start + sp.native_offset); } @@ -11014,7 +11041,7 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf) if (frame->ji->is_interp) { guint8 *addr; - addr = mono_interp_frame_get_arg (frame->interp_frame, pos); + addr = mini_get_interp_callbacks ()->frame_get_arg (frame->interp_frame, pos); buffer_add_value_full (buf, sig->params [pos], addr, frame->domain, FALSE, NULL); } else { @@ -11041,7 +11068,7 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf) if (frame->ji->is_interp) { guint8 *addr; - addr = mono_interp_frame_get_local (frame->interp_frame, pos); + addr = mini_get_interp_callbacks ()->frame_get_local (frame->interp_frame, pos); buffer_add_value_full (buf, header->locals [pos], addr, frame->domain, FALSE, NULL); } else { @@ -11071,7 +11098,7 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf) if (frame->ji->is_interp) { guint8 *addr; - addr = mono_interp_frame_get_this (frame->interp_frame); + addr = mini_get_interp_callbacks ()->frame_get_this (frame->interp_frame); buffer_add_value_full (buf, &frame->actual_method->klass->this_arg, addr, frame->domain, FALSE, NULL); } else { @@ -11097,7 +11124,7 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf) if (frame->ji->is_interp) { guint8 *addr; - addr = mono_interp_frame_get_this (frame->interp_frame); + addr = mini_get_interp_callbacks ()->frame_get_this (frame->interp_frame); buffer_add_value_full (buf, &frame->api_method->klass->byval_arg, addr, frame->domain, FALSE, NULL); } else { @@ -11174,9 +11201,9 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf) guint8 *addr; if (is_arg) - addr = mono_interp_frame_get_arg (frame->interp_frame, pos); + addr = mini_get_interp_callbacks ()->frame_get_arg (frame->interp_frame, pos); else - addr = mono_interp_frame_get_local (frame->interp_frame, pos); + addr = mini_get_interp_callbacks ()->frame_get_local (frame->interp_frame, pos); set_interp_var (t, addr, val_buf); } else { set_var (t, var, &frame->ctx, frame->domain, val_buf, frame->reg_locations, &tls->restore_state.ctx); @@ -11217,7 +11244,7 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf) if (frame->ji->is_interp) { guint8 *addr; - addr = mono_interp_frame_get_this (frame->interp_frame); + addr = mini_get_interp_callbacks ()->frame_get_this (frame->interp_frame); set_interp_var (&frame->actual_method->klass->this_arg, addr, val_buf); } else { var = jit->this_var; @@ -12046,10 +12073,10 @@ unity_process_breakpoint_inner(DebuggerTlsData *tls, gboolean from_signal, Il2Cp inst = (BreakpointInstance *)g_ptr_array_index(bp->children, j); if (inst->il_offset == sequencePoint->ilOffset) { if (bp->req->event_kind == EVENT_KIND_STEP) { - for (int j = 0; j < bp->children->len; ++j) + for (int k = 0; k < bp->children->len; ++k) { - BreakpointInstance *inst = (BreakpointInstance *)g_ptr_array_index(bp->children, j); - if (inst->seq_point == sequencePoint) + BreakpointInstance *inst1 = (BreakpointInstance *)g_ptr_array_index(bp->children, k); + if (inst1->seq_point == sequencePoint) { g_ptr_array_add(ss_reqs_orig, bp->req); break; diff --git a/mono/mini/driver.c b/mono/mini/driver.c index fc14f286f2ce..a058e521a4bd 100644 --- a/mono/mini/driver.c +++ b/mono/mini/driver.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -57,6 +58,8 @@ #include "mini.h" #include "jit.h" #include "aot-compiler.h" +#include "aot-runtime.h" +#include "mini-runtime.h" #include "interp/interp.h" #include @@ -561,6 +564,171 @@ mini_regression_list (int verbose, int count, char *images []) return total; } +static void +interp_regression_step (MonoImage *image, int verbose, int *total_run, int *total, GTimer *timer, MonoDomain *domain) +{ + int result, expected, failed, cfailed, run; + double elapsed, transform_time; + int i; + MonoObject *result_obj; + static gboolean filter_method_init = FALSE; + static const char *filter_method = NULL; + + g_print ("Test run: image=%s\n", mono_image_get_filename (image)); + cfailed = failed = run = 0; + transform_time = elapsed = 0.0; + + g_timer_start (timer); + for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) { + MonoObject *exc = NULL; + MonoError error; + MonoMethod *method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error); + if (!method) { + mono_error_cleanup (&error); /* FIXME don't swallow the error */ + continue; + } + + if (!filter_method_init) { + filter_method = g_getenv ("INTERP_FILTER_METHOD"); + filter_method_init = TRUE; + } + gboolean filter = FALSE; + if (filter_method) { + const char *name = filter_method; + + if ((strchr (name, '.') > name) || strchr (name, ':')) { + MonoMethodDesc *desc = mono_method_desc_new (name, TRUE); + filter = mono_method_desc_full_match (desc, method); + mono_method_desc_free (desc); + } else { + filter = strcmp (method->name, name) == 0; + } + } else { /* no filter, check for `Category' attribute on method */ + filter = TRUE; + MonoCustomAttrInfo* ainfo = mono_custom_attrs_from_method_checked (method, &error); + mono_error_cleanup (&error); + + if (ainfo) { + int j; + for (j = 0; j < ainfo->num_attrs && filter; ++j) { + MonoCustomAttrEntry *centry = &ainfo->attrs [j]; + if (centry->ctor == NULL) + continue; + + MonoClass *klass = centry->ctor->klass; + if (strcmp (klass->name, "CategoryAttribute")) + continue; + + MonoObject *obj = mono_custom_attrs_get_attr_checked (ainfo, klass, &error); + /* FIXME: there is an ordering problem if there're multiple attributes, do this instead: + * MonoObject *obj = create_custom_attr (ainfo->image, centry->ctor, centry->data, centry->data_size, &error); */ + mono_error_cleanup (&error); + MonoMethod *getter = mono_class_get_method_from_name (klass, "get_Category", -1); + MonoObject *str = mini_get_interp_callbacks ()->runtime_invoke (getter, obj, NULL, &exc, &error); + mono_error_cleanup (&error); + char *utf8_str = mono_string_to_utf8_checked ((MonoString *) str, &error); + mono_error_cleanup (&error); + if (!strcmp (utf8_str, "!INTERPRETER")) { + g_print ("skip %s...\n", method->name); + filter = FALSE; + } + } + } + } + if (strncmp (method->name, "test_", 5) == 0 && filter) { + MonoError interp_error; + MonoObject *exc = NULL; + + result_obj = mini_get_interp_callbacks ()->runtime_invoke (method, NULL, NULL, &exc, &interp_error); + if (!mono_error_ok (&interp_error)) { + cfailed++; + g_print ("Test '%s' execution failed.\n", method->name); + } else if (exc != NULL) { + g_print ("Exception in Test '%s' occured:\n", method->name); + mono_object_describe (exc); + run++; + failed++; + } else { + result = *(gint32 *) mono_object_unbox (result_obj); + expected = atoi (method->name + 5); // FIXME: oh no. + run++; + + if (result != expected) { + failed++; + g_print ("Test '%s' failed result (got %d, expected %d).\n", method->name, result, expected); + } + } + } + } + g_timer_stop (timer); + elapsed = g_timer_elapsed (timer, NULL); + if (failed > 0 || cfailed > 0){ + g_print ("Results: total tests: %d, failed: %d, cfailed: %d (pass: %.2f%%)\n", + run, failed, cfailed, 100.0*(run-failed-cfailed)/run); + } else { + g_print ("Results: total tests: %d, all pass \n", run); + } + + g_print ("Elapsed time: %f secs (%f, %f)\n\n", elapsed, + elapsed - transform_time, transform_time); + *total += failed + cfailed; + *total_run += run; +} + +static int +interp_regression (MonoImage *image, int verbose, int *total_run) +{ + MonoMethod *method; + GTimer *timer = g_timer_new (); + MonoDomain *domain = mono_domain_get (); + guint32 i; + int total; + + /* load the metadata */ + for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) { + MonoError error; + method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error); + if (!method) { + mono_error_cleanup (&error); + continue; + } + mono_class_init (method->klass); + } + + total = 0; + *total_run = 0; + interp_regression_step (image, verbose, total_run, &total, timer, domain); + + g_timer_destroy (timer); + return total; +} + +/* TODO: merge this code with the regression harness of the JIT */ +static int +mono_interp_regression_list (int verbose, int count, char *images []) +{ + int i, total, total_run, run; + + total_run = total = 0; + for (i = 0; i < count; ++i) { + MonoAssembly *ass = mono_assembly_open_predicate (images [i], FALSE, FALSE, NULL, NULL, NULL); + if (!ass) { + g_warning ("failed to load assembly: %s", images [i]); + continue; + } + total += interp_regression (mono_assembly_get_image (ass), verbose, &run); + total_run += run; + } + if (total > 0) { + g_print ("Overall results: tests: %d, failed: %d (pass: %.2f%%)\n", total_run, total, 100.0*(total_run-total)/total_run); + } else { + g_print ("Overall results: tests: %d, 100%% pass\n", total_run); + } + + return total; +} + + #ifdef MONO_JIT_INFO_TABLE_TEST typedef struct _JitInfoData { diff --git a/mono/mini/exceptions-amd64.c b/mono/mini/exceptions-amd64.c index be3330b61b5c..5a4c0fdfce40 100644 --- a/mono/mini/exceptions-amd64.c +++ b/mono/mini/exceptions-amd64.c @@ -42,6 +42,8 @@ #include "mini.h" #include "mini-amd64.h" +#include "mini-runtime.h" +#include "aot-runtime.h" #include "tasklets.h" #define ALIGN_TO(val,align) (((val) + ((align) - 1)) & ~((align) - 1)) diff --git a/mono/mini/exceptions-arm.c b/mono/mini/exceptions-arm.c index 20d15e38e38b..a3ab2ac90e73 100644 --- a/mono/mini/exceptions-arm.c +++ b/mono/mini/exceptions-arm.c @@ -36,6 +36,8 @@ #include "mini.h" #include "mini-arm.h" +#include "mini-runtime.h" +#include "aot-runtime.h" #include "mono/utils/mono-sigcontext.h" #include "mono/utils/mono-compiler.h" diff --git a/mono/mini/exceptions-arm64.c b/mono/mini/exceptions-arm64.c index 9bdd8e3c5f6b..53bb332b6994 100644 --- a/mono/mini/exceptions-arm64.c +++ b/mono/mini/exceptions-arm64.c @@ -15,6 +15,8 @@ */ #include "mini.h" +#include "mini-runtime.h" +#include "aot-runtime.h" #include #include diff --git a/mono/mini/exceptions-mips.c b/mono/mini/exceptions-mips.c index cc8e56d525af..850fcc084af3 100644 --- a/mono/mini/exceptions-mips.c +++ b/mono/mini/exceptions-mips.c @@ -28,6 +28,8 @@ #include "mini.h" #include "mini-mips.h" +#include "mini-runtime.h" +#include "aot-runtime.h" #define GENERIC_EXCEPTION_SIZE 256 diff --git a/mono/mini/exceptions-ppc.c b/mono/mini/exceptions-ppc.c index 5e22cb967c88..d00ed4c942c5 100644 --- a/mono/mini/exceptions-ppc.c +++ b/mono/mini/exceptions-ppc.c @@ -30,6 +30,8 @@ #include "mini.h" #include "mini-ppc.h" +#include "mini-runtime.h" +#include "aot-runtime.h" /* diff --git a/mono/mini/exceptions-s390x.c b/mono/mini/exceptions-s390x.c index 19204c6ccd6b..4f7694acbe0a 100644 --- a/mono/mini/exceptions-s390x.c +++ b/mono/mini/exceptions-s390x.c @@ -60,6 +60,8 @@ #include "mini.h" #include "mini-s390x.h" #include "support-s390x.h" +#include "mini-runtime.h" +#include "aot-runtime.h" /*========================= End of Includes ========================*/ diff --git a/mono/mini/exceptions-x86.c b/mono/mini/exceptions-x86.c index 268838badcd1..b4df2f2c03b7 100644 --- a/mono/mini/exceptions-x86.c +++ b/mono/mini/exceptions-x86.c @@ -30,7 +30,9 @@ #include "mini.h" #include "mini-x86.h" +#include "mini-runtime.h" #include "tasklets.h" +#include "aot-runtime.h" static gpointer signal_exception_trampoline; diff --git a/mono/mini/genmdesc.pl b/mono/mini/genmdesc.pl deleted file mode 100755 index ae49ecba9f28..000000000000 --- a/mono/mini/genmdesc.pl +++ /dev/null @@ -1,257 +0,0 @@ -#!/usr/bin/perl -w - -# perl replacement of genmdesc.c for use when cross-compiling - -use strict; -no locale; - -# must keep in sync with mini.h -my @spec_names = qw(dest src1 src2 src3 len clob nacl); -sub INST_DEST () {return 0;} -sub INST_SRC1 () {return 1;} -sub INST_SRC2 () {return 2;} -sub INST_SRC3 () {return 3;} -sub INST_LEN () {return 4;} -sub INST_CLOB () {return 5;} -# making INST_NACL the same as INST_MAX is not a mistake, -# INST_NACL writes over INST_LEN, it's not its own field -sub INST_NACL () {return 6;} -sub INST_MAX () {return 6;} - -# this must include all the #defines used in mini-ops.h -my @defines = qw (__i386__ __x86_64__ __ppc__ __powerpc__ __ppc64__ __arm__ - __sparc__ sparc __s390__ s390 __alpha__ __mips__ __aarch64__ __wasm__); -my %table =(); -my %template_table =(); -my @opcodes = (); - -my $nacl = 0; - -sub parse_file -{ - my ($define, $file) = @_; - my @enabled = (1); - my $i = 0; - open (OPS, $file) || die "Cannot open $file: $!"; - while () { - if (/^\s*#\s*if\s+(.*)/) { - my $defines = $1; - die "fix the genmdesc.pl cpp parser to handle all operators" if /(&&)|([!<>=])/; - unshift @enabled, scalar ($defines =~ /defined\s*\(\s*$define\s*\)/); - next; - } - if (/^\s*#\s*ifdef\s+(\S+)/) { - my $defines = $1; - unshift @enabled, $defines eq $define; - next; - } - if (/^\s*#\s*endif/) { - shift @enabled; - next; - } - next unless $enabled [0]; - next unless /MINI_OP3?\s*\(\s*(\S+?)\s*,\s*"(.*?)"/; - my ($sym, $name) = ($1, $2); - push @opcodes, [$sym, $name]; - $table{$name} = {num => $i, name => $name}; - $i++; - } - close (OPS); -} - -sub load_opcodes -{ - my ($srcdir, $arch) = @_; - my $opcodes_def = "$srcdir/../cil/opcode.def"; - my $i = 0; - my $arch_found = 0; - - my $cpp = $ENV{"CPP"}; - $cpp = "cpp" unless defined $cpp; - $cpp .= " -undef "; - foreach (@defines) { - $cpp .= " -U$_"; - $arch_found = 1 if $arch eq $_; - } - die "$arch arch is not supported.\n" unless $arch_found; - - my $arch_define = $arch; - if ($arch =~ "__i386__") { - $arch_define = "TARGET_X86"; - } - if ($arch =~ "__x86_64__") { - $arch_define = "TARGET_AMD64"; - } - if ($arch =~ "__arm__") { - $arch_define = "TARGET_ARM"; - } - if ($arch =~ "__aarch64__") { - $arch_define = "TARGET_ARM64"; - } - if ($arch =~ "__wasm__") { - $arch_define = "TARGET_WASM"; - } - parse_file ($arch_define, "$srcdir/mini-ops.h"); - return; - $cpp .= " -D$arch_define $srcdir/mini-ops.h|"; - #print "Running: $cpp\n"; - open (OPS, $cpp) || die "Cannot execute cpp: $!"; - while () { - next unless /MINI_OP3?\s*\(\s*(\S+?)\s*,\s*"(.*?)"/; - my ($sym, $name) = ($1, $2); - push @opcodes, [$sym, $name]; - $table{$name} = {num => $i, name => $name}; - $i++; - } - close (OPS); -} - -sub load_file { - my ($name) = @_; - my $line = 0; - my $comment = ""; - - open (DESC, $name) || die "Cannot open $name: $!"; - while () { - my $is_template = 0; - $line++; - next if /^\s*$/; - if (/^\s*(#.*)?$/) { - $comment .= "$1\n"; - next; - } - my @values = split (/\s+/); - next unless ($values [0] =~ /(\S+?):/); - my $name = $1; - my $desc; - if ($name eq "template") { - $is_template = 1; - $desc = {}; - } else { - $desc = $table {$name}; - die "Invalid opcode $name at line $line\n" unless defined $desc; - die "Duplicated opcode $name at line $line\n" if $desc->{"desc"}; - } - shift @values; - $desc->{"desc"} = $_; - $desc->{"comment"} = $comment; - $desc->{"spec"} = {}; - $comment = ""; - #print "values for $name: " . join (' ', @values) . " num: " . int(@values), "\n"; - for my $val (@values) { - if ($val =~ /(\S+):(.*)/) { - if ($1 eq "name") { - die "name tag only valid in templates at line $line\n" unless $is_template; - die "Duplicated name tag in template $desc->{'name'} at line $line\n" if defined $desc->{'name'}; - die "Duplicated template $2 at line $line\n" if defined $template_table {$2}; - $desc->{'name'} = $2; - $template_table {$2} = $desc; - } elsif ($1 eq "template") { - my $tdesc = $template_table {$2}; - die "Invalid template name $2 at line $line\n" unless defined $tdesc; - $desc->{"spec"} = {%{$tdesc->{"spec"}}}; - } else { - $desc->{"spec"}->{$1} = $2; - } - } - } - die "Template without name at line $1" if ($is_template && !defined ($desc->{'name'})); - } - close (DESC); -} - -sub build_spec { - my ($spec) = shift; - my %spec = %{$spec}; - my @vals = (); - foreach (@spec_names) { - my $val = $spec->{$_}; - if (defined $val) { - push @vals, $val; - } else { - push @vals, undef; - } - } - #print "vals: " . join (' ', @vals) . "\n"; - my $res = ""; - my $n = 0; - for (my $i = 0; $i < @vals; ++$i) { - next if $i == INST_NACL; - if (defined $vals [$i]) { - if ($i == INST_LEN) { - $n = $vals [$i]; - if ($n =~ /[^0-9]/) { - die "Invalid instruction length $n\n"; - } - if ((defined $vals [INST_NACL]) and $nacl == 1){ - $n = $vals [INST_NACL]; - } - $res .= sprintf ("\\x%x\" \"", + $n); - } else { - if ($vals [$i] =~ /^[a-zA-Z0-9]$/) { - $res .= $vals [$i]; - } else { - $res .= sprintf ("\\x%x\" \"", $vals [$i]); - } - } - } else { - $res .= "\\x0\" \""; - } - } - return $res; -} - -sub build_table { - my ($fname, $name) = @_; - my $i; - my $idx; - my $idx_array = "const guint16 mono_${name}_idx [] = {\n"; - - open (OUT, ">$fname") || die "Cannot open file $fname: $!"; - print OUT "/* File automatically generated by genmdesc, don't change */\n\n"; - print OUT "const char mono_$name [] = {\n"; - print OUT "\t\"" . ("\\x0" x INST_MAX) . "\"\t/* null entry */\n"; - $idx = 1; - - for ($i = 0; $i < @opcodes; ++$i) { - my $name = $opcodes [$i]->[1]; - my $desc = $table {$name}; - my $spec = $desc->{"spec"}; - if (defined $spec) { - print OUT "\t\""; - print OUT build_spec ($spec); - print OUT "\"\t/* $name */\n"; - my $pos = $idx * INST_MAX; - $idx_array .= "\t$pos,\t/* $name */\n"; - ++$idx; - } else { - $idx_array .= "\t0,\t/* $name */\n"; - } - } - print OUT "};\n\n"; - print OUT "$idx_array};\n\n"; - close (OUT); -} - -sub usage { - die "genmdesc.pl arch srcdir [--nacl] output name desc [desc2 ...]\n"; -} - -my $arch = shift || usage (); -my $srcdir = shift || usage (); -my $output = shift || usage (); -if ($output eq "--nacl") -{ - $nacl = 1; - $output = shift || usage(); -} -my $name = shift || usage (); -usage () unless @ARGV; -my @files = @ARGV; - -load_opcodes ($srcdir, $arch); -foreach my $file (@files) { - load_file ($file); -} -build_table ($output, $name); - diff --git a/mono/mini/genmdesc.py b/mono/mini/genmdesc.py new file mode 100755 index 000000000000..bc820ee67946 --- /dev/null +++ b/mono/mini/genmdesc.py @@ -0,0 +1,207 @@ +#!/usr/bin/env python + +# +# This tool is used to generate the cpu-.h files used by the JIT. The input is the +# cpu-.md file, along with the instruction metadata in mini-ops.h. +# + +import sys +import os +import re + +# Keep it in sync with mini.h +MONO_INST_DEST = 0 +MONO_INST_SRC1 = 1 +MONO_INST_SRC2 = 2 +MONO_INST_SRC3 = 3 +MONO_INST_LEN = 4 +MONO_INST_CLOB = 5 +MONO_INST_MAX = 6 + +allowed_defines = { "TARGET_X86" : 1, + "TARGET_AMD64" : 1, + "TARGET_ARM" : 1, + "TARGET_ARM64" : 1, + "TARGET_POWERPC" : 1, + "TARGET_SPARC" : 1, + "TARGET_S390X" : 1, + "TARGET_MIPS" : 1, + "TARGET_WASM" : 1 + } + +class OpDef: + def __init__ (self, num, name, dest_def, src1_def, src2_def): + # num is the opcode value/index + self.num = num + self.name = name + self.dest_def = dest_def + self.src1_def = src1_def + self.src2_def = src2_def + self.used = False + # Data read from the cpu descriptor file + self.spec = ["", "", "", "", "", "", "", "", "", ""] + self.desc_idx = 0 + +def usage (): + print ("Usage: genmdesc.py ") + +def parse_mini_ops (target_define): + opcodes = {} + opcode_id = 0 + enabled = [target_define] + is_enabled = True + opcode_file = open (os.path.join (srcdir, "mini-ops.h")) + # + # Implement a subset of a c preprocessor, only handling #ifdef/#endif directives + # + for line in opcode_file: + line = line.strip () + # print ("{0} {1}".format (line, is_enabled)) + m = re.search (r'^\s*#if (.+)', line) + # FIXME: Check list of defines against an allowed list + if m != None: + is_enabled = False + parts = m.group (1).split ("||") + for part in parts: + part = part.strip () + m = re.search (r'defined\((.+)\)', part) + if m == None: + print ("Unknown #ifdef line {0}".format (line)) + exit (1) + define = m.group (1) + # Check that the file only contains TARGET_... defines + if not define in allowed_defines: + print ("Unknown define '{0}' in mini-ops.h".format (define)) + exit (1) + for d in enabled: + if d == define: + is_enabled = True + elif line == "#endif": + is_enabled = True + else: + if is_enabled and line.startswith ("MINI_OP"): + m = re.search (r"MINI_OP\(\w+\s*\,\s*\"([^\"]+)\", (\w+), (\w+), (\w+)\)", line) + if m != None: + opcodes [m.group (1)] = OpDef(opcode_id, m.group (1), m.group (2), m.group (3), m.group (4)) + else: + m = re.search (r"MINI_OP3\(\w+\s*\,\s*\"([^\"]+)\", (\w+), (\w+), (\w+), (\w+)\)", line) + if m != None: + opcodes [m.group (1)] = OpDef(opcode_id, m.group (1), m.group (2), m.group (3), m.group (4)) + else: + print ("Unable to parse line: '{0}'".format (line)) + exit (1) + opcode_id += 1 + opcode_file.close () + return opcodes + +def parse_input(infile, opcodes): + for line in infile: + line = line.strip () + if line == "" or line.startswith ("#"): + continue + # Lines look like: + # expand_i2: dest:x src1:i len:18 + parts = line.split (" ") + op_name = parts [0][:-1] + if not op_name in opcodes: + print ("Unknown opcode '{0}'".format (op_name)) + exit (1) + opcode = opcodes [op_name] + opcode.used = True + for part in parts[1:]: + part = part.strip () + if part == "": + continue + [spec, value] = part.split (":") + if spec == "dest": + if opcode.dest_def == "NONE": + print ("Inconsistent dreg for opcode '{0}'".format (op_name)) + opcode.spec [MONO_INST_DEST] = value + elif spec == "src1": + if opcode.src1_def == "NONE": + print ("Inconsistent src1 for opcode '{0}'".format (op_name)) + opcode.spec [MONO_INST_SRC1] = value + elif spec == "src2": + if opcode.src2_def == "NONE": + print ("Inconsistent src2 for opcode '{0}'".format (op_name)) + opcode.spec [MONO_INST_SRC2] = value + elif spec == "src3": + opcode.spec [MONO_INST_SRC3] = value + elif spec == "len": + opcode.spec [MONO_INST_LEN] = chr(int(value)) + elif spec == "clob": + opcode.spec [MONO_INST_CLOB] = value + else: + print ("Unknown specifier '{0}' for opcode '{0}'".format (spec)) + exit (1) + +def gen_output(f, opcodes): + sorted_opcodes = [] + for op in opcodes.values (): + sorted_opcodes.append (op) + sorted_opcodes.sort (key=lambda op: op.num) + + f.write ("/* File automatically generated by genmdesc.py, don't change */\n\n") + + # Write desc table + f.write ("const char mono_{0} [] = {{\n".format (symbol_name)) + f.write ("\t\"") + for i in range(MONO_INST_MAX): + f.write (r"\x0") + f.write ("\"\t/* null entry */\n") + idx = 1 + for op in sorted_opcodes: + if not op.used: + continue + try: + f.write ("\t\"") + for c in op.spec[:MONO_INST_MAX]: + if c == "": + f.write (r"\x0") + f.write ("\" \"") + elif c.isalnum () and ord (c) < 0x80: + f.write (c) + else: + f.write (r"\x{0:x}".format (ord (c))) + f.write ("\" \"") + f.write ("\"\t/* {0} */\n".format (op.name)) + op.desc_idx = idx * MONO_INST_MAX + idx += 1 + except: + print ("Error emitting opcode '{0}': '{1}'.".format (op.name, sys.exc_info())) + f.write ("};\n") + + # Write index table + f.write ("const guint16 mono_{0}_idx [] = {{\n".format (symbol_name)) + for op in sorted_opcodes: + if not op.used: + f.write ("\t0,\t/* {0} */\n".format (op.name)) + else: + f.write ("\t{0},\t/* {1} */\n".format (op.desc_idx, op.name)) + f.write ("};\n\n") + +# +# MAIN +# + +if len (sys.argv) != 6: + usage () + exit (1) + +target_define = sys.argv [1] +srcdir = sys.argv [2] +outfile_name = sys.argv [3] +symbol_name = sys.argv [4] +infile_name = sys.argv [5] + +# Parse mini-ops.h file for opcode metadata +opcodes = parse_mini_ops(target_define) + +# Parse input file +infile = open (infile_name, 'r') +parse_input (infile, opcodes) + +# Generate output +f = open (outfile_name, 'w') +gen_output (f, opcodes) +f.close () diff --git a/mono/mini/il2cpp-stubs.cpp b/mono/mini/il2cpp-stubs.cpp index c4f576cf7259..bbd5c4c4c7a4 100644 --- a/mono/mini/il2cpp-stubs.cpp +++ b/mono/mini/il2cpp-stubs.cpp @@ -141,6 +141,7 @@ void il2cpp_mono_free_method_signatures() { mono_g_hash_table_foreach(method_signatures, il2cpp_mono_free_method_signature, NULL); mono_g_hash_table_destroy(method_signatures); + method_signatures = NULL; } } diff --git a/mono/mini/interp-stubs.c b/mono/mini/interp-stubs.c new file mode 100644 index 000000000000..e35227ed1526 --- /dev/null +++ b/mono/mini/interp-stubs.c @@ -0,0 +1,180 @@ +#include + +#include "interp/interp.h" + +/* interpreter callback stubs */ + +static MonoJitInfo* +stub_find_jit_info (MonoDomain *domain, MonoMethod *method) +{ + return NULL; +} + +static void +stub_set_breakpoint (MonoJitInfo *jinfo, gpointer ip) +{ + g_assert_not_reached (); +} + +static void +stub_clear_breakpoint (MonoJitInfo *jinfo, gpointer ip) +{ + g_assert_not_reached (); +} + +static MonoJitInfo* +stub_frame_get_jit_info (MonoInterpFrameHandle frame) +{ + g_assert_not_reached (); + return NULL; +} + +static gpointer +stub_frame_get_ip (MonoInterpFrameHandle frame) +{ + g_assert_not_reached (); + return NULL; +} + +static gpointer +stub_frame_get_arg (MonoInterpFrameHandle frame, int pos) +{ + g_assert_not_reached (); + return NULL; +} + +static gpointer +stub_frame_get_local (MonoInterpFrameHandle frame, int pos) +{ + g_assert_not_reached (); + return NULL; +} + +static gpointer +stub_frame_get_this (MonoInterpFrameHandle frame) +{ + g_assert_not_reached (); + return NULL; +} + +static MonoInterpFrameHandle +stub_frame_get_parent (MonoInterpFrameHandle frame) +{ + g_assert_not_reached (); + return NULL; +} + +static void +stub_start_single_stepping (void) +{ +} + +static void +stub_stop_single_stepping (void) +{ +} + +static void +stub_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoJitExceptionInfo *ei, MonoInterpFrameHandle interp_frame, gpointer handler_ip) +{ + g_assert_not_reached (); +} + +static gboolean +stub_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip) +{ + g_assert_not_reached (); +} + +static gboolean +stub_run_filter (StackFrameInfo *frame, MonoException *ex, int clause_index, gpointer handler_ip) +{ + g_assert_not_reached (); + return FALSE; +} + +static void +stub_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_data) +{ + g_assert_not_reached (); +} + +static gboolean +stub_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame) +{ + g_assert_not_reached (); + return FALSE; +} + +static gpointer +stub_create_method_pointer (MonoMethod *method, MonoError *error) +{ + g_assert_not_reached (); + return NULL; +} + +static MonoObject* +stub_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error) +{ + g_assert_not_reached (); + return NULL; +} + +static void +stub_init_delegate (MonoDelegate *del) +{ + g_assert_not_reached (); +} + +#ifndef DISABLE_REMOTING +static gpointer +stub_get_remoting_invoke (gpointer imethod, MonoError *error) +{ + g_assert_not_reached (); + return NULL; +} +#endif + +static gpointer +stub_create_trampoline (MonoDomain *domain, MonoMethod *method, MonoError *error) +{ + g_assert_not_reached (); + return NULL; +} + +static void +stub_walk_stack_with_ctx (MonoInternalStackWalk func, MonoContext *ctx, MonoUnwindOptions options, void *user_data) +{ + g_assert_not_reached (); +} + +void +mono_interp_stub_init (void) +{ + MonoInterpCallbacks c; + c.create_method_pointer = stub_create_method_pointer; + c.runtime_invoke = stub_runtime_invoke; + c.init_delegate = stub_init_delegate; +#ifndef DISABLE_REMOTING + c.get_remoting_invoke = stub_get_remoting_invoke; +#endif + c.create_trampoline = stub_create_trampoline; + c.walk_stack_with_ctx = stub_walk_stack_with_ctx; + c.set_resume_state = stub_set_resume_state; + c.run_finally = stub_run_finally; + c.run_filter = stub_run_filter; + c.frame_iter_init = stub_frame_iter_init; + c.frame_iter_next = stub_frame_iter_next; + c.find_jit_info = stub_find_jit_info; + c.set_breakpoint = stub_set_breakpoint; + c.clear_breakpoint = stub_clear_breakpoint; + c.frame_get_jit_info = stub_frame_get_jit_info; + c.frame_get_ip = stub_frame_get_ip; + c.frame_get_arg = stub_frame_get_arg; + c.frame_get_local = stub_frame_get_local; + c.frame_get_this = stub_frame_get_this; + c.frame_get_parent = stub_frame_get_parent; + c.start_single_stepping = stub_start_single_stepping; + c.stop_single_stepping = stub_stop_single_stepping; + mini_install_interp_callbacks (&c); +} diff --git a/mono/mini/interp/interp-internals.h b/mono/mini/interp/interp-internals.h index 90c1d92d917d..9acd88c0fd99 100644 --- a/mono/mini/interp/interp-internals.h +++ b/mono/mini/interp/interp-internals.h @@ -9,6 +9,7 @@ #include #include #include "config.h" +#include "interp.h" #define MINT_TYPE_I1 0 #define MINT_TYPE_U1 1 diff --git a/mono/mini/interp/interp-stubs.c b/mono/mini/interp/interp-stubs.c deleted file mode 100644 index 78e627ca36f5..000000000000 --- a/mono/mini/interp/interp-stubs.c +++ /dev/null @@ -1,112 +0,0 @@ -#include - -#ifdef DISABLE_INTERPRETER - -#include "interp.h" - -/* Dummy versions of interpreter functions to avoid ifdefs at call sites */ - -MonoJitInfo* -mono_interp_find_jit_info (MonoDomain *domain, MonoMethod *method) -{ - return NULL; -} - -void -mono_interp_set_breakpoint (MonoJitInfo *jinfo, gpointer ip) -{ - g_assert_not_reached (); -} - -void -mono_interp_clear_breakpoint (MonoJitInfo *jinfo, gpointer ip) -{ - g_assert_not_reached (); -} - -MonoJitInfo* -mono_interp_frame_get_jit_info (MonoInterpFrameHandle frame) -{ - g_assert_not_reached (); - return NULL; -} - -gpointer -mono_interp_frame_get_ip (MonoInterpFrameHandle frame) -{ - g_assert_not_reached (); - return NULL; -} - -gpointer -mono_interp_frame_get_arg (MonoInterpFrameHandle frame, int pos) -{ - g_assert_not_reached (); - return NULL; -} - -gpointer -mono_interp_frame_get_local (MonoInterpFrameHandle frame, int pos) -{ - g_assert_not_reached (); - return NULL; -} - -gpointer -mono_interp_frame_get_this (MonoInterpFrameHandle frame) -{ - g_assert_not_reached (); - return NULL; -} - -MonoInterpFrameHandle -mono_interp_frame_get_parent (MonoInterpFrameHandle frame) -{ - g_assert_not_reached (); - return NULL; -} - -void -mono_interp_start_single_stepping (void) -{ -} - -void -mono_interp_stop_single_stepping (void) -{ -} - -void -mono_interp_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoJitExceptionInfo *ei, MonoInterpFrameHandle interp_frame, gpointer handler_ip) -{ - g_assert_not_reached (); -} - -gboolean -mono_interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip) -{ - g_assert_not_reached (); -} - -gboolean -mono_interp_run_filter (StackFrameInfo *frame, MonoException *ex, int clause_index, gpointer handler_ip) -{ - g_assert_not_reached (); - return FALSE; -} - -void -mono_interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_data) -{ - g_assert_not_reached (); -} - -gboolean -mono_interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame) -{ - g_assert_not_reached (); - return FALSE; -} - -#endif - diff --git a/mono/mini/interp/interp.c b/mono/mini/interp/interp.c index 83183e07cee1..7737ba180d95 100644 --- a/mono/mini/interp/interp.c +++ b/mono/mini/interp/interp.c @@ -48,7 +48,6 @@ #include #include #include -#include #include #include #include @@ -65,6 +64,8 @@ #include "hacks.h" #include +#include +#include #include #include @@ -266,8 +267,8 @@ lookup_imethod (MonoDomain *domain, MonoMethod *method) } #ifndef DISABLE_REMOTING -gpointer -mono_interp_get_remoting_invoke (gpointer imethod, MonoError *error) +static gpointer +interp_get_remoting_invoke (gpointer imethod, MonoError *error) { InterpMethod *imethod_cast = (InterpMethod*) imethod; @@ -316,8 +317,8 @@ mono_interp_get_imethod (MonoDomain *domain, MonoMethod *method, MonoError *erro return rtm; } -gpointer -mono_interp_create_trampoline (MonoDomain *domain, MonoMethod *method, MonoError *error) +static gpointer +interp_create_trampoline (MonoDomain *domain, MonoMethod *method, MonoError *error) { if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) method = mono_marshal_get_synchronized_wrapper (method); @@ -805,7 +806,7 @@ ves_array_element_address (InterpFrame *frame, MonoClass *required_type, MonoArr return mono_array_addr_with_size (ao, esize, pos); } -void +static void interp_walk_stack_with_ctx (MonoInternalStackWalk func, MonoContext *ctx, MonoUnwindOptions options, void *user_data) { ThreadContext *context = mono_native_tls_get_value (thread_context_id); @@ -1087,8 +1088,8 @@ ves_pinvoke_method (InterpFrame *frame, MonoMethodSignature *sig, MonoFuncV addr g_free (margs); } -void -mono_interp_init_delegate (MonoDelegate *del) +static void +interp_init_delegate (MonoDelegate *del) { if (del->method) return; @@ -1405,8 +1406,8 @@ get_trace_ips (MonoDomain *domain, InterpFrame *top) #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b) #endif -MonoObject* -mono_interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error) +static MonoObject* +interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error) { InterpFrame frame, *old_frame; ThreadContext * volatile context = mono_native_tls_get_value (thread_context_id); @@ -2110,8 +2111,8 @@ static void interp_entry_instance_ret_3 (gpointer this_arg, gpointer res, ARGLIS static void interp_entry_instance_ret_4 (gpointer this_arg, gpointer res, ARGLIST4) INTERP_ENTRY4 (this_arg, res, rmethod) static void interp_entry_instance_ret_5 (gpointer this_arg, gpointer res, ARGLIST5) INTERP_ENTRY5 (this_arg, res, rmethod) static void interp_entry_instance_ret_6 (gpointer this_arg, gpointer res, ARGLIST6) INTERP_ENTRY6 (this_arg, res, rmethod) -static void interp_entry_instance_ret_7 (gpointer this_arg, gpointer res, ARGLIST7) INTERP_ENTRY6 (this_arg, res, rmethod) -static void interp_entry_instance_ret_8 (gpointer this_arg, gpointer res, ARGLIST8) INTERP_ENTRY6 (this_arg, res, rmethod) +static void interp_entry_instance_ret_7 (gpointer this_arg, gpointer res, ARGLIST7) INTERP_ENTRY7 (this_arg, res, rmethod) +static void interp_entry_instance_ret_8 (gpointer this_arg, gpointer res, ARGLIST8) INTERP_ENTRY8 (this_arg, res, rmethod) #define INTERP_ENTRY_FUNCLIST(type) interp_entry_ ## type ## _0, interp_entry_ ## type ## _1, interp_entry_ ## type ## _2, interp_entry_ ## type ## _3, interp_entry_ ## type ## _4, interp_entry_ ## type ## _5, interp_entry_ ## type ## _6, interp_entry_ ## type ## _7, interp_entry_ ## type ## _8 @@ -2130,13 +2131,13 @@ interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer } /* - * mono_interp_create_method_pointer: + * interp_create_method_pointer: * * Return a function pointer which can be used to call METHOD using the * interpreter. Return NULL for methods which are not supported. */ -gpointer -mono_interp_create_method_pointer (MonoMethod *method, MonoError *error) +static gpointer +interp_create_method_pointer (MonoMethod *method, MonoError *error) { gpointer addr; MonoMethodSignature *sig = mono_method_signature (method); @@ -2152,9 +2153,9 @@ mono_interp_create_method_pointer (MonoMethod *method, MonoError *error) wrapper = mini_get_interp_in_wrapper (sig); gpointer jit_wrapper = mono_jit_compile_method_jit_only (wrapper, error); - mono_error_assert_ok (error); + if (!mono_error_ok (error)) + g_error ("couldn't compile wrapper \"%s\" for \"%s\" (error: %s)\n", mono_method_get_full_name (wrapper), mono_method_get_full_name (method), mono_error_get_message (error)); - //printf ("%s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1)); gpointer entry_func; if (sig->param_count > MAX_INTERP_ENTRY_ARGS) { entry_func = interp_entry_general; @@ -2213,11 +2214,11 @@ static int opcode_counts[512]; sp->data.l = 0; \ output_indent (); \ char *mn = mono_method_full_name (frame->imethod->method, FALSE); \ - g_print ("(%p) %s -> ", mono_thread_internal_current (), mn); \ + char *disasm = mono_interp_dis_mintop(rtm->code, ip); \ + g_print ("(%p) %s -> %s\t%d:%s\n", mono_thread_internal_current (), mn, disasm, vt_sp - vtalloc, ins); \ g_free (mn); \ - mono_interp_dis_mintop(rtm->code, ip); \ - g_print ("\t%d:%s\n", vt_sp - vtalloc, ins); \ g_free (ins); \ + g_free (disasm); \ } #else #define DUMP_INSTR() @@ -5168,187 +5169,15 @@ mono_interp_parse_options (const char *options) } } -void -mono_interp_init () -{ - mono_native_tls_alloc (&thread_context_id, NULL); - set_context (NULL); - - mono_interp_transform_init (); -} - typedef int (*TestMethod) (void); -static void -interp_regression_step (MonoImage *image, int verbose, int *total_run, int *total, GTimer *timer, MonoDomain *domain) -{ - int result, expected, failed, cfailed, run; - double elapsed, transform_time; - int i; - MonoObject *result_obj; - static gboolean filter_method_init = FALSE; - static const char *filter_method = NULL; - - g_print ("Test run: image=%s\n", mono_image_get_filename (image)); - cfailed = failed = run = 0; - transform_time = elapsed = 0.0; - - g_timer_start (timer); - for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) { - MonoObject *exc = NULL; - MonoError error; - MonoMethod *method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error); - if (!method) { - mono_error_cleanup (&error); /* FIXME don't swallow the error */ - continue; - } - - if (!filter_method_init) { - filter_method = g_getenv ("INTERP_FILTER_METHOD"); - filter_method_init = TRUE; - } - gboolean filter = FALSE; - if (filter_method) { - const char *name = filter_method; - - if ((strchr (name, '.') > name) || strchr (name, ':')) { - MonoMethodDesc *desc = mono_method_desc_new (name, TRUE); - filter = mono_method_desc_full_match (desc, method); - mono_method_desc_free (desc); - } else { - filter = strcmp (method->name, name) == 0; - } - } else { /* no filter, check for `Category' attribute on method */ - filter = TRUE; - MonoCustomAttrInfo* ainfo = mono_custom_attrs_from_method_checked (method, &error); - mono_error_cleanup (&error); - - if (ainfo) { - int j; - for (j = 0; j < ainfo->num_attrs && filter; ++j) { - MonoCustomAttrEntry *centry = &ainfo->attrs [j]; - if (centry->ctor == NULL) - continue; - - MonoClass *klass = centry->ctor->klass; - if (strcmp (klass->name, "CategoryAttribute")) - continue; - - MonoObject *obj = mono_custom_attrs_get_attr_checked (ainfo, klass, &error); - /* FIXME: there is an ordering problem if there're multiple attributes, do this instead: - * MonoObject *obj = create_custom_attr (ainfo->image, centry->ctor, centry->data, centry->data_size, &error); */ - mono_error_cleanup (&error); - MonoMethod *getter = mono_class_get_method_from_name (klass, "get_Category", -1); - MonoObject *str = mono_interp_runtime_invoke (getter, obj, NULL, &exc, &error); - mono_error_cleanup (&error); - char *utf8_str = mono_string_to_utf8_checked ((MonoString *) str, &error); - mono_error_cleanup (&error); - if (!strcmp (utf8_str, "!INTERPRETER")) { - g_print ("skip %s...\n", method->name); - filter = FALSE; - } - } - } - } - if (strncmp (method->name, "test_", 5) == 0 && filter) { - MonoError interp_error; - MonoObject *exc = NULL; - - result_obj = mono_interp_runtime_invoke (method, NULL, NULL, &exc, &interp_error); - if (!mono_error_ok (&interp_error)) { - cfailed++; - g_print ("Test '%s' execution failed.\n", method->name); - } else if (exc != NULL) { - g_print ("Exception in Test '%s' occured:\n", method->name); - mono_object_describe (exc); - run++; - failed++; - } else { - result = *(gint32 *) mono_object_unbox (result_obj); - expected = atoi (method->name + 5); // FIXME: oh no. - run++; - - if (result != expected) { - failed++; - g_print ("Test '%s' failed result (got %d, expected %d).\n", method->name, result, expected); - } - } - } - } - g_timer_stop (timer); - elapsed = g_timer_elapsed (timer, NULL); - if (failed > 0 || cfailed > 0){ - g_print ("Results: total tests: %d, failed: %d, cfailed: %d (pass: %.2f%%)\n", - run, failed, cfailed, 100.0*(run-failed-cfailed)/run); - } else { - g_print ("Results: total tests: %d, all pass \n", run); - } - - g_print ("Elapsed time: %f secs (%f, %f)\n\n", elapsed, - elapsed - transform_time, transform_time); - *total += failed + cfailed; - *total_run += run; -} - -static int -interp_regression (MonoImage *image, int verbose, int *total_run) -{ - MonoMethod *method; - GTimer *timer = g_timer_new (); - MonoDomain *domain = mono_domain_get (); - guint32 i; - int total; - - /* load the metadata */ - for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) { - MonoError error; - method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error); - if (!method) { - mono_error_cleanup (&error); - continue; - } - mono_class_init (method->klass); - } - - total = 0; - *total_run = 0; - interp_regression_step (image, verbose, total_run, &total, timer, domain); - - g_timer_destroy (timer); - return total; -} - -int -mono_interp_regression_list (int verbose, int count, char *images []) -{ - int i, total, total_run, run; - - total_run = total = 0; - for (i = 0; i < count; ++i) { - MonoAssembly *ass = mono_assembly_open_predicate (images [i], FALSE, FALSE, NULL, NULL, NULL); - if (!ass) { - g_warning ("failed to load assembly: %s", images [i]); - continue; - } - total += interp_regression (mono_assembly_get_image (ass), verbose, &run); - total_run += run; - } - if (total > 0) { - g_print ("Overall results: tests: %d, failed: %d (pass: %.2f%%)\n", total_run, total, 100.0*(total_run-total)/total_run); - } else { - g_print ("Overall results: tests: %d, 100%% pass\n", total_run); - } - - return total; -} - /* - * mono_interp_set_resume_state: + * interp_set_resume_state: * * Set the state the interpeter will continue to execute from after execution returns to the interpreter. */ -void -mono_interp_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoJitExceptionInfo *ei, MonoInterpFrameHandle interp_frame, gpointer handler_ip) +static void +interp_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoJitExceptionInfo *ei, MonoInterpFrameHandle interp_frame, gpointer handler_ip) { ThreadContext *context; @@ -5367,14 +5196,14 @@ mono_interp_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoJi } /* - * mono_interp_run_finally: + * interp_run_finally: * * Run the finally clause identified by CLAUSE_INDEX in the intepreter frame given by * frame->interp_frame. * Return TRUE if the finally clause threw an exception. */ -gboolean -mono_interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip) +static gboolean +interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip) { InterpFrame *iframe = frame->interp_frame; ThreadContext *context = mono_native_tls_get_value (thread_context_id); @@ -5387,13 +5216,13 @@ mono_interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handl } /* - * mono_interp_run_filter: + * interp_run_filter: * * Run the filter clause identified by CLAUSE_INDEX in the intepreter frame given by * frame->interp_frame. */ -gboolean -mono_interp_run_filter (StackFrameInfo *frame, MonoException *ex, int clause_index, gpointer handler_ip) +static gboolean +interp_run_filter (StackFrameInfo *frame, MonoException *ex, int clause_index, gpointer handler_ip) { InterpFrame *iframe = frame->interp_frame; ThreadContext *context = mono_native_tls_get_value (thread_context_id); @@ -5419,12 +5248,12 @@ typedef struct { } StackIter; /* - * mono_interp_frame_iter_init: + * interp_frame_iter_init: * * Initialize an iterator for iterating through interpreted frames. */ -void -mono_interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_data) +static void +interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_data) { StackIter *stack_iter = (StackIter*)iter; @@ -5432,12 +5261,12 @@ mono_interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_dat } /* - * mono_interp_frame_iter_next: + * interp_frame_iter_next: * * Fill out FRAME with date for the next interpreter frame. */ -gboolean -mono_interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame) +static gboolean +interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame) { StackIter *stack_iter = (StackIter*)iter; InterpFrame *iframe = stack_iter->current; @@ -5463,8 +5292,8 @@ mono_interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame) return TRUE; } -MonoJitInfo* -mono_interp_find_jit_info (MonoDomain *domain, MonoMethod *method) +static MonoJitInfo* +interp_find_jit_info (MonoDomain *domain, MonoMethod *method) { InterpMethod* rtm; @@ -5475,24 +5304,24 @@ mono_interp_find_jit_info (MonoDomain *domain, MonoMethod *method) return NULL; } -void -mono_interp_set_breakpoint (MonoJitInfo *jinfo, gpointer ip) +static void +interp_set_breakpoint (MonoJitInfo *jinfo, gpointer ip) { guint16 *code = (guint16*)ip; g_assert (*code == MINT_SDB_SEQ_POINT); *code = MINT_SDB_BREAKPOINT; } -void -mono_interp_clear_breakpoint (MonoJitInfo *jinfo, gpointer ip) +static void +interp_clear_breakpoint (MonoJitInfo *jinfo, gpointer ip) { guint16 *code = (guint16*)ip; g_assert (*code == MINT_SDB_BREAKPOINT); *code = MINT_SDB_SEQ_POINT; } -MonoJitInfo* -mono_interp_frame_get_jit_info (MonoInterpFrameHandle frame) +static MonoJitInfo* +interp_frame_get_jit_info (MonoInterpFrameHandle frame) { InterpFrame *iframe = (InterpFrame*)frame; @@ -5500,8 +5329,8 @@ mono_interp_frame_get_jit_info (MonoInterpFrameHandle frame) return iframe->imethod->jinfo; } -gpointer -mono_interp_frame_get_ip (MonoInterpFrameHandle frame) +static gpointer +interp_frame_get_ip (MonoInterpFrameHandle frame) { InterpFrame *iframe = (InterpFrame*)frame; @@ -5509,8 +5338,8 @@ mono_interp_frame_get_ip (MonoInterpFrameHandle frame) return (gpointer)iframe->ip; } -gpointer -mono_interp_frame_get_arg (MonoInterpFrameHandle frame, int pos) +static gpointer +interp_frame_get_arg (MonoInterpFrameHandle frame, int pos) { InterpFrame *iframe = (InterpFrame*)frame; @@ -5521,8 +5350,8 @@ mono_interp_frame_get_arg (MonoInterpFrameHandle frame, int pos) return iframe->args + arg_offset; } -gpointer -mono_interp_frame_get_local (MonoInterpFrameHandle frame, int pos) +static gpointer +interp_frame_get_local (MonoInterpFrameHandle frame, int pos) { InterpFrame *iframe = (InterpFrame*)frame; @@ -5531,8 +5360,8 @@ mono_interp_frame_get_local (MonoInterpFrameHandle frame, int pos) return iframe->locals + iframe->imethod->local_offsets [pos]; } -gpointer -mono_interp_frame_get_this (MonoInterpFrameHandle frame) +static gpointer +interp_frame_get_this (MonoInterpFrameHandle frame) { InterpFrame *iframe = (InterpFrame*)frame; @@ -5544,22 +5373,58 @@ mono_interp_frame_get_this (MonoInterpFrameHandle frame) return iframe->args + arg_offset; } -MonoInterpFrameHandle -mono_interp_frame_get_parent (MonoInterpFrameHandle frame) +static MonoInterpFrameHandle +interp_frame_get_parent (MonoInterpFrameHandle frame) { InterpFrame *iframe = (InterpFrame*)frame; return iframe->parent; } -void -mono_interp_start_single_stepping (void) +static void +interp_start_single_stepping (void) { ss_enabled = TRUE; } -void -mono_interp_stop_single_stepping (void) +static void +interp_stop_single_stepping (void) { ss_enabled = FALSE; } + +void +mono_interp_init () +{ + mono_native_tls_alloc (&thread_context_id, NULL); + set_context (NULL); + + mono_interp_transform_init (); + + MonoInterpCallbacks c; + c.create_method_pointer = interp_create_method_pointer; + c.runtime_invoke = interp_runtime_invoke; + c.init_delegate = interp_init_delegate; +#ifndef DISABLE_REMOTING + c.get_remoting_invoke = interp_get_remoting_invoke; +#endif + c.create_trampoline = interp_create_trampoline; + c.walk_stack_with_ctx = interp_walk_stack_with_ctx; + c.set_resume_state = interp_set_resume_state; + c.run_finally = interp_run_finally; + c.run_filter = interp_run_filter; + c.frame_iter_init = interp_frame_iter_init; + c.frame_iter_next = interp_frame_iter_next; + c.find_jit_info = interp_find_jit_info; + c.set_breakpoint = interp_set_breakpoint; + c.clear_breakpoint = interp_clear_breakpoint; + c.frame_get_jit_info = interp_frame_get_jit_info; + c.frame_get_ip = interp_frame_get_ip; + c.frame_get_arg = interp_frame_get_arg; + c.frame_get_local = interp_frame_get_local; + c.frame_get_this = interp_frame_get_this; + c.frame_get_parent = interp_frame_get_parent; + c.start_single_stepping = interp_start_single_stepping; + c.stop_single_stepping = interp_stop_single_stepping; + mini_install_interp_callbacks (&c); +} diff --git a/mono/mini/interp/interp.h b/mono/mini/interp/interp.h index c7540238e548..ea0a8cd63fd9 100644 --- a/mono/mini/interp/interp.h +++ b/mono/mini/interp/interp.h @@ -4,7 +4,7 @@ #ifndef __MONO_MINI_INTERPRETER_H__ #define __MONO_MINI_INTERPRETER_H__ -#include +#include #ifdef TARGET_WASM #define INTERP_ICALL_TRAMP_IARGS 12 @@ -28,7 +28,6 @@ struct _InterpMethodArguments { typedef struct _InterpMethodArguments InterpMethodArguments; - typedef struct _MonoInterpStackIter MonoInterpStackIter; /* Needed for stack allocation */ @@ -38,79 +37,36 @@ struct _MonoInterpStackIter { typedef gpointer MonoInterpFrameHandle; -int -mono_interp_regression_list (int verbose, int count, char *images []); - -void -mono_interp_init (void); - -gpointer -mono_interp_create_method_pointer (MonoMethod *method, MonoError *error); - -MonoObject* -mono_interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error); - -void -mono_interp_init_delegate (MonoDelegate *del); - -gpointer -mono_interp_get_remoting_invoke (gpointer imethod, MonoError *error); - -gpointer -mono_interp_create_trampoline (MonoDomain *domain, MonoMethod *method, MonoError *error); - -void -mono_interp_parse_options (const char *options); - -void -interp_walk_stack_with_ctx (MonoInternalStackWalk func, MonoContext *ctx, MonoUnwindOptions options, void *user_data); - -void -mono_interp_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoJitExceptionInfo *ei, MonoInterpFrameHandle interp_frame, gpointer handler_ip); - -gboolean -mono_interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip); - -gboolean -mono_interp_run_filter (StackFrameInfo *frame, MonoException *ex, int clause_index, gpointer handler_ip); -void -mono_interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_data); - -gboolean -mono_interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame); - -MonoJitInfo* -mono_interp_find_jit_info (MonoDomain *domain, MonoMethod *method); - -void -mono_interp_set_breakpoint (MonoJitInfo *jinfo, gpointer ip); - -void -mono_interp_clear_breakpoint (MonoJitInfo *jinfo, gpointer ip); - -MonoJitInfo* -mono_interp_frame_get_jit_info (MonoInterpFrameHandle frame); - -gpointer -mono_interp_frame_get_ip (MonoInterpFrameHandle frame); - -gpointer -mono_interp_frame_get_arg (MonoInterpFrameHandle frame, int pos); - -gpointer -mono_interp_frame_get_local (MonoInterpFrameHandle frame, int pos); - -gpointer -mono_interp_frame_get_this (MonoInterpFrameHandle frame); - -MonoInterpFrameHandle -mono_interp_frame_get_parent (MonoInterpFrameHandle frame); +struct _MonoInterpCallbacks { + gpointer (*create_method_pointer) (MonoMethod *method, MonoError *error); + MonoObject* (*runtime_invoke) (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error); + void (*init_delegate) (MonoDelegate *del); +#ifndef DISABLE_REMOTING + gpointer (*get_remoting_invoke) (gpointer imethod, MonoError *error); +#endif + gpointer (*create_trampoline) (MonoDomain *domain, MonoMethod *method, MonoError *error); + void (*walk_stack_with_ctx) (MonoInternalStackWalk func, MonoContext *ctx, MonoUnwindOptions options, void *user_data); + void (*set_resume_state) (MonoJitTlsData *jit_tls, MonoException *ex, MonoJitExceptionInfo *ei, MonoInterpFrameHandle interp_frame, gpointer handler_ip); + gboolean (*run_finally) (StackFrameInfo *frame, int clause_index, gpointer handler_ip); + gboolean (*run_filter) (StackFrameInfo *frame, MonoException *ex, int clause_index, gpointer handler_ip); + void (*frame_iter_init) (MonoInterpStackIter *iter, gpointer interp_exit_data); + gboolean (*frame_iter_next) (MonoInterpStackIter *iter, StackFrameInfo *frame); + MonoJitInfo* (*find_jit_info) (MonoDomain *domain, MonoMethod *method); + void (*set_breakpoint) (MonoJitInfo *jinfo, gpointer ip); + void (*clear_breakpoint) (MonoJitInfo *jinfo, gpointer ip); + MonoJitInfo* (*frame_get_jit_info) (MonoInterpFrameHandle frame); + gpointer (*frame_get_ip) (MonoInterpFrameHandle frame); + gpointer (*frame_get_arg) (MonoInterpFrameHandle frame, int pos); + gpointer (*frame_get_local) (MonoInterpFrameHandle frame, int pos); + gpointer (*frame_get_this) (MonoInterpFrameHandle frame); + MonoInterpFrameHandle (*frame_get_parent) (MonoInterpFrameHandle frame); + void (*start_single_stepping) (void); + void (*stop_single_stepping) (void); +}; -void -mono_interp_start_single_stepping (void); +void mono_interp_parse_options (const char *options); -void -mono_interp_stop_single_stepping (void); +void mono_interp_init (void); #endif /* __MONO_MINI_INTERPRETER_H__ */ diff --git a/mono/mini/interp/mintops.c b/mono/mini/interp/mintops.c index f3db03aa417f..3a8e04dfb19a 100644 --- a/mono/mini/interp/mintops.c +++ b/mono/mini/interp/mintops.c @@ -35,12 +35,11 @@ MintOpArgType mono_interp_opargtype[] = { }; #undef OPDEF -const guint16 * -mono_interp_dis_mintop(const guint16 *base, const guint16 *ip) +const guint16* +mono_interp_dis_mintop_len (const guint16 *ip) { int len = mono_interp_oplen [*ip]; - guint32 token; - int target; + if (len < 0 || len > 10) { g_print ("op %d len %d\n", *ip, len); g_assert_not_reached (); @@ -49,73 +48,83 @@ mono_interp_dis_mintop(const guint16 *base, const guint16 *ip) len = 3 + n * 2; } - g_print ("IL_%04x: %-10s", ip - base, mono_interp_opname [*ip]); + return ip + len; +} + +char * +mono_interp_dis_mintop(const guint16 *base, const guint16 *ip) +{ + GString *str = g_string_new (""); + guint32 token; + int target; + + g_string_append_printf (str, "IL_%04x: %-10s", ip - base, mono_interp_opname [*ip]); switch (mono_interp_opargtype [*ip]) { case MintOpNoArgs: break; case MintOpUShortInt: - g_print (" %u", * (guint16 *)(ip + 1)); + g_string_append_printf (str, " %u", * (guint16 *)(ip + 1)); break; case MintOpTwoShorts: - g_print (" %u,%u", * (guint16 *)(ip + 1), * (guint16 *)(ip + 2)); + g_string_append_printf (str, " %u,%u", * (guint16 *)(ip + 1), * (guint16 *)(ip + 2)); break; case MintOpShortAndInt: - g_print (" %u,%u", * (guint16 *)(ip + 1), (guint32)READ32(ip + 2)); + g_string_append_printf (str, " %u,%u", * (guint16 *)(ip + 1), (guint32)READ32(ip + 2)); break; case MintOpShortInt: - g_print (" %d", * (short *)(ip + 1)); + g_string_append_printf (str, " %d", * (short *)(ip + 1)); break; case MintOpClassToken: case MintOpMethodToken: case MintOpFieldToken: token = * (guint16 *)(ip + 1); - g_print (" %u", token); + g_string_append_printf (str, " %u", token); break; case MintOpInt: - g_print (" %d", (gint32)READ32 (ip + 1)); + g_string_append_printf (str, " %d", (gint32)READ32 (ip + 1)); break; case MintOpLongInt: - g_print (" %lld", (gint64)READ64 (ip + 1)); + g_string_append_printf (str, " %lld", (gint64)READ64 (ip + 1)); break; case MintOpFloat: { gint32 tmp = READ32 (ip + 1); - g_print (" %g", * (float *)&tmp); + g_string_append_printf (str, " %g", * (float *)&tmp); break; } case MintOpDouble: { gint64 tmp = READ64 (ip + 1); - g_print (" %g", * (double *)&tmp); + g_string_append_printf (str, " %g", * (double *)&tmp); break; } case MintOpShortBranch: target = ip + * (short *)(ip + 1) - base; - g_print (" IL_%04x", target); + g_string_append_printf (str, " IL_%04x", target); break; case MintOpBranch: target = ip + (gint32)READ32 (ip + 1) - base; - g_print (" IL_%04x", target); + g_string_append_printf (str, " IL_%04x", target); break; case MintOpSwitch: { const guint16 *p = ip + 1; int sval = (gint32)READ32 (p); int i; p += 2; - g_print ("("); + g_string_append_printf (str, "("); for (i = 0; i < sval; ++i) { int offset; if (i > 0) - g_print (", "); + g_string_append_printf (str, ", "); offset = (gint32)READ32 (p); - g_print ("IL_%04x", p + offset - base); + g_string_append_printf (str, "IL_%04x", p + offset - base); p += 2; } - g_print (")"); + g_string_append_printf (str, ")"); break; } default: - g_print("unknown arg type\n"); + g_string_append_printf (str, "unknown arg type\n"); } - return ip + len; + return g_string_free (str, FALSE); } diff --git a/mono/mini/interp/mintops.h b/mono/mini/interp/mintops.h index 7a9bc4da0179..24b4952ade01 100644 --- a/mono/mini/interp/mintops.h +++ b/mono/mini/interp/mintops.h @@ -56,7 +56,8 @@ enum { extern const char *mono_interp_opname[]; extern unsigned char mono_interp_oplen[]; extern MintOpArgType mono_interp_opargtype[]; -extern const guint16 *mono_interp_dis_mintop(const unsigned short *base, const guint16 *ip); +extern char* mono_interp_dis_mintop(const unsigned short *base, const guint16 *ip); +extern const guint16* mono_interp_dis_mintop_len (const guint16 *ip); #endif diff --git a/mono/mini/interp/transform.c b/mono/mini/interp/transform.c index 9b748cc2c0d6..3b6f6c0ae6e7 100644 --- a/mono/mini/interp/transform.c +++ b/mono/mini/interp/transform.c @@ -18,6 +18,7 @@ #include #include +#include #include "mintops.h" #include "interp-internals.h" @@ -966,7 +967,7 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target } } - g_error ("TODO: %s", tm); + g_error ("TODO: interp_transform_call %s:%s", target_method->klass->name, tm); } else if (mono_class_is_subclass_of (target_method->klass, mono_defaults.array_class, FALSE)) { if (!strcmp (tm, "get_Rank")) { op = MINT_ARRAY_RANK; @@ -3775,7 +3776,7 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, unsig } if (func == mono_ftnptr_to_delegate) { - g_error ("TODO: ?"); + g_error ("TODO: CEE_MONO_ICALL mono_ftnptr_to_delegate?"); } ADD_CODE(td, get_data_item_index (td, func)); td->sp -= info->sig->param_count; @@ -4188,8 +4189,10 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, unsig g_print ("Runtime method: %s %p, VT stack size: %d\n", mono_method_full_name (method, TRUE), rtm, td->max_vt_sp); g_print ("Calculated stack size: %d, stated size: %d\n", td->max_stack_height, header->max_stack); while (p < td->new_ip) { - p = mono_interp_dis_mintop(td->new_code, p); - g_print ("\n"); + char *ins = mono_interp_dis_mintop (td->new_code, p); + g_print ("%s\n", ins); + g_free (ins); + p = mono_interp_dis_mintop_len (p); } } g_assert (td->max_stack_height <= (header->max_stack + 1)); @@ -4384,7 +4387,7 @@ mono_interp_transform_method (InterpMethod *imethod, ThreadContext *context, Int MONO_PROFILER_RAISE (jit_done, (method, NULL)); return NULL; } else if (!strcmp (method->name, "UnsafeStore")) { - g_error ("TODO"); + g_error ("TODO ArrayClass::UnsafeStore"); } } diff --git a/mono/mini/jit-icalls.c b/mono/mini/jit-icalls.c index e4c34d807784..44960ceb04e1 100644 --- a/mono/mini/jit-icalls.c +++ b/mono/mini/jit-icalls.c @@ -19,6 +19,8 @@ #endif #include "jit-icalls.h" +#include "aot-runtime.h" +#include "mini-runtime.h" #include #include #include diff --git a/mono/mini/llvm-jit.cpp b/mono/mini/llvm-jit.cpp index e09d72e9192f..11ff116f5685 100644 --- a/mono/mini/llvm-jit.cpp +++ b/mono/mini/llvm-jit.cpp @@ -195,7 +195,7 @@ class MonoLLVMJIT { #if LLVM_API_VERSION >= 500 ModuleHandleT m = CompileLayer.addModule(M, - std::move(Resolver)); + std::move(Resolver)).get (); return m; #else return CompileLayer.addModuleSet(singletonSet(M), @@ -245,15 +245,23 @@ class MonoLLVMJIT { auto sym = CompileLayer.findSymbolIn (ModuleHandle, mangle (var->getName ()), true); auto addr = sym.getAddress (); g_assert (addr); +#if LLVM_API_VERSION >= 500 + callee_addrs [i] = (gpointer)addr.get (); +#else callee_addrs [i] = (gpointer)addr; +#endif } auto ehsym = CompileLayer.findSymbolIn(ModuleHandle, "mono_eh_frame", false); auto ehaddr = ehsym.getAddress (); g_assert (ehaddr); +#if LLVM_API_VERSION >= 500 + *eh_frame = (gpointer)ehaddr.get (); + return (gpointer)BodyAddr.get (); +#else *eh_frame = (gpointer)ehaddr; - return (gpointer)BodyAddr; +#endif } private: diff --git a/mono/mini/m2n-gen.cs b/mono/mini/m2n-gen.cs new file mode 100644 index 000000000000..5f3844edc60e --- /dev/null +++ b/mono/mini/m2n-gen.cs @@ -0,0 +1,146 @@ +using System; + +class EmitCtx +{ + int iarg, farg; + + public string Emit (char c) { + switch (c) { + case 'I': + iarg += 1; + return $"(int)margs->iargs [{iarg - 1}]"; + case 'F': + farg += 1; + return $"*(float*)&margs->fargs [FIDX ({farg - 1})]"; + case 'L': + iarg += 2; + return $"get_long_arg (margs, {iarg - 2})"; + case 'D': + farg += 1; + return $"margs->fargs [FIDX ({farg - 1})]"; + default: + throw new Exception ("IDK how to handle " + c); + } + } +} + +class Driver { + static string[] cookies = new string[] { + "V", + "VI", + "VII", + "VIII", + "VIIII", + "VIIIII", + "VIIIIII", + "I", + "II", + "III", + "IIII", + "IIIII", + "IIIIII", + "IIIIIII", + "IIIIIIIII", + "L", + "LL", + "LI", + "LIL", + "LILII", + "DD", + "DDD", + "VIF", + "VIFF", + "VIFFFF", + "VIFFFFFI", + "FF", + "DI", + "FI", + "IIL", + "IILI", + "IILLLI", + "LII", + "VID", + "VIIIIIII", + "VILLI", + + "DID", + "DIDD", + "FIF", + "FIFF", + "LILL", + "VIL", + }; + + static string TypeToSigType (char c) { + switch (c) { + case 'V': return "void"; + case 'I': return "int"; + case 'L': return "gint64"; + case 'F': return "float"; + case 'D': return "double"; + default: + throw new Exception ("Can't handle " + c); + } + } + + static void Main () { + Console.WriteLine ("/*"); + Console.WriteLine ("* DON'T EDIT THIS FILE"); + Console.WriteLine ("* This file was generated by m2n-gen.cs - use it instead."); + Console.WriteLine ("*/"); + foreach (var c in cookies) { + Console.WriteLine ("static void"); + Console.WriteLine ($"wasm_invoke_{c.ToLower ()} (void *target_func, InterpMethodArguments *margs)"); + Console.WriteLine ("{"); + + + Console.Write ($"\t{TypeToSigType (c [0])} (*func)("); + for (int i = 1; i < c.Length; ++i) { + char p = c [i]; + if (i > 1) + Console.Write (", "); + Console.Write ($"{TypeToSigType (p)} arg_{i - 1}"); + } + if (c.Length == 1) + Console.Write ("void"); + + Console.WriteLine (") = target_func;\n"); + + var ctx = new EmitCtx (); + + Console.Write ("\t"); + if (c [0] != 'V') + Console.Write ($"{TypeToSigType (c [0])} res = "); + + Console.Write ("func ("); + for (int i = 1; i < c.Length; ++i) { + char p = c [i]; + if (i > 1) + Console.Write (", "); + Console.Write (ctx.Emit (p)); + } + Console.WriteLine (");"); + + if (c [0] != 'V') + Console.WriteLine ($"\t*({TypeToSigType (c [0])}*)margs->retval = res;"); + + Console.WriteLine ("\n}\n"); + } + + Console.WriteLine ("static void\nicall_trampoline_dispatch (const char *cookie, void *target_func, InterpMethodArguments *margs)"); + Console.WriteLine ("{"); + for (int i = 0; i < cookies.Length; ++i) { + var c = cookies [i]; + Console.Write ("\t"); + if (i > 0) + Console.Write ("else "); + Console.WriteLine ($"if (!strcmp (\"{c}\", cookie))"); + Console.WriteLine ($"\t\twasm_invoke_{c.ToLower ()} (target_func, margs);"); + } + Console.WriteLine ("\telse {"); + Console.WriteLine ("\t\tprintf (\"CANNOT HANDLE COOKIE %s\\n\", cookie);"); + Console.WriteLine ("\t\tg_assert (0);"); + Console.WriteLine ("\t}"); + Console.WriteLine ("}"); + } +} diff --git a/mono/mini/main.c b/mono/mini/main.c index bd4f6674dfbc..874548e3b13d 100644 --- a/mono/mini/main.c +++ b/mono/mini/main.c @@ -21,6 +21,7 @@ #include #include #include "mini.h" +#include "mini-runtime.h" #ifdef HAVE_UNISTD_H # include diff --git a/mono/mini/memory-access.c b/mono/mini/memory-access.c index 630e0442b8ff..f53ad917fc6f 100644 --- a/mono/mini/memory-access.c +++ b/mono/mini/memory-access.c @@ -474,8 +474,6 @@ mini_emit_memory_load (MonoCompile *cfg, MonoType *type, MonoInst *src, int offs void mini_emit_memory_store (MonoCompile *cfg, MonoType *type, MonoInst *dest, MonoInst *value, int ins_flag) { - MonoInst *ins; - if (ins_flag & MONO_INST_VOLATILE) { /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */ mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL); @@ -488,12 +486,14 @@ mini_emit_memory_store (MonoCompile *cfg, MonoType *type, MonoInst *dest, MonoIn EMIT_NEW_TEMPSTORE (cfg, mov, tmp_var->inst_c0, value); EMIT_NEW_VARLOADA (cfg, addr, tmp_var, tmp_var->inst_vtype); mini_emit_memory_copy_internal (cfg, dest, addr, mono_class_from_mono_type (type), 1, FALSE); - } + } else { + MonoInst *ins; - /* FIXME: should check item at sp [1] is compatible with the type of the store. */ + /* FIXME: should check item at sp [1] is compatible with the type of the store. */ + EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, type, dest->dreg, 0, value->dreg); + ins->flags |= ins_flag; + } - EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, type, dest->dreg, 0, value->dreg); - ins->flags |= ins_flag; if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && mini_type_is_reference (type) && !MONO_INS_IS_PCONST_NULL (value)) { /* insert call to write barrier */ diff --git a/mono/mini/method-to-ir.c b/mono/mini/method-to-ir.c index fc3da586bd9c..ed9001779cf9 100644 --- a/mono/mini/method-to-ir.c +++ b/mono/mini/method-to-ir.c @@ -75,6 +75,7 @@ #include "seq-points.h" #include "aot-compiler.h" #include "mini-llvm.h" +#include "mini-runtime.h" #define BRANCH_COST 10 #define INLINE_LENGTH_LIMIT 20 @@ -682,8 +683,9 @@ ip_in_finally_clause (MonoCompile *cfg, int offset) return FALSE; } +/* Find clauses between ip and target, from inner to outer */ static GList* -mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type) +mono_find_leave_clauses (MonoCompile *cfg, unsigned char *ip, unsigned char *target) { MonoMethodHeader *header = cfg->header; MonoExceptionClause *clause; @@ -694,8 +696,7 @@ mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *targe clause = &header->clauses [i]; if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) { - if (clause->flags == type) - res = g_list_append_mempool (cfg->mempool, res, clause); + res = g_list_append_mempool (cfg->mempool, res, clause); } } return res; @@ -11452,11 +11453,17 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b cfg->cbb->try_end = (intptr_t)(ip - header->code); #endif - if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) { + if ((handlers = mono_find_leave_clauses (cfg, ip, target))) { GList *tmp; - + /* + * For each finally clause that we exit we need to invoke the finally block. + * After each invocation we need to add try holes for all the clauses that + * we already exited. + */ for (tmp = handlers; tmp; tmp = tmp->next) { MonoExceptionClause *clause = (MonoExceptionClause *)tmp->data; + if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY) + continue; MonoInst *abort_exc = (MonoInst *)mono_find_exvar_for_offset (cfg, clause->handler_offset); MonoBasicBlock *dont_throw; @@ -11468,7 +11475,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER); ins->inst_target_bb = tblock; - ins->inst_eh_block = clause; + ins->inst_eh_blocks = tmp; MONO_ADD_INS (cfg->cbb, ins); cfg->cbb->has_call_handler = 1; diff --git a/mono/mini/mini-amd64.c b/mono/mini/mini-amd64.c index 36632747857d..4b7a7cc77507 100644 --- a/mono/mini/mini-amd64.c +++ b/mono/mini/mini-amd64.c @@ -45,6 +45,8 @@ #include "cpu-amd64.h" #include "debugger-agent.h" #include "mini-gc.h" +#include "mini-runtime.h" +#include "aot-runtime.h" #ifdef MONO_XEN_OPT static gboolean optimize_for_xen = TRUE; @@ -1378,67 +1380,6 @@ mono_arch_get_global_int_regs (MonoCompile *cfg) return regs; } - -GList* -mono_arch_get_global_fp_regs (MonoCompile *cfg) -{ - GList *regs = NULL; - int i; - - /* All XMM registers */ - for (i = 0; i < 16; ++i) - regs = g_list_prepend (regs, GINT_TO_POINTER (i)); - - return regs; -} - -GList* -mono_arch_get_iregs_clobbered_by_call (MonoCallInst *call) -{ - static GList *r = NULL; - - if (r == NULL) { - GList *regs = NULL; - - regs = g_list_prepend (regs, (gpointer)AMD64_RBP); - regs = g_list_prepend (regs, (gpointer)AMD64_RBX); - regs = g_list_prepend (regs, (gpointer)AMD64_R12); - regs = g_list_prepend (regs, (gpointer)AMD64_R13); - regs = g_list_prepend (regs, (gpointer)AMD64_R14); - regs = g_list_prepend (regs, (gpointer)AMD64_R15); - - regs = g_list_prepend (regs, (gpointer)AMD64_R10); - regs = g_list_prepend (regs, (gpointer)AMD64_R9); - regs = g_list_prepend (regs, (gpointer)AMD64_R8); - regs = g_list_prepend (regs, (gpointer)AMD64_RDI); - regs = g_list_prepend (regs, (gpointer)AMD64_RSI); - regs = g_list_prepend (regs, (gpointer)AMD64_RDX); - regs = g_list_prepend (regs, (gpointer)AMD64_RCX); - regs = g_list_prepend (regs, (gpointer)AMD64_RAX); - - mono_atomic_cas_ptr ((gpointer*)&r, regs, NULL); - } - - return r; -} - -GList* -mono_arch_get_fregs_clobbered_by_call (MonoCallInst *call) -{ - int i; - static GList *r = NULL; - - if (r == NULL) { - GList *regs = NULL; - - for (i = 0; i < AMD64_XMM_NREG; ++i) - regs = g_list_prepend (regs, GINT_TO_POINTER (MONO_MAX_IREGS + i)); - - mono_atomic_cas_ptr ((gpointer*)&r, regs, NULL); - } - - return r; -} /* * mono_arch_regalloc_cost: @@ -4865,7 +4806,13 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, 8); mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb); amd64_call_imm (code, 0); - mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb); + /* + * ins->inst_eh_blocks and bb->clause_holes are part of same GList. + * Holes from bb->clause_holes will be added separately for the entire + * basic block. Add only the rest of them. + */ + for (GList *tmp = ins->inst_eh_blocks; tmp != bb->clause_holes; tmp = tmp->prev) + mono_cfg_add_try_hole (cfg, (MonoExceptionClause *)tmp->data, code, bb); /* Restore stack alignment */ amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, 8); break; @@ -7468,13 +7415,12 @@ enum { }; void* -mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers) +mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments) { guchar *code = (guchar *)p; int save_mode = SAVE_NONE; MonoMethod *method = cfg->method; MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret); - int i; switch (ret_type->type) { case MONO_TYPE_VOID: @@ -7542,20 +7488,10 @@ mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolea else amd64_mov_reg_imm (code, AMD64_RAX, 0); - if (preserve_argument_registers) { - for (i = 0; i < PARAM_REGS; ++i) - amd64_push_reg (code, param_regs [i]); - } - mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_METHODCONST, method); amd64_set_reg_template (code, AMD64_ARG_REG1); code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func, TRUE); - if (preserve_argument_registers) { - for (i = PARAM_REGS - 1; i >= 0; --i) - amd64_pop_reg (code, param_regs [i]); - } - /* Restore result */ switch (save_mode) { case SAVE_EAX: diff --git a/mono/mini/mini-amd64.h b/mono/mini/mini-amd64.h index 694362db6374..7fa4e1841348 100644 --- a/mono/mini/mini-amd64.h +++ b/mono/mini/mini-amd64.h @@ -366,7 +366,7 @@ typedef struct { */ #define MONO_ARCH_VARARG_ICALLS 1 -#if !defined( HOST_WIN32 ) && defined (HAVE_SIGACTION) +#if !defined( HOST_WIN32 ) && !defined(__HAIKU__) && defined (HAVE_SIGACTION) #define MONO_ARCH_USE_SIGACTION 1 diff --git a/mono/mini/mini-arm.c b/mono/mini/mini-arm.c index 13bda4a196cf..75e4fd098a4e 100644 --- a/mono/mini/mini-arm.c +++ b/mono/mini/mini-arm.c @@ -30,6 +30,8 @@ #include "ir-emit.h" #include "debugger-agent.h" #include "mini-gc.h" +#include "mini-runtime.h" +#include "aot-runtime.h" #include "mono/arch/arm/arm-vfp-codegen.h" /* Sanity check: This makes no sense */ @@ -146,8 +148,6 @@ static gpointer bp_trigger_page; * * We do not care about FPA. We will support soft float and VFP. */ -int mono_exc_esp_offset = 0; - #define arm_is_imm12(v) ((v) > -4096 && (v) < 4096) #define arm_is_imm8(v) ((v) > -256 && (v) < 256) #define arm_is_fpimm8(v) ((v) >= -1020 && (v) <= 1020) @@ -3002,7 +3002,7 @@ enum { }; void* -mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers) +mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments) { guchar *code = p; int save_mode = SAVE_NONE; @@ -5294,7 +5294,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb); code = mono_arm_patchable_bl (code, ARMCOND_AL); cfg->thunk_area += THUNK_SIZE; - mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb); + for (GList *tmp = ins->inst_eh_blocks; tmp != bb->clause_holes; tmp = tmp->prev) + mono_cfg_add_try_hole (cfg, (MonoExceptionClause *)tmp->data, code, bb); break; case OP_GET_EX_OBJ: if (ins->dreg != ARMREG_R0) diff --git a/mono/mini/mini-arm64-gsharedvt.c b/mono/mini/mini-arm64-gsharedvt.c index c50ef05a3895..d2b1d27f6128 100644 --- a/mono/mini/mini-arm64-gsharedvt.c +++ b/mono/mini/mini-arm64-gsharedvt.c @@ -11,6 +11,7 @@ #include "mini.h" #include "mini-arm64.h" #include "mini-arm64-gsharedvt.h" +#include "aot-runtime.h" /* * GSHAREDVT diff --git a/mono/mini/mini-arm64.c b/mono/mini/mini-arm64.c index 84432f0a1d62..092bfd45385a 100644 --- a/mono/mini/mini-arm64.c +++ b/mono/mini/mini-arm64.c @@ -19,6 +19,8 @@ #include "mini.h" #include "cpu-arm64.h" #include "ir-emit.h" +#include "aot-runtime.h" +#include "mini-runtime.h" #include #include @@ -2581,7 +2583,7 @@ mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean ena } void* -mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers) +mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments) { NOT_IMPLEMENTED; return NULL; @@ -4303,7 +4305,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) mono_add_patch_info_rel (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb, MONO_R_ARM64_BL); arm_bl (code, 0); cfg->thunk_area += THUNK_SIZE; - mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb); + for (GList *tmp = ins->inst_eh_blocks; tmp != bb->clause_holes; tmp = tmp->prev) + mono_cfg_add_try_hole (cfg, (MonoExceptionClause *)tmp->data, code, bb); break; case OP_START_HANDLER: { MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region); diff --git a/mono/mini/mini-cross-helpers.c b/mono/mini/mini-cross-helpers.c index 3a4e30eab6e3..d76d02664cc0 100644 --- a/mono/mini/mini-cross-helpers.c +++ b/mono/mini/mini-cross-helpers.c @@ -9,6 +9,7 @@ #include "config.h" #include "mini.h" +#include "mini-runtime.h" #ifndef DISABLE_INTERPRETER #include "interp/interp.h" #endif diff --git a/mono/mini/mini-exceptions.c b/mono/mini/mini-exceptions.c index 551ffe26e28b..fa050c7d79f6 100644 --- a/mono/mini/mini-exceptions.c +++ b/mono/mini/mini-exceptions.c @@ -75,6 +75,8 @@ #include "seq-points.h" #include "llvm-runtime.h" #include "mini-llvm.h" +#include "aot-runtime.h" +#include "mini-runtime.h" #include "interp/interp.h" #ifdef ENABLE_LLVM @@ -228,11 +230,9 @@ mono_exceptions_init (void) #ifdef MONO_ARCH_HAVE_EXCEPTIONS_INIT mono_arch_exceptions_init (); #endif -#ifndef DISABLE_INTERPRETER if (mono_use_interpreter) - cbs.mono_walk_stack_with_ctx = interp_walk_stack_with_ctx; + cbs.mono_walk_stack_with_ctx = mini_get_interp_callbacks ()->walk_stack_with_ctx; else -#endif cbs.mono_walk_stack_with_ctx = mono_runtime_walk_stack_with_ctx; cbs.mono_walk_stack_with_state = mono_walk_stack_with_state; @@ -318,7 +318,7 @@ mono_get_throw_exception_addr (void) return &throw_exception_func; } -static gboolean +static gboolean is_address_protected (MonoJitInfo *ji, MonoJitExceptionInfo *ei, gpointer ip) { MonoTryBlockHoleTableJitInfo *table; @@ -719,9 +719,9 @@ unwinder_unwind_frame (Unwinder *unwinder, } } - unwinder->in_interp = mono_interp_frame_iter_next (&unwinder->interp_iter, frame); + unwinder->in_interp = mini_get_interp_callbacks ()->frame_iter_next (&unwinder->interp_iter, frame); if (frame->type == FRAME_TYPE_INTERP) { - parent = mono_interp_frame_get_parent (frame->interp_frame); + parent = mini_get_interp_callbacks ()->frame_get_parent (frame->interp_frame); /* This is needed so code which uses ctx->sp for frame ordering would work */ MONO_CONTEXT_SET_SP (new_ctx, parent); } @@ -735,7 +735,7 @@ unwinder_unwind_frame (Unwinder *unwinder, return FALSE; if (frame->type == FRAME_TYPE_INTERP_TO_MANAGED) { unwinder->in_interp = TRUE; - mono_interp_frame_iter_init (&unwinder->interp_iter, frame->interp_exit_data); + mini_get_interp_callbacks ()->frame_iter_init (&unwinder->interp_iter, frame->interp_exit_data); } return TRUE; } @@ -1803,7 +1803,7 @@ handle_exception_first_pass (MonoContext *ctx, MonoObject *obj, gint32 *out_filt mono_debugger_agent_begin_exception_filter (mono_ex, ctx, &initial_ctx); if (ji->is_interp) { - filtered = mono_interp_run_filter (&frame, (MonoException*)ex_obj, i, ei->data.filter); + filtered = mini_get_interp_callbacks ()->run_filter (&frame, (MonoException*)ex_obj, i, ei->data.filter); } else { filtered = call_filter (ctx, ei->data.filter); } @@ -2111,7 +2111,7 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu } else { free_stack = 0xffffff; } - + for (i = clause_index_start; i < ji->num_clauses; i++) { MonoJitExceptionInfo *ei = &ji->clauses [i]; gboolean filtered = FALSE; @@ -2217,7 +2217,7 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu * like the call which transitioned to JITted code has succeeded, but the * return value register etc. is not set, so we have to be careful. */ - mono_interp_set_resume_state (jit_tls, mono_ex, ei, frame.interp_frame, ei->handler_start); + mini_get_interp_callbacks ()->set_resume_state (jit_tls, mono_ex, ei, frame.interp_frame, ei->handler_start); /* Undo the IP adjustment done by mono_arch_unwind_frame () */ #if defined(TARGET_AMD64) ctx->gregs [AMD64_RIP] ++; @@ -2227,6 +2227,8 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu ctx->pc |= 1; #elif defined(TARGET_ARM64) ctx->pc ++; +#elif defined (HOST_WASM) + //nada? #else NOT_IMPLEMENTED; #endif @@ -2290,7 +2292,7 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu } else { mini_set_abort_threshold (ctx); if (in_interp) { - gboolean has_ex = mono_interp_run_finally (&frame, i, ei->handler_start); + gboolean has_ex = mini_get_interp_callbacks ()->run_finally (&frame, i, ei->handler_start); if (has_ex) return 0; } else { diff --git a/mono/mini/mini-generic-sharing.c b/mono/mini/mini-generic-sharing.c index 0238d69cdb79..9d95b3ae207f 100644 --- a/mono/mini/mini-generic-sharing.c +++ b/mono/mini/mini-generic-sharing.c @@ -20,6 +20,8 @@ #include #include "mini.h" +#include "aot-runtime.h" +#include "mini-runtime.h" #define ALLOW_PARTIAL_SHARING TRUE //#define ALLOW_PARTIAL_SHARING FALSE diff --git a/mono/mini/mini-llvm.c b/mono/mini/mini-llvm.c index da400184c384..d823ffb6c540 100644 --- a/mono/mini/mini-llvm.c +++ b/mono/mini/mini-llvm.c @@ -34,6 +34,7 @@ #include "llvm-jit.h" #include "aot-compiler.h" #include "mini-llvm.h" +#include "mini-runtime.h" #ifndef DISABLE_JIT @@ -8749,9 +8750,12 @@ emit_aot_file_info (MonoLLVMModule *module) fields [tindex ++] = LLVMConstNull (eltype); fields [tindex ++] = LLVMConstNull (eltype); } + fields [tindex ++] = AddJitGlobal (module, eltype, "weak_field_indexes"); - for (i = 0; i < MONO_AOT_FILE_INFO_NUM_SYMBOLS; ++i) + for (i = 0; i < MONO_AOT_FILE_INFO_NUM_SYMBOLS; ++i) { + g_assert (fields [2 + i]); fields [2 + i] = LLVMConstBitCast (fields [2 + i], eltype); + } /* Scalars */ fields [tindex ++] = LLVMConstInt (LLVMInt32Type (), info->plt_got_offset_base, FALSE); diff --git a/mono/mini/mini-llvm.h b/mono/mini/mini-llvm.h index 0942c9a7d423..212bbedbb598 100644 --- a/mono/mini/mini-llvm.h +++ b/mono/mini/mini-llvm.h @@ -6,6 +6,7 @@ #define __MONO_MINI_LLVM_H__ #include "mini.h" +#include "aot-runtime.h" /* LLVM backend */ /* KEEP THIS IN SYNCH WITH mini-llvm-loaded.c */ diff --git a/mono/mini/mini-mips.c b/mono/mini/mini-mips.c index 364a232304e1..8452e9714a37 100644 --- a/mono/mini/mini-mips.c +++ b/mono/mini/mini-mips.c @@ -29,6 +29,8 @@ #include "cpu-mips.h" #include "trace.h" #include "ir-emit.h" +#include "aot-runtime.h" +#include "mini-runtime.h" #define SAVE_FP_REGS 0 @@ -63,8 +65,6 @@ enum { #define mono_mini_arch_unlock() mono_os_mutex_unlock (&mini_arch_mutex) static mono_mutex_t mini_arch_mutex; -int mono_exc_esp_offset = 0; - /* Whenever the host is little-endian */ static int little_endian; /* Index of ms word/register */ @@ -3975,7 +3975,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) mips_jalr (code, mips_t9, mips_ra); mips_nop (code); /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/ - mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb); + for (GList *tmp = ins->inst_eh_blocks; tmp != bb->clause_holes; tmp = tmp->prev) + mono_cfg_add_try_hole (cfg, (MonoExceptionClause *)tmp->data, code, bb); break; case OP_LABEL: ins->inst_c0 = code - cfg->native_code; @@ -5170,7 +5171,7 @@ enum { }; void* -mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers) +mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments) { guchar *code = p; int save_mode = SAVE_NONE; diff --git a/mono/mini/mini-ops.h b/mono/mini/mini-ops.h index 32ad106ab571..3381b21cef4f 100644 --- a/mono/mini/mini-ops.h +++ b/mono/mini/mini-ops.h @@ -1172,7 +1172,7 @@ MINI_OP(OP_AMD64_LOADI8_MEMINDEX, "amd64_loadi8_memindex", IREG, IREG, IR MINI_OP(OP_AMD64_SAVE_SP_TO_LMF, "amd64_save_sp_to_lmf", NONE, NONE, NONE) #endif -#if defined(__ppc__) || defined(__powerpc__) || defined(__ppc64__) || defined(TARGET_POWERPC) +#if defined(TARGET_POWERPC) MINI_OP(OP_PPC_SUBFIC, "ppc_subfic", IREG, IREG, NONE) MINI_OP(OP_PPC_SUBFZE, "ppc_subfze", IREG, IREG, NONE) MINI_OP(OP_CHECK_FINITE, "ppc_check_finite", NONE, IREG, NONE) @@ -1185,7 +1185,7 @@ MINI_OP(OP_ARM_RSC_IMM, "arm_rsc_imm", IREG, IREG, NONE) MINI_OP(OP_ARM_SETFREG_R4, "arm_setfreg_r4", FREG, FREG, NONE) #endif -#if defined(__sparc__) || defined(sparc) +#if defined(TARGET_SPARC) MINI_OP(OP_SPARC_BRZ, "sparc_brz", NONE, NONE, NONE) MINI_OP(OP_SPARC_BRLEZ, "sparc_brlez", NONE, NONE, NONE) MINI_OP(OP_SPARC_BRLZ, "sparc_brlz", NONE, NONE, NONE) @@ -1200,14 +1200,14 @@ MINI_OP(OP_SPARC_COND_EXC_LTZ, "sparc_cond_exc_ltz", NONE, NONE, NONE) MINI_OP(OP_SPARC_COND_EXC_NEZ, "sparc_cond_exc_nez", NONE, NONE, NONE) #endif -#if defined(__s390__) || defined(s390) +#if defined(TARGET_S390X) MINI_OP(OP_S390_LOADARG, "s390_loadarg", NONE, NONE, NONE) MINI_OP(OP_S390_ARGREG, "s390_argreg", NONE, NONE, NONE) MINI_OP(OP_S390_ARGPTR, "s390_argptr", NONE, NONE, NONE) MINI_OP(OP_S390_STKARG, "s390_stkarg", NONE, NONE, NONE) MINI_OP(OP_S390_MOVE, "s390_move", IREG, IREG, NONE) MINI_OP(OP_S390_SETF4RET, "s390_setf4ret", FREG, FREG, NONE) -MINI_OP(OP_S390_BKCHAIN, "s390_bkchain", NONE, NONE, NONE) +MINI_OP(OP_S390_BKCHAIN, "s390_bkchain", IREG, IREG, NONE) MINI_OP(OP_S390_LADD, "s390_long_add", LREG, IREG, IREG) MINI_OP(OP_S390_LADD_OVF, "s390_long_add_ovf", LREG, IREG, IREG) MINI_OP(OP_S390_LADD_OVF_UN, "s390_long_add_ovf_un", LREG, IREG, IREG) @@ -1229,7 +1229,7 @@ MINI_OP(OP_S390_CGIJ, "s390_cgij", LREG, NONE, NONE) MINI_OP(OP_S390_CLGIJ, "s390_cgij_un", LREG, NONE, NONE) #endif -#if defined(__mips__) +#if defined(TARGET_MIPS) MINI_OP(OP_MIPS_BEQ, "mips_beq", NONE, IREG, IREG) MINI_OP(OP_MIPS_BGEZ, "mips_bgez", NONE, IREG, NONE) MINI_OP(OP_MIPS_BGTZ, "mips_bgtz", NONE, IREG, NONE) diff --git a/mono/mini/mini-posix.c b/mono/mini/mini-posix.c index 397d33492e91..8db0345497b1 100644 --- a/mono/mini/mini-posix.c +++ b/mono/mini/mini-posix.c @@ -65,7 +65,7 @@ #include "trace.h" #include "version.h" #include "debugger-agent.h" - +#include "mini-runtime.h" #include "jit-icalls.h" #ifdef HOST_DARWIN diff --git a/mono/mini/mini-ppc.c b/mono/mini/mini-ppc.c index 252f82f1721f..c67653937c2e 100644 --- a/mono/mini/mini-ppc.c +++ b/mono/mini/mini-ppc.c @@ -29,6 +29,8 @@ #endif #include "trace.h" #include "ir-emit.h" +#include "aot-runtime.h" +#include "mini-runtime.h" #ifdef __APPLE__ #include #endif @@ -68,8 +70,6 @@ enum { #define mono_mini_arch_unlock() mono_os_mutex_unlock (&mini_arch_mutex) static mono_mutex_t mini_arch_mutex; -int mono_exc_esp_offset = 0; - /* * The code generated for sequence points reads from this location, which is * made read-only when single stepping is enabled. @@ -1455,20 +1455,6 @@ mono_arch_allocate_vars (MonoCompile *m) offset += 8; /* the MonoLMF structure is stored just below the stack pointer */ - -#if 0 - /* this stuff should not be needed on ppc and the new jit, - * because a call on ppc to the handlers doesn't change the - * stack pointer and the jist doesn't manipulate the stack pointer - * for operations involving valuetypes. - */ - /* reserve space to store the esp */ - offset += sizeof (gpointer); - - /* this is a global constant */ - mono_exc_esp_offset = offset; -#endif - if (MONO_TYPE_ISSTRUCT (sig->ret)) { offset += sizeof(gpointer) - 1; offset &= ~(sizeof(gpointer) - 1); @@ -1904,7 +1890,7 @@ enum { }; void* -mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers) +mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments) { guchar *code = p; int save_mode = SAVE_NONE; @@ -4107,7 +4093,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_CALL_HANDLER: mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb); ppc_bl (code, 0); - mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb); + for (GList *tmp = ins->inst_eh_blocks; tmp != bb->clause_holes; tmp = tmp->prev) + mono_cfg_add_try_hole (cfg, (MonoExceptionClause *)tmp->data, code, bb); break; case OP_LABEL: ins->inst_c0 = code - cfg->native_code; diff --git a/mono/mini/mini-profiler.c b/mono/mini/mini-profiler.c index c6c615886622..4fdf12918ef8 100644 --- a/mono/mini/mini-profiler.c +++ b/mono/mini/mini-profiler.c @@ -204,7 +204,7 @@ mini_profiler_context_get_this (MonoProfilerCallContext *ctx) return NULL; if (ctx->interp_frame) - return memdup_with_type (mono_interp_frame_get_this (ctx->interp_frame), &ctx->method->klass->this_arg); + return memdup_with_type (mini_get_interp_callbacks ()->frame_get_this (ctx->interp_frame), &ctx->method->klass->this_arg); MonoDebugMethodJitInfo *info = mono_debug_find_method (ctx->method, mono_domain_get ()); @@ -223,7 +223,7 @@ mini_profiler_context_get_argument (MonoProfilerCallContext *ctx, guint32 pos) return NULL; if (ctx->interp_frame) - return memdup_with_type (mono_interp_frame_get_arg (ctx->interp_frame, pos), sig->params [pos]); + return memdup_with_type (mini_get_interp_callbacks ()->frame_get_arg (ctx->interp_frame, pos), sig->params [pos]); MonoDebugMethodJitInfo *info = mono_debug_find_method (ctx->method, mono_domain_get ()); @@ -250,7 +250,7 @@ mini_profiler_context_get_local (MonoProfilerCallContext *ctx, guint32 pos) mono_metadata_free_mh (header); if (ctx->interp_frame) - return memdup_with_type (mono_interp_frame_get_local (ctx->interp_frame, pos), t); + return memdup_with_type (mini_get_interp_callbacks ()->frame_get_local (ctx->interp_frame, pos), t); MonoDebugMethodJitInfo *info = mono_debug_find_method (ctx->method, mono_domain_get ()); diff --git a/mono/mini/mini-runtime.c b/mono/mini/mini-runtime.c index 8798c8341a15..472787db6ac8 100644 --- a/mono/mini/mini-runtime.c +++ b/mono/mini/mini-runtime.c @@ -77,6 +77,7 @@ #include "trace.h" #include "version.h" #include "aot-compiler.h" +#include "aot-runtime.h" #include "jit-icalls.h" @@ -85,6 +86,7 @@ #include "debugger-agent.h" #include "lldb.h" #include "mixed_callstack_plugin.h" +#include "mini-runtime.h" #ifdef MONO_ARCH_LLVM_SUPPORTED #ifdef ENABLE_LLVM @@ -93,9 +95,7 @@ #endif #endif -#ifndef DISABLE_INTERPRETER #include "interp/interp.h" -#endif static guint32 default_opt = 0; static gboolean default_opt_set = FALSE; @@ -1999,13 +1999,11 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, gboolean jit_ return NULL; } -#ifndef DISABLE_INTERPRETER if (mono_use_interpreter && !jit_only) { - code = mono_interp_create_method_pointer (method, error); + code = mini_get_interp_callbacks ()->create_method_pointer (method, error); if (code) return code; } -#endif if (mono_llvm_only) /* Should be handled by the caller */ @@ -2634,10 +2632,8 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec MonoJitInfo *ji = NULL; gboolean callee_gsharedvt = FALSE; -#ifndef DISABLE_INTERPRETER if (mono_use_interpreter) - return mono_interp_runtime_invoke (method, obj, params, exc, error); -#endif + return mini_get_interp_callbacks ()->runtime_invoke (method, obj, params, exc, error); error_init (error); if (exc) @@ -3324,12 +3320,9 @@ mini_get_delegate_arg (MonoMethod *method, gpointer method_ptr) void mini_init_delegate (MonoDelegate *del) { -#ifndef DISABLE_INTERPRETER if (mono_use_interpreter) - mono_interp_init_delegate (del); - else -#endif - if (mono_llvm_only) + mini_get_interp_callbacks ()->init_delegate (del); + else if (mono_llvm_only) del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr); } @@ -3790,6 +3783,22 @@ mini_add_profiler_argument (const char *desc) g_ptr_array_add (profile_options, (gpointer) desc); } + +MonoInterpCallbacks interp_cbs; + +void +mini_install_interp_callbacks (MonoInterpCallbacks *cbs) +{ + memcpy (&interp_cbs, cbs, sizeof (MonoInterpCallbacks)); +} + +MonoInterpCallbacks * +mini_get_interp_callbacks (void) +{ + return &interp_cbs; +} + + MonoDomain * mini_init (const char *filename, const char *runtime_version) { @@ -3811,8 +3820,11 @@ mini_init (const char *filename, const char *runtime_version) #endif #ifndef DISABLE_INTERPRETER - mono_interp_init (); + if (mono_use_interpreter) + mono_interp_init (); + else #endif + mono_interp_stub_init (); mono_os_mutex_init_recursive (&jit_mutex); @@ -3867,10 +3879,11 @@ mini_init (const char *filename, const char *runtime_version) callbacks.create_remoting_trampoline = mono_jit_create_remoting_trampoline; #endif #endif -#if !defined (DISABLE_INTERPRETER) && !defined (DISABLE_REMOTING) +#ifndef DISABLE_REMOTING if (mono_use_interpreter) - callbacks.interp_get_remoting_invoke = mono_interp_get_remoting_invoke; + callbacks.interp_get_remoting_invoke = mini_get_interp_callbacks ()->get_remoting_invoke; #endif + callbacks.get_weak_field_indexes = mono_aot_get_weak_field_indexes; mono_install_callbacks (&callbacks); @@ -4317,7 +4330,7 @@ register_icalls (void) register_icall (mono_throw_method_access, "mono_throw_method_access", "void ptr ptr", FALSE); register_icall_no_wrapper (mono_dummy_jit_icall, "mono_dummy_jit_icall", "void"); - register_icall_with_wrapper (mono_monitor_enter_internal, "mono_monitor_enter_internal", "void obj"); + register_icall_with_wrapper (mono_monitor_enter_internal, "mono_monitor_enter_internal", "int32 obj"); register_icall_with_wrapper (mono_monitor_enter_v4_internal, "mono_monitor_enter_v4_internal", "void obj ptr"); register_icall_no_wrapper (mono_monitor_enter_fast, "mono_monitor_enter_fast", "int obj"); register_icall_no_wrapper (mono_monitor_enter_v4_fast, "mono_monitor_enter_v4_fast", "int obj ptr"); diff --git a/mono/mini/mini-runtime.h b/mono/mini/mini-runtime.h new file mode 100644 index 000000000000..c4dcd503f6ab --- /dev/null +++ b/mono/mini/mini-runtime.h @@ -0,0 +1,191 @@ +/** + * \file + * + * Runtime declarations for the JIT. + * + * Copyright 2002-2003 Ximian Inc + * Copyright 2003-2011 Novell Inc + * Copyright 2011 Xamarin Inc + * Licensed under the MIT license. See LICENSE file in the project root for full license information. + */ + +#ifndef __MONO_MINI_RUNTIME_H__ +#define __MONO_MINI_RUNTIME_H__ + +#include "mini.h" + +/* Per-domain information maintained by the JIT */ +typedef struct +{ + /* Maps MonoMethod's to a GSList of GOT slot addresses pointing to its code */ + GHashTable *jump_target_got_slot_hash; + GHashTable *jump_target_hash; + /* Maps methods/klasses to the address of the given type of trampoline */ + GHashTable *class_init_trampoline_hash; + GHashTable *jump_trampoline_hash; + GHashTable *jit_trampoline_hash; + GHashTable *delegate_trampoline_hash; + /* Maps ClassMethodPair -> MonoDelegateTrampInfo */ + GHashTable *static_rgctx_trampoline_hash; + GHashTable *llvm_vcall_trampoline_hash; + /* maps MonoMethod -> MonoJitDynamicMethodInfo */ + GHashTable *dynamic_code_hash; + GHashTable *method_code_hash; + /* Maps methods to a RuntimeInvokeInfo structure, protected by the associated MonoDomain lock */ + MonoConcurrentHashTable *runtime_invoke_hash; + /* Maps MonoMethod to a GPtrArray containing sequence point locations */ + /* Protected by the domain lock */ + GHashTable *seq_points; + /* Debugger agent data */ + gpointer agent_info; + /* Maps MonoMethod to an arch-specific structure */ + GHashTable *arch_seq_points; + /* Maps a GSharedVtTrampInfo structure to a trampoline address */ + GHashTable *gsharedvt_arg_tramp_hash; + /* memcpy/bzero methods specialized for small constant sizes */ + gpointer *memcpy_addr [17]; + gpointer *bzero_addr [17]; + gpointer llvm_module; + /* Maps MonoMethod -> GSlist of addresses */ + GHashTable *llvm_jit_callees; + /* Maps MonoMethod -> RuntimeMethod */ + MonoInternalHashTable interp_code_hash; +} MonoJitDomainInfo; + +#define domain_jit_info(domain) ((MonoJitDomainInfo*)((domain)->runtime_info)) + +/* + * Stores state need to resume exception handling when using LLVM + */ +typedef struct { + MonoJitInfo *ji; + int clause_index; + MonoContext ctx, new_ctx; + /* FIXME: GC */ + gpointer ex_obj; + MonoLMF *lmf; + int first_filter_idx, filter_idx; +} ResumeState; + +struct MonoJitTlsData { + gpointer end_of_stack; + guint32 stack_size; + MonoLMF *lmf; + MonoLMF *first_lmf; + gpointer restore_stack_prot; + guint32 handling_stack_ovf; + gpointer signal_stack; + guint32 signal_stack_size; + gpointer stack_ovf_guard_base; + guint32 stack_ovf_guard_size; + guint stack_ovf_valloced : 1; + void (*abort_func) (MonoObject *object); + /* Used to implement --debug=casts */ + MonoClass *class_cast_from, *class_cast_to; + + /* Stores state needed by handler block with a guard */ + MonoContext ex_ctx; + ResumeState resume_state; + + /* handler block been guarded. It's safe to store this even for dynamic methods since there + is an activation on stack making sure it will remain alive.*/ + MonoJitExceptionInfo *handler_block; + + /* context to be used by the guard trampoline when resuming interruption.*/ + MonoContext handler_block_context; + /* + * Stores the state at the exception throw site to be used by mono_stack_walk () + * when it is called from profiler functions during exception handling. + */ + MonoContext orig_ex_ctx; + gboolean orig_ex_ctx_set; + + /* + * Stores if we need to run a chained exception in Windows. + */ + gboolean mono_win_chained_exception_needs_run; + + /* + * The current exception in flight + */ + guint32 thrown_exc; + /* + * If the current exception is not a subclass of Exception, + * the original exception. + */ + guint32 thrown_non_exc; + + /* + * The calling assembly in llvmonly mode. + */ + MonoImage *calling_image; + + /* + * The stack frame "high water mark" for ThreadAbortExceptions. + * We will rethrow the exception upon exiting a catch clause that's + * in a function stack frame above the water mark(isn't being called by + * the catch block that caught the ThreadAbortException). + */ + gpointer abort_exc_stack_threshold; + + /* + * List of methods being JIT'd in the current thread. + */ + int active_jit_methods; + + gpointer interp_context; + +#if defined(TARGET_WIN32) + MonoContext stack_restore_ctx; +#endif +}; + +/* + * This structure is an extension of MonoLMF and contains extra information. + */ +typedef struct { + struct MonoLMF lmf; + gboolean debugger_invoke; + gboolean interp_exit; + MonoContext ctx; /* if debugger_invoke is TRUE */ + /* If interp_exit is TRUE */ + gpointer interp_exit_data; +} MonoLMFExt; + +/* main function */ +MONO_API int mono_main (int argc, char* argv[]); +MONO_API void mono_set_defaults (int verbose_level, guint32 opts); +MONO_API void mono_parse_env_options (int *ref_argc, char **ref_argv []); +MONO_API char *mono_parse_options_from (const char *options, int *ref_argc, char **ref_argv []); + +/* actual definition in interp.h */ +typedef struct _MonoInterpCallbacks MonoInterpCallbacks; + +void mono_interp_stub_init (void); +void mini_install_interp_callbacks (MonoInterpCallbacks *cbs); +MonoInterpCallbacks* mini_get_interp_callbacks (void); + +MonoDomain* mini_init (const char *filename, const char *runtime_version); +void mini_cleanup (MonoDomain *domain); +MONO_API MonoDebugOptions *mini_get_debug_options (void); +MONO_API gboolean mini_parse_debug_option (const char *option); + +void mini_jit_init (void); +void mini_jit_cleanup (void); +void mono_disable_optimizations (guint32 opts); +void mono_set_optimizations (guint32 opts); +void mono_precompile_assemblies (void); +MONO_API int mono_parse_default_optimizations (const char* p); +gboolean mono_running_on_valgrind (void); + +MonoLMF * mono_get_lmf (void); +MonoLMF** mono_get_lmf_addr (void); +void mono_set_lmf (MonoLMF *lmf); +void mono_push_lmf (MonoLMFExt *ext); +void mono_pop_lmf (MonoLMF *lmf); +MonoJitTlsData* mono_get_jit_tls (void); +MONO_API MonoDomain* mono_jit_thread_attach (MonoDomain *domain); +MONO_API void mono_jit_set_domain (MonoDomain *domain); + +#endif /* __MONO_MINI_RUNTIME_H__ */ + diff --git a/mono/mini/mini-s390x.c b/mono/mini/mini-s390x.c index f5c00186d75d..ac42af3983b5 100644 --- a/mono/mini/mini-s390x.c +++ b/mono/mini/mini-s390x.c @@ -340,6 +340,8 @@ if (ins->inst_true_bb->native_offset) { \ #include "ir-emit.h" #include "trace.h" #include "mini-gc.h" +#include "aot-runtime.h" +#include "mini-runtime.h" /*========================= End of Includes ========================*/ @@ -450,8 +452,6 @@ static void compare_and_branch(MonoBasicBlock *, MonoInst *, int, gboolean); /* G l o b a l V a r i a b l e s */ /*------------------------------------------------------------------*/ -int mono_exc_esp_offset = 0; - __thread int indent_level = 0; __thread FILE *trFd = NULL; int curThreadNo = 0; @@ -2659,26 +2659,6 @@ mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_instrument_mem_needs */ -/* */ -/* Function - Allow tracing to work with this interface (with */ -/* an optional argument). */ -/* */ -/*------------------------------------------------------------------*/ - -void -mono_arch_instrument_mem_needs (MonoMethod *method, int *stack, int *code) -{ - /* no stack room needed now (may be needed for FASTCALL-trace support) */ - *stack = 0; - /* split prolog-epilog requirements? */ - *code = 50; /* max bytes needed: check this number */ -} - -/*========================= End of Function ========================*/ - /*------------------------------------------------------------------*/ /* */ /* Name - mono_arch_instrument_prolog */ @@ -2734,7 +2714,7 @@ mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, /*------------------------------------------------------------------*/ void* -mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers) +mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments) { guchar *code = p; int save_mode = SAVE_NONE, @@ -4426,7 +4406,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb); s390_brasl (code, s390_r14, 0); - mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb); + for (GList *tmp = ins->inst_eh_blocks; tmp != bb->clause_holes; tmp = tmp->prev) + mono_cfg_add_try_hole (cfg, (MonoExceptionClause *)tmp->data, code, bb); } break; case OP_LABEL: { diff --git a/mono/mini/mini-sparc.c b/mono/mini/mini-sparc.c index 1b5f97b572b7..d1eb219853a2 100644 --- a/mono/mini/mini-sparc.c +++ b/mono/mini/mini-sparc.c @@ -3136,7 +3136,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) /* This is a jump inside the method, so call_simple works even on V9 */ sparc_call_simple (code, 0); sparc_nop (code); - mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb); + for (GList *tmp = ins->inst_eh_blocks; tmp != bb->clause_holes; tmp = tmp->prev) + mono_cfg_add_try_hole (cfg, (MonoExceptionClause *)tmp->data, code, bb); break; case OP_LABEL: ins->inst_c0 = (guint8*)code - cfg->native_code; @@ -3776,7 +3777,7 @@ enum { }; void* -mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers) +mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments) { guint32 *code = (guint32*)p; int save_mode = SAVE_NONE; diff --git a/mono/mini/mini-trampolines.c b/mono/mini/mini-trampolines.c index 0c02fcf8bf0c..30fa8daf2914 100644 --- a/mono/mini/mini-trampolines.c +++ b/mono/mini/mini-trampolines.c @@ -22,10 +22,10 @@ #include "mini.h" #include "lldb.h" #include "mixed_callstack_plugin.h" +#include "aot-runtime.h" +#include "mini-runtime.h" -#ifndef DISABLE_INTERPRETER #include "interp/interp.h" -#endif /* * Address of the trampoline code. This is used by the debugger to check @@ -1400,14 +1400,12 @@ mono_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean ad error_init (error); -#ifndef DISABLE_INTERPRETER if (mono_use_interpreter) { - gpointer ret = mono_interp_create_trampoline (domain, method, error); + gpointer ret = mini_get_interp_callbacks ()->create_trampoline (domain, method, error); if (!mono_error_ok (error)) return NULL; return ret; } -#endif code = mono_jit_find_compiled_method_with_jit_info (domain, method, &ji); /* diff --git a/mono/mini/mini-wasm.c b/mono/mini/mini-wasm.c index af53b5cc585d..236892a48620 100644 --- a/mono/mini/mini-wasm.c +++ b/mono/mini/mini-wasm.c @@ -162,7 +162,19 @@ The following functions don't belong here, but are due to laziness. gboolean mono_w32file_get_volume_information (const gunichar2 *path, gunichar2 *volumename, gint volumesize, gint *outserial, gint *maxcomp, gint *fsflags, gunichar2 *fsbuffer, gint fsbuffersize) { - g_error ("mono_w32file_get_volume_information"); + glong len; + gboolean status = FALSE; + + gunichar2 *ret = g_utf8_to_utf16 ("memfs", -1, NULL, &len, NULL); + if (ret != NULL && len < fsbuffersize) { + memcpy (fsbuffer, ret, len * sizeof (gunichar2)); + fsbuffer [len] = 0; + status = TRUE; + } + if (ret != NULL) + g_free (ret); + + return status; } diff --git a/mono/mini/mini-wasm.h b/mono/mini/mini-wasm.h index 55adab22dad8..e4f76af6f0b7 100644 --- a/mono/mini/mini-wasm.h +++ b/mono/mini/mini-wasm.h @@ -45,4 +45,7 @@ typedef struct { #define MONO_ARCH_IMT_REG WASM_REG_0 #define MONO_ARCH_RGCTX_REG WASM_REG_0 +/* must be at a power of 2 and >= 8 */ +#define MONO_ARCH_FRAME_ALIGNMENT 16 + #endif /* __MONO_MINI_WASM_H__ */ diff --git a/mono/mini/mini-windows-dllmain.c b/mono/mini/mini-windows-dllmain.c index cd3f1f04c1a7..2a8200500b02 100644 --- a/mono/mini/mini-windows-dllmain.c +++ b/mono/mini/mini-windows-dllmain.c @@ -12,6 +12,7 @@ #include #include #include "mini.h" +#include "mini-runtime.h" #ifdef HOST_WIN32 #include diff --git a/mono/mini/mini-windows.c b/mono/mini/mini-windows.c index 404b62fd2ebd..a10343f44e2b 100644 --- a/mono/mini/mini-windows.c +++ b/mono/mini/mini-windows.c @@ -45,6 +45,7 @@ #include #include "mini.h" +#include "mini-runtime.h" #include "mini-windows.h" #include #include diff --git a/mono/mini/mini-x86.c b/mono/mini/mini-x86.c index d8124d008ac5..e5092d3e7ea5 100644 --- a/mono/mini/mini-x86.c +++ b/mono/mini/mini-x86.c @@ -39,6 +39,8 @@ #include "cpu-x86.h" #include "ir-emit.h" #include "mini-gc.h" +#include "aot-runtime.h" +#include "mini-runtime.h" #ifndef TARGET_WIN32 #ifdef MONO_XEN_OPT @@ -1677,7 +1679,7 @@ enum { }; void* -mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers) +mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments) { guchar *code = p; int arg_size = 0, stack_usage = 0, save_mode = SAVE_NONE; @@ -3250,7 +3252,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) x86_alu_reg_imm (code, X86_SUB, X86_ESP, MONO_ARCH_FRAME_ALIGNMENT - 4); mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb); x86_call_imm (code, 0); - mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb); + for (GList *tmp = ins->inst_eh_blocks; tmp != bb->clause_holes; tmp = tmp->prev) + mono_cfg_add_try_hole (cfg, (MonoExceptionClause *)tmp->data, code, bb); x86_alu_reg_imm (code, X86_ADD, X86_ESP, MONO_ARCH_FRAME_ALIGNMENT - 4); break; case OP_START_HANDLER: { diff --git a/mono/mini/mini.c b/mono/mini/mini.c index a405a5398d18..0b7283612b31 100644 --- a/mono/mini/mini.c +++ b/mono/mini/mini.c @@ -79,6 +79,8 @@ #include "mini-llvm.h" #include "lldb.h" #include "mixed_callstack_plugin.h" +#include "aot-runtime.h" +#include "mini-runtime.h" MonoCallSpec *mono_jit_trace_calls; MonoMethodDesc *mono_inject_async_exc_method; @@ -3944,12 +3946,6 @@ mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass * return FALSE; } -void* -mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments) -{ - return mono_arch_instrument_epilog_full (cfg, func, p, enable_arguments, FALSE); -} - void mono_cfg_add_try_hole (MonoCompile *cfg, MonoExceptionClause *clause, guint8 *start, MonoBasicBlock *bb) { diff --git a/mono/mini/mini.h b/mono/mini/mini.h index 00d041950828..ca8eb0a7116a 100644 --- a/mono/mini/mini.h +++ b/mono/mini/mini.h @@ -119,9 +119,6 @@ #define MONO_USE_AOT_COMPILER #endif -/* Version number of the AOT file format */ -#define MONO_AOT_FILE_VERSION 141 - //TODO: This is x86/amd64 specific. #define mono_simd_shuffle_mask(a,b,c,d) ((a) | ((b) << 2) | ((c) << 4) | ((d) << 6)) @@ -132,192 +129,6 @@ #define MONO_TYPE_IS_PRIMITIVE(t) ((!(t)->byref && ((((t)->type >= MONO_TYPE_BOOLEAN && (t)->type <= MONO_TYPE_R8) || ((t)->type >= MONO_TYPE_I && (t)->type <= MONO_TYPE_U))))) -#define MONO_AOT_TRAMP_PAGE_SIZE 16384 - -/* Constants used to encode different types of methods in AOT */ -enum { - MONO_AOT_METHODREF_MIN = 240, - /* Image index bigger than METHODREF_MIN */ - MONO_AOT_METHODREF_LARGE_IMAGE_INDEX = 249, - /* Runtime provided methods on arrays */ - MONO_AOT_METHODREF_ARRAY = 250, - MONO_AOT_METHODREF_NO_AOT_TRAMPOLINE = 251, - /* Wrappers */ - MONO_AOT_METHODREF_WRAPPER = 252, - /* Methods on generic instances */ - MONO_AOT_METHODREF_GINST = 253, - /* Methods resolve using a METHODSPEC token */ - MONO_AOT_METHODREF_METHODSPEC = 254, -}; - -/* Constants used to encode different types of types in AOT */ -enum { - /* typedef index */ - MONO_AOT_TYPEREF_TYPEDEF_INDEX = 1, - /* typedef index + image index */ - MONO_AOT_TYPEREF_TYPEDEF_INDEX_IMAGE = 2, - /* typespec token */ - MONO_AOT_TYPEREF_TYPESPEC_TOKEN = 3, - /* generic inst */ - MONO_AOT_TYPEREF_GINST = 4, - /* type/method variable */ - MONO_AOT_TYPEREF_VAR = 5, - /* array */ - MONO_AOT_TYPEREF_ARRAY = 6, - /* blob index of the type encoding */ - MONO_AOT_TYPEREF_BLOB_INDEX = 7, - /* ptr */ - MONO_AOT_TYPEREF_PTR = 8 -}; - -/* Trampolines which we have a lot of */ -typedef enum { - MONO_AOT_TRAMP_SPECIFIC = 0, - MONO_AOT_TRAMP_STATIC_RGCTX = 1, - MONO_AOT_TRAMP_IMT = 2, - MONO_AOT_TRAMP_GSHAREDVT_ARG = 3, - MONO_AOT_TRAMP_NUM = 4 -} MonoAotTrampoline; - -typedef enum { - MONO_AOT_FILE_FLAG_WITH_LLVM = 1, - MONO_AOT_FILE_FLAG_FULL_AOT = 2, - MONO_AOT_FILE_FLAG_DEBUG = 4, - MONO_AOT_FILE_FLAG_LLVM_THUMB = 8, - MONO_AOT_FILE_FLAG_LLVM_ONLY = 16, - MONO_AOT_FILE_FLAG_SAFEPOINTS = 32, - MONO_AOT_FILE_FLAG_SEPARATE_DATA = 64, - MONO_AOT_FILE_FLAG_EAGER_LOAD = 128, -} MonoAotFileFlags; - -typedef enum { - MONO_AOT_TABLE_BLOB, - MONO_AOT_TABLE_IMAGE_TABLE, - MONO_AOT_TABLE_CLASS_NAME, - MONO_AOT_TABLE_METHOD_INFO_OFFSETS, - MONO_AOT_TABLE_EX_INFO_OFFSETS, - MONO_AOT_TABLE_CLASS_INFO_OFFSETS, - MONO_AOT_TABLE_GOT_INFO_OFFSETS, - MONO_AOT_TABLE_LLVM_GOT_INFO_OFFSETS, - MONO_AOT_TABLE_EXTRA_METHOD_INFO_OFFSETS, - MONO_AOT_TABLE_EXTRA_METHOD_TABLE, - MONO_AOT_TABLE_NUM -} MonoAotFileTable; - -/* This structure is stored in the AOT file */ -typedef struct MonoAotFileInfo -{ - /* The version number of the AOT file format, should match MONO_AOT_FILE_VERSION */ - guint32 version; - /* For alignment */ - guint32 dummy; - - /* All the pointers should be at the start to avoid alignment problems */ - /* Symbols */ -#define MONO_AOT_FILE_INFO_FIRST_SYMBOL jit_got - /* Global Offset Table for JITted code */ - gpointer jit_got; - /* Global Offset Table for LLVM code */ - gpointer llvm_got; - /* Mono EH Frame created by llc when using LLVM */ - gpointer mono_eh_frame; - /* Points to the get_method () function in the LLVM image or NULL */ - gpointer llvm_get_method; - /* Points to the get_unbox_tramp () function in the LLVM image or NULL */ - gpointer llvm_get_unbox_tramp; - gpointer jit_code_start; - gpointer jit_code_end; - gpointer method_addresses; - /* Data blob */ - gpointer blob; - gpointer class_name_table; - gpointer class_info_offsets; - gpointer method_info_offsets; - gpointer ex_info_offsets; - gpointer extra_method_info_offsets; - gpointer extra_method_table; - gpointer got_info_offsets; - gpointer llvm_got_info_offsets; - gpointer image_table; - gpointer mem_end; - /* The GUID of the assembly which the AOT image was generated from */ - gpointer assembly_guid; - /* - * The runtime version string for AOT images generated using 'bind-to-runtime-version', - * NULL otherwise. - */ - gpointer runtime_version; - /* Blocks of various kinds of trampolines */ - gpointer specific_trampolines; - gpointer static_rgctx_trampolines; - gpointer imt_trampolines; - gpointer gsharedvt_arg_trampolines; - /* In static mode, points to a table of global symbols for trampolines etc */ - gpointer globals; - /* Points to a string containing the assembly name*/ - gpointer assembly_name; - /* Start of Mono's Program Linkage Table */ - gpointer plt; - /* End of Mono's Program Linkage Table */ - gpointer plt_end; - gpointer unwind_info; - /* Points to a table mapping methods to their unbox trampolines */ - gpointer unbox_trampolines; - /* Points to the end of the previous table */ - gpointer unbox_trampolines_end; - /* Points to a table of unbox trampoline addresses/offsets */ - gpointer unbox_trampoline_addresses; -#define MONO_AOT_FILE_INFO_LAST_SYMBOL unbox_trampoline_addresses - - /* Scalars */ - /* The index of the first GOT slot used by the PLT */ - guint32 plt_got_offset_base; - /* Number of entries in the GOT */ - guint32 got_size; - /* Number of entries in the PLT */ - guint32 plt_size; - /* Number of methods */ - guint32 nmethods; - /* A union of MonoAotFileFlags */ - guint32 flags; - /* Optimization flags used to compile the module */ - guint32 opts; - /* SIMD flags used to compile the module */ - guint32 simd_opts; - /* Index of the blob entry holding the GC used by this module */ - gint32 gc_name_index; - guint32 num_rgctx_fetch_trampolines; - /* These are used for sanity checking object layout problems when cross-compiling */ - guint32 double_align, long_align, generic_tramp_num; - /* The page size used by trampoline pages */ - guint32 tramp_page_size; - /* - * The number of GOT entries which need to be preinitialized when the - * module is loaded. - */ - guint32 nshared_got_entries; - /* The size of the data file, if MONO_AOT_FILE_FLAG_SEPARATE_DATA is set */ - guint32 datafile_size; - - /* Arrays */ - /* Offsets for tables inside the data file if MONO_AOT_FILE_FLAG_SEPARATE_DATA is set */ - // FIXME: Sync with AOT - guint32 table_offsets [MONO_AOT_TABLE_NUM]; - /* Number of trampolines */ - guint32 num_trampolines [MONO_AOT_TRAMP_NUM]; - /* The indexes of the first GOT slots used by the trampolines */ - guint32 trampoline_got_offset_base [MONO_AOT_TRAMP_NUM]; - /* The size of one trampoline */ - guint32 trampoline_size [MONO_AOT_TRAMP_NUM]; - /* The offset where the trampolines begin on a trampoline page */ - guint32 tramp_page_code_offsets [MONO_AOT_TRAMP_NUM]; - /* GUID of aot compilation */ - guint8 aotid[16]; -} MonoAotFileInfo; - -/* Number of symbols in the MonoAotFileInfo structure */ -#define MONO_AOT_FILE_INFO_NUM_SYMBOLS (((G_STRUCT_OFFSET (MonoAotFileInfo, MONO_AOT_FILE_INFO_LAST_SYMBOL) - G_STRUCT_OFFSET (MonoAotFileInfo, MONO_AOT_FILE_INFO_FIRST_SYMBOL)) / sizeof (gpointer)) + 1) - typedef struct { MonoClass *klass; @@ -331,44 +142,6 @@ typedef struct gboolean is_virtual; } MonoDelegateClassMethodPair; -/* Per-domain information maintained by the JIT */ -typedef struct -{ - /* Maps MonoMethod's to a GSList of GOT slot addresses pointing to its code */ - GHashTable *jump_target_got_slot_hash; - GHashTable *jump_target_hash; - /* Maps methods/klasses to the address of the given type of trampoline */ - GHashTable *class_init_trampoline_hash; - GHashTable *jump_trampoline_hash; - GHashTable *jit_trampoline_hash; - GHashTable *delegate_trampoline_hash; - /* Maps ClassMethodPair -> MonoDelegateTrampInfo */ - GHashTable *static_rgctx_trampoline_hash; - GHashTable *llvm_vcall_trampoline_hash; - /* maps MonoMethod -> MonoJitDynamicMethodInfo */ - GHashTable *dynamic_code_hash; - GHashTable *method_code_hash; - /* Maps methods to a RuntimeInvokeInfo structure, protected by the associated MonoDomain lock */ - MonoConcurrentHashTable *runtime_invoke_hash; - /* Maps MonoMethod to a GPtrArray containing sequence point locations */ - /* Protected by the domain lock */ - GHashTable *seq_points; - /* Debugger agent data */ - gpointer agent_info; - /* Maps MonoMethod to an arch-specific structure */ - GHashTable *arch_seq_points; - /* Maps a GSharedVtTrampInfo structure to a trampoline address */ - GHashTable *gsharedvt_arg_tramp_hash; - /* memcpy/bzero methods specialized for small constant sizes */ - gpointer *memcpy_addr [17]; - gpointer *bzero_addr [17]; - gpointer llvm_module; - /* Maps MonoMethod -> GSlist of addresses */ - GHashTable *llvm_jit_callees; - /* Maps MonoMethod -> RuntimeMethod */ - MonoInternalHashTable interp_code_hash; -} MonoJitDomainInfo; - typedef struct { MonoJitInfo *ji; MonoCodeManager *code_mp; @@ -380,8 +153,6 @@ typedef struct { MonoGenericParam *parent; } MonoGSharedGenericParam; -#define domain_jit_info(domain) ((MonoJitDomainInfo*)((domain)->runtime_info)) - /* Contains a list of ips which needs to be patched when a method is compiled */ typedef struct { GSList *list; @@ -544,7 +315,6 @@ typedef struct MonoSpillInfo MonoSpillInfo; extern MonoCallSpec *mono_jit_trace_calls; extern gboolean mono_break_on_exc; -extern int mono_exc_esp_offset; extern gboolean mono_compile_aot; extern gboolean mono_aot_only; extern gboolean mono_llvm_only; @@ -909,7 +679,7 @@ struct MonoInst { MonoClass *klass; int *phi_args; MonoCallInst *call_inst; - MonoExceptionClause *exception_clause; + GList *exception_clauses; } op [2]; gint64 i8const; double r8const; @@ -1068,7 +838,7 @@ enum { #define inst_call data.op[1].call_inst #define inst_phi_args data.op[1].phi_args -#define inst_eh_block data.op[1].exception_clause +#define inst_eh_blocks data.op[1].exception_clauses static inline void mono_inst_set_src_registers (MonoInst *ins, int *regs) @@ -1143,103 +913,7 @@ struct MonoMethodVar { gint32 vreg; }; -/* - * Stores state need to resume exception handling when using LLVM - */ -typedef struct { - MonoJitInfo *ji; - int clause_index; - MonoContext ctx, new_ctx; - /* FIXME: GC */ - gpointer ex_obj; - MonoLMF *lmf; - int first_filter_idx, filter_idx; -} ResumeState; - -typedef struct { - gpointer end_of_stack; - guint32 stack_size; - MonoLMF *lmf; - MonoLMF *first_lmf; - gpointer restore_stack_prot; - guint32 handling_stack_ovf; - gpointer signal_stack; - guint32 signal_stack_size; - gpointer stack_ovf_guard_base; - guint32 stack_ovf_guard_size; - guint stack_ovf_valloced : 1; - void (*abort_func) (MonoObject *object); - /* Used to implement --debug=casts */ - MonoClass *class_cast_from, *class_cast_to; - - /* Stores state needed by handler block with a guard */ - MonoContext ex_ctx; - ResumeState resume_state; - - /* handler block been guarded. It's safe to store this even for dynamic methods since there - is an activation on stack making sure it will remain alive.*/ - MonoJitExceptionInfo *handler_block; - - /* context to be used by the guard trampoline when resuming interruption.*/ - MonoContext handler_block_context; - /* - * Stores the state at the exception throw site to be used by mono_stack_walk () - * when it is called from profiler functions during exception handling. - */ - MonoContext orig_ex_ctx; - gboolean orig_ex_ctx_set; - - /* - * Stores if we need to run a chained exception in Windows. - */ - gboolean mono_win_chained_exception_needs_run; - - /* - * The current exception in flight - */ - guint32 thrown_exc; - /* - * If the current exception is not a subclass of Exception, - * the original exception. - */ - guint32 thrown_non_exc; - - /* - * The calling assembly in llvmonly mode. - */ - MonoImage *calling_image; - - /* - * The stack frame "high water mark" for ThreadAbortExceptions. - * We will rethrow the exception upon exiting a catch clause that's - * in a function stack frame above the water mark(isn't being called by - * the catch block that caught the ThreadAbortException). - */ - gpointer abort_exc_stack_threshold; - - /* - * List of methods being JIT'd in the current thread. - */ - int active_jit_methods; - - gpointer interp_context; - -#if defined(TARGET_WIN32) - MonoContext stack_restore_ctx; -#endif -} MonoJitTlsData; - -/* - * This structure is an extension of MonoLMF and contains extra information. - */ -typedef struct { - struct MonoLMF lmf; - gboolean debugger_invoke; - gboolean interp_exit; - MonoContext ctx; /* if debugger_invoke is TRUE */ - /* If interp_exit is TRUE */ - gpointer interp_exit_data; -} MonoLMFExt; +typedef struct MonoJitTlsData MonoJitTlsData; /* Generic sharing */ @@ -2364,17 +2038,6 @@ mono_bb_last_inst (MonoBasicBlock *bb, int filter) return ins; } -/* main function */ -MONO_API int mono_main (int argc, char* argv[]); -MONO_API void mono_set_defaults (int verbose_level, guint32 opts); -MONO_API void mono_parse_env_options (int *ref_argc, char **ref_argv []); -MONO_API char *mono_parse_options_from (const char *options, int *ref_argc, char **ref_argv []); - -MonoDomain* mini_init (const char *filename, const char *runtime_version); -void mini_cleanup (MonoDomain *domain); -MONO_API MonoDebugOptions *mini_get_debug_options (void); -MONO_API gboolean mini_parse_debug_option (const char *option); - /* profiler support */ void mini_add_profiler_argument (const char *desc); void mini_profiler_emit_enter (MonoCompile *cfg); @@ -2394,10 +2057,6 @@ void mono_cfg_dump_close_group (MonoCompile *cfg); void mono_cfg_dump_ir (MonoCompile *cfg, const char *phase_name); /* helper methods */ -void mini_jit_init (void); -void mini_jit_cleanup (void); -void mono_disable_optimizations (guint32 opts); -void mono_set_optimizations (guint32 opts); void mono_set_bisect_methods (guint32 opt, const char *method_list_filename); guint32 mono_get_optimizations_for_method (MonoMethod *method, guint32 default_opt); char* mono_opt_descr (guint32 flags); @@ -2408,8 +2067,6 @@ MonoInst* mono_find_spvar_for_region (MonoCompile *cfg, int region); MonoInst* mono_find_exvar_for_offset (MonoCompile *cfg, int offset); int mono_get_block_region_notry (MonoCompile *cfg, int region) MONO_LLVM_INTERNAL; -void mono_precompile_assemblies (void); -MONO_API int mono_parse_default_optimizations (const char* p); void mono_bblock_add_inst (MonoBasicBlock *bb, MonoInst *inst) MONO_LLVM_INTERNAL; void mono_bblock_insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *ins_to_insert); void mono_bblock_insert_before_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *ins_to_insert); @@ -2478,14 +2135,6 @@ gpointer mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *met gpointer mono_jit_compile_method (MonoMethod *method, MonoError *error); gpointer mono_jit_compile_method_jit_only (MonoMethod *method, MonoError *error); gpointer mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, int opt, MonoError *error); -MonoLMF * mono_get_lmf (void); -MonoLMF** mono_get_lmf_addr (void); -void mono_set_lmf (MonoLMF *lmf); -void mono_push_lmf (MonoLMFExt *ext); -void mono_pop_lmf (MonoLMF *lmf); -MonoJitTlsData* mono_get_jit_tls (void); -MONO_API MonoDomain* mono_jit_thread_attach (MonoDomain *domain); -MONO_API void mono_jit_set_domain (MonoDomain *domain); MonoInst* mono_create_tls_get (MonoCompile *cfg, MonoTlsKey key); GList *mono_varlist_insert_sorted (MonoCompile *cfg, GList *list, MonoMethodVar *mv, int sort_type); GList *mono_varlist_sort (MonoCompile *cfg, GList *list, int sort_type); @@ -2525,8 +2174,7 @@ gint32 mono_linterval_get_intersect_pos (MonoLiveInterval *i1, MonoLiveInter void mono_linterval_split (MonoCompile *cfg, MonoLiveInterval *interval, MonoLiveInterval **i1, MonoLiveInterval **i2, int pos); void mono_liveness_handle_exception_clauses (MonoCompile *cfg); -/* Native Client functions */ -gpointer mono_realloc_native_code(MonoCompile *cfg); +gpointer mono_realloc_native_code (MonoCompile *cfg); extern MonoDebugOptions debug_options; @@ -2536,65 +2184,13 @@ jinfo_get_method (MonoJitInfo *ji) return mono_jit_info_get_method (ji); } -/* AOT */ -void mono_aot_init (void); -void mono_aot_cleanup (void); -gpointer mono_aot_get_method_checked (MonoDomain *domain, - MonoMethod *method, MonoError *error); -gpointer mono_aot_get_method_from_token (MonoDomain *domain, MonoImage *image, guint32 token, MonoError *error); -gboolean mono_aot_is_got_entry (guint8 *code, guint8 *addr); -guint8* mono_aot_get_plt_entry (guint8 *code); -guint32 mono_aot_get_plt_info_offset (mgreg_t *regs, guint8 *code); -gboolean mono_aot_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res); -gboolean mono_aot_get_class_from_name (MonoImage *image, const char *name_space, const char *name, MonoClass **klass); -MonoJitInfo* mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr); -gpointer mono_aot_plt_resolve (gpointer aot_module, guint32 plt_info_offset, guint8 *code, MonoError *error); -void mono_aot_patch_plt_entry (guint8 *code, guint8 *plt_entry, gpointer *got, mgreg_t *regs, guint8 *addr); -gpointer mono_aot_get_method_from_vt_slot (MonoDomain *domain, MonoVTable *vtable, int slot, MonoError *error); -gpointer mono_aot_create_specific_trampoline (MonoImage *image, gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len); -gpointer mono_aot_get_trampoline (const char *name); -gpointer mono_aot_get_trampoline_full (const char *name, MonoTrampInfo **out_tinfo); -gpointer mono_aot_get_unbox_trampoline (MonoMethod *method); -gpointer mono_aot_get_lazy_fetch_trampoline (guint32 slot); -gpointer mono_aot_get_static_rgctx_trampoline (gpointer ctx, gpointer addr); -gpointer mono_aot_get_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count, gpointer fail_tramp); -gpointer mono_aot_get_gsharedvt_arg_trampoline(gpointer arg, gpointer addr); -guint8* mono_aot_get_unwind_info (MonoJitInfo *ji, guint32 *unwind_info_len); -guint32 mono_aot_method_hash (MonoMethod *method); -gboolean mono_aot_can_dedup (MonoMethod *method); -MonoMethod* mono_aot_get_array_helper_from_wrapper (MonoMethod *method); -void mono_aot_set_make_unreadable (gboolean unreadable); -gboolean mono_aot_is_pagefault (void *ptr); -void mono_aot_handle_pagefault (void *ptr); -void mono_aot_register_jit_icall (const char *name, gpointer addr); -guint32 mono_aot_find_method_index (MonoMethod *method); -void mono_aot_init_llvm_method (gpointer aot_module, guint32 method_index); -void mono_aot_init_gshared_method_this (gpointer aot_module, guint32 method_index, MonoObject *this_ins); -void mono_aot_init_gshared_method_mrgctx (gpointer aot_module, guint32 method_index, MonoMethodRuntimeGenericContext *rgctx); -void mono_aot_init_gshared_method_vtable (gpointer aot_module, guint32 method_index, MonoVTable *vtable); - -/* This is an exported function */ -MONO_API void mono_aot_register_module (gpointer *aot_info); - -/* These are used to load the AOT data for aot images compiled with MONO_AOT_FILE_FLAG_SEPARATE_DATA */ -/* - * Return the AOT data for ASSEMBLY. SIZE is the size of the data. OUT_HANDLE should be set to a handle which is later - * passed to the free function. - */ -typedef unsigned char* (*MonoLoadAotDataFunc) (MonoAssembly *assembly, int size, gpointer user_data, void **out_handle); -/* Not yet used */ -typedef void (*MonoFreeAotDataFunc) (MonoAssembly *assembly, int size, gpointer user_data, void *handle); -MONO_API void mono_install_load_aot_data_hook (MonoLoadAotDataFunc load_func, MonoFreeAotDataFunc free_func, gpointer user_data); - void mono_xdebug_init (const char *xdebug_opts); void mono_save_xdebug_info (MonoCompile *cfg); void mono_save_trampoline_xdebug_info (MonoTrampInfo *info); /* This is an exported function */ void mono_xdebug_flush (void); -gboolean mono_method_blittable (MonoMethod *method); gboolean mono_method_same_domain (MonoJitInfo *caller, MonoJitInfo *callee); - void mono_register_opcode_emulation (int opcode, const char* name, const char *sigstr, gpointer func, gboolean no_throw); void mono_draw_graph (MonoCompile *cfg, MonoGraphOptions draw_options); void mono_add_ins_to_end (MonoBasicBlock *bb, MonoInst *inst); @@ -2659,7 +2255,6 @@ gpointer* mini_resolve_imt_method (MonoVTable *vt, gpointer *vtable_slot MonoError *error); MonoFtnDesc *mini_create_llvmonly_ftndesc (MonoDomain *domain, gpointer addr, gpointer arg); -gboolean mono_running_on_valgrind (void); void* mono_global_codeman_reserve (int size); void mono_global_codeman_foreach (MonoCodeManagerFunc func, void *user_data); const char *mono_regname_full (int reg, int bank); @@ -2687,7 +2282,6 @@ MonoMethod* mini_get_memcpy_method (void); MonoMethod* mini_get_memset_method (void); int mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass); - CompRelation mono_opcode_to_cond (int opcode) MONO_LLVM_INTERNAL; CompType mono_opcode_to_type (int opcode, int cmp_opcode); CompRelation mono_negate_cond (CompRelation cond); @@ -2723,7 +2317,6 @@ void mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoCl gboolean mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used); - MonoInst *mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins); void mono_decompose_long_opts (MonoCompile *cfg); void mono_decompose_vtype_opts (MonoCompile *cfg); @@ -2735,27 +2328,24 @@ void mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local void mono_allocate_gsharedvt_vars (MonoCompile *cfg); void mono_if_conversion (MonoCompile *cfg); - - /* Delegates */ gpointer mini_get_delegate_arg (MonoMethod *method, gpointer method_ptr); void mini_init_delegate (MonoDelegate *del); char* mono_get_delegate_virtual_invoke_impl_name (gboolean load_imt_reg, int offset); gpointer mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method); +void mono_codegen (MonoCompile *cfg); +void mono_call_inst_add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, int vreg, int hreg, int bank) MONO_LLVM_INTERNAL; +void mono_call_inst_add_outarg_vt (MonoCompile *cfg, MonoCallInst *call, MonoInst *outarg_vt); + /* methods that must be provided by the arch-specific port */ void mono_arch_init (void); void mono_arch_finish_init (void); void mono_arch_cleanup (void); void mono_arch_cpu_init (void); guint32 mono_arch_cpu_optimizations (guint32 *exclude_mask); -void mono_arch_instrument_mem_needs (MonoMethod *method, int *stack, int *code); void *mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments); void *mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments); -void *mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers); -void mono_codegen (MonoCompile *cfg); -void mono_call_inst_add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, int vreg, int hreg, int bank) MONO_LLVM_INTERNAL; -void mono_call_inst_add_outarg_vt (MonoCompile *cfg, MonoCallInst *call, MonoInst *outarg_vt); const char *mono_arch_regname (int reg); const char *mono_arch_fregname (int reg); void mono_arch_exceptions_init (void); @@ -2770,14 +2360,10 @@ guint8 *mono_arch_create_llvm_native_thunk (MonoDomain *domain, guint8* ad gpointer mono_arch_get_get_tls_tramp (void); GList *mono_arch_get_allocatable_int_vars (MonoCompile *cfg); GList *mono_arch_get_global_int_regs (MonoCompile *cfg); -GList *mono_arch_get_global_fp_regs (MonoCompile *cfg); -GList *mono_arch_get_iregs_clobbered_by_call (MonoCallInst *call); -GList *mono_arch_get_fregs_clobbered_by_call (MonoCallInst *call); guint32 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv); void mono_arch_patch_code (MonoCompile *cfg, MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors, MonoError *error); void mono_arch_patch_code_new (MonoCompile *cfg, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gpointer target); void mono_arch_flush_icache (guint8 *code, gint size); -int mono_arch_max_epilog_size (MonoCompile *cfg); guint8 *mono_arch_emit_prolog (MonoCompile *cfg); void mono_arch_emit_epilog (MonoCompile *cfg); void mono_arch_emit_exceptions (MonoCompile *cfg); @@ -3007,8 +2593,6 @@ mono_perform_abc_removal (MonoCompile *cfg); extern void mono_perform_abc_removal (MonoCompile *cfg); extern void -mono_perform_ssapre (MonoCompile *cfg); -extern void mono_local_cprop (MonoCompile *cfg); extern void mono_local_cprop (MonoCompile *cfg); @@ -3086,7 +2670,6 @@ mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_va gboolean mini_class_is_generic_sharable (MonoClass *klass); - gboolean mini_generic_inst_is_sharable (MonoGenericInst *inst, gboolean allow_type_vars, gboolean allow_partial); @@ -3297,5 +2880,4 @@ gboolean MONO_SIG_HANDLER_SIGNATURE (mono_chain_signal); #endif - #endif /* __MONO_MINI_H__ */ diff --git a/mono/mini/seq-points.c b/mono/mini/seq-points.c index b2e5ba6526d9..4bb98711471f 100644 --- a/mono/mini/seq-points.c +++ b/mono/mini/seq-points.c @@ -10,6 +10,7 @@ */ #include "mini.h" +#include "mini-runtime.h" #include "seq-points.h" static void diff --git a/mono/mini/tasklets.c b/mono/mini/tasklets.c index e767f63125a6..9ade74f6df36 100644 --- a/mono/mini/tasklets.c +++ b/mono/mini/tasklets.c @@ -7,6 +7,7 @@ #include "mono/metadata/exception.h" #include "mono/metadata/gc-internals.h" #include "mini.h" +#include "mini-runtime.h" #if defined(MONO_SUPPORT_TASKLETS) @@ -112,7 +113,7 @@ continuation_store (MonoContinuation *cont, int state, MonoException **e) mono_gc_free_fixed (cont->saved_stack); cont->stack_used_size = num_bytes; cont->stack_alloc_size = num_bytes * 1.1; - cont->saved_stack = mono_gc_alloc_fixed (cont->stack_alloc_size, NULL, MONO_ROOT_SOURCE_THREADING, "saved tasklet stack"); + cont->saved_stack = mono_gc_alloc_fixed (cont->stack_alloc_size, NULL, MONO_ROOT_SOURCE_THREADING, NULL, "Tasklet Saved Stack"); tasklets_unlock (); } memcpy (cont->saved_stack, cont->return_sp, num_bytes); diff --git a/mono/mini/tramp-amd64.c b/mono/mini/tramp-amd64.c index 1de7abd6cff0..a9d913beee4d 100644 --- a/mono/mini/tramp-amd64.c +++ b/mono/mini/tramp-amd64.c @@ -28,6 +28,7 @@ #include "mini.h" #include "mini-amd64.h" +#include "mini-runtime.h" #include "debugger-agent.h" #ifndef DISABLE_INTERPRETER diff --git a/mono/mini/tramp-arm.c b/mono/mini/tramp-arm.c index 688162fe570a..3dd655b8d4c7 100644 --- a/mono/mini/tramp-arm.c +++ b/mono/mini/tramp-arm.c @@ -24,6 +24,7 @@ #include "mini.h" #include "mini-arm.h" +#include "mini-runtime.h" #include "debugger-agent.h" #include "jit-icalls.h" diff --git a/mono/mini/tramp-arm64.c b/mono/mini/tramp-arm64.c index b7cff17e4da8..a46b26ae4316 100644 --- a/mono/mini/tramp-arm64.c +++ b/mono/mini/tramp-arm64.c @@ -16,6 +16,7 @@ */ #include "mini.h" +#include "mini-runtime.h" #include "debugger-agent.h" #include diff --git a/mono/mini/tramp-mips.c b/mono/mini/tramp-mips.c index bb2beef7424c..0930b7324f27 100644 --- a/mono/mini/tramp-mips.c +++ b/mono/mini/tramp-mips.c @@ -25,6 +25,7 @@ #include "mini.h" #include "mini-mips.h" +#include "mini-runtime.h" /* * get_unbox_trampoline: diff --git a/mono/mini/tramp-ppc.c b/mono/mini/tramp-ppc.c index faecb47d4de8..c0c113cd106e 100644 --- a/mono/mini/tramp-ppc.c +++ b/mono/mini/tramp-ppc.c @@ -23,6 +23,7 @@ #include "mini.h" #include "mini-ppc.h" +#include "mini-runtime.h" #if 0 /* Same as mono_create_ftnptr, but doesn't require a domain */ diff --git a/mono/mini/tramp-s390x.c b/mono/mini/tramp-s390x.c index 0588ee7e1603..c15b35860d2d 100644 --- a/mono/mini/tramp-s390x.c +++ b/mono/mini/tramp-s390x.c @@ -46,6 +46,7 @@ #include "mini.h" #include "mini-s390x.h" +#include "mini-runtime.h" #include "support-s390x.h" #include "jit-icalls.h" diff --git a/mono/mini/tramp-x86.c b/mono/mini/tramp-x86.c index 1a97578c465a..111f6f580321 100644 --- a/mono/mini/tramp-x86.c +++ b/mono/mini/tramp-x86.c @@ -24,6 +24,7 @@ #include "mini.h" #include "mini-x86.h" +#include "mini-runtime.h" #include "debugger-agent.h" #include "jit-icalls.h" diff --git a/mono/mini/wasm_m2n_invoke.g.h b/mono/mini/wasm_m2n_invoke.g.h new file mode 100644 index 000000000000..fc48f313f8c9 --- /dev/null +++ b/mono/mini/wasm_m2n_invoke.g.h @@ -0,0 +1,501 @@ +/* + * DON'T EDIT THIS FILE + * This file was generated by m2n-gen.cs - use it instead. + */ +static void +wasm_invoke_v (void *target_func, InterpMethodArguments *margs) +{ + void (*func)(void) = target_func; + + func (); + +} + +static void +wasm_invoke_vi (void *target_func, InterpMethodArguments *margs) +{ + void (*func)(int arg_0) = target_func; + + func ((int)margs->iargs [0]); + +} + +static void +wasm_invoke_vii (void *target_func, InterpMethodArguments *margs) +{ + void (*func)(int arg_0, int arg_1) = target_func; + + func ((int)margs->iargs [0], (int)margs->iargs [1]); + +} + +static void +wasm_invoke_viii (void *target_func, InterpMethodArguments *margs) +{ + void (*func)(int arg_0, int arg_1, int arg_2) = target_func; + + func ((int)margs->iargs [0], (int)margs->iargs [1], (int)margs->iargs [2]); + +} + +static void +wasm_invoke_viiii (void *target_func, InterpMethodArguments *margs) +{ + void (*func)(int arg_0, int arg_1, int arg_2, int arg_3) = target_func; + + func ((int)margs->iargs [0], (int)margs->iargs [1], (int)margs->iargs [2], (int)margs->iargs [3]); + +} + +static void +wasm_invoke_viiiii (void *target_func, InterpMethodArguments *margs) +{ + void (*func)(int arg_0, int arg_1, int arg_2, int arg_3, int arg_4) = target_func; + + func ((int)margs->iargs [0], (int)margs->iargs [1], (int)margs->iargs [2], (int)margs->iargs [3], (int)margs->iargs [4]); + +} + +static void +wasm_invoke_viiiiii (void *target_func, InterpMethodArguments *margs) +{ + void (*func)(int arg_0, int arg_1, int arg_2, int arg_3, int arg_4, int arg_5) = target_func; + + func ((int)margs->iargs [0], (int)margs->iargs [1], (int)margs->iargs [2], (int)margs->iargs [3], (int)margs->iargs [4], (int)margs->iargs [5]); + +} + +static void +wasm_invoke_i (void *target_func, InterpMethodArguments *margs) +{ + int (*func)(void) = target_func; + + int res = func (); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_ii (void *target_func, InterpMethodArguments *margs) +{ + int (*func)(int arg_0) = target_func; + + int res = func ((int)margs->iargs [0]); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_iii (void *target_func, InterpMethodArguments *margs) +{ + int (*func)(int arg_0, int arg_1) = target_func; + + int res = func ((int)margs->iargs [0], (int)margs->iargs [1]); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_iiii (void *target_func, InterpMethodArguments *margs) +{ + int (*func)(int arg_0, int arg_1, int arg_2) = target_func; + + int res = func ((int)margs->iargs [0], (int)margs->iargs [1], (int)margs->iargs [2]); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_iiiii (void *target_func, InterpMethodArguments *margs) +{ + int (*func)(int arg_0, int arg_1, int arg_2, int arg_3) = target_func; + + int res = func ((int)margs->iargs [0], (int)margs->iargs [1], (int)margs->iargs [2], (int)margs->iargs [3]); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_iiiiii (void *target_func, InterpMethodArguments *margs) +{ + int (*func)(int arg_0, int arg_1, int arg_2, int arg_3, int arg_4) = target_func; + + int res = func ((int)margs->iargs [0], (int)margs->iargs [1], (int)margs->iargs [2], (int)margs->iargs [3], (int)margs->iargs [4]); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_iiiiiii (void *target_func, InterpMethodArguments *margs) +{ + int (*func)(int arg_0, int arg_1, int arg_2, int arg_3, int arg_4, int arg_5) = target_func; + + int res = func ((int)margs->iargs [0], (int)margs->iargs [1], (int)margs->iargs [2], (int)margs->iargs [3], (int)margs->iargs [4], (int)margs->iargs [5]); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_iiiiiiiii (void *target_func, InterpMethodArguments *margs) +{ + int (*func)(int arg_0, int arg_1, int arg_2, int arg_3, int arg_4, int arg_5, int arg_6, int arg_7) = target_func; + + int res = func ((int)margs->iargs [0], (int)margs->iargs [1], (int)margs->iargs [2], (int)margs->iargs [3], (int)margs->iargs [4], (int)margs->iargs [5], (int)margs->iargs [6], (int)margs->iargs [7]); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_l (void *target_func, InterpMethodArguments *margs) +{ + gint64 (*func)(void) = target_func; + + gint64 res = func (); + *(gint64*)margs->retval = res; + +} + +static void +wasm_invoke_ll (void *target_func, InterpMethodArguments *margs) +{ + gint64 (*func)(gint64 arg_0) = target_func; + + gint64 res = func (get_long_arg (margs, 0)); + *(gint64*)margs->retval = res; + +} + +static void +wasm_invoke_li (void *target_func, InterpMethodArguments *margs) +{ + gint64 (*func)(int arg_0) = target_func; + + gint64 res = func ((int)margs->iargs [0]); + *(gint64*)margs->retval = res; + +} + +static void +wasm_invoke_lil (void *target_func, InterpMethodArguments *margs) +{ + gint64 (*func)(int arg_0, gint64 arg_1) = target_func; + + gint64 res = func ((int)margs->iargs [0], get_long_arg (margs, 1)); + *(gint64*)margs->retval = res; + +} + +static void +wasm_invoke_lilii (void *target_func, InterpMethodArguments *margs) +{ + gint64 (*func)(int arg_0, gint64 arg_1, int arg_2, int arg_3) = target_func; + + gint64 res = func ((int)margs->iargs [0], get_long_arg (margs, 1), (int)margs->iargs [3], (int)margs->iargs [4]); + *(gint64*)margs->retval = res; + +} + +static void +wasm_invoke_dd (void *target_func, InterpMethodArguments *margs) +{ + double (*func)(double arg_0) = target_func; + + double res = func (margs->fargs [FIDX (0)]); + *(double*)margs->retval = res; + +} + +static void +wasm_invoke_ddd (void *target_func, InterpMethodArguments *margs) +{ + double (*func)(double arg_0, double arg_1) = target_func; + + double res = func (margs->fargs [FIDX (0)], margs->fargs [FIDX (1)]); + *(double*)margs->retval = res; + +} + +static void +wasm_invoke_vif (void *target_func, InterpMethodArguments *margs) +{ + void (*func)(int arg_0, float arg_1) = target_func; + + func ((int)margs->iargs [0], *(float*)&margs->fargs [FIDX (0)]); + +} + +static void +wasm_invoke_viff (void *target_func, InterpMethodArguments *margs) +{ + void (*func)(int arg_0, float arg_1, float arg_2) = target_func; + + func ((int)margs->iargs [0], *(float*)&margs->fargs [FIDX (0)], *(float*)&margs->fargs [FIDX (1)]); + +} + +static void +wasm_invoke_viffff (void *target_func, InterpMethodArguments *margs) +{ + void (*func)(int arg_0, float arg_1, float arg_2, float arg_3, float arg_4) = target_func; + + func ((int)margs->iargs [0], *(float*)&margs->fargs [FIDX (0)], *(float*)&margs->fargs [FIDX (1)], *(float*)&margs->fargs [FIDX (2)], *(float*)&margs->fargs [FIDX (3)]); + +} + +static void +wasm_invoke_vifffffi (void *target_func, InterpMethodArguments *margs) +{ + void (*func)(int arg_0, float arg_1, float arg_2, float arg_3, float arg_4, float arg_5, int arg_6) = target_func; + + func ((int)margs->iargs [0], *(float*)&margs->fargs [FIDX (0)], *(float*)&margs->fargs [FIDX (1)], *(float*)&margs->fargs [FIDX (2)], *(float*)&margs->fargs [FIDX (3)], *(float*)&margs->fargs [FIDX (4)], (int)margs->iargs [1]); + +} + +static void +wasm_invoke_ff (void *target_func, InterpMethodArguments *margs) +{ + float (*func)(float arg_0) = target_func; + + float res = func (*(float*)&margs->fargs [FIDX (0)]); + *(float*)margs->retval = res; + +} + +static void +wasm_invoke_di (void *target_func, InterpMethodArguments *margs) +{ + double (*func)(int arg_0) = target_func; + + double res = func ((int)margs->iargs [0]); + *(double*)margs->retval = res; + +} + +static void +wasm_invoke_fi (void *target_func, InterpMethodArguments *margs) +{ + float (*func)(int arg_0) = target_func; + + float res = func ((int)margs->iargs [0]); + *(float*)margs->retval = res; + +} + +static void +wasm_invoke_iil (void *target_func, InterpMethodArguments *margs) +{ + int (*func)(int arg_0, gint64 arg_1) = target_func; + + int res = func ((int)margs->iargs [0], get_long_arg (margs, 1)); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_iili (void *target_func, InterpMethodArguments *margs) +{ + int (*func)(int arg_0, gint64 arg_1, int arg_2) = target_func; + + int res = func ((int)margs->iargs [0], get_long_arg (margs, 1), (int)margs->iargs [3]); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_iillli (void *target_func, InterpMethodArguments *margs) +{ + int (*func)(int arg_0, gint64 arg_1, gint64 arg_2, gint64 arg_3, int arg_4) = target_func; + + int res = func ((int)margs->iargs [0], get_long_arg (margs, 1), get_long_arg (margs, 3), get_long_arg (margs, 5), (int)margs->iargs [7]); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_lii (void *target_func, InterpMethodArguments *margs) +{ + gint64 (*func)(int arg_0, int arg_1) = target_func; + + gint64 res = func ((int)margs->iargs [0], (int)margs->iargs [1]); + *(gint64*)margs->retval = res; + +} + +static void +wasm_invoke_vid (void *target_func, InterpMethodArguments *margs) +{ + void (*func)(int arg_0, double arg_1) = target_func; + + func ((int)margs->iargs [0], margs->fargs [FIDX (0)]); + +} + +static void +wasm_invoke_viiiiiii (void *target_func, InterpMethodArguments *margs) +{ + void (*func)(int arg_0, int arg_1, int arg_2, int arg_3, int arg_4, int arg_5, int arg_6) = target_func; + + func ((int)margs->iargs [0], (int)margs->iargs [1], (int)margs->iargs [2], (int)margs->iargs [3], (int)margs->iargs [4], (int)margs->iargs [5], (int)margs->iargs [6]); + +} + +static void +wasm_invoke_villi (void *target_func, InterpMethodArguments *margs) +{ + void (*func)(int arg_0, gint64 arg_1, gint64 arg_2, int arg_3) = target_func; + + func ((int)margs->iargs [0], get_long_arg (margs, 1), get_long_arg (margs, 3), (int)margs->iargs [5]); + +} + +static void +wasm_invoke_did (void *target_func, InterpMethodArguments *margs) +{ + double (*func)(int arg_0, double arg_1) = target_func; + + double res = func ((int)margs->iargs [0], margs->fargs [FIDX (0)]); + *(double*)margs->retval = res; + +} + +static void +wasm_invoke_didd (void *target_func, InterpMethodArguments *margs) +{ + double (*func)(int arg_0, double arg_1, double arg_2) = target_func; + + double res = func ((int)margs->iargs [0], margs->fargs [FIDX (0)], margs->fargs [FIDX (1)]); + *(double*)margs->retval = res; + +} + +static void +wasm_invoke_fif (void *target_func, InterpMethodArguments *margs) +{ + float (*func)(int arg_0, float arg_1) = target_func; + + float res = func ((int)margs->iargs [0], *(float*)&margs->fargs [FIDX (0)]); + *(float*)margs->retval = res; + +} + +static void +wasm_invoke_fiff (void *target_func, InterpMethodArguments *margs) +{ + float (*func)(int arg_0, float arg_1, float arg_2) = target_func; + + float res = func ((int)margs->iargs [0], *(float*)&margs->fargs [FIDX (0)], *(float*)&margs->fargs [FIDX (1)]); + *(float*)margs->retval = res; + +} + +static void +wasm_invoke_lill (void *target_func, InterpMethodArguments *margs) +{ + gint64 (*func)(int arg_0, gint64 arg_1, gint64 arg_2) = target_func; + + gint64 res = func ((int)margs->iargs [0], get_long_arg (margs, 1), get_long_arg (margs, 3)); + *(gint64*)margs->retval = res; + +} + +static void +wasm_invoke_vil (void *target_func, InterpMethodArguments *margs) +{ + void (*func)(int arg_0, gint64 arg_1) = target_func; + + func ((int)margs->iargs [0], get_long_arg (margs, 1)); + +} + +static void +icall_trampoline_dispatch (const char *cookie, void *target_func, InterpMethodArguments *margs) +{ + if (!strcmp ("V", cookie)) + wasm_invoke_v (target_func, margs); + else if (!strcmp ("VI", cookie)) + wasm_invoke_vi (target_func, margs); + else if (!strcmp ("VII", cookie)) + wasm_invoke_vii (target_func, margs); + else if (!strcmp ("VIII", cookie)) + wasm_invoke_viii (target_func, margs); + else if (!strcmp ("VIIII", cookie)) + wasm_invoke_viiii (target_func, margs); + else if (!strcmp ("VIIIII", cookie)) + wasm_invoke_viiiii (target_func, margs); + else if (!strcmp ("VIIIIII", cookie)) + wasm_invoke_viiiiii (target_func, margs); + else if (!strcmp ("I", cookie)) + wasm_invoke_i (target_func, margs); + else if (!strcmp ("II", cookie)) + wasm_invoke_ii (target_func, margs); + else if (!strcmp ("III", cookie)) + wasm_invoke_iii (target_func, margs); + else if (!strcmp ("IIII", cookie)) + wasm_invoke_iiii (target_func, margs); + else if (!strcmp ("IIIII", cookie)) + wasm_invoke_iiiii (target_func, margs); + else if (!strcmp ("IIIIII", cookie)) + wasm_invoke_iiiiii (target_func, margs); + else if (!strcmp ("IIIIIII", cookie)) + wasm_invoke_iiiiiii (target_func, margs); + else if (!strcmp ("IIIIIIIII", cookie)) + wasm_invoke_iiiiiiiii (target_func, margs); + else if (!strcmp ("L", cookie)) + wasm_invoke_l (target_func, margs); + else if (!strcmp ("LL", cookie)) + wasm_invoke_ll (target_func, margs); + else if (!strcmp ("LI", cookie)) + wasm_invoke_li (target_func, margs); + else if (!strcmp ("LIL", cookie)) + wasm_invoke_lil (target_func, margs); + else if (!strcmp ("LILII", cookie)) + wasm_invoke_lilii (target_func, margs); + else if (!strcmp ("DD", cookie)) + wasm_invoke_dd (target_func, margs); + else if (!strcmp ("DDD", cookie)) + wasm_invoke_ddd (target_func, margs); + else if (!strcmp ("VIF", cookie)) + wasm_invoke_vif (target_func, margs); + else if (!strcmp ("VIFF", cookie)) + wasm_invoke_viff (target_func, margs); + else if (!strcmp ("VIFFFF", cookie)) + wasm_invoke_viffff (target_func, margs); + else if (!strcmp ("VIFFFFFI", cookie)) + wasm_invoke_vifffffi (target_func, margs); + else if (!strcmp ("FF", cookie)) + wasm_invoke_ff (target_func, margs); + else if (!strcmp ("DI", cookie)) + wasm_invoke_di (target_func, margs); + else if (!strcmp ("FI", cookie)) + wasm_invoke_fi (target_func, margs); + else if (!strcmp ("IIL", cookie)) + wasm_invoke_iil (target_func, margs); + else if (!strcmp ("IILI", cookie)) + wasm_invoke_iili (target_func, margs); + else if (!strcmp ("IILLLI", cookie)) + wasm_invoke_iillli (target_func, margs); + else if (!strcmp ("LII", cookie)) + wasm_invoke_lii (target_func, margs); + else if (!strcmp ("VID", cookie)) + wasm_invoke_vid (target_func, margs); + else if (!strcmp ("VIIIIIII", cookie)) + wasm_invoke_viiiiiii (target_func, margs); + else if (!strcmp ("VILLI", cookie)) + wasm_invoke_villi (target_func, margs); + else if (!strcmp ("DID", cookie)) + wasm_invoke_did (target_func, margs); + else if (!strcmp ("DIDD", cookie)) + wasm_invoke_didd (target_func, margs); + else if (!strcmp ("FIF", cookie)) + wasm_invoke_fif (target_func, margs); + else if (!strcmp ("FIFF", cookie)) + wasm_invoke_fiff (target_func, margs); + else if (!strcmp ("LILL", cookie)) + wasm_invoke_lill (target_func, margs); + else if (!strcmp ("VIL", cookie)) + wasm_invoke_vil (target_func, margs); + else { + printf ("CANNOT HANDLE COOKIE %s\n", cookie); + g_assert (0); + } +} diff --git a/mono/profiler/aot.c b/mono/profiler/aot.c index a6f044f6feca..fd22478353df 100644 --- a/mono/profiler/aot.c +++ b/mono/profiler/aot.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -166,6 +167,11 @@ mono_profiler_init_aot (const char *desc); void mono_profiler_init_aot (const char *desc) { + if (mono_jit_aot_compiling ()) { + mono_profiler_printf_err ("The AOT profiler is not meant to be run during AOT compilation."); + exit (1); + } + parse_args (desc [strlen ("aot")] == ':' ? desc + strlen ("aot") + 1 : ""); if (!aot_profiler.outfile_name) diff --git a/mono/profiler/coverage.c b/mono/profiler/coverage.c index 21a3b8cbda48..53dcc0cba2a2 100644 --- a/mono/profiler/coverage.c +++ b/mono/profiler/coverage.c @@ -75,6 +75,8 @@ #include #include +#include + #include #include #include @@ -723,7 +725,7 @@ unref_coverage_assemblies (gpointer key, gpointer value, gpointer userdata) } static void -log_shutdown (MonoProfiler *prof) +cov_shutdown (MonoProfiler *prof) { g_assert (prof == &coverage_profiler); @@ -888,6 +890,11 @@ mono_profiler_init_coverage (const char *desc); void mono_profiler_init_coverage (const char *desc) { + if (mono_jit_aot_compiling ()) { + mono_profiler_printf_err ("The coverage profiler does not currently support instrumenting AOT code."); + exit (1); + } + GPtrArray *filters = NULL; parse_args (desc [strlen("coverage")] == ':' ? desc + strlen ("coverage") + 1 : ""); @@ -934,13 +941,7 @@ mono_profiler_init_coverage (const char *desc) MonoProfilerHandle handle = coverage_profiler.handle = mono_profiler_create (&coverage_profiler); - /* - * Required callbacks. These are either necessary for the profiler itself - * to function, or provide metadata that's needed if other events (e.g. - * allocations, exceptions) are dynamically enabled/disabled. - */ - - mono_profiler_set_runtime_shutdown_end_callback (handle, log_shutdown); + mono_profiler_set_runtime_shutdown_end_callback (handle, cov_shutdown); mono_profiler_set_runtime_initialized_callback (handle, runtime_initialized); mono_profiler_enable_coverage (); diff --git a/mono/profiler/log-args.c b/mono/profiler/log-args.c index 0e934f8526b0..0c8bd040a386 100644 --- a/mono/profiler/log-args.c +++ b/mono/profiler/log-args.c @@ -67,6 +67,7 @@ parse_arg (const char *arg, ProfilerConfig *config) first_processed = TRUE; if (match_option (arg, "nodefaults", NULL)) { //enables new style of default events, IE, nothing. + return; } else { config->enable_mask = PROFLOG_EXCEPTION_EVENTS | PROFLOG_COUNTER_EVENTS; config->always_do_root_report = TRUE; @@ -76,6 +77,8 @@ parse_arg (const char *arg, ProfilerConfig *config) if (match_option (arg, "help", NULL)) { usage (); + } else if (match_option (arg, "nodefaults", NULL)) { + mono_profiler_printf_err ("nodefaults can only be used as the first argument"); } else if (match_option (arg, "report", NULL)) { config->do_report = TRUE; } else if (match_option (arg, "debug", NULL)) { diff --git a/mono/profiler/log.c b/mono/profiler/log.c index 8a96303d752a..e0c19bed121e 100644 --- a/mono/profiler/log.c +++ b/mono/profiler/log.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -84,7 +85,7 @@ static gint32 sync_points_ctr, assembly_loads_ctr, assembly_unloads_ctr, class_loads_ctr, - class_unloads_ctr, + vtable_loads_ctr, method_entries_ctr, method_exits_ctr, method_exception_exits_ctr, @@ -122,6 +123,7 @@ struct _LogBuffer { uint64_t time_base; uint64_t last_time; + gboolean has_ptr_base; uintptr_t ptr_base; uintptr_t method_base; uintptr_t last_method; @@ -166,6 +168,12 @@ typedef struct { int small_id; } MonoProfilerThread; +// Default value in `profiler_tls` for new threads. +#define MONO_PROFILER_THREAD_ZERO ((MonoProfilerThread *) NULL) + +// This is written to `profiler_tls` to indicate that a thread has stopped. +#define MONO_PROFILER_THREAD_DEAD ((MonoProfilerThread *) -1) + // Do not use these TLS macros directly unless you know what you're doing. #ifdef HOST_WIN32 @@ -234,19 +242,19 @@ process_id (void) #define ENTER_LOG(COUNTER, BUFFER, SIZE) \ do { \ MonoProfilerThread *thread__ = get_thread (); \ - if (thread__->attached) \ - buffer_lock (); \ g_assert (!thread__->busy && "Why are we trying to write a new event while already writing one?"); \ thread__->busy = TRUE; \ mono_atomic_inc_i32 ((COUNTER)); \ + if (thread__->attached) \ + buffer_lock (); \ LogBuffer *BUFFER = ensure_logbuf_unsafe (thread__, (SIZE)) #define EXIT_LOG_EXPLICIT(SEND) \ - thread__->busy = FALSE; \ if ((SEND)) \ send_log_unsafe (TRUE); \ if (thread__->attached) \ buffer_unlock (); \ + thread__->busy = FALSE; \ } while (0) // Pass these to EXIT_LOG_EXPLICIT () for easier reading. @@ -512,6 +520,8 @@ init_thread (gboolean add_to_lls) { MonoProfilerThread *thread = PROF_TLS_GET (); + g_assert (thread != MONO_PROFILER_THREAD_DEAD && "Why are we trying to resurrect a stopped thread?"); + /* * Sometimes we may try to initialize a thread twice. One example is the * main thread: We initialize it when setting up the profiler, but we will @@ -523,14 +533,14 @@ init_thread (gboolean add_to_lls) * These cases are harmless anyhow. Just return if we've already done the * initialization work. */ - if (thread) + if (thread != MONO_PROFILER_THREAD_ZERO) return thread; thread = g_malloc (sizeof (MonoProfilerThread)); thread->node.key = thread_id (); thread->attached = add_to_lls; thread->call_depth = 0; - thread->busy = 0; + thread->busy = FALSE; thread->ended = FALSE; init_buffer_state (thread); @@ -559,7 +569,7 @@ deinit_thread (MonoProfilerThread *thread) g_assert (!thread->attached && "Why are we manually freeing an attached thread?"); g_free (thread); - PROF_TLS_SET (NULL); + PROF_TLS_SET (MONO_PROFILER_THREAD_DEAD); } static MonoProfilerThread * @@ -665,7 +675,7 @@ buffer_unlock (void) gint32 state = mono_atomic_load_i32 (&log_profiler.buffer_lock_state); // See the comment in buffer_lock (). - if (state == PROF_TLS_GET ()->small_id << 16) + if (state == get_thread ()->small_id << 16) return; g_assert (state && "Why are we decrementing a zero reader count?"); @@ -702,7 +712,7 @@ buffer_unlock_excl (void) gint32 excl = state >> 16; g_assert (excl && "Why is the exclusive lock not held?"); - g_assert (excl == PROF_TLS_GET ()->small_id && "Why does another thread hold the exclusive lock?"); + g_assert (excl == get_thread ()->small_id && "Why does another thread hold the exclusive lock?"); g_assert (!(state & 0xFFFF) && "Why are there readers when the exclusive lock is held?"); mono_atomic_store_i32 (&log_profiler.buffer_lock_state, 0); @@ -820,8 +830,10 @@ emit_uvalue (LogBuffer *logbuffer, uint64_t value) static void emit_ptr (LogBuffer *logbuffer, const void *ptr) { - if (!logbuffer->ptr_base) + if (!logbuffer->has_ptr_base) { logbuffer->ptr_base = (uintptr_t) ptr; + logbuffer->has_ptr_base = TRUE; + } emit_svalue (logbuffer, (intptr_t) ptr - logbuffer->ptr_base); @@ -1108,7 +1120,7 @@ dump_buffer_threadless (LogBuffer *buf) static void send_log_unsafe (gboolean if_needed) { - MonoProfilerThread *thread = PROF_TLS_GET (); + MonoProfilerThread *thread = get_thread (); if (!if_needed || (if_needed && thread->buffer->next)) { if (!thread->attached) @@ -1124,7 +1136,7 @@ send_log_unsafe (gboolean if_needed) static void sync_point_flush (void) { - g_assert (mono_atomic_load_i32 (&log_profiler.buffer_lock_state) == PROF_TLS_GET ()->small_id << 16 && "Why don't we hold the exclusive lock?"); + g_assert (mono_atomic_load_i32 (&log_profiler.buffer_lock_state) == get_thread ()->small_id << 16 && "Why don't we hold the exclusive lock?"); MONO_LLS_FOREACH_SAFE (&log_profiler.profiler_thread_list, MonoProfilerThread, thread) { g_assert (thread->attached && "Why is a thread in the LLS not attached?"); @@ -1138,7 +1150,7 @@ sync_point_flush (void) static void sync_point_mark (MonoProfilerSyncPointType type) { - g_assert (mono_atomic_load_i32 (&log_profiler.buffer_lock_state) == PROF_TLS_GET ()->small_id << 16 && "Why don't we hold the exclusive lock?"); + g_assert (mono_atomic_load_i32 (&log_profiler.buffer_lock_state) == get_thread ()->small_id << 16 && "Why don't we hold the exclusive lock?"); ENTER_LOG (&sync_points_ctr, logbuffer, EVENT_SIZE /* event */ + @@ -1171,7 +1183,7 @@ gc_reference (MonoObject *obj, MonoClass *klass, uintptr_t size, uintptr_t num, ENTER_LOG (&heap_objects_ctr, logbuffer, EVENT_SIZE /* event */ + LEB128_SIZE /* obj */ + - LEB128_SIZE /* klass */ + + LEB128_SIZE /* vtable */ + LEB128_SIZE /* size */ + LEB128_SIZE /* num */ + num * ( @@ -1182,7 +1194,7 @@ gc_reference (MonoObject *obj, MonoClass *klass, uintptr_t size, uintptr_t num, emit_event (logbuffer, TYPE_HEAP_OBJECT | TYPE_HEAP); emit_obj (logbuffer, obj); - emit_ptr (logbuffer, klass); + emit_ptr (logbuffer, mono_object_get_vtable (obj)); emit_value (logbuffer, size); emit_value (logbuffer, num); @@ -1200,35 +1212,89 @@ gc_reference (MonoObject *obj, MonoClass *klass, uintptr_t size, uintptr_t num, } static void -gc_roots (MonoProfiler *prof, MonoObject *const *objects, const MonoProfilerGCRootType *root_types, const uintptr_t *extra_info, uint64_t num) +gc_roots (MonoProfiler *prof, uint64_t num, const mono_byte *const *addresses, MonoObject *const *objects) { ENTER_LOG (&heap_roots_ctr, logbuffer, EVENT_SIZE /* event */ + LEB128_SIZE /* num */ + - LEB128_SIZE /* collections */ + num * ( - LEB128_SIZE /* object */ + - LEB128_SIZE /* root type */ + - LEB128_SIZE /* extra info */ + LEB128_SIZE /* address */ + + LEB128_SIZE /* object */ ) ); emit_event (logbuffer, TYPE_HEAP_ROOT | TYPE_HEAP); emit_value (logbuffer, num); - emit_value (logbuffer, mono_gc_collection_count (mono_gc_max_generation ())); for (int i = 0; i < num; ++i) { + emit_ptr (logbuffer, addresses [i]); emit_obj (logbuffer, objects [i]); - emit_value (logbuffer, root_types [i]); - emit_value (logbuffer, extra_info [i]); } EXIT_LOG; } +static void +gc_root_register (MonoProfiler *prof, const mono_byte *start, size_t size, MonoGCRootSource source, const void *key, const char *name) +{ + // We don't write raw domain/context pointers in metadata events. + switch (source) { + case MONO_ROOT_SOURCE_DOMAIN: + if (key) + key = (void *)(uintptr_t) mono_domain_get_id ((MonoDomain *) key); + break; + case MONO_ROOT_SOURCE_CONTEXT_STATIC: + key = (void *)(uintptr_t) mono_context_get_id ((MonoAppContext *) key); + break; + default: + break; + } + + int name_len = name ? strlen (name) + 1 : 0; + + ENTER_LOG (&heap_roots_ctr, logbuffer, + EVENT_SIZE /* event */ + + LEB128_SIZE /* start */ + + LEB128_SIZE /* size */ + + BYTE_SIZE /* source */ + + LEB128_SIZE /* key */ + + name_len /* name */ + ); + + emit_event (logbuffer, TYPE_HEAP_ROOT_REGISTER | TYPE_HEAP); + emit_ptr (logbuffer, start); + emit_uvalue (logbuffer, size); + emit_byte (logbuffer, source); + emit_ptr (logbuffer, key); + emit_string (logbuffer, name, name_len); + + EXIT_LOG; +} + +static void +gc_root_deregister (MonoProfiler *prof, const mono_byte *start) +{ + ENTER_LOG (&heap_roots_ctr, logbuffer, + EVENT_SIZE /* event */ + + LEB128_SIZE /* start */ + ); + + emit_event (logbuffer, TYPE_HEAP_ROOT_UNREGISTER | TYPE_HEAP); + emit_ptr (logbuffer, start); + + EXIT_LOG; +} + +static void +trigger_heapshot (void) +{ + // Rely on the finalization callback triggering a GC. + mono_atomic_store_i32 (&log_profiler.heapshot_requested, 1); + mono_gc_finalize_notify (); +} static void -trigger_on_demand_heapshot (void) +process_heapshot (void) { if (mono_atomic_load_i32 (&log_profiler.heapshot_requested)) mono_gc_collect (mono_gc_max_generation ()); @@ -1263,7 +1329,7 @@ gc_event (MonoProfiler *profiler, MonoProfilerGCEvent ev, uint32_t generation) log_profiler.do_heap_walk = generation == mono_gc_max_generation (); break; case MONO_PROFILER_HEAPSHOT_ON_DEMAND: - log_profiler.do_heap_walk = mono_atomic_load_i32 (&log_profiler.heapshot_requested); + // Handled below. break; case MONO_PROFILER_HEAPSHOT_X_GC: log_profiler.do_heap_walk = !(log_profiler.gc_count % log_config.hs_freq_gc); @@ -1276,11 +1342,10 @@ gc_event (MonoProfiler *profiler, MonoProfilerGCEvent ev, uint32_t generation) } /* - * heapshot_requested is set either because on-demand heapshot is - * enabled and a heapshot was triggered, or because we're doing a - * shutdown heapshot. In the latter case, we won't check it in the - * switch above, so check it here and override any decision we made - * above. + * heapshot_requested is set either because a heapshot was triggered + * manually (through the API or command server) or because we're doing + * a shutdown heapshot. Either way, a manually triggered heapshot + * overrides any decision we made in the switch above. */ if (mono_atomic_load_i32 (&log_profiler.heapshot_requested)) log_profiler.do_heap_walk = TRUE; @@ -1436,7 +1501,7 @@ gc_alloc (MonoProfiler *prof, MonoObject *obj) ENTER_LOG (&gc_allocs_ctr, logbuffer, EVENT_SIZE /* event */ + - LEB128_SIZE /* klass */ + + LEB128_SIZE /* vtable */ + LEB128_SIZE /* obj */ + LEB128_SIZE /* size */ + (do_bt ? ( @@ -1448,7 +1513,7 @@ gc_alloc (MonoProfiler *prof, MonoObject *obj) ); emit_event (logbuffer, do_bt | TYPE_ALLOC); - emit_ptr (logbuffer, mono_object_get_class (obj)); + emit_ptr (logbuffer, mono_object_get_vtable (obj)); emit_obj (logbuffer, obj); emit_value (logbuffer, len); @@ -1550,7 +1615,8 @@ finalize_begin (MonoProfiler *prof) static void finalize_end (MonoProfiler *prof) { - trigger_on_demand_heapshot (); + process_heapshot (); + if (ENABLED (PROFLOG_GC_FINALIZATION_EVENTS)) { ENTER_LOG (&finalize_ends_ctr, buf, EVENT_SIZE /* event */ @@ -1760,6 +1826,30 @@ class_loaded (MonoProfiler *prof, MonoClass *klass) g_free (name); } +static void +vtable_loaded (MonoProfiler *prof, MonoVTable *vtable) +{ + MonoClass *klass = mono_vtable_class (vtable); + MonoDomain *domain = mono_vtable_domain (vtable); + uint32_t domain_id = domain ? mono_domain_get_id (domain) : 0; + + ENTER_LOG (&vtable_loads_ctr, logbuffer, + EVENT_SIZE /* event */ + + BYTE_SIZE /* type */ + + LEB128_SIZE /* vtable */ + + LEB128_SIZE /* domain id */ + + LEB128_SIZE /* klass */ + ); + + emit_event (logbuffer, TYPE_END_LOAD | TYPE_METADATA); + emit_byte (logbuffer, TYPE_VTABLE); + emit_ptr (logbuffer, vtable); + emit_ptr (logbuffer, (void *)(uintptr_t) domain_id); + emit_ptr (logbuffer, klass); + + EXIT_LOG; +} + static void method_enter (MonoProfiler *prof, MonoMethod *method, MonoProfilerCallContext *ctx) { @@ -2008,7 +2098,7 @@ thread_end (MonoProfiler *prof, uintptr_t tid) thread->ended = TRUE; remove_thread (thread); - PROF_TLS_SET (NULL); + PROF_TLS_SET (MONO_PROFILER_THREAD_DEAD); } static void @@ -2641,9 +2731,9 @@ counters_emit (void) name = mono_counter_get_name (agent->counter); emit_value (logbuffer, mono_counter_get_section (agent->counter)); emit_string (logbuffer, name, strlen (name) + 1); - emit_byte (logbuffer, mono_counter_get_type (agent->counter)); - emit_byte (logbuffer, mono_counter_get_unit (agent->counter)); - emit_byte (logbuffer, mono_counter_get_variance (agent->counter)); + emit_value (logbuffer, mono_counter_get_type (agent->counter)); + emit_value (logbuffer, mono_counter_get_unit (agent->counter)); + emit_value (logbuffer, mono_counter_get_variance (agent->counter)); emit_value (logbuffer, agent->index); agent->emitted = TRUE; @@ -2730,7 +2820,7 @@ counters_sample (uint64_t timestamp) } emit_uvalue (logbuffer, agent->index); - emit_byte (logbuffer, type); + emit_value (logbuffer, type); switch (type) { case MONO_COUNTER_INT: #if SIZEOF_VOID_P == 4 @@ -3800,11 +3890,8 @@ helper_thread (void *arg) buf [len] = 0; - if (log_config.hs_mode == MONO_PROFILER_HEAPSHOT_ON_DEMAND && !strcmp (buf, "heapshot\n")) { - // Rely on the finalization callback triggering a GC. - mono_atomic_store_i32 (&log_profiler.heapshot_requested, 1); - mono_gc_finalize_notify (); - } + if (!strcmp (buf, "heapshot\n")) + trigger_heapshot (); } if (FD_ISSET (log_profiler.server_socket, &rfds)) { @@ -3965,7 +4052,7 @@ handle_writer_queue_entry (void) g_ptr_array_free (entry->methods, TRUE); if (wrote_methods) { - MonoProfilerThread *thread = PROF_TLS_GET (); + MonoProfilerThread *thread = get_thread (); dump_buffer_threadless (thread->buffer); init_buffer_state (thread); @@ -4190,6 +4277,12 @@ proflog_icall_SetHeapshotCollectionsFrequency (gint32 value) log_config.hs_freq_gc = value; } +ICALL_EXPORT void +proflog_icall_TriggerHeapshot (void) +{ + trigger_heapshot (); +} + ICALL_EXPORT gint32 proflog_icall_GetCallDepth (void) { @@ -4483,7 +4576,7 @@ runtime_initialized (MonoProfiler *profiler) register_counter ("Event: Assembly loads", &assembly_loads_ctr); register_counter ("Event: Assembly unloads", &assembly_unloads_ctr); register_counter ("Event: Class loads", &class_loads_ctr); - register_counter ("Event: Class unloads", &class_unloads_ctr); + register_counter ("Event: VTable loads", &vtable_loads_ctr); register_counter ("Event: Method entries", &method_entries_ctr); register_counter ("Event: Method exits", &method_exits_ctr); register_counter ("Event: Method exception leaves", &method_exception_exits_ctr); @@ -4537,6 +4630,7 @@ runtime_initialized (MonoProfiler *profiler) ADD_ICALL (SetHeapshotMillisecondsFrequency); ADD_ICALL (GetHeapshotCollectionsFrequency); ADD_ICALL (SetHeapshotCollectionsFrequency); + ADD_ICALL (TriggerHeapshot); ADD_ICALL (GetCallDepth); ADD_ICALL (SetCallDepth); ADD_ICALL (GetSampleMode); @@ -4612,20 +4706,12 @@ create_profiler (const char *args, const char *filename, GPtrArray *filters) log_profiler.gzfile = gzdopen (fileno (log_profiler.file), "wb"); #endif - /* - * If you hit this assert while increasing MAX_FRAMES, you need to increase - * SAMPLE_BLOCK_SIZE as well. - */ - g_assert (SAMPLE_SLOT_SIZE (MAX_FRAMES) * 2 < LOCK_FREE_ALLOC_SB_USABLE_SIZE (SAMPLE_BLOCK_SIZE)); - // FIXME: We should free this stuff too. mono_lock_free_allocator_init_size_class (&log_profiler.sample_size_class, SAMPLE_SLOT_SIZE (log_config.num_frames), SAMPLE_BLOCK_SIZE); mono_lock_free_allocator_init_allocator (&log_profiler.sample_allocator, &log_profiler.sample_size_class, MONO_MEM_ACCOUNT_PROFILER); mono_lock_free_queue_init (&log_profiler.sample_reuse_queue); - g_assert (sizeof (WriterQueueEntry) * 2 < LOCK_FREE_ALLOC_SB_USABLE_SIZE (WRITER_ENTRY_BLOCK_SIZE)); - // FIXME: We should free this stuff too. mono_lock_free_allocator_init_size_class (&log_profiler.writer_entry_size_class, sizeof (WriterQueueEntry), WRITER_ENTRY_BLOCK_SIZE); mono_lock_free_allocator_init_allocator (&log_profiler.writer_entry_allocator, &log_profiler.writer_entry_size_class, MONO_MEM_ACCOUNT_PROFILER); @@ -4653,6 +4739,13 @@ mono_profiler_init_log (const char *desc); void mono_profiler_init_log (const char *desc) { + /* + * If you hit this assert while increasing MAX_FRAMES, you need to increase + * SAMPLE_BLOCK_SIZE as well. + */ + g_assert (SAMPLE_SLOT_SIZE (MAX_FRAMES) * 2 < LOCK_FREE_ALLOC_SB_USABLE_SIZE (SAMPLE_BLOCK_SIZE)); + g_assert (sizeof (WriterQueueEntry) * 2 < LOCK_FREE_ALLOC_SB_USABLE_SIZE (WRITER_ENTRY_BLOCK_SIZE)); + GPtrArray *filters = NULL; proflog_parse_args (&log_config, desc [3] == ':' ? desc + 4 : ""); @@ -4666,6 +4759,18 @@ mono_profiler_init_log (const char *desc) } } + MonoProfilerHandle handle = log_profiler.handle = mono_profiler_create (&log_profiler); + + if (log_config.enter_leave) + mono_profiler_set_call_instrumentation_filter_callback (handle, method_filter); + + /* + * If the runtime was invoked for the purpose of AOT compilation only, the + * only thing we want to do is install the call instrumentation filter. + */ + if (mono_jit_aot_compiling ()) + goto done; + init_time (); PROF_TLS_INIT (); @@ -4674,8 +4779,6 @@ mono_profiler_init_log (const char *desc) mono_lls_init (&log_profiler.profiler_thread_list, NULL); - MonoProfilerHandle handle = log_profiler.handle = mono_profiler_create (&log_profiler); - /* * Required callbacks. These are either necessary for the profiler itself * to function, or provide metadata that's needed if other events (e.g. @@ -4689,7 +4792,7 @@ mono_profiler_init_log (const char *desc) mono_profiler_set_gc_event_callback (handle, gc_event); mono_profiler_set_thread_started_callback (handle, thread_start); - mono_profiler_set_thread_stopped_callback (handle, thread_end); + mono_profiler_set_thread_exited_callback (handle, thread_end); mono_profiler_set_thread_name_callback (handle, thread_name); mono_profiler_set_domain_loaded_callback (handle, domain_loaded); @@ -4707,8 +4810,13 @@ mono_profiler_init_log (const char *desc) mono_profiler_set_class_loaded_callback (handle, class_loaded); + mono_profiler_set_vtable_loaded_callback (handle, vtable_loaded); + mono_profiler_set_jit_done_callback (handle, method_jitted); + mono_profiler_set_gc_root_register_callback (handle, gc_root_register); + mono_profiler_set_gc_root_unregister_callback (handle, gc_root_deregister); + if (ENABLED (PROFLOG_EXCEPTION_EVENTS)) { mono_profiler_set_exception_throw_callback (handle, throw_exc); mono_profiler_set_exception_clause_callback (handle, clause_exc); @@ -4750,7 +4858,6 @@ mono_profiler_init_log (const char *desc) mono_profiler_set_jit_code_buffer_callback (handle, code_buffer_new); if (log_config.enter_leave) { - mono_profiler_set_call_instrumentation_filter_callback (handle, method_filter); mono_profiler_set_method_enter_callback (handle, method_enter); mono_profiler_set_method_leave_callback (handle, method_leave); mono_profiler_set_method_tail_call_callback (handle, tail_call); @@ -4772,4 +4879,7 @@ mono_profiler_init_log (const char *desc) */ if (!mono_profiler_set_sample_mode (handle, log_config.sampling_mode, log_config.sample_freq)) mono_profiler_printf_err ("Another profiler controls sampling parameters; the log profiler will not be able to modify them."); + +done: + ; } diff --git a/mono/profiler/log.h b/mono/profiler/log.h index bab555388b35..8ea1991e36ec 100644 --- a/mono/profiler/log.h +++ b/mono/profiler/log.h @@ -2,7 +2,6 @@ #define __MONO_PROFLOG_H__ #include -#define MONO_PROFILER_UNSTABLE_GC_ROOTS #include #include @@ -10,7 +9,7 @@ #define LOG_HEADER_ID 0x4D505A01 #define LOG_VERSION_MAJOR 2 #define LOG_VERSION_MINOR 0 -#define LOG_DATA_VERSION 14 +#define LOG_DATA_VERSION 15 /* * Changes in major/minor versions: @@ -72,6 +71,13 @@ removed type field from TYPE_SAMPLE_HIT removed MONO_GC_EVENT_{MARK,RECLAIM}_{START,END} reverted the root_type field back to uleb128 + removed MONO_PROFILER_CODE_BUFFER_UNKNOWN (was never used) + renumbered the MonoProfilerCodeBufferType enum + * version 15: reverted the type, unit, and variance fields back to uleb128 + added TYPE_HEAP_ROOT_{REGISTER,UNREGISTER} + TYPE_HEAP_ROOT now has a different, saner format + added TYPE_VTABLE metadata load event + changed TYPE_ALLOC and TYPE_HEAP_OBJECT to include a vtable pointer instead of a class pointer */ /* @@ -152,7 +158,7 @@ * type alloc format: * type: TYPE_ALLOC * exinfo: zero or TYPE_ALLOC_BT - * [ptr: sleb128] class as a byte difference from ptr_base + * [vtable: sleb128] MonoVTable* as a pointer difference from ptr_base * [obj: sleb128] object address as a byte difference from obj_base * [size: uleb128] size of the object in the heap * If exinfo == TYPE_ALLOC_BT, a backtrace follows. @@ -191,7 +197,7 @@ * exinfo: one of: TYPE_END_LOAD, TYPE_END_UNLOAD (optional for TYPE_THREAD and TYPE_DOMAIN, * doesn't occur for TYPE_CLASS) * [mtype: byte] metadata type, one of: TYPE_CLASS, TYPE_IMAGE, TYPE_ASSEMBLY, TYPE_DOMAIN, - * TYPE_THREAD, TYPE_CONTEXT + * TYPE_THREAD, TYPE_CONTEXT, TYPE_VTABLE * [pointer: sleb128] pointer of the metadata type depending on mtype * if mtype == TYPE_CLASS * [image: sleb128] MonoImage* as a pointer difference from ptr_base @@ -204,9 +210,12 @@ * if mtype == TYPE_DOMAIN && exinfo == 0 * [name: string] domain friendly name * if mtype == TYPE_CONTEXT - * [domain: sleb128] domain id as pointer + * [domain: sleb128] domain id as pointer difference from ptr_base * if mtype == TYPE_THREAD && exinfo == 0 * [name: string] thread name + * if mtype == TYPE_VTABLE + * [domain: sleb128] domain id as pointer difference from ptr_base, can be zero for proxy VTables + * [class: sleb128] MonoClass* as a pointer difference from ptr_base * * type method format: * type: TYPE_METHOD @@ -250,10 +259,10 @@ * * type heap format * type: TYPE_HEAP - * exinfo: one of TYPE_HEAP_START, TYPE_HEAP_END, TYPE_HEAP_OBJECT, TYPE_HEAP_ROOT + * exinfo: one of TYPE_HEAP_START, TYPE_HEAP_END, TYPE_HEAP_OBJECT, TYPE_HEAP_ROOT, TYPE_HEAP_ROOT_REGISTER, TYPE_HEAP_ROOT_UNREGISTER * if exinfo == TYPE_HEAP_OBJECT * [object: sleb128] the object as a difference from obj_base - * [class: sleb128] the object MonoClass* as a difference from ptr_base + * [vtable: sleb128] MonoVTable* as a pointer difference from ptr_base * [size: uleb128] size of the object on the heap * [num_refs: uleb128] number of object references * each referenced objref is preceded by a uleb128 encoded offset: the @@ -265,11 +274,17 @@ * provide additional referenced objects. * if exinfo == TYPE_HEAP_ROOT * [num_roots: uleb128] number of root references - * [num_gc: uleb128] number of major gcs - * [object: sleb128] the object as a difference from obj_base - * [root_type: uleb128] the root_type: MonoProfileGCRootType (profiler.h) - * [extra_info: uleb128] the extra_info value - * object, root_type and extra_info are repeated num_roots times + * for i = 0 to num_roots + * [address: sleb128] the root address as a difference from ptr_base + * [object: sleb128] the object address as a difference from obj_base + * if exinfo == TYPE_HEAP_ROOT_REGISTER + * [start: sleb128] start address as a difference from ptr_base + * [size: uleb] size of the root region + * [source: byte] MonoGCRootSource enum value + * [key: sleb128] root key, meaning dependent on type, value as a difference from ptr_base + * [desc: string] description of the root + * if exinfo == TYPE_HEAP_ROOT_UNREGISTER + * [start: sleb128] start address as a difference from ptr_base * * type sample format * type: TYPE_SAMPLE @@ -297,16 +312,16 @@ * if section == MONO_COUNTER_PERFCOUNTERS: * [section_name: string] section name of counter * [name: string] name of counter - * [type: byte] type of counter - * [unit: byte] unit of counter - * [variance: byte] variance of counter + * [type: uleb128] type of counter + * [unit: uleb128] unit of counter + * [variance: uleb128] variance of counter * [index: uleb128] unique index of counter * if exinfo == TYPE_SAMPLE_COUNTERS * while true: * [index: uleb128] unique index of counter * if index == 0: * break - * [type: byte] type of counter value + * [type: uleb128] type of counter value * if type == string: * if value == null: * [0: byte] 0 -> value is null @@ -376,6 +391,8 @@ enum { TYPE_HEAP_END = 1 << 4, TYPE_HEAP_OBJECT = 2 << 4, TYPE_HEAP_ROOT = 3 << 4, + TYPE_HEAP_ROOT_REGISTER = 4 << 4, + TYPE_HEAP_ROOT_UNREGISTER = 5 << 4, /* extended type for TYPE_METADATA */ TYPE_END_LOAD = 2 << 4, TYPE_END_UNLOAD = 4 << 4, @@ -431,6 +448,7 @@ enum { TYPE_DOMAIN = 4, TYPE_THREAD = 5, TYPE_CONTEXT = 6, + TYPE_VTABLE = 7, }; typedef enum { diff --git a/mono/profiler/mprof-report.c b/mono/profiler/mprof-report.c index 40076afbb903..97265da0a304 100644 --- a/mono/profiler/mprof-report.c +++ b/mono/profiler/mprof-report.c @@ -76,6 +76,23 @@ #define HASH_SIZE 9371 #define SMALL_HASH_SIZE 31 +/* Version < 14 root type enum */ +typedef enum { + /* Upper 2 bytes. */ + MONO_PROFILER_GC_ROOT_PINNING = 1 << 8, + MONO_PROFILER_GC_ROOT_WEAKREF = 2 << 8, + MONO_PROFILER_GC_ROOT_INTERIOR = 4 << 8, + + /* Lower 2 bytes (flags). */ + MONO_PROFILER_GC_ROOT_STACK = 1 << 0, + MONO_PROFILER_GC_ROOT_FINALIZER = 1 << 1, + MONO_PROFILER_GC_ROOT_HANDLE = 1 << 2, + MONO_PROFILER_GC_ROOT_OTHER = 1 << 3, + MONO_PROFILER_GC_ROOT_MISC = 1 << 4, + + MONO_PROFILER_GC_ROOT_TYPEMASK = 0xff, +} MonoProfilerGCRootType; + static int debug = 0; static int collect_traces = 0; static int show_traces = 0; @@ -661,6 +678,54 @@ lookup_class (intptr_t klass) return cd; } +typedef struct _VTableDesc VTableDesc; +struct _VTableDesc { + VTableDesc *next; + intptr_t vtable; + ClassDesc *klass; +}; + +static VTableDesc* vtable_hash [HASH_SIZE] = {0}; + +static VTableDesc* +add_vtable (intptr_t vtable, intptr_t klass) +{ + int slot = ((vtable >> 2) & 0xffff) % HASH_SIZE; + + VTableDesc *vt = vtable_hash [slot]; + + while (vt && vt->vtable != vtable) + vt = vt->next; + + if (vt) + return vt; + + vt = (VTableDesc *) g_calloc (sizeof (VTableDesc), 1); + + vt->vtable = vtable; + vt->klass = lookup_class (klass); + vt->next = vtable_hash [slot]; + + vtable_hash [slot] = vt; + + return vt; +} + +static VTableDesc * +lookup_vtable (intptr_t vtable) +{ + int slot = ((vtable >> 2) & 0xffff) % HASH_SIZE; + VTableDesc *vt = vtable_hash [slot]; + + while (vt && vt->vtable != vtable) + vt = vt->next; + + if (!vt) + return add_vtable (vtable, 0); + + return vt; +} + typedef struct _MethodDesc MethodDesc; struct _MethodDesc { MethodDesc *next; @@ -2562,6 +2627,12 @@ decode_buffer (ProfContext *ctx) while (*p) p++; p++; } + } else if (mtype == TYPE_VTABLE) { + intptr_t domaindiff = decode_sleb128 (p, &p); + intptr_t classdiff = decode_sleb128 (p, &p); + if (debug) + fprintf (outfile, "vtable %p for class %p in domain %p at %llu\n", (void *) (ptrdiff + ptr_base), (void *) (classdiff + ptr_base), (void *) (domaindiff + ptr_base), (unsigned long long) time_base); + add_vtable (ptr_base + ptrdiff, ptr_base + classdiff); } break; } @@ -2574,12 +2645,17 @@ decode_buffer (ProfContext *ctx) int num_bt = 0; MethodDesc* sframes [8]; MethodDesc** frames = sframes; - ClassDesc *cd = lookup_class (ptr_base + ptrdiff); + ClassDesc *cd; + if (ctx->data_version > 14) { + VTableDesc *vt = lookup_vtable (ptr_base + ptrdiff); + cd = vt->klass; + } else + cd = lookup_class (ptr_base + ptrdiff); len = decode_uleb128 (p, &p); LOG_TIME (time_base, tdiff); time_base += tdiff; if (debug) - fprintf (outfile, "alloced object %p, size %llu (%s) at %llu\n", (void*)OBJ_ADDR (objdiff), (unsigned long long) len, lookup_class (ptr_base + ptrdiff)->name, (unsigned long long) time_base); + fprintf (outfile, "alloced object %p, size %llu (%s) at %llu\n", (void*)OBJ_ADDR (objdiff), (unsigned long long) len, cd->name, (unsigned long long) time_base); if (has_bt) { num_bt = 8; frames = decode_bt (ctx, sframes, &num_bt, p, &p, ptr_base, &method_base); @@ -2663,7 +2739,12 @@ decode_buffer (ProfContext *ctx) uintptr_t num = decode_uleb128 (p, &p); uintptr_t ref_offset = 0; uintptr_t last_obj_offset = 0; - ClassDesc *cd = lookup_class (ptr_base + ptrdiff); + ClassDesc *cd; + if (ctx->data_version > 14) { + VTableDesc *vt = lookup_vtable (ptr_base + ptrdiff); + cd = vt->klass; + } else + cd = lookup_class (ptr_base + ptrdiff); if (size) { HeapClassDesc *hcd = add_heap_shot_class (thread->current_heap_shot, cd, size); if (collect_traces) { @@ -2691,29 +2772,68 @@ decode_buffer (ProfContext *ctx) fprintf (outfile, "traced object %p, size %llu (%s), refs: %zd\n", (void*)OBJ_ADDR (objdiff), (unsigned long long) size, cd->name, num); } else if (subtype == TYPE_HEAP_ROOT) { uintptr_t num; - if (ctx->data_version > 12) { + if (ctx->data_version > 14) { + int i; uint64_t tdiff = decode_uleb128 (p + 1, &p); LOG_TIME (time_base, tdiff); time_base += tdiff; num = decode_uleb128 (p, &p); - } else - num = decode_uleb128 (p + 1, &p); - uintptr_t gc_num G_GNUC_UNUSED = decode_uleb128 (p, &p); - int i; - for (i = 0; i < num; ++i) { - intptr_t objdiff = decode_sleb128 (p, &p); - int root_type; - if (ctx->data_version == 13) - root_type = *p++; - else - root_type = decode_uleb128 (p, &p); - /* we just discard the extra info for now */ - uintptr_t extra_info = decode_uleb128 (p, &p); - if (debug) - fprintf (outfile, "object %p is a %s root\n", (void*)OBJ_ADDR (objdiff), get_root_name (root_type)); - if (collect_traces) - thread_add_root (thread, OBJ_ADDR (objdiff), root_type, extra_info); + for (i = 0; i < num; ++i) { + intptr_t ptrdiff = decode_sleb128 (p, &p); + intptr_t objdiff = decode_sleb128 (p, &p); + + if (debug) + fprintf (outfile, "root object %p at address %p\n", (void*)OBJ_ADDR (objdiff), (void *) (ptr_base + ptrdiff)); + if (collect_traces) + thread_add_root (thread, OBJ_ADDR (objdiff), MONO_PROFILER_GC_ROOT_MISC, 0); + } + } else { + if (ctx->data_version > 12) { + uint64_t tdiff = decode_uleb128 (p + 1, &p); + LOG_TIME (time_base, tdiff); + time_base += tdiff; + num = decode_uleb128 (p, &p); + } else + num = decode_uleb128 (p + 1, &p); + uintptr_t gc_num G_GNUC_UNUSED = decode_uleb128 (p, &p); + int i; + for (i = 0; i < num; ++i) { + intptr_t objdiff = decode_sleb128 (p, &p); + int root_type; + if (ctx->data_version == 13) + root_type = *p++; + else + root_type = decode_uleb128 (p, &p); + /* we just discard the extra info for now */ + uintptr_t extra_info = decode_uleb128 (p, &p); + if (debug) + fprintf (outfile, "object %p is a %s root\n", (void*)OBJ_ADDR (objdiff), get_root_name (root_type)); + if (collect_traces) + thread_add_root (thread, OBJ_ADDR (objdiff), root_type, extra_info); + } } + } else if (subtype == TYPE_HEAP_ROOT_REGISTER) { + uint64_t tdiff = decode_uleb128 (p + 1, &p); + LOG_TIME (time_base, tdiff); + time_base += tdiff; + + int64_t ptrdiff = decode_sleb128 (p, &p); + uint64_t size = decode_uleb128 (p, &p); + int type = *p++; + int64_t keydiff = decode_sleb128 (p, &p); + char *desc = (char*) p; + while (*p++); + + if (debug) + fprintf (outfile, "root register address %p size %lld type %d key %p name %s\n", (void *) (ptr_base + ptrdiff), (unsigned long long) size, type, (void *) (ptr_base + keydiff), desc); + } else if (subtype == TYPE_HEAP_ROOT_UNREGISTER) { + uint64_t tdiff = decode_uleb128 (p + 1, &p); + LOG_TIME (time_base, tdiff); + time_base += tdiff; + int64_t ptrdiff = decode_sleb128 (p, &p); + + if (debug) + fprintf (outfile, "root unregister address %p\n", (void *) (ptr_base + ptrdiff)); } else if (subtype == TYPE_HEAP_END) { uint64_t tdiff = decode_uleb128 (p + 1, &p); LOG_TIME (time_base, tdiff); @@ -3003,7 +3123,7 @@ decode_buffer (ProfContext *ctx) } name = pstrdup ((char*)p); while (*p++); - if (ctx->data_version > 12) { + if (ctx->data_version > 12 && ctx->data_version < 15) { type = *p++; unit = *p++; variance = *p++; @@ -3040,7 +3160,7 @@ decode_buffer (ProfContext *ctx) } } - if (ctx->data_version > 12) + if (ctx->data_version > 12 && ctx->data_version < 15) type = *p++; else type = decode_uleb128 (p, &p); diff --git a/mono/sgen/gc-internal-agnostic.h b/mono/sgen/gc-internal-agnostic.h index f1c887b5754f..1bc27c711c6a 100644 --- a/mono/sgen/gc-internal-agnostic.h +++ b/mono/sgen/gc-internal-agnostic.h @@ -45,12 +45,14 @@ #define MONO_GC_HANDLE_IS_OBJECT_POINTER(slot) (MONO_GC_HANDLE_TAG (slot) == (MONO_GC_HANDLE_OCCUPIED_MASK | MONO_GC_HANDLE_VALID_MASK)) #define MONO_GC_HANDLE_IS_METADATA_POINTER(slot) (MONO_GC_HANDLE_TAG (slot) == MONO_GC_HANDLE_OCCUPIED_MASK) +/* These should match System.Runtime.InteropServices.GCHandleType */ typedef enum { HANDLE_TYPE_MIN = 0, HANDLE_WEAK = HANDLE_TYPE_MIN, HANDLE_WEAK_TRACK, HANDLE_NORMAL, HANDLE_PINNED, + HANDLE_WEAK_FIELDS, HANDLE_TYPE_MAX } GCHandleType; diff --git a/mono/sgen/sgen-client.h b/mono/sgen/sgen-client.h index 4137cacc3c2a..4ce37cc3a6ca 100644 --- a/mono/sgen/sgen-client.h +++ b/mono/sgen/sgen-client.h @@ -107,20 +107,31 @@ void sgen_client_nursery_objects_pinned (void **definitely_pinned, int count); /* * Called at a semi-random point during minor collections. No action is necessary. */ -void sgen_client_collecting_minor (SgenPointerQueue *fin_ready_queue, SgenPointerQueue *critical_fin_queue); +void sgen_client_collecting_minor_report_roots (SgenPointerQueue *fin_ready_queue, SgenPointerQueue *critical_fin_queue); /* * Called at semi-random points during major collections. No action is necessary. */ -void sgen_client_collecting_major_1 (void); -void sgen_client_collecting_major_2 (void); -void sgen_client_collecting_major_3 (SgenPointerQueue *fin_ready_queue, SgenPointerQueue *critical_fin_queue); +void sgen_client_collecting_major_report_roots (SgenPointerQueue *fin_ready_queue, SgenPointerQueue *critical_fin_queue); /* * Called after a LOS object has been pinned. No action is necessary. */ void sgen_client_pinned_los_object (GCObject *obj); +/* + * Called for each cemented obj + */ +void sgen_client_pinned_cemented_object (GCObject *obj); + +/* + * Called for each major heap obj pinned + */ +void sgen_client_pinned_major_heap_object (GCObject *obj); + +void sgen_client_pinning_start (void); +void sgen_client_pinning_end (void); + /* * Called for every degraded allocation. No action is necessary. */ @@ -223,6 +234,18 @@ gpointer sgen_client_get_provenance (void); */ void sgen_client_describe_invalid_pointer (GCObject *ptr); +/* + * Return the weak bitmap for a class + */ +gsize *sgen_client_get_weak_bitmap (GCVTable vt, int *nbits); + +/* + * Scheduled @cv to be invoked later in the background. + * + * This function is idepotent WRT background execution. Meaning that calling it multiple times with the same funciton pointer before any bg execution happens will only call @cb once. + */ +void sgen_client_schedule_background_job (void (*cb)(void)); + /* * These client binary protocol functions are called from the respective binary protocol * functions. No action is necessary. We suggest implementing them as inline functions in @@ -294,4 +317,5 @@ SgenThreadInfo* mono_thread_info_current (void); * Get the current thread's small ID. This will be called on managed and worker threads. */ int mono_thread_info_get_small_id (void); + #endif diff --git a/mono/sgen/sgen-descriptor.h b/mono/sgen/sgen-descriptor.h index 2c7f19b18c46..f10ebf6a5104 100644 --- a/mono/sgen/sgen-descriptor.h +++ b/mono/sgen/sgen-descriptor.h @@ -122,6 +122,7 @@ enum { }; typedef void (*SgenUserMarkFunc) (GCObject **addr, void *gc_data); +typedef void (*SgenUserReportRootFunc) (void *addr, GCObject *obj, void *gc_data); typedef void (*SgenUserRootMarkFunc) (void *addr, SgenUserMarkFunc mark_func, void *gc_data); SgenDescriptor sgen_make_user_root_descriptor (SgenUserRootMarkFunc marker); diff --git a/mono/sgen/sgen-gc.c b/mono/sgen/sgen-gc.c index fb3be3507b18..8e597946baa8 100644 --- a/mono/sgen/sgen-gc.c +++ b/mono/sgen/sgen-gc.c @@ -673,6 +673,7 @@ pin_objects_from_nursery_pin_queue (gboolean do_scan_objects, ScanCopyContext ct * Finally - pin the object! */ desc = sgen_obj_get_descriptor_safe (obj_to_pin); + if (do_scan_objects) { scan_func (obj_to_pin, desc, queue); } else { @@ -1773,6 +1774,7 @@ collect_nursery (const char *reason, gboolean is_overflow, SgenGrayQueue *unpin_ time_minor_pinning += TV_ELAPSED (btv, atv); SGEN_LOG (2, "Finding pinned pointers: %zd in %lld usecs", sgen_get_pinned_count (), (long long)TV_ELAPSED (btv, atv)); SGEN_LOG (4, "Start scan with %zd pinned objects", sgen_get_pinned_count ()); + sgen_client_pinning_end (); remset.start_scan_remsets (); @@ -1785,9 +1787,6 @@ collect_nursery (const char *reason, gboolean is_overflow, SgenGrayQueue *unpin_ sgen_pin_stats_report (); - /* FIXME: Why do we do this at this specific, seemingly random, point? */ - sgen_client_collecting_minor (&fin_ready_queue, &critical_fin_queue); - TV_GETTIME (atv); time_minor_scan_pinned += TV_ELAPSED (btv, atv); @@ -1861,6 +1860,10 @@ collect_nursery (const char *reason, gboolean is_overflow, SgenGrayQueue *unpin_ sgen_debug_dump_heap ("minor", mono_atomic_load_i32 (&gc_stats.minor_gc_count) - 1, NULL); + // This is used by the profiler to report GC roots. + // Invariants: Heap's finished, no more moves left. Pin queue no longer in use, we can do whatever with it. + sgen_client_collecting_minor_report_roots (&fin_ready_queue, &critical_fin_queue); + /* prepare the pin queue for the next collection */ sgen_finish_pinning (); if (sgen_have_pending_finalizers ()) { @@ -1976,8 +1979,6 @@ major_copy_or_mark_from_roots (SgenGrayQueue *gc_thread_gray_queue, size_t *old_ sgen_cement_force_pinned (); } - sgen_client_collecting_major_1 (); - /* * pin_queue now contains all candidate pointers, sorted and * uniqued. We must do two passes now to figure out which @@ -2028,6 +2029,7 @@ major_copy_or_mark_from_roots (SgenGrayQueue *gc_thread_gray_queue, size_t *old_ time_major_pinning += TV_ELAPSED (atv, btv); SGEN_LOG (2, "Finding pinned pointers: %zd in %lld usecs", sgen_get_pinned_count (), (long long)TV_ELAPSED (atv, btv)); SGEN_LOG (4, "Start scan with %zd pinned objects", sgen_get_pinned_count ()); + sgen_client_pinning_end (); if (mode == COPY_OR_MARK_FROM_ROOTS_START_CONCURRENT) sgen_finish_pinning_for_conc (); @@ -2056,13 +2058,9 @@ major_copy_or_mark_from_roots (SgenGrayQueue *gc_thread_gray_queue, size_t *old_ main_gc_thread = mono_native_thread_self (); #endif - sgen_client_collecting_major_2 (); - TV_GETTIME (atv); time_major_scan_pinned += TV_ELAPSED (btv, atv); - sgen_client_collecting_major_3 (&fin_ready_queue, &critical_fin_queue); - enqueue_scan_from_roots_jobs (gc_thread_gray_queue, heap_start, heap_end, object_ops_nopar, FALSE); TV_GETTIME (btv); @@ -2257,6 +2255,8 @@ major_finish_collection (SgenGrayQueue *gc_thread_gray_queue, const char *reason if (do_concurrent_checks && concurrent_collection_in_progress) sgen_debug_check_nursery_is_clean (); + sgen_client_collecting_major_report_roots (&fin_ready_queue, &critical_fin_queue); + /* prepare the pin queue for the next collection */ sgen_finish_pinning (); @@ -2592,19 +2592,14 @@ typedef struct { } SgenGcRequest; static SgenGcRequest gc_request; -static gboolean pending_request; - -extern void request_gc_cycle (void); #include -EMSCRIPTEN_KEEPALIVE void -mono_gc_pump_callback (void) +static void +gc_pump_callback (void) { - if (!pending_request) - return; - pending_request = FALSE; - sgen_perform_collection_inner (gc_request.requested_size, gc_request.generation_to_collect, gc_request.reason, TRUE, TRUE); + sgen_perform_collection_inner (gc_request.requested_size, gc_request.generation_to_collect, gc_request.reason, TRUE, TRUE); + gc_request.generation_to_collect = 0; } #endif @@ -2614,14 +2609,14 @@ sgen_perform_collection (size_t requested_size, int generation_to_collect, const #ifdef HOST_WASM g_assert (stw); //can't handle non-stw mode (IE, domain unload) //we ignore wait_to_finish - if (!pending_request || gc_request.generation_to_collect <= generation_to_collect) { //no active request or request was for a smaller part of the heap + + //There's a window for racing where we're executing other bg jobs before the GC, they trigger a GC request and it overrides this one. + //I belive this case to be benign as it will, in the worst case, upgrade a minor to a major collection. + if (gc_request.generation_to_collect <= generation_to_collect) { gc_request.requested_size = requested_size; gc_request.generation_to_collect = generation_to_collect; gc_request.reason = reason; - if (!pending_request) { - request_gc_cycle (); - pending_request = TRUE; - } + sgen_client_schedule_background_job (gc_pump_callback); } degraded_mode = 1; //enable degraded mode so allocation can continue @@ -2656,21 +2651,6 @@ report_internal_mem_usage (void) * ###################################################################### */ -/* - * If the object has been forwarded it means it's still referenced from a root. - * If it is pinned it's still alive as well. - * A LOS object is only alive if we have pinned it. - * Return TRUE if @obj is ready to be finalized. - */ -static inline gboolean -sgen_is_object_alive (GCObject *object) -{ - if (ptr_in_nursery (object)) - return sgen_nursery_is_object_alive (object); - - return sgen_major_is_object_alive (object); -} - /* * This function returns true if @object is either alive and belongs to the * current collection - major collections are full heap, so old gen objects @@ -2800,10 +2780,13 @@ sgen_have_pending_finalizers (void) * We do not coalesce roots. */ int -sgen_register_root (char *start, size_t size, SgenDescriptor descr, int root_type, int source, const char *msg) +sgen_register_root (char *start, size_t size, SgenDescriptor descr, int root_type, int source, void *key, const char *msg) { RootRecord new_root; int i; + + sgen_client_root_registered (start, size, source, key, msg); + LOCK_GC; for (i = 0; i < ROOT_TYPE_NUM; ++i) { RootRecord *root = (RootRecord *)sgen_hash_table_lookup (&roots_hash [i], start); @@ -2842,6 +2825,8 @@ sgen_deregister_root (char* addr) int root_type; RootRecord root; + sgen_client_root_deregistered (addr); + LOCK_GC; for (root_type = 0; root_type < ROOT_TYPE_NUM; ++root_type) { if (sgen_hash_table_remove (&roots_hash [root_type], addr, &root)) @@ -3722,7 +3707,7 @@ sgen_gc_init (void) sgen_card_table_init (&remset); - sgen_register_root (NULL, 0, sgen_make_user_root_descriptor (sgen_mark_normal_gc_handles), ROOT_TYPE_NORMAL, MONO_ROOT_SOURCE_GC_HANDLE, "normal gc handles"); + sgen_register_root (NULL, 0, sgen_make_user_root_descriptor (sgen_mark_normal_gc_handles), ROOT_TYPE_NORMAL, MONO_ROOT_SOURCE_GC_HANDLE, NULL, "GC Handles (SGen, Normal)"); gc_initialized = 1; diff --git a/mono/sgen/sgen-gc.h b/mono/sgen/sgen-gc.h index 8cdec588b666..0b446599d1bf 100644 --- a/mono/sgen/sgen-gc.h +++ b/mono/sgen/sgen-gc.h @@ -394,7 +394,7 @@ enum { extern SgenHashTable roots_hash [ROOT_TYPE_NUM]; -int sgen_register_root (char *start, size_t size, SgenDescriptor descr, int root_type, int source, const char *msg) +int sgen_register_root (char *start, size_t size, SgenDescriptor descr, int root_type, int source, void *key, const char *msg) MONO_PERMIT (need (sgen_lock_gc)); void sgen_deregister_root (char* addr) MONO_PERMIT (need (sgen_lock_gc)); @@ -794,6 +794,8 @@ gboolean sgen_object_is_live (GCObject *obj); void sgen_init_fin_weak_hash (void); +void sgen_register_obj_with_weak_fields (GCObject *obj); + /* FIXME: move the toggleref stuff out of here */ void sgen_mark_togglerefs (char *start, char *end, ScanCopyContext ctx); void sgen_clear_togglerefs (char *start, char *end, ScanCopyContext ctx); @@ -962,6 +964,23 @@ sgen_major_is_object_alive (GCObject *object) return major_collector.is_object_live (object); } + +/* + * If the object has been forwarded it means it's still referenced from a root. + * If it is pinned it's still alive as well. + * A LOS object is only alive if we have pinned it. + * Return TRUE if @obj is ready to be finalized. + */ +static inline gboolean +sgen_is_object_alive (GCObject *object) +{ + if (sgen_ptr_in_nursery (object)) + return sgen_nursery_is_object_alive (object); + + return sgen_major_is_object_alive (object); +} + + /* * This function returns true if @object is either alive or it belongs to the old gen * and we're currently doing a minor collection. @@ -997,6 +1016,8 @@ void sgen_gchandle_iterate (GCHandleType handle_type, int max_generation, SgenGC void sgen_gchandle_set_target (guint32 gchandle, GCObject *obj); void sgen_mark_normal_gc_handles (void *addr, SgenUserMarkFunc mark_func, void *gc_data) MONO_PERMIT (need (sgen_world_stopped)); +void sgen_gc_handles_report_roots (SgenUserReportRootFunc mark_func, void *gc_data) + MONO_PERMIT (need (sgen_world_stopped)); gpointer sgen_gchandle_get_metadata (guint32 gchandle); GCObject *sgen_gchandle_get_target (guint32 gchandle); void sgen_gchandle_free (guint32 gchandle); diff --git a/mono/sgen/sgen-gchandles.c b/mono/sgen/sgen-gchandles.c index 4a140e53668e..2aa0d233fd3e 100644 --- a/mono/sgen/sgen-gchandles.c +++ b/mono/sgen/sgen-gchandles.c @@ -94,16 +94,26 @@ static void bucket_alloc_callback (gpointer *bucket, guint32 new_bucket_size, gboolean alloc) { if (alloc) - sgen_register_root ((char *)bucket, new_bucket_size, SGEN_DESCRIPTOR_NULL, ROOT_TYPE_PINNED, MONO_ROOT_SOURCE_GC_HANDLE, "pinned gc handles"); + sgen_register_root ((char *)bucket, new_bucket_size, SGEN_DESCRIPTOR_NULL, ROOT_TYPE_PINNED, MONO_ROOT_SOURCE_GC_HANDLE, NULL, "GC Handle Bucket (SGen, Pinned)"); else sgen_deregister_root ((char *)bucket); } +static void +bucket_alloc_report_root (gpointer *bucket, guint32 new_bucket_size, gboolean alloc) +{ + if (alloc) + sgen_client_root_registered ((char *)bucket, new_bucket_size, MONO_ROOT_SOURCE_GC_HANDLE, NULL, "GC Handle Bucket (SGen, Normal)"); + else + sgen_client_root_deregistered ((char *)bucket); +} + static HandleData gc_handles [] = { { SGEN_ARRAY_LIST_INIT (NULL, is_slot_set, try_occupy_slot, -1), (HANDLE_WEAK) }, { SGEN_ARRAY_LIST_INIT (NULL, is_slot_set, try_occupy_slot, -1), (HANDLE_WEAK_TRACK) }, - { SGEN_ARRAY_LIST_INIT (NULL, is_slot_set, try_occupy_slot, -1), (HANDLE_NORMAL) }, - { SGEN_ARRAY_LIST_INIT (bucket_alloc_callback, is_slot_set, try_occupy_slot, -1), (HANDLE_PINNED) } + { SGEN_ARRAY_LIST_INIT (bucket_alloc_report_root, is_slot_set, try_occupy_slot, -1), (HANDLE_NORMAL) }, + { SGEN_ARRAY_LIST_INIT (bucket_alloc_callback, is_slot_set, try_occupy_slot, -1), (HANDLE_PINNED) }, + { SGEN_ARRAY_LIST_INIT (NULL, is_slot_set, try_occupy_slot, -1), (HANDLE_WEAK_FIELDS) }, }; static HandleData * @@ -132,6 +142,22 @@ sgen_mark_normal_gc_handles (void *addr, SgenUserMarkFunc mark_func, void *gc_da } SGEN_ARRAY_LIST_END_FOREACH_SLOT; } +void +sgen_gc_handles_report_roots (SgenUserReportRootFunc report_func, void *gc_data) +{ + HandleData *handles = gc_handles_for_type (HANDLE_NORMAL); + SgenArrayList *array = &handles->entries_array; + volatile gpointer *slot; + gpointer hidden, revealed; + + SGEN_ARRAY_LIST_FOREACH_SLOT (array, slot) { + hidden = *slot; + revealed = MONO_GC_REVEAL_POINTER (hidden, FALSE); + + if (MONO_GC_HANDLE_IS_OBJECT_POINTER (hidden)) + report_func ((void*)slot, revealed, gc_data); + } SGEN_ARRAY_LIST_END_FOREACH_SLOT; +} static guint32 alloc_handle (HandleData *handles, GCObject *obj, gboolean track) @@ -394,11 +420,52 @@ null_link_if_necessary (gpointer hidden, GCHandleType handle_type, int max_gener return MONO_GC_HANDLE_OBJECT_POINTER (copy, is_weak); } +static gpointer +scan_for_weak (gpointer hidden, GCHandleType handle_type, int max_generation, gpointer user) +{ + const gboolean is_weak = GC_HANDLE_TYPE_IS_WEAK (handle_type); + ScanCopyContext *ctx = (ScanCopyContext *)user; + + if (!MONO_GC_HANDLE_VALID (hidden)) + return hidden; + + GCObject *obj = (GCObject *)MONO_GC_REVEAL_POINTER (hidden, is_weak); + + /* If the object is dead we free the gc handle */ + if (!sgen_is_object_alive (obj)) + return NULL; + + /* Relocate it */ + ctx->ops->copy_or_mark_object (&obj, ctx->queue); + + int nbits; + gsize *weak_bitmap = sgen_client_get_weak_bitmap (SGEN_LOAD_VTABLE (obj), &nbits); + for (int i = 0; i < nbits; ++i) { + if (weak_bitmap [i / (sizeof (gsize) * 8)] & ((gsize)1 << (i % (sizeof (gsize) * 8)))) { + GCObject **addr = (GCObject **)((char*)obj + (i * sizeof (gpointer))); + GCObject *field = *addr; + + /* if the object in the weak field is alive, we relocate it */ + if (field && sgen_is_object_alive (field)) + ctx->ops->copy_or_mark_object (addr, ctx->queue); + else + *addr = NULL; + } + } + + /* Update link if object was moved. */ + return MONO_GC_HANDLE_OBJECT_POINTER (obj, is_weak); +} + /* LOCKING: requires that the GC lock is held */ void sgen_null_link_in_range (int generation, ScanCopyContext ctx, gboolean track) { sgen_gchandle_iterate (track ? HANDLE_WEAK_TRACK : HANDLE_WEAK, generation, null_link_if_necessary, &ctx); + + //we're always called for gen zero. !track means short ref + if (generation == 0 && !track) + sgen_gchandle_iterate (HANDLE_WEAK_FIELDS, generation, scan_for_weak, &ctx); } typedef struct { @@ -435,6 +502,15 @@ sgen_null_links_if (SgenObjectPredicateFunc predicate, void *data, int generatio sgen_gchandle_iterate (track ? HANDLE_WEAK_TRACK : HANDLE_WEAK, generation, null_link_if, &closure); } +void +sgen_register_obj_with_weak_fields (GCObject *obj) +{ + // + // We use a gc handle to be able to do some processing for these objects at every gc + // + alloc_handle (gc_handles_for_type (HANDLE_WEAK_FIELDS), obj, FALSE); +} + void sgen_init_gchandles (void) { diff --git a/mono/sgen/sgen-marksweep.c b/mono/sgen/sgen-marksweep.c index c17846d9decd..2624aa7f514b 100644 --- a/mono/sgen/sgen-marksweep.c +++ b/mono/sgen/sgen-marksweep.c @@ -1410,6 +1410,7 @@ mark_pinned_objects_in_block (MSBlockInfo *block, size_t first_entry, size_t las continue; MS_MARK_OBJECT_AND_ENQUEUE (obj, sgen_obj_get_descriptor (obj), block, queue); sgen_pin_stats_register_object (obj, GENERATION_OLD); + sgen_client_pinned_major_heap_object (obj); last_index = index; } diff --git a/mono/sgen/sgen-pinning.c b/mono/sgen/sgen-pinning.c index 6b43771a93ec..b23b20b58829 100644 --- a/mono/sgen/sgen-pinning.c +++ b/mono/sgen/sgen-pinning.c @@ -43,6 +43,7 @@ sgen_init_pinning (void) { memset (pin_hash_filter, 0, sizeof (pin_hash_filter)); pin_queue.mem_type = INTERNAL_MEM_PIN_QUEUE; + sgen_client_pinning_start (); } void @@ -367,6 +368,7 @@ pin_from_hash (CementHashEntry *hash, gboolean has_been_reset) if (has_been_reset) SGEN_ASSERT (5, hash [i].count >= SGEN_CEMENT_THRESHOLD, "Cementing hash inconsistent"); + sgen_client_pinned_cemented_object (hash [i].obj); sgen_pin_stage_ptr (hash [i].obj); binary_protocol_cement_stage (hash [i].obj); /* FIXME: do pin stats if enabled */ diff --git a/mono/tests/Makefile.am b/mono/tests/Makefile.am index ff7ac6eb445a..cff377fc0276 100755 --- a/mono/tests/Makefile.am +++ b/mono/tests/Makefile.am @@ -528,8 +528,9 @@ TESTS_CS_SRC= \ bug-58782-capture-and-throw.cs \ recursive-struct-arrays.cs \ bug-59281.cs \ - init_array_with_lazy_type.cs - + init_array_with_lazy_type.cs \ + weak-fields.cs \ + threads-leak.cs if AMD64 TESTS_CS_SRC += async-exc-compilation.cs finally_guard.cs finally_block_ending_in_dead_bb.cs @@ -707,7 +708,7 @@ PLATFORM_DISABLED_TESTS += monitor.exe threadpool-exceptions5.exe appdomain-unlo endif if ARM -PLATFORM_DISABLED_TESTS += filter-stack.exe +PLATFORM_DISABLED_TESTS += filter-stack.exe weak-fields.exe INTERP_PLATFORM_DISABLED_TESTS= \ assemblyresolve_event6.exe \ delegate-async-exit.exe \ @@ -720,6 +721,7 @@ INTERP_PLATFORM_DISABLED_TESTS= \ endif if ARM64 +PLATFORM_DISABLED_TESTS += weak-fields.exe INTERP_PLATFORM_DISABLED_TESTS= \ assemblyresolve_event6.exe \ finalizer-exception.exe @@ -903,6 +905,10 @@ PROFILE_DISABLED_TESTS += \ appdomain-loader.exe \ assemblyresolve_event3.exe \ appdomain-serialize-exception.exe + +# https://bugzilla.xamarin.com/show_bug.cgi?id=60973 +PROFILE_DISABLED_TESTS += \ + weak-fields.exe endif if HYBRID_AOT_TESTS @@ -966,6 +972,7 @@ DISABLED_TESTS = \ # bug-48015.exe: be careful when re-enabling, it happens that it returns with # exit code 0, but doesn't actually execute the test. # block_guard_restore_aligment_on_exit.exe: flaky (10% of the time it hangs and thus times out) +# weak-fields.exe: https://bugzilla.xamarin.com/show_bug.cgi?id=60973 INTERP_DISABLED_TESTS = \ $(KNOWN_FAILING_TESTS) \ $(INTERP_PLATFORM_DISABLED_TESTS) \ @@ -1024,6 +1031,7 @@ INTERP_DISABLED_TESTS = \ threadpool-exceptions5.exe \ thunks.exe \ typeload-unaligned.exe \ + weak-fields.exe \ vararg.exe \ vararg2.exe \ winx64structs.exe @@ -2071,5 +2079,13 @@ internalsvisibleto-correctcase-2-sign2048.dll internalsvisibleto-wrongcase-2-sig $(Q) $(MCS_NO_UNSAFE) -out:internalsvisibleto-wrongcase-2-sign2048.dll -target:library -d:WRONG_CASE -d:SIGN2048 internalsvisibleto-library.cs $(Q) $(MCS_NO_UNSAFE) -out:internalsvisibleto-compilertest-sign2048.exe -warn:0 -r:internalsvisibleto-correctcase-2-sign2048.dll -r:internalsvisibleto-wrongcase-2-sign2048.dll -d:SIGN2048 internalsvisibleto-compilertest.cs +EXTRA_DIST += weakattribute.cs + +# Contains copies of types which don't exist in the desktop profile so tests can use them +Mono.Runtime.Testing.dll: weakattribute.cs + $(MCS) -target:library -out:$@ $< + +weak-fields.exe: weak-fields.cs Mono.Runtime.Testing.dll + $(MCS) -r:Mono.Runtime.Testing.dll -r:$(CLASS)/System.dll -r:$(CLASS)/System.Xml.dll -r:$(CLASS)/System.Core.dll -r:TestDriver.dll $(TEST_DRIVER_HARD_KILL_FEATURE) -out:$@ $< CLEANFILES = $(TESTS_CS) $(TESTS_IL) $(TESTS_BENCH) $(TESTS_STRESS) $(TESTSAOT_CS) $(TESTSAOT_IL) $(TESTSAOT_BENCH) $(TESTSAOT_STRESS) *.dll *.stdout *.aotlog *.exe stest.dat LeafAssembly.dll MidAssembly.dll appdomain-marshalbyref-assemblyload2/*.dll diff --git a/mono/tests/assembly_append_ordering.cs b/mono/tests/assembly_append_ordering.cs index 6f0b471ed8a6..13da3b7fa7e7 100644 --- a/mono/tests/assembly_append_ordering.cs +++ b/mono/tests/assembly_append_ordering.cs @@ -32,6 +32,7 @@ static int Main () { return 0; } + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] static Assembly TriggerLoadingSystemCore () { int[] x = new int[] { 1,2,3}; @@ -56,4 +57,4 @@ static Assembly DefineDynamicAssembly (AppDomain domain) return assemblyBuilder; } -} \ No newline at end of file +} diff --git a/mono/tests/threads-leak.cs b/mono/tests/threads-leak.cs new file mode 100644 index 000000000000..f91b72acb31d --- /dev/null +++ b/mono/tests/threads-leak.cs @@ -0,0 +1,45 @@ +using System; +using System.Threading; + +class Driver +{ + static ManualResetEvent mre = new ManualResetEvent (false); + + class MyClassInThread + { + public int I { get; set; } + + ~MyClassInThread() + { + try { + Console.WriteLine($"Finalizer {I}"); + } catch (NotSupportedException) { + } + + mre.Set (); + } + } + + public static void Main(string[] args) + { + for (int i = 0; i < 50; ++i) { + SpawnThread(i); + GC.Collect(); + GC.Collect(); + GC.Collect(); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Console.WriteLine($"Loop {i}"); + } + + if (!mre.WaitOne(0)) + Environment.Exit (1); + } + + static void SpawnThread(int i) + { + var th = new Thread(_ => {}) { IsBackground = true, }; + th.Start(new MyClassInThread { I = i }); + th.Join(); + } +} diff --git a/mono/tests/weak-fields.cs b/mono/tests/weak-fields.cs new file mode 100644 index 000000000000..1bd8337c09b5 --- /dev/null +++ b/mono/tests/weak-fields.cs @@ -0,0 +1,71 @@ +using System; +using System.Threading; + +[AttributeUsage(AttributeTargets.Field)] +public sealed class Weak2Attribute : Attribute +{ +} + +public class Finalizable { + public int a; + + ~Finalizable () { + Console.WriteLine ("Finalized. {0}", a); + } +} + +public class OneField { + int x; +} +public class Tests +{ + static Finalizable retain; + + [Weak] + public object Obj; + [Weak2] + public object Obj3; + [Weak] + public object Obj2; + [Weak] + public Finalizable Obj4; + + public static int Main (String[] args) { + var t = new Tests (); + var thread = new Thread (delegate () { + t.Obj = new Finalizable (); + t.Obj2 = new Finalizable (); + t.Obj3 = new Finalizable (); + t.Obj4 = retain = new Finalizable (); + retain.a = 0x1029458; + }); + thread.Start (); + thread.Join (); + GC.Collect (0); + GC.Collect (); + GC.WaitForPendingFinalizers (); + GC.WaitForPendingFinalizers (); + if (t.Obj != null) + return 1; + if (t.Obj2 != null) + return 2; + if (t.Obj3 == null) + return 3; + //overflow the nursery, make sure we fill it + for (int i = 0; i < 1000 * 1000 * 10; ++i) + new OneField (); + + if (retain.a != 0x1029458) + return 4; + + retain = null; + GC.Collect (); + GC.WaitForPendingFinalizers (); + GC.WaitForPendingFinalizers (); + if (t.Obj4 != null) + return 5; + + return 0; + } + +} diff --git a/mono/tests/weakattribute.cs b/mono/tests/weakattribute.cs new file mode 100644 index 000000000000..ed1875cb9521 --- /dev/null +++ b/mono/tests/weakattribute.cs @@ -0,0 +1,10 @@ +using System; + +namespace System { + +[AttributeUsage(AttributeTargets.Field)] +public sealed class WeakAttribute : Attribute +{ +} + +} diff --git a/mono/utils/lock-free-alloc.c b/mono/utils/lock-free-alloc.c index 6394061f7531..4f154d2a5003 100644 --- a/mono/utils/lock-free-alloc.c +++ b/mono/utils/lock-free-alloc.c @@ -415,6 +415,8 @@ alloc_from_new_sb (MonoLockFreeAllocator *heap) for (i = 1; i < count - 1; ++i) *(unsigned int*)((char*)desc->sb + i * slot_size) = i + 1; + *(unsigned int*)((char*)desc->sb + (count - 1) * slot_size) = 0; + mono_memory_write_barrier (); /* Make it active or free it again. */ diff --git a/mono/utils/mono-context.c b/mono/utils/mono-context.c index 134963818239..4dfbbb34163e 100644 --- a/mono/utils/mono-context.c +++ b/mono/utils/mono-context.c @@ -233,6 +233,27 @@ mono_sigctx_to_monoctx (void *sigctx, MonoContext *mctx) mctx->gregs [AMD64_R13] = context->R13; mctx->gregs [AMD64_R14] = context->R14; mctx->gregs [AMD64_R15] = context->R15; +#elif defined(__HAIKU__) + // Haiku uses sigcontext because there's no ucontext + struct sigcontext *ctx = (struct sigcontext *)sigctx; + + mctx->gregs [AMD64_RIP] = ctx->regs.rip; + mctx->gregs [AMD64_RAX] = ctx->regs.rax; + mctx->gregs [AMD64_RCX] = ctx->regs.rcx; + mctx->gregs [AMD64_RDX] = ctx->regs.rdx; + mctx->gregs [AMD64_RBX] = ctx->regs.rbx; + mctx->gregs [AMD64_RSP] = ctx->regs.rsp; + mctx->gregs [AMD64_RBP] = ctx->regs.rbp; + mctx->gregs [AMD64_RSI] = ctx->regs.rsi; + mctx->gregs [AMD64_RDI] = ctx->regs.rdi; + mctx->gregs [AMD64_R8] = ctx->regs.r8; + mctx->gregs [AMD64_R9] = ctx->regs.r9; + mctx->gregs [AMD64_R10] = ctx->regs.r10; + mctx->gregs [AMD64_R11] = ctx->regs.r11; + mctx->gregs [AMD64_R12] = ctx->regs.r12; + mctx->gregs [AMD64_R13] = ctx->regs.r13; + mctx->gregs [AMD64_R14] = ctx->regs.r14; + mctx->gregs [AMD64_R15] = ctx->regs.r15; #else g_assert_not_reached (); #endif @@ -305,6 +326,27 @@ mono_monoctx_to_sigctx (MonoContext *mctx, void *sigctx) context->R13 = mctx->gregs [AMD64_R13]; context->R14 = mctx->gregs [AMD64_R14]; context->R15 = mctx->gregs [AMD64_R15]; +#elif defined(__HAIKU__) + // Haiku uses sigcontext because there's no ucontext + struct sigcontext *ctx = (struct sigcontext *)sigctx; + + ctx->regs.rip = mctx->gregs [AMD64_RIP]; + ctx->regs.rax = mctx->gregs [AMD64_RAX]; + ctx->regs.rcx = mctx->gregs [AMD64_RCX]; + ctx->regs.rdx = mctx->gregs [AMD64_RDX]; + ctx->regs.rbx = mctx->gregs [AMD64_RBX]; + ctx->regs.rsp = mctx->gregs [AMD64_RSP]; + ctx->regs.rbp = mctx->gregs [AMD64_RBP]; + ctx->regs.rsi = mctx->gregs [AMD64_RSI]; + ctx->regs.rdi = mctx->gregs [AMD64_RDI]; + ctx->regs.r8 = mctx->gregs [AMD64_R8]; + ctx->regs.r9 = mctx->gregs [AMD64_R9]; + ctx->regs.r10 = mctx->gregs [AMD64_R10]; + ctx->regs.r11 = mctx->gregs [AMD64_R11]; + ctx->regs.r12 = mctx->gregs [AMD64_R12]; + ctx->regs.r13 = mctx->gregs [AMD64_R13]; + ctx->regs.r14 = mctx->gregs [AMD64_R14]; + ctx->regs.r15 = mctx->gregs [AMD64_R15]; #else g_assert_not_reached (); #endif diff --git a/mono/utils/mono-context.h b/mono/utils/mono-context.h index fa4ce7effd12..10f6fc1df46a 100644 --- a/mono/utils/mono-context.h +++ b/mono/utils/mono-context.h @@ -247,12 +247,23 @@ typedef struct { #if !defined( HOST_WIN32 ) -#if defined(HAVE_SIGACTION) || defined(__APPLE__) // the __APPLE__ check is required for the tvos simulator, which has ucontext_t but not sigaction +// the __APPLE__ check is required for the tvos simulator, which has ucontext_t but not sigaction +#if defined(HAVE_SIGACTION) || defined(__APPLE__) #define MONO_SIGNAL_USE_UCONTEXT_T 1 #endif #endif +#ifdef __HAIKU__ +/* sigcontext surrogate */ +struct sigcontext { + vregs regs; +}; + +// Haiku doesn't support this +#undef MONO_SIGNAL_USE_UCONTEXT_T +#endif + typedef struct { mgreg_t gregs [AMD64_NREG]; #if defined(__APPLE__) || (defined(__linux__) && defined(__GLIBC__)) || defined(HOST_WIN32) diff --git a/mono/utils/mono-logger-internals.h b/mono/utils/mono-logger-internals.h index 596537eae2a2..3da9f1cac305 100644 --- a/mono/utils/mono-logger-internals.h +++ b/mono/utils/mono-logger-internals.h @@ -12,18 +12,22 @@ G_BEGIN_DECLS typedef enum { - MONO_TRACE_ASSEMBLY = (gint32)(1 << 0), - MONO_TRACE_TYPE = (gint32)(1 << 1), - MONO_TRACE_DLLIMPORT = (gint32)(1 << 2), - MONO_TRACE_GC = (gint32)(1 << 3), - MONO_TRACE_CONFIG = (gint32)(1 << 4), - MONO_TRACE_AOT = (gint32)(1 << 5), - MONO_TRACE_SECURITY = (gint32)(1 << 6), - MONO_TRACE_THREADPOOL = (gint32)(1 << 7), - MONO_TRACE_IO_THREADPOOL = (gint32)(1 << 8), - MONO_TRACE_IO_LAYER = (gint32)(1 << 9), - MONO_TRACE_W32HANDLE = (gint32)(1 << 10), - MONO_TRACE_ALL = ~(gint32)(0) + MONO_TRACE_ASSEMBLY = 1 << 0, + MONO_TRACE_TYPE = 1 << 1, + MONO_TRACE_DLLIMPORT = 1 << 2, + MONO_TRACE_GC = 1 << 3, + MONO_TRACE_CONFIG = 1 << 4, + MONO_TRACE_AOT = 1 << 5, + MONO_TRACE_SECURITY = 1 << 6, + MONO_TRACE_THREADPOOL = 1 << 7, + MONO_TRACE_IO_SELECTOR = 1 << 8, + MONO_TRACE_IO_LAYER_PROCESS = 1 << 9, + MONO_TRACE_IO_LAYER_SOCKET = 1 << 10, + MONO_TRACE_IO_LAYER_FILE = 1 << 11, + MONO_TRACE_IO_LAYER_EVENT = 1 << 12, + MONO_TRACE_IO_LAYER_SEMAPHORE = 1 << 13, + MONO_TRACE_IO_LAYER_MUTEX = 1 << 14, + MONO_TRACE_IO_LAYER_HANDLE = 1 << 15, } MonoTraceMask; MONO_API extern GLogLevelFlags mono_internal_current_level; @@ -56,7 +60,7 @@ mono_trace_is_traced (GLogLevelFlags level, MonoTraceMask mask); G_GNUC_UNUSED static void mono_tracev (GLogLevelFlags level, MonoTraceMask mask, const char *format, va_list args) { - if(G_UNLIKELY (level <= mono_internal_current_level && mask & mono_internal_current_mask)) + if(G_UNLIKELY (level <= mono_internal_current_level && (mask & mono_internal_current_mask))) mono_tracev_inner (level, mask, format, args); } @@ -72,7 +76,7 @@ mono_tracev (GLogLevelFlags level, MonoTraceMask mask, const char *format, va_li G_GNUC_UNUSED MONO_ATTR_FORMAT_PRINTF(3,4) static void mono_trace (GLogLevelFlags level, MonoTraceMask mask, const char *format, ...) { - if(G_UNLIKELY (level <= mono_internal_current_level && mask & mono_internal_current_mask)) { + if(G_UNLIKELY (level <= mono_internal_current_level && (mask & mono_internal_current_mask))) { va_list args; va_start (args, format); mono_tracev_inner (level, mask, format, args); diff --git a/mono/utils/mono-logger.c b/mono/utils/mono-logger.c index d8d9e82ee44a..dc428bfc39d9 100644 --- a/mono/utils/mono-logger.c +++ b/mono/utils/mono-logger.c @@ -16,7 +16,7 @@ typedef struct { } MonoLogLevelEntry; GLogLevelFlags mono_internal_current_level = INT_MAX; -MonoTraceMask mono_internal_current_mask = MONO_TRACE_ALL; +MonoTraceMask mono_internal_current_mask = ~((MonoTraceMask)0); gboolean mono_trace_log_header = FALSE; static GQueue *level_stack = NULL; @@ -276,11 +276,37 @@ mono_trace_set_mask_string (const char *value) const char *tok; guint32 flags = 0; - const char *valid_flags[] = {"asm", "type", "dll", "gc", "cfg", "aot", "security", "threadpool", "io-threadpool", "io-layer", "w32handle", "all", NULL}; - const MonoTraceMask valid_masks[] = {MONO_TRACE_ASSEMBLY, MONO_TRACE_TYPE, MONO_TRACE_DLLIMPORT, - MONO_TRACE_GC, MONO_TRACE_CONFIG, MONO_TRACE_AOT, MONO_TRACE_SECURITY, - MONO_TRACE_THREADPOOL, MONO_TRACE_IO_THREADPOOL, MONO_TRACE_IO_LAYER, - MONO_TRACE_W32HANDLE, MONO_TRACE_ALL }; + static const struct { const char * const flag; const MonoTraceMask mask; } flag_mask_map[] = { + { "asm", MONO_TRACE_ASSEMBLY }, + { "type", MONO_TRACE_TYPE }, + { "dll", MONO_TRACE_DLLIMPORT }, + { "gc", MONO_TRACE_GC }, + { "cfg", MONO_TRACE_CONFIG }, + { "aot", MONO_TRACE_AOT }, + { "security", MONO_TRACE_SECURITY }, + { "threadpool", MONO_TRACE_THREADPOOL }, + { "io-threadpool", MONO_TRACE_IO_SELECTOR }, + { "io-selector", MONO_TRACE_IO_SELECTOR }, + { "io-layer-process", MONO_TRACE_IO_LAYER_PROCESS }, + { "io-layer-socket", MONO_TRACE_IO_LAYER_SOCKET }, + { "io-layer-file", MONO_TRACE_IO_LAYER_FILE }, + { "io-layer-console", MONO_TRACE_IO_LAYER_FILE }, + { "io-layer-pipe", MONO_TRACE_IO_LAYER_FILE }, + { "io-layer-event", MONO_TRACE_IO_LAYER_EVENT }, + { "io-layer-semaphore", MONO_TRACE_IO_LAYER_SEMAPHORE }, + { "io-layer-mutex", MONO_TRACE_IO_LAYER_MUTEX }, + { "io-layer-handle", MONO_TRACE_IO_LAYER_HANDLE }, + { "io-layer", MONO_TRACE_IO_LAYER_PROCESS + | MONO_TRACE_IO_LAYER_SOCKET + | MONO_TRACE_IO_LAYER_FILE + | MONO_TRACE_IO_LAYER_EVENT + | MONO_TRACE_IO_LAYER_SEMAPHORE + | MONO_TRACE_IO_LAYER_MUTEX + | MONO_TRACE_IO_LAYER_HANDLE }, + { "w32handle", MONO_TRACE_IO_LAYER_HANDLE }, + { "all", ~((MonoTraceMask)0) }, + { NULL, 0 }, + }; if(!value) return; @@ -292,15 +318,15 @@ mono_trace_set_mask_string (const char *value) tok++; continue; } - for (i = 0; valid_flags[i]; i++) { - size_t len = strlen (valid_flags[i]); - if (strncmp (tok, valid_flags[i], len) == 0 && (tok[len] == 0 || tok[len] == ',')) { - flags |= valid_masks[i]; + for (i = 0; flag_mask_map[i].flag; i++) { + size_t len = strlen (flag_mask_map[i].flag); + if (strncmp (tok, flag_mask_map[i].flag, len) == 0 && (tok[len] == 0 || tok[len] == ',')) { + flags |= flag_mask_map[i].mask; tok += len; break; } } - if (!valid_flags[i]) { + if (!flag_mask_map[i].flag) { g_print("Unknown trace flag: %s\n", tok); break; } @@ -317,7 +343,7 @@ mono_trace_set_mask_string (const char *value) gboolean mono_trace_is_traced (GLogLevelFlags level, MonoTraceMask mask) { - return (level <= mono_internal_current_level && mask & mono_internal_current_mask); + return (level <= mono_internal_current_level && (mask & mono_internal_current_mask)); } /** diff --git a/mono/utils/mono-mmap.c b/mono/utils/mono-mmap.c index b040751ff1dc..f4cbf6d84241 100644 --- a/mono/utils/mono-mmap.c +++ b/mono/utils/mono-mmap.c @@ -403,6 +403,8 @@ mono_valloc_aligned (size_t size, size_t alignment, int flags, MonoMemAccountTyp void *res = NULL; if (posix_memalign (&res, alignment, size)) return NULL; + + memset (res, 0, size); return res; } diff --git a/mono/utils/mono-os-mutex.h b/mono/utils/mono-os-mutex.h index eb7c4bb5b153..2f7da400d87e 100644 --- a/mono/utils/mono-os-mutex.h +++ b/mono/utils/mono-os-mutex.h @@ -41,7 +41,7 @@ G_BEGIN_DECLS #if !defined(HOST_WIN32) -#if !defined(CLOCK_MONOTONIC) || defined(HOST_DARWIN) || defined(HOST_ANDROID) +#if !defined(CLOCK_MONOTONIC) || defined(HOST_DARWIN) || defined(HOST_ANDROID) || defined(HOST_WASM) #define BROKEN_CLOCK_SOURCE #endif diff --git a/mono/utils/mono-threads-wasm.c b/mono/utils/mono-threads-wasm.c index 60816ed8d578..040903b04899 100644 --- a/mono/utils/mono-threads-wasm.c +++ b/mono/utils/mono-threads-wasm.c @@ -3,14 +3,40 @@ #include #include + #if defined (USE_WASM_BACKEND) +#include +#include + +#include +#include + #define round_down(addr, val) ((void*)((addr) & ~((val) - 1))) +EMSCRIPTEN_KEEPALIVE +static int +wasm_get_stack_base (void) +{ + return EM_ASM_INT ({ + return STACK_BASE; + }); +} + +EMSCRIPTEN_KEEPALIVE +static int +wasm_get_stack_size (void) +{ + return EM_ASM_INT ({ + return TOTAL_STACK; + }); +} + + int mono_threads_get_max_stack_size (void) { - return 65536 * 8; //totally arbitrary, this value is actually useless until WASM supports multiple threads. + return wasm_get_stack_size (); } @@ -104,15 +130,15 @@ mono_threads_platform_yield (void) void mono_threads_platform_get_stack_bounds (guint8 **staddr, size_t *stsize) { - *staddr = round_down ((size_t)&staddr, 65536); //WASM pagesize is 64k - *stsize = 65536 * 4; //we say it's 4 pages, there isn't much that uses this beyond the GC + *staddr = (void*)wasm_get_stack_base (); + *stsize = wasm_get_stack_size (); } gboolean mono_thread_platform_create_thread (MonoThreadStart thread_fn, gpointer thread_data, gsize* const stack_size, MonoNativeThreadId *tid) { - g_error ("WASM doesn't support threading"); + g_warning ("WASM doesn't support threading"); return FALSE; } @@ -132,4 +158,32 @@ mono_threads_platform_in_critical_region (MonoNativeThreadId tid) return FALSE; } + +extern void schedule_background_exec (void); + +static GSList *jobs; + +void +mono_threads_schedule_background_job (background_job_cb cb) +{ + if (!jobs) + schedule_background_exec (); + + if (!g_slist_find (jobs, cb)) + jobs = g_slist_prepend (jobs, cb); +} + +EMSCRIPTEN_KEEPALIVE void +mono_background_exec (void) +{ + GSList *j = jobs, *cur; + jobs = NULL; + + for (cur = j; cur; cur = cur->next) { + background_job_cb cb = (background_job_cb)cur->data; + cb (); + } + g_slist_free (j); +} + #endif diff --git a/mono/utils/mono-threads.h b/mono/utils/mono-threads.h index d08546531867..2cc3d54ff4fd 100644 --- a/mono/utils/mono-threads.h +++ b/mono/utils/mono-threads.h @@ -649,4 +649,10 @@ mono_thread_info_wait_multiple_handle (MonoThreadHandle **thread_handles, gsize void mono_threads_join_lock (void); void mono_threads_join_unlock (void); + +#ifdef HOST_WASM +typedef void (*background_job_cb)(void); +void mono_threads_schedule_background_job (background_job_cb cb); +#endif + #endif /* __MONO_THREADS_H__ */ diff --git a/msvc/libmini-common.targets b/msvc/libmini-common.targets index b201a6a1176d..624b41f0cace 100644 --- a/msvc/libmini-common.targets +++ b/msvc/libmini-common.targets @@ -70,6 +70,7 @@ + diff --git a/msvc/libmini-common.targets.filters b/msvc/libmini-common.targets.filters index 3d27a2447cf0..d2065a9b336f 100644 --- a/msvc/libmini-common.targets.filters +++ b/msvc/libmini-common.targets.filters @@ -208,6 +208,9 @@ Source Files$(MonoMiniFilterSubFolder)\common + + Source Files$(MonoMiniFilterSubFolder)\common + diff --git a/msvc/libmini-interp.targets b/msvc/libmini-interp.targets index bd9b821072ff..31ef8c03a231 100644 --- a/msvc/libmini-interp.targets +++ b/msvc/libmini-interp.targets @@ -8,9 +8,6 @@ - - $(ExcludeFromWindowsBuild) - diff --git a/msvc/libmini-interp.targets.filters b/msvc/libmini-interp.targets.filters index afe32ef5f94c..267a6baaaf91 100644 --- a/msvc/libmini-interp.targets.filters +++ b/msvc/libmini-interp.targets.filters @@ -13,9 +13,6 @@ Source Files$(MonoMiniFilterSubFolder)\interp - - Source Files$(MonoMiniFilterSubFolder)\interp - Header Files$(MonoMiniFilterSubFolder)\interp diff --git a/msvc/libmono-dynamic.vcxproj b/msvc/libmono-dynamic.vcxproj index 3743f43468ed..d63cc408b1e6 100644 --- a/msvc/libmono-dynamic.vcxproj +++ b/msvc/libmono-dynamic.vcxproj @@ -89,6 +89,12 @@ true + + false + + + false + @@ -104,6 +110,7 @@ 4996;4018;4244;%(DisableSpecificWarnings) Level3 true + 4716 _DEBUG;%(PreprocessorDefinitions) @@ -143,6 +150,7 @@ 4996;4018;4244;%(DisableSpecificWarnings) Level3 true + 4716 _DEBUG;%(PreprocessorDefinitions) @@ -176,6 +184,7 @@ Level3 + 4716 NDEBUG;%(PreprocessorDefinitions) @@ -215,6 +224,7 @@ Level3 + 4716 NDEBUG;%(PreprocessorDefinitions) diff --git a/msvc/libmonoruntime-unity.targets b/msvc/libmonoruntime-unity.targets index 1537b0610a30..4a7c19738af5 100644 --- a/msvc/libmonoruntime-unity.targets +++ b/msvc/libmonoruntime-unity.targets @@ -6,5 +6,6 @@ + diff --git a/msvc/libmonoruntime-unity.targets.filters b/msvc/libmonoruntime-unity.targets.filters index ebfb58fe7014..46ccf1069f0d 100644 --- a/msvc/libmonoruntime-unity.targets.filters +++ b/msvc/libmonoruntime-unity.targets.filters @@ -16,6 +16,10 @@ Header Files$(MonoRuntimeFilterSubFolder)\unity + + Source Files$(MonoRuntimeFilterSubFolder)\unity + + diff --git a/msvc/scripts/genproj.cs b/msvc/scripts/genproj.cs index 3987abb212b1..1e6b41108a78 100644 --- a/msvc/scripts/genproj.cs +++ b/msvc/scripts/genproj.cs @@ -756,7 +756,8 @@ public VsCsproj Generate (string library_output, Dictionary" + NewLine, src); } - sources.Remove (sources.Length - 1, 1); + if (sources.Length > 1) + sources.Remove (sources.Length - 1, 1); //if (library == "corlib-build") // otherwise, does not compile on fx_version == 4.0 //{ diff --git a/net_4_x.sln b/net_4_x.sln index 58b04b904f72..b9abc113c8ea 100644 --- a/net_4_x.sln +++ b/net_4_x.sln @@ -303,6 +303,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Reflection.Context-n EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Profiler.Log-net_4_x", "mcs/class/Mono.Profiler.Log/Mono.Profiler.Log-net_4_x.csproj", "{58A188CE-DED8-48B0-98B7-065A260D21DF}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Runtime.CompilerServices.Unsafe-net_4_x", "mcs/class/System.Runtime.CompilerServices.Unsafe/System.Runtime.CompilerServices.Unsafe-net_4_x.csproj", "{6C50BF24-90AB-4654-B295-16A1C717643C}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "legacy_Mono.Cecil-net_4_x", "mcs/class/legacy/Mono.Cecil/legacy_Mono.Cecil-net_4_x.csproj", "{CF1339E8-584B-4B3D-9A93-6F4AFDAFEE66}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Facades_System.Security.Cryptography.X509Certificates-net_4_x", "mcs/class/Facades/System.Security.Cryptography.X509Certificates/Facades_System.Security.Cryptography.X509Certificates-net_4_x.csproj", "{C2E71C2B-A806-4FEB-AE2D-A5BE884E3BA7}" @@ -1285,6 +1287,10 @@ Global {58A188CE-DED8-48B0-98B7-065A260D21DF}.Debug|Any CPU.Build.0 = Debug|Any CPU {58A188CE-DED8-48B0-98B7-065A260D21DF}.Release|Any CPU.ActiveCfg = Release|Any CPU {58A188CE-DED8-48B0-98B7-065A260D21DF}.Release|Any CPU.Build.0 = Release|Any CPU + {6C50BF24-90AB-4654-B295-16A1C717643C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6C50BF24-90AB-4654-B295-16A1C717643C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6C50BF24-90AB-4654-B295-16A1C717643C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6C50BF24-90AB-4654-B295-16A1C717643C}.Release|Any CPU.Build.0 = Release|Any CPU {CF1339E8-584B-4B3D-9A93-6F4AFDAFEE66}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CF1339E8-584B-4B3D-9A93-6F4AFDAFEE66}.Debug|Any CPU.Build.0 = Debug|Any CPU {CF1339E8-584B-4B3D-9A93-6F4AFDAFEE66}.Release|Any CPU.ActiveCfg = Release|Any CPU diff --git a/packaging/MacSDK/msbuild.py b/packaging/MacSDK/msbuild.py index ce0da39bbe09..99504f041c25 100644 --- a/packaging/MacSDK/msbuild.py +++ b/packaging/MacSDK/msbuild.py @@ -3,7 +3,7 @@ class MSBuild (GitHubPackage): def __init__ (self): GitHubPackage.__init__ (self, 'mono', 'msbuild', '15', # note: fix scripts/ci/run-test-mac-sdk.sh when bumping the version number - revision = '5bb588162eadfc68c6af8895397f4f65f8008b24') + revision = 'abbd02a3b0fa710c5a208b62bc0ba944b0a5badf') def build (self): self.sh ('./cibuild.sh --scope Compile --target Mono --host Mono --config Release') diff --git a/runtime/Makefile.am b/runtime/Makefile.am index dbb8a2624b0d..a96903ce9c20 100644 --- a/runtime/Makefile.am +++ b/runtime/Makefile.am @@ -138,7 +138,7 @@ PLATFORM_PATH_SEPARATOR = : endif # assemblies which are excluded from testing in mcs-compileall below -VERIFY_TESTS_FILTER = +VERIFY_TESTS_FILTER = System.Runtime.CompilerServices.Unsafe.dll if HOST_WIN32 # Mono.WebBrowser.dll fails to verify on Windows diff --git a/scripts/.gitignore b/scripts/.gitignore index 0c479324de92..952573b9274d 100644 --- a/scripts/.gitignore +++ b/scripts/.gitignore @@ -87,6 +87,7 @@ /sgen1 /signcode /csc +/vbc /sn /soapsuds /sqlmetal diff --git a/scripts/Makefile.am b/scripts/Makefile.am index 9f792fd13655..c647615d9e66 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -36,7 +36,8 @@ bin_SCRIPTS = \ mono-test-install \ peverify \ mcs \ - csc \ + csc \ + vbc \ csi \ mono-package-runtime \ mono-heapviz \ @@ -158,6 +159,7 @@ EXTRA_DIST = \ update_submodules.sh \ mcs.in \ csc.in \ + vbc.in \ dmcs.in \ csi.in \ mono-package-runtime \ @@ -208,6 +210,10 @@ csc: csc.in Makefile $(REWRITE_COMMON) $(srcdir)/csc.in > $@.tmp mv -f $@.tmp $@ +vbc: vbc.in Makefile + $(REWRITE_COMMON) $(srcdir)/vbc.in > $@.tmp + mv -f $@.tmp $@ + dmcs: dmcs.in Makefile $(REWRITE_COMMON) $(srcdir)/dmcs.in > $@.tmp mv -f $@.tmp $@ diff --git a/scripts/ci/run-test-default.sh b/scripts/ci/run-test-default.sh index e121a80d9eca..39c17a76a5cf 100755 --- a/scripts/ci/run-test-default.sh +++ b/scripts/ci/run-test-default.sh @@ -15,6 +15,7 @@ ${TESTCMD} --label=verify --timeout=15m make -w -C runtime mcs-compileall ${TESTCMD} --label=profiler --timeout=30m make -w -C mono/profiler -k check ${TESTCMD} --label=compiler --timeout=30m make -w -C mcs/tests run-test ${TESTCMD} --label=compiler-errors --timeout=30m make -w -C mcs/errors run-test +${TESTCMD} --label=System-xunit --timeout=5m make -w -C mcs/class/System run-xunit-test ${TESTCMD} --label=System --timeout=10m bash -c "export MONO_TLS_PROVIDER=legacy && make -w -C mcs/class/System run-test" if [[ ${label} == osx-* ]]; then ${TESTCMD} --label=System-btls --timeout=10m bash -c "export MONO_TLS_PROVIDER=btls && make -w -C mcs/class/System run-test"; fi ${TESTCMD} --label=System.XML --timeout=5m make -w -C mcs/class/System.XML run-test @@ -85,6 +86,8 @@ ${TESTCMD} --label=System.Xaml --timeout=5m make -w -C mcs/class/System.Xaml run ${TESTCMD} --label=System.Net.Http --timeout=5m make -w -C mcs/class/System.Net.Http run-test ${TESTCMD} --label=System.Json --timeout=5m make -w -C mcs/class/System.Json run-test ${TESTCMD} --label=System.Threading.Tasks.Dataflow --timeout=5m make -w -C mcs/class/System.Threading.Tasks.Dataflow run-test +# Due to https://bugzilla.xamarin.com/show_bug.cgi?id=60865 +if [[ ${label} == *i386 ]] || [[ ${label} == w32 ]] || [[ ${label} == *armel ]] || [[ ${label} == *armhf ]]; then ${TESTCMD} --label=System.Runtime.CompilerServices.Unsafe-xunit --skip; else ${TESTCMD} --label=System.Runtime.CompilerServices.Unsafe-xunit --timeout=5m make -w -C mcs/class/System.Runtime.CompilerServices.Unsafe run-xunit-test; fi ${TESTCMD} --label=Mono.Debugger.Soft --timeout=5m make -w -C mcs/class/Mono.Debugger.Soft run-test ${TESTCMD} --label=Microsoft.CSharp-xunit --timeout=5m make -w -C mcs/class/Microsoft.CSharp run-xunit-test ${TESTCMD} --label=Microsoft.Build --timeout=5m make -w -C mcs/class/Microsoft.Build run-test diff --git a/scripts/ci/run-test-mac-sdk.sh b/scripts/ci/run-test-mac-sdk.sh index 186fff5c28d5..22d73a312cd0 100755 --- a/scripts/ci/run-test-mac-sdk.sh +++ b/scripts/ci/run-test-mac-sdk.sh @@ -1,6 +1,6 @@ #!/bin/bash -e -${TESTCMD} --label=bockbuild --timeout=180m ${MONO_REPO_ROOT}/scripts/mac-sdk-package.sh +${TESTCMD} --label=bockbuild --timeout=180m --fatal ${MONO_REPO_ROOT}/scripts/mac-sdk-package.sh # switch to using package Mono instead of system export PATH=${MONO_REPO_ROOT}/external/bockbuild/stage/bin:$PATH diff --git a/scripts/mono-package-runtime b/scripts/mono-package-runtime index d71942ba0cfc..10e26f26930a 100755 --- a/scripts/mono-package-runtime +++ b/scripts/mono-package-runtime @@ -1,4 +1,8 @@ #!/bin/sh +extension=".dylib" +if test `uname -o` = GNU/Linux; then + extension=".so" +fi if test x$2 = x; then echo usage is: mono-package-runtime MONO_INSTALL_PREFIX LABEL @@ -31,6 +35,6 @@ fi o=`pwd`/$output cd $prefix -(zip -u $o.zip bin/mono lib/mono/4.5/mscorlib.dll lib/mono/4.5/System*dll lib/mono/4.5/Mono.CSharp.dll lib/mono/4.5/Microsoft*dll lib/mono/4.5/FSharp*.dll lib/mono/4.5/I18N*dll lib/mono/4.5/Accessibility.dll lib/mono/4.5/RabbitMQ.Client.dll lib/mono/4.5/ICSharpCode.SharpZipLib.dll lib/mono/4.5/CustomMarshalers.dll etc/mono/config etc/mono/4.5/machine.config etc/mono/4.5/web.config lib/mono/4.5/Mono.Cairo.dll lib/mono/4.5/Mono.Data.Sqlite.dll lib/mono/4.5/Mono.Posix.dll lib/mono/4.5/Mono.Security.*dll lib/mono/4.5/Mono.Simd.dll) +(zip -u $o.zip bin/mono lib/mono/4.5/mscorlib.dll lib/mono/4.5/System*dll lib/mono/4.5/Mono.CSharp.dll lib/mono/4.5/Microsoft*dll lib/mono/4.5/FSharp*.dll lib/mono/4.5/I18N*dll lib/mono/4.5/Accessibility.dll lib/mono/4.5/RabbitMQ.Client.dll lib/mono/4.5/ICSharpCode.SharpZipLib.dll lib/mono/4.5/CustomMarshalers.dll etc/mono/config etc/mono/4.5/machine.config etc/mono/4.5/web.config lib/mono/4.5/Mono.Cairo.dll lib/mono/4.5/Mono.Data.Sqlite.dll lib/mono/4.5/Mono.Posix.dll lib/mono/4.5/Mono.Security.*dll lib/mono/4.5/Mono.Simd.dll lib/libMonoSupportW$extension lib/libMonoPosixHelper$extension lib/libmono-btls-shared$extension) echo Created file $o.zip diff --git a/scripts/mono-service.in b/scripts/mono-service.in index f86087ec9c8c..539074b71540 100644 --- a/scripts/mono-service.in +++ b/scripts/mono-service.in @@ -33,7 +33,6 @@ if test x$assembly = x; then exit 1 fi -export MONO_DISABLE_SHM=1 if $debug; then exec @bindir@/@mono_interp@ $MONO_OPTIONS @mono_instdir@/@framework_version@/mono-service.exe $args else diff --git a/scripts/vbc.in b/scripts/vbc.in new file mode 100644 index 000000000000..7bdd70ecb480 --- /dev/null +++ b/scripts/vbc.in @@ -0,0 +1,2 @@ +#!/bin/sh +exec @bindir@/mono --gc-params=nursery-size=64m $MONO_OPTIONS @mono_instdir@/4.5/vbc.exe "$@" diff --git a/sdks/ios/Makefile b/sdks/ios/Makefile index 1de8fa7ef5c2..fe168f9ade8a 100644 --- a/sdks/ios/Makefile +++ b/sdks/ios/Makefile @@ -47,7 +47,7 @@ start-sim: stop-sim: xcrun simctl shutdown booted -NUNIT = nunit-lite-console.exe -exclude:MobileNotWorking,NotOnMac,NotWorking,ValueAdd,CAS,InetAccess,NotWorkingInterpreter -labels +NUNIT = nunit-lite-console.exe -exclude:MobileNotWorking,NotOnMac,NotWorking,ValueAdd,CAS,InetAccess,NotWorkingLinqInterpreter -labels TESTDIR = $(BCL_DIR)/tests # Options for each test diff --git a/sdks/paths.mk b/sdks/paths.mk index 8bb87ee3bc4f..d1dfd65b0c2f 100644 --- a/sdks/paths.mk +++ b/sdks/paths.mk @@ -1,3 +1,5 @@ +MAKEFLAGS += --no-builtin-rules + -include $(TOP)/sdks/Make.config ifndef DISABLE_ANDROID diff --git a/sdks/wasm/Makefile b/sdks/wasm/Makefile index dd0203e01d3a..f5f838785c61 100644 --- a/sdks/wasm/Makefile +++ b/sdks/wasm/Makefile @@ -33,13 +33,15 @@ MINI_TEST_FILES= \ mixed.cs \ gc-test.cs +APP_SOURCES = \ + main.cs \ + incrementalrunner.cs -BCL_INPUT_ASM = $(patsubst %,$(WASM_BCL_DIR)/%,$(BCL_ASSEMBLIES)) -BCL_OUTPUT_ASM = $(patsubst %,$(MANAGED_DEPLOY_DIR)/%,$(BCL_ASSEMBLIES)) -DEPS_FILES = $(patsubst %,$(MANAGED_DEPLOY_DIR)/%,$(DEPS_ASSEMBLIES)) +MINI_TEST_SOURCES = $(patsubst %,$(MINI_PATH)/%,$(MINI_TEST_FILES)) + +TEST_DEPS = $(patsubst %,managed/%,$(BCL_ASSEMBLIES)) managed/nunitlite.dll +TEST_MCS_DEPS = $(patsubst %,-r:%, $(TEST_DEPS)) -MINI_TEST_SOURCES= $(patsubst %,$(MINI_PATH)/%,$(MINI_TEST_FILES)) -MINI_TEST_DEPS= $(patsubst %,-r:%,$(BCL_OUTPUT_ASM) $(DEPS_FILES)) .stamp-depot-tools: git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git depot_tools @@ -58,33 +60,39 @@ driver.o: driver.c $(EMCC) -g -Os -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s BINARYEN=1 -s "BINARYEN_TRAP_MODE='clamp'" -s TOTAL_MEMORY=134217728 -s ALIASING_FUNCTION_POINTERS=0 driver.c -c -o driver.o mono.js: driver.o library_mono.js $(TOP)/sdks/out/wasm-interp/lib/libmonosgen-2.0.a - $(EMCC) -g4 -Os -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s BINARYEN=1 -s "BINARYEN_TRAP_MODE='clamp'" -s TOTAL_MEMORY=134217728 -s ALIASING_FUNCTION_POINTERS=0 --js-library library_mono.js driver.o $(TOP)/sdks/out/wasm-interp/lib/libmonosgen-2.0.a -o mono.js + $(EMCC) -g4 -Os -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s BINARYEN=1 -s "BINARYEN_TRAP_MODE='clamp'" -s TOTAL_MEMORY=134217728 -s ALIASING_FUNCTION_POINTERS=0 -s ASSERTIONS=2 --js-library library_mono.js driver.o $(TOP)/sdks/out/wasm-interp/lib/libmonosgen-2.0.a -o mono.js build-native: mono.js -#FIXME some Make magic here would be appreciated -.stamp-copy-bcl: $(TOP)/sdks/wasm/managed $(BCL_INPUT_ASM) - mkdir -p managed/ - cp $(BCL_INPUT_ASM) managed/ - touch $@ - -managed/main.exe: main.cs .stamp-copy-bcl managed/nunitlite.dll - mcs /nostdlib /unsafe main.cs -r:managed/nunitlite.dll $(MINI_TEST_DEPS) -out:managed/main.exe +managed/: + mkdir -p $@ -managed/mini_tests.dll: $(MINI_TEST_SOURCES) mini-test-runner.cs .stamp-copy-bcl managed/nunitlite.dll - mcs /nostdlib /unsafe -target:library -out:managed/mini_tests.dll -define:__MOBILE__,ARCH_32 $(MINI_TEST_DEPS) $(MINI_TEST_SOURCES) mini-test-runner.cs +$(patsubst %,managed/%,$(BCL_ASSEMBLIES)): managed/%: $(WASM_BCL_DIR)/% | managed/ + cp $< $@ -managed/nunitlite.dll: $(TOP)/mcs/class/lib/wasm/nunitlite.dll +#FIXME change BCL sdk build to include nunitlite.dll in out/bcl/wasm/ +managed/nunitlite.dll: $(TOP)/mcs/class/lib/wasm/nunitlite.dll | managed/ cd $(TOP)/mcs/tools/nunit-lite && make PROFILE=wasm - cp $< $@ + cp $< $@ -build-managed: .stamp-copy-bcl managed/nunitlite.dll managed/mini_tests.dll managed/main.exe +managed/main.exe: $(TEST_DEPS) $(APP_SOURCES) | managed/ + mcs /nostdlib /unsafe -out:$@ $(TEST_MCS_DEPS) $(APP_SOURCES) -build: build-native build-managed +$(TOP)/mcs/class/lib/wasm/tests/wasm_corlib_test.dll: + cd $(TOP)/mcs/class/corlib && make test-local PROFILE=wasm +managed/wasm_corlib_test.dll: $(TOP)/mcs/class/lib/wasm/tests/wasm_corlib_test.dll + cp $< $@ + +managed/mini_tests.dll: $(TEST_DEPS) $(MINI_TEST_SOURCES) mini-test-runner.cs | managed/ + mcs /nostdlib /unsafe -target:library -out:$@ -define:__MOBILE__,ARCH_32 $(TEST_MCS_DEPS) $(MINI_TEST_SOURCES) mini-test-runner.cs + +build-managed: managed/nunitlite.dll managed/mini_tests.dll managed/wasm_corlib_test.dll managed/main.exe + +build: build-native build-managed -run: toolchain build - $(D8) --expose_wasm test.js +run-%: toolchain build + $(D8) --expose_wasm test.js -- $* clean: diff --git a/sdks/wasm/driver.c b/sdks/wasm/driver.c index 8f7e9efa222d..42d03fe561d2 100644 --- a/sdks/wasm/driver.c +++ b/sdks/wasm/driver.c @@ -123,8 +123,8 @@ mono_wasm_invoke_js (MonoString *str, int *is_exception) EMSCRIPTEN_KEEPALIVE void mono_wasm_load_runtime (const char *managed_path) { - // monoeg_g_setenv ("MONO_LOG_LEVEL", "debug", 1); - // monoeg_g_setenv ("MONO_LOG_MASK", "gc", 1); + monoeg_g_setenv ("MONO_LOG_LEVEL", "debug", 1); + monoeg_g_setenv ("MONO_LOG_MASK", "gc", 1); mono_jit_set_aot_mode (MONO_AOT_MODE_INTERP_LLVMONLY); mono_set_assemblies_path (m_strdup (managed_path)); root_domain = mono_jit_init_version ("mono", "v4.0.30319"); diff --git a/sdks/wasm/incrementalrunner.cs b/sdks/wasm/incrementalrunner.cs new file mode 100644 index 000000000000..eea3f842b13b --- /dev/null +++ b/sdks/wasm/incrementalrunner.cs @@ -0,0 +1,344 @@ +using System; +using System.Reflection; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; +using System.Diagnostics; + + +using NUnit.Framework; +using NUnit.Framework.Internal; +using NUnit.Framework.Api; +using NUnit.Framework.Internal.Filters; +using NUnitLite.Runner; + + +public class MyListener : ITestListener +{ + int scount, count; + public void TestStarted(ITest test) + { + if (test.IsSuite) + ++scount; + else + ++count; + if (!test.IsSuite) + Console.WriteLine ("{0} {1}/{2}", test.Name, scount, count); + } + + public void TestFinished(ITestResult result) + { + } + + public void TestOutput(TestOutput testOutput) + { + } +} + +class AbstractAction { + internal TestExecutionContext context, initialCtx; + internal TestResult testResult; + internal IncrementalTestRunner runner; + Test test; + AbstractAction parent; + + internal AbstractAction (Test test, AbstractAction parent, IncrementalTestRunner runner) + { + this.test = test; + this.runner = runner; + this.parent = parent; + this.initialCtx = parent.context; + this.testResult = test.MakeTestResult (); + } + + internal AbstractAction (Test test, TestExecutionContext initialCtx, IncrementalTestRunner runner) + { + this.test = test; + this.runner = runner; + this.initialCtx = initialCtx; + this.testResult = test.MakeTestResult (); + } + + protected void SetupContext () { + this.context = new TestExecutionContext (this.initialCtx); + this.context.CurrentTest = this.test; + this.context.CurrentResult = this.testResult; + ((ITestListener)IncrementalTestRunner.listener.GetValue (this.context)).TestStarted (this.test); + this.context.StartTime = DateTime.Now; + + IncrementalTestRunner.setCurrentContext.Invoke (null, new object[] { this.context }); + + long startTicks = Stopwatch.GetTimestamp(); + runner.finallyDelegate.Set (context, startTicks, testResult); + } + + protected void WorkItemComplete () + { + if (this.parent != null) + this.parent.testResult.AddResult (testResult); + + runner.finallyDelegate.Complete (); + // _state = WorkItemState.Complete; + // if (Completed != null) + // Completed(this, EventArgs.Empty); + } +} + +class TestAction : AbstractAction { + TestMethod test; + + public TestAction (TestMethod test, AbstractAction parent, IncrementalTestRunner runner) : base (test, parent, runner) + { + this.test = test; + } + + public void PerformWork () { + SetupContext (); + try + { + testResult = test.MakeTestCommand ().Execute(this.context); + } + finally + { + WorkItemComplete (); + } + } +} + +class TestSuiteAction : AbstractAction { + TestSuite testSuite; + List children; + + public TestSuiteAction (TestSuite test, AbstractAction parent, IncrementalTestRunner runner) : base (test, parent, runner) + { + this.testSuite = test; + } + + public TestSuiteAction (TestSuite test, TestExecutionContext initialCtx, IncrementalTestRunner runner) : base (test, initialCtx, runner) + { + this.testSuite = test; + } + + void EnqueueChildren () { + foreach (var t in children) { + if (t is TestSuite) { + var a = new TestSuiteAction ((TestSuite)t, this, runner); + runner.actions.Enqueue (a.PerformWork); + } else { + var a = new TestAction ((TestMethod)t, this, runner); + runner.actions.Enqueue (a.PerformWork); + } + } + } + + private void SkipChildren () + { + foreach (var t in children) { + TestResult result = ((Test)t).MakeTestResult (); + if (testResult.ResultState.Status == TestStatus.Failed) + result.SetResult (ResultState.Failure, "TestFixtureSetUp Failed"); + else + result.SetResult (testResult.ResultState, testResult.Message); + testResult.AddResult (result); + } + } + + void SkipFixture (ResultState resultState, string message, string stackTrace) + { + testResult.SetResult (resultState, message, stackTrace); + SkipChildren (); + } + + private string GetSkipReason() + { + return (string)testSuite.Properties.Get(PropertyNames.SkipReason); + } + + private string GetProviderStackTrace() + { + return (string)testSuite.Properties.Get(PropertyNames.ProviderStackTrace); + } + + public void PerformWork () { + SetupContext (); + + children = new List (); + + if (testSuite.HasChildren) { + foreach (Test test in testSuite.Tests) { + if (runner.filter.Pass(test)) + children.Add (test); + } + } + + switch (testSuite.RunState) { + default: + case RunState.Runnable: + case RunState.Explicit: + testResult.SetResult (ResultState.Success); + PerformOneTimeSetUp (); + + if (children.Count > 0) { + switch (testResult.ResultState.Status) + { + case TestStatus.Passed: + EnqueueChildren (); + break; + + case TestStatus.Skipped: + case TestStatus.Inconclusive: + case TestStatus.Failed: + SkipChildren (); + break; + } + } + + //all action enqueuing actions have already run, now it's ok to enqueue this. + runner.actions.Enqueue (() => runner.actions.Enqueue (this.PerformOneTimeTearDown)); + break; + + case RunState.Skipped: + SkipFixture (ResultState.Skipped, GetSkipReason(), null); + break; + + case RunState.Ignored: + SkipFixture (ResultState.Ignored, GetSkipReason(), null); + break; + + case RunState.NotRunnable: + SkipFixture (ResultState.NotRunnable, GetSkipReason(), GetProviderStackTrace()); + break; + } + + //all action enqueuing actions have already run, now it's ok to enqueue this. + runner.actions.Enqueue (() => runner.actions.Enqueue (this.WorkItemComplete)); + } + + private void PerformOneTimeTearDown () + { + IncrementalTestRunner.setCurrentContext.Invoke (null, new object[] { this.context }); + testSuite.GetOneTimeTearDownCommand ().Execute(this.context); + } + + private void PerformOneTimeSetUp () + { + try + { + testSuite.GetOneTimeSetUpCommand().Execute(this.context); + + // SetUp may have changed some things + this.context.UpdateContext(); + } + catch (Exception ex) + { + if (ex is NUnitException || ex is System.Reflection.TargetInvocationException) + ex = ex.InnerException; + + testResult.RecordException (ex); + } + } +} + +public class IncrementalTestRunner { + internal static PropertyInfo listener = typeof (TestExecutionContext).GetProperty ("Listener", BindingFlags.Instance | BindingFlags.NonPublic); + internal static MethodInfo setCurrentContext = typeof (TestExecutionContext).GetMethod ("SetCurrentContext", BindingFlags.Static | BindingFlags.NonPublic); + + IDictionary loadOptions; + internal ITestFilter filter = TestFilter.Empty; + UnhandledExceptionEventHandler crashHandler; + + internal FinallyDelegate finallyDelegate; + ITestAssemblyBuilder builder; + // ITestAssemblyRunner runner; + + public IncrementalTestRunner () { + this.finallyDelegate = new FinallyDelegate(); + this.builder = new NUnitLiteTestAssemblyBuilder(); + // this.runner = new NUnitLiteTestAssemblyRunner(new NUnitLiteTestAssemblyBuilder(), finallyDelegate); + + this.loadOptions = new Hashtable (); + } + + + TestSuite testSuite; + + public void Add (Assembly assembly) { + testSuite = builder.Build (assembly, loadOptions); + if (testSuite == null) + throw new Exception ("Could not load " + assembly); + // if (!runner.Load (assembly, loadOptions)) + // throw new Exception ("Could not load " + assembly); + } + + public void Exclude (string categories) { + var excludeFilter = new NotFilter (new SimpleCategoryExpression(categories).Filter); + filter = And (filter, excludeFilter); + } + + public void RunOnly (string testName) { + var nameFilter = new SimpleNameFilter (testName); + filter = And (filter, nameFilter); + } + + internal Queue actions = new Queue (); + int test_step_count; + + TestSuiteAction rootAction; + void QueueActions (TestSuite suite) { + TestExecutionContext context = new TestExecutionContext (); + if (this.loadOptions.Contains ("WorkDirectory")) + context.WorkDirectory = (string)this.loadOptions ["WorkDirectory"]; + else + context.WorkDirectory = Environment.CurrentDirectory; + + listener.SetValue (context, new MyListener ()); + rootAction = new TestSuiteAction (suite, context, this); + actions.Enqueue (rootAction.PerformWork); + } + + public void Start (int step) { + if (actions.Count > 0) + throw new Exception ("Test already started"); + + crashHandler = new UnhandledExceptionEventHandler(TopLevelHandler); + AppDomain.CurrentDomain.UnhandledException += crashHandler; + + this.test_step_count = step; + QueueActions (testSuite); + } + + public bool Step () { + int remaining = test_step_count; + + while (actions.Count > 0 && remaining > 0) { + var a = actions.Dequeue (); + a (); + --remaining; + } + + if (actions.Count == 0) { + new ResultReporter (rootAction.testResult, Console.Out).ReportResults (); + return false; + } + + return true; + } + + void TopLevelHandler(object sender, UnhandledExceptionEventArgs e) + { + // Make sure that the test harness knows this exception was thrown + if (finallyDelegate != null) + finallyDelegate.HandleUnhandledExc(e.ExceptionObject as Exception); + } + + static ITestFilter And (ITestFilter filter, ITestFilter other) { + if (filter.IsEmpty) + filter = other; + else if (filter is AndFilter) + ((AndFilter)filter).Add(other); + else + filter = new AndFilter(filter, other); + return filter; + } +} \ No newline at end of file diff --git a/sdks/wasm/library_mono.js b/sdks/wasm/library_mono.js index cb0c786085f5..d5c5082b1ec8 100644 --- a/sdks/wasm/library_mono.js +++ b/sdks/wasm/library_mono.js @@ -6,12 +6,12 @@ var MonoSupportLib = { pump_message: function () { while (MONO.pump_count > 0) { --MONO.pump_count; - Module.ccall ("mono_gc_pump_callback"); + Module.ccall ("mono_background_exec"); } } }, - request_gc_cycle: function () { + schedule_background_exec: function () { ++MONO.pump_count; if (ENVIRONMENT_IS_WEB) { window.setTimeout (MONO.pump_message, 0); diff --git a/sdks/wasm/main.cs b/sdks/wasm/main.cs index fe1e3a8c1219..89cb9fe11707 100644 --- a/sdks/wasm/main.cs +++ b/sdks/wasm/main.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading; +using System.Threading.Tasks; using System.Reflection; using NUnitLite.Runner; using NUnit.Framework.Internal; @@ -10,12 +11,6 @@ using System.Runtime.InteropServices; using System.Runtime.CompilerServices; - -public class MyRunner : TextUI, ITestListener -{ - public String failed_tests = ""; -} - namespace WebAssembly { public sealed class Runtime { [MethodImplAttribute (MethodImplOptions.InternalCall)] @@ -42,37 +37,86 @@ static void Main () { Send ("run", "mini"); } + + static int step_count, tp_pump_count; + static Task cur_task; + + static void TPStart () { + var l = new List (); + for (int i = 0; i < 10; ++i) { + l.Add (Task.Run (() => { + ++step_count; + })); + } + cur_task = Task.WhenAll (l).ContinueWith (t => { + }); + } + + static bool TPPump () { + if (tp_pump_count > 10) { + Console.WriteLine ("Pumped the TP test 10 times and no progress giving up"); + return false; + } + tp_pump_count++; + return !cur_task.IsCompleted; + } + + + static Action dele; + static IAsyncResult dele_result; + static void BeginSomething () { + } + + static void DeleStart () + { + dele = new Action (BeginSomething); + dele_result = dele.BeginInvoke (null, null); + } + + static bool DelePump () + { + if (dele_result.IsCompleted) { + dele.EndInvoke (dele_result); + return false; + } + return true; + } + + + static int fin_count; + interface IFoo {} + class Foo : IFoo { + ~Foo () { + ++fin_count; + } + } + static void GcStart () + { + IFoo[] arr = new IFoo [10]; + Volatile.Write (ref arr [1], new Foo ()); + for (int i = 0; i < 100; ++i) { + var x = new Foo (); + } + } + + static bool GcPump () + { + GC.Collect (); + return fin_count < 100; + } + + static int run_count; public static string Send (string key, string val) { - if (key == "say") { - if (val == "hello") { - return "OK:" + WebAssembly.Runtime.InvokeJS ("1 + 2"); - } else if (val == "js-exception") { - try { - return "OK:" + WebAssembly.Runtime.InvokeJS ("throw 1"); - } catch (WebAssembly.JSException e) { - Console.WriteLine (e.Message); - return "EH:" + e.Message; - } - } else if (val == "sharp-exception") { - throw new Exception ("error!"); - } + if (key == "start-test") { + StartTest (val); + return "SUCCESS"; } - - if (key != "run") - return "INVALID-ARG"; - if (val == "gc") { - Console.WriteLine ("running {0} step", run_count); - for (int i = 0; i < 1000 * 2; ++i) { - var x = new object [1000]; - } - ++run_count; - return run_count >= 10 ? "DONE" : "IN PROGRESS"; + if (key == "pump-test") { + return PumpTest (val) ? "IN-PROGRESS" : "DONE" ; } - StartTest (val); - return "SUCCESS"; - return "FAIL"; + return "INVALID-KEY"; } public class TestSuite { @@ -82,12 +126,50 @@ public class TestSuite { static TestSuite[] suites = new TestSuite [] { new TestSuite () { Name = "mini", File = "managed/mini_tests.dll" }, - new TestSuite () { Name = "corlib", File = "monodroid_corlib_test.dll" }, - new TestSuite () { Name = "system", File = "monodroid_System_test.dll" }, + new TestSuite () { Name = "corlib", File = "managed/wasm_corlib_test.dll" }, + new TestSuite () { Name = "system", File = "managed/wasm_System_test.dll" }, }; + static IncrementalTestRunner testRunner; + + public static bool PumpTest (string name) { + if (name == "tp") + return TPPump (); + if (name == "dele") + return DelePump (); + if (name == "gc") + return GcPump (); + + if (testRunner == null) + return false; + try { + bool res = testRunner.Step (); + if (!res) + testRunner = null; + return res; + } catch (Exception e) { + Console.WriteLine (e); + return true; + } + } + public static void StartTest (string name) { var baseDir = AppDomain.CurrentDomain.BaseDirectory; + if (testRunner != null) + throw new Exception ("Test in progress"); + + if (name == "tp") { + TPStart (); + return; + } + if (name == "dele") { + DeleStart (); + return; + } + if (name == "gc") { + GcStart (); + return; + } string extra_disable = ""; @@ -106,16 +188,16 @@ public static void StartTest (string name) { test_name = args [i]; } - var arg_list = new List (); - arg_list.Add ("-labels"); - if (test_name != null) - arg_list.Add ("-test=" + test_name); + testRunner = new IncrementalTestRunner (); + // testRunner.PrintLabels (); + // if (test_name != null) + // testRunner.RunTest (test_name); - arg_list.Add ("-exclude=WASM,NotWorking,ValueAdd,CAS,InetAccess"); - arg_list.Add (baseDir + "/" + testsuite_name); + testRunner.Exclude ("WASM,NotWorking,ValueAdd,CAS,InetAccess,InterpreterNotWorking,MultiThreaded"); + testRunner.Add (Assembly.LoadFrom (baseDir + "/" + testsuite_name)); + // testRunner.RunOnly ("MonoTests.System.Threading.AutoResetEventTest.MultipleSet"); - var runner = new MyRunner (); - runner.Execute (arg_list.ToArray ()); + testRunner.Start (10); } } diff --git a/sdks/wasm/test.js b/sdks/wasm/test.js index 89132e7645e8..ceed96b89c36 100644 --- a/sdks/wasm/test.js +++ b/sdks/wasm/test.js @@ -35,7 +35,7 @@ var Module = { }, }; -var assemblies = [ "mscorlib.dll", "System.dll", "System.Core.dll", "main.exe", "nunitlite.dll", "mini_tests.dll"]; +var assemblies = [ "mscorlib.dll", "System.dll", "System.Core.dll", "main.exe", "nunitlite.dll", "mini_tests.dll", "wasm_corlib_test.dll"]; load ("mono.js"); Module.finish_loading (); @@ -91,8 +91,13 @@ function conv_string (mono_obj) { return res; } -function cs_eval (str) { - return conv_string (call_method (send_message, null, [mono_string ("eval"), mono_string (str)])) +function mono_send_msg (key, val) { + try { + return conv_string (call_method (send_message, null, [mono_string (key), mono_string (val)])); + } catch (e) { + print ("BAD SEND MSG: " + e); + return null; + } } load_runtime ("managed"); @@ -100,6 +105,7 @@ var main_module = assembly_load ("main") if (!main_module) throw 1; + var driver_class = find_class (main_module, "", "Driver") if (!driver_class) throw 2; @@ -110,31 +116,15 @@ if (!send_message) print ("-----LOADED ----"); -var res = call_method (send_message, null, [mono_string ("run"), mono_string ("mini")]) -if (res) - print ("TEST RUN: " + conv_string (res)) - -do { - res = conv_string (call_method (send_message, null, [mono_string ("run"), mono_string ("gc")])) - Module.pump_message (); -} while (res == "IN PROGRESS"); -print ("DONE") - +for (var i = 0; i < arguments.length; ++i) { + var res = mono_send_msg ("start-test", arguments [i]) + print ("-----STARTED " + arguments [i] + "---- " + res); -var res = call_method (send_message, null, [mono_string ("say"), mono_string ("hello")]) -res = conv_string (res); -if (res != "OK:3") - throw 4; - -var res = call_method (send_message, null, [mono_string ("say"), mono_string ("js-exception")]) -res = conv_string (res); -if (res != "EH:1") - throw 5; - -try { - call_method (send_message, null, [mono_string ("say"), mono_string ("sharp-exception")]) - print ("no exception??"); - throw 6; -} catch (e) { + if (res == "SUCCESS") { + while (mono_send_msg ("pump-test", arguments [i]) != "DONE") { + Module.pump_message (); + print ("|"); + } + print ("\nDONE") + } } - diff --git a/support/sys-time.c b/support/sys-time.c index 83afa0c8466b..4f5db9c8b226 100644 --- a/support/sys-time.c +++ b/support/sys-time.c @@ -10,6 +10,9 @@ #include #include #include +#ifdef __HAIKU__ +#include +#endif #include "map.h" #include "mph.h" @@ -47,11 +50,6 @@ Mono_Posix_Syscall_settimeofday ( struct Mono_Posix_Timeval *tv, struct Mono_Posix_Timezone *tz) { -#if defined(__HAIKU__) - /* FIXME: Haiku doesn't support this either, consider - using set_real_time_clock instead? */ - return -1; -#else struct timeval _tv = {0}; struct timeval *ptv = NULL; struct timezone _tz = {0}; @@ -69,10 +67,14 @@ Mono_Posix_Syscall_settimeofday ( ptz = &_tz; } +#ifdef __HAIKU__ + set_real_time_clock(ptv->tv_sec); + r = 0; +#else r = settimeofday (ptv, ptz); +#endif return r; -#endif } static inline struct timeval*