diff --git a/Makefile.am b/Makefile.am index 5976e456b4..7165f466e6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -144,9 +144,10 @@ update-llvm-version: update-solution-files: + (pushd msvc/scripts; rm genproj.exe; $(MAKE) genproj.exe; popd) $(MAKE) update-csproj $(MAKE) package-inputs - (cd msvc/scripts; $(MAKE) genproj.exe; mono genproj.exe $(GENPROJ_ARGS)) + (cd msvc/scripts; mono --debug genproj.exe $(GENPROJ_ARGS)) update-solution-files-with-tests: $(MAKE) "GENPROJ_ARGS=2012 true true" update-solution-files diff --git a/Makefile.in b/Makefile.in index a0ff1c491a..41a6250323 100644 --- a/Makefile.in +++ b/Makefile.in @@ -88,8 +88,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ ltmain.sh ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -278,6 +276,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -296,7 +295,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -310,7 +308,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -424,7 +421,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ @@ -1060,9 +1056,10 @@ update-llvm-version: REV=`$(LLVM_DIR)/bin/llvm-config --version` && sed -e "s,expected_llvm_version=.*,expected_llvm_version=\"$$REV\"," < configure.ac > tmp && mv tmp configure.ac && echo "Version set to $$REV." update-solution-files: + (pushd msvc/scripts; rm genproj.exe; $(MAKE) genproj.exe; popd) $(MAKE) update-csproj $(MAKE) package-inputs - (cd msvc/scripts; $(MAKE) genproj.exe; mono genproj.exe $(GENPROJ_ARGS)) + (cd msvc/scripts; mono --debug genproj.exe $(GENPROJ_ARGS)) update-solution-files-with-tests: $(MAKE) "GENPROJ_ARGS=2012 true true" update-solution-files diff --git a/README.md b/README.md index 09f2613f79..33d7ae9502 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ The Mono project is part of the [.NET Foundation](http://www.dotnetfoundation.or | Windows | amd64 | [![windows-amd64][15]][16] | | Windows | i386 | [![windows-i386][17]][18] | | CentOS | s390x (cs) | [![centos-s390x][19]][20] | -| Debian 8 | ppc64el (cs) | [![debian-8-ppc64el][21]][22]| +| Debian 9 | ppc64el (cs) | [![debian-9-ppc64el][21]][22]| _(cs) = community supported architecture_ @@ -53,8 +53,8 @@ _(cs) = community supported architecture_ [18]: https://jenkins.mono-project.com/job/z/label=w32/ [19]: https://jenkins.mono-project.com/job/test-mono-mainline-community/label=centos-s390x/badge/icon [20]: https://jenkins.mono-project.com/job/test-mono-mainline-community/label=centos-s390x -[21]: https://jenkins.mono-project.com/job/test-mono-mainline-community-chroot/label=debian-8-ppc64el/badge/icon -[22]: https://jenkins.mono-project.com/job/test-mono-mainline-community-chroot/label=debian-8-ppc64el +[21]: https://jenkins.mono-project.com/job/test-mono-mainline-community-chroot/label=debian-9-ppc64el/badge/icon +[22]: https://jenkins.mono-project.com/job/test-mono-mainline-community-chroot/label=debian-9-ppc64el Compilation and Installation ============================ @@ -111,7 +111,7 @@ Once you have installed the software, you can run a few programs: * `mono program.exe` runtime engine -* `mcs program.cs` C# compiler +* `mcs program.cs` C# compiler * `monodis program.exe` CIL Disassembler @@ -128,6 +128,14 @@ Directory Roadmap * `external/` - Git submodules for external libraries (Newtonsoft.Json, ikvm, etc). +* `ikvm-native/` - Glue code for ikvm. + +* `libgc/` - The (deprecated) Boehm GC implementation. + +* `llvm/` - Utility Makefiles for integrating the Mono LLVM fork. + +* `m4/` - General utility Makefiles. + * `man/` - Manual pages for the various Mono commands and programs. * `mcs/` - The class libraries, compiler and tools @@ -142,26 +150,52 @@ Directory Roadmap * `arch/` - Architecture specific portions. + * `benchmark/` - A collection of benchmarks. + + * `btls/` - Build files for the BTLS library which incorporates BoringSSL. + * `cil/` - Common Intermediate Representation, XML definition of the CIL bytecodes. - * `dis/` - CIL executable Disassembler + * `dis/` - CIL executable Disassembler. - * `io-layer/` - The I/O layer and system abstraction for -emulating the .NET IO model. + * `eglib/` - Independent implementation of the glib API. * `metadata/` - The object system and metadata reader. * `mini/` - The Just in Time Compiler. + * `profiler/` - The profiler implementation. + + * `sgen/` - The SGen Garbage Collector implementation. + + * `tests/` - The main runtime tests. + + * `unit-tests/` - Additional runtime unit tests. + + * `utils/` - Utility functions used across the runtime codebase. + +* `msvc/` - Logic for the MSVC / Visual Studio based runtime and BCL build system. +The latter is experimental at the moment. + +* `packaging/` - Packaging logic for the OS X and Windows Mono packages. + +* `po/` - Translation files. + * `runtime/` - A directory that contains the Makefiles that link the mono/ and mcs/ build systems. -* `samples/` -Some simple sample programs on uses of the Mono -runtime as an embedded library. +* `samples/` - Some simple sample programs on uses of the Mono +runtime as an embedded library. * `scripts/` - Scripts used to invoke Mono and the corresponding program. +* `sdks/` - A new way of embedding Mono into Xamarin.iOS, Xamarin.Android and other products. + +* `support/` - Various support libraries. + +* `tools/` - A collection of tools, mostly used during Mono development. + Contributing to Mono ==================== diff --git a/acceptance-tests/Makefile.in.REMOVED.git-id b/acceptance-tests/Makefile.in.REMOVED.git-id index 346758c2a8..bb5fd4b4d5 100644 --- a/acceptance-tests/Makefile.in.REMOVED.git-id +++ b/acceptance-tests/Makefile.in.REMOVED.git-id @@ -1 +1 @@ -9196f4b94d89c752be303d5fd83b1fe324a94e16 \ No newline at end of file +9b9b777791cf346eab05c49479d7f54faae5e82e \ No newline at end of file diff --git a/aclocal.m4 b/aclocal.m4 index de1772c2f2..3c4db3fe8d 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -1204,10 +1204,6 @@ AC_SUBST([am__untar]) ]) # _AM_PROG_TAR m4_include([m4/ax_check_compile_flag.m4]) -m4_include([m4/iconv.m4]) -m4_include([m4/lib-ld.m4]) -m4_include([m4/lib-link.m4]) -m4_include([m4/lib-prefix.m4]) m4_include([m4/libtool.m4]) m4_include([m4/ltoptions.m4]) m4_include([m4/ltsugar.m4]) diff --git a/config.h.in b/config.h.in index 74ae8bf4f0..1a77ac9ce9 100644 --- a/config.h.in +++ b/config.h.in @@ -89,20 +89,17 @@ /* Disable CAS/CoreCLR security */ #undef DISABLE_SECURITY -/* Disable major=copying support in SGEN. */ -#undef DISABLE_SGEN_MAJOR_COPYING +/* Disable debug helpers in SGEN. */ +#undef DISABLE_SGEN_DEBUG_HELPERS -/* Disable major=marksweep-fixed support in SGEN. */ -#undef DISABLE_SGEN_MAJOR_MARKSWEEP_FIXED +/* Disable gc bridge support in SGEN. */ +#undef DISABLE_SGEN_GC_BRIDGE -/* Disable major=marksweep-fixed-par support in SGEN. */ -#undef DISABLE_SGEN_MAJOR_MARKSWEEP_FIXED_PAR +/* Disable concurrent gc support in SGEN. */ +#undef DISABLE_SGEN_MAJOR_MARKSWEEP_CONC -/* Disable major=marksweep-par support in SGEN. */ -#undef DISABLE_SGEN_MAJOR_MARKSWEEP_PAR - -/* Disable wbarrier=remset support in SGEN. */ -#undef DISABLE_SGEN_REMSET +/* Disable minor=split support in SGEN. */ +#undef DISABLE_SGEN_SPLIT_NURSERY /* Disable Shadow Copy for AppDomains */ #undef DISABLE_SHADOW_COPY @@ -131,6 +128,9 @@ /* Enable metadata checked build */ #undef ENABLE_CHECKED_BUILD_METADATA +/* Enable private types checked build */ +#undef ENABLE_CHECKED_BUILD_PRIVATE_TYPES + /* Enable thread checked build */ #undef ENABLE_CHECKED_BUILD_THREAD @@ -167,6 +167,9 @@ /* Define to 1 if you have the `accept4' function. */ #undef HAVE_ACCEPT4 +/* Have access */ +#undef HAVE_ACCESS + /* Has the 'aintl' function */ #undef HAVE_AINTL @@ -437,9 +440,6 @@ /* Define to 1 if you have the header file. */ #undef HAVE_GRP_H -/* Define if you have the iconv() function and it works. */ -#undef HAVE_ICONV - /* Define to 1 if you have the header file. */ #undef HAVE_ICONV_H @@ -1134,9 +1134,6 @@ /* ... */ #undef HOST_X86 -/* Define as const if the declaration of iconv() needs const. */ -#undef ICONV_CONST - /* Enable lazy gc thread creation by the embedding host. */ #undef LAZY_GC_THREAD_CREATION diff --git a/configure.REMOVED.git-id b/configure.REMOVED.git-id index b679f801fa..cfdaffdcab 100644 --- a/configure.REMOVED.git-id +++ b/configure.REMOVED.git-id @@ -1 +1 @@ -b6ab66aa835fd7733c5e05d7ed8c48fa74fe11af \ No newline at end of file +f82402782c183a9b3d0d7ff8dcf09665fe659437 \ No newline at end of file diff --git a/configure.ac.REMOVED.git-id b/configure.ac.REMOVED.git-id index 66b1b0cd0b..7ffe7957e1 100644 --- a/configure.ac.REMOVED.git-id +++ b/configure.ac.REMOVED.git-id @@ -1 +1 @@ -3a22b6f6da68c5076ef8e6587eb734f126d62c2e \ No newline at end of file +62d58e5ad09d9ee78241060e8c8fd498d658b690 \ No newline at end of file diff --git a/data/Makefile.in b/data/Makefile.in index 7d705db3ad..5d6265b909 100644 --- a/data/Makefile.in +++ b/data/Makefile.in @@ -95,8 +95,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(srcdir)/reactive.pc.in $(srcdir)/config.in README ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -301,6 +299,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -319,7 +318,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -333,7 +331,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -447,7 +444,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ diff --git a/data/config.in b/data/config.in index 282bc11495..36aa4c9085 100644 --- a/data/config.in +++ b/data/config.in @@ -40,4 +40,5 @@ + diff --git a/data/net_2_0/Browsers/Makefile.in b/data/net_2_0/Browsers/Makefile.in index bdc22ae982..60195d109e 100644 --- a/data/net_2_0/Browsers/Makefile.in +++ b/data/net_2_0/Browsers/Makefile.in @@ -84,8 +84,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -223,6 +221,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -241,7 +240,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -255,7 +253,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -369,7 +366,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ diff --git a/data/net_2_0/Makefile.in b/data/net_2_0/Makefile.in index d5d040c5a8..af1192159c 100644 --- a/data/net_2_0/Makefile.in +++ b/data/net_2_0/Makefile.in @@ -84,8 +84,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -283,6 +281,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -301,7 +300,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -315,7 +313,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -429,7 +426,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ diff --git a/data/net_2_0/machine.config b/data/net_2_0/machine.config index 2f8090f028..2577c81dd9 100644 --- a/data/net_2_0/machine.config +++ b/data/net_2_0/machine.config @@ -116,7 +116,7 @@ - + diff --git a/data/net_4_0/Browsers/Makefile.in b/data/net_4_0/Browsers/Makefile.in index c6edc0471b..ca08c91695 100644 --- a/data/net_4_0/Browsers/Makefile.in +++ b/data/net_4_0/Browsers/Makefile.in @@ -84,8 +84,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -223,6 +221,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -241,7 +240,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -255,7 +253,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -369,7 +366,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ diff --git a/data/net_4_0/Makefile.in b/data/net_4_0/Makefile.in index 0f58377469..ee39452793 100644 --- a/data/net_4_0/Makefile.in +++ b/data/net_4_0/Makefile.in @@ -84,8 +84,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -283,6 +281,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -301,7 +300,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -315,7 +313,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -429,7 +426,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ diff --git a/data/net_4_0/machine.config b/data/net_4_0/machine.config index 30bc2105f3..f3b71c43c5 100644 --- a/data/net_4_0/machine.config +++ b/data/net_4_0/machine.config @@ -133,7 +133,7 @@ - + diff --git a/data/net_4_5/Browsers/Makefile.in b/data/net_4_5/Browsers/Makefile.in index df9fd89466..232064bb09 100644 --- a/data/net_4_5/Browsers/Makefile.in +++ b/data/net_4_5/Browsers/Makefile.in @@ -84,8 +84,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -223,6 +221,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -241,7 +240,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -255,7 +253,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -369,7 +366,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ diff --git a/data/net_4_5/Makefile.in b/data/net_4_5/Makefile.in index 366ad98077..374a7d6489 100644 --- a/data/net_4_5/Makefile.in +++ b/data/net_4_5/Makefile.in @@ -84,8 +84,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -283,6 +281,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -301,7 +300,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -315,7 +313,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -429,7 +426,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ diff --git a/data/net_4_5/machine.config b/data/net_4_5/machine.config index d17369394e..455709536f 100644 --- a/data/net_4_5/machine.config +++ b/data/net_4_5/machine.config @@ -136,7 +136,7 @@ - + diff --git a/docs/Makefile.in b/docs/Makefile.in index 0c8de4e4f8..99553dbe54 100644 --- a/docs/Makefile.in +++ b/docs/Makefile.in @@ -84,8 +84,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs README TODO ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -223,6 +221,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -241,7 +240,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -255,7 +253,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -369,7 +366,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ diff --git a/docs/deploy/mono-api-jit.html b/docs/deploy/mono-api-jit.html index 3ee491f486..bdb10fbf04 100644 --- a/docs/deploy/mono-api-jit.html +++ b/docs/deploy/mono-api-jit.html @@ -225,7 +225,7 @@ typedef struct _MonoJitInfo MonoJitInfo;
Syntax
MonoJitInfo* -mono_jit_info_table_find (MonoDomain *domain, char *addr) +mono_jit_info_table_find (MonoDomain *domain, gpointer addr)

diff --git a/docs/deploy/mono-api-profiler.html b/docs/deploy/mono-api-profiler.html index 5dd79c8c44..65304476aa 100644 --- a/docs/deploy/mono-api-profiler.html +++ b/docs/deploy/mono-api-profiler.html @@ -677,7 +677,7 @@ mono_profiler_set_call_instrumentation_filter_callback (MonoProfilerHandle handl filter functions from all installed profilers. If any of them return flags other than MONO_PROFILER_CALL_INSTRUMENTATION_NONE, then the given method will be instrumented as requested. All filters are guaranteed to be called - exactly once per method, even if earlier filters have already specified all + at least once per method, even if earlier filters have already specified all flags.

Note that filter functions must be installed before a method is compiled in diff --git a/docs/deploy/mono-api-string.html b/docs/deploy/mono-api-string.html index 4689a3d1de..af0a3937e3 100644 --- a/docs/deploy/mono-api-string.html +++ b/docs/deploy/mono-api-string.html @@ -463,7 +463,7 @@ mono_string_to_utf8_checked (MonoString *s, MonoError *error)

Parameters
s a System.String
error a MonoError.
Description
- Converts a MonoString to its UTF-8 representation. May fail; check + Converts a MonoString to its UTF-8 representation. May fail; check error to determine whether the conversion was successful. The resulting buffer should be freed with mono_free().
diff --git a/docs/docs.make b/docs/docs.make index f0b9799035..aaef10a8ce 100644 --- a/docs/docs.make +++ b/docs/docs.make @@ -13,10 +13,10 @@ ASSEMBLED_DOCS = \ monoapi.tree monoapi.zip convert.exe: $(srcdir)/convert.cs AgilityPack.dll - $(CSCOMPILE) -r:$(topdir)/class/lib/$(PROFILE)/System.Xml.dll -out:$@ $< -r:AgilityPack.dll + $(CSCOMPILE) -r:$(topdir)/class/lib/$(PROFILE)/mscorlib.dll -r:$(topdir)/class/lib/$(PROFILE)/System.Xml.dll -out:$@ $< -r:AgilityPack.dll AgilityPack.dll: - $(CSCOMPILE) -r:$(topdir)/class/lib/$(PROFILE)/System.dll -r:$(topdir)/class/lib/$(PROFILE)/System.Xml.dll -target:library -out:$@ $(srcdir)/HtmlAgilityPack/*.cs + $(CSCOMPILE) -r:$(topdir)/class/lib/$(PROFILE)/mscorlib.dll -r:$(topdir)/class/lib/$(PROFILE)/System.dll -r:$(topdir)/class/lib/$(PROFILE)/System.Xml.dll -target:library -out:$@ $(srcdir)/HtmlAgilityPack/*.cs monoapi.zip: monoapi.tree @test -f $@ || { rm -f $< && $(MAKE) $<; } diff --git a/external/api-snapshot/profiles/monodroid/Facades/System.Diagnostics.StackTrace.cs b/external/api-snapshot/profiles/monodroid/Facades/System.Diagnostics.StackTrace.cs index a4e48af644..4fcf860379 100644 --- a/external/api-snapshot/profiles/monodroid/Facades/System.Diagnostics.StackTrace.cs +++ b/external/api-snapshot/profiles/monodroid/Facades/System.Diagnostics.StackTrace.cs @@ -15,6 +15,7 @@ [assembly:System.Runtime.CompilerServices.CompilationRelaxationsAttribute(8)] [assembly:System.Runtime.CompilerServices.RuntimeCompatibilityAttribute(WrapNonExceptionThrows=true)] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.StackFrame))] +[assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.StackFrameExtensions))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.StackTrace))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.SymbolStore.ISymbolBinder))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.SymbolStore.ISymbolBinder1))] @@ -31,56 +32,3 @@ [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.SymbolStore.SymDocumentType))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.SymbolStore.SymLanguageType))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.SymbolStore.SymLanguageVendor))] -namespace System -{ - [System.AttributeUsageAttribute((System.AttributeTargets)(32767), AllowMultiple=true)] - internal partial class MonoDocumentationNoteAttribute : System.MonoTODOAttribute - { - public MonoDocumentationNoteAttribute(string comment) { } - } - [System.AttributeUsageAttribute((System.AttributeTargets)(32767), AllowMultiple=true)] - internal partial class MonoExtensionAttribute : System.MonoTODOAttribute - { - public MonoExtensionAttribute(string comment) { } - } - [System.AttributeUsageAttribute((System.AttributeTargets)(32767), AllowMultiple=true)] - internal partial class MonoInternalNoteAttribute : System.MonoTODOAttribute - { - public MonoInternalNoteAttribute(string comment) { } - } - [System.AttributeUsageAttribute((System.AttributeTargets)(32767), AllowMultiple=true)] - internal partial class MonoLimitationAttribute : System.MonoTODOAttribute - { - public MonoLimitationAttribute(string comment) { } - } - [System.AttributeUsageAttribute((System.AttributeTargets)(32767), AllowMultiple=true)] - internal partial class MonoNotSupportedAttribute : System.MonoTODOAttribute - { - public MonoNotSupportedAttribute(string comment) { } - } - [System.AttributeUsageAttribute((System.AttributeTargets)(32767), AllowMultiple=true)] - internal partial class MonoTODOAttribute : System.Attribute - { - public MonoTODOAttribute() { } - public MonoTODOAttribute(string comment) { } - public string Comment { get { throw null; } } - } -} -namespace System.Diagnostics -{ - public static partial class StackFrameExtensions - { - [System.MonoTODOAttribute] - public static System.IntPtr GetNativeImageBase(this System.Diagnostics.StackFrame stackFrame) { throw null; } - [System.MonoTODOAttribute] - public static System.IntPtr GetNativeIP(this System.Diagnostics.StackFrame stackFrame) { throw null; } - [System.MonoTODOAttribute] - public static bool HasILOffset(this System.Diagnostics.StackFrame stackFrame) { throw null; } - [System.MonoTODOAttribute] - public static bool HasMethod(this System.Diagnostics.StackFrame stackFrame) { throw null; } - [System.MonoTODOAttribute] - public static bool HasNativeImage(this System.Diagnostics.StackFrame stackFrame) { throw null; } - [System.MonoTODOAttribute] - public static bool HasSource(this System.Diagnostics.StackFrame stackFrame) { throw null; } - } -} diff --git a/external/api-snapshot/profiles/monodroid/Facades/System.Globalization.Extensions.cs b/external/api-snapshot/profiles/monodroid/Facades/System.Globalization.Extensions.cs index a4ee0a672a..d7c6d06568 100644 --- a/external/api-snapshot/profiles/monodroid/Facades/System.Globalization.Extensions.cs +++ b/external/api-snapshot/profiles/monodroid/Facades/System.Globalization.Extensions.cs @@ -14,22 +14,7 @@ [assembly:System.Reflection.AssemblyTitleAttribute("System.Globalization.Extensions")] [assembly:System.Runtime.CompilerServices.CompilationRelaxationsAttribute(8)] [assembly:System.Runtime.CompilerServices.RuntimeCompatibilityAttribute(WrapNonExceptionThrows=true)] +[assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Globalization.GlobalizationExtensions))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Globalization.IdnMapping))] +[assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.StringNormalizationExtensions))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Text.NormalizationForm))] -namespace System -{ - public static partial class StringNormalizationExtensions - { - public static bool IsNormalized(this string strInput) { throw null; } - public static bool IsNormalized(this string strInput, System.Text.NormalizationForm normalizationForm) { throw null; } - public static string Normalize(this string strInput) { throw null; } - public static string Normalize(this string strInput, System.Text.NormalizationForm normalizationForm) { throw null; } - } -} -namespace System.Globalization -{ - public static partial class GlobalizationExtensions - { - public static System.StringComparer GetStringComparer(this System.Globalization.CompareInfo compareInfo, System.Globalization.CompareOptions options) { throw null; } - } -} diff --git a/external/api-snapshot/profiles/monodroid/Facades/System.IO.FileSystem.AccessControl.cs b/external/api-snapshot/profiles/monodroid/Facades/System.IO.FileSystem.AccessControl.cs index ed828426ec..5be2213680 100644 --- a/external/api-snapshot/profiles/monodroid/Facades/System.IO.FileSystem.AccessControl.cs +++ b/external/api-snapshot/profiles/monodroid/Facades/System.IO.FileSystem.AccessControl.cs @@ -21,41 +21,6 @@ [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.AccessControl.FileSystemAuditRule))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.AccessControl.FileSystemRights))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.AccessControl.FileSystemSecurity))] -namespace System -{ - [System.AttributeUsageAttribute((System.AttributeTargets)(32767), AllowMultiple=true)] - internal partial class MonoDocumentationNoteAttribute : System.MonoTODOAttribute - { - public MonoDocumentationNoteAttribute(string comment) { } - } - [System.AttributeUsageAttribute((System.AttributeTargets)(32767), AllowMultiple=true)] - internal partial class MonoExtensionAttribute : System.MonoTODOAttribute - { - public MonoExtensionAttribute(string comment) { } - } - [System.AttributeUsageAttribute((System.AttributeTargets)(32767), AllowMultiple=true)] - internal partial class MonoInternalNoteAttribute : System.MonoTODOAttribute - { - public MonoInternalNoteAttribute(string comment) { } - } - [System.AttributeUsageAttribute((System.AttributeTargets)(32767), AllowMultiple=true)] - internal partial class MonoLimitationAttribute : System.MonoTODOAttribute - { - public MonoLimitationAttribute(string comment) { } - } - [System.AttributeUsageAttribute((System.AttributeTargets)(32767), AllowMultiple=true)] - internal partial class MonoNotSupportedAttribute : System.MonoTODOAttribute - { - public MonoNotSupportedAttribute(string comment) { } - } - [System.AttributeUsageAttribute((System.AttributeTargets)(32767), AllowMultiple=true)] - internal partial class MonoTODOAttribute : System.Attribute - { - public MonoTODOAttribute() { } - public MonoTODOAttribute(string comment) { } - public string Comment { get { throw null; } } - } -} namespace System.IO { public static partial class FileSystemAclExtensions diff --git a/external/api-snapshot/profiles/monodroid/Facades/System.Runtime.Loader.cs b/external/api-snapshot/profiles/monodroid/Facades/System.Runtime.Loader.cs index 95669b0def..284a2e1f6a 100644 --- a/external/api-snapshot/profiles/monodroid/Facades/System.Runtime.Loader.cs +++ b/external/api-snapshot/profiles/monodroid/Facades/System.Runtime.Loader.cs @@ -15,13 +15,7 @@ [assembly:System.Runtime.CompilerServices.CompilationRelaxationsAttribute(8)] [assembly:System.Runtime.CompilerServices.RuntimeCompatibilityAttribute(WrapNonExceptionThrows=true)] [assembly:System.Security.Permissions.SecurityPermissionAttribute(System.Security.Permissions.SecurityAction.RequestMinimum, SkipVerification=true)] -namespace System.Reflection.Metadata -{ - public static partial class AssemblyExtensions - { - public unsafe static bool TryGetRawMetadata(this System.Reflection.Assembly assembly, out byte* blob, out int length) { blob = default(byte*); length = default(int); throw null; } - } -} +[assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Reflection.Metadata.AssemblyExtensions))] namespace System.Runtime.Loader { public abstract partial class AssemblyLoadContext diff --git a/external/api-snapshot/profiles/monodroid/Facades/System.Runtime.Serialization.Primitives.cs b/external/api-snapshot/profiles/monodroid/Facades/System.Runtime.Serialization.Primitives.cs index deeae7fd40..245a75cc58 100644 --- a/external/api-snapshot/profiles/monodroid/Facades/System.Runtime.Serialization.Primitives.cs +++ b/external/api-snapshot/profiles/monodroid/Facades/System.Runtime.Serialization.Primitives.cs @@ -24,6 +24,7 @@ [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.IExtensibleDataObject))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.IgnoreDataMemberAttribute))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.InvalidDataContractException))] +[assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.ISerializationSurrogateProvider))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.KnownTypeAttribute))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.OnDeserializedAttribute))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.OnDeserializingAttribute))] @@ -41,12 +42,3 @@ [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Xml.IXmlBinaryWriterInitializer))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Xml.IXmlTextReaderInitializer))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Xml.IXmlTextWriterInitializer))] -namespace System.Runtime.Serialization -{ - public partial interface ISerializationSurrogateProvider - { - object GetDeserializedObject(object obj, System.Type targetType); - object GetObjectToSerialize(object obj, System.Type targetType); - System.Type GetSurrogateType(System.Type type); - } -} diff --git a/external/api-snapshot/profiles/monodroid/Facades/System.Runtime.Serialization.Xml.cs b/external/api-snapshot/profiles/monodroid/Facades/System.Runtime.Serialization.Xml.cs index a67fcf45ac..e73197499f 100644 --- a/external/api-snapshot/profiles/monodroid/Facades/System.Runtime.Serialization.Xml.cs +++ b/external/api-snapshot/profiles/monodroid/Facades/System.Runtime.Serialization.Xml.cs @@ -16,6 +16,7 @@ [assembly:System.Runtime.CompilerServices.RuntimeCompatibilityAttribute(WrapNonExceptionThrows=true)] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.DataContractResolver))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.DataContractSerializer))] +[assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.DataContractSerializerExtensions))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.DataContractSerializerSettings))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.InvalidDataContractException))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.XmlObjectSerializer))] @@ -30,11 +31,3 @@ [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Xml.XmlDictionaryReaderQuotaTypes))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Xml.XmlDictionaryString))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Xml.XmlDictionaryWriter))] -namespace System.Runtime.Serialization -{ - public static partial class DataContractSerializerExtensions - { - public static System.Runtime.Serialization.ISerializationSurrogateProvider GetSerializationSurrogateProvider(this System.Runtime.Serialization.DataContractSerializer serializer) { throw null; } - public static void SetSerializationSurrogateProvider(this System.Runtime.Serialization.DataContractSerializer serializer, System.Runtime.Serialization.ISerializationSurrogateProvider provider) { } - } -} diff --git a/external/api-snapshot/profiles/monodroid/Facades/System.Security.Cryptography.Algorithms.cs b/external/api-snapshot/profiles/monodroid/Facades/System.Security.Cryptography.Algorithms.cs index f1efb453c2..f16ccb2c06 100644 --- a/external/api-snapshot/profiles/monodroid/Facades/System.Security.Cryptography.Algorithms.cs +++ b/external/api-snapshot/profiles/monodroid/Facades/System.Security.Cryptography.Algorithms.cs @@ -37,6 +37,7 @@ [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.HMACSHA256))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.HMACSHA384))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.HMACSHA512))] +[assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.IncrementalHash))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.MaskGenerationMethod))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.MD5))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.PKCS1MaskGenerationMethod))] @@ -67,17 +68,3 @@ [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.SHA512Managed))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.SignatureDescription))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.TripleDES))] -namespace System.Security.Cryptography -{ - public sealed partial class IncrementalHash : System.IDisposable - { - internal IncrementalHash() { } - public System.Security.Cryptography.HashAlgorithmName AlgorithmName { get { throw null; } } - public void AppendData(byte[] data) { } - public void AppendData(byte[] data, int offset, int count) { } - public static System.Security.Cryptography.IncrementalHash CreateHash(System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { throw null; } - public static System.Security.Cryptography.IncrementalHash CreateHMAC(System.Security.Cryptography.HashAlgorithmName hashAlgorithm, byte[] key) { throw null; } - public void Dispose() { } - public byte[] GetHashAndReset() { throw null; } - } -} diff --git a/external/api-snapshot/profiles/monodroid/Facades/System.Security.SecureString.cs b/external/api-snapshot/profiles/monodroid/Facades/System.Security.SecureString.cs index 3f4ac56df5..231de51638 100644 --- a/external/api-snapshot/profiles/monodroid/Facades/System.Security.SecureString.cs +++ b/external/api-snapshot/profiles/monodroid/Facades/System.Security.SecureString.cs @@ -15,13 +15,4 @@ [assembly:System.Runtime.CompilerServices.CompilationRelaxationsAttribute(8)] [assembly:System.Runtime.CompilerServices.RuntimeCompatibilityAttribute(WrapNonExceptionThrows=true)] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.SecureString))] -namespace System.Security -{ - public static partial class SecureStringMarshal - { - public static System.IntPtr SecureStringToCoTaskMemAnsi(System.Security.SecureString s) { throw null; } - public static System.IntPtr SecureStringToCoTaskMemUnicode(System.Security.SecureString s) { throw null; } - public static System.IntPtr SecureStringToGlobalAllocAnsi(System.Security.SecureString s) { throw null; } - public static System.IntPtr SecureStringToGlobalAllocUnicode(System.Security.SecureString s) { throw null; } - } -} +[assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.SecureStringMarshal))] diff --git a/external/api-snapshot/profiles/monodroid/Facades/System.Xml.XPath.XDocument.cs b/external/api-snapshot/profiles/monodroid/Facades/System.Xml.XPath.XDocument.cs index fb266a0bb2..cd4e9b3066 100644 --- a/external/api-snapshot/profiles/monodroid/Facades/System.Xml.XPath.XDocument.cs +++ b/external/api-snapshot/profiles/monodroid/Facades/System.Xml.XPath.XDocument.cs @@ -15,10 +15,4 @@ [assembly:System.Runtime.CompilerServices.CompilationRelaxationsAttribute(8)] [assembly:System.Runtime.CompilerServices.RuntimeCompatibilityAttribute(WrapNonExceptionThrows=true)] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Xml.XPath.Extensions))] -namespace System.Xml.XPath -{ - public static partial class XDocumentExtensions - { - public static System.Xml.XPath.IXPathNavigable ToXPathNavigable(this System.Xml.Linq.XNode node) { throw null; } - } -} +[assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Xml.XPath.XDocumentExtensions))] diff --git a/external/api-snapshot/profiles/monodroid/System.Core.cs.REMOVED.git-id b/external/api-snapshot/profiles/monodroid/System.Core.cs.REMOVED.git-id index e3fba8c5e0..273b4ad62d 100644 --- a/external/api-snapshot/profiles/monodroid/System.Core.cs.REMOVED.git-id +++ b/external/api-snapshot/profiles/monodroid/System.Core.cs.REMOVED.git-id @@ -1 +1 @@ -1677ef1e7504f41839769cf611c93149e1d4800f \ No newline at end of file +9353b66f78db9388051dacdf077cea687c85e6ad \ No newline at end of file diff --git a/external/api-snapshot/profiles/monodroid/System.Runtime.Serialization.cs b/external/api-snapshot/profiles/monodroid/System.Runtime.Serialization.cs index ed96253a1c..994c1d3524 100644 --- a/external/api-snapshot/profiles/monodroid/System.Runtime.Serialization.cs +++ b/external/api-snapshot/profiles/monodroid/System.Runtime.Serialization.cs @@ -99,6 +99,11 @@ namespace System.Runtime.Serialization public override void WriteStartObject(System.Xml.XmlDictionaryWriter writer, object graph) { } public override void WriteStartObject(System.Xml.XmlWriter writer, object graph) { } } + public static partial class DataContractSerializerExtensions + { + public static System.Runtime.Serialization.ISerializationSurrogateProvider GetSerializationSurrogateProvider(this System.Runtime.Serialization.DataContractSerializer serializer) { throw null; } + public static void SetSerializationSurrogateProvider(this System.Runtime.Serialization.DataContractSerializer serializer, System.Runtime.Serialization.ISerializationSurrogateProvider provider) { } + } public partial class DataContractSerializerSettings { public DataContractSerializerSettings() { } @@ -180,6 +185,12 @@ namespace System.Runtime.Serialization public InvalidDataContractException(string message) { } public InvalidDataContractException(string message, System.Exception innerException) { } } + public partial interface ISerializationSurrogateProvider + { + object GetDeserializedObject(object obj, System.Type targetType); + object GetObjectToSerialize(object obj, System.Type targetType); + System.Type GetSurrogateType(System.Type type); + } [System.AttributeUsageAttribute((System.AttributeTargets)(12), Inherited=true, AllowMultiple=true)] public sealed partial class KnownTypeAttribute : System.Attribute { diff --git a/external/api-snapshot/profiles/monodroid/System.Xml.Linq.cs b/external/api-snapshot/profiles/monodroid/System.Xml.Linq.cs index d07d888d62..868f4c41af 100644 --- a/external/api-snapshot/profiles/monodroid/System.Xml.Linq.cs +++ b/external/api-snapshot/profiles/monodroid/System.Xml.Linq.cs @@ -508,4 +508,8 @@ namespace System.Xml.XPath public static System.Collections.Generic.IEnumerable XPathSelectElements(this System.Xml.Linq.XNode node, string expression) { throw null; } public static System.Collections.Generic.IEnumerable XPathSelectElements(this System.Xml.Linq.XNode node, string expression, System.Xml.IXmlNamespaceResolver resolver) { throw null; } } + public static partial class XDocumentExtensions + { + public static System.Xml.XPath.IXPathNavigable ToXPathNavigable(this System.Xml.Linq.XNode node) { throw null; } + } } diff --git a/external/api-snapshot/profiles/monodroid/System.cs.REMOVED.git-id b/external/api-snapshot/profiles/monodroid/System.cs.REMOVED.git-id index d1c3cbf384..80bd8eb1ce 100644 --- a/external/api-snapshot/profiles/monodroid/System.cs.REMOVED.git-id +++ b/external/api-snapshot/profiles/monodroid/System.cs.REMOVED.git-id @@ -1 +1 @@ -715bb57073b8a2870f37ffde44c9c05c221ef92c \ No newline at end of file +65e4560d5595dc280c9096fe0d5f437aa2fdb1fe \ No newline at end of file diff --git a/external/api-snapshot/profiles/monodroid/mscorlib.cs.REMOVED.git-id b/external/api-snapshot/profiles/monodroid/mscorlib.cs.REMOVED.git-id index 3b4dd8bb2f..3c1c8ac6c1 100644 --- a/external/api-snapshot/profiles/monodroid/mscorlib.cs.REMOVED.git-id +++ b/external/api-snapshot/profiles/monodroid/mscorlib.cs.REMOVED.git-id @@ -1 +1 @@ -4a6825fa570dca67303aca29491b1368004c6eee \ No newline at end of file +68e9da8935703ec351b96ccea7fbf64a5cbea145 \ No newline at end of file diff --git a/external/api-snapshot/profiles/monotouch/Facades/System.Diagnostics.StackTrace.cs b/external/api-snapshot/profiles/monotouch/Facades/System.Diagnostics.StackTrace.cs index a4e48af644..4fcf860379 100644 --- a/external/api-snapshot/profiles/monotouch/Facades/System.Diagnostics.StackTrace.cs +++ b/external/api-snapshot/profiles/monotouch/Facades/System.Diagnostics.StackTrace.cs @@ -15,6 +15,7 @@ [assembly:System.Runtime.CompilerServices.CompilationRelaxationsAttribute(8)] [assembly:System.Runtime.CompilerServices.RuntimeCompatibilityAttribute(WrapNonExceptionThrows=true)] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.StackFrame))] +[assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.StackFrameExtensions))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.StackTrace))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.SymbolStore.ISymbolBinder))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.SymbolStore.ISymbolBinder1))] @@ -31,56 +32,3 @@ [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.SymbolStore.SymDocumentType))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.SymbolStore.SymLanguageType))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.SymbolStore.SymLanguageVendor))] -namespace System -{ - [System.AttributeUsageAttribute((System.AttributeTargets)(32767), AllowMultiple=true)] - internal partial class MonoDocumentationNoteAttribute : System.MonoTODOAttribute - { - public MonoDocumentationNoteAttribute(string comment) { } - } - [System.AttributeUsageAttribute((System.AttributeTargets)(32767), AllowMultiple=true)] - internal partial class MonoExtensionAttribute : System.MonoTODOAttribute - { - public MonoExtensionAttribute(string comment) { } - } - [System.AttributeUsageAttribute((System.AttributeTargets)(32767), AllowMultiple=true)] - internal partial class MonoInternalNoteAttribute : System.MonoTODOAttribute - { - public MonoInternalNoteAttribute(string comment) { } - } - [System.AttributeUsageAttribute((System.AttributeTargets)(32767), AllowMultiple=true)] - internal partial class MonoLimitationAttribute : System.MonoTODOAttribute - { - public MonoLimitationAttribute(string comment) { } - } - [System.AttributeUsageAttribute((System.AttributeTargets)(32767), AllowMultiple=true)] - internal partial class MonoNotSupportedAttribute : System.MonoTODOAttribute - { - public MonoNotSupportedAttribute(string comment) { } - } - [System.AttributeUsageAttribute((System.AttributeTargets)(32767), AllowMultiple=true)] - internal partial class MonoTODOAttribute : System.Attribute - { - public MonoTODOAttribute() { } - public MonoTODOAttribute(string comment) { } - public string Comment { get { throw null; } } - } -} -namespace System.Diagnostics -{ - public static partial class StackFrameExtensions - { - [System.MonoTODOAttribute] - public static System.IntPtr GetNativeImageBase(this System.Diagnostics.StackFrame stackFrame) { throw null; } - [System.MonoTODOAttribute] - public static System.IntPtr GetNativeIP(this System.Diagnostics.StackFrame stackFrame) { throw null; } - [System.MonoTODOAttribute] - public static bool HasILOffset(this System.Diagnostics.StackFrame stackFrame) { throw null; } - [System.MonoTODOAttribute] - public static bool HasMethod(this System.Diagnostics.StackFrame stackFrame) { throw null; } - [System.MonoTODOAttribute] - public static bool HasNativeImage(this System.Diagnostics.StackFrame stackFrame) { throw null; } - [System.MonoTODOAttribute] - public static bool HasSource(this System.Diagnostics.StackFrame stackFrame) { throw null; } - } -} diff --git a/external/api-snapshot/profiles/monotouch/Facades/System.Globalization.Extensions.cs b/external/api-snapshot/profiles/monotouch/Facades/System.Globalization.Extensions.cs index a4ee0a672a..d7c6d06568 100644 --- a/external/api-snapshot/profiles/monotouch/Facades/System.Globalization.Extensions.cs +++ b/external/api-snapshot/profiles/monotouch/Facades/System.Globalization.Extensions.cs @@ -14,22 +14,7 @@ [assembly:System.Reflection.AssemblyTitleAttribute("System.Globalization.Extensions")] [assembly:System.Runtime.CompilerServices.CompilationRelaxationsAttribute(8)] [assembly:System.Runtime.CompilerServices.RuntimeCompatibilityAttribute(WrapNonExceptionThrows=true)] +[assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Globalization.GlobalizationExtensions))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Globalization.IdnMapping))] +[assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.StringNormalizationExtensions))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Text.NormalizationForm))] -namespace System -{ - public static partial class StringNormalizationExtensions - { - public static bool IsNormalized(this string strInput) { throw null; } - public static bool IsNormalized(this string strInput, System.Text.NormalizationForm normalizationForm) { throw null; } - public static string Normalize(this string strInput) { throw null; } - public static string Normalize(this string strInput, System.Text.NormalizationForm normalizationForm) { throw null; } - } -} -namespace System.Globalization -{ - public static partial class GlobalizationExtensions - { - public static System.StringComparer GetStringComparer(this System.Globalization.CompareInfo compareInfo, System.Globalization.CompareOptions options) { throw null; } - } -} diff --git a/external/api-snapshot/profiles/monotouch/Facades/System.IO.FileSystem.AccessControl.cs b/external/api-snapshot/profiles/monotouch/Facades/System.IO.FileSystem.AccessControl.cs index ed828426ec..5be2213680 100644 --- a/external/api-snapshot/profiles/monotouch/Facades/System.IO.FileSystem.AccessControl.cs +++ b/external/api-snapshot/profiles/monotouch/Facades/System.IO.FileSystem.AccessControl.cs @@ -21,41 +21,6 @@ [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.AccessControl.FileSystemAuditRule))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.AccessControl.FileSystemRights))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.AccessControl.FileSystemSecurity))] -namespace System -{ - [System.AttributeUsageAttribute((System.AttributeTargets)(32767), AllowMultiple=true)] - internal partial class MonoDocumentationNoteAttribute : System.MonoTODOAttribute - { - public MonoDocumentationNoteAttribute(string comment) { } - } - [System.AttributeUsageAttribute((System.AttributeTargets)(32767), AllowMultiple=true)] - internal partial class MonoExtensionAttribute : System.MonoTODOAttribute - { - public MonoExtensionAttribute(string comment) { } - } - [System.AttributeUsageAttribute((System.AttributeTargets)(32767), AllowMultiple=true)] - internal partial class MonoInternalNoteAttribute : System.MonoTODOAttribute - { - public MonoInternalNoteAttribute(string comment) { } - } - [System.AttributeUsageAttribute((System.AttributeTargets)(32767), AllowMultiple=true)] - internal partial class MonoLimitationAttribute : System.MonoTODOAttribute - { - public MonoLimitationAttribute(string comment) { } - } - [System.AttributeUsageAttribute((System.AttributeTargets)(32767), AllowMultiple=true)] - internal partial class MonoNotSupportedAttribute : System.MonoTODOAttribute - { - public MonoNotSupportedAttribute(string comment) { } - } - [System.AttributeUsageAttribute((System.AttributeTargets)(32767), AllowMultiple=true)] - internal partial class MonoTODOAttribute : System.Attribute - { - public MonoTODOAttribute() { } - public MonoTODOAttribute(string comment) { } - public string Comment { get { throw null; } } - } -} namespace System.IO { public static partial class FileSystemAclExtensions diff --git a/external/api-snapshot/profiles/monotouch/Facades/System.Reflection.Emit.Lightweight.cs b/external/api-snapshot/profiles/monotouch/Facades/System.Reflection.Emit.Lightweight.cs index 27cd7b8b33..43d99bfcb9 100644 --- a/external/api-snapshot/profiles/monotouch/Facades/System.Reflection.Emit.Lightweight.cs +++ b/external/api-snapshot/profiles/monotouch/Facades/System.Reflection.Emit.Lightweight.cs @@ -14,28 +14,4 @@ [assembly:System.Reflection.AssemblyTitleAttribute("System.Reflection.Emit.Lightweight")] [assembly:System.Runtime.CompilerServices.CompilationRelaxationsAttribute(8)] [assembly:System.Runtime.CompilerServices.RuntimeCompatibilityAttribute(WrapNonExceptionThrows=true)] -namespace System.Reflection.Emit -{ - public abstract partial class DynamicMethod : System.Reflection.MethodInfo, System.Reflection.ICustomAttributeProvider - { - public DynamicMethod(string name, System.Reflection.MethodAttributes attributes, System.Reflection.CallingConventions callingConvention, System.Type returnType, System.Type[] parameterTypes, System.Reflection.Module m, bool skipVisibility) { } - public DynamicMethod(string name, System.Reflection.MethodAttributes attributes, System.Reflection.CallingConventions callingConvention, System.Type returnType, System.Type[] parameterTypes, System.Type owner, bool skipVisibility) { } - public DynamicMethod(string name, System.Type returnType, System.Type[] parameterTypes) { } - public DynamicMethod(string name, System.Type returnType, System.Type[] parameterTypes, bool restrictedSkipVisibility) { } - public DynamicMethod(string name, System.Type returnType, System.Type[] parameterTypes, System.Reflection.Module m) { } - public DynamicMethod(string name, System.Type returnType, System.Type[] parameterTypes, System.Reflection.Module m, bool skipVisibility) { } - public DynamicMethod(string name, System.Type returnType, System.Type[] parameterTypes, System.Type owner) { } - public DynamicMethod(string name, System.Type returnType, System.Type[] parameterTypes, System.Type owner, bool skipVisibility) { } - public override System.Reflection.MethodAttributes Attributes { get { throw null; } } - public override System.Reflection.CallingConventions CallingConvention { get { throw null; } } - public override System.Type DeclaringType { get { throw null; } } - public bool InitLocals { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - public override System.Reflection.MethodImplAttributes MethodImplementationFlags { get { throw null; } } - public override string Name { get { throw null; } } - public override System.Reflection.ParameterInfo ReturnParameter { get { throw null; } } - public override System.Type ReturnType { get { throw null; } } - public System.Reflection.Emit.ILGenerator GetILGenerator() { throw null; } - public System.Reflection.Emit.ILGenerator GetILGenerator(int streamSize) { throw null; } - public override System.Reflection.ParameterInfo[] GetParameters() { throw null; } - } -} +[assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Reflection.Emit.DynamicMethod))] diff --git a/external/api-snapshot/profiles/monotouch/Facades/System.Runtime.Loader.cs b/external/api-snapshot/profiles/monotouch/Facades/System.Runtime.Loader.cs index 95669b0def..284a2e1f6a 100644 --- a/external/api-snapshot/profiles/monotouch/Facades/System.Runtime.Loader.cs +++ b/external/api-snapshot/profiles/monotouch/Facades/System.Runtime.Loader.cs @@ -15,13 +15,7 @@ [assembly:System.Runtime.CompilerServices.CompilationRelaxationsAttribute(8)] [assembly:System.Runtime.CompilerServices.RuntimeCompatibilityAttribute(WrapNonExceptionThrows=true)] [assembly:System.Security.Permissions.SecurityPermissionAttribute(System.Security.Permissions.SecurityAction.RequestMinimum, SkipVerification=true)] -namespace System.Reflection.Metadata -{ - public static partial class AssemblyExtensions - { - public unsafe static bool TryGetRawMetadata(this System.Reflection.Assembly assembly, out byte* blob, out int length) { blob = default(byte*); length = default(int); throw null; } - } -} +[assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Reflection.Metadata.AssemblyExtensions))] namespace System.Runtime.Loader { public abstract partial class AssemblyLoadContext diff --git a/external/api-snapshot/profiles/monotouch/Facades/System.Runtime.Serialization.Primitives.cs b/external/api-snapshot/profiles/monotouch/Facades/System.Runtime.Serialization.Primitives.cs index deeae7fd40..245a75cc58 100644 --- a/external/api-snapshot/profiles/monotouch/Facades/System.Runtime.Serialization.Primitives.cs +++ b/external/api-snapshot/profiles/monotouch/Facades/System.Runtime.Serialization.Primitives.cs @@ -24,6 +24,7 @@ [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.IExtensibleDataObject))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.IgnoreDataMemberAttribute))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.InvalidDataContractException))] +[assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.ISerializationSurrogateProvider))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.KnownTypeAttribute))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.OnDeserializedAttribute))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.OnDeserializingAttribute))] @@ -41,12 +42,3 @@ [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Xml.IXmlBinaryWriterInitializer))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Xml.IXmlTextReaderInitializer))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Xml.IXmlTextWriterInitializer))] -namespace System.Runtime.Serialization -{ - public partial interface ISerializationSurrogateProvider - { - object GetDeserializedObject(object obj, System.Type targetType); - object GetObjectToSerialize(object obj, System.Type targetType); - System.Type GetSurrogateType(System.Type type); - } -} diff --git a/external/api-snapshot/profiles/monotouch/Facades/System.Runtime.Serialization.Xml.cs b/external/api-snapshot/profiles/monotouch/Facades/System.Runtime.Serialization.Xml.cs index a67fcf45ac..e73197499f 100644 --- a/external/api-snapshot/profiles/monotouch/Facades/System.Runtime.Serialization.Xml.cs +++ b/external/api-snapshot/profiles/monotouch/Facades/System.Runtime.Serialization.Xml.cs @@ -16,6 +16,7 @@ [assembly:System.Runtime.CompilerServices.RuntimeCompatibilityAttribute(WrapNonExceptionThrows=true)] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.DataContractResolver))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.DataContractSerializer))] +[assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.DataContractSerializerExtensions))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.DataContractSerializerSettings))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.InvalidDataContractException))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.XmlObjectSerializer))] @@ -30,11 +31,3 @@ [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Xml.XmlDictionaryReaderQuotaTypes))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Xml.XmlDictionaryString))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Xml.XmlDictionaryWriter))] -namespace System.Runtime.Serialization -{ - public static partial class DataContractSerializerExtensions - { - public static System.Runtime.Serialization.ISerializationSurrogateProvider GetSerializationSurrogateProvider(this System.Runtime.Serialization.DataContractSerializer serializer) { throw null; } - public static void SetSerializationSurrogateProvider(this System.Runtime.Serialization.DataContractSerializer serializer, System.Runtime.Serialization.ISerializationSurrogateProvider provider) { } - } -} diff --git a/external/api-snapshot/profiles/monotouch/Facades/System.Security.Cryptography.Algorithms.cs b/external/api-snapshot/profiles/monotouch/Facades/System.Security.Cryptography.Algorithms.cs index f1efb453c2..f16ccb2c06 100644 --- a/external/api-snapshot/profiles/monotouch/Facades/System.Security.Cryptography.Algorithms.cs +++ b/external/api-snapshot/profiles/monotouch/Facades/System.Security.Cryptography.Algorithms.cs @@ -37,6 +37,7 @@ [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.HMACSHA256))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.HMACSHA384))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.HMACSHA512))] +[assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.IncrementalHash))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.MaskGenerationMethod))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.MD5))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.PKCS1MaskGenerationMethod))] @@ -67,17 +68,3 @@ [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.SHA512Managed))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.SignatureDescription))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.TripleDES))] -namespace System.Security.Cryptography -{ - public sealed partial class IncrementalHash : System.IDisposable - { - internal IncrementalHash() { } - public System.Security.Cryptography.HashAlgorithmName AlgorithmName { get { throw null; } } - public void AppendData(byte[] data) { } - public void AppendData(byte[] data, int offset, int count) { } - public static System.Security.Cryptography.IncrementalHash CreateHash(System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { throw null; } - public static System.Security.Cryptography.IncrementalHash CreateHMAC(System.Security.Cryptography.HashAlgorithmName hashAlgorithm, byte[] key) { throw null; } - public void Dispose() { } - public byte[] GetHashAndReset() { throw null; } - } -} diff --git a/external/api-snapshot/profiles/monotouch/Facades/System.Security.SecureString.cs b/external/api-snapshot/profiles/monotouch/Facades/System.Security.SecureString.cs index 3f4ac56df5..231de51638 100644 --- a/external/api-snapshot/profiles/monotouch/Facades/System.Security.SecureString.cs +++ b/external/api-snapshot/profiles/monotouch/Facades/System.Security.SecureString.cs @@ -15,13 +15,4 @@ [assembly:System.Runtime.CompilerServices.CompilationRelaxationsAttribute(8)] [assembly:System.Runtime.CompilerServices.RuntimeCompatibilityAttribute(WrapNonExceptionThrows=true)] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.SecureString))] -namespace System.Security -{ - public static partial class SecureStringMarshal - { - public static System.IntPtr SecureStringToCoTaskMemAnsi(System.Security.SecureString s) { throw null; } - public static System.IntPtr SecureStringToCoTaskMemUnicode(System.Security.SecureString s) { throw null; } - public static System.IntPtr SecureStringToGlobalAllocAnsi(System.Security.SecureString s) { throw null; } - public static System.IntPtr SecureStringToGlobalAllocUnicode(System.Security.SecureString s) { throw null; } - } -} +[assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.SecureStringMarshal))] diff --git a/external/api-snapshot/profiles/monotouch/Facades/System.Xml.XPath.XDocument.cs b/external/api-snapshot/profiles/monotouch/Facades/System.Xml.XPath.XDocument.cs index fb266a0bb2..cd4e9b3066 100644 --- a/external/api-snapshot/profiles/monotouch/Facades/System.Xml.XPath.XDocument.cs +++ b/external/api-snapshot/profiles/monotouch/Facades/System.Xml.XPath.XDocument.cs @@ -15,10 +15,4 @@ [assembly:System.Runtime.CompilerServices.CompilationRelaxationsAttribute(8)] [assembly:System.Runtime.CompilerServices.RuntimeCompatibilityAttribute(WrapNonExceptionThrows=true)] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Xml.XPath.Extensions))] -namespace System.Xml.XPath -{ - public static partial class XDocumentExtensions - { - public static System.Xml.XPath.IXPathNavigable ToXPathNavigable(this System.Xml.Linq.XNode node) { throw null; } - } -} +[assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Xml.XPath.XDocumentExtensions))] diff --git a/external/api-snapshot/profiles/monotouch/System.Core.cs.REMOVED.git-id b/external/api-snapshot/profiles/monotouch/System.Core.cs.REMOVED.git-id index 9ef115c4eb..c134c940e1 100644 --- a/external/api-snapshot/profiles/monotouch/System.Core.cs.REMOVED.git-id +++ b/external/api-snapshot/profiles/monotouch/System.Core.cs.REMOVED.git-id @@ -1 +1 @@ -7beebcc3cdb0bf41205daab75b21a8a91b5f1c0d \ No newline at end of file +6f17a1037233b0ccc170bec511e7bf1dee5f7faf \ No newline at end of file diff --git a/external/api-snapshot/profiles/monotouch/System.Runtime.Serialization.cs b/external/api-snapshot/profiles/monotouch/System.Runtime.Serialization.cs index ed96253a1c..994c1d3524 100644 --- a/external/api-snapshot/profiles/monotouch/System.Runtime.Serialization.cs +++ b/external/api-snapshot/profiles/monotouch/System.Runtime.Serialization.cs @@ -99,6 +99,11 @@ namespace System.Runtime.Serialization public override void WriteStartObject(System.Xml.XmlDictionaryWriter writer, object graph) { } public override void WriteStartObject(System.Xml.XmlWriter writer, object graph) { } } + public static partial class DataContractSerializerExtensions + { + public static System.Runtime.Serialization.ISerializationSurrogateProvider GetSerializationSurrogateProvider(this System.Runtime.Serialization.DataContractSerializer serializer) { throw null; } + public static void SetSerializationSurrogateProvider(this System.Runtime.Serialization.DataContractSerializer serializer, System.Runtime.Serialization.ISerializationSurrogateProvider provider) { } + } public partial class DataContractSerializerSettings { public DataContractSerializerSettings() { } @@ -180,6 +185,12 @@ namespace System.Runtime.Serialization public InvalidDataContractException(string message) { } public InvalidDataContractException(string message, System.Exception innerException) { } } + public partial interface ISerializationSurrogateProvider + { + object GetDeserializedObject(object obj, System.Type targetType); + object GetObjectToSerialize(object obj, System.Type targetType); + System.Type GetSurrogateType(System.Type type); + } [System.AttributeUsageAttribute((System.AttributeTargets)(12), Inherited=true, AllowMultiple=true)] public sealed partial class KnownTypeAttribute : System.Attribute { diff --git a/external/api-snapshot/profiles/monotouch/System.Xml.Linq.cs b/external/api-snapshot/profiles/monotouch/System.Xml.Linq.cs index d07d888d62..868f4c41af 100644 --- a/external/api-snapshot/profiles/monotouch/System.Xml.Linq.cs +++ b/external/api-snapshot/profiles/monotouch/System.Xml.Linq.cs @@ -508,4 +508,8 @@ namespace System.Xml.XPath public static System.Collections.Generic.IEnumerable XPathSelectElements(this System.Xml.Linq.XNode node, string expression) { throw null; } public static System.Collections.Generic.IEnumerable XPathSelectElements(this System.Xml.Linq.XNode node, string expression, System.Xml.IXmlNamespaceResolver resolver) { throw null; } } + public static partial class XDocumentExtensions + { + public static System.Xml.XPath.IXPathNavigable ToXPathNavigable(this System.Xml.Linq.XNode node) { throw null; } + } } diff --git a/external/api-snapshot/profiles/monotouch/System.cs.REMOVED.git-id b/external/api-snapshot/profiles/monotouch/System.cs.REMOVED.git-id index 10fa13b75b..9c5e7f9feb 100644 --- a/external/api-snapshot/profiles/monotouch/System.cs.REMOVED.git-id +++ b/external/api-snapshot/profiles/monotouch/System.cs.REMOVED.git-id @@ -1 +1 @@ -a4f7bcc187e2d92981b872a5ef20e5bc0cf311f7 \ No newline at end of file +50cb212eb3f264ae44f1b9f3cf5ba18bef8efb99 \ No newline at end of file diff --git a/external/api-snapshot/profiles/monotouch/mscorlib.cs.REMOVED.git-id b/external/api-snapshot/profiles/monotouch/mscorlib.cs.REMOVED.git-id index b3ce3c8e80..bda40e779a 100644 --- a/external/api-snapshot/profiles/monotouch/mscorlib.cs.REMOVED.git-id +++ b/external/api-snapshot/profiles/monotouch/mscorlib.cs.REMOVED.git-id @@ -1 +1 @@ -8ba95ce82ff14d35d267993fc549a54bc93c9b99 \ No newline at end of file +4c8868b66fe131f296aea7f8a4a8b8ae85d864fd \ No newline at end of file diff --git a/external/api-snapshot/profiles/net_4_x/Facades/System.Diagnostics.StackTrace.cs b/external/api-snapshot/profiles/net_4_x/Facades/System.Diagnostics.StackTrace.cs index a4e48af644..4fcf860379 100644 --- a/external/api-snapshot/profiles/net_4_x/Facades/System.Diagnostics.StackTrace.cs +++ b/external/api-snapshot/profiles/net_4_x/Facades/System.Diagnostics.StackTrace.cs @@ -15,6 +15,7 @@ [assembly:System.Runtime.CompilerServices.CompilationRelaxationsAttribute(8)] [assembly:System.Runtime.CompilerServices.RuntimeCompatibilityAttribute(WrapNonExceptionThrows=true)] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.StackFrame))] +[assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.StackFrameExtensions))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.StackTrace))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.SymbolStore.ISymbolBinder))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.SymbolStore.ISymbolBinder1))] @@ -31,56 +32,3 @@ [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.SymbolStore.SymDocumentType))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.SymbolStore.SymLanguageType))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.SymbolStore.SymLanguageVendor))] -namespace System -{ - [System.AttributeUsageAttribute((System.AttributeTargets)(32767), AllowMultiple=true)] - internal partial class MonoDocumentationNoteAttribute : System.MonoTODOAttribute - { - public MonoDocumentationNoteAttribute(string comment) { } - } - [System.AttributeUsageAttribute((System.AttributeTargets)(32767), AllowMultiple=true)] - internal partial class MonoExtensionAttribute : System.MonoTODOAttribute - { - public MonoExtensionAttribute(string comment) { } - } - [System.AttributeUsageAttribute((System.AttributeTargets)(32767), AllowMultiple=true)] - internal partial class MonoInternalNoteAttribute : System.MonoTODOAttribute - { - public MonoInternalNoteAttribute(string comment) { } - } - [System.AttributeUsageAttribute((System.AttributeTargets)(32767), AllowMultiple=true)] - internal partial class MonoLimitationAttribute : System.MonoTODOAttribute - { - public MonoLimitationAttribute(string comment) { } - } - [System.AttributeUsageAttribute((System.AttributeTargets)(32767), AllowMultiple=true)] - internal partial class MonoNotSupportedAttribute : System.MonoTODOAttribute - { - public MonoNotSupportedAttribute(string comment) { } - } - [System.AttributeUsageAttribute((System.AttributeTargets)(32767), AllowMultiple=true)] - internal partial class MonoTODOAttribute : System.Attribute - { - public MonoTODOAttribute() { } - public MonoTODOAttribute(string comment) { } - public string Comment { get { throw null; } } - } -} -namespace System.Diagnostics -{ - public static partial class StackFrameExtensions - { - [System.MonoTODOAttribute] - public static System.IntPtr GetNativeImageBase(this System.Diagnostics.StackFrame stackFrame) { throw null; } - [System.MonoTODOAttribute] - public static System.IntPtr GetNativeIP(this System.Diagnostics.StackFrame stackFrame) { throw null; } - [System.MonoTODOAttribute] - public static bool HasILOffset(this System.Diagnostics.StackFrame stackFrame) { throw null; } - [System.MonoTODOAttribute] - public static bool HasMethod(this System.Diagnostics.StackFrame stackFrame) { throw null; } - [System.MonoTODOAttribute] - public static bool HasNativeImage(this System.Diagnostics.StackFrame stackFrame) { throw null; } - [System.MonoTODOAttribute] - public static bool HasSource(this System.Diagnostics.StackFrame stackFrame) { throw null; } - } -} diff --git a/external/api-snapshot/profiles/net_4_x/Facades/System.Globalization.Extensions.cs b/external/api-snapshot/profiles/net_4_x/Facades/System.Globalization.Extensions.cs index a4ee0a672a..d7c6d06568 100644 --- a/external/api-snapshot/profiles/net_4_x/Facades/System.Globalization.Extensions.cs +++ b/external/api-snapshot/profiles/net_4_x/Facades/System.Globalization.Extensions.cs @@ -14,22 +14,7 @@ [assembly:System.Reflection.AssemblyTitleAttribute("System.Globalization.Extensions")] [assembly:System.Runtime.CompilerServices.CompilationRelaxationsAttribute(8)] [assembly:System.Runtime.CompilerServices.RuntimeCompatibilityAttribute(WrapNonExceptionThrows=true)] +[assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Globalization.GlobalizationExtensions))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Globalization.IdnMapping))] +[assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.StringNormalizationExtensions))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Text.NormalizationForm))] -namespace System -{ - public static partial class StringNormalizationExtensions - { - public static bool IsNormalized(this string strInput) { throw null; } - public static bool IsNormalized(this string strInput, System.Text.NormalizationForm normalizationForm) { throw null; } - public static string Normalize(this string strInput) { throw null; } - public static string Normalize(this string strInput, System.Text.NormalizationForm normalizationForm) { throw null; } - } -} -namespace System.Globalization -{ - public static partial class GlobalizationExtensions - { - public static System.StringComparer GetStringComparer(this System.Globalization.CompareInfo compareInfo, System.Globalization.CompareOptions options) { throw null; } - } -} diff --git a/external/api-snapshot/profiles/net_4_x/Facades/System.IO.FileSystem.AccessControl.cs b/external/api-snapshot/profiles/net_4_x/Facades/System.IO.FileSystem.AccessControl.cs index ed828426ec..5be2213680 100644 --- a/external/api-snapshot/profiles/net_4_x/Facades/System.IO.FileSystem.AccessControl.cs +++ b/external/api-snapshot/profiles/net_4_x/Facades/System.IO.FileSystem.AccessControl.cs @@ -21,41 +21,6 @@ [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.AccessControl.FileSystemAuditRule))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.AccessControl.FileSystemRights))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.AccessControl.FileSystemSecurity))] -namespace System -{ - [System.AttributeUsageAttribute((System.AttributeTargets)(32767), AllowMultiple=true)] - internal partial class MonoDocumentationNoteAttribute : System.MonoTODOAttribute - { - public MonoDocumentationNoteAttribute(string comment) { } - } - [System.AttributeUsageAttribute((System.AttributeTargets)(32767), AllowMultiple=true)] - internal partial class MonoExtensionAttribute : System.MonoTODOAttribute - { - public MonoExtensionAttribute(string comment) { } - } - [System.AttributeUsageAttribute((System.AttributeTargets)(32767), AllowMultiple=true)] - internal partial class MonoInternalNoteAttribute : System.MonoTODOAttribute - { - public MonoInternalNoteAttribute(string comment) { } - } - [System.AttributeUsageAttribute((System.AttributeTargets)(32767), AllowMultiple=true)] - internal partial class MonoLimitationAttribute : System.MonoTODOAttribute - { - public MonoLimitationAttribute(string comment) { } - } - [System.AttributeUsageAttribute((System.AttributeTargets)(32767), AllowMultiple=true)] - internal partial class MonoNotSupportedAttribute : System.MonoTODOAttribute - { - public MonoNotSupportedAttribute(string comment) { } - } - [System.AttributeUsageAttribute((System.AttributeTargets)(32767), AllowMultiple=true)] - internal partial class MonoTODOAttribute : System.Attribute - { - public MonoTODOAttribute() { } - public MonoTODOAttribute(string comment) { } - public string Comment { get { throw null; } } - } -} namespace System.IO { public static partial class FileSystemAclExtensions diff --git a/external/api-snapshot/profiles/net_4_x/Facades/System.Runtime.Serialization.Primitives.cs b/external/api-snapshot/profiles/net_4_x/Facades/System.Runtime.Serialization.Primitives.cs index deeae7fd40..245a75cc58 100644 --- a/external/api-snapshot/profiles/net_4_x/Facades/System.Runtime.Serialization.Primitives.cs +++ b/external/api-snapshot/profiles/net_4_x/Facades/System.Runtime.Serialization.Primitives.cs @@ -24,6 +24,7 @@ [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.IExtensibleDataObject))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.IgnoreDataMemberAttribute))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.InvalidDataContractException))] +[assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.ISerializationSurrogateProvider))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.KnownTypeAttribute))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.OnDeserializedAttribute))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.OnDeserializingAttribute))] @@ -41,12 +42,3 @@ [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Xml.IXmlBinaryWriterInitializer))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Xml.IXmlTextReaderInitializer))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Xml.IXmlTextWriterInitializer))] -namespace System.Runtime.Serialization -{ - public partial interface ISerializationSurrogateProvider - { - object GetDeserializedObject(object obj, System.Type targetType); - object GetObjectToSerialize(object obj, System.Type targetType); - System.Type GetSurrogateType(System.Type type); - } -} diff --git a/external/api-snapshot/profiles/net_4_x/Facades/System.Runtime.Serialization.Xml.cs b/external/api-snapshot/profiles/net_4_x/Facades/System.Runtime.Serialization.Xml.cs index a67fcf45ac..e73197499f 100644 --- a/external/api-snapshot/profiles/net_4_x/Facades/System.Runtime.Serialization.Xml.cs +++ b/external/api-snapshot/profiles/net_4_x/Facades/System.Runtime.Serialization.Xml.cs @@ -16,6 +16,7 @@ [assembly:System.Runtime.CompilerServices.RuntimeCompatibilityAttribute(WrapNonExceptionThrows=true)] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.DataContractResolver))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.DataContractSerializer))] +[assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.DataContractSerializerExtensions))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.DataContractSerializerSettings))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.InvalidDataContractException))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.XmlObjectSerializer))] @@ -30,11 +31,3 @@ [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Xml.XmlDictionaryReaderQuotaTypes))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Xml.XmlDictionaryString))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Xml.XmlDictionaryWriter))] -namespace System.Runtime.Serialization -{ - public static partial class DataContractSerializerExtensions - { - public static System.Runtime.Serialization.ISerializationSurrogateProvider GetSerializationSurrogateProvider(this System.Runtime.Serialization.DataContractSerializer serializer) { throw null; } - public static void SetSerializationSurrogateProvider(this System.Runtime.Serialization.DataContractSerializer serializer, System.Runtime.Serialization.ISerializationSurrogateProvider provider) { } - } -} diff --git a/external/api-snapshot/profiles/net_4_x/Facades/System.Security.Cryptography.Algorithms.cs b/external/api-snapshot/profiles/net_4_x/Facades/System.Security.Cryptography.Algorithms.cs index f1efb453c2..f16ccb2c06 100644 --- a/external/api-snapshot/profiles/net_4_x/Facades/System.Security.Cryptography.Algorithms.cs +++ b/external/api-snapshot/profiles/net_4_x/Facades/System.Security.Cryptography.Algorithms.cs @@ -37,6 +37,7 @@ [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.HMACSHA256))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.HMACSHA384))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.HMACSHA512))] +[assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.IncrementalHash))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.MaskGenerationMethod))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.MD5))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.PKCS1MaskGenerationMethod))] @@ -67,17 +68,3 @@ [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.SHA512Managed))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.SignatureDescription))] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.TripleDES))] -namespace System.Security.Cryptography -{ - public sealed partial class IncrementalHash : System.IDisposable - { - internal IncrementalHash() { } - public System.Security.Cryptography.HashAlgorithmName AlgorithmName { get { throw null; } } - public void AppendData(byte[] data) { } - public void AppendData(byte[] data, int offset, int count) { } - public static System.Security.Cryptography.IncrementalHash CreateHash(System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { throw null; } - public static System.Security.Cryptography.IncrementalHash CreateHMAC(System.Security.Cryptography.HashAlgorithmName hashAlgorithm, byte[] key) { throw null; } - public void Dispose() { } - public byte[] GetHashAndReset() { throw null; } - } -} diff --git a/external/api-snapshot/profiles/net_4_x/Facades/System.Security.SecureString.cs b/external/api-snapshot/profiles/net_4_x/Facades/System.Security.SecureString.cs index 3f4ac56df5..231de51638 100644 --- a/external/api-snapshot/profiles/net_4_x/Facades/System.Security.SecureString.cs +++ b/external/api-snapshot/profiles/net_4_x/Facades/System.Security.SecureString.cs @@ -15,13 +15,4 @@ [assembly:System.Runtime.CompilerServices.CompilationRelaxationsAttribute(8)] [assembly:System.Runtime.CompilerServices.RuntimeCompatibilityAttribute(WrapNonExceptionThrows=true)] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.SecureString))] -namespace System.Security -{ - public static partial class SecureStringMarshal - { - public static System.IntPtr SecureStringToCoTaskMemAnsi(System.Security.SecureString s) { throw null; } - public static System.IntPtr SecureStringToCoTaskMemUnicode(System.Security.SecureString s) { throw null; } - public static System.IntPtr SecureStringToGlobalAllocAnsi(System.Security.SecureString s) { throw null; } - public static System.IntPtr SecureStringToGlobalAllocUnicode(System.Security.SecureString s) { throw null; } - } -} +[assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.SecureStringMarshal))] diff --git a/external/api-snapshot/profiles/net_4_x/Facades/System.Xml.XPath.XDocument.cs b/external/api-snapshot/profiles/net_4_x/Facades/System.Xml.XPath.XDocument.cs index fb266a0bb2..cd4e9b3066 100644 --- a/external/api-snapshot/profiles/net_4_x/Facades/System.Xml.XPath.XDocument.cs +++ b/external/api-snapshot/profiles/net_4_x/Facades/System.Xml.XPath.XDocument.cs @@ -15,10 +15,4 @@ [assembly:System.Runtime.CompilerServices.CompilationRelaxationsAttribute(8)] [assembly:System.Runtime.CompilerServices.RuntimeCompatibilityAttribute(WrapNonExceptionThrows=true)] [assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Xml.XPath.Extensions))] -namespace System.Xml.XPath -{ - public static partial class XDocumentExtensions - { - public static System.Xml.XPath.IXPathNavigable ToXPathNavigable(this System.Xml.Linq.XNode node) { throw null; } - } -} +[assembly:System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Xml.XPath.XDocumentExtensions))] diff --git a/external/api-snapshot/profiles/net_4_x/Microsoft.VisualC.cs b/external/api-snapshot/profiles/net_4_x/Microsoft.VisualC.cs index f61b561aac..2da5b31197 100644 --- a/external/api-snapshot/profiles/net_4_x/Microsoft.VisualC.cs +++ b/external/api-snapshot/profiles/net_4_x/Microsoft.VisualC.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -[assembly:System.Reflection.AssemblyVersionAttribute("0.0.0.0")] +[assembly:System.Reflection.AssemblyVersionAttribute("10.0.0.0")] [assembly:System.Diagnostics.DebuggableAttribute((System.Diagnostics.DebuggableAttribute.DebuggingModes)(2))] [assembly:System.Runtime.CompilerServices.CompilationRelaxationsAttribute(8)] [assembly:System.Runtime.CompilerServices.RuntimeCompatibilityAttribute(WrapNonExceptionThrows=true)] diff --git a/external/api-snapshot/profiles/net_4_x/Mono.Cecil.cs.REMOVED.git-id b/external/api-snapshot/profiles/net_4_x/Mono.Cecil.cs.REMOVED.git-id index 7b2da70822..e8350013a6 100644 --- a/external/api-snapshot/profiles/net_4_x/Mono.Cecil.cs.REMOVED.git-id +++ b/external/api-snapshot/profiles/net_4_x/Mono.Cecil.cs.REMOVED.git-id @@ -1 +1 @@ -dfcf34172908a18aaf781b2b50e901e96b820136 \ No newline at end of file +ab7d67e411350069bbfbb253ebf85aaea01ddab9 \ No newline at end of file diff --git a/external/api-snapshot/profiles/net_4_x/Mono.Debugger.Soft.cs b/external/api-snapshot/profiles/net_4_x/Mono.Debugger.Soft.cs index c6431526e8..aa4b283d16 100644 --- a/external/api-snapshot/profiles/net_4_x/Mono.Debugger.Soft.cs +++ b/external/api-snapshot/profiles/net_4_x/Mono.Debugger.Soft.cs @@ -502,6 +502,7 @@ namespace Mono.Debugger.Soft public PointerValue(Mono.Debugger.Soft.VirtualMachine vm, Mono.Debugger.Soft.TypeMirror type, long addr) { } public long Address { get { throw null; } } public Mono.Debugger.Soft.TypeMirror Type { get { throw null; } } + public Mono.Debugger.Soft.Value Value { get { throw null; } } public override bool Equals(object obj) { throw null; } public override int GetHashCode() { throw null; } public override string ToString() { throw null; } @@ -740,6 +741,7 @@ namespace Mono.Debugger.Soft public Mono.Debugger.Soft.Value GetValue(Mono.Debugger.Soft.FieldInfoMirror field, Mono.Debugger.Soft.ThreadMirror thread) { throw null; } public Mono.Debugger.Soft.Value[] GetValues(System.Collections.Generic.IList fields) { throw null; } public Mono.Debugger.Soft.Value[] GetValues(System.Collections.Generic.IList fields, Mono.Debugger.Soft.ThreadMirror thread) { throw null; } + public int GetValueSize() { throw null; } protected virtual bool HasElementTypeImpl() { throw null; } public Mono.Debugger.Soft.Value InvokeMethod(Mono.Debugger.Soft.ThreadMirror thread, Mono.Debugger.Soft.MethodMirror method, System.Collections.Generic.IList arguments) { throw null; } public Mono.Debugger.Soft.Value InvokeMethod(Mono.Debugger.Soft.ThreadMirror thread, Mono.Debugger.Soft.MethodMirror method, System.Collections.Generic.IList arguments, Mono.Debugger.Soft.InvokeOptions options) { throw null; } diff --git a/external/api-snapshot/profiles/net_4_x/System.Core.cs.REMOVED.git-id b/external/api-snapshot/profiles/net_4_x/System.Core.cs.REMOVED.git-id index 730c75da45..cd82736726 100644 --- a/external/api-snapshot/profiles/net_4_x/System.Core.cs.REMOVED.git-id +++ b/external/api-snapshot/profiles/net_4_x/System.Core.cs.REMOVED.git-id @@ -1 +1 @@ -cecb542171a3b1867631ef29e4d5bc67beb85cac \ No newline at end of file +5df2d7b09fea3948f8c715a83c9f842b202b3049 \ No newline at end of file diff --git a/external/api-snapshot/profiles/net_4_x/System.Runtime.Serialization.cs b/external/api-snapshot/profiles/net_4_x/System.Runtime.Serialization.cs index 23a536b667..131f8efadd 100644 --- a/external/api-snapshot/profiles/net_4_x/System.Runtime.Serialization.cs +++ b/external/api-snapshot/profiles/net_4_x/System.Runtime.Serialization.cs @@ -102,6 +102,11 @@ namespace System.Runtime.Serialization public override void WriteStartObject(System.Xml.XmlDictionaryWriter writer, object graph) { } public override void WriteStartObject(System.Xml.XmlWriter writer, object graph) { } } + public static partial class DataContractSerializerExtensions + { + public static System.Runtime.Serialization.ISerializationSurrogateProvider GetSerializationSurrogateProvider(this System.Runtime.Serialization.DataContractSerializer serializer) { throw null; } + public static void SetSerializationSurrogateProvider(this System.Runtime.Serialization.DataContractSerializer serializer, System.Runtime.Serialization.ISerializationSurrogateProvider provider) { } + } public partial class DataContractSerializerSettings { public DataContractSerializerSettings() { } @@ -197,6 +202,12 @@ namespace System.Runtime.Serialization public InvalidDataContractException(string message) { } public InvalidDataContractException(string message, System.Exception innerException) { } } + public partial interface ISerializationSurrogateProvider + { + object GetDeserializedObject(object obj, System.Type targetType); + object GetObjectToSerialize(object obj, System.Type targetType); + System.Type GetSurrogateType(System.Type type); + } [System.AttributeUsageAttribute((System.AttributeTargets)(12), Inherited=true, AllowMultiple=true)] public sealed partial class KnownTypeAttribute : System.Attribute { diff --git a/external/api-snapshot/profiles/net_4_x/System.Windows.Forms.cs.REMOVED.git-id b/external/api-snapshot/profiles/net_4_x/System.Windows.Forms.cs.REMOVED.git-id index 37a2b4ba75..b1fc497fbd 100644 --- a/external/api-snapshot/profiles/net_4_x/System.Windows.Forms.cs.REMOVED.git-id +++ b/external/api-snapshot/profiles/net_4_x/System.Windows.Forms.cs.REMOVED.git-id @@ -1 +1 @@ -cb9c6e6fbc4a0183a36f31597b80f48f72d4d557 \ No newline at end of file +aa80ec33fa038ce4493ea6b9885861adb0e5a3f1 \ No newline at end of file diff --git a/external/api-snapshot/profiles/net_4_x/System.Xml.Linq.cs b/external/api-snapshot/profiles/net_4_x/System.Xml.Linq.cs index b61c2060df..4e0470ddc3 100644 --- a/external/api-snapshot/profiles/net_4_x/System.Xml.Linq.cs +++ b/external/api-snapshot/profiles/net_4_x/System.Xml.Linq.cs @@ -509,4 +509,8 @@ namespace System.Xml.XPath public static System.Collections.Generic.IEnumerable XPathSelectElements(this System.Xml.Linq.XNode node, string expression) { throw null; } public static System.Collections.Generic.IEnumerable XPathSelectElements(this System.Xml.Linq.XNode node, string expression, System.Xml.IXmlNamespaceResolver resolver) { throw null; } } + public static partial class XDocumentExtensions + { + public static System.Xml.XPath.IXPathNavigable ToXPathNavigable(this System.Xml.Linq.XNode node) { throw null; } + } } diff --git a/external/api-snapshot/profiles/net_4_x/System.cs.REMOVED.git-id b/external/api-snapshot/profiles/net_4_x/System.cs.REMOVED.git-id index 1d2a1f2c44..2b23900b47 100644 --- a/external/api-snapshot/profiles/net_4_x/System.cs.REMOVED.git-id +++ b/external/api-snapshot/profiles/net_4_x/System.cs.REMOVED.git-id @@ -1 +1 @@ -b09677c78004a91a3d87bb964cf9a79ac800fab4 \ No newline at end of file +06d56d3a31822e894d57eb3351139516b39799de \ No newline at end of file diff --git a/external/api-snapshot/profiles/net_4_x/mscorlib.cs.REMOVED.git-id b/external/api-snapshot/profiles/net_4_x/mscorlib.cs.REMOVED.git-id index 61748bdbab..4b8a0445e8 100644 --- a/external/api-snapshot/profiles/net_4_x/mscorlib.cs.REMOVED.git-id +++ b/external/api-snapshot/profiles/net_4_x/mscorlib.cs.REMOVED.git-id @@ -1 +1 @@ -9a68bbd21ee9196ff71f50bc108c1324eae4f4f9 \ No newline at end of file +43bab23ba317a77d77755935069083d3560b770d \ No newline at end of file diff --git a/external/binary-reference-assemblies/build/monodroid/Makefile b/external/binary-reference-assemblies/build/monodroid/Makefile index ec756d9c7a..0d90c10295 100644 --- a/external/binary-reference-assemblies/build/monodroid/Makefile +++ b/external/binary-reference-assemblies/build/monodroid/Makefile @@ -21,8 +21,9 @@ bare/System_REFS := mscorlib bare/System.Xml_REFS := mscorlib bare/System mscorlib_CSC_ARGS := -runtimemetadataversion:v4.0.30319 +System_CSC_ARGS := ../../src/Mono/System.extra.cs -ECMA_KEY := ../../../mono/mcs/class/ecma.pub # Public Key Token: b77a5c561934e089 +ECMA_KEY := ../../../../../mono/mcs/class/ecma.pub # Public Key Token: b77a5c561934e089 ECMA_KEY_ASSEMBLIES := System.Core System.Net.Http System.Numerics System.Xml System mscorlib \ bare/System bare/System.Xml diff --git a/external/binary-reference-assemblies/build/monodroid/System.dll.REMOVED.git-id b/external/binary-reference-assemblies/build/monodroid/System.dll.REMOVED.git-id index 70e4d31e34..1bc77c0e0f 100644 --- a/external/binary-reference-assemblies/build/monodroid/System.dll.REMOVED.git-id +++ b/external/binary-reference-assemblies/build/monodroid/System.dll.REMOVED.git-id @@ -1 +1 @@ -ab4c9433b3b63fe16e478cc37a18ea453bc19ff1 \ No newline at end of file +b0ba3c261fe2fa1392dc649a3da36ccb1eb213ba \ No newline at end of file diff --git a/external/binary-reference-assemblies/build/monotouch/Makefile b/external/binary-reference-assemblies/build/monotouch/Makefile index 2966aace3a..e1ae21744d 100644 --- a/external/binary-reference-assemblies/build/monotouch/Makefile +++ b/external/binary-reference-assemblies/build/monotouch/Makefile @@ -21,8 +21,9 @@ bare/System_REFS := mscorlib bare/System.Xml_REFS := mscorlib bare/System mscorlib_CSC_ARGS := -runtimemetadataversion:v4.0.30319 +System_CSC_ARGS := ../../src/Mono/System.extra.cs -ECMA_KEY := ../../../mono/mcs/class/ecma.pub # Public Key Token: b77a5c561934e089 +ECMA_KEY := ../../../../../mono/mcs/class/ecma.pub # Public Key Token: b77a5c561934e089 ECMA_KEY_ASSEMBLIES := System.Core System.Net.Http System.Numerics System.Xml System mscorlib \ bare/System bare/System.Xml diff --git a/external/binary-reference-assemblies/build/monotouch/System.dll.REMOVED.git-id b/external/binary-reference-assemblies/build/monotouch/System.dll.REMOVED.git-id index cb814ff5c6..72414abdb6 100644 --- a/external/binary-reference-assemblies/build/monotouch/System.dll.REMOVED.git-id +++ b/external/binary-reference-assemblies/build/monotouch/System.dll.REMOVED.git-id @@ -1 +1 @@ -c10bd54a5cd051a2a47e5599bb382bf9db02da79 \ No newline at end of file +589327cb425c2811156435a75cd5c0cc003ae1dc \ No newline at end of file diff --git a/external/binary-reference-assemblies/src/mono/System.extra.cs b/external/binary-reference-assemblies/src/mono/System.extra.cs new file mode 100644 index 0000000000..ec2cc87ffa --- /dev/null +++ b/external/binary-reference-assemblies/src/mono/System.extra.cs @@ -0,0 +1,94 @@ +using System; +using System.IO; +using System.Net; +using System.Net.Security; +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo ("Mono.Security, PublicKey=002400000480000094000000060200000024000052534131000400000100010079159977d2d03a8e6bea7a2e74e8d1afcc93e8851974952bb480a12c9134474d04062447c37e0e68c080536fcf3c3fbe2ff9c979ce998475e506e8ce82dd5b0f350dc10e93bf2eeecf874b24770c5081dbea7447fddafa277b22de47d6ffea449674a4f9fccf84d15069089380284dbdd35f46cdff12a1bd78e4ef0065d016df")] + +namespace System.Security.Cryptography.X509Certificates +{ + abstract class X509Certificate2Impl + { + } + + static class X509Helper2 + { + internal static long GetSubjectNameHash (X509Certificate certificate) + { + throw null; + } + + internal static void ExportAsPEM (X509Certificate certificate, Stream stream, bool includeHumanReadableForm) + { + throw null; + } + } +} + +namespace Mono.Net.Security +{ + static class NoReflectionHelper + { + internal static object GetInternalValidator (object provider, object settings) + { + throw null; + } + + internal static object GetDefaultValidator (object settings) + { + throw null; + } + + internal static object GetProvider () + { + throw null; + } + + internal static bool IsInitialized { + get { + throw null; + } + } + + internal static void Initialize () + { + throw null; + } + + internal static void Initialize (string provider) + { + throw null; + } + + internal static HttpWebRequest CreateHttpsRequest (Uri requestUri, object provider, object settings) + { + throw null; + } + + internal static object CreateHttpListener (object certificate, object provider, object settings) + { + throw null; + } + + internal static object GetMonoSslStream (SslStream stream) + { + throw null; + } + + internal static object GetMonoSslStream (HttpListenerContext context) + { + throw null; + } + + internal static bool IsProviderSupported (string name) + { + throw null; + } + + internal static object GetProvider (string name) + { + throw null; + } + } +} diff --git a/external/binary-reference-assemblies/v4.7.1/Makefile b/external/binary-reference-assemblies/v4.7.1/Makefile index 1ef6753373..0bcf238661 100644 --- a/external/binary-reference-assemblies/v4.7.1/Makefile +++ b/external/binary-reference-assemblies/v4.7.1/Makefile @@ -258,7 +258,7 @@ Facades/System.Xml.XmlSerializer_REFS := mscorlib System.Xml Facades/netstandard_REFS := mscorlib System System.Core System.Data System.Diagnostics.Tracing System.Drawing System.IO.Compression System.IO.Compression.FileSystem System.ComponentModel.Composition System.Net.Http System.Numerics System.Runtime.Serialization System.Transactions System.Web System.Xml System.Xml.Linq mscorlib_CSC_ARGS := -runtimemetadataversion:v4.0.30319 -System_CSC_ARGS := -d:CONFIG_DEP -d:XML_DEP +System_CSC_ARGS := -d:CONFIG_DEP -d:XML_DEP ../src/Mono/System.extra.cs System.Configuration_CSC_ARGS := -d:CONFIG_DEP System.Xml_CSC_ARGS := -d:CONFIG_DEP System.ServiceModel.Activation_CSC_ARGS := -d:SERVICEMODEL_DEP -d:WEB_DEP diff --git a/external/binary-reference-assemblies/v4.7.1/System.dll.REMOVED.git-id b/external/binary-reference-assemblies/v4.7.1/System.dll.REMOVED.git-id index 840b8f072b..7d06f83249 100644 --- a/external/binary-reference-assemblies/v4.7.1/System.dll.REMOVED.git-id +++ b/external/binary-reference-assemblies/v4.7.1/System.dll.REMOVED.git-id @@ -1 +1 @@ -a30decf6496151191fbebdc8c0ea6709870a4ed3 \ No newline at end of file +ea33a272ed6642fd300e619349eab0546fec86e1 \ No newline at end of file diff --git a/external/boringssl/CMakeLists.txt b/external/boringssl/CMakeLists.txt index 2ba98c0db4..9bf6d1b488 100644 --- a/external/boringssl/CMakeLists.txt +++ b/external/boringssl/CMakeLists.txt @@ -166,6 +166,12 @@ elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64") set(ARCH "aarch64") elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "s390x") set(ARCH "s390x") +elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "powerpc") + set(ARCH "powerpc") +elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "riscv32") + set(ARCH "riscv32") +elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "riscv64") + set(ARCH "riscv64") else() message(FATAL_ERROR "Unknown processor:" ${CMAKE_SYSTEM_PROCESSOR}) endif() diff --git a/external/boringssl/crypto/bio/socket_helper.c b/external/boringssl/crypto/bio/socket_helper.c index 950078845a..73b3c4fce5 100644 --- a/external/boringssl/crypto/bio/socket_helper.c +++ b/external/boringssl/crypto/bio/socket_helper.c @@ -18,6 +18,7 @@ #include #include +#include #include #include #include diff --git a/external/boringssl/include/openssl/base.h b/external/boringssl/include/openssl/base.h index 96eb6936eb..92de1f63b1 100644 --- a/external/boringssl/include/openssl/base.h +++ b/external/boringssl/include/openssl/base.h @@ -97,6 +97,12 @@ extern "C" { #elif defined(__s390x__) #define OPENSSL_64_BIT #define OPENSSL_S390X +#elif defined(__riscv) && __riscv_xlen == 32 +#define OPENSSL_32_BIT +#define OPENSSL_RISCV32 +#elif defined(__riscv) && __riscv_xlen == 64 +#define OPENSSL_64_BIT +#define OPENSSL_RISCV64 #else #error "Unknown target CPU" #endif diff --git a/external/boringssl/include/openssl/thread.h b/external/boringssl/include/openssl/thread.h index 9a96fb43da..1900d9e3bd 100644 --- a/external/boringssl/include/openssl/thread.h +++ b/external/boringssl/include/openssl/thread.h @@ -77,7 +77,7 @@ typedef struct crypto_mutex_st { typedef union crypto_mutex_st { void *handle; } CRYPTO_MUTEX; -#elif defined(__MACH__) && defined(__APPLE__) +#elif (defined(__MACH__) && defined(__APPLE__)) || defined(_AIX) typedef pthread_rwlock_t CRYPTO_MUTEX; #else /* It is reasonable to include pthread.h on non-Windows systems, however the diff --git a/external/cecil/Mono.Cecil.Cil/PortablePdb.cs b/external/cecil/Mono.Cecil.Cil/PortablePdb.cs index 717249e909..a7883e71d1 100644 --- a/external/cecil/Mono.Cecil.Cil/PortablePdb.cs +++ b/external/cecil/Mono.Cecil.Cil/PortablePdb.cs @@ -569,6 +569,9 @@ namespace Mono.Cecil.Cil { if (hash_algo == DocumentHashAlgorithm.SHA1) return hash_sha1; + if (hash_algo == DocumentHashAlgorithm.SHA256) + return hash_sha256; + return new Guid (); } diff --git a/external/cecil/Mono.Cecil.Cil/Symbols.cs b/external/cecil/Mono.Cecil.Cil/Symbols.cs index 4c4a8b0306..c47761dd90 100644 --- a/external/cecil/Mono.Cecil.Cil/Symbols.cs +++ b/external/cecil/Mono.Cecil.Cil/Symbols.cs @@ -1000,7 +1000,7 @@ namespace Mono.Cecil { public static bool IsPortablePdb (string fileName) { - using (var file = new FileStream (fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) + using (var file = new FileStream (fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) return IsPortablePdb (file); } diff --git a/external/cecil/Mono.Cecil.PE/Image.cs b/external/cecil/Mono.Cecil.PE/Image.cs index d9d182ad7e..25ea1869ed 100644 --- a/external/cecil/Mono.Cecil.PE/Image.cs +++ b/external/cecil/Mono.Cecil.PE/Image.cs @@ -28,6 +28,7 @@ namespace Mono.Cecil.PE { public string RuntimeVersion; public TargetArchitecture Architecture; public ModuleCharacteristics Characteristics; + public ushort LinkerVersion; public ImageDebugHeader DebugHeader; diff --git a/external/cecil/Mono.Cecil.PE/ImageReader.cs b/external/cecil/Mono.Cecil.PE/ImageReader.cs index 63213f3941..f3f3d2641a 100644 --- a/external/cecil/Mono.Cecil.PE/ImageReader.cs +++ b/external/cecil/Mono.Cecil.PE/ImageReader.cs @@ -81,8 +81,8 @@ namespace Mono.Cecil.PE { // Characteristics 2 ushort characteristics = ReadUInt16 (); - ushort subsystem, dll_characteristics; - ReadOptionalHeaders (out subsystem, out dll_characteristics); + ushort subsystem, dll_characteristics, linker_version; + ReadOptionalHeaders (out subsystem, out dll_characteristics, out linker_version); ReadSections (sections); ReadCLIHeader (); ReadMetadata (); @@ -90,6 +90,7 @@ namespace Mono.Cecil.PE { image.Kind = GetModuleKind (characteristics, subsystem); image.Characteristics = (ModuleCharacteristics) dll_characteristics; + image.LinkerVersion = linker_version; } TargetArchitecture ReadArchitecture () @@ -108,7 +109,7 @@ namespace Mono.Cecil.PE { return ModuleKind.Console; } - void ReadOptionalHeaders (out ushort subsystem, out ushort dll_characteristics) + void ReadOptionalHeaders (out ushort subsystem, out ushort dll_characteristics, out ushort linker) { // - PEOptionalHeader // - StandardFieldsHeader @@ -118,8 +119,7 @@ namespace Mono.Cecil.PE { // pe32 || pe64 - // LMajor 1 - // LMinor 1 + linker = ReadUInt16 (); // CodeSize 4 // InitializedDataSize 4 // UninitializedDataSize4 @@ -142,7 +142,7 @@ namespace Mono.Cecil.PE { // ImageSize 4 // HeaderSize 4 // FileChecksum 4 - Advance (66); + Advance (64); // SubSystem 2 subsystem = ReadUInt16 (); diff --git a/external/cecil/Mono.Cecil.PE/ImageWriter.cs b/external/cecil/Mono.Cecil.PE/ImageWriter.cs index f69e134677..366f4f4205 100644 --- a/external/cecil/Mono.Cecil.PE/ImageWriter.cs +++ b/external/cecil/Mono.Cecil.PE/ImageWriter.cs @@ -218,9 +218,8 @@ namespace Mono.Cecil.PE { void WriteOptionalHeaders () { - WriteUInt16 ((ushort) (!pe64 ? 0x10b : 0x20b)); // Magic - WriteByte (8); // LMajor - WriteByte (0); // LMinor + WriteUInt16 ((ushort) (!pe64 ? 0x10b : 0x20b)); // Magic + WriteUInt16 (module.linker_version); WriteUInt32 (text.SizeOfRawData); // CodeSize WriteUInt32 ((reloc != null ? reloc.SizeOfRawData : 0) + (rsrc != null ? rsrc.SizeOfRawData : 0)); // InitializedDataSize diff --git a/external/cecil/Mono.Cecil/AssemblyWriter.cs b/external/cecil/Mono.Cecil/AssemblyWriter.cs index 52c601c742..7b3710e2fd 100644 --- a/external/cecil/Mono.Cecil/AssemblyWriter.cs +++ b/external/cecil/Mono.Cecil/AssemblyWriter.cs @@ -2414,10 +2414,12 @@ namespace Mono.Cecil { var signature = CreateSignatureWriter (); signature.WriteUInt32 ((uint) async_method.catch_handler.Offset + 1); - for (int i = 0; i < async_method.yields.Count; i++) { - signature.WriteUInt32 ((uint) async_method.yields [i].Offset); - signature.WriteUInt32 ((uint) async_method.resumes [i].Offset); - signature.WriteCompressedUInt32 (async_method.resume_methods [i].MetadataToken.RID); + if (!async_method.yields.IsNullOrEmpty ()) { + for (int i = 0; i < async_method.yields.Count; i++) { + signature.WriteUInt32 ((uint) async_method.yields [i].Offset); + signature.WriteUInt32 ((uint) async_method.resumes [i].Offset); + signature.WriteCompressedUInt32 (async_method.resume_methods [i].MetadataToken.RID); + } } AddCustomDebugInformation (provider, async_method, signature); diff --git a/external/cecil/Mono.Cecil/CustomAttribute.cs b/external/cecil/Mono.Cecil/CustomAttribute.cs index 135f8b7247..d64411fc22 100644 --- a/external/cecil/Mono.Cecil/CustomAttribute.cs +++ b/external/cecil/Mono.Cecil/CustomAttribute.cs @@ -9,7 +9,7 @@ // using System; - +using System.Diagnostics; using Mono.Collections.Generic; namespace Mono.Cecil { @@ -68,6 +68,7 @@ namespace Mono.Cecil { Collection ConstructorArguments { get; } } + [DebuggerDisplay ("{AttributeType}")] public sealed class CustomAttribute : ICustomAttribute { internal CustomAttributeValueProjection projection; diff --git a/external/cecil/Mono.Cecil/ModuleDefinition.cs b/external/cecil/Mono.Cecil/ModuleDefinition.cs index d82db4e490..85381c0bbd 100644 --- a/external/cecil/Mono.Cecil/ModuleDefinition.cs +++ b/external/cecil/Mono.Cecil/ModuleDefinition.cs @@ -276,6 +276,7 @@ namespace Mono.Cecil { TargetArchitecture architecture; ModuleAttributes attributes; ModuleCharacteristics characteristics; + internal ushort linker_version = 8; Guid mvid; internal uint timestamp; @@ -350,7 +351,7 @@ namespace Mono.Cecil { set { characteristics = value; } } - [Obsolete("Use FileName")] + [Obsolete ("Use FileName")] public string FullyQualifiedName { get { return file_name; } } @@ -607,6 +608,7 @@ namespace Mono.Cecil { this.architecture = image.Architecture; this.attributes = image.Attributes; this.characteristics = image.Characteristics; + this.linker_version = image.LinkerVersion; this.file_name = image.FileName; this.timestamp = image.Timestamp; diff --git a/external/cecil/Mono.Cecil/ModuleKind.cs b/external/cecil/Mono.Cecil/ModuleKind.cs index a5aa2274a4..2cd084db5a 100644 --- a/external/cecil/Mono.Cecil/ModuleKind.cs +++ b/external/cecil/Mono.Cecil/ModuleKind.cs @@ -38,6 +38,7 @@ namespace Mono.Cecil { public enum ModuleAttributes { ILOnly = 1, Required32Bit = 2, + ILLibrary = 4, StrongNameSigned = 8, Preferred32Bit = 0x00020000, } diff --git a/external/cecil/Mono.Cecil/SecurityDeclaration.cs b/external/cecil/Mono.Cecil/SecurityDeclaration.cs index 2762d08b39..a18d14f25a 100644 --- a/external/cecil/Mono.Cecil/SecurityDeclaration.cs +++ b/external/cecil/Mono.Cecil/SecurityDeclaration.cs @@ -9,7 +9,7 @@ // using System; - +using System.Diagnostics; using Mono.Collections.Generic; namespace Mono.Cecil { @@ -38,6 +38,7 @@ namespace Mono.Cecil { Collection SecurityDeclarations { get; } } + [DebuggerDisplay ("{AttributeType}")] public sealed class SecurityAttribute : ICustomAttribute { TypeReference attribute_type; diff --git a/external/corefx/src/Common/src/CoreLib/System/Text/StringBuilder.cs b/external/corefx/src/Common/src/CoreLib/System/Text/StringBuilder.cs index c4b99e9a00..d5b6e7f312 100644 --- a/external/corefx/src/Common/src/CoreLib/System/Text/StringBuilder.cs +++ b/external/corefx/src/Common/src/CoreLib/System/Text/StringBuilder.cs @@ -27,7 +27,9 @@ namespace System.Text // object unless specified otherwise. This class may be used in conjunction with the String // class to carry out modifications upon strings. [Serializable] +#if !MONO [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] +#endif public sealed partial class StringBuilder : ISerializable { // A StringBuilder is internally represented as a linked list of blocks each of which holds diff --git a/external/corefx/src/System.Collections/tests/BitArray/BitArray_CtorTests.cs b/external/corefx/src/System.Collections/tests/BitArray/BitArray_CtorTests.cs index 43527706bc..f50f0d6562 100644 --- a/external/corefx/src/System.Collections/tests/BitArray/BitArray_CtorTests.cs +++ b/external/corefx/src/System.Collections/tests/BitArray/BitArray_CtorTests.cs @@ -192,6 +192,7 @@ namespace System.Collections.Tests } [Fact] + [SkipOnTargetFramework(TargetFrameworkMonikers.Mono, "Flaky test - OOM")] public static void Ctor_LargeIntArrayOverflowingBitArray_ThrowsArgumentException() { AssertExtensions.Throws("values", () => new BitArray(new int[int.MaxValue / BitsPerInt32 + 1 ])); @@ -231,6 +232,7 @@ namespace System.Collections.Tests } [Fact] + [SkipOnTargetFramework(TargetFrameworkMonikers.Mono, "Flaky test - OOM")] public static void Ctor_LargeByteArrayOverflowingBitArray_ThrowsArgumentException() { AssertExtensions.Throws("bytes", () => new BitArray(new byte[int.MaxValue / BitsPerByte + 1 ])); @@ -250,6 +252,7 @@ namespace System.Collections.Tests [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "A bug in BitArray.Clone() caused an ArgumentExeption to be thrown in this case.")] [Fact] + [SkipOnTargetFramework(TargetFrameworkMonikers.Mono, "Flaky test - OOM")] public static void Clone_LongLength_Works() { BitArray bitArray = new BitArray(int.MaxValue - 30); diff --git a/external/corefx/src/System.Drawing.Common/tests/Helpers.cs b/external/corefx/src/System.Drawing.Common/tests/Helpers.cs index 01a94a1759..fba64f1b25 100644 --- a/external/corefx/src/System.Drawing.Common/tests/Helpers.cs +++ b/external/corefx/src/System.Drawing.Common/tests/Helpers.cs @@ -27,6 +27,9 @@ namespace System.Drawing } else { +#if MONO + return true; +#else IntPtr nativeLib; if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { @@ -42,6 +45,7 @@ namespace System.Drawing } return nativeLib != IntPtr.Zero; +#endif } } diff --git a/external/corefx/src/System.Drawing.Common/tests/StringFormatTests.cs b/external/corefx/src/System.Drawing.Common/tests/StringFormatTests.cs index a39913348b..ce4616c1f7 100644 --- a/external/corefx/src/System.Drawing.Common/tests/StringFormatTests.cs +++ b/external/corefx/src/System.Drawing.Common/tests/StringFormatTests.cs @@ -185,6 +185,7 @@ namespace System.Drawing.Tests } [ConditionalFact(Helpers.GdiplusIsAvailable)] + [SkipOnTargetFramework(TargetFrameworkMonikers.Mono)] public void SetTabStops_NegativeFirstTabOffset_ThrowsArgumentException() { using (var format = new StringFormat()) @@ -194,6 +195,7 @@ namespace System.Drawing.Tests } [ConditionalFact(Helpers.GdiplusIsAvailable)] + [SkipOnTargetFramework(TargetFrameworkMonikers.Mono)] public void SetTabStops_NegativeInfinityInTabStops_ThrowsNotImplementedException() { using (var format = new StringFormat()) @@ -308,6 +310,7 @@ namespace System.Drawing.Tests } [ConditionalFact(Helpers.GdiplusIsAvailable)] + [SkipOnTargetFramework(TargetFrameworkMonikers.Mono)] public void DigitSubstitutionLanguage_GetSetWhenDisposed_ThrowsArgumentException() { var format = new StringFormat(); diff --git a/external/corefx/src/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.UnknownUnix.cs b/external/corefx/src/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.UnknownUnix.cs index 26ecd256a8..026c082e34 100644 --- a/external/corefx/src/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.UnknownUnix.cs +++ b/external/corefx/src/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.UnknownUnix.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#if MONO +#if MONO && !MOBILE using System; using System.IO; diff --git a/external/corefx/src/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.cs b/external/corefx/src/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.cs index ae3f5557d6..8eff45a82a 100644 --- a/external/corefx/src/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.cs +++ b/external/corefx/src/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.cs @@ -8,7 +8,7 @@ using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; -#if MONO +#if MONO && !MOBILE using System; using System.IO; diff --git a/external/corefx/src/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.unit.cs b/external/corefx/src/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.unit.cs index f10331a097..1f227a52ba 100644 --- a/external/corefx/src/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.unit.cs +++ b/external/corefx/src/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.unit.cs @@ -54,6 +54,7 @@ namespace System.IO.Tests } [Fact] + [SkipOnTargetFramework(TargetFrameworkMonikers.Mono, "Not working")] public void FileSystemWatcher_EmptyAction_TriggersNothing() { using (var testDirectory = new TempDirectory(GetTestFilePath())) diff --git a/external/corefx/src/System.Private.DataContractSerialization/src/System/Xml/XmlCanonicalWriter.cs b/external/corefx/src/System.Private.DataContractSerialization/src/System/Xml/XmlCanonicalWriter.cs index d849c2c785..6f0bbba8f2 100644 --- a/external/corefx/src/System.Private.DataContractSerialization/src/System/Xml/XmlCanonicalWriter.cs +++ b/external/corefx/src/System.Private.DataContractSerialization/src/System/Xml/XmlCanonicalWriter.cs @@ -7,6 +7,9 @@ using System.IO; using System.Runtime; using System.Runtime.Serialization; using System.Text; +#if MONO +using Fx = System.Runtime.Fx; +#endif namespace System.Xml diff --git a/external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.cs b/external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.cs index d078cda53a..511312b4ef 100644 --- a/external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.cs +++ b/external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.cs @@ -1081,6 +1081,16 @@ namespace System.Text.RegularExpressions protected bool UseOptionC() { +#if MOBILE + return false; +#elif MONO + // This is here so we can debug this issue: https://github.com/mono/mono/pull/7982, + // once that is fixed, we can remove this. Disabling it completely for mobile + // as we are not likely to debug the threading issue there. + if (Environment.GetEnvironmentVariable ("MONO_REGEX_COMPILED_ENABLE") == null) + return false; +#endif + return (roptions & RegexOptions.Compiled) != 0; } diff --git a/external/corefx/src/System.Threading.Tasks.Parallel/tests/ParallelForTests.cs b/external/corefx/src/System.Threading.Tasks.Parallel/tests/ParallelForTests.cs index b25d5b1fea..ca16e2ab03 100644 --- a/external/corefx/src/System.Threading.Tasks.Parallel/tests/ParallelForTests.cs +++ b/external/corefx/src/System.Threading.Tasks.Parallel/tests/ParallelForTests.cs @@ -993,6 +993,7 @@ namespace System.Threading.Tasks.Tests } [Fact] + [SkipOnTargetFramework(TargetFrameworkMonikers.Mono, "https://github.com/mono/mono/issues/7992")] public static void TestInvokeDOPAndCancel() { ParallelOptions parallelOptions = null; diff --git a/external/corert/BuildToolsVersion.txt b/external/corert/BuildToolsVersion.txt index 8cc3da5def..4edf3134b6 100644 --- a/external/corert/BuildToolsVersion.txt +++ b/external/corert/BuildToolsVersion.txt @@ -1 +1 @@ -2.1.0-prerelease-02403-01 +2.1.0-preview2-02521-03 diff --git a/external/corert/Documentation/how-to-build-WebAssembly.md b/external/corert/Documentation/how-to-build-WebAssembly.md index 72fb034b25..84e6ed6dfe 100644 --- a/external/corert/Documentation/how-to-build-WebAssembly.md +++ b/external/corert/Documentation/how-to-build-WebAssembly.md @@ -1,5 +1,6 @@ # Build WebAssembly # -Currently, building WebAssembly is only possible on Windows. + +## Build WebAssembly on Windows ## 1. Install Emscripten by following the instructions [here](https://kripken.github.io/emscripten-site/docs/getting_started/downloads.html). 2. Follow the instructions [here](https://kripken.github.io/emscripten-site/docs/getting_started/downloads.html#updating-the-sdk) to update Emscripten to the latest version. @@ -7,15 +8,33 @@ Currently, building WebAssembly is only possible on Windows. 4. Build the WebAssembly runtime by running ```build.cmd wasm``` from the repo root. 5. Run the WebAssembly "Hello World" test by running ```C:\corert\tests\runtest.cmd wasm```. -To debug compiling WebAssembly: +## Build WebAssembly on OSX ## + +1. Install Emscripten by following the instructions [here](https://kripken.github.io/emscripten-site/docs/getting_started/downloads.html). +2. Follow the instructions [here](https://kripken.github.io/emscripten-site/docs/getting_started/downloads.html#updating-the-sdk) to update Emscripten to the latest version. +3. Get CoreRT set up by installing [Prerequisites](prerequisites-for-building.md). +4. Build the WebAssembly runtime by running ```./build.sh wasm``` from the repo root. +5. Run the WebAssembly "Hello World" test by opening it in [Firefox](https://www.getfirefox.com). + +## Build WebAssembly on Ubuntu 16.04.3 ## + +1. Get CoreRT set up by installing [Prerequisites](prerequisites-for-building.md), except install ```libicu55``` for Ubuntu 16 instead of ```libicu52```. +2. Install Emscripten by following the instructions [here](https://kripken.github.io/emscripten-site/docs/getting_started/downloads.html). +3. Follow the instructions [here](https://kripken.github.io/emscripten-site/docs/getting_started/downloads.html#updating-the-sdk) to update Emscripten to the latest version. +4. Build the WebAssembly runtime by running ```./build.sh wasm``` from the repo root. +5. Run the WebAssembly "Hello World" test by opening it in [Firefox](https://www.getfirefox.com). + + +# How to debug the IL->WebAssembly compilation # +This is Windows only for now. 1. Set the ILCompiler startup command line to ```@C:\corert\tests\src\Simple\HelloWasm\obj\Debug\wasm\native\HelloWasm.ilc.rsp```. That will generate HelloWasm.bc, an LLVM bitcode file. 2. To compile that to WebAssembly, run ```emcc HelloWasm.bc -s ALLOW_MEMORY_GROWTH=1 C:\corert\bin\WebAssembly.wasm.Debug\sdk\libPortableRuntime.bc C:\corert\bin\WebAssembly.wasm.Debug\sdk\libbootstrappercpp.bc -s WASM=1 -o HelloWasm.html``` (if emcc isn't on your path, you'll need to launch an Emscripten command prompt to do this). That will generate a .wasm file with your code as well as html and js files to run it. -To run a WebAssembly application -1. Ensure you have Edge 41 or above or [Firefox](https://www.getfirefox.com). +# How to run a WebAssembly application # +1. Ensure you have Edge 41 (Windows only) or above or [Firefox](https://www.getfirefox.com). 2. Open the generated html file in Edge or Firefox and look at the on-screen console for output. -Useful tips: +# Useful tips # * To manually make ILC compile to WebAssembly, add ```--wasm``` to the command line. * Add ```-g3``` to the emcc command line to generate more debuggable output and a .wast file with the text form of the WebAssembly. * Omit ```-s WASM=1``` from the emcc command line to generate asm.js. Browser debuggers currently work better with asm.js and it's often a bit more readable than wast. diff --git a/external/corert/Documentation/how-to-run-tests.md b/external/corert/Documentation/how-to-run-tests.md index b38b1df4f0..9e43d11918 100644 --- a/external/corert/Documentation/how-to-run-tests.md +++ b/external/corert/Documentation/how-to-run-tests.md @@ -28,8 +28,9 @@ tests\runtest.sh You should see the below message when you build CoreRT or run the local tests manually, otherwise something is broken. ``` -JIT - TOTAL: 7 PASSED: 7 +JIT - TOTAL: 12 PASSED: 12 CPP - TOTAL: 2 PASSED: 2 +WASM - TOTAL: 1 PASSED: 1 ``` ## External Tests @@ -55,7 +56,7 @@ tests\runtest.cmd /coreclr Top200|All|KnownGood On Linux / macOS: -**TBD** +tests/runtest.sh -coreclr Top200|All|KnownGood ### Suppress Windows Error Reporting Dialogs It's advisable to use some sort of a dialog killer tool if you see test regressions as many tests fail with pop-ups for Windows Error Reporting. However, the following regedit scripts have also proven to be useful to mask these pop-ups. diff --git a/external/corert/Documentation/prerequisites-for-building.md b/external/corert/Documentation/prerequisites-for-building.md index b8360e4281..368e8f4cda 100644 --- a/external/corert/Documentation/prerequisites-for-building.md +++ b/external/corert/Documentation/prerequisites-for-building.md @@ -20,7 +20,7 @@ sudo apt-get update ``` ```sh -sudo apt-get install cmake clang-3.9 libicu52 libunwind8 uuid-dev +sudo apt-get install cmake clang-3.9 libicu52 libunwind8 uuid-dev libcurl4-openssl-dev zlib1g-dev ``` # macOS (10.12+) @@ -28,6 +28,23 @@ sudo apt-get install cmake clang-3.9 libicu52 libunwind8 uuid-dev 1. Install [Command Line Tools for XCode 8](https://developer.apple.com/xcode/download/) or higher. 2. Install [CMake](https://cmake.org/download/) 3.8.0 or later. Launch `/Applications/CMake.app/Contents/MacOS/CMake` GUI. Goto "OSX App Menu -> Tools -> Install For Command Line Use" and follow the steps. +# openSUSE Leap 42.3 + +First install llvm-3.9. This is a bit cumbersome because the LLVM that comes from the `zypper` feeds is too old. + +```sh +wget http://releases.llvm.org/3.9.0/clang+llvm-3.9.0-x86_64-opensuse13.2.tar.xz +tar xf clang+llvm-3.9.0-x86_64-opensuse13.2.tar.xz +cd clang+llvm-3.9.0-x86_64-opensuse13.2 +sudo cp -R * /usr/local/ +``` + +Next install the rest of the dependencies: + +```sh +sudo zypper install cmake libuuid-devel icu libcurl-devel zlib-devel +``` + # Bash on Ubuntu on Windows (Windows 10 Creators Update or later) Make sure you run with Ubuntu 16.04 Xenial userland (this is the default after Windows 10 Creators Update, but if you enabled the "Bash on Ubuntu on Windows" feature before the Creators Update, you need to [upgrade manually](https://blogs.msdn.microsoft.com/commandline/2017/04/11/windows-10-creators-update-whats-new-in-bashwsl-windows-console/)). Running `lsb_release -a` will give you the version. diff --git a/external/corert/DotnetCLIVersion.txt b/external/corert/DotnetCLIVersion.txt index 227cea2156..eca07e4c1a 100644 --- a/external/corert/DotnetCLIVersion.txt +++ b/external/corert/DotnetCLIVersion.txt @@ -1 +1 @@ -2.0.0 +2.1.2 diff --git a/external/corert/Packaging.props b/external/corert/Packaging.props index 88abaa0194..339171f666 100644 --- a/external/corert/Packaging.props +++ b/external/corert/Packaging.props @@ -8,8 +8,7 @@ $(ProjectDir)THIRD-PARTY-NOTICES.TXT TODO https://dot.net - - $(ToolsDir)net46/ + $(BuildToolsTaskDir) $(Platform) x64 diff --git a/external/corert/README.md b/external/corert/README.md index 12181ef2eb..e5bc3366ff 100644 --- a/external/corert/README.md +++ b/external/corert/README.md @@ -4,8 +4,7 @@ This repo contains the .NET Core runtime optimized for AOT compilation ## Platform Support This is a work in progress. The current state of platform support: -- Windows x64 w/ RyuJIT codegen: Simple ASP.NET apps [compile and run](https://github.com/dotnet/corert/tree/master/samples/WebApi) -- MacOS and Linux x64 w/ RyuJIT codegen: Same as Windows, the libraries are less complete. +- Windows, MacOS and Linux x64 w/ RyuJIT codegen: Simple apps. Check our [ASP.NET Core](samples/WebApi/) and [MonoGame](samples/MonoGame/) samples. - Linux ARM w/ RyuJIT codegen: ElmSharp Hello Tizen application ([detailed status](https://github.com/dotnet/corert/issues/4856)) - CppCodeGen (targets all platforms that support C++): Simple C# programs. The big missing features are [reflection](https://github.com/dotnet/corert/issues/2035), [garbage collection](https://github.com/dotnet/corert/issues/2033) and [exception handling](https://github.com/dotnet/corert/issues/910). - WebAssembly: Early prototype that compiles and runs very trivial programs only. Many features are [not yet implemented](https://github.com/dotnet/corert/issues?q=is%3Aissue+is%3Aopen+label%3Aarch-wasm). diff --git a/external/corert/buildscripts/build-managed.cmd b/external/corert/buildscripts/build-managed.cmd index e6258748ac..c052aef787 100644 --- a/external/corert/buildscripts/build-managed.cmd +++ b/external/corert/buildscripts/build-managed.cmd @@ -46,6 +46,11 @@ IF ERRORLEVEL 1 exit /b %ERRORLEVEL% "%__DotNetCliPath%\dotnet.exe" publish "%__SourceDir%\ILCompiler\netcoreapp\ilc.csproj" -r %__NugetRuntimeId% -o "%__RootBinDir%\%__BuildOS%.%__BuildArch%.%__BuildType%\tools" IF ERRORLEVEL 1 exit /b %ERRORLEVEL% +"%__DotNetCliPath%\dotnet.exe" restore "%__SourceDir%\ILVerify\netcoreapp\ILVerify.csproj" -r %__NugetRuntimeId% +IF ERRORLEVEL 1 exit /b %ERRORLEVEL% +"%__DotNetCliPath%\dotnet.exe" publish "%__SourceDir%\ILVerify\netcoreapp\ILVerify.csproj" -r %__NugetRuntimeId% -o "%__RootBinDir%\%__BuildOS%.%__BuildArch%.%__BuildType%\ILVerify" +IF ERRORLEVEL 1 exit /b %ERRORLEVEL% + :: Set the environment for the managed build call "!VS%__VSProductVersion%COMNTOOLS!\VsDevCmd.bat" echo Commencing build of managed components for %__BuildOS%.%__BuildArch%.%__BuildType% diff --git a/external/corert/buildscripts/build-managed.sh b/external/corert/buildscripts/build-managed.sh index 5c0addc6f5..9b53eb2f9e 100755 --- a/external/corert/buildscripts/build-managed.sh +++ b/external/corert/buildscripts/build-managed.sh @@ -92,11 +92,11 @@ get_official_cross_builds() return 0 fi __tizenToolsRoot=${__ProjectRoot}/Tools/tizen - __corefxsite="https://ci.dot.net/job/dotnet_corefx/job/master/view/Official%20Builds/job/" - __coreclrsite="https://ci.dot.net/job/dotnet_coreclr/job/master/view/Official%20Builds/job/" + __corefxsite="https://ci.dot.net/job/dotnet_corefx/job/master/job/" + __coreclrsite="https://ci.dot.net/job/dotnet_coreclr/job/master/job/" __buildArchiveName="build.tar.gz" __systemNativeLibName="System.Native.a" - __systemGlobNativeLibName="libSystem.Globalization.Native.a" + __systemGlobNativeLibName="System.Globalization.Native.a" if [ $__BuildType = "Debug" ]; then __buildtype="debug" else @@ -106,7 +106,7 @@ get_official_cross_builds() __coreclrsource="armel_cross_${__buildtype}_tizen/lastSuccessfulBuild/artifact/bin/Product/Linux.armel.${__BuildType}/${__systemGlobNativeLibName}" mkdir -p $__tizenToolsRoot - (cd ${__tizenToolsRoot} && wget -N "${__corefxsite}${__corefxsource}") + (cd ${__tizenToolsRoot} && wget -t0 -N "${__corefxsite}${__corefxsource}") export BUILDERRORLEVEL=$? if [ $BUILDERRORLEVEL != 0 ]; then exit $BUILDERRORLEVEL @@ -114,7 +114,7 @@ get_official_cross_builds() tar xvf ${__tizenToolsRoot}/${__buildArchiveName} -C ${__tizenToolsRoot} ./${__systemNativeLibName} cp ${__tizenToolsRoot}/${__systemNativeLibName} $__ProjectRoot/bin/Linux.${__BuildArch}.${__BuildType}/framework - (cd ${__tizenToolsRoot} && wget -N "${__coreclrsite}${__coreclrsource}") + (cd ${__tizenToolsRoot} && wget -t0 -N "${__coreclrsite}${__coreclrsource}") export BUILDERRORLEVEL=$? if [ $BUILDERRORLEVEL != 0 ]; then exit $BUILDERRORLEVEL diff --git a/external/corert/buildscripts/buildvars-setup.cmd b/external/corert/buildscripts/buildvars-setup.cmd index 62beab9bab..6e52eda5d6 100644 --- a/external/corert/buildscripts/buildvars-setup.cmd +++ b/external/corert/buildscripts/buildvars-setup.cmd @@ -2,6 +2,12 @@ set __BuildArch=x64 set __BuildType=Debug set __BuildOS=Windows_NT +set __HostOS=Windows_NT + +:: Disable telemetry, first time experience, and global sdk look for the CLI +set DOTNET_CLI_TELEMETRY_OPTOUT=1 +set DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 +set DOTNET_MULTILEVEL_LOOKUP=0 :: Set the various build properties here so that CMake and MSBuild can pick them up set "__ProjectDir=%~dp0.." @@ -118,7 +124,7 @@ if defined VisualStudioVersion goto :RunVCVars set _VSWHERE="%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" if exist %_VSWHERE% ( - for /f "usebackq tokens=*" %%i in (`%_VSWHERE% -latest -prerelease -property installationPath`) do set _VSCOMNTOOLS=%%i\Common7\Tools + for /f "usebackq tokens=*" %%i in (`%_VSWHERE% -latest -prerelease -property installationPath -products *`) do set _VSCOMNTOOLS=%%i\Common7\Tools ) if not exist "%_VSCOMNTOOLS%" goto :MissingVersion @@ -162,8 +168,8 @@ set Platform= set __VCBuildArch=x86_amd64 if /i "%__BuildArch%" == "x86" (set __VCBuildArch=x86) -set __NugetRuntimeId=win7-x64 -if /i "%__BuildArch%" == "x86" (set __NugetRuntimeId=win7-x86) +set __NugetRuntimeId=win-x64 +if /i "%__BuildArch%" == "x86" (set __NugetRuntimeId=win-x86) :Done set BUILDVARS_DONE=1 diff --git a/external/corert/buildscripts/buildvars-setup.sh b/external/corert/buildscripts/buildvars-setup.sh index 1615565652..f41d79efc6 100755 --- a/external/corert/buildscripts/buildvars-setup.sh +++ b/external/corert/buildscripts/buildvars-setup.sh @@ -68,8 +68,6 @@ get_current_linux_rid() { # remove the last version digit VERSION_ID=${VERSION_ID%.*} rid=alpine.$VERSION_ID - elif [[ $ID == "ubuntu" ]]; then - rid=$ID.$VERSION_ID fi elif [ -e /etc/redhat-release ]; then @@ -82,6 +80,10 @@ get_current_linux_rid() { echo $rid } +# Disable telemetry, first time experience, and global sdk look for the CLI +export DOTNET_CLI_TELEMETRY_OPTOUT=1 +export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 +export DOTNET_MULTILEVEL_LOOKUP=0 export __scriptpath="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" export __ProjectRoot=$__scriptpath/.. @@ -109,6 +111,12 @@ export __CrossBuild=0 __BuildArch=$__HostArch +# Checking for any clang versions, if there is a symlink +if [ -x "$(command -v clang)" ]; then + __ClangMajorVersion="$(echo | clang -dM -E - | grep __clang_major__ | cut -f3 -d ' ')" + __ClangMinorVersion="$(echo | clang -dM -E - | grep __clang_minor__ | cut -f3 -d ' ')" +fi + while [ "$1" != "" ]; do lowerI="$(echo $1 | awk '{print tolower($0)}')" case $lowerI in @@ -171,6 +179,22 @@ while [ "$1" != "" ]; do export __ClangMajorVersion=3 export __ClangMinorVersion=9 ;; + clang4.0) + export __ClangMajorVersion=4 + export __ClangMinorVersion=0 + ;; + clang5.0) + export __ClangMajorVersion=5 + export __ClangMinorVersion=0 + ;; + clang6.0) + export __ClangMajorVersion=6 + export __ClangMinorVersion=0 + ;; + clang7.0) + export __ClangMajorVersion=7 + export __ClangMinorVersion=0 + ;; cross) export __CrossBuild=1 ;; @@ -193,41 +217,49 @@ done export $__BuildArch +# Use uname to determine what the OS is. +export OSName=$(uname -s) +case $OSName in + Darwin) + export __HostOS=OSX + export __NugetRuntimeId=osx-x64 + ulimit -n 2048 + ;; + + FreeBSD) + export __HostOS=FreeBSD + # TODO: Add proper FreeBSD target + export __NugetRuntimeId=linux-x64 + ;; + + Linux) + export __HostOS=Linux + export __NugetRuntimeId=$(get_current_linux_rid)-$__HostArch + ;; + + NetBSD) + export __HostOS=NetBSD + # TODO: Add proper NetBSD target + export __NugetRuntimeId=linux-x64 + ;; + + *) + echo "Unsupported OS $OSName detected, configuring as if for Linux" + export __HostOS=Linux + export __NugetRuntimeId=linux-x64 + ;; +esac + +# For msbuild +if [ $__HostOS != "OSX" ]; then + export CppCompilerAndLinker=clang-${__ClangMajorVersion}.${__ClangMinorVersion} +fi + +export __BuildOS="$__HostOS" + +# Overwrite __BuildOS with WebAssembly if wasm is target build arch, but keep the __NugetRuntimeId to match the Host OS if [ $__BuildArch == "wasm" ]; then export __BuildOS=WebAssembly -else - # Use uname to determine what the OS is. - export OSName=$(uname -s) - case $OSName in - Darwin) - export __BuildOS=OSX - export __NugetRuntimeId=osx.10.10-x64 - ulimit -n 2048 - ;; - - FreeBSD) - export __BuildOS=FreeBSD - # TODO: Add proper FreeBSD target - export __NugetRuntimeId=ubuntu.14.04-x64 - ;; - - Linux) - export __BuildOS=Linux - export __NugetRuntimeId=$(get_current_linux_rid)-$__HostArch - ;; - - NetBSD) - export __BuildOS=NetBSD - # TODO: Add proper NetBSD target - export __NugetRuntimeId=ubuntu.14.04-x64 - ;; - - *) - echo "Unsupported OS $OSName detected, configuring as if for Linux" - export __BuildOS=Linux - export __NugetRuntimeId=ubuntu.14.04-x64 - ;; - esac fi # If neither managed nor native are passed as arguments, default to building both diff --git a/external/corert/cross/arm/toolchain.cmake b/external/corert/cross/arm/toolchain.cmake index 35611cc50d..772148750d 100644 --- a/external/corert/cross/arm/toolchain.cmake +++ b/external/corert/cross/arm/toolchain.cmake @@ -9,14 +9,14 @@ add_compile_options(-mthumb) add_compile_options(-mfpu=vfpv3) add_compile_options(--sysroot=${CROSS_ROOTFS}) -set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} -target arm-linux-gnueabihf") +set(CROSS_LINK_FLAGS "-target arm-linux-gnueabihf") set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} -B ${CROSS_ROOTFS}/usr/lib/gcc/arm-linux-gnueabihf") set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} -L${CROSS_ROOTFS}/lib/arm-linux-gnueabihf") set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} --sysroot=${CROSS_ROOTFS}") -set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${CROSS_LINK_FLAGS}" CACHE STRING "" FORCE) -set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${CROSS_LINK_FLAGS}" CACHE STRING "" FORCE) -set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${CROSS_LINK_FLAGS}" CACHE STRING "" FORCE) +set(CMAKE_EXE_LINKER_FLAGS "${CROSS_LINK_FLAGS}" CACHE STRING "TOOLCHAIN_EXE_LINKER_FLAGS" FORCE) +set(CMAKE_SHARED_LINKER_FLAGS "${CROSS_LINK_FLAGS}" CACHE STRING "TOOLCHAIN_SHARED_LINKER_FLAGS" FORCE) +set(CMAKE_MODULE_LINKER_FLAGS "${CROSS_LINK_FLAGS}" CACHE STRING "TOOLCHAIN_MODULE_LINKER_FLAGS" FORCE) set(CMAKE_FIND_ROOT_PATH "${CROSS_ROOTFS}") set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) diff --git a/external/corert/cross/arm64/toolchain.cmake b/external/corert/cross/arm64/toolchain.cmake index cb92340f1b..18c4caafa8 100644 --- a/external/corert/cross/arm64/toolchain.cmake +++ b/external/corert/cross/arm64/toolchain.cmake @@ -7,14 +7,14 @@ set(CMAKE_SYSTEM_PROCESSOR aarch64) add_compile_options(-target aarch64-linux-gnu) add_compile_options(--sysroot=${CROSS_ROOTFS}) -set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} -target aarch64-linux-gnu") +set(CROSS_LINK_FLAGS "-target aarch64-linux-gnu") set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} -B ${CROSS_ROOTFS}/usr/lib/gcc/aarch64-linux-gnu") set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} -L${CROSS_ROOTFS}/lib/aarch64-linux-gnu") set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} --sysroot=${CROSS_ROOTFS}") -set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${CROSS_LINK_FLAGS}" CACHE STRING "" FORCE) -set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${CROSS_LINK_FLAGS}" CACHE STRING "" FORCE) -set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${CROSS_LINK_FLAGS}" CACHE STRING "" FORCE) +set(CMAKE_EXE_LINKER_FLAGS "${CROSS_LINK_FLAGS}" CACHE STRING "TOOLCHAIN_EXE_LINKER_FLAGS" FORCE) +set(CMAKE_SHARED_LINKER_FLAGS "${CROSS_LINK_FLAGS}" CACHE STRING "TOOLCHAIN_SHARED_LINKER_FLAGS" FORCE) +set(CMAKE_MODULE_LINKER_FLAGS "${CROSS_LINK_FLAGS}" CACHE STRING "TOOLCHAIN_MODULE_LINKER_FLAGS" FORCE) set(CMAKE_FIND_ROOT_PATH "${CROSS_ROOTFS}") set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) diff --git a/external/corert/cross/armel/toolchain.cmake b/external/corert/cross/armel/toolchain.cmake index 1dc6ec5d88..ac42b54ddc 100644 --- a/external/corert/cross/armel/toolchain.cmake +++ b/external/corert/cross/armel/toolchain.cmake @@ -19,7 +19,7 @@ add_compile_options(-mthumb) add_compile_options(-mfpu=vfpv3) add_compile_options(--sysroot=${CROSS_ROOTFS}) -set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} -target ${TOOLCHAIN}") +set(CROSS_LINK_FLAGS "-target ${TOOLCHAIN}") set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} --sysroot=${CROSS_ROOTFS}") if("$ENV{__DistroRid}" MATCHES "tizen.*") @@ -37,9 +37,9 @@ else() set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} -L${CROSS_ROOTFS}/usr/lib/gcc/${TOOLCHAIN}/4.9") endif() -set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${CROSS_LINK_FLAGS}" CACHE STRING "" FORCE) -set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${CROSS_LINK_FLAGS}" CACHE STRING "" FORCE) -set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${CROSS_LINK_FLAGS}" CACHE STRING "" FORCE) +set(CMAKE_EXE_LINKER_FLAGS "${CROSS_LINK_FLAGS}" CACHE STRING "TOOLCHAIN_EXE_LINKER_FLAGS" FORCE) +set(CMAKE_SHARED_LINKER_FLAGS "${CROSS_LINK_FLAGS}" CACHE STRING "TOOLCHAIN_SHARED_LINKER_FLAGS" FORCE) +set(CMAKE_MODULE_LINKER_FLAGS "${CROSS_LINK_FLAGS}" CACHE STRING "TOOLCHAIN_MODULE_LINKER_FLAGS" FORCE) set(CMAKE_FIND_ROOT_PATH "${CROSS_ROOTFS}") set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) diff --git a/external/corert/cross/x86/toolchain.cmake b/external/corert/cross/x86/toolchain.cmake index 1389a768fb..ccc3a03565 100644 --- a/external/corert/cross/x86/toolchain.cmake +++ b/external/corert/cross/x86/toolchain.cmake @@ -7,14 +7,14 @@ add_compile_options("-m32") add_compile_options("--sysroot=${CROSS_ROOTFS}") add_compile_options("-Wno-error=unused-command-line-argument") -set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} --sysroot=${CROSS_ROOTFS}") +set(CROSS_LINK_FLAGS "--sysroot=${CROSS_ROOTFS}") set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} -B ${CROSS_ROOTFS}/usr/lib/gcc/i686-linux-gnu") set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} -L${CROSS_ROOTFS}/lib/i386-linux-gnu") set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} -m32") -set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${CROSS_LINK_FLAGS}" CACHE STRING "" FORCE) -set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${CROSS_LINK_FLAGS}" CACHE STRING "" FORCE) -set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${CROSS_LINK_FLAGS}" CACHE STRING "" FORCE) +set(CMAKE_EXE_LINKER_FLAGS "${CROSS_LINK_FLAGS}" CACHE STRING "TOOLCHAIN_EXE_LINKER_FLAGS" FORCE) +set(CMAKE_SHARED_LINKER_FLAGS "${CROSS_LINK_FLAGS}" CACHE STRING "TOOLCHAIN_SHARED_LINKER_FLAGS" FORCE) +set(CMAKE_MODULE_LINKER_FLAGS "${CROSS_LINK_FLAGS}" CACHE STRING "TOOLCHAIN_MODULE_LINKER_FLAGS" FORCE) set(CMAKE_FIND_ROOT_PATH "${CROSS_ROOTFS}") set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) diff --git a/external/corert/dependencies.props b/external/corert/dependencies.props index dd8d755ceb..6d97c96dfc 100644 --- a/external/corert/dependencies.props +++ b/external/corert/dependencies.props @@ -1,10 +1,10 @@ - 2.1.0-preview1-26030-01 + 2.1.0-preview2-26207-13 1.0.19-prerelease-00001 - 4.5.0-preview1-26029-02 - 4.6.0-preview1-26029-02 - 2.1.0-preview1-26030-01 + 4.5.0-preview2-26202-05 + 4.6.0-preview2-26202-05 + 2.1.0-preview2-26207-13 2.0.0 1.0.1-prerelease-02104-02 diff --git a/external/corert/init-tools.sh b/external/corert/init-tools.sh index ed2cffd5d0..969c985487 100755 --- a/external/corert/init-tools.sh +++ b/external/corert/init-tools.sh @@ -130,11 +130,11 @@ if [ ! -e $__INIT_TOOLS_DONE_MARKER ]; then fi echo "Initializing BuildTools..." - echo "Running: $__BUILD_TOOLS_PATH/init-tools.sh $__scriptpath $__DOTNET_CMD $__TOOLRUNTIME_DIR" >> $__init_tools_log + echo "Running: $__BUILD_TOOLS_PATH/init-tools.sh $__scriptpath $__DOTNET_CMD $__TOOLRUNTIME_DIR $__PACKAGES_DIR" >> $__init_tools_log # Executables restored with .NET Core 2.0 do not have executable permission flags. https://github.com/NuGet/Home/issues/4424 chmod +x $__BUILD_TOOLS_PATH/init-tools.sh - $__BUILD_TOOLS_PATH/init-tools.sh $__scriptpath $__DOTNET_CMD $__TOOLRUNTIME_DIR >> $__init_tools_log + $__BUILD_TOOLS_PATH/init-tools.sh $__scriptpath $__DOTNET_CMD $__TOOLRUNTIME_DIR $__PACKAGES_DIR >> $__init_tools_log if [ "$?" != "0" ]; then echo "ERROR: An error occurred when trying to initialize the tools." 1>&2 display_error_message diff --git a/external/corert/samples/MonoGame/NeonShooter.csproj b/external/corert/samples/MonoGame/NeonShooter.csproj new file mode 100644 index 0000000000..3d6614148f --- /dev/null +++ b/external/corert/samples/MonoGame/NeonShooter.csproj @@ -0,0 +1,92 @@ + + + + Exe + netcoreapp2.0 + false + $(DefineConstants);WINDOWS;LINUX + + + + + + + + + Game.cs + + + Game\Art.cs + + + Game\BlackHole.cs + + + Game\BloomComponent.cs + + + Game\BloomSettings.cs + + + Game\Bullet.cs + + + Game\ColorUtil.cs + + + Game\Enemy.cs + + + Game\EnemySpawner.cs + + + Game\Entity.cs + + + Game\EntityManager.cs + + + Game\Extensions.cs + + + Game\Grid.cs + + + Game\Input.cs + + + Game\MathUtil.cs + + + Game\ParticleManager.cs + + + Game\ParticleState.cs + + + Game\PlayerShip.cs + + + Game\PlayerStatus.cs + + + Game\Sound.cs + + + Program.cs + + + + + + Content\NeonShooter.mgcb + + + + + + + + + + diff --git a/external/corert/samples/MonoGame/Platformer2D.csproj b/external/corert/samples/MonoGame/Platformer2D.csproj new file mode 100644 index 0000000000..b815519420 --- /dev/null +++ b/external/corert/samples/MonoGame/Platformer2D.csproj @@ -0,0 +1,71 @@ + + + + Exe + netcoreapp2.0 + false + $(DefineConstants);WINDOWS;LINUX + + + + + + + + + Game\Accelerometer.cs + + + Game\Animation.cs + + + Game\AnimationPlayer.cs + + + Game\Circle.cs + + + Game\Enemy.cs + + + Game\Gem.cs + + + Game\Level.cs + + + Game\Player.cs + + + Game\RectangleExtensions.cs + + + Game\Tile.cs + + + Game\TouchCollectionExtensions.cs + + + Game.cs + + + Game\VirtualGamePad.cs + + + Program.cs + + + + + + Content\Platformer2D.mgcb + + + + + + + + + + diff --git a/external/corert/samples/MonoGame/README.md b/external/corert/samples/MonoGame/README.md new file mode 100644 index 0000000000..2291d2bedf --- /dev/null +++ b/external/corert/samples/MonoGame/README.md @@ -0,0 +1,94 @@ +# Building a MonoGame app with CoreRT + +This document will guide you through compiling a .NET Core [MonoGame](http://www.monogame.net) game with CoreRT. + +## Install the .NET Core SDK +CoreRT is an AOT-optimized .NET Core runtime. If you're new to .NET Core make sure to visit the [official starting page](http://dotnet.github.io). It will guide you through installing pre-requisites and building your first app. +If you're already familiar with .NET Core make sure you've [downloaded and installed the .NET Core 2 SDK](https://www.microsoft.com/net/download/core). + +## Create .NET Core MonoGame project +Open a new shell/command prompt window and run the following commands. +```bash +> dotnet new --install MonoGame.Template.CSharp +> dotnet new mgdesktopgl -o MyGame +> cd MyGame +``` + +This will install .NET Core MonoGame template and create empty game project. .NET Core MonoGame port lives at https://github.com/cra0zy/MonoGame/tree/core currently. Thank you @cra0zy for the great work! + +Verify that the empty game builds and runs. You should see blue window: + +```bash +> dotnet run +``` + +MonoGame tools require [Mono](http://www.mono-project.com/download/) on non-Windows platforms. + +## Add CoreRT to your project +Using CoreRT to compile your application is done via the ILCompiler NuGet package, which is [published to MyGet with the CoreRT daily builds](https://dotnet.myget.org/feed/dotnet-core/package/nuget/Microsoft.DotNet.ILCompiler). +For the compiler to work, it first needs to be added to your project. + +In your shell/command prompt navigate to the root directory of your project and run the command: + +```bash +> dotnet new nuget +``` + +This will add a nuget.config file to your application. Open the file and in the `` `` element under ```` add the following: + +```xml + + +``` + +Once you've added the package source, add a reference to the compiler by running the following command: + +```bash +> dotnet add package Microsoft.DotNet.ILCompiler -v 1.0.0-alpha-* +``` + +## Restore and Publish your app + +Once the package has been successfully added it's time to compile and publish your app! In the shell/command prompt window, run the following command: + +```bash +> dotnet publish -r -c +``` + +where `` is your project configuration (such as Debug or Release) and `` is the runtime identifier (one of win-x64, linux-x64, osx-x64). For example, if you want to publish a release configuration of your app for a 64-bit version of Windows the command would look like: + +```bash +> dotnet publish -r win-x64 -c release +``` + +Once completed, you can find the native executable in the root folder of your project under `/bin/x64//netcoreapp2.0/publish/`. Navigate to `/bin/x64//netcoreapp2.0/publish/` in your project folder and run the produced native executable. + +## Try MonoGame sample game + +Clone MonoGame samples from github: + +```bash +> git clone https://github.com/MonoGame/MonoGame.Samples +``` + +MonoGame samples include project files for number of targets, but not for .NET Core yet. One has to create the project using above steps and transplant links to sample sources and assets to it. This directory contains .NET Core project for Platformer2D and NeonShooter samples that assume MonoGame.Samples is cloned under it. Build it and start playing! + +```bash +> dotnet publish -r win-x64 -c release Platformer2D.csproj +> bin\x64\Release\netcoreapp2.0\publish\Platformer2D.exe +``` + +The NeonShooter sample works on Windows-only due to https://github.com/MonoGame/MonoGame/issues/3270. + +## Using reflection +Runtime directives are XML configuration files, which specify which otherwise unreachable elements of your program are available for reflection. They are used at compile-time to enable AOT compilation in applications at runtime. The runtime directives are reference in the project via RdXmlFile item: + +```xml + + + +``` + +MonoGame serialization engine uses reflection to create types representing the game assets that needs to mentioned in the [rd.xml](rd.xml) file. If you see MissingMetadataException thrown during game startup, add the missing types to the rd.xml file. + +Feel free to modify the sample application and experiment. However, keep in mind some functionality might not yet be supported in CoreRT. Let us know on the [Issues page](https://github.com/dotnet/corert/issues/). diff --git a/external/corert/samples/MonoGame/nuget.config b/external/corert/samples/MonoGame/nuget.config new file mode 100644 index 0000000000..d8d3f2b015 --- /dev/null +++ b/external/corert/samples/MonoGame/nuget.config @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/external/corert/samples/MonoGame/rd.xml b/external/corert/samples/MonoGame/rd.xml new file mode 100644 index 0000000000..051a95f9a8 --- /dev/null +++ b/external/corert/samples/MonoGame/rd.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/external/corert/samples/WebApi/README.md b/external/corert/samples/WebApi/README.md index a47f25e124..5c5ca2ed03 100644 --- a/external/corert/samples/WebApi/README.md +++ b/external/corert/samples/WebApi/README.md @@ -75,10 +75,10 @@ If your application makes use of reflection, you will need to create a rd.xml fi At runtime, if a method or type is not found or cannot be loaded, an exception will be thrown. The exception message will contain information on the missing type reference, which you can then add to the rd.xml of your program. -Once you've created a rd.xml file, navigate to the root directory of your project and open its `.csproj` file and in the first `` element add the following: +Once you've created a rd.xml file, navigate to the root directory of your project and open its `.csproj` file and in the first `` element add the following: ```xml -path_to_rdxml_file\rd.xml + ``` where path_to_rdxml_file is the location of the file on your disk. @@ -120,13 +120,13 @@ public class ValuesController ## Restore and Publish your app -Once the package has been successfully added it's time to compile and publish your app! If you're using Windows, make sure you're using `x64 Native Tools Command Prompt for VS 2017` instead of the standard Windows command prompt. In the shell/command prompt window, run the following command: +Once the package has been successfully added it's time to compile and publish your app! In the shell/command prompt window, run the following command: ```bash > dotnet publish -r -c ``` -where `` is your project configuration (such as Debug or Release) and `` is the runtime identifier, which you specified in the csproj file (one of win-x64, linux-x64, osx-x64). For example, if you want to publish a release configuration of your app for a 64-bit version of Windows the command would look like: +where `` is your project configuration (such as Debug or Release) and `` is the runtime identifier (one of win-x64, linux-x64, osx-x64). For example, if you want to publish a release configuration of your app for a 64-bit version of Windows the command would look like: ```bash > dotnet publish -r win-x64 -c release @@ -136,6 +136,8 @@ Once completed, you can find the native executable in the root folder of your pr ## Try it out! +If you are running macOS, make sure you have [libuv](https://github.com/libuv/libuv) installed, as ASP.NET is built on top of libuv. You can use [homebrew](https://brew.sh/) to get it (`brew install libuv`). + Navigate to `/bin/x64//netcoreapp2.0/publish/` in your project folder and run the produced executable. It should display "Now listening on: http://localhost:XXXX" with XXXX being a port on your machine. Open your browser and navigate to that URL. You should see "Hello World!" displayed in your browser. Feel free to modify the sample application and experiment. However, keep in mind some functionality might not yet be supported in CoreRT. Let us know on the [Issues page](https://github.com/dotnet/corert/issues/). diff --git a/external/corert/samples/WebApi/SampleWebApi.csproj b/external/corert/samples/WebApi/SampleWebApi.csproj index d485b393d8..724c9b9c77 100644 --- a/external/corert/samples/WebApi/SampleWebApi.csproj +++ b/external/corert/samples/WebApi/SampleWebApi.csproj @@ -2,9 +2,12 @@ netcoreapp2.0 - rd.xml + + + + diff --git a/external/corert/src/BuildIntegration/Microsoft.NETCore.Native.Publish.targets b/external/corert/src/BuildIntegration/Microsoft.NETCore.Native.Publish.targets index 12743b911b..5a801d7652 100644 --- a/external/corert/src/BuildIntegration/Microsoft.NETCore.Native.Publish.targets +++ b/external/corert/src/BuildIntegration/Microsoft.NETCore.Native.Publish.targets @@ -50,6 +50,9 @@ + + + diff --git a/external/corert/src/BuildIntegration/Microsoft.NETCore.Native.Unix.props b/external/corert/src/BuildIntegration/Microsoft.NETCore.Native.Unix.props index 69539c5e13..441f4754c4 100644 --- a/external/corert/src/BuildIntegration/Microsoft.NETCore.Native.Unix.props +++ b/external/corert/src/BuildIntegration/Microsoft.NETCore.Native.Unix.props @@ -33,6 +33,11 @@ See the LICENSE file in the project root for more information. + + .a + .bc + + @@ -48,24 +53,28 @@ See the LICENSE file in the project root for more information. - - + + - - - - - - - - + + + + + + + + + + + + + - @@ -79,6 +88,7 @@ See the LICENSE file in the project root for more information. + diff --git a/external/corert/src/BuildIntegration/Microsoft.NETCore.Native.Windows.props b/external/corert/src/BuildIntegration/Microsoft.NETCore.Native.Windows.props index 0182d55187..eadca8826d 100644 --- a/external/corert/src/BuildIntegration/Microsoft.NETCore.Native.Windows.props +++ b/external/corert/src/BuildIntegration/Microsoft.NETCore.Native.Windows.props @@ -45,24 +45,23 @@ See the LICENSE file in the project root for more information. - - - - - - - - - - - - + + + + + + + + + + + + - @@ -77,9 +76,28 @@ See the LICENSE file in the project root for more information. - - + + - + + + + + + + + + + + + + + <_CppToolsDirectory>$(_FindVCVarsallOutput.Split(`#`)[0]) + "$(_CppToolsDirectory)cl.exe" + "$(_CppToolsDirectory)link.exe" + "$(_CppToolsDirectory)lib.exe" + + + diff --git a/external/corert/src/BuildIntegration/Microsoft.NETCore.Native.targets b/external/corert/src/BuildIntegration/Microsoft.NETCore.Native.targets index 6e03efac7a..23b817c7a7 100644 --- a/external/corert/src/BuildIntegration/Microsoft.NETCore.Native.targets +++ b/external/corert/src/BuildIntegration/Microsoft.NETCore.Native.targets @@ -141,7 +141,7 @@ See the LICENSE file in the project root for more information. @@ -155,7 +155,7 @@ See the LICENSE file in the project root for more information. - + @@ -202,6 +202,7 @@ See the LICENSE file in the project root for more information. + @@ -214,8 +215,8 @@ See the LICENSE file in the project root for more information. - - + + @@ -224,12 +225,13 @@ See the LICENSE file in the project root for more information. "$(NativeObject)" -o "$(NativeBinary)" -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 - $(EmccArgs) "$(IlcPath)\sdk\libPortableRuntime.bc" "$(IlcPath)\sdk\libbootstrappercpp.bc" + $(EmccArgs) "$(IlcPath)/sdk/libPortableRuntime.bc" "$(IlcPath)/sdk/libbootstrappercpp.bc" $(EmccArgs) -O2 --llvm-lto 2 $(EmccArgs) -g3 - + + diff --git a/external/corert/src/BuildIntegration/findvcvarsall.bat b/external/corert/src/BuildIntegration/findvcvarsall.bat new file mode 100644 index 0000000000..91c3bfe33d --- /dev/null +++ b/external/corert/src/BuildIntegration/findvcvarsall.bat @@ -0,0 +1,30 @@ +@ECHO OFF +SETLOCAL + +SET vswherePath=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe +IF NOT EXIST "%vswherePath%" GOTO :ERROR + +FOR /F "tokens=*" %%i IN ( ' + "%vswherePath%" -latest -prerelease -products * ^ + -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 ^ + -property installationPath' + ) DO SET vsBase=%%i + +IF "%vsBase%"=="" GOTO :ERROR + +CALL "%vsBase%\vc\Auxiliary\Build\vcvarsall.bat" %1% > NUL + +FOR /F "delims=" %%W IN ('where link') DO ( + FOR %%A IN ("%%W") DO ECHO %%~dpA# + GOTO :CAPTURE_LIB_PATHS +) + +:CAPTURE_LIB_PATHS +ECHO %LIB% + +EXIT /B 0 + +ENDLOCAL + +:ERROR + EXIT /B 1 diff --git a/external/corert/src/Common/src/Internal/NativeFormat/NativeFormat.cs b/external/corert/src/Common/src/Internal/NativeFormat/NativeFormat.cs index 6a430c0c8d..3c8539adcf 100644 --- a/external/corert/src/Common/src/Internal/NativeFormat/NativeFormat.cs +++ b/external/corert/src/Common/src/Internal/NativeFormat/NativeFormat.cs @@ -16,7 +16,7 @@ using System; // // - Naturally compressed: Integers are stored using variable length encoding. Offsets are stored as relative offsets. // -// - Random accesss: Random access to selected information should be fast. It is achieved by using tokens as offsets. +// - Random access: Random access to selected information should be fast. It is achieved by using tokens as offsets. // // - Locality: Access to related information should be accessing data that are close to each other. // diff --git a/external/corert/src/Common/src/Internal/NativeFormat/NativeFormatWriter.cs b/external/corert/src/Common/src/Internal/NativeFormat/NativeFormatWriter.cs index bdc3466076..c237fa62dc 100644 --- a/external/corert/src/Common/src/Internal/NativeFormat/NativeFormatWriter.cs +++ b/external/corert/src/Common/src/Internal/NativeFormat/NativeFormatWriter.cs @@ -260,7 +260,7 @@ namespace Internal.NativeFormat #endif } - // Aggresive phase that only allows offsets to shrink. + // Aggressive phase that only allows offsets to shrink. _phase = SavePhase.Shrinking; for (; ; ) { diff --git a/external/corert/src/Common/src/Internal/Text/Utf8StringBuilder.cs b/external/corert/src/Common/src/Internal/Text/Utf8StringBuilder.cs index 1fcca94507..0cdd95abcd 100644 --- a/external/corert/src/Common/src/Internal/Text/Utf8StringBuilder.cs +++ b/external/corert/src/Common/src/Internal/Text/Utf8StringBuilder.cs @@ -78,6 +78,11 @@ namespace Internal.Text return Encoding.UTF8.GetString(_buffer, 0, _length); } + public string ToString(int start) + { + return Encoding.UTF8.GetString(_buffer, start, _length - start); + } + public Utf8String ToUtf8String() { var ret = new byte[_length]; @@ -98,5 +103,50 @@ namespace Internal.Text Buffer.BlockCopy(_buffer, 0, newBuffer, 0, _length); _buffer = newBuffer; } + + // Find the boundary of the last character prior to a position + // If pos points to the last byte of a char, then return pos; Otherwise, + // return the position of the last byte of the preceding char. + public int LastCharBoundary(int pos) + { + Debug.Assert(pos < _length); + + if (_buffer[pos] < 128 /*10000000*/) + { + // This is a single byte character + return pos; + } + + int origPos = pos; + + // Skip following bytes of a multi-byte character until the first byte is seen + while (_buffer[pos] < 192 /*11000000*/) + { + pos--; + } + + if (pos == origPos - 3) + { + // We just skipped a four-byte character + Debug.Assert(_buffer[pos] >= 240 /*11110000*/); + return origPos; + } + + if (pos == origPos - 2 && _buffer[pos] < 240 && _buffer[pos] >= 224 /*11100000*/) + { + // We just skipped a three-byte character + return origPos; + } + + if (pos == origPos - 1 && _buffer[pos] < 224) + { + // We just skipped a two-byte character + Debug.Assert(_buffer[pos] >= 192 /*11000000*/); + return origPos; + } + + // We were in the middle of a multi-byte character + return pos - 1; + } } } diff --git a/external/corert/src/Common/src/Interop/Windows/mincore/Interop.MUI.cs b/external/corert/src/Common/src/Interop/Windows/mincore/Interop.MUI.cs deleted file mode 100644 index 247218b98a..0000000000 --- a/external/corert/src/Common/src/Interop/Windows/mincore/Interop.MUI.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Runtime.InteropServices; -using System.Text; - -internal static partial class Interop -{ - internal static unsafe partial class mincore - { - internal const int MUI_LANGUAGE_ID = 0x4; - internal const int MUI_LANGUAGE_NAME = 0x8; - internal const int MUI_PREFERRED_UI_LANGUAGES = 0x10; - internal const int MUI_INSTALLED_LANGUAGES = 0x20; - internal const int MUI_ALL_LANGUAGES = 0x40; - internal const int MUI_LANG_NEUTRAL_PE_FILE = 0x100; - internal const int MUI_NON_LANG_NEUTRAL_FILE = 0x200; - - [DllImport("api-ms-win-core-localization-l1-2-1.dll", CharSet = CharSet.Unicode)] - internal static extern bool GetFileMUIPath(int flags, String filePath, StringBuilder language, ref int languageLength, StringBuilder fileMuiPath, ref int fileMuiPathLength, ref Int64 enumerator); - } -} \ No newline at end of file diff --git a/external/corert/src/Common/src/Interop/Windows/mincore/Interop.TimeZone.Win32.cs b/external/corert/src/Common/src/Interop/Windows/mincore/Interop.TimeZone.Win32.cs deleted file mode 100644 index a7044fb3c4..0000000000 --- a/external/corert/src/Common/src/Interop/Windows/mincore/Interop.TimeZone.Win32.cs +++ /dev/null @@ -1,95 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Runtime.InteropServices; - -internal static partial class Interop -{ - internal static unsafe partial class mincore - { - [StructLayout(LayoutKind.Sequential)] - internal struct REGISTRY_TIME_ZONE_INFORMATION - { - public Int32 Bias; - public Int32 StandardBias; - public Int32 DaylightBias; - public SYSTEMTIME StandardDate; - public SYSTEMTIME DaylightDate; - - public REGISTRY_TIME_ZONE_INFORMATION(TIME_ZONE_INFORMATION tzi) - { - Bias = tzi.Bias; - StandardDate = tzi.StandardDate; - StandardBias = tzi.StandardBias; - DaylightDate = tzi.DaylightDate; - DaylightBias = tzi.DaylightBias; - } - - public REGISTRY_TIME_ZONE_INFORMATION(Byte[] bytes) - { - // - // typedef struct _REG_TZI_FORMAT { - // [00-03] LONG Bias; - // [04-07] LONG StandardBias; - // [08-11] LONG DaylightBias; - // [12-27] SYSTEMTIME StandardDate; - // [12-13] WORD wYear; - // [14-15] WORD wMonth; - // [16-17] WORD wDayOfWeek; - // [18-19] WORD wDay; - // [20-21] WORD wHour; - // [22-23] WORD wMinute; - // [24-25] WORD wSecond; - // [26-27] WORD wMilliseconds; - // [28-43] SYSTEMTIME DaylightDate; - // [28-29] WORD wYear; - // [30-31] WORD wMonth; - // [32-33] WORD wDayOfWeek; - // [34-35] WORD wDay; - // [36-37] WORD wHour; - // [38-39] WORD wMinute; - // [40-41] WORD wSecond; - // [42-43] WORD wMilliseconds; - // } REG_TZI_FORMAT; - // - if (bytes == null || bytes.Length != 44) - { - throw new ArgumentException(SR.Argument_InvalidREG_TZI_FORMAT, nameof(bytes)); - } - Bias = ToInt32(bytes, 0); - StandardBias = ToInt32(bytes, 4); - DaylightBias = ToInt32(bytes, 8); - - StandardDate.wYear = (ushort)ToInt16(bytes, 12); - StandardDate.wMonth = (ushort)ToInt16(bytes, 14); - StandardDate.wDayOfWeek = (ushort)ToInt16(bytes, 16); - StandardDate.wDay = (ushort)ToInt16(bytes, 18); - StandardDate.wHour = (ushort)ToInt16(bytes, 20); - StandardDate.wMinute = (ushort)ToInt16(bytes, 22); - StandardDate.wSecond = (ushort)ToInt16(bytes, 24); - StandardDate.wMilliseconds = (ushort)ToInt16(bytes, 26); - - DaylightDate.wYear = (ushort)ToInt16(bytes, 28); - DaylightDate.wMonth = (ushort)ToInt16(bytes, 30); - DaylightDate.wDayOfWeek = (ushort)ToInt16(bytes, 32); - DaylightDate.wDay = (ushort)ToInt16(bytes, 34); - DaylightDate.wHour = (ushort)ToInt16(bytes, 36); - DaylightDate.wMinute = (ushort)ToInt16(bytes, 38); - DaylightDate.wSecond = (ushort)ToInt16(bytes, 40); - DaylightDate.wMilliseconds = (ushort)ToInt16(bytes, 42); - } - - private static short ToInt16(byte[] value, int startIndex) - { - return (short)(value[startIndex] | (value[startIndex + 1] << 8)); - } - - private static int ToInt32(byte[] value, int startIndex) - { - return value[startIndex] | (value[startIndex + 1] << 8) | (value[startIndex + 2] << 16) | (value[startIndex + 3] << 24); - } - } - } -} diff --git a/external/corert/src/Common/src/Interop/Windows/mincore/Interop.TimeZone.cs b/external/corert/src/Common/src/Interop/Windows/mincore/Interop.TimeZone.cs index f40a5f4d4b..e2c80e9abf 100644 --- a/external/corert/src/Common/src/Interop/Windows/mincore/Interop.TimeZone.cs +++ b/external/corert/src/Common/src/Interop/Windows/mincore/Interop.TimeZone.cs @@ -75,7 +75,6 @@ internal static partial class Interop internal const int TIME_ZONE_ID_UNKNOWN = 0; internal const int TIME_ZONE_ID_STANDARD = 1; internal const int TIME_ZONE_ID_DAYLIGHT = 2; - internal const int MAX_PATH = 260; [DllImport("api-ms-win-core-timezone-l1-1-0.dll")] internal extern static uint EnumDynamicTimeZoneInformation(uint dwIndex, out TIME_DYNAMIC_ZONE_INFORMATION lpTimeZoneInformation); diff --git a/external/corert/src/Common/src/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs b/external/corert/src/Common/src/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs index c635b01342..d27fbf6b48 100644 --- a/external/corert/src/Common/src/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs +++ b/external/corert/src/Common/src/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs @@ -274,15 +274,22 @@ namespace Internal.TypeSystem return false; } - private static MethodDesc FindMatchingVirtualMethodOnTypeByNameAndSig(MethodDesc targetMethod, DefType currentType) + /// + /// Find matching a matching method by name and sig on a type. (Restricted to virtual methods only) + /// + /// + /// + /// Used to control the order of the search. For historical purposes to + /// match .NET Framework behavior, this is typically true, but not always. There is no particular rationale + /// for the particular orders other than to attempt to be consistent in virtual method override behavior + /// betweeen runtimes. + /// + /// + private static MethodDesc FindMatchingVirtualMethodOnTypeByNameAndSig(MethodDesc targetMethod, DefType currentType, bool reverseMethodSearch, Func nameSigMatchMethodIsValidCandidate) { string name = targetMethod.Name; MethodSignature sig = targetMethod.Signature; - // TODO: InstantiatedType.GetMethod can't handle this for a situation like - // an instantiation of Foo.M(T) because sig is instantiated, but it compares - // it to the uninstantiated version - //MethodDesc implMethod = currentType.GetMethod(name, sig); MethodDesc implMethod = null; foreach (MethodDesc candidate in currentType.GetAllMethods()) { @@ -293,11 +300,15 @@ namespace Internal.TypeSystem { if (candidate.Signature.Equals(sig)) { - if (implMethod != null) + if (nameSigMatchMethodIsValidCandidate == null || nameSigMatchMethodIsValidCandidate(targetMethod, candidate)) { - throw NotImplemented.ActiveIssue("https://github.com/dotnet/corert/issues/190"); + implMethod = candidate; + + // If reverseMethodSearch is enabled, we want to find the last match on this type, not the first + // (reverseMethodSearch is used for most matches except for searches for name/sig method matches for interface methods on the most derived type) + if (!reverseMethodSearch) + return implMethod; } - implMethod = candidate; } } } @@ -313,7 +324,7 @@ namespace Internal.TypeSystem { while (currentType != null) { - MethodDesc nameSigOverride = FindMatchingVirtualMethodOnTypeByNameAndSigWithSlotCheck(targetMethod, currentType); + MethodDesc nameSigOverride = FindMatchingVirtualMethodOnTypeByNameAndSigWithSlotCheck(targetMethod, currentType, reverseMethodSearch:true); if (nameSigOverride != null) { @@ -339,7 +350,7 @@ namespace Internal.TypeSystem // Loop until a newslot method is found while ((currentType != null) && !method.IsNewSlot) { - MethodDesc foundMethod = FindMatchingVirtualMethodOnTypeByNameAndSig(method, currentType); + MethodDesc foundMethod = FindMatchingVirtualMethodOnTypeByNameAndSig(method, currentType, reverseMethodSearch: true, nameSigMatchMethodIsValidCandidate:null); if (foundMethod != null) { method = foundMethod; @@ -353,22 +364,25 @@ namespace Internal.TypeSystem return method; } - private static MethodDesc FindMatchingVirtualMethodOnTypeByNameAndSigWithSlotCheck(MethodDesc method, DefType currentType) + /// + /// Find matching a matching method by name and sig on a type. (Restricted to virtual methods only) Only search amongst methods with the same vtable slot. + /// + /// + /// + /// Used to control the order of the search. For historical purposes to + /// match .NET Framework behavior, this is typically true, but not always. There is no particular rationale + /// for the particular orders other than to attempt to be consistent in virtual method override behavior + /// betweeen runtimes. + /// + private static MethodDesc FindMatchingVirtualMethodOnTypeByNameAndSigWithSlotCheck(MethodDesc method, DefType currentType, bool reverseMethodSearch) { - MethodDesc foundMethod = FindMatchingVirtualMethodOnTypeByNameAndSig(method, currentType); - if (foundMethod != null) - { - if (VerifyMethodsHaveTheSameVirtualSlot(foundMethod, method)) - { - return foundMethod; - } - } - - return null; + return FindMatchingVirtualMethodOnTypeByNameAndSig(method, currentType, reverseMethodSearch, nameSigMatchMethodIsValidCandidate: s_VerifyMethodsHaveTheSameVirtualSlot); } + private static Func s_VerifyMethodsHaveTheSameVirtualSlot = VerifyMethodsHaveTheSameVirtualSlot; + // Return true if the slot that defines methodToVerify matches slotDefiningMethod - private static bool VerifyMethodsHaveTheSameVirtualSlot(MethodDesc methodToVerify, MethodDesc slotDefiningMethod) + private static bool VerifyMethodsHaveTheSameVirtualSlot(MethodDesc slotDefiningMethod, MethodDesc methodToVerify) { MethodDesc slotDefiningMethodOfMethodToVerify = FindSlotDefiningMethodForVirtualMethod(methodToVerify); return slotDefiningMethodOfMethodToVerify == slotDefiningMethod; @@ -384,7 +398,7 @@ namespace Internal.TypeSystem unificationGroup.SetDefiningMethod(methodImpl); } - MethodDesc nameSigMatchMethod = FindMatchingVirtualMethodOnTypeByNameAndSigWithSlotCheck(unificationGroup.DefiningMethod, currentType); + MethodDesc nameSigMatchMethod = FindMatchingVirtualMethodOnTypeByNameAndSigWithSlotCheck(unificationGroup.DefiningMethod, currentType, reverseMethodSearch: true); MetadataType baseType = currentType.MetadataBaseType; // Unless the current type has a name/sig match for the group, look to the base type to define the unification group further @@ -404,7 +418,7 @@ namespace Internal.TypeSystem foreach (MethodDesc memberMethod in unificationGroup) { - MethodDesc nameSigMatchMemberMethod = FindMatchingVirtualMethodOnTypeByNameAndSigWithSlotCheck(memberMethod, currentType); + MethodDesc nameSigMatchMemberMethod = FindMatchingVirtualMethodOnTypeByNameAndSigWithSlotCheck(memberMethod, currentType, reverseMethodSearch: true); if (nameSigMatchMemberMethod != null) { if (separatedMethods == null) @@ -504,7 +518,9 @@ namespace Internal.TypeSystem if (foundExplicitInterface) { - MethodDesc foundOnCurrentType = FindMatchingVirtualMethodOnTypeByNameAndSig(interfaceMethod, currentType); + MethodDesc foundOnCurrentType = FindMatchingVirtualMethodOnTypeByNameAndSig(interfaceMethod, currentType + , reverseMethodSearch: false /* When searching for name/sig overrides on a type that explicitly defines an interface, search through the type in the forward direction*/ + , nameSigMatchMethodIsValidCandidate :null); foundOnCurrentType = FindSlotDefiningMethodForVirtualMethod(foundOnCurrentType); if (baseType == null) @@ -540,7 +556,16 @@ namespace Internal.TypeSystem } else { - return FindNameSigOverrideForInterfaceMethodRecursive(interfaceMethod, currentType); + MethodDesc foundOnCurrentType = FindMatchingVirtualMethodOnTypeByNameAndSig(interfaceMethod, currentType + , reverseMethodSearch: false /* When searching for name/sig overrides on a type that is the first type in the hierarchy to require the interface, search through the type in the forward direction*/ + , nameSigMatchMethodIsValidCandidate: null); + + foundOnCurrentType = FindSlotDefiningMethodForVirtualMethod(foundOnCurrentType); + + if (foundOnCurrentType != null) + return foundOnCurrentType; + + return FindNameSigOverrideForInterfaceMethodRecursive(interfaceMethod, baseType); } } } @@ -605,7 +630,10 @@ namespace Internal.TypeSystem if (currentType == null) return null; - MethodDesc nameSigOverride = FindMatchingVirtualMethodOnTypeByNameAndSig(interfaceMethod, currentType); + MethodDesc nameSigOverride = FindMatchingVirtualMethodOnTypeByNameAndSig(interfaceMethod, currentType + , reverseMethodSearch: true /* When searching for a name sig match for an interface on parent types search in reverse order of declaration */ + , nameSigMatchMethodIsValidCandidate:null); + if (nameSigOverride != null) { return FindSlotDefiningMethodForVirtualMethod(nameSigOverride); diff --git a/external/corert/src/Common/src/TypeSystem/Ecma/MetadataExtensions.cs b/external/corert/src/Common/src/TypeSystem/Ecma/MetadataExtensions.cs index db5912bfa9..bbe4eed38d 100644 --- a/external/corert/src/Common/src/TypeSystem/Ecma/MetadataExtensions.cs +++ b/external/corert/src/Common/src/TypeSystem/Ecma/MetadataExtensions.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Generic; using System.Reflection; using System.Reflection.Metadata; diff --git a/external/corert/src/Common/src/TypeSystem/IL/DelegateInfo.cs b/external/corert/src/Common/src/TypeSystem/IL/DelegateInfo.cs index 66267bf451..5322fc6181 100644 --- a/external/corert/src/Common/src/TypeSystem/IL/DelegateInfo.cs +++ b/external/corert/src/Common/src/TypeSystem/IL/DelegateInfo.cs @@ -209,7 +209,10 @@ namespace Internal.IL private static bool IsNativeCallingConventionCompatible(TypeDesc type) { - if (type.IsPointer || type.IsByRef) + if (type.IsPointer) + return true; + + if (type.IsByRef) return IsNativeCallingConventionCompatible(((ParameterizedType)type).ParameterType); if (!type.IsValueType) diff --git a/external/corert/src/Common/src/TypeSystem/IL/Stubs/ArrayMethodILEmitter.cs b/external/corert/src/Common/src/TypeSystem/IL/Stubs/ArrayMethodILEmitter.cs index 4e8e7a1715..e9a431af1b 100644 --- a/external/corert/src/Common/src/TypeSystem/IL/Stubs/ArrayMethodILEmitter.cs +++ b/external/corert/src/Common/src/TypeSystem/IL/Stubs/ArrayMethodILEmitter.cs @@ -87,7 +87,7 @@ namespace Internal.IL.Stubs var rangeExceptionLabel = _emitter.NewCodeLabel(); ILCodeLabel typeMismatchExceptionLabel = null; - if (!_elementType.IsValueType) + if (_elementType.IsGCPointer) { // Type check if (_method.Kind == ArrayMethodKind.Set) diff --git a/external/corert/src/Common/src/TypeSystem/IL/Stubs/ILEmitter.cs b/external/corert/src/Common/src/TypeSystem/IL/Stubs/ILEmitter.cs index 596a9b4bf0..042636f41b 100644 --- a/external/corert/src/Common/src/TypeSystem/IL/Stubs/ILEmitter.cs +++ b/external/corert/src/Common/src/TypeSystem/IL/Stubs/ILEmitter.cs @@ -549,25 +549,6 @@ namespace Internal.IL.Stubs } } - // Workaround for places that emit IL that doesn't conform to the ECMA-335 CIL stack requirements. - // https://github.com/dotnet/corert/issues/5152 - // This class and all references to it should be deleted when the issue is fixed. - // Do not add new references to this. - public class ILStubMethodILWithNonConformingStack : ILStubMethodIL - { - public ILStubMethodILWithNonConformingStack(MethodDesc owningMethod, byte[] ilBytes, LocalVariableDefinition[] locals, Object[] tokens, MethodDebugInformation debugInfo) - : base(owningMethod, ilBytes, locals, tokens, debugInfo) - { - } - - public ILStubMethodILWithNonConformingStack(ILStubMethodIL methodIL) - : base(methodIL) - { - } - - public override int MaxStack => GetILBytes().Length; - } - public class ILCodeLabel { private ILCodeStream _codeStream; @@ -665,7 +646,7 @@ namespace Internal.IL.Stubs return newLabel; } - public MethodIL Link(MethodDesc owningMethod, bool nonConformingStackWorkaround = false) + public MethodIL Link(MethodDesc owningMethod) { int totalLength = 0; int numSequencePoints = 0; @@ -711,17 +692,8 @@ namespace Internal.IL.Stubs debugInfo = new EmittedMethodDebugInformation(sequencePoints); } - ILStubMethodIL result; - if (nonConformingStackWorkaround) - { - // nonConformingStackWorkaround is a workaround for https://github.com/dotnet/corert/issues/5152 - result = new ILStubMethodILWithNonConformingStack(owningMethod, ilInstructions, _locals.ToArray(), _tokens.ToArray(), debugInfo); - } - else - { - result = new ILStubMethodIL(owningMethod, ilInstructions, _locals.ToArray(), _tokens.ToArray(), debugInfo); - result.CheckStackBalance(); - } + var result = new ILStubMethodIL(owningMethod, ilInstructions, _locals.ToArray(), _tokens.ToArray(), debugInfo); + result.CheckStackBalance(); return result; } diff --git a/external/corert/src/Common/src/TypeSystem/IL/Stubs/PInvokeILEmitter.cs b/external/corert/src/Common/src/TypeSystem/IL/Stubs/PInvokeILEmitter.cs index 6a0669b8c3..fa503b7427 100644 --- a/external/corert/src/Common/src/TypeSystem/IL/Stubs/PInvokeILEmitter.cs +++ b/external/corert/src/Common/src/TypeSystem/IL/Stubs/PInvokeILEmitter.cs @@ -107,6 +107,7 @@ namespace Internal.IL.Stubs { ILEmitter emitter = ilCodeStreams.Emitter; ILCodeStream fnptrLoadStream = ilCodeStreams.FunctionPointerLoadStream; + ILCodeStream marshallingCodeStream = ilCodeStreams.MarshallingCodeStream; ILCodeStream callsiteSetupCodeStream = ilCodeStreams.CallsiteSetupCodeStream; TypeSystemContext context = _targetMethod.Context; @@ -155,7 +156,7 @@ namespace Internal.IL.Stubs ILLocalVariable vDelegateStub = emitter.NewLocal(delegateMethod.DelegateType); fnptrLoadStream.EmitStLoc(vDelegateStub); - fnptrLoadStream.EmitLdLoc(vDelegateStub); + marshallingCodeStream.EmitLdLoc(vDelegateStub); MethodDesc invokeMethod = delegateMethod.DelegateType.GetKnownMethod("Invoke", null); callsiteSetupCodeStream.Emit(ILOpcode.callvirt, emitter.NewToken(invokeMethod)); } @@ -304,10 +305,10 @@ namespace Internal.IL.Stubs EmitPInvokeCall(pInvokeILCodeStreams); } + _marshallers[0].LoadReturnValue(unmarshallingCodestream); unmarshallingCodestream.Emit(ILOpcode.ret); - return new PInvokeILStubMethodIL((ILStubMethodIL)emitter.Link(_targetMethod, nonConformingStackWorkaround: true), - IsStubRequired()); + return new PInvokeILStubMethodIL((ILStubMethodIL)emitter.Link(_targetMethod), IsStubRequired()); } public static MethodIL EmitIL(MethodDesc method, @@ -395,7 +396,7 @@ namespace Internal.IL.Stubs } } - public sealed class PInvokeILStubMethodIL : ILStubMethodILWithNonConformingStack + public sealed class PInvokeILStubMethodIL : ILStubMethodIL { public bool IsStubRequired { get; } public PInvokeILStubMethodIL(ILStubMethodIL methodIL, bool isStubRequired) : base(methodIL) diff --git a/external/corert/src/Common/src/TypeSystem/IL/Stubs/UnsafeIntrinsics.cs b/external/corert/src/Common/src/TypeSystem/IL/Stubs/UnsafeIntrinsics.cs index 86ce8c7f92..7bc575a771 100644 --- a/external/corert/src/Common/src/TypeSystem/IL/Stubs/UnsafeIntrinsics.cs +++ b/external/corert/src/Common/src/TypeSystem/IL/Stubs/UnsafeIntrinsics.cs @@ -52,6 +52,18 @@ namespace Internal.IL.Stubs (byte)ILOpcode.ldarg_0, (byte)ILOpcode.ldarg_1, (byte)ILOpcode.prefix1, unchecked((byte)ILOpcode.ceq), (byte)ILOpcode.ret }, Array.Empty(), null); + case "IsAddressGreaterThan": + return new ILStubMethodIL(method, new byte[] + { + (byte)ILOpcode.ldarg_0, (byte)ILOpcode.ldarg_1, + (byte)ILOpcode.prefix1, unchecked((byte)ILOpcode.cgt_un), + (byte)ILOpcode.ret }, Array.Empty(), null); + case "IsAddressLessThan": + return new ILStubMethodIL(method, new byte[] + { + (byte)ILOpcode.ldarg_0, (byte)ILOpcode.ldarg_1, + (byte)ILOpcode.prefix1, unchecked((byte)ILOpcode.clt_un), + (byte)ILOpcode.ret }, Array.Empty(), null); case "ByteOffset": return new ILStubMethodIL(method, new byte[] { diff --git a/external/corert/src/Common/src/TypeSystem/IL/Stubs/ValueTypeGetFieldHelperMethodOverride.Sorting.cs b/external/corert/src/Common/src/TypeSystem/IL/Stubs/ValueTypeGetFieldHelperMethodOverride.Sorting.cs new file mode 100644 index 0000000000..4122b8c3cd --- /dev/null +++ b/external/corert/src/Common/src/TypeSystem/IL/Stubs/ValueTypeGetFieldHelperMethodOverride.Sorting.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Internal.TypeSystem; + +namespace Internal.IL.Stubs +{ + partial class ValueTypeGetFieldHelperMethodOverride + { + protected internal override int ClassCode => 2036839816; + + protected internal override int CompareToImpl(MethodDesc other, TypeSystemComparer comparer) + { + var otherMethod = (ValueTypeGetFieldHelperMethodOverride)other; + + return comparer.Compare(_owningType, otherMethod._owningType); + } + } +} diff --git a/external/corert/src/Common/src/TypeSystem/IL/Stubs/ValueTypeGetFieldHelperMethodOverride.cs b/external/corert/src/Common/src/TypeSystem/IL/Stubs/ValueTypeGetFieldHelperMethodOverride.cs new file mode 100644 index 0000000000..33d71794a6 --- /dev/null +++ b/external/corert/src/Common/src/TypeSystem/IL/Stubs/ValueTypeGetFieldHelperMethodOverride.cs @@ -0,0 +1,145 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; + +using Internal.TypeSystem; + +namespace Internal.IL.Stubs +{ + /// + /// Synthetic method override of "int ValueType.__GetFieldHelper(Int32, out EETypePtr)". This method is injected + /// into all value types that cannot have their Equals(object) and GetHashCode() methods operate on individual + /// bytes. The purpose of the override is to provide access to the value types' fields and their types. + /// + public sealed partial class ValueTypeGetFieldHelperMethodOverride : ILStubMethod + { + private DefType _owningType; + private MethodSignature _signature; + + internal ValueTypeGetFieldHelperMethodOverride(DefType owningType) + { + _owningType = owningType; + } + + public override TypeSystemContext Context + { + get + { + return _owningType.Context; + } + } + + public override TypeDesc OwningType + { + get + { + return _owningType; + } + } + + public override MethodSignature Signature + { + get + { + if (_signature == null) + { + TypeSystemContext context = _owningType.Context; + TypeDesc int32Type = context.GetWellKnownType(WellKnownType.Int32); + TypeDesc eeTypePtrType = context.SystemModule.GetKnownType("System", "EETypePtr"); + + _signature = new MethodSignature(0, 0, int32Type, new[] { + int32Type, + eeTypePtrType.MakeByRefType() + }); + } + + return _signature; + } + } + + public override MethodIL EmitIL() + { + TypeDesc owningType = _owningType.InstantiateAsOpen(); + + ILEmitter emitter = new ILEmitter(); + + TypeDesc eeTypePtrType = Context.SystemModule.GetKnownType("System", "EETypePtr"); + MethodDesc eeTypePtrOfMethod = eeTypePtrType.GetKnownMethod("EETypePtrOf", null); + ILToken eeTypePtrToken = emitter.NewToken(eeTypePtrType); + + var switchStream = emitter.NewCodeStream(); + var getFieldStream = emitter.NewCodeStream(); + + ArrayBuilder fieldGetters = new ArrayBuilder(); + foreach (FieldDesc field in owningType.GetFields()) + { + if (field.IsStatic) + continue; + + ILCodeLabel label = emitter.NewCodeLabel(); + fieldGetters.Add(label); + + getFieldStream.EmitLabel(label); + getFieldStream.EmitLdArg(2); + + // We need something we can instantiate EETypePtrOf over. Also, the classlib + // code doesn't handle pointers. + TypeDesc boxableFieldType = field.FieldType; + if (boxableFieldType.IsPointer || boxableFieldType.IsFunctionPointer) + boxableFieldType = Context.GetWellKnownType(WellKnownType.IntPtr); + + MethodDesc ptrOfField = eeTypePtrOfMethod.MakeInstantiatedMethod(boxableFieldType); + getFieldStream.Emit(ILOpcode.call, emitter.NewToken(ptrOfField)); + + getFieldStream.Emit(ILOpcode.stobj, eeTypePtrToken); + + getFieldStream.EmitLdArg(0); + getFieldStream.Emit(ILOpcode.ldflda, emitter.NewToken(field)); + + getFieldStream.EmitLdArg(0); + + getFieldStream.Emit(ILOpcode.sub); + + getFieldStream.Emit(ILOpcode.ret); + } + + if (fieldGetters.Count > 0) + { + switchStream.EmitLdArg(1); + switchStream.EmitSwitch(fieldGetters.ToArray()); + } + + switchStream.EmitLdc(fieldGetters.Count); + + switchStream.Emit(ILOpcode.ret); + + return emitter.Link(this); + } + + public override Instantiation Instantiation + { + get + { + return Instantiation.Empty; + } + } + + public override bool IsVirtual + { + get + { + return true; + } + } + + public override string Name + { + get + { + return "__GetFieldHelper"; + } + } + } +} diff --git a/external/corert/src/Common/src/TypeSystem/IL/TypeSystemContext.ValueTypeMethods.cs b/external/corert/src/Common/src/TypeSystem/IL/TypeSystemContext.ValueTypeMethods.cs new file mode 100644 index 0000000000..a1487a5ac5 --- /dev/null +++ b/external/corert/src/Common/src/TypeSystem/IL/TypeSystemContext.ValueTypeMethods.cs @@ -0,0 +1,243 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; + +using Internal.IL.Stubs; + +using Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + public abstract partial class TypeSystemContext + { + private MethodDesc _objectEqualsMethod; + + private class ValueTypeMethodHashtable : LockFreeReaderHashtable + { + protected override int GetKeyHashCode(DefType key) => key.GetHashCode(); + protected override int GetValueHashCode(MethodDesc value) => value.OwningType.GetHashCode(); + protected override bool CompareKeyToValue(DefType key, MethodDesc value) => key == value.OwningType; + protected override bool CompareValueToValue(MethodDesc v1, MethodDesc v2) => v1.OwningType == v2.OwningType; + + protected override MethodDesc CreateValueFromKey(DefType key) + { + return new ValueTypeGetFieldHelperMethodOverride(key); + } + } + + private ValueTypeMethodHashtable _valueTypeMethodHashtable = new ValueTypeMethodHashtable(); + + protected virtual IEnumerable GetAllMethodsForValueType(TypeDesc valueType) + { + TypeDesc valueTypeDefinition = valueType.GetTypeDefinition(); + + if (RequiresGetFieldHelperMethod((MetadataType)valueTypeDefinition)) + { + MethodDesc getFieldHelperMethod = _valueTypeMethodHashtable.GetOrCreateValue((DefType)valueTypeDefinition); + + // Check that System.ValueType has the method we're overriding. + Debug.Assert(valueTypeDefinition.BaseType.GetMethod(getFieldHelperMethod.Name, null) != null); + + if (valueType != valueTypeDefinition) + { + yield return GetMethodForInstantiatedType(getFieldHelperMethod, (InstantiatedType)valueType); + } + else + { + yield return getFieldHelperMethod; + } + } + + foreach (MethodDesc method in valueType.GetMethods()) + yield return method; + } + + private bool RequiresGetFieldHelperMethod(MetadataType valueType) + { + if (_objectEqualsMethod == null) + _objectEqualsMethod = GetWellKnownType(WellKnownType.Object).GetMethod("Equals", null); + + // If the classlib doesn't have Object.Equals, we don't need this. + if (_objectEqualsMethod == null) + return false; + + // Byref-like valuetypes cannot be boxed. + if (valueType.IsByRefLike) + return false; + + // Enums get their overrides from System.Enum. + if (valueType.IsEnum) + return false; + + return !_typeStateHashtable.GetOrCreateValue(valueType).CanCompareValueTypeBits; + } + + private class TypeState + { + private enum Flags + { + CanCompareValueTypeBits = 0x0000_0001, + CanCompareValueTypeBitsComputed = 0x0000_0002, + } + + private volatile Flags _flags; + private readonly TypeStateHashtable _hashtable; + + public TypeDesc Type { get; } + + public bool CanCompareValueTypeBits + { + get + { + Flags flags = _flags; + if ((flags & Flags.CanCompareValueTypeBitsComputed) == 0) + { + Debug.Assert(Type.IsValueType); + if (ComputeCanCompareValueTypeBits((MetadataType)Type)) + flags |= Flags.CanCompareValueTypeBits; + flags |= Flags.CanCompareValueTypeBitsComputed; + + _flags = flags; + } + return (flags & Flags.CanCompareValueTypeBits) != 0; + } + } + + public TypeState(TypeDesc type, TypeStateHashtable hashtable) + { + Type = type; + _hashtable = hashtable; + } + + private bool ComputeCanCompareValueTypeBits(MetadataType type) + { + Debug.Assert(type.IsValueType); + + if (type.ContainsGCPointers) + return false; + + if (type.IsGenericDefinition) + return false; + + OverlappingFieldTracker overlappingFieldTracker = new OverlappingFieldTracker(type); + + bool result = true; + foreach (var field in type.GetFields()) + { + if (field.IsStatic) + continue; + + if (!overlappingFieldTracker.TrackField(field)) + { + // This field overlaps with another field - can't compare memory + result = false; + break; + } + + TypeDesc fieldType = field.FieldType; + if (fieldType.IsPrimitive || fieldType.IsEnum || fieldType.IsPointer || fieldType.IsFunctionPointer) + { + TypeFlags category = fieldType.UnderlyingType.Category; + if (category == TypeFlags.Single || category == TypeFlags.Double) + { + // Double/Single have weird behaviors around negative/positive zero + result = false; + break; + } + } + else + { + // Would be a suprise if this wasn't a valuetype. We checked ContainsGCPointers above. + Debug.Assert(fieldType.IsValueType); + + MethodDesc objectEqualsMethod = fieldType.Context._objectEqualsMethod; + + // If the field overrides Equals, we can't use the fast helper because we need to call the method. + if (fieldType.FindVirtualFunctionTargetMethodOnObjectType(objectEqualsMethod).OwningType == fieldType) + { + result = false; + break; + } + + if (!_hashtable.GetOrCreateValue((MetadataType)fieldType).CanCompareValueTypeBits) + { + result = false; + break; + } + } + } + + // If there are gaps, we can't memcompare + if (result && overlappingFieldTracker.HasGaps) + result = false; + + return result; + } + } + + private class TypeStateHashtable : LockFreeReaderHashtable + { + protected override int GetKeyHashCode(TypeDesc key) => key.GetHashCode(); + protected override int GetValueHashCode(TypeState value) => value.Type.GetHashCode(); + protected override bool CompareKeyToValue(TypeDesc key, TypeState value) => key == value.Type; + protected override bool CompareValueToValue(TypeState v1, TypeState v2) => v1.Type == v2.Type; + + protected override TypeState CreateValueFromKey(TypeDesc key) + { + return new TypeState(key, this); + } + } + private TypeStateHashtable _typeStateHashtable = new TypeStateHashtable(); + + private struct OverlappingFieldTracker + { + private bool[] _usedBytes; + + public OverlappingFieldTracker(MetadataType type) + { + _usedBytes = new bool[type.InstanceFieldSize.AsInt]; + } + + public bool TrackField(FieldDesc field) + { + int fieldBegin = field.Offset.AsInt; + + TypeDesc fieldType = field.FieldType; + + int fieldEnd; + if (fieldType.IsPointer || fieldType.IsFunctionPointer) + { + fieldEnd = fieldBegin + field.Context.Target.PointerSize; + } + else + { + Debug.Assert(fieldType.IsValueType); + fieldEnd = fieldBegin + ((DefType)fieldType).InstanceFieldSize.AsInt; + } + + for (int i = fieldBegin; i < fieldEnd; i++) + { + if (_usedBytes[i]) + return false; + _usedBytes[i] = true; + } + + return true; + } + + public bool HasGaps + { + get + { + for (int i = 0; i < _usedBytes.Length; i++) + if (!_usedBytes[i]) + return true; + + return false; + } + } + } + } +} diff --git a/external/corert/src/Common/src/TypeSystem/Interop/IL/MarshalHelpers.cs b/external/corert/src/Common/src/TypeSystem/Interop/IL/MarshalHelpers.cs index 78fc4d24ae..a65a6a3a6e 100644 --- a/external/corert/src/Common/src/TypeSystem/Interop/IL/MarshalHelpers.cs +++ b/external/corert/src/Common/src/TypeSystem/Interop/IL/MarshalHelpers.cs @@ -101,6 +101,10 @@ namespace Internal.TypeSystem.Interop if (importModule == "[MRT]" || importModule == "*") return false; + // Force link time symbol resolution for "__Internal" module for compatibility with Mono + if (importModule == "__Internal") + return false; + if (method.Context.Target.IsWindows) { return !importModule.StartsWith("api-ms-win-"); @@ -847,9 +851,8 @@ namespace Internal.TypeSystem.Interop codeStream.Emit(ILOpcode.ldstr, emitter.NewToken(message)); codeStream.Emit(ILOpcode.newobj, emitter.NewToken(exceptionCtor)); codeStream.Emit(ILOpcode.throw_); - codeStream.Emit(ILOpcode.ret); - return new PInvokeILStubMethodIL((ILStubMethodIL)emitter.Link(method, nonConformingStackWorkaround: true), true); + return new PInvokeILStubMethodIL((ILStubMethodIL)emitter.Link(method), isStubRequired: true); } } diff --git a/external/corert/src/Common/src/TypeSystem/Interop/IL/Marshaller.cs b/external/corert/src/Common/src/TypeSystem/Interop/IL/Marshaller.cs index a8f5078a2a..ef75539f16 100644 --- a/external/corert/src/Common/src/TypeSystem/Interop/IL/Marshaller.cs +++ b/external/corert/src/Common/src/TypeSystem/Interop/IL/Marshaller.cs @@ -434,7 +434,7 @@ namespace Internal.TypeSystem.Interop } } - public void EmitArgumentMarshallingIL() + private void EmitArgumentMarshallingIL() { switch (MarshalDirection) { @@ -443,7 +443,7 @@ namespace Internal.TypeSystem.Interop } } - public void EmitElementMarshallingIL() + private void EmitElementMarshallingIL() { switch (MarshalDirection) { @@ -452,7 +452,7 @@ namespace Internal.TypeSystem.Interop } } - public void EmitFieldMarshallingIL() + private void EmitFieldMarshallingIL() { switch (MarshalDirection) { @@ -526,14 +526,22 @@ namespace Internal.TypeSystem.Interop StoreNativeValue(_ilCodeStreams.ReturnValueMarshallingCodeStream); AllocAndTransformNativeToManaged(_ilCodeStreams.ReturnValueMarshallingCodeStream); + } - LoadManagedValue(_ilCodeStreams.ReturnValueMarshallingCodeStream); + public virtual void LoadReturnValue(ILCodeStream codeStream) + { + Debug.Assert(Return); + + switch (MarshalDirection) + { + case MarshalDirection.Forward: LoadManagedValue(codeStream); return; + case MarshalDirection.Reverse: LoadNativeValue(codeStream); return; + } } protected virtual void SetupArguments() { ILEmitter emitter = _ilCodeStreams.Emitter; - ILCodeStream marshallingCodeStream = _ilCodeStreams.MarshallingCodeStream; if (MarshalDirection == MarshalDirection.Forward) { @@ -560,7 +568,6 @@ namespace Internal.TypeSystem.Interop protected virtual void SetupArgumentsForElementMarshalling() { ILEmitter emitter = _ilCodeStreams.Emitter; - ILCodeStream marshallingCodeStream = _ilCodeStreams.MarshallingCodeStream; _managedHome = new Home(emitter.NewLocal(ManagedType), ManagedType, isByRef: false); _nativeHome = new Home(emitter.NewLocal(NativeType), NativeType, isByRef: false); @@ -569,7 +576,6 @@ namespace Internal.TypeSystem.Interop protected virtual void SetupArgumentsForFieldMarshalling() { ILEmitter emitter = _ilCodeStreams.Emitter; - ILCodeStream marshallingCodeStream = _ilCodeStreams.MarshallingCodeStream; // // these are temporary locals for propagating value @@ -581,7 +587,6 @@ namespace Internal.TypeSystem.Interop protected virtual void SetupArgumentsForReturnValueMarshalling() { ILEmitter emitter = _ilCodeStreams.Emitter; - ILCodeStream marshallingCodeStream = _ilCodeStreams.MarshallingCodeStream; _managedHome = new Home(emitter.NewLocal(ManagedType), ManagedType, isByRef: false); _nativeHome = new Home(emitter.NewLocal(NativeType), NativeType, isByRef: false); @@ -768,8 +773,6 @@ namespace Internal.TypeSystem.Interop StoreManagedValue(_ilCodeStreams.ReturnValueMarshallingCodeStream); AllocAndTransformManagedToNative(_ilCodeStreams.ReturnValueMarshallingCodeStream); - - LoadNativeValue(_ilCodeStreams.ReturnValueMarshallingCodeStream); } protected virtual void EmitMarshalArgumentNativeToManaged() @@ -902,6 +905,10 @@ namespace Internal.TypeSystem.Interop protected override void EmitMarshalReturnValueNativeToManaged() { } + public override void LoadReturnValue(ILCodeStream codeStream) + { + Debug.Assert(Return); + } } class BlittableValueMarshaller : Marshaller @@ -1095,7 +1102,7 @@ namespace Internal.TypeSystem.Interop codeStream.Emit(ILOpcode.brfalse, lNullArray); // allocate memory - // nativeParameter = (byte**)CoTaskMemAllocAndZeroMemory((IntPtr)(checked(manageParameter.Length * sizeof(byte*)))); + // nativeParameter = (byte**)CoTaskMemAllocAndZeroMemory((IntPtr)(checked(managedParameter.Length * sizeof(byte*)))); // loads the number of elements EmitElementCount(codeStream, MarshalDirection.Forward); @@ -1104,10 +1111,6 @@ namespace Internal.TypeSystem.Interop codeStream.Emit(ILOpcode.sizeof_, emitter.NewToken(nativeElementType)); codeStream.Emit(ILOpcode.mul_ovf); - codeStream.Emit(ILOpcode.call, emitter.NewToken( - Context.SystemModule. - GetKnownType("System", "IntPtr"). - GetKnownMethod("op_Explicit", null))); codeStream.Emit(ILOpcode.call, emitter.NewToken( Context.GetHelperEntryPoint("InteropHelpers", "CoTaskMemAllocAndZeroMemory"))); @@ -1174,8 +1177,7 @@ namespace Internal.TypeSystem.Interop codeStream.EmitLdLoc(vIndex); codeStream.EmitLdLoc(vLength); - codeStream.Emit(ILOpcode.clt); - codeStream.Emit(ILOpcode.brtrue, lLoopHeader); + codeStream.Emit(ILOpcode.blt, lLoopHeader); codeStream.EmitLabel(lNullArray); } @@ -1243,8 +1245,7 @@ namespace Internal.TypeSystem.Interop codeStream.EmitLabel(lRangeCheck); codeStream.EmitLdLoc(vIndex); codeStream.EmitLdLoc(vLength); - codeStream.Emit(ILOpcode.clt); - codeStream.Emit(ILOpcode.brtrue, lLoopHeader); + codeStream.Emit(ILOpcode.blt, lLoopHeader); codeStream.EmitLabel(lNullArray); } @@ -1323,8 +1324,7 @@ namespace Internal.TypeSystem.Interop codeStream.EmitLdLoc(vIndex); codeStream.EmitLdLoc(vLength); - codeStream.Emit(ILOpcode.clt); - codeStream.Emit(ILOpcode.brtrue, lLoopHeader); + codeStream.Emit(ILOpcode.blt, lLoopHeader); } LoadNativeValue(codeStream); @@ -1831,7 +1831,7 @@ namespace Internal.TypeSystem.Interop LoadManagedValue(codeStream); codeStream.Emit(ILOpcode.call, _ilCodeStreams.Emitter.NewToken( - Context.GetHelperEntryPoint("InteropHelpers", "GetStubForPInvokeDelegate"))); + Context.GetHelperEntryPoint("InteropHelpers", "GetFunctionPointerForDelegate"))); StoreNativeValue(codeStream); } @@ -1842,7 +1842,7 @@ namespace Internal.TypeSystem.Interop codeStream.Emit(ILOpcode.ldtoken, _ilCodeStreams.Emitter.NewToken(ManagedType)); codeStream.Emit(ILOpcode.call, _ilCodeStreams.Emitter.NewToken( - Context.GetHelperEntryPoint("InteropHelpers", "GetPInvokeDelegateForStub"))); + Context.GetHelperEntryPoint("InteropHelpers", "GetDelegateForFunctionPointer"))); StoreManagedValue(codeStream); } @@ -2042,8 +2042,7 @@ namespace Internal.TypeSystem.Interop codeStream.EmitLdLoc(vIndex); codeStream.EmitLdLoc(vLength); - codeStream.Emit(ILOpcode.clt); - codeStream.Emit(ILOpcode.brtrue, lLoopHeader); + codeStream.Emit(ILOpcode.blt, lLoopHeader); codeStream.EmitLabel(lDone); } @@ -2121,8 +2120,7 @@ namespace Internal.TypeSystem.Interop codeStream.EmitLdLoc(vIndex); codeStream.EmitLdLoc(vLength); - codeStream.Emit(ILOpcode.clt); - codeStream.Emit(ILOpcode.brtrue, lLoopHeader); + codeStream.Emit(ILOpcode.blt, lLoopHeader); } } diff --git a/external/corert/src/Common/src/TypeSystem/RuntimeDetermined/DefType.RuntimeDetermined.cs b/external/corert/src/Common/src/TypeSystem/RuntimeDetermined/DefType.RuntimeDetermined.cs index 58dedeb743..02d1b25233 100644 --- a/external/corert/src/Common/src/TypeSystem/RuntimeDetermined/DefType.RuntimeDetermined.cs +++ b/external/corert/src/Common/src/TypeSystem/RuntimeDetermined/DefType.RuntimeDetermined.cs @@ -10,6 +10,10 @@ namespace Internal.TypeSystem { get { + // Handles situation when shared code refers to uninstantiated generic + // type definitions (think: LDTOKEN). + // Walking the instantiation would make us assert. This is simply + // not a runtime determined type. if (IsGenericDefinition) return false; @@ -80,4 +84,4 @@ namespace Internal.TypeSystem return this; } } -} \ No newline at end of file +} diff --git a/external/corert/src/Common/src/TypeSystem/RuntimeDetermined/MethodDesc.RuntimeDetermined.cs b/external/corert/src/Common/src/TypeSystem/RuntimeDetermined/MethodDesc.RuntimeDetermined.cs index ad83c69f67..8fd47116dd 100644 --- a/external/corert/src/Common/src/TypeSystem/RuntimeDetermined/MethodDesc.RuntimeDetermined.cs +++ b/external/corert/src/Common/src/TypeSystem/RuntimeDetermined/MethodDesc.RuntimeDetermined.cs @@ -84,6 +84,13 @@ namespace Internal.TypeSystem if (containingType.IsRuntimeDeterminedSubtype) return true; + // Handles situation when shared code refers to uninstantiated generic + // method definitions (think: LDTOKEN). + // Walking the instantiation would make us assert. This is simply + // not a runtime determined method. + if (IsGenericMethodDefinition) + return false; + foreach (TypeDesc typeArg in Instantiation) { if (typeArg.IsRuntimeDeterminedSubtype) diff --git a/external/corert/src/Common/test-runtime/XUnit.Runtime.depproj b/external/corert/src/Common/test-runtime/XUnit.Runtime.depproj index dae724a68a..5f1674de36 100644 --- a/external/corert/src/Common/test-runtime/XUnit.Runtime.depproj +++ b/external/corert/src/Common/test-runtime/XUnit.Runtime.depproj @@ -4,7 +4,7 @@ - win7-x64 + win-x64 netcoreapp2.0 true $(RuntimePath) diff --git a/external/corert/src/Framework/Framework-native.depproj b/external/corert/src/Framework/Framework-native.depproj index 8719e1c856..cc3093531c 100644 --- a/external/corert/src/Framework/Framework-native.depproj +++ b/external/corert/src/Framework/Framework-native.depproj @@ -9,8 +9,6 @@ .NETCoreApp,Version=v2.0 netcoreapp2.0 $(NuPkgRid) - osx-x64 - linux-x64 true diff --git a/external/corert/src/Framework/Framework-uapaot.depproj b/external/corert/src/Framework/Framework-uapaot.depproj index 5ad5937ad5..ab8e28d15e 100644 --- a/external/corert/src/Framework/Framework-uapaot.depproj +++ b/external/corert/src/Framework/Framework-uapaot.depproj @@ -24,6 +24,8 @@ + + diff --git a/external/corert/src/Framework/Framework.depproj b/external/corert/src/Framework/Framework.depproj index 23f206ea6b..e994ff4256 100644 --- a/external/corert/src/Framework/Framework.depproj +++ b/external/corert/src/Framework/Framework.depproj @@ -8,8 +8,6 @@ .NETCoreApp,Version=v2.1 netcoreapp2.1 $(NuPkgRid) - osx-x64 - linux-x64 true diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/AnalysisBasedMetadataManager.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/AnalysisBasedMetadataManager.cs index ccbeb5afb5..3a51c070d6 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/AnalysisBasedMetadataManager.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/AnalysisBasedMetadataManager.cs @@ -155,7 +155,7 @@ namespace ILCompiler void ICompilationRootProvider.AddCompilationRoots(IRootingServiceProvider rootProvider) { - // We go over all the types and members that need a runtime artiface present in the + // We go over all the types and members that need a runtime artifact present in the // compiled executable and root it. const string reason = "Reflection"; diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/BlockedInternalsBlockingPolicy.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/BlockedInternalsBlockingPolicy.cs index c0ac54a272..b7f8e4346a 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/BlockedInternalsBlockingPolicy.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/BlockedInternalsBlockingPolicy.cs @@ -94,6 +94,10 @@ namespace ILCompiler private bool ComputeIsBlocked(EcmaType type, ModuleBlockingMode blockingMode) { + // If the type is explicitly blocked, it's always blocked. + if (type.HasCustomAttribute("System.Runtime.CompilerServices", "ReflectionBlockedAttribute")) + return true; + // If no blocking is applied to the module, the type is not blocked if (blockingMode == ModuleBlockingMode.None) return false; diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/CompilerTypeSystemContext.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/CompilerTypeSystemContext.cs index b224f558fd..4feb7a5824 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/CompilerTypeSystemContext.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/CompilerTypeSystemContext.cs @@ -97,13 +97,20 @@ namespace ILCompiler private SimpleNameHashtable _simpleNameHashtable = new SimpleNameHashtable(); private SharedGenericsMode _genericsMode; - + public CompilerTypeSystemContext(TargetDetails details, SharedGenericsMode genericsMode) : base(details) { _genericsMode = genericsMode; _vectorOfTFieldLayoutAlgorithm = new VectorOfTFieldLayoutAlgorithm(_metadataFieldLayoutAlgorithm); + + GenericsConfig = new SharedGenericsConfiguration(); + } + + public SharedGenericsConfiguration GenericsConfig + { + get; } public IReadOnlyDictionary InputFilePaths @@ -345,6 +352,10 @@ namespace ILCompiler { return GetAllMethodsForEnum(type); } + else if (type.IsValueType) + { + return GetAllMethodsForValueType(type); + } return type.GetMethods(); } @@ -473,4 +484,32 @@ namespace ILCompiler Disabled, CanonicalReferenceTypes, } + + public class SharedGenericsConfiguration + { + // + // Universal Shared Generics heuristics magic values determined empirically + // + public long UniversalCanonGVMReflectionRootHeuristic_InstantiationCount { get; } + public long UniversalCanonGVMDepthHeuristic_NonCanonDepth { get; } + public long UniversalCanonGVMDepthHeuristic_CanonDepth { get; } + + // Controls how many different instantiations of a generic method, or method on generic type + // should be allowed before trying to fall back to only supplying USG in the reflection + // method table. + public long UniversalCanonReflectionMethodRootHeuristic_InstantiationCount { get; } + + public SharedGenericsConfiguration() + { + UniversalCanonGVMReflectionRootHeuristic_InstantiationCount = 4; + UniversalCanonGVMDepthHeuristic_NonCanonDepth = 2; + UniversalCanonGVMDepthHeuristic_CanonDepth = 1; + + // Unlike the GVM heuristics which are intended to kick in aggresively + // this heuristic exists to make it so that a fair amount of generic + // expansion is allowed. Numbers are chosen to allow a fairly large + // amount of generic expansion before trimming. + UniversalCanonReflectionMethodRootHeuristic_InstantiationCount = 1024; + } + }; } diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/CoreRTNameMangler.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/CoreRTNameMangler.cs index 33a13fc2ed..86cac8dc03 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/CoreRTNameMangler.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/CoreRTNameMangler.cs @@ -115,16 +115,21 @@ namespace ILCompiler if (mangledName != literal) { - if (_sha256 == null) + byte[] hash; + lock (this) { - // Use SHA256 hash here to provide a high degree of uniqueness to symbol names without requiring them to be long - // This hash function provides an exceedingly high likelihood that no two strings will be given equal symbol names - // This is not considered used for security purpose; however collisions would be highly unfortunate as they will cause compilation - // failure. - _sha256 = SHA256.Create(); - } + if (_sha256 == null) + { + // Use SHA256 hash here to provide a high degree of uniqueness to symbol names without requiring them to be long + // This hash function provides an exceedingly high likelihood that no two strings will be given equal symbol names + // This is not considered used for security purpose; however collisions would be highly unfortunate as they will cause compilation + // failure. + _sha256 = SHA256.Create(); + } - var hash = _sha256.ComputeHash(GetBytesFromString(literal)); + hash = _sha256.ComputeHash(GetBytesFromString(literal)); + } + mangledName += "_" + BitConverter.ToString(hash).Replace("-", ""); } diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ArrayMapNode.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ArrayMapNode.cs index 6b298e7e92..4f8c8ba46a 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ArrayMapNode.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ArrayMapNode.cs @@ -36,7 +36,6 @@ namespace ILCompiler.DependencyAnalysis public override ObjectNodeSection Section => _externalReferences.Section; public override bool StaticDependenciesAreComputed => true; - public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) => !factory.MetadataManager.SupportsReflection; protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/BlockReflectionTypeMapNode.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/BlockReflectionTypeMapNode.cs index 2955b3d0ed..95fa4b07ea 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/BlockReflectionTypeMapNode.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/BlockReflectionTypeMapNode.cs @@ -37,8 +37,6 @@ namespace ILCompiler.DependencyAnalysis public override bool StaticDependenciesAreComputed => true; - public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) => !factory.MetadataManager.SupportsReflection; - protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CanonicalEETypeNode.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CanonicalEETypeNode.cs index 498e5d36d7..2383df2315 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CanonicalEETypeNode.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CanonicalEETypeNode.cs @@ -67,7 +67,7 @@ namespace ILCompiler.DependencyAnalysis protected override ISymbolNode GetBaseTypeNode(NodeFactory factory) { - return _type.BaseType != null ? factory.NecessaryTypeSymbol(_type.NormalizedBaseType()) : null; + return _type.BaseType != null ? factory.NecessaryTypeSymbol(GetFullCanonicalTypeForCanonicalType(_type.BaseType)) : null; } protected override int GCDescSize diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ClassConstructorContextMap.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ClassConstructorContextMap.cs index 2ee6b9cf9c..0624ee1c6f 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ClassConstructorContextMap.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ClassConstructorContextMap.cs @@ -36,8 +36,6 @@ namespace ILCompiler.DependencyAnalysis public override bool StaticDependenciesAreComputed => true; - public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) => !factory.MetadataManager.SupportsReflection; - protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CodeBasedDependencyAlgorithm.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CodeBasedDependencyAlgorithm.cs index be47cef80d..54acfb2af0 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CodeBasedDependencyAlgorithm.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CodeBasedDependencyAlgorithm.cs @@ -23,7 +23,9 @@ namespace ILCompiler.DependencyAnalysis if (dependencies == null) dependencies = new DependencyList(); - dependencies.Add(factory.MaximallyConstructableType(method.OwningType), "Reflection invoke"); + // The fact we need to exclude Project N is likely a bug in Project N metadata manager + if (factory.Target.Abi != TargetAbi.ProjectN) + dependencies.Add(factory.MaximallyConstructableType(method.OwningType), "Reflection invoke"); if (factory.MetadataManager.HasReflectionInvokeStubForInvokableMethod(method) && ((factory.Target.Abi != TargetAbi.ProjectN) || ProjectNDependencyBehavior.EnableFullAnalysis || !method.IsCanonicalMethod(CanonicalFormKind.Any))) @@ -98,7 +100,7 @@ namespace ILCompiler.DependencyAnalysis factory.InteropStubManager.AddDependeciesDueToPInvoke(ref dependencies, factory, method); - if (method.IsIntrinsic && factory.Target.Abi != TargetAbi.ProjectN) + if (method.IsIntrinsic && factory.Target.Abi != TargetAbi.ProjectN && factory.MetadataManager.SupportsReflection) { if (method.OwningType is MetadataType owningType) { diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ConstructedEETypeNode.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ConstructedEETypeNode.cs index 4bfd1ea7f7..a835bc1f70 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ConstructedEETypeNode.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ConstructedEETypeNode.cs @@ -102,7 +102,7 @@ namespace ILCompiler.DependencyAnalysis dependencyList.Add(factory.VTable(closestDefType), "VTable"); - if (closestDefType.HasInstantiation) + if (closestDefType.HasInstantiation && factory.MetadataManager.SupportsReflection) { TypeDesc canonType = _type.ConvertToCanonForm(CanonicalFormKind.Specific); TypeDesc canonClosestDefType = closestDefType.ConvertToCanonForm(CanonicalFormKind.Specific); diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/DictionaryLayoutNode.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/DictionaryLayoutNode.cs index 5dbf7af844..f1582f1d88 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/DictionaryLayoutNode.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/DictionaryLayoutNode.cs @@ -145,14 +145,17 @@ namespace ILCompiler.DependencyAnalysis public override IEnumerable GetStaticDependencies(NodeFactory factory) { - // Root the template for the type. In the future, we may want to control this via type reflectability instead. - if (_owningMethodOrType is MethodDesc) + if (factory.MetadataManager.SupportsReflection) { - yield return new DependencyListEntry(factory.NativeLayout.TemplateMethodLayout((MethodDesc)_owningMethodOrType), "Type loader template"); - } - else - { - yield return new DependencyListEntry(factory.NativeLayout.TemplateTypeLayout((TypeDesc) _owningMethodOrType), "Type loader template"); + // Root the template for the type. In the future, we may want to control this via type reflectability instead. + if (_owningMethodOrType is MethodDesc) + { + yield return new DependencyListEntry(factory.NativeLayout.TemplateMethodLayout((MethodDesc)_owningMethodOrType), "Type loader template"); + } + else + { + yield return new DependencyListEntry(factory.NativeLayout.TemplateTypeLayout((TypeDesc)_owningMethodOrType), "Type loader template"); + } } if (HasFixedSlots) diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/EETypeNode.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/EETypeNode.cs index 53eec543b6..dc09feaf89 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/EETypeNode.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/EETypeNode.cs @@ -231,7 +231,7 @@ namespace ILCompiler.DependencyAnalysis if (impl.OwningType == defType && !impl.IsAbstract) { MethodDesc canonImpl = impl.GetCanonMethodTarget(CanonicalFormKind.Specific); - yield return new CombinedDependencyListEntry(factory.MethodEntrypoint(canonImpl, _type.IsValueType), factory.VirtualMethodUse(decl.Normalize()), "Virtual method"); + yield return new CombinedDependencyListEntry(factory.MethodEntrypoint(canonImpl, _type.IsValueType), factory.VirtualMethodUse(decl), "Virtual method"); } } @@ -243,7 +243,7 @@ namespace ILCompiler.DependencyAnalysis // Add conditional dependencies for interface methods the type implements. For example, if the type T implements // interface IFoo which has a method M1, add a dependency on T.M1 dependent on IFoo.M1 being called, since it's // possible for any IFoo object to actually be an instance of T. - foreach (DefType interfaceType in defType.NormalizedRuntimeInterfaces()) + foreach (DefType interfaceType in defType.RuntimeInterfaces) { Debug.Assert(interfaceType.IsInterface); @@ -277,7 +277,7 @@ namespace ILCompiler.DependencyAnalysis if (_type.RuntimeInterfaces.Length > 0 && !factory.VTable(closestDefType).HasFixedSlots) { - foreach (var implementedInterface in _type.NormalizedRuntimeInterfaces()) + foreach (var implementedInterface in _type.RuntimeInterfaces) { // If the type implements ICastable, the methods are implicitly necessary if (implementedInterface == factory.ICastableInterface) @@ -634,6 +634,22 @@ namespace ILCompiler.DependencyAnalysis } } + protected static TypeDesc GetFullCanonicalTypeForCanonicalType(TypeDesc type) + { + if (type.IsCanonicalSubtype(CanonicalFormKind.Specific)) + { + return type.ConvertToCanonForm(CanonicalFormKind.Specific); + } + else if (type.IsCanonicalSubtype(CanonicalFormKind.Universal)) + { + return type.ConvertToCanonForm(CanonicalFormKind.Universal); + } + else + { + return type; + } + } + protected virtual ISymbolNode GetBaseTypeNode(NodeFactory factory) { return _type.BaseType != null ? factory.NecessaryTypeSymbol(_type.BaseType) : null; @@ -681,7 +697,7 @@ namespace ILCompiler.DependencyAnalysis declType = declType.GetClosestDefType(); templateType = templateType.ConvertToCanonForm(CanonicalFormKind.Specific); - var baseType = declType.NormalizedBaseType(); + var baseType = declType.BaseType; if (baseType != null) { Debug.Assert(templateType.BaseType != null); @@ -1017,18 +1033,18 @@ namespace ILCompiler.DependencyAnalysis } // It must be possible to create an EEType for the base type of this type - TypeDesc baseType = type.NormalizedBaseType(); + TypeDesc baseType = type.BaseType; if (baseType != null) { // Make sure EEType can be created for this. - factory.NecessaryTypeSymbol(baseType); + factory.NecessaryTypeSymbol(GetFullCanonicalTypeForCanonicalType(baseType)); } // We need EETypes for interfaces - foreach (var intf in type.NormalizedRuntimeInterfaces()) + foreach (var intf in type.RuntimeInterfaces) { // Make sure EEType can be created for this. - factory.NecessaryTypeSymbol(intf); + factory.NecessaryTypeSymbol(GetFullCanonicalTypeForCanonicalType(intf)); } // Validate classes, structs, enums, interfaces, and delegates diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ExactMethodInstantiationsNode.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ExactMethodInstantiationsNode.cs index 57313c7a98..d1dffa4b02 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ExactMethodInstantiationsNode.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ExactMethodInstantiationsNode.cs @@ -36,7 +36,6 @@ namespace ILCompiler.DependencyAnalysis public override ObjectNodeSection Section => _externalReferences.Section; public override bool StaticDependenciesAreComputed => true; protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); - public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) => !factory.MetadataManager.SupportsReflection; public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericMethodsHashtableNode.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericMethodsHashtableNode.cs index 870f489982..bb6d875536 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericMethodsHashtableNode.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericMethodsHashtableNode.cs @@ -35,7 +35,6 @@ namespace ILCompiler.DependencyAnalysis public override bool IsShareable => false; public override ObjectNodeSection Section => _externalReferences.Section; public override bool StaticDependenciesAreComputed => true; - public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) => !factory.MetadataManager.SupportsReflection; protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericMethodsTemplateMap.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericMethodsTemplateMap.cs index 7a92d5dce5..5f48eff374 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericMethodsTemplateMap.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericMethodsTemplateMap.cs @@ -35,7 +35,6 @@ namespace ILCompiler.DependencyAnalysis public override bool IsShareable => false; public override ObjectNodeSection Section => _externalReferences.Section; public override bool StaticDependenciesAreComputed => true; - public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) => !factory.MetadataManager.SupportsReflection; protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericTypesHashtableNode.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericTypesHashtableNode.cs index f48ec5dd79..0d9907e9fe 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericTypesHashtableNode.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericTypesHashtableNode.cs @@ -34,7 +34,6 @@ namespace ILCompiler.DependencyAnalysis public override bool IsShareable => false; public override ObjectNodeSection Section => _externalReferences.Section; public override bool StaticDependenciesAreComputed => true; - public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) => !factory.MetadataManager.SupportsReflection; protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) @@ -71,4 +70,4 @@ namespace ILCompiler.DependencyAnalysis protected internal override int Phase => (int)ObjectNodePhase.Ordered; protected internal override int ClassCode => (int)ObjectNodeOrder.GenericTypesHashtableNode; } -} \ No newline at end of file +} diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericTypesTemplateMap.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericTypesTemplateMap.cs index 2be294a156..812a2a3fb5 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericTypesTemplateMap.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericTypesTemplateMap.cs @@ -36,7 +36,6 @@ namespace ILCompiler.DependencyAnalysis public override bool IsShareable => false; public override ObjectNodeSection Section => _externalReferences.Section; public override bool StaticDependenciesAreComputed => true; - public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) => !factory.MetadataManager.SupportsReflection; protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericVirtualMethodTableNode.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericVirtualMethodTableNode.cs index 7e7e582a48..69e35880d9 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericVirtualMethodTableNode.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/GenericVirtualMethodTableNode.cs @@ -38,7 +38,6 @@ namespace ILCompiler.DependencyAnalysis public override bool IsShareable => false; public override ObjectNodeSection Section => _externalReferences.Section; public override bool StaticDependenciesAreComputed => true; - public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) => !factory.MetadataManager.SupportsReflection; protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); /// diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceDispatchMapNode.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceDispatchMapNode.cs index a406b1be5f..e2f6a6535f 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceDispatchMapNode.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceDispatchMapNode.cs @@ -49,7 +49,7 @@ namespace ILCompiler.DependencyAnalysis result.Add(factory.InterfaceDispatchMapIndirection(_type), "Interface dispatch map indirection node"); // VTable slots of implemented interfaces are consulted during emission - foreach (TypeDesc runtimeInterface in _type.NormalizedRuntimeInterfaces()) + foreach (TypeDesc runtimeInterface in _type.RuntimeInterfaces) { result.Add(factory.VTable(runtimeInterface), "Interface for a dispatch map"); } @@ -61,10 +61,10 @@ namespace ILCompiler.DependencyAnalysis { var entryCountReservation = builder.ReserveInt(); int entryCount = 0; - int interfaceIndex = 0; - foreach (var interfaceType in _type.NormalizedRuntimeInterfaces()) + for (int interfaceIndex = 0; interfaceIndex < _type.RuntimeInterfaces.Length; interfaceIndex++) { + var interfaceType = _type.RuntimeInterfaces[interfaceIndex]; Debug.Assert(interfaceType.IsInterface); IReadOnlyList virtualSlots = factory.VTable(interfaceType).Slots; @@ -80,12 +80,10 @@ namespace ILCompiler.DependencyAnalysis { builder.EmitShort(checked((short)interfaceIndex)); builder.EmitShort(checked((short)(interfaceMethodSlot + (interfaceType.HasGenericDictionarySlot() ? 1 : 0)))); - builder.EmitShort(checked((short)VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, implMethod.Normalize()))); + builder.EmitShort(checked((short)VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, implMethod))); entryCount++; } } - - interfaceIndex++; } builder.EmitInt(entryCountReservation, entryCount); diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceGenericVirtualMethodTableNode.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceGenericVirtualMethodTableNode.cs index 3fd60f7bda..4418d2984f 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceGenericVirtualMethodTableNode.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceGenericVirtualMethodTableNode.cs @@ -39,7 +39,6 @@ namespace ILCompiler.DependencyAnalysis public override bool IsShareable => false; public override ObjectNodeSection Section => _externalReferences.Section; public override bool StaticDependenciesAreComputed => true; - public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) => !factory.MetadataManager.SupportsReflection; protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); /// diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/MetadataNode.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/MetadataNode.cs index 46bb90e094..246e804cef 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/MetadataNode.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/MetadataNode.cs @@ -35,8 +35,6 @@ namespace ILCompiler.DependencyAnalysis public override bool StaticDependenciesAreComputed => true; - public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) => !factory.MetadataManager.SupportsReflection; - protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/MrtImports.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/MrtImports.cs index 8289c2f51b..e7bce493e3 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/MrtImports.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/MrtImports.cs @@ -114,7 +114,7 @@ namespace ILCompiler.DependencyAnalysis protected override sealed string GetName(NodeFactory factory) { - string prefix = "MrtImport " + Ordinal.ToStringInvariant() + " __mrt_"; + string prefix = "MrtImport " + Ordinal.ToStringInvariant() + " __mrt__"; return prefix + GetNonImportedName(factory.NameMangler); } @@ -122,7 +122,7 @@ namespace ILCompiler.DependencyAnalysis public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) { - sb.Append("__mrt_").Append(nameMangler.CompilationUnitPrefix).Append(GetNonImportedName(nameMangler)); + sb.Append("__mrt__").Append(nameMangler.CompilationUnitPrefix).Append(GetNonImportedName(nameMangler)); } public bool RepresentsIndirectionCell => true; diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NativeLayoutInfoNode.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NativeLayoutInfoNode.cs index bed4f3fe42..a73b9edc3b 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NativeLayoutInfoNode.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NativeLayoutInfoNode.cs @@ -52,7 +52,6 @@ namespace ILCompiler.DependencyAnalysis public override bool IsShareable => false; public override ObjectNodeSection Section => _externalReferences.Section; public override bool StaticDependenciesAreComputed => true; - public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) => !factory.MetadataManager.SupportsReflection; protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); public Section LdTokenInfoSection => _ldTokenInfoSection; diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NativeLayoutVertexNode.cs.REMOVED.git-id b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NativeLayoutVertexNode.cs.REMOVED.git-id index aa698a15c8..a535d50619 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NativeLayoutVertexNode.cs.REMOVED.git-id +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NativeLayoutVertexNode.cs.REMOVED.git-id @@ -1 +1 @@ -6c1be4884e98026a251a0ea6f4bd4f3d823dfddc \ No newline at end of file +2c9122d7c05284011fce591922f542b5ddef2fc1 \ No newline at end of file diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NecessaryCanonicalEETypeNode.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NecessaryCanonicalEETypeNode.cs index 775c607576..2a72b509be 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NecessaryCanonicalEETypeNode.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NecessaryCanonicalEETypeNode.cs @@ -24,9 +24,9 @@ namespace ILCompiler.DependencyAnalysis protected override ISymbolNode GetBaseTypeNode(NodeFactory factory) { - return _type.BaseType != null ? factory.NecessaryTypeSymbol(_type.NormalizedBaseType()) : null; + return _type.BaseType != null ? factory.NecessaryTypeSymbol(GetFullCanonicalTypeForCanonicalType(_type.BaseType)) : null; } protected internal override int ClassCode => 1505000724; } -} +} \ No newline at end of file diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.GenericLookups.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.GenericLookups.cs index a7649e88a7..7540667e7f 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.GenericLookups.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.GenericLookups.cs @@ -217,14 +217,14 @@ namespace ILCompiler.DependencyAnalysis private NodeCache _objectAllocators; - public GenericLookupResult ObjectAlloctor(TypeDesc type) + public GenericLookupResult ObjectAllocator(TypeDesc type) { return _objectAllocators.GetOrAdd(type); } private NodeCache _arrayAllocators; - public GenericLookupResult ArrayAlloctor(TypeDesc type) + public GenericLookupResult ArrayAllocator(TypeDesc type) { return _arrayAllocators.GetOrAdd(type); } diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs index 2a25d967bc..6bfbf947d5 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs @@ -1056,6 +1056,7 @@ namespace ILCompiler.DependencyAnalysis InteropStubManager.AddToReadyToRunHeader(ReadyToRunHeader, this, commonFixupsTableNode); MetadataManager.AddToReadyToRunHeader(ReadyToRunHeader, this, commonFixupsTableNode); MetadataManager.AttachToDependencyGraph(graph); + ReadyToRunHeader.Add(MetadataManager.BlobIdToReadyToRunSection(ReflectionMapBlob.CommonFixupsTable), commonFixupsTableNode, commonFixupsTableNode, commonFixupsTableNode.EndSymbol); } protected struct MethodKey : IEquatable diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ObjectDataBuilder.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ObjectDataBuilder.cs index 034d3afe23..b42c3e382f 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ObjectDataBuilder.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ObjectDataBuilder.cs @@ -278,6 +278,8 @@ namespace ILCompiler.DependencyAnalysis case RelocType.IMAGE_REL_BASED_THUMB_BRANCH24: case RelocType.IMAGE_REL_BASED_ARM64_BRANCH26: case RelocType.IMAGE_REL_BASED_THUMB_MOV32: + case RelocType.IMAGE_REL_BASED_ARM64_PAGEBASE_REL21: + case RelocType.IMAGE_REL_BASED_ARM64_PAGEOFFSET_12L: // Do not vacate space for this kind of relocation, because // the space is embedded in the instruction. break; diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ObjectWriter.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ObjectWriter.cs index dde97273e1..25242c8776 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ObjectWriter.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ObjectWriter.cs @@ -19,7 +19,7 @@ using ObjectData = ILCompiler.DependencyAnalysis.ObjectNode.ObjectData; namespace ILCompiler.DependencyAnalysis { /// - /// Object writer using https://github.com/dotnet/llilc + /// Object writer using src/Native/ObjWriter /// internal class ObjectWriter : IDisposable, ITypesDebugInfoWriter { @@ -194,14 +194,16 @@ namespace ILCompiler.DependencyAnalysis private static extern int EmitSymbolRef(IntPtr objWriter, byte[] symbolName, RelocType relocType, int delta); public int EmitSymbolRef(Utf8StringBuilder symbolName, RelocType relocType, int delta = 0) { - // Workaround for ObjectWriter's lack of support for IMAGE_REL_BASED_RELPTR32 - // https://github.com/dotnet/corert/issues/3278 - if (relocType == RelocType.IMAGE_REL_BASED_RELPTR32) + if (_targetPlatform.Architecture != TargetArchitecture.ARMEL && _targetPlatform.Architecture != TargetArchitecture.ARM) { - relocType = RelocType.IMAGE_REL_BASED_REL32; - delta = checked(delta + sizeof(int)); + // Workaround for ObjectWriter's lack of support for IMAGE_REL_BASED_RELPTR32 + // https://github.com/dotnet/corert/issues/3278 + if (relocType == RelocType.IMAGE_REL_BASED_RELPTR32) + { + relocType = RelocType.IMAGE_REL_BASED_REL32; + delta = checked(delta + sizeof(int)); + } } - return EmitSymbolRef(_nativeObjectWriter, symbolName.Append('\0').UnderlyingArray, relocType, delta); } @@ -275,6 +277,40 @@ namespace ILCompiler.DependencyAnalysis [DllImport(NativeObjectWriterFileName)] private static extern uint GetCompleteClassTypeIndex(IntPtr objWriter, ClassTypeDescriptor classTypeDescriptor, ClassFieldsTypeDescriptor classFieldsTypeDescriptior, DataFieldDescriptor[] fields); + [DllImport(NativeObjectWriterFileName)] + private static extern void EmitARMFnStart(IntPtr objWriter); + public void EmitARMFnStart() + { + Debug.Assert(!_frameOpened); + EmitARMFnStart(_nativeObjectWriter); + _frameOpened = true; + } + + [DllImport(NativeObjectWriterFileName)] + private static extern void EmitARMFnEnd(IntPtr objWriter); + public void EmitARMFnEnd() + { + Debug.Assert(_frameOpened); + EmitARMFnEnd(_nativeObjectWriter); + _frameOpened = false; + } + + [DllImport(NativeObjectWriterFileName)] + private static extern void EmitARMExIdxCode(IntPtr objWriter, int nativeOffset, byte[] blob); + public void EmitARMExIdxCode(int nativeOffset, byte[] blob) + { + Debug.Assert(_frameOpened); + EmitARMExIdxCode(_nativeObjectWriter, nativeOffset, blob); + } + + [DllImport(NativeObjectWriterFileName)] + private static extern void EmitARMExIdxLsda(IntPtr objWriter, byte[] blob); + public void EmitARMExIdxLsda(byte[] blob) + { + Debug.Assert(_frameOpened); + EmitARMExIdxLsda(_nativeObjectWriter, blob); + } + public uint GetClassTypeIndex(ClassTypeDescriptor classTypeDescriptor) { return GetClassTypeIndex(_nativeObjectWriter, classTypeDescriptor); @@ -625,20 +661,32 @@ namespace ILCompiler.DependencyAnalysis public void EmitCFICodes(int offset) { + bool forArm = (_targetPlatform.Architecture == TargetArchitecture.ARMEL || _targetPlatform.Architecture == TargetArchitecture.ARM); + // Emit end the old frame before start a frame. if (_offsetToCfiEnd.Contains(offset)) { - EmitCFIEnd(offset); + if (forArm) + EmitARMFnEnd(); + else + EmitCFIEnd(offset); } if (_offsetToCfiStart.Contains(offset)) { - EmitCFIStart(offset); + if (forArm) + EmitARMFnStart(); + else + EmitCFIStart(offset); byte[] blobSymbolName; if (_offsetToCfiLsdaBlobName.TryGetValue(offset, out blobSymbolName)) { - EmitCFILsda(blobSymbolName); + if (forArm) + EmitARMExIdxLsda(blobSymbolName); + else + EmitCFILsda(blobSymbolName); + } else { @@ -653,7 +701,10 @@ namespace ILCompiler.DependencyAnalysis { foreach (byte[] cfi in cfis) { - EmitCFICode(offset, cfi); + if (forArm) + EmitARMExIdxCode(offset, cfi); + else + EmitCFICode(offset, cfi); } } } diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReadyToRunGenericHelperNode.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReadyToRunGenericHelperNode.cs index 090fdf7bb6..ddd1479b27 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReadyToRunGenericHelperNode.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReadyToRunGenericHelperNode.cs @@ -168,6 +168,9 @@ namespace ILCompiler.DependencyAnalysis public override bool HasConditionalStaticDependencies => true; public override IEnumerable GetConditionalStaticDependencies(NodeFactory factory) { + if (!factory.MetadataManager.SupportsReflection) + return Array.Empty(); + List conditionalDependencies = new List(); NativeLayoutSavedVertexNode templateLayout; if (_dictionaryOwner is MethodDesc) diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReflectableMethodNode.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReflectableMethodNode.cs index 2664308a82..78d27ef41a 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReflectableMethodNode.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReflectableMethodNode.cs @@ -22,6 +22,8 @@ namespace ILCompiler.DependencyAnalysis public ReflectableMethodNode(MethodDesc method) { Debug.Assert(method.IsAbstract || method.IsPInvoke); + Debug.Assert(!method.IsCanonicalMethod(CanonicalFormKind.Any) || + method.GetCanonMethodTarget(CanonicalFormKind.Specific) == method); _method = method; } @@ -45,4 +47,4 @@ namespace ILCompiler.DependencyAnalysis public override IEnumerable GetConditionalStaticDependencies(NodeFactory factory) => null; public override IEnumerable SearchDynamicDependencies(List> markedNodes, int firstNode, NodeFactory factory) => null; } -} \ No newline at end of file +} diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReflectionFieldMapNode.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReflectionFieldMapNode.cs index ddae41d987..93bf599792 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReflectionFieldMapNode.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReflectionFieldMapNode.cs @@ -39,8 +39,6 @@ namespace ILCompiler.DependencyAnalysis public override ObjectNodeSection Section => _externalReferences.Section; - public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) => !factory.MetadataManager.SupportsReflection; - public override bool StaticDependenciesAreComputed => true; protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReflectionInvokeMapNode.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReflectionInvokeMapNode.cs index b41717a869..73a95d2e5d 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReflectionInvokeMapNode.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReflectionInvokeMapNode.cs @@ -44,8 +44,6 @@ namespace ILCompiler.DependencyAnalysis public override ObjectNodeSection Section => _externalReferences.Section; - public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) => !factory.MetadataManager.SupportsReflection; - public override bool StaticDependenciesAreComputed => true; protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReflectionVirtualInvokeMapNode.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReflectionVirtualInvokeMapNode.cs index a6b2cf4b93..2b5f45090e 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReflectionVirtualInvokeMapNode.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReflectionVirtualInvokeMapNode.cs @@ -39,7 +39,6 @@ namespace ILCompiler.DependencyAnalysis public override bool IsShareable => false; public override ObjectNodeSection Section => _externalReferences.Section; public override bool StaticDependenciesAreComputed => true; - public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) => !factory.MetadataManager.SupportsReflection; protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); public static bool NeedsVirtualInvokeInfo(MethodDesc method) @@ -115,7 +114,7 @@ namespace ILCompiler.DependencyAnalysis if (!method.HasInstantiation) { - MethodDesc slotDefiningMethod = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(method).Normalize(); + MethodDesc slotDefiningMethod = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(method); if (!factory.VTable(slotDefiningMethod.OwningType).HasFixedSlots) { dependencies.Add(factory.VirtualMethodUse(slotDefiningMethod), "Reflection virtual invoke method"); diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ResourceDataNode.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ResourceDataNode.cs index 9ff7a7243f..cc9dd6a2ce 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ResourceDataNode.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ResourceDataNode.cs @@ -42,8 +42,6 @@ namespace ILCompiler.DependencyAnalysis public override bool StaticDependenciesAreComputed => true; - public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) => !factory.MetadataManager.SupportsReflection; - public int Offset => 0; public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) @@ -193,4 +191,4 @@ namespace ILCompiler.DependencyAnalysis /// public int Length { get; } } -} \ No newline at end of file +} diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ResourceIndexNode.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ResourceIndexNode.cs index 053a3112b6..4ad4a3b897 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ResourceIndexNode.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ResourceIndexNode.cs @@ -33,8 +33,6 @@ namespace ILCompiler.DependencyAnalysis public override bool StaticDependenciesAreComputed => true; - public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) => !factory.MetadataManager.SupportsReflection; - public int Offset => 0; public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) @@ -101,4 +99,4 @@ namespace ILCompiler.DependencyAnalysis protected internal override int Phase => (int)ObjectNodePhase.Ordered; protected internal override int ClassCode => (int)ObjectNodeOrder.ResourceIndexNode; } -} \ No newline at end of file +} diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/RuntimeDecodableJumpStub.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/RuntimeDecodableJumpStub.cs index 1d4f00f6b3..d4d8e06ffd 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/RuntimeDecodableJumpStub.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/RuntimeDecodableJumpStub.cs @@ -42,8 +42,10 @@ namespace ILCompiler.DependencyAnalysis public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) { string name = WrappedMethodIndirectionCellNode.GetMangledName(nameMangler); - Debug.Assert(name.StartsWith("__mrt_")); - sb.Append(name.Substring(6)); + Debug.Assert(name.StartsWith("__mrt__")); + // Add a __imp__ prefix to indicate this is a stub to the debugger + sb.Append("__imp__"); + sb.Append(name.Substring("__mrt__".Length)); } protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/StackTraceEmbeddedMetadataNode.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/StackTraceEmbeddedMetadataNode.cs index 728bad0ecc..b1ab09a295 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/StackTraceEmbeddedMetadataNode.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/StackTraceEmbeddedMetadataNode.cs @@ -35,8 +35,6 @@ namespace ILCompiler.DependencyAnalysis public override bool StaticDependenciesAreComputed => true; - public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) => !factory.MetadataManager.SupportsReflection; - public int Offset => 0; protected internal override int Phase => (int)ObjectNodePhase.Ordered; diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/StackTraceMethodMappingNode.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/StackTraceMethodMappingNode.cs index 0bfc65a28a..de12c6f923 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/StackTraceMethodMappingNode.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/StackTraceMethodMappingNode.cs @@ -28,8 +28,6 @@ namespace ILCompiler.DependencyAnalysis public override bool StaticDependenciesAreComputed => true; - public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) => !factory.MetadataManager.SupportsReflection; - public int Offset => 0; protected internal override int Phase => (int)ObjectNodePhase.Ordered; diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/StaticsInfoHashtableNode.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/StaticsInfoHashtableNode.cs index 22122f7ede..14b81d92ed 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/StaticsInfoHashtableNode.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/StaticsInfoHashtableNode.cs @@ -38,7 +38,6 @@ namespace ILCompiler.DependencyAnalysis public override bool IsShareable => false; public override ObjectNodeSection Section => _externalReferences.Section; public override bool StaticDependenciesAreComputed => true; - public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) => !factory.MetadataManager.SupportsReflection; protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM64/ARM64Emitter.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM64/ARM64Emitter.cs index abeb8ee7f2..da3d8b6e94 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM64/ARM64Emitter.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_ARM64/ARM64Emitter.cs @@ -59,7 +59,6 @@ namespace ILCompiler.DependencyAnalysis.ARM64 { if (symbol.RepresentsIndirectionCell) { - Debug.Assert(false, "The following code to emit an jump stub to an indirection cell is untested. When testing on ARM64 please remove this assert and verify it is correct"); // xip0 register num is 0x10 // ADRP xip0, [symbol (21bit ADRP thing)] @@ -119,6 +118,5 @@ namespace ILCompiler.DependencyAnalysis.ARM64 { return i == (int)(sbyte)i; } - } } diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/TypeGVMEntriesNode.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/TypeGVMEntriesNode.cs index 2932a50e2a..c32bcbe700 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/TypeGVMEntriesNode.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/TypeGVMEntriesNode.cs @@ -111,14 +111,16 @@ namespace ILCompiler.DependencyAnalysis public IEnumerable ScanForGenericVirtualMethodEntries() { - foreach (var method in _associatedType.GetMethods()) + foreach (MethodDesc decl in _associatedType.EnumAllVirtualSlots()) { - if (!method.IsVirtual || !method.HasInstantiation) + // Non-Generic virtual methods are tracked by an orthogonal mechanism. + if (!decl.HasInstantiation) continue; - MethodDesc slotDecl = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(method); - Debug.Assert(slotDecl != null); - yield return new TypeGVMEntryInfo(slotDecl, method, null); + MethodDesc impl = _associatedType.FindVirtualFunctionTargetMethodOnObjectType(decl); + + if (impl.OwningType == _associatedType) + yield return new TypeGVMEntryInfo(decl, impl, null); } } diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/TypeMetadataMapNode.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/TypeMetadataMapNode.cs index ea58dd3508..75012d6e8e 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/TypeMetadataMapNode.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/TypeMetadataMapNode.cs @@ -37,8 +37,6 @@ namespace ILCompiler.DependencyAnalysis public override bool StaticDependenciesAreComputed => true; - public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) => !factory.MetadataManager.SupportsReflection; - protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/UtcNodeFactory.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/UtcNodeFactory.cs index fbeb03680d..776ca6a2b9 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/UtcNodeFactory.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/UtcNodeFactory.cs @@ -205,6 +205,7 @@ namespace ILCompiler InteropStubManager.AddToReadyToRunHeader(ReadyToRunHeader, this, commonFixupsTableNode); MetadataManager.AddToReadyToRunHeader(ReadyToRunHeader, this, commonFixupsTableNode); MetadataManager.AttachToDependencyGraph(graph); + ReadyToRunHeader.Add(MetadataManager.BlobIdToReadyToRunSection(ReflectionMapBlob.CommonFixupsTable), commonFixupsTableNode, commonFixupsTableNode, commonFixupsTableNode.EndSymbol); } protected override IMethodNode CreateMethodEntrypointNode(MethodDesc method) diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/VTableSliceNode.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/VTableSliceNode.cs index 956afc8794..59777bae9a 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/VTableSliceNode.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/VTableSliceNode.cs @@ -22,8 +22,6 @@ namespace ILCompiler.DependencyAnalysis public VTableSliceNode(TypeDesc type) { Debug.Assert(!type.IsArray, "Wanted to call GetClosestDefType?"); - Debug.Assert(!type.IsCanonicalSubtype(CanonicalFormKind.Any) || - type.ConvertToCanonForm(CanonicalFormKind.Specific) == type); _type = type; } @@ -48,10 +46,9 @@ namespace ILCompiler.DependencyAnalysis public override IEnumerable GetStaticDependencies(NodeFactory factory) { - DefType baseType = _type.NormalizedBaseType(); - if (baseType != null) + if (_type.HasBaseType) { - return new[] { new DependencyListEntry(factory.VTable(baseType), "Base type VTable") }; + return new[] { new DependencyListEntry(factory.VTable(_type.BaseType), "Base type VTable") }; } return null; diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/VirtualMethodUseNode.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/VirtualMethodUseNode.cs index 9f29f53ce2..aec52ca2dd 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/VirtualMethodUseNode.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/VirtualMethodUseNode.cs @@ -30,9 +30,6 @@ namespace ILCompiler.DependencyAnalysis Debug.Assert(!decl.IsRuntimeDeterminedExactMethod); Debug.Assert(decl.IsVirtual); - Debug.Assert(!decl.IsCanonicalMethod(CanonicalFormKind.Any) || - decl.GetCanonMethodTarget(CanonicalFormKind.Specific) == decl); - // Virtual method use always represents the slot defining method of the virtual. // Places that might see virtual methods being used through an override need to normalize // to the slot defining method. @@ -71,7 +68,9 @@ namespace ILCompiler.DependencyAnalysis dependencies.Add(new DependencyListEntry(factory.VTable(_decl.OwningType), "VTable of a VirtualMethodUse")); - factory.MetadataManager.GetDependenciesDueToVirtualMethodReflectability(ref dependencies, factory, _decl); + // Do not report things like Foo.Frob(). + if (!_decl.IsCanonicalMethod(CanonicalFormKind.Any) || canonDecl == _decl) + factory.MetadataManager.GetDependenciesDueToVirtualMethodReflectability(ref dependencies, factory, _decl); return dependencies; } diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/EmptyMetadataManager.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/EmptyMetadataManager.cs index 97eed867a3..2ae0536691 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/EmptyMetadataManager.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/EmptyMetadataManager.cs @@ -21,6 +21,11 @@ namespace ILCompiler { } + public override void AddToReadyToRunHeader(ReadyToRunHeaderNode header, NodeFactory nodeFactory, ExternalReferencesTableNode commonFixupsTableNode) + { + // We don't attach any metadata blobs. + } + public override IEnumerable GetCompilationModulesWithMetadata() { return Array.Empty(); diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/GeneratingMetadataManager.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/GeneratingMetadataManager.cs index 27af8432ce..b01a4bb5f3 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/GeneratingMetadataManager.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/GeneratingMetadataManager.cs @@ -90,26 +90,7 @@ namespace ILCompiler if (!_stackTraceEmissionPolicy.ShouldIncludeMethod(method)) continue; - MetadataRecord record = transform.HandleQualifiedMethod(typicalMethod); - - // As a twist, instantiated generic methods appear as if instantiated over their formals. - if (typicalMethod.HasInstantiation) - { - var methodInst = new MethodInstantiation - { - Method = record, - }; - methodInst.GenericTypeArguments.Capacity = typicalMethod.Instantiation.Length; - foreach (EcmaGenericParameter typeArgument in typicalMethod.Instantiation) - { - var genericParam = new TypeReference - { - TypeName = (ConstantStringValue)typeArgument.Name, - }; - methodInst.GenericTypeArguments.Add(genericParam); - } - record = methodInst; - } + MetadataRecord record = CreateStackTraceRecord(transform, method); stackTraceRecords.Add(new KeyValuePair( method, diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/MetadataManager.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/MetadataManager.cs index ab86d40e28..2c2c6123bd 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/MetadataManager.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/MetadataManager.cs @@ -15,6 +15,14 @@ using ReadyToRunSectionType = Internal.Runtime.ReadyToRunSectionType; using ReflectionMapBlob = Internal.Runtime.ReflectionMapBlob; using DependencyList = ILCompiler.DependencyAnalysisFramework.DependencyNodeCore.DependencyList; +using MetadataRecord = Internal.Metadata.NativeFormat.Writer.MetadataRecord; +using MemberReference = Internal.Metadata.NativeFormat.Writer.MemberReference; +using TypeReference = Internal.Metadata.NativeFormat.Writer.TypeReference; +using TypeSpecification = Internal.Metadata.NativeFormat.Writer.TypeSpecification; +using ConstantStringValue = Internal.Metadata.NativeFormat.Writer.ConstantStringValue; +using TypeInstantiationSignature = Internal.Metadata.NativeFormat.Writer.TypeInstantiationSignature; +using MethodInstantiation = Internal.Metadata.NativeFormat.Writer.MethodInstantiation; + namespace ILCompiler { /// @@ -66,7 +74,7 @@ namespace ILCompiler return result; } - public void AddToReadyToRunHeader(ReadyToRunHeaderNode header, NodeFactory nodeFactory, ExternalReferencesTableNode commonFixupsTableNode) + public virtual void AddToReadyToRunHeader(ReadyToRunHeaderNode header, NodeFactory nodeFactory, ExternalReferencesTableNode commonFixupsTableNode) { var metadataNode = new MetadataNode(); header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.EmbeddedMetadata), metadataNode, metadataNode, metadataNode.EndSymbol); @@ -135,16 +143,10 @@ namespace ILCompiler var defaultConstructorMapNode = new DefaultConstructorMapNode(commonFixupsTableNode); header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.DefaultConstructorMap), defaultConstructorMapNode, defaultConstructorMapNode, defaultConstructorMapNode.EndSymbol); -#if !CORERT - var stackTraceEmbeddedMetadataNode = new StackTraceEmbeddedMetadataNode(); - header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.BlobIdStackTraceEmbeddedMetadata), stackTraceEmbeddedMetadataNode, stackTraceEmbeddedMetadataNode, stackTraceEmbeddedMetadataNode.EndSymbol); -#endif - var stackTraceMethodMappingNode = new StackTraceMethodMappingNode(); header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.BlobIdStackTraceMethodRvaToTokenMapping), stackTraceMethodMappingNode, stackTraceMethodMappingNode, stackTraceMethodMappingNode.EndSymbol); // The external references tables should go last - header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.CommonFixupsTable), commonFixupsTableNode, commonFixupsTableNode, commonFixupsTableNode.EndSymbol); header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.NativeReferences), nativeReferencesTableNode, nativeReferencesTableNode, nativeReferencesTableNode.EndSymbol); header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.NativeStatics), nativeStaticsTableNode, nativeStaticsTableNode, nativeStaticsTableNode.EndSymbol); } @@ -567,7 +569,59 @@ namespace ILCompiler out List> fieldMappings, out List> stackTraceMapping); + protected MetadataRecord CreateStackTraceRecord(Metadata.MetadataTransform transform, MethodDesc method) + { + // In the metadata, we only represent the generic definition + MethodDesc methodToGenerateMetadataFor = method.GetTypicalMethodDefinition(); + MetadataRecord record = transform.HandleQualifiedMethod(methodToGenerateMetadataFor); + // If we're generating a MemberReference to a method on a generic type, the owning type + // should appear as if instantiated over its formals + TypeDesc owningTypeToGenerateMetadataFor = methodToGenerateMetadataFor.OwningType; + if (owningTypeToGenerateMetadataFor.HasInstantiation + && record is MemberReference memberRefRecord + && memberRefRecord.Parent is TypeReference) + { + List genericArgs = new List(); + foreach (Internal.TypeSystem.Ecma.EcmaGenericParameter genericParam in owningTypeToGenerateMetadataFor.Instantiation) + { + genericArgs.Add(new TypeReference + { + TypeName = (ConstantStringValue)genericParam.Name, + }); + } + + memberRefRecord.Parent = new TypeSpecification + { + Signature = new TypeInstantiationSignature + { + GenericType = memberRefRecord.Parent, + GenericTypeArguments = genericArgs, + } + }; + } + + // As a twist, instantiated generic methods appear as if instantiated over their formals. + if (methodToGenerateMetadataFor.HasInstantiation) + { + var methodInst = new MethodInstantiation + { + Method = record, + }; + methodInst.GenericTypeArguments.Capacity = methodToGenerateMetadataFor.Instantiation.Length; + foreach (Internal.TypeSystem.Ecma.EcmaGenericParameter typeArgument in methodToGenerateMetadataFor.Instantiation) + { + var genericParam = new TypeReference + { + TypeName = (ConstantStringValue)typeArgument.Name, + }; + methodInst.GenericTypeArguments.Add(genericParam); + } + record = methodInst; + } + + return record; + } /// /// Returns a set of modules that will get some metadata emitted into the output module diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/MethodExtensions.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/MethodExtensions.cs index 6b259d5a12..15070a4b4e 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/MethodExtensions.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/MethodExtensions.cs @@ -113,16 +113,5 @@ namespace ILCompiler return false; } - - /// - /// Gets fully canonicalized method if method is canonical. - /// - public static MethodDesc Normalize(this MethodDesc method) - { - // If method is Foo<__Canon,object>::Method, we get Foo<__Canon,__Canon>::Method. - if (method.IsCanonicalMethod(CanonicalFormKind.Any)) - return method.GetCanonMethodTarget(CanonicalFormKind.Specific); - return method; - } } } diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/PrecomputedMetadataManager.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/PrecomputedMetadataManager.cs index 7e0cad821c..0e333d323d 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/PrecomputedMetadataManager.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/PrecomputedMetadataManager.cs @@ -19,6 +19,7 @@ using ILCompiler.Metadata; using ILCompiler.DependencyAnalysis; using Debug = System.Diagnostics.Debug; +using ReflectionMapBlob = Internal.Runtime.ReflectionMapBlob; namespace ILCompiler { @@ -74,6 +75,14 @@ namespace ILCompiler _stackTraceEmissionPolicy = stackTraceEmissionPolicy; } + public override void AddToReadyToRunHeader(ReadyToRunHeaderNode header, NodeFactory nodeFactory, ExternalReferencesTableNode commonFixupsTableNode) + { + base.AddToReadyToRunHeader(header, nodeFactory, commonFixupsTableNode); + + var stackTraceEmbeddedMetadataNode = new StackTraceEmbeddedMetadataNode(); + header.Add(BlobIdToReadyToRunSection(ReflectionMapBlob.BlobIdStackTraceEmbeddedMetadata), stackTraceEmbeddedMetadataNode, stackTraceEmbeddedMetadataNode, stackTraceEmbeddedMetadataNode.EndSymbol); + } + /// /// Read a method that describes the type system to metadata mappings. /// @@ -135,6 +144,9 @@ namespace ILCompiler private IEnumerable ReadRequiredGenericsEntities(MethodIL method) { ILStreamReader il = new ILStreamReader(method); + bool needSecondPass = false; + Dictionary openMethodToInstantiationCount = new Dictionary(); + // structure is // REPEAT N TIMES //ldtoken generic type/method/field @@ -142,7 +154,7 @@ namespace ILCompiler while (true) { if (il.TryReadRet()) // ret - yield break; + break; TypeSystemEntity tse; il.TryReadLdtokenAsTypeSystemEntity(out tse); @@ -180,12 +192,89 @@ namespace ILCompiler genericMethod.OwningType.Instantiation.CheckValidInstantiationArguments() && genericMethod.CheckConstraints()) { - // TODO: Detect large number of instantiations of the same method and collapse to using dynamic - // USG instantiations at runtime, to avoid infinite generic expansion and large compilation times. - yield return tse; + // If we encounter a large number of instantiations of the same generic method, add the universal generic form + // and stop adding further instantiations over the same generic method definition + if (genericMethod.HasInstantiation || genericMethod.OwningType.HasInstantiation) + { + MethodDesc openMethod = genericMethod.GetTypicalMethodDefinition(); + long count; + if (openMethodToInstantiationCount.TryGetValue(openMethod, out count)) + { + openMethodToInstantiationCount[openMethod] = count + 1; + } + else + { + openMethodToInstantiationCount.Add(openMethod, 1); + } + + needSecondPass = true; + } + else + { + yield return tse; + } } } } + + if (needSecondPass) + { + ILStreamReader ilpass2 = new ILStreamReader(method); + + while (true) + { + if (ilpass2.TryReadRet()) + yield break; + + TypeSystemEntity tse; + ilpass2.TryReadLdtokenAsTypeSystemEntity(out tse); + ilpass2.ReadPop(); + + if (tse == null) + throw new BadImageFormatException(); + + if (tse is MethodDesc) + { + MethodDesc genericMethod = (MethodDesc)tse; + + if (genericMethod.Instantiation.CheckValidInstantiationArguments() && + genericMethod.OwningType.Instantiation.CheckValidInstantiationArguments() && + genericMethod.CheckConstraints()) + { + // If we encounter a large number of instantiations of the same generic method, add the universal generic form + // and stop adding further instantiations over the same generic method definition + if (genericMethod.HasInstantiation || genericMethod.OwningType.HasInstantiation) + { + MethodDesc openMethod = genericMethod.GetTypicalMethodDefinition(); + long count; + bool found = openMethodToInstantiationCount.TryGetValue(openMethod, out count); + Debug.Assert(found); + + // We have 2 heuristics, one for GVMs and one for normal methods that happen to have generics + bool isGVM = genericMethod.IsVirtual && genericMethod.HasInstantiation; + long heuristicCount = isGVM ? _typeSystemContext.GenericsConfig.UniversalCanonGVMReflectionRootHeuristic_InstantiationCount : + _typeSystemContext.GenericsConfig.UniversalCanonReflectionMethodRootHeuristic_InstantiationCount; + + if (count >= heuristicCount) + { + // We've hit the threshold of instantiations so add the USG form + tse = genericMethod.GetCanonMethodTarget(CanonicalFormKind.Universal); + + // Set the instantiation count to -1 as a sentinel value + openMethodToInstantiationCount[openMethod] = -1; + } + else if (count == -1) + { + // Previously we added the USG form to _SpecifiedGenericMethods, now just skip + continue; + } + + yield return tse; + } + } + } + } + } } private Instantiation GetUniversalCanonicalInstantiation(int numArgs) @@ -888,28 +977,7 @@ namespace ILCompiler if (!_stackTraceEmissionPolicy.ShouldIncludeMethod(method)) continue; - // In the metadata, we only represent the generic definition - MethodDesc methodToGenerateMetadataFor = method.GetTypicalMethodDefinition(); - MetadataRecord record = transform.HandleQualifiedMethod(methodToGenerateMetadataFor); - - // As a twist, instantiated generic methods appear as if instantiated over their formals. - if (methodToGenerateMetadataFor.HasInstantiation) - { - var methodInst = new MethodInstantiation - { - Method = record, - }; - methodInst.GenericTypeArguments.Capacity = methodToGenerateMetadataFor.Instantiation.Length; - foreach (EcmaGenericParameter typeArgument in methodToGenerateMetadataFor.Instantiation) - { - var genericParam = new TypeReference - { - TypeName = (ConstantStringValue)typeArgument.Name, - }; - methodInst.GenericTypeArguments.Add(genericParam); - } - record = methodInst; - } + MetadataRecord record = CreateStackTraceRecord(transform, method); stackTraceRecords.Add(new KeyValuePair( method, diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/TypeExtensions.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/TypeExtensions.cs index 35f8d8503b..5cf56d1724 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/TypeExtensions.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/TypeExtensions.cs @@ -183,74 +183,5 @@ namespace ILCompiler return false; } - - /// - /// Gets a fully canonicalized base type if base type is canonical, or unmodified base type otherwise. - /// - public static DefType NormalizedBaseType(this TypeDesc type) - { - // Base type for Foo<__Canon> where Foo is defined as - // class Foo : Bar { } - // is Bar<__Canon, string>. This method normalizes it to Bar<__Canon, __Canon>. - DefType baseType = type.BaseType; - if (baseType != null && baseType.IsCanonicalSubtype(CanonicalFormKind.Any)) - baseType = (DefType)baseType.ConvertToCanonForm(CanonicalFormKind.Specific); - return baseType; - } - - /// - /// Gets an interface list that is fully canonicalized if the interfaces are canonical or the unmodified - /// interface types otherwise. - /// - public static NormalizedInterfaceList NormalizedRuntimeInterfaces(this TypeDesc type) - { - // Interface list for Foo<__Canon> where Foo is defined as - // class Foo : IFooer - // is IFooer<__Canon, object>. This method normalizes it to IFooer<__Canon, __Canon>. - return new NormalizedInterfaceList(type); - } - - public struct NormalizedInterfaceList - { - private readonly TypeDesc _type; - - public NormalizedInterfaceList(TypeDesc type) - { - _type = type; - } - - public Enumerator GetEnumerator() - { - return new Enumerator(_type); - } - - public struct Enumerator - { - private readonly DefType[] _interfaces; - private int _index; - - public Enumerator(TypeDesc type) - { - _interfaces = type.RuntimeInterfaces; - _index = -1; - } - - public DefType Current - { - get - { - DefType intface = _interfaces[_index]; - if (intface.IsCanonicalSubtype(CanonicalFormKind.Any)) - intface = (DefType)intface.ConvertToCanonForm(CanonicalFormKind.Specific); - return intface; - } - } - - public bool MoveNext() - { - return ++_index < _interfaces.Length; - } - } - } } } diff --git a/external/corert/src/ILCompiler.Compiler/src/Compiler/UtcNameMangler.cs b/external/corert/src/ILCompiler.Compiler/src/Compiler/UtcNameMangler.cs index 5943a5ed61..6eaf70a75b 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Compiler/UtcNameMangler.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Compiler/UtcNameMangler.cs @@ -202,7 +202,12 @@ namespace ILCompiler if (mangledName != literal) { - var hash = _sha256.ComputeHash(GetBytesFromString(literal)); + byte[] hash; + lock (this) + { + hash = _sha256.ComputeHash(GetBytesFromString(literal)); + } + mangledName += "_" + BitConverter.ToString(hash).Replace("-", ""); } diff --git a/external/corert/src/ILCompiler.Compiler/src/Logger.cs b/external/corert/src/ILCompiler.Compiler/src/Logger.cs index f50ca450d4..69cf480646 100644 --- a/external/corert/src/ILCompiler.Compiler/src/Logger.cs +++ b/external/corert/src/ILCompiler.Compiler/src/Logger.cs @@ -2,6 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#if SUPPORT_JIT +extern alias System_Private_CoreLib; +using TextWriter = System_Private_CoreLib::System.IO.TextWriter; +#endif + using System.IO; namespace ILCompiler diff --git a/external/corert/src/ILCompiler.CppCodeGen/src/CppCodeGen/CppWriter.cs b/external/corert/src/ILCompiler.CppCodeGen/src/CppCodeGen/CppWriter.cs index be43013037..ef08550b7b 100644 --- a/external/corert/src/ILCompiler.CppCodeGen/src/CppCodeGen/CppWriter.cs +++ b/external/corert/src/ILCompiler.CppCodeGen/src/CppCodeGen/CppWriter.cs @@ -316,7 +316,13 @@ namespace ILCompiler.CppCodeGen public string GetCppFieldName(FieldDesc field) { - return _compilation.NameMangler.GetMangledFieldName(field).ToString(); + string name = _compilation.NameMangler.GetMangledFieldName(field).ToString(); + + // TODO: name mangling robustness + if (name == "register") + name = "_" + name + "_"; + + return name; } public string GetCppStaticFieldName(FieldDesc field) @@ -329,7 +335,7 @@ namespace ILCompiler.CppCodeGen public string SanitizeCppVarName(string varName) { // TODO: name mangling robustness - if (varName == "errno" || varName == "environ" || varName == "template" || varName == "typename") // some names collide with CRT headers + if (varName == "errno" || varName == "environ" || varName == "template" || varName == "typename" || varName == "register") // some names collide with CRT headers return "_" + varName + "_"; return _compilation.NameMangler.SanitizeName(varName); diff --git a/external/corert/src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs b/external/corert/src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs index 1b88ec3eab..ae062dad6f 100644 --- a/external/corert/src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs +++ b/external/corert/src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs @@ -817,7 +817,9 @@ namespace Internal.IL private void ImportBreak() { - throw new NotImplementedException("Opcode: break"); + AppendLine(); + Append("__debug_break()"); + AppendSemicolon(); } private void ImportLoadVar(int index, bool argument) @@ -2382,6 +2384,8 @@ namespace Internal.IL var index = _stack.Pop(); var arrayPtr = _stack.Pop(); + // TODO: type check, unless readonly prefix was applied + // Range check AppendLine(); Append("__range_check("); @@ -2637,7 +2641,7 @@ namespace Internal.IL private void ImportReadOnlyPrefix() { - throw new NotImplementedException(); + _pendingPrefix |= Prefix.ReadOnly; } private void TriggerCctor(TypeDesc type) diff --git a/external/corert/src/ILCompiler.TypeSystem/src/ILCompiler.TypeSystem.csproj b/external/corert/src/ILCompiler.TypeSystem/src/ILCompiler.TypeSystem.csproj index d9de5b3c90..c9b2ef2bfd 100644 --- a/external/corert/src/ILCompiler.TypeSystem/src/ILCompiler.TypeSystem.csproj +++ b/external/corert/src/ILCompiler.TypeSystem/src/ILCompiler.TypeSystem.csproj @@ -379,6 +379,12 @@ IL\Stubs\StructMarshallingThunk.Sorting.cs + + IL\Stubs\ValueTypeGetFieldHelperMethodOverride.cs + + + IL\Stubs\ValueTypeGetFieldHelperMethodOverride.Sorting.cs + IL\TypeSystemContext.DelegateInfo.cs @@ -418,6 +424,9 @@ IL\TypeSystemContext.EnumMethods.cs + + IL\TypeSystemContext.ValueTypeMethods.cs + TypeSystem\Interop\IL\InlineArrayType.Sorting.cs diff --git a/external/corert/src/ILCompiler.TypeSystem/tests/UniversalGenericFieldLayoutTests.cs b/external/corert/src/ILCompiler.TypeSystem/tests/UniversalGenericFieldLayoutTests.cs index 090c59a41e..938828c795 100644 --- a/external/corert/src/ILCompiler.TypeSystem/tests/UniversalGenericFieldLayoutTests.cs +++ b/external/corert/src/ILCompiler.TypeSystem/tests/UniversalGenericFieldLayoutTests.cs @@ -21,7 +21,7 @@ namespace TypeSystemTests public UniversalGenericFieldLayoutTests() { - // Architecure specific tests may use these contexts + // Architecture specific tests may use these contexts _contextX64 = new TestTypeSystemContext(TargetArchitecture.X64); var systemModuleX64 = _contextX64.CreateModuleForSimpleName("CoreTestAssembly"); _contextX64.SetSystemModule(systemModuleX64); diff --git a/external/corert/src/ILCompiler.WebAssembly/src/CodeGen/EvaluationStack.cs b/external/corert/src/ILCompiler.WebAssembly/src/CodeGen/EvaluationStack.cs index c218dd4407..92c1919764 100644 --- a/external/corert/src/ILCompiler.WebAssembly/src/CodeGen/EvaluationStack.cs +++ b/external/corert/src/ILCompiler.WebAssembly/src/CodeGen/EvaluationStack.cs @@ -483,6 +483,30 @@ namespace Internal.IL } } + /// + /// Represents the result of a ldftn or ldvirtftn + /// + internal class FunctionPointerEntry : ExpressionEntry + { + /// + /// True if the function pointer was loaded as a virtual function pointer + /// + public bool IsVirtual { get; } + + public MethodDesc Method { get; } + + public FunctionPointerEntry(string name, MethodDesc method, LLVMValueRef llvmValue, TypeDesc type, bool isVirtual) : base(StackValueKind.NativeInt, name, llvmValue, type) + { + Method = method; + IsVirtual = isVirtual; + } + + public override StackEntry Duplicate() + { + return new FunctionPointerEntry(Name, Method, RawLLVMValue, Type, IsVirtual); + } + } + /// /// Entry representing some token (either of TypeDesc, MethodDesc or FieldDesc) along with its string representation /// @@ -490,14 +514,14 @@ namespace Internal.IL { public T LdToken { get; } - public LdTokenEntry(StackValueKind kind, string name, T token, TypeDesc type = null) : base(kind, name, default(LLVMValueRef), type) + public LdTokenEntry(StackValueKind kind, string name, T token, LLVMValueRef llvmValue, TypeDesc type = null) : base(kind, name, llvmValue, type) { LdToken = token; } public override StackEntry Duplicate() { - return new LdTokenEntry(Kind, Name, LdToken, Type); + return new LdTokenEntry(Kind, Name, LdToken, RawLLVMValue, Type); } protected override LLVMValueRef ValueAsTypeInternal(LLVMTypeRef type, LLVMBuilderRef builder, bool signExtend) @@ -546,7 +570,10 @@ namespace Internal.IL protected override LLVMValueRef ValueAsTypeInternal(LLVMTypeRef type, LLVMBuilderRef builder, bool signExtend) { - return _importer.LoadTemp(LocalIndex, type); + LLVMTypeRef origLLVMType = ILImporter.GetLLVMTypeForTypeDesc(Type); + LLVMValueRef value = _importer.LoadTemp(LocalIndex, origLLVMType); + + return ILImporter.CastIfNecessary(builder, value, type); } public override StackEntry Duplicate() diff --git a/external/corert/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs b/external/corert/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs deleted file mode 100644 index 71da8d50a3..0000000000 --- a/external/corert/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs +++ /dev/null @@ -1,2134 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections.Generic; -using System.Diagnostics; - -using Internal.TypeSystem; -using ILCompiler; -using LLVMSharp; -using ILCompiler.CodeGen; -using ILCompiler.DependencyAnalysis; -using ILCompiler.DependencyAnalysisFramework; -using Internal.TypeSystem.Ecma; - -namespace Internal.IL -{ - // Implements an IL scanner that scans method bodies to be compiled by the code generation - // backend before the actual compilation happens to gain insights into the code. - partial class ILImporter - { - public enum LocalVarKind - { - Argument, - Local, - Temp - } - - ArrayBuilder _dependencies = new ArrayBuilder(); - public IEnumerable GetDependencies() - { - return _dependencies.ToArray(); - } - - public LLVMModuleRef Module { get; } - private readonly MethodDesc _method; - private readonly MethodIL _methodIL; - private readonly MethodSignature _signature; - private readonly TypeDesc _thisType; - private readonly WebAssemblyCodegenCompilation _compilation; - private LLVMValueRef _llvmFunction; - private LLVMBasicBlockRef _curBasicBlock; - private LLVMBuilderRef _builder; - private readonly LocalVariableDefinition[] _locals; - private List _spilledExpressions = new List(); - - private readonly byte[] _ilBytes; - - /// - /// Stack of values pushed onto the IL stack: locals, arguments, values, function pointer, ... - /// - private EvaluationStack _stack = new EvaluationStack(0); - - private class BasicBlock - { - // Common fields - public enum ImportState : byte - { - Unmarked, - IsPending - } - - public BasicBlock Next; - - public int StartOffset; - public ImportState State = ImportState.Unmarked; - - public EvaluationStack EntryStack; - - public bool TryStart; - public bool FilterStart; - public bool HandlerStart; - - public LLVMBasicBlockRef Block; - } - - private class ExceptionRegion - { - public ILExceptionRegion ILRegion; - } - private ExceptionRegion[] _exceptionRegions; - - public ILImporter(WebAssemblyCodegenCompilation compilation, MethodDesc method, MethodIL methodIL, string mangledName) - { - Module = compilation.Module; - _compilation = compilation; - _method = method; - _methodIL = methodIL; - _ilBytes = methodIL.GetILBytes(); - _locals = methodIL.GetLocals(); - _signature = method.Signature; - _thisType = method.OwningType; - - var ilExceptionRegions = methodIL.GetExceptionRegions(); - _exceptionRegions = new ExceptionRegion[ilExceptionRegions.Length]; - for (int i = 0; i < ilExceptionRegions.Length; i++) - { - _exceptionRegions[i] = new ExceptionRegion() { ILRegion = ilExceptionRegions[i] }; - } - _llvmFunction = GetOrCreateLLVMFunction(mangledName); - _builder = LLVM.CreateBuilder(); - } - - public void Import() - { - FindBasicBlocks(); - - try - { - ImportBasicBlocks(); - } - catch - { - // Change the function body to trap - foreach (BasicBlock block in _basicBlocks) - { - if (block != null && block.Block.Pointer != IntPtr.Zero) - { - LLVM.DeleteBasicBlock(block.Block); - } - } - LLVMBasicBlockRef trapBlock = LLVM.AppendBasicBlock(_llvmFunction, "Trap"); - LLVM.PositionBuilderAtEnd(_builder, trapBlock); - EmitTrapCall(); - LLVM.BuildRetVoid(_builder); - throw; - } - finally - { - // Generate thunk for runtime exports - if (_method.IsRuntimeExport) - { - EmitNativeToManagedThunk(_compilation, _method, ((EcmaMethod)_method).GetRuntimeExportName(), _llvmFunction); - } - } - } - - private void GenerateProlog() - { - int totalLocalSize = 0; - foreach(LocalVariableDefinition local in _locals) - { - int localSize = local.Type.GetElementSize().AsInt; - totalLocalSize += localSize; - } - - var sp = LLVM.GetFirstParam(_llvmFunction); - int paramOffset = GetTotalParameterOffset(); - for (int i = 0; i < totalLocalSize; i++) - { - var stackOffset = LLVM.BuildGEP(_builder, sp, new LLVMValueRef[] { LLVM.ConstInt(LLVM.Int32Type(), (ulong)(paramOffset + i), LLVMMisc.False) }, String.Empty); - LLVM.BuildStore(_builder, LLVM.ConstInt(LLVM.Int8Type(), 0, LLVMMisc.False), stackOffset); - } - } - - private LLVMValueRef CreateLLVMFunction(string mangledName) - { - LLVMTypeRef universalSignature = LLVM.FunctionType(LLVM.VoidType(), new LLVMTypeRef[] { LLVM.PointerType(LLVM.Int8Type(), 0), LLVM.PointerType(LLVM.Int8Type(), 0) }, false); - return LLVM.AddFunction(Module, mangledName , universalSignature); - } - - private LLVMValueRef GetOrCreateLLVMFunction(string mangledName) - { - LLVMValueRef llvmFunction = LLVM.GetNamedFunction(Module, mangledName); - - if(llvmFunction.Pointer == IntPtr.Zero) - { - return CreateLLVMFunction(mangledName); - } - return llvmFunction; - } - - private LLVMValueRef GetOrCreateLLVMFunction(string mangledName, LLVMTypeRef functionType) - { - LLVMValueRef llvmFunction = LLVM.GetNamedFunction(Module, mangledName); - - if (llvmFunction.Pointer == IntPtr.Zero) - { - return LLVM.AddFunction(Module, mangledName, functionType); - } - return llvmFunction; - } - - private void ImportCallMemset(LLVMValueRef targetPointer, byte value, int length) - { - LLVMValueRef objectSizeValue = BuildConstInt32(length); - var memsetSignature = LLVM.FunctionType(LLVM.VoidType(), new LLVMTypeRef[] { LLVM.PointerType(LLVM.Int8Type(), 0), LLVM.Int8Type(), LLVM.Int32Type(), LLVM.Int32Type(), LLVM.Int1Type() }, false); - LLVM.BuildCall(_builder, GetOrCreateLLVMFunction("llvm.memset.p0i8.i32", memsetSignature), new LLVMValueRef[] { targetPointer, BuildConstInt8(value), objectSizeValue, BuildConstInt32(1), BuildConstInt1(0) }, String.Empty); - } - - private void PushLoadExpression(StackValueKind kind, string name, LLVMValueRef rawLLVMValue, TypeDesc type) - { - Debug.Assert(kind != StackValueKind.Unknown, "Unknown stack kind"); - _stack.Push(new LoadExpressionEntry(kind, name, rawLLVMValue, type)); - } - - /// - /// Push an expression named of kind . - /// - /// Kind of entry in stack - /// Variable to be pushed - /// Type if any of - private void PushExpression(StackValueKind kind, string name, LLVMValueRef llvmValue, TypeDesc type = null) - { - Debug.Assert(kind != StackValueKind.Unknown, "Unknown stack kind"); - - switch (kind) - { - case StackValueKind.Int32: - { - if (!type.IsWellKnownType(WellKnownType.Int32) - && !type.IsWellKnownType(WellKnownType.IntPtr) - && !type.IsWellKnownType(WellKnownType.UInt32) - && !type.IsWellKnownType(WellKnownType.UIntPtr)) - { - llvmValue = LLVM.BuildIntCast(_builder, llvmValue, LLVM.Int32Type(), ""); - } - } - break; - - case StackValueKind.Int64: - { - if (!type.IsWellKnownType(WellKnownType.Int64) - && !(type.IsWellKnownType(WellKnownType.UInt64))) - { - llvmValue = LLVM.BuildIntCast(_builder, llvmValue, LLVM.Int64Type(), ""); - } - } - break; - - case StackValueKind.NativeInt: - break; - } - - _stack.Push(new ExpressionEntry(kind, name, llvmValue, type)); - } - - private void MarkInstructionBoundary() - { - } - - private LLVMBasicBlockRef GetLLVMBasicBlockForBlock(BasicBlock block) - { - if (block.Block.Pointer == IntPtr.Zero) - { - block.Block = LLVM.AppendBasicBlock(_llvmFunction, "Block" + block.StartOffset); - } - return block.Block; - } - - private void StartImportingBasicBlock(BasicBlock basicBlock) - { - _stack.Clear(); - - EvaluationStack entryStack = basicBlock.EntryStack; - if (entryStack != null) - { - int n = entryStack.Length; - for (int i = 0; i < n; i++) - { - _stack.Push(entryStack[i].Duplicate()); - } - } - - bool isFirstBlock = false; - if(_curBasicBlock.Equals(default(LLVMBasicBlockRef))) - { - isFirstBlock = true; - } - _curBasicBlock = GetLLVMBasicBlockForBlock(basicBlock); - - LLVM.PositionBuilderAtEnd(_builder, _curBasicBlock); - - if(isFirstBlock) - { - GenerateProlog(); - } - } - - private void EndImportingBasicBlock(BasicBlock basicBlock) - { - var terminator = basicBlock.Block.GetBasicBlockTerminator(); - if (terminator.Pointer == IntPtr.Zero) - { - if (_basicBlocks.Length > _currentOffset) - { - if (_basicBlocks[_currentOffset].StartOffset == 0) - throw new InvalidProgramException(); - - LLVM.BuildBr(_builder, GetLLVMBasicBlockForBlock(_basicBlocks[_currentOffset])); - } - else - { - LLVM.BuildRet(_builder, default(LLVMValueRef)); - } - } - } - - private void StartImportingInstruction() - { - } - - private void EndImportingInstruction() - { - } - - private void ImportNop() - { - EmitDoNothingCall(); - } - - private void ImportBreak() - { - } - - private void ImportLoadVar(int index, bool argument) - { - LLVMValueRef typedLoadLocation = LoadVarAddress(index, argument ? LocalVarKind.Argument : LocalVarKind.Local, out TypeDesc type); - PushLoadExpression(GetStackValueKind(type), "ld" + (argument ? "arg" : "loc") + index + "_", typedLoadLocation, type); - } - - private LLVMValueRef LoadTemp(int index) - { - LLVMValueRef address = LoadVarAddress(index, LocalVarKind.Temp, out TypeDesc type); - return LLVM.BuildLoad(_builder, CastToPointerToTypeDesc(address, type), "ldtemp"); - } - - internal LLVMValueRef LoadTemp(int index, LLVMTypeRef asType) - { - LLVMValueRef address = LoadVarAddress(index, LocalVarKind.Temp, out TypeDesc type); - return LLVM.BuildLoad(_builder, CastIfNecessary(address, LLVM.PointerType(asType, 0)), "ldtemp"); - } - - private void StoreTemp(int index, LLVMValueRef value) - { - LLVMValueRef address = LoadVarAddress(index, LocalVarKind.Temp, out TypeDesc type); - LLVM.BuildStore(_builder, CastToTypeDesc(value, type), CastToPointerToTypeDesc(address, type)); - } - - internal static LLVMValueRef LoadValue(LLVMBuilderRef builder, LLVMValueRef address, TypeDesc sourceType, LLVMTypeRef targetType, bool signExtend) - { - if (targetType.TypeKind == LLVMTypeKind.LLVMIntegerTypeKind && sourceType.IsPrimitive && !sourceType.IsPointer) - { - var sourceLLVMType = ILImporter.GetLLVMTypeForTypeDesc(sourceType); - var typedAddress = CastIfNecessary(builder, address, LLVM.PointerType(sourceLLVMType, 0)); - return CastIntValue(builder, LLVM.BuildLoad(builder, typedAddress, "ldvalue"), targetType, signExtend); - } - else - { - var typedAddress = CastIfNecessary(builder, address, LLVM.PointerType(targetType, 0)); - return LLVM.BuildLoad(builder, typedAddress, "ldvalue"); - } - } - - private static LLVMValueRef CastIntValue(LLVMBuilderRef builder, LLVMValueRef value, LLVMTypeRef type, bool signExtend) - { - LLVMTypeKind typeKind = LLVM.TypeOf(value).TypeKind; - if (LLVM.TypeOf(value).Pointer == type.Pointer) - { - return value; - } - else if (typeKind == LLVMTypeKind.LLVMPointerTypeKind) - { - return LLVM.BuildPtrToInt(builder, value, type, "intcast"); - } - else if (typeKind == LLVMTypeKind.LLVMFloatTypeKind || typeKind == LLVMTypeKind.LLVMDoubleTypeKind) - { - if (signExtend) - { - return LLVM.BuildFPToSI(builder, value, type, "fptosi"); - } - else - { - return LLVM.BuildFPToUI(builder, value, type, "fptoui"); - } - } - else if (signExtend && type.GetIntTypeWidth() > LLVM.TypeOf(value).GetIntTypeWidth()) - { - return LLVM.BuildSExtOrBitCast(builder, value, type, "SExtOrBitCast"); - } - else - { - Debug.Assert(typeKind == LLVMTypeKind.LLVMIntegerTypeKind); - return LLVM.BuildIntCast(builder, value, type, "intcast"); - } - } - - private LLVMValueRef LoadVarAddress(int index, LocalVarKind kind, out TypeDesc type) - { - int varBase; - int varCountBase; - int varOffset; - LLVMTypeRef valueType; - - if (kind == LocalVarKind.Argument) - { - varCountBase = 0; - varBase = 0; - if (!_signature.IsStatic) - { - varCountBase = 1; - } - - GetArgSizeAndOffsetAtIndex(index, out int argSize, out varOffset); - - if (!_signature.IsStatic && index == 0) - { - type = _thisType; - if (type.IsValueType) - { - type = type.MakeByRefType(); - } - } - else - { - type = _signature[index - varCountBase]; - } - valueType = GetLLVMTypeForTypeDesc(type); - } - else if (kind == LocalVarKind.Local) - { - varBase = GetTotalParameterOffset(); - GetLocalSizeAndOffsetAtIndex(index, out int localSize, out varOffset); - valueType = GetLLVMTypeForTypeDesc(_locals[index].Type); - type = _locals[index].Type; - } - else - { - varBase = GetTotalRealLocalOffset(); - GetSpillSizeAndOffsetAtIndex(index, out int localSize, out varOffset); - valueType = GetLLVMTypeForTypeDesc(_spilledExpressions[index].Type); - type = _spilledExpressions[index].Type; - } - - return LLVM.BuildGEP(_builder, LLVM.GetFirstParam(_llvmFunction), - new LLVMValueRef[] { LLVM.ConstInt(LLVM.Int32Type(), (uint)(varBase + varOffset), LLVMMisc.False) }, - String.Empty); - - } - - private StackValueKind GetStackValueKind(TypeDesc type) - { - switch (type.Category) - { - case TypeFlags.Boolean: - case TypeFlags.Char: - case TypeFlags.SByte: - case TypeFlags.Byte: - case TypeFlags.Int16: - case TypeFlags.UInt16: - case TypeFlags.Int32: - case TypeFlags.UInt32: - return StackValueKind.Int32; - case TypeFlags.Int64: - case TypeFlags.UInt64: - return StackValueKind.Int64; - case TypeFlags.Single: - case TypeFlags.Double: - return StackValueKind.Float; - case TypeFlags.IntPtr: - case TypeFlags.UIntPtr: - return StackValueKind.NativeInt; - case TypeFlags.ValueType: - case TypeFlags.Nullable: - return StackValueKind.ValueType; - case TypeFlags.Enum: - return GetStackValueKind(type.UnderlyingType); - case TypeFlags.Class: - case TypeFlags.Interface: - case TypeFlags.Array: - case TypeFlags.SzArray: - return StackValueKind.ObjRef; - case TypeFlags.ByRef: - return StackValueKind.ByRef; - case TypeFlags.Pointer: - return StackValueKind.NativeInt; - default: - return StackValueKind.Unknown; - } - } - - private void ImportStoreVar(int index, bool argument) - { - TypeDesc varType; - StackEntry toStore = _stack.Pop(); - LLVMValueRef varAddress = LoadVarAddress(index, argument ? LocalVarKind.Argument : LocalVarKind.Local, out varType); - CastingStore(varAddress, toStore, varType); - } - - private void ImportStoreHelper(LLVMValueRef toStore, LLVMTypeRef valueType, LLVMValueRef basePtr, uint offset) - { - LLVMValueRef typedToStore = CastIfNecessary(toStore, valueType); - - var storeLocation = LLVM.BuildGEP(_builder, basePtr, - new LLVMValueRef[] { LLVM.ConstInt(LLVM.Int32Type(), offset, LLVMMisc.False) }, - String.Empty); - var typedStoreLocation = CastIfNecessary(storeLocation, LLVM.PointerType(valueType, 0)); - LLVM.BuildStore(_builder, typedToStore, typedStoreLocation); - } - - private LLVMValueRef CastToRawPointer(LLVMValueRef source) - { - return CastIfNecessary(source, LLVM.PointerType(LLVM.Int8Type(), 0)); - } - - private LLVMValueRef CastToTypeDesc(LLVMValueRef source, TypeDesc type) - { - return CastIfNecessary(source, GetLLVMTypeForTypeDesc(type)); - } - - private LLVMValueRef CastToPointerToTypeDesc(LLVMValueRef source, TypeDesc type) - { - return CastIfNecessary(source, LLVM.PointerType(GetLLVMTypeForTypeDesc(type), 0)); - } - - private void CastingStore(LLVMValueRef address, StackEntry value, TypeDesc targetType) - { - var typedStoreLocation = CastToPointerToTypeDesc(address, targetType); - LLVM.BuildStore(_builder, value.ValueAsType(targetType, _builder), typedStoreLocation); - } - - private LLVMValueRef CastIfNecessary(LLVMValueRef source, LLVMTypeRef valueType) - { - return CastIfNecessary(_builder, source, valueType); - } - - internal static LLVMValueRef CastIfNecessary(LLVMBuilderRef builder, LLVMValueRef source, LLVMTypeRef valueType) - { - LLVMTypeRef sourceType = LLVM.TypeOf(source); - if (sourceType.Pointer == valueType.Pointer) - return source; - - LLVMTypeKind toStoreKind = LLVM.GetTypeKind(LLVM.TypeOf(source)); - LLVMTypeKind valueTypeKind = LLVM.GetTypeKind(valueType); - - LLVMValueRef typedToStore = source; - if (toStoreKind == LLVMTypeKind.LLVMPointerTypeKind && valueTypeKind == LLVMTypeKind.LLVMPointerTypeKind) - { - typedToStore = LLVM.BuildPointerCast(builder, source, valueType, "CastIfNecessaryPtr"); - } - else if (toStoreKind == LLVMTypeKind.LLVMPointerTypeKind && valueTypeKind == LLVMTypeKind.LLVMIntegerTypeKind) - { - typedToStore = LLVM.BuildPtrToInt(builder, source, valueType, "CastIfNecessaryInt"); - } - else if (toStoreKind == LLVMTypeKind.LLVMIntegerTypeKind && valueTypeKind == LLVMTypeKind.LLVMArrayTypeKind) - { - typedToStore = LLVM.BuildLoad(builder, CastIfNecessary(builder, source, LLVM.PointerType(valueType, 0)), "CastIfNecessaryArrayLoad"); - } - else if (toStoreKind == LLVMTypeKind.LLVMPointerTypeKind && valueTypeKind == LLVMTypeKind.LLVMArrayTypeKind) - { - typedToStore = LLVM.BuildLoad(builder, CastIfNecessary(builder, source, LLVM.PointerType(valueType, 0)), "CastIfNecessaryArrayLoad"); - } - else if (toStoreKind == LLVMTypeKind.LLVMPointerTypeKind && valueTypeKind != LLVMTypeKind.LLVMIntegerTypeKind) - { - throw new NotImplementedException($"trying to cast {toStoreKind} to {valueTypeKind}"); - } - else if (toStoreKind == LLVMTypeKind.LLVMIntegerTypeKind && valueTypeKind == LLVMTypeKind.LLVMPointerTypeKind) - { - typedToStore = LLVM.BuildIntToPtr(builder, source, valueType, "CastIfNecessaryPtr"); - } - else if (toStoreKind != LLVMTypeKind.LLVMIntegerTypeKind && valueTypeKind == LLVMTypeKind.LLVMPointerTypeKind) - { - throw new NotImplementedException($"trying to cast {toStoreKind} to {valueTypeKind}"); - } - else if (toStoreKind != valueTypeKind && toStoreKind != LLVMTypeKind.LLVMIntegerTypeKind && valueTypeKind != LLVMTypeKind.LLVMIntegerTypeKind) - { - throw new NotImplementedException($"trying to cast {toStoreKind} to {valueTypeKind}"); - } - else if (toStoreKind == valueTypeKind && toStoreKind == LLVMTypeKind.LLVMIntegerTypeKind) - { - Debug.Assert(toStoreKind != LLVMTypeKind.LLVMPointerTypeKind && valueTypeKind != LLVMTypeKind.LLVMPointerTypeKind); - typedToStore = LLVM.BuildIntCast(builder, source, valueType, "CastIfNecessaryInt"); - } - else if (toStoreKind != LLVMTypeKind.LLVMFloatTypeKind && valueTypeKind == LLVMTypeKind.LLVMFloatTypeKind) - { - typedToStore = LLVM.BuildFPCast(builder, source, valueType, "CastIfNecessaryFloat"); - } - else if ((toStoreKind == LLVMTypeKind.LLVMDoubleTypeKind || toStoreKind == LLVMTypeKind.LLVMFloatTypeKind) && - valueTypeKind == LLVMTypeKind.LLVMIntegerTypeKind) - { - //TODO: keep track of the TypeDesc so we can call BuildFPToUI when the integer is unsigned - typedToStore = LLVM.BuildFPToSI(builder, source, valueType, "CastIfNecessaryFloat"); - } - else if (toStoreKind == LLVMTypeKind.LLVMIntegerTypeKind && valueTypeKind == LLVMTypeKind.LLVMDoubleTypeKind) - { - throw new NotImplementedException(); - } - - return typedToStore; - } - - internal static LLVMTypeRef GetLLVMTypeForTypeDesc(TypeDesc type) - { - switch (type.Category) - { - case TypeFlags.Boolean: - return LLVM.Int1Type(); - - case TypeFlags.SByte: - case TypeFlags.Byte: - return LLVM.Int8Type(); - - case TypeFlags.Int16: - case TypeFlags.UInt16: - case TypeFlags.Char: - return LLVM.Int16Type(); - - case TypeFlags.Int32: - case TypeFlags.UInt32: - return LLVM.Int32Type(); - case TypeFlags.IntPtr: - case TypeFlags.UIntPtr: - case TypeFlags.Array: - case TypeFlags.SzArray: - case TypeFlags.ByRef: - case TypeFlags.Class: - case TypeFlags.Interface: - return LLVM.PointerType(LLVM.Int8Type(), 0); - - case TypeFlags.Pointer: - return LLVM.PointerType(type.GetParameterType().IsVoid ? LLVM.Int8Type() : GetLLVMTypeForTypeDesc(type.GetParameterType()), 0); - - case TypeFlags.Int64: - case TypeFlags.UInt64: - return LLVM.Int64Type(); - - case TypeFlags.Single: - return LLVM.FloatType(); - - case TypeFlags.Double: - return LLVM.DoubleType(); - - case TypeFlags.ValueType: - case TypeFlags.Nullable: - return LLVM.ArrayType(LLVM.Int8Type(), (uint)type.GetElementSize().AsInt); - - case TypeFlags.Enum: - return GetLLVMTypeForTypeDesc(type.UnderlyingType); - - case TypeFlags.Void: - return LLVM.VoidType(); - - default: - throw new NotImplementedException(type.Category.ToString()); - } - } - - private int GetTotalLocalOffset() - { - int offset = GetTotalRealLocalOffset(); - for (int i = 0; i < _spilledExpressions.Count; i++) - { - offset += _spilledExpressions[i].Type.GetElementSize().AsInt; - } - return offset; - } - - private int GetTotalRealLocalOffset() - { - int offset = 0; - for (int i = 0; i < _locals.Length; i++) - { - offset += _locals[i].Type.GetElementSize().AsInt; - } - return offset; - } - - private int GetTotalParameterOffset() - { - int offset = 0; - for (int i = 0; i < _signature.Length; i++) - { - offset += _signature[i].GetElementSize().AsInt; - } - if (!_signature.IsStatic) - { - // If this is a struct, then it's a pointer on the stack - if (_thisType.IsValueType) - { - offset += _thisType.Context.Target.PointerSize; - } - else - { - offset += _thisType.GetElementSize().AsInt; - } - } - - return offset; - } - - private void GetArgSizeAndOffsetAtIndex(int index, out int size, out int offset) - { - int thisSize = 0; - if (!_signature.IsStatic) - { - thisSize = _thisType.IsValueType ? _thisType.Context.Target.PointerSize : _thisType.GetElementSize().AsInt; - if (index == 0) - { - size = thisSize; - offset = 0; - return; - } - else - { - index--; - } - } - - var argType = _signature[index]; - size = argType.GetElementSize().AsInt; - - offset = thisSize; - for (int i = 0; i < index; i++) - { - offset += _signature[i].GetElementSize().AsInt; - } - } - - private void GetLocalSizeAndOffsetAtIndex(int index, out int size, out int offset) - { - LocalVariableDefinition local = _locals[index]; - size = local.Type.GetElementSize().AsInt; - - offset = 0; - for (int i = 0; i < index; i++) - { - offset += _locals[i].Type.GetElementSize().AsInt; - } - } - - private void GetSpillSizeAndOffsetAtIndex(int index, out int size, out int offset) - { - SpilledExpressionEntry spill = _spilledExpressions[index]; - size = spill.Type.GetElementSize().AsInt; - - offset = 0; - for (int i = 0; i < index; i++) - { - offset += _spilledExpressions[i].Type.GetElementSize().AsInt; - } - } - - private void ImportAddressOfVar(int index, bool argument) - { - TypeDesc type; - LLVMValueRef typedLoadLocation = LoadVarAddress(index, argument ? LocalVarKind.Argument : LocalVarKind.Local, out type); - _stack.Push(new AddressExpressionEntry(StackValueKind.ByRef, "ldloca", typedLoadLocation, type.MakePointerType())); - } - - private void ImportDup() - { - _stack.Push(_stack.Peek().Duplicate()); - } - - private void ImportPop() - { - _stack.Pop(); - } - - private void ImportJmp(int token) - { - throw new NotImplementedException("jmp"); - } - - private void ImportCasting(ILOpcode opcode, int token) - { - } - - private void ImportLoadNull() - { - _stack.Push(new ExpressionEntry(StackValueKind.ObjRef, "null", LLVM.ConstInt(LLVM.Int32Type(), 0, LLVMMisc.False))); - } - - private void ImportReturn() - { - if (_signature.ReturnType != GetWellKnownType(WellKnownType.Void)) - { - StackEntry retVal = _stack.Pop(); - LLVMTypeRef valueType = GetLLVMTypeForTypeDesc(_signature.ReturnType); - ImportStoreHelper(retVal.ValueAsType(valueType, _builder), valueType, LLVM.GetNextParam(LLVM.GetFirstParam(_llvmFunction)), 0); - } - - LLVM.BuildRetVoid(_builder); - } - - private void ImportCall(ILOpcode opcode, int token) - { - MethodDesc callee = (MethodDesc)_methodIL.GetObject(token); - if (callee.IsIntrinsic) - { - if (ImportIntrinsicCall(callee)) - { - return; - } - } - - if (callee.IsPInvoke) - { - ImportRawPInvoke(callee); - return; - } - - if (opcode == ILOpcode.newobj) - { - if (callee.OwningType.IsString) - { - // String constructors actually look like regular method calls - IMethodNode node = _compilation.NodeFactory.StringAllocator(callee); - _dependencies.Add(node); - callee = node.Method; - opcode = ILOpcode.call; - } - else - { - StackEntry newObjResult = AllocateObject(callee.OwningType); - //one for the real result and one to be consumed by ctor - if (callee.Signature.Length > _stack.Length) //System.Reflection.MemberFilter.ctor - throw new InvalidProgramException(); - _stack.InsertAt(newObjResult, _stack.Top - callee.Signature.Length); - _stack.InsertAt(newObjResult, _stack.Top - callee.Signature.Length); - } - } - - // we don't really have virtual call support, but we'll treat it as direct for now - if (opcode != ILOpcode.call && opcode != ILOpcode.callvirt && opcode != ILOpcode.newobj) - { - throw new NotImplementedException(); - } - if (opcode == ILOpcode.callvirt && callee.IsAbstract) - { - throw new NotImplementedException(); - } - - if (callee.OwningType.IsDelegate) - { - throw new NotImplementedException(); - } - - HandleCall(callee, opcode); - } - - private LLVMValueRef LLVMFunctionForMethod(MethodDesc callee, StackEntry thisPointer, bool isCallVirt) - { - string calleeName = _compilation.NameMangler.GetMangledMethodName(callee).ToString(); - if (thisPointer != null && callee.IsVirtual && isCallVirt) - { - // TODO: Full resolution of virtual methods - if (!callee.IsNewSlot) - throw new NotImplementedException(); - - if (!_compilation.HasFixedSlotVTable(callee.OwningType)) - _dependencies.Add(_compilation.NodeFactory.VirtualMethodUse(callee)); - - //TODO: needs runtime support for DispatchByInterface - if (callee.OwningType.IsInterface) - throw new NotImplementedException(); - - return GetCallableVirtualMethod(thisPointer.ValueAsType(LLVM.PointerType(LLVM.Int8Type(), 0), _builder), callee); - } - else - { - return GetOrCreateLLVMFunction(calleeName); - } - } - - private LLVMValueRef GetOrCreateMethodSlot(MethodDesc method) - { - var vtableSlotSymbol = _compilation.NodeFactory.VTableSlot(method); - _dependencies.Add(vtableSlotSymbol); - LLVMValueRef slot = LoadAddressOfSymbolNode(vtableSlotSymbol); - return LLVM.BuildLoad(_builder, slot, string.Empty); - } - - private LLVMValueRef GetCallableVirtualMethod(LLVMValueRef objectPtr, MethodDesc method) - { - Debug.Assert(method.IsVirtual); - if (method.OwningType.IsInterface) - { - throw new NotImplementedException(); - } - else - { - LLVMValueRef slot = GetOrCreateMethodSlot(method); - var pointerSize = method.Context.Target.PointerSize; - LLVMTypeRef universalSignature = LLVM.FunctionType(LLVM.VoidType(), new LLVMTypeRef[] { LLVM.PointerType(LLVM.Int8Type(), 0), LLVM.PointerType(LLVM.Int8Type(), 0) }, false); - var rawObjectPtr = CastIfNecessary(objectPtr, LLVM.PointerType(LLVM.PointerType(LLVM.PointerType(universalSignature, 0), 0), 0)); - var eeType = LLVM.BuildLoad(_builder, rawObjectPtr, "ldEEType"); - var slotPtr = LLVM.BuildGEP(_builder, eeType, new LLVMValueRef[] { slot }, "__getslot__"); - var functionPtr = LLVM.BuildLoad(_builder, slotPtr, "ld__getslot__"); - return functionPtr; - } - } - - private ExpressionEntry AllocateObject(TypeDesc type) - { - MetadataType metadataType = (MetadataType)type; - int objectSize = metadataType.InstanceByteCount.AsInt; - if (metadataType.IsValueType) - { - objectSize += type.Context.Target.PointerSize; - } - - LLVMValueRef eeTypePointer = GetEETypeForTypeDesc(type, true); - var rhpNewFastSig = LLVM.FunctionType(LLVMTypeRef.PointerType(LLVMTypeRef.Int8Type(), 0), new LLVMTypeRef[] { LLVM.TypeOf(eeTypePointer) }, false); - var rhpNewFast = GetOrCreateLLVMFunction("RhpNewFast", rhpNewFastSig); - LLVMValueRef allocatedMemory = LLVM.BuildCall(_builder, rhpNewFast, new LLVMValueRef[] { eeTypePointer }, "newobj"); - return new ExpressionEntry(StackValueKind.ObjRef, "newobj", allocatedMemory, type); - } - - private static LLVMValueRef BuildConstInt1(int number) - { - Debug.Assert(number == 0 || number == 1, "Non-boolean int1"); - return LLVM.ConstInt(LLVM.Int1Type(), (ulong)number, LLVMMisc.False); - } - - private static LLVMValueRef BuildConstInt8(byte number) - { - return LLVM.ConstInt(LLVM.Int8Type(), number, LLVMMisc.False); - } - - private static LLVMValueRef BuildConstInt32(int number) - { - return LLVM.ConstInt(LLVM.Int32Type(), (ulong)number, LLVMMisc.False); - } - - private LLVMValueRef GetEETypeForTypeDesc(TypeDesc target, bool constructed) - { - ISymbolNode node; - if (constructed) - { - node = _compilation.NodeFactory.ConstructedTypeSymbol(target); - } - else - { - node = _compilation.NodeFactory.NecessaryTypeSymbol(target); - } - LLVMValueRef eeTypePointer = LoadAddressOfSymbolNode(node); - _dependencies.Add(node); - - return eeTypePointer; - } - - /// - /// Implements intrinsic methods instread of calling them - /// - /// True if the method was implemented - private bool ImportIntrinsicCall(MethodDesc method) - { - Debug.Assert(method.IsIntrinsic); - - if (!(method.OwningType is MetadataType metadataType)) - { - return false; - } - - switch (method.Name) - { - // Workaround for not being able to build a WASM version of CoreLib. This method - // would return the x64 size, which is too large for WASM - case "get_OffsetToStringData": - if (metadataType.Name == "RuntimeHelpers" && metadataType.Namespace == "System.Runtime.CompilerServices") - { - _stack.Push(new Int32ConstantEntry(8, _method.Context.GetWellKnownType(WellKnownType.Int32))); - return true; - } - break; - } - - return false; - } - - private void HandleCall(MethodDesc callee, ILOpcode opcode = ILOpcode.call) - { - AddMethodReference(callee); - int offset = GetTotalParameterOffset() + GetTotalLocalOffset() + callee.Signature.ReturnType.GetElementSize().AsInt; - - LLVMValueRef shadowStack = LLVM.BuildGEP(_builder, LLVM.GetFirstParam(_llvmFunction), - new LLVMValueRef[] { LLVM.ConstInt(LLVM.Int32Type(), (uint)offset, LLVMMisc.False) }, - String.Empty); - var castShadowStack = LLVM.BuildPointerCast(_builder, shadowStack, LLVM.PointerType(LLVM.Int8Type(), 0), "castshadowstack"); - - int returnOffset = GetTotalParameterOffset() + GetTotalLocalOffset(); - var returnAddress = LLVM.BuildGEP(_builder, LLVM.GetFirstParam(_llvmFunction), - new LLVMValueRef[] { LLVM.ConstInt(LLVM.Int32Type(), (uint)returnOffset, LLVMMisc.False) }, - String.Empty); - var castReturnAddress = LLVM.BuildPointerCast(_builder, returnAddress, LLVM.PointerType(LLVM.Int8Type(), 0), "castreturnaddress"); - - // argument offset - uint argOffset = 0; - int instanceAdjustment = 0; - if (!callee.Signature.IsStatic) - { - instanceAdjustment = 1; - } - - // The last argument is the top of the stack. We need to reverse them and store starting at the first argument - StackEntry[] argumentValues = new StackEntry[callee.Signature.Length + instanceAdjustment]; - - for(int i = 0; i < argumentValues.Length; i++) - { - argumentValues[argumentValues.Length - i - 1] = _stack.Pop(); - } - - for (int index = 0; index < argumentValues.Length; index++) - { - StackEntry toStore = argumentValues[index]; - - TypeDesc argType; - if (index == 0 && !callee.Signature.IsStatic) - { - if(callee.OwningType.IsValueType) - argType = callee.OwningType.MakeByRefType(); - else - argType = callee.OwningType; - } - else - { - argType = callee.Signature[index - instanceAdjustment]; - } - - LLVMTypeRef valueType = GetLLVMTypeForTypeDesc(argType); - - ImportStoreHelper(toStore.ValueAsType(valueType, _builder), valueType, castShadowStack, argOffset); - - argOffset += (uint)argType.GetElementSize().AsInt; - } - - LLVMValueRef fn = LLVMFunctionForMethod(callee, callee.Signature.IsStatic ? null : argumentValues[0], opcode == ILOpcode.callvirt); - LLVM.BuildCall(_builder, fn, new LLVMValueRef[] { - castShadowStack, - castReturnAddress}, string.Empty); - - - if (!callee.Signature.ReturnType.IsVoid) - { - LLVMTypeRef returnLLVMType = GetLLVMTypeForTypeDesc(callee.Signature.ReturnType); - LLVMValueRef returnLLVMPointer = LLVM.BuildPointerCast(_builder, returnAddress, LLVM.PointerType(returnLLVMType, 0), "castreturnpointer"); - PushLoadExpression(GetStackValueKind(callee.Signature.ReturnType), String.Empty, returnLLVMPointer, callee.Signature.ReturnType); - } - } - - private void AddMethodReference(MethodDesc method) - { - _dependencies.Add(_compilation.NodeFactory.MethodEntrypoint(method)); - } - - private void ImportRawPInvoke(MethodDesc method) - { - LLVMValueRef nativeFunc = LLVM.GetNamedFunction(Module, method.Name); - - //emscripten dies if this is output because its expected to have i32, i32, i64. But the runtime has defined it as i8*, i8*, i64 - if (method.Name == "memmove") - throw new NotImplementedException(); - - - // Create an import if we haven't already - if (nativeFunc.Pointer == IntPtr.Zero) - { - // Set up native parameter types - LLVMTypeRef[] paramTypes = new LLVMTypeRef[method.Signature.Length]; - for (int i = 0; i < paramTypes.Length; i++) - { - paramTypes[i] = GetLLVMTypeForTypeDesc(method.Signature[i]); - } - - // Define the full signature - LLVMTypeRef nativeFuncType = LLVM.FunctionType(GetLLVMTypeForTypeDesc(method.Signature.ReturnType), paramTypes, LLVMMisc.False); - - nativeFunc = LLVM.AddFunction(Module, method.Name, nativeFuncType); - LLVM.SetLinkage(nativeFunc, LLVMLinkage.LLVMDLLImportLinkage); - } - - LLVMValueRef[] arguments = new LLVMValueRef[method.Signature.Length]; - for(int i = 0; i < arguments.Length; i++) - { - // Arguments are reversed on the stack - // Coerce pointers to the native type - TypeDesc signatureType = method.Signature[arguments.Length - i - 1]; - arguments[arguments.Length - i - 1] = _stack.Pop().ValueAsType(GetLLVMTypeForTypeDesc(signatureType), _builder); - } - - // Save the top of the shadow stack in case the callee reverse P/Invokes - LLVMValueRef stackFrameSize = BuildConstInt32(GetTotalParameterOffset() + GetTotalLocalOffset()); - LLVM.BuildStore(_builder, LLVM.BuildGEP(_builder, LLVM.GetFirstParam(_llvmFunction), new LLVMValueRef[] { stackFrameSize }, "shadowStackTop"), - LLVM.GetNamedGlobal(Module, "t_pShadowStackTop")); - - // Don't name the return value if the function returns void, it's invalid - var returnValue = LLVM.BuildCall(_builder, nativeFunc, arguments, !method.Signature.ReturnType.IsVoid ? "call" : string.Empty); - - if(!method.Signature.ReturnType.IsVoid) - PushExpression(GetStackValueKind(method.Signature.ReturnType), "retval", returnValue, method.Signature.ReturnType); - } - - static LLVMValueRef s_shadowStackTop = default(LLVMValueRef); - LLVMValueRef ShadowStackTop - { - get - { - if (s_shadowStackTop.Pointer.Equals(IntPtr.Zero)) - { - s_shadowStackTop = LLVM.AddGlobal(Module, LLVM.PointerType(LLVM.Int8Type(), 0), "t_pShadowStackTop"); - LLVM.SetLinkage(s_shadowStackTop, LLVMLinkage.LLVMInternalLinkage); - LLVM.SetInitializer(s_shadowStackTop, LLVM.ConstPointerNull(LLVM.PointerType(LLVM.Int8Type(), 0))); - LLVM.SetThreadLocal(s_shadowStackTop, LLVMMisc.True); - } - return s_shadowStackTop; - } - } - - private void EmitNativeToManagedThunk(WebAssemblyCodegenCompilation compilation, MethodDesc method, string nativeName, LLVMValueRef managedFunction) - { - LLVMTypeRef[] llvmParams = new LLVMTypeRef[method.Signature.Length]; - for (int i = 0; i < llvmParams.Length; i++) - { - llvmParams[i] = GetLLVMTypeForTypeDesc(method.Signature[i]); - } - - LLVMTypeRef thunkSig = LLVM.FunctionType(GetLLVMTypeForTypeDesc(method.Signature.ReturnType), llvmParams, false); - LLVMValueRef thunkFunc = LLVM.AddFunction(compilation.Module, nativeName, thunkSig); - LLVMBasicBlockRef block = LLVM.AppendBasicBlock(thunkFunc, "Block0"); - LLVMBuilderRef builder = LLVM.CreateBuilder(); - LLVM.PositionBuilderAtEnd(builder, block); - - LLVMValueRef shadowStack = LLVM.BuildLoad(builder, ShadowStackTop, ""); - - int curOffset = 0; - for (int i = 0; i < llvmParams.Length; i++) - { - LLVMValueRef argAddr = LLVM.BuildGEP(builder, shadowStack, new LLVMValueRef[] { LLVM.ConstInt(LLVM.Int32Type(), (ulong)curOffset, LLVMMisc.False) }, "arg" + i); - LLVM.BuildStore(builder, LLVM.GetParam(thunkFunc, (uint)i), CastIfNecessary(builder, argAddr, LLVM.PointerType(llvmParams[i], 0))); - curOffset += method.Signature[i].GetElementSize().AsInt; - } - - LLVMValueRef retAddr = LLVM.BuildGEP(builder, shadowStack, new LLVMValueRef[] { LLVM.ConstInt(LLVM.Int32Type(), (ulong)curOffset, LLVMMisc.False) }, "retAddr"); - LLVM.BuildCall(builder, managedFunction, new LLVMValueRef[] { shadowStack, retAddr }, ""); - if (method.Signature.ReturnType != compilation.TypeSystemContext.GetWellKnownType(WellKnownType.Void)) - { - LLVM.BuildRet(builder, LLVM.BuildLoad(builder, CastIfNecessary(builder, retAddr, LLVM.PointerType(GetLLVMTypeForTypeDesc(method.Signature.ReturnType), 0)), "")); - } - else - { - LLVM.BuildRetVoid(builder); - } - } - - private void ImportCalli(int token) - { - } - - private void ImportLdFtn(int token, ILOpcode opCode) - { - } - - private void ImportLoadInt(long value, StackValueKind kind) - { - switch (kind) - { - case StackValueKind.Int32: - case StackValueKind.NativeInt: - _stack.Push(new Int32ConstantEntry((int)value, _method.Context.GetWellKnownType(WellKnownType.Int32))); - break; - - case StackValueKind.Int64: - _stack.Push(new Int64ConstantEntry(value, _method.Context.GetWellKnownType(WellKnownType.Int64))); - break; - - default: - throw new InvalidOperationException(kind.ToString()); - } - - } - - private void ImportLoadFloat(double value) - { - _stack.Push(new FloatConstantEntry(value, _method.Context.GetWellKnownType(WellKnownType.Double))); - } - - private void ImportBranch(ILOpcode opcode, BasicBlock target, BasicBlock fallthrough) - { - if (opcode == ILOpcode.br) - { - ImportFallthrough(target); - //TODO: why does this illegal branch happen in System.Reflection.MemberFilter.ctor - if (target.StartOffset == 0) - throw new InvalidProgramException(); - LLVM.BuildBr(_builder, GetLLVMBasicBlockForBlock(target)); - } - else - { - LLVMValueRef condition; - - if (opcode == ILOpcode.brfalse || opcode == ILOpcode.brtrue) - { - var op = _stack.Pop(); - LLVMValueRef value = op.ValueAsInt32(_builder, false); - - if (LLVM.TypeOf(value).TypeKind != LLVMTypeKind.LLVMIntegerTypeKind) - throw new InvalidProgramException("branch on non integer"); - - if (opcode == ILOpcode.brfalse) - { - condition = LLVM.BuildICmp(_builder, LLVMIntPredicate.LLVMIntEQ, value, LLVM.ConstInt(LLVM.TypeOf(value), 0, LLVMMisc.False), "brfalse"); - } - else - { - condition = LLVM.BuildICmp(_builder, LLVMIntPredicate.LLVMIntNE, value, LLVM.ConstInt(LLVM.TypeOf(value), 0, LLVMMisc.False), "brtrue"); - } - } - else - { - var op1 = _stack.Pop(); - var op2 = _stack.Pop(); - - // StackValueKind is carefully ordered to make this work (assuming the IL is valid) - StackValueKind kind; - - if (op1.Kind > op2.Kind) - { - kind = op1.Kind; - } - else - { - kind = op2.Kind; - } - - LLVMValueRef right = op1.ValueForStackKind(kind, _builder, false); - LLVMValueRef left = op2.ValueForStackKind(kind, _builder, false); - - if (kind != StackValueKind.Float) - { - switch (opcode) - { - case ILOpcode.beq: - condition = LLVM.BuildICmp(_builder, LLVMIntPredicate.LLVMIntEQ, left, right, "beq"); - break; - case ILOpcode.bge: - condition = LLVM.BuildICmp(_builder, LLVMIntPredicate.LLVMIntSGE, left, right, "bge"); - break; - case ILOpcode.bgt: - condition = LLVM.BuildICmp(_builder, LLVMIntPredicate.LLVMIntSGT, left, right, "bgt"); - break; - case ILOpcode.ble: - condition = LLVM.BuildICmp(_builder, LLVMIntPredicate.LLVMIntSLE, left, right, "ble"); - break; - case ILOpcode.blt: - condition = LLVM.BuildICmp(_builder, LLVMIntPredicate.LLVMIntSLT, left, right, "blt"); - break; - case ILOpcode.bne_un: - condition = LLVM.BuildICmp(_builder, LLVMIntPredicate.LLVMIntNE, left, right, "bne_un"); - break; - case ILOpcode.bge_un: - condition = LLVM.BuildICmp(_builder, LLVMIntPredicate.LLVMIntUGE, left, right, "bge_un"); - break; - case ILOpcode.bgt_un: - condition = LLVM.BuildICmp(_builder, LLVMIntPredicate.LLVMIntUGT, left, right, "bgt_un"); - break; - case ILOpcode.ble_un: - condition = LLVM.BuildICmp(_builder, LLVMIntPredicate.LLVMIntULE, left, right, "ble_un"); - break; - case ILOpcode.blt_un: - condition = LLVM.BuildICmp(_builder, LLVMIntPredicate.LLVMIntULT, left, right, "blt_un"); - break; - default: - throw new NotSupportedException(); // unreachable - } - } - else - { - switch (opcode) - { - case ILOpcode.beq: - condition = LLVM.BuildFCmp(_builder, LLVMRealPredicate.LLVMRealOEQ, left, right, "beq"); - break; - case ILOpcode.bge: - condition = LLVM.BuildFCmp(_builder, LLVMRealPredicate.LLVMRealOGE, left, right, "bge"); - break; - case ILOpcode.bgt: - condition = LLVM.BuildFCmp(_builder, LLVMRealPredicate.LLVMRealOGT, left, right, "bgt"); - break; - case ILOpcode.ble: - condition = LLVM.BuildFCmp(_builder, LLVMRealPredicate.LLVMRealOLE, left, right, "ble"); - break; - case ILOpcode.blt: - condition = LLVM.BuildFCmp(_builder, LLVMRealPredicate.LLVMRealOLT, left, right, "blt"); - break; - case ILOpcode.bne_un: - condition = LLVM.BuildFCmp(_builder, LLVMRealPredicate.LLVMRealONE, left, right, "bne_un"); - break; - case ILOpcode.bge_un: - condition = LLVM.BuildFCmp(_builder, LLVMRealPredicate.LLVMRealUGE, left, right, "bge_un"); - break; - case ILOpcode.bgt_un: - condition = LLVM.BuildFCmp(_builder, LLVMRealPredicate.LLVMRealUGT, left, right, "bgt_un"); - break; - case ILOpcode.ble_un: - condition = LLVM.BuildFCmp(_builder, LLVMRealPredicate.LLVMRealULE, left, right, "ble_un"); - break; - case ILOpcode.blt_un: - condition = LLVM.BuildFCmp(_builder, LLVMRealPredicate.LLVMRealULT, left, right, "blt_un"); - break; - default: - throw new NotSupportedException(); // unreachable - } - } - } - //TODO: why did this happen only during an optimized build of [System.Private.CoreLib]System.Threading.Lock.ReleaseContended - if (target.StartOffset == 0) - throw new NotImplementedException("cant branch to entry basic block"); - - ImportFallthrough(target); - ImportFallthrough(fallthrough); - LLVM.BuildCondBr(_builder, condition, GetLLVMBasicBlockForBlock(target), GetLLVMBasicBlockForBlock(fallthrough)); - } - } - - private void ImportSwitchJump(int jmpBase, int[] jmpDelta, BasicBlock fallthrough) - { - var operand = _stack.Pop(); - - var @switch = LLVM.BuildSwitch(_builder, operand.ValueAsInt32(_builder, false), GetLLVMBasicBlockForBlock(fallthrough), (uint)jmpDelta.Length); - for (var i = 0; i < jmpDelta.Length; i++) - { - var target = _basicBlocks[_currentOffset + jmpDelta[i]]; - LLVM.AddCase(@switch, LLVM.ConstInt(LLVM.Int32Type(), (ulong)i, false), GetLLVMBasicBlockForBlock(target)); - ImportFallthrough(target); - } - - ImportFallthrough(fallthrough); - } - - private void ImportLoadIndirect(int token) - { - ImportLoadIndirect(ResolveTypeToken(token)); - } - - private void ImportLoadIndirect(TypeDesc type) - { - var pointer = _stack.Pop(); - Debug.Assert(pointer is ExpressionEntry || pointer is ConstantEntry); - var expressionPointer = pointer as ExpressionEntry; - TypeDesc pointerElementType = pointer.Type.GetParameterType(); - LLVMValueRef rawValue = expressionPointer?.RawLLVMValue ?? LLVM.ConstNull(GetLLVMTypeForTypeDesc(pointerElementType)); - _stack.Push(new LoadExpressionEntry(type != null ? GetStackValueKind(type) : StackValueKind.ByRef, "ldind", - rawValue, pointer.Type.GetParameterType())); - } - - private void ImportStoreIndirect(int token) - { - ImportStoreIndirect(ResolveTypeToken(token)); - } - - private void ImportStoreIndirect(TypeDesc type) - { - StackEntry value = _stack.Pop(); - StackEntry destinationPointer = _stack.Pop(); - LLVMValueRef typedValue; - LLVMValueRef typedPointer; - - if (type != null) - { - typedValue = value.ValueAsType(type, _builder); - typedPointer = destinationPointer.ValueAsType(type.MakePointerType(), _builder); - } - else - { - typedPointer = destinationPointer.ValueAsType(LLVM.PointerType(LLVM.Int32Type(), 0), _builder); - typedValue = value.ValueAsInt32(_builder, false); - } - - LLVM.BuildStore(_builder, typedValue, typedPointer); - } - - private void ImportBinaryOperation(ILOpcode opcode) - { - StackEntry op1 = _stack.Pop(); - StackEntry op2 = _stack.Pop(); - - // StackValueKind is carefully ordered to make this work (assuming the IL is valid) - StackValueKind kind; - TypeDesc type; - - if (op1.Kind > op2.Kind) - { - kind = op1.Kind; - type = op1.Type; - } - else - { - kind = op2.Kind; - type = op2.Type; - } - - // The one exception from the above rule - if (kind == StackValueKind.ByRef) - { - kind = StackValueKind.NativeInt; - type = type.MakePointerType(); - } - - LLVMValueRef result; - LLVMValueRef left = op1.ValueForStackKind(kind, _builder, false); - LLVMValueRef right = op2.ValueForStackKind(kind, _builder, false); - if (kind == StackValueKind.Float) - { - switch (opcode) - { - case ILOpcode.add: - result = LLVM.BuildFAdd(_builder, left, right, "fadd"); - break; - case ILOpcode.sub: - result = LLVM.BuildFSub(_builder, left, right, "fsub"); - break; - case ILOpcode.mul: - result = LLVM.BuildFMul(_builder, left, right, "fmul"); - break; - case ILOpcode.div: - result = LLVM.BuildFDiv(_builder, left, right, "fdiv"); - break; - case ILOpcode.rem: - result = LLVM.BuildFRem(_builder, left, right, "frem"); - break; - - // TODO: Overflow checks - case ILOpcode.add_ovf: - case ILOpcode.add_ovf_un: - result = LLVM.BuildFAdd(_builder, left, right, "fadd"); - break; - case ILOpcode.sub_ovf: - case ILOpcode.sub_ovf_un: - result = LLVM.BuildFSub(_builder, left, right, "fsub"); - break; - case ILOpcode.mul_ovf: - case ILOpcode.mul_ovf_un: - result = LLVM.BuildFMul(_builder, left, right, "fmul"); - break; - - default: - throw new InvalidOperationException(); // Should be unreachable - } - } - else - { - switch (opcode) - { - case ILOpcode.add: - result = LLVM.BuildAdd(_builder, left, right, "add"); - break; - case ILOpcode.sub: - result = LLVM.BuildSub(_builder, left, right, "sub"); - break; - case ILOpcode.mul: - result = LLVM.BuildMul(_builder, left, right, "mul"); - break; - case ILOpcode.div: - result = LLVM.BuildSDiv(_builder, left, right, "sdiv"); - break; - case ILOpcode.div_un: - result = LLVM.BuildUDiv(_builder, left, right, "udiv"); - break; - case ILOpcode.rem: - result = LLVM.BuildSRem(_builder, left, right, "srem"); - break; - case ILOpcode.rem_un: - result = LLVM.BuildURem(_builder, left, right, "urem"); - break; - case ILOpcode.and: - result = LLVM.BuildAnd(_builder, left, right, "and"); - break; - case ILOpcode.or: - result = LLVM.BuildOr(_builder, left, right, "or"); - break; - case ILOpcode.xor: - result = LLVM.BuildXor(_builder, left, right, "xor"); - break; - - // TODO: Overflow checks - case ILOpcode.add_ovf: - case ILOpcode.add_ovf_un: - result = LLVM.BuildAdd(_builder, left, right, "add"); - break; - case ILOpcode.sub_ovf: - case ILOpcode.sub_ovf_un: - result = LLVM.BuildSub(_builder, left, right, "sub"); - break; - case ILOpcode.mul_ovf: - case ILOpcode.mul_ovf_un: - result = LLVM.BuildMul(_builder, left, right, "mul"); - break; - - default: - throw new InvalidOperationException(); // Should be unreachable - } - } - - - if (kind == StackValueKind.NativeInt || kind == StackValueKind.ByRef || kind == StackValueKind.ObjRef) - { - //we need to put the type back if we changed it because it started out a pointer - result = CastToTypeDesc(result, type); - } - PushExpression(kind, "binop", result, type); - } - - private void ImportShiftOperation(ILOpcode opcode) - { - LLVMValueRef result; - StackEntry numBitsToShift = _stack.Pop(); - StackEntry valueToShift = _stack.Pop(); - - LLVMValueRef valueToShiftValue = valueToShift.ValueForStackKind(valueToShift.Kind, _builder, false); - - switch (opcode) - { - case ILOpcode.shl: - result = LLVM.BuildShl(_builder, valueToShiftValue, numBitsToShift.ValueAsInt32(_builder, false), "shl"); - break; - case ILOpcode.shr: - result = LLVM.BuildAShr(_builder, valueToShiftValue, numBitsToShift.ValueAsInt32(_builder, false), "shr"); - break; - case ILOpcode.shr_un: - result = LLVM.BuildLShr(_builder, valueToShiftValue, numBitsToShift.ValueAsInt32(_builder, false), "shr"); - break; - default: - throw new InvalidOperationException(); // Should be unreachable - } - - PushExpression(valueToShift.Kind, "shiftop", result, valueToShift.Type); - } - - private void ImportCompareOperation(ILOpcode opcode) - { - var op1 = _stack.Pop(); - var op2 = _stack.Pop(); - - // StackValueKind is carefully ordered to make this work (assuming the IL is valid) - StackValueKind kind; - - if (op1.Kind > op2.Kind) - { - kind = op1.Kind; - } - else - { - kind = op2.Kind; - } - - LLVMValueRef result; - LLVMValueRef typeSaneOp1 = op1.ValueForStackKind(kind, _builder, true); - LLVMValueRef typeSaneOp2 = op2.ValueForStackKind(kind, _builder, true); - - if (kind != StackValueKind.Float) - { - switch (opcode) - { - case ILOpcode.ceq: - result = LLVM.BuildICmp(_builder, LLVMIntPredicate.LLVMIntEQ, typeSaneOp2, typeSaneOp1, "ceq"); - break; - case ILOpcode.cgt: - result = LLVM.BuildICmp(_builder, LLVMIntPredicate.LLVMIntSGT, typeSaneOp2, typeSaneOp1, "cgt"); - break; - case ILOpcode.clt: - result = LLVM.BuildICmp(_builder, LLVMIntPredicate.LLVMIntSLT, typeSaneOp2, typeSaneOp1, "clt"); - break; - case ILOpcode.cgt_un: - result = LLVM.BuildICmp(_builder, LLVMIntPredicate.LLVMIntUGT, typeSaneOp2, typeSaneOp1, "cgt_un"); - break; - case ILOpcode.clt_un: - result = LLVM.BuildICmp(_builder, LLVMIntPredicate.LLVMIntULT, typeSaneOp2, typeSaneOp1, "clt_un"); - break; - default: - throw new NotSupportedException(); // unreachable - } - } - else - { - switch (opcode) - { - case ILOpcode.ceq: - result = LLVM.BuildFCmp(_builder, LLVMRealPredicate.LLVMRealOEQ, typeSaneOp2, typeSaneOp1, "ceq"); - break; - case ILOpcode.cgt: - result = LLVM.BuildFCmp(_builder, LLVMRealPredicate.LLVMRealOGT, typeSaneOp2, typeSaneOp1, "cgt"); - break; - case ILOpcode.clt: - result = LLVM.BuildFCmp(_builder, LLVMRealPredicate.LLVMRealOLT, typeSaneOp2, typeSaneOp1, "clt"); - break; - case ILOpcode.cgt_un: - result = LLVM.BuildFCmp(_builder, LLVMRealPredicate.LLVMRealUGT, typeSaneOp2, typeSaneOp1, "cgt_un"); - break; - case ILOpcode.clt_un: - result = LLVM.BuildFCmp(_builder, LLVMRealPredicate.LLVMRealULT, typeSaneOp2, typeSaneOp1, "clt_un"); - break; - default: - throw new NotSupportedException(); // unreachable - } - } - - PushExpression(StackValueKind.Int32, "cmpop", result, GetWellKnownType(WellKnownType.SByte)); - } - - private void ImportConvert(WellKnownType wellKnownType, bool checkOverflow, bool unsigned) - { - StackEntry value = _stack.Pop(); - LLVMValueRef convertedValue; - //conv.u for a pointer should change to a int8* - if (wellKnownType == WellKnownType.UIntPtr) - { - if (value.Kind == StackValueKind.Int32) - { - convertedValue = LLVM.BuildIntToPtr(_builder, value.ValueAsInt32(_builder, false), LLVM.PointerType(LLVM.Int8Type(), 0), "conv.u"); - } - else - { - convertedValue = value.ValueAsType(GetWellKnownType(wellKnownType), _builder); - } - } - else - { - convertedValue = value.ValueAsType(GetWellKnownType(wellKnownType), _builder); - } - PushExpression(value.Kind, "conv", convertedValue, value.Type); - } - - private void ImportUnaryOperation(ILOpcode opCode) - { - var argument = _stack.Pop(); - - LLVMValueRef result; - switch (opCode) - { - case ILOpcode.neg: - if (argument.Kind == StackValueKind.Float) - { - result = LLVM.BuildFNeg(_builder, argument.ValueForStackKind(argument.Kind, _builder, false), "neg"); - } - else - { - result = LLVM.BuildNeg(_builder, argument.ValueForStackKind(argument.Kind, _builder, true), "neg"); - } - break; - case ILOpcode.not: - result = LLVM.BuildNot(_builder, argument.ValueForStackKind(argument.Kind, _builder, true), "not"); - break; - default: - throw new NotSupportedException(); // unreachable - } - - PushExpression(argument.Kind, "unaryop", result, argument.Type); - } - - private void ImportCpOpj(int token) - { - var type = ResolveTypeToken(token); - - if (!type.IsValueType) - { - throw new InvalidOperationException(); - } - - var src = _stack.Pop(); - - if (src.Kind != StackValueKind.NativeInt && src.Kind != StackValueKind.ByRef && src.Kind != StackValueKind.ObjRef) - { - throw new InvalidOperationException(); - } - - var dest = _stack.Pop(); - - if (dest.Kind != StackValueKind.NativeInt && dest.Kind != StackValueKind.ByRef && dest.Kind != StackValueKind.ObjRef) - { - throw new InvalidOperationException(); - } - - var pointerType = GetLLVMTypeForTypeDesc(type.MakePointerType()); - - var value = LLVM.BuildLoad(_builder, src.ValueAsType(pointerType, _builder), "cpobj.load"); - - LLVM.BuildStore(_builder, value, dest.ValueAsType(pointerType, _builder)); - } - - private void ImportUnbox(int token, ILOpcode opCode) - { - TypeDesc type = ResolveTypeToken(token); - if (type.IsNullable) - throw new NotImplementedException(); - - if (opCode == ILOpcode.unbox) - { - var unboxResult = _stack.Pop().ValueAsType(LLVM.PointerType(LLVM.Int8Type(), 0), _builder); - LLVMValueRef unboxData = LLVM.BuildGEP(_builder, unboxResult, new LLVMValueRef[] { BuildConstInt32(type.Context.Target.PointerSize) }, "unboxData"); - var expressionType = type.MakeByRefType(); - //push the pointer to the data, but it shouldnt be implicitly dereferenced - PushExpression(GetStackValueKind(expressionType), "unboxed", unboxData, expressionType); - } - else //unbox_any - { - Debug.Assert(opCode == ILOpcode.unbox_any); - - //TODO: when the runtime is ready switch this to calling the real RhUnboxAny - //LLVMValueRef eeType = GetEETypeForTypeDesc(type); - //var eeTypeDesc = _compilation.TypeSystemContext.SystemModule.GetKnownType("System", "EETypePtr"); - //LLVMValueRef untypedObjectValue = LLVM.BuildAlloca(_builder, GetLLVMTypeForTypeDesc(type), "objptr"); - //PushExpression(StackValueKind.ByRef, "objPtr", untypedObjectValue, type.MakePointerType()); - //PushExpression(StackValueKind.ByRef, "eeType", eeType, eeTypeDesc); - //CallRuntimeExport(_compilation.TypeSystemContext, "RhUnboxAny"); - //PushLoadExpression(GetStackValueKind(type), "unboxed", untypedObjectValue, type); - //this can be removed once we can call RhUnboxAny - if (!type.IsValueType) - throw new NotImplementedException(); - - var unboxResult = _stack.Pop().ValueAsType(LLVM.PointerType(LLVM.Int8Type(), 0), _builder); - LLVMValueRef unboxData = LLVM.BuildGEP(_builder, unboxResult, new LLVMValueRef[] { BuildConstInt32(type.Context.Target.PointerSize) }, "unboxData"); - PushLoadExpression(GetStackValueKind(type), "unboxed", unboxData, type); - } - } - - private void ImportRefAnyVal(int token) - { - } - - private void ImportCkFinite() - { - } - - private void ImportMkRefAny(int token) - { - } - - private void ImportLdToken(int token) - { - var ldtokenValue = _methodIL.GetObject(token); - WellKnownType ldtokenKind; - string name; - StackEntry value; - if (ldtokenValue is TypeDesc) - { - ldtokenKind = WellKnownType.RuntimeTypeHandle; - PushExpression(StackValueKind.ByRef, "ldtoken", GetEETypeForTypeDesc(ldtokenValue as TypeDesc, false), _compilation.TypeSystemContext.SystemModule.GetKnownType("System", "EETypePtr")); - MethodDesc helper = _compilation.TypeSystemContext.GetHelperEntryPoint("LdTokenHelpers", "GetRuntimeTypeHandle"); - AddMethodReference(helper); - HandleCall(helper); - name = ldtokenValue.ToString(); - } - else if (ldtokenValue is FieldDesc) - { - ldtokenKind = WellKnownType.RuntimeFieldHandle; - value = new LdTokenEntry(StackValueKind.ValueType, null, (FieldDesc)ldtokenValue, GetWellKnownType(ldtokenKind)); - _stack.Push(value); - } - else if (ldtokenValue is MethodDesc) - { - throw new NotImplementedException(); - } - else - { - throw new InvalidOperationException(); - } - } - - private void ImportLocalAlloc() - { - } - - private void ImportEndFilter() - { - } - - private void ImportCpBlk() - { - } - - private void ImportInitBlk() - { - } - - private void ImportRethrow() - { - EmitTrapCall(); - } - - private void ImportSizeOf(int token) - { - } - - private void ImportRefAnyType() - { - } - - private void ImportArgList() - { - } - - private void ImportUnalignedPrefix(byte alignment) - { - } - - private void ImportVolatilePrefix() - { - } - - private void ImportTailPrefix() - { - } - - private void ImportConstrainedPrefix(int token) - { - } - - private void ImportNoPrefix(byte mask) - { - } - - private void ImportReadOnlyPrefix() - { - } - - private void ImportThrow() - { - var exceptionObject = _stack.Pop(); - - EmitTrapCall(); - } - - private LLVMValueRef GetInstanceFieldAddress(StackEntry objectEntry, FieldDesc field) - { - var objectType = objectEntry.Type ?? field.OwningType; - LLVMValueRef untypedObjectValue; - LLVMTypeRef llvmObjectType = GetLLVMTypeForTypeDesc(objectType); - if (objectType.IsValueType && !objectType.IsPointer && objectEntry.Kind != StackValueKind.NativeInt && objectEntry.Kind != StackValueKind.ByRef) - { - if (objectEntry is LoadExpressionEntry) - { - untypedObjectValue = CastToRawPointer(((LoadExpressionEntry)objectEntry).RawLLVMValue); - } - else - { - untypedObjectValue = LLVM.BuildAlloca(_builder, llvmObjectType, "objptr"); - LLVM.BuildStore(_builder, objectEntry.ValueAsType(llvmObjectType, _builder), untypedObjectValue); - untypedObjectValue = LLVM.BuildPointerCast(_builder, untypedObjectValue, LLVM.PointerType(LLVMTypeRef.Int8Type(), 0), "objptrcast"); - } - } - else - { - untypedObjectValue = objectEntry.ValueAsType(LLVM.PointerType(LLVMTypeRef.Int8Type(), 0), _builder); - } - if (field.Offset.AsInt == 0) - { - return untypedObjectValue; - } - else - { - var loadLocation = LLVM.BuildGEP(_builder, untypedObjectValue, - new LLVMValueRef[] { LLVM.ConstInt(LLVM.Int32Type(), (ulong)field.Offset.AsInt, LLVMMisc.False) }, String.Empty); - return loadLocation; - } - } - - private LLVMValueRef GetFieldAddress(FieldDesc field, bool isStatic) - { - if (field.IsStatic) - { - //pop unused value - if (!isStatic) - _stack.Pop(); - - return WebAssemblyObjectWriter.EmitGlobal(Module, field, _compilation.NameMangler); - } - else - { - return GetInstanceFieldAddress(_stack.Pop(), field); - } - } - - private void ImportLoadField(int token, bool isStatic) - { - FieldDesc field = (FieldDesc)_methodIL.GetObject(token); - LLVMValueRef fieldAddress = GetFieldAddress(field, isStatic); - PushLoadExpression(GetStackValueKind(field.FieldType), "ldfld_" + field.Name, fieldAddress, field.FieldType); - } - - private void ImportAddressOfField(int token, bool isStatic) - { - FieldDesc field = (FieldDesc)_methodIL.GetObject(token); - LLVMValueRef fieldAddress = GetFieldAddress(field, isStatic); - _stack.Push(new AddressExpressionEntry(StackValueKind.ByRef, "ldflda", fieldAddress, field.FieldType.MakePointerType())); - } - - private void ImportStoreField(int token, bool isStatic) - { - FieldDesc field = (FieldDesc)_methodIL.GetObject(token); - StackEntry valueEntry = _stack.Pop(); - LLVMValueRef fieldAddress = GetFieldAddress(field, isStatic); - CastingStore(fieldAddress, valueEntry, field.FieldType); - } - - // Loads symbol address. Address is represented as a i32* - private LLVMValueRef LoadAddressOfSymbolNode(ISymbolNode node) - { - LLVMValueRef addressOfAddress = WebAssemblyObjectWriter.GetSymbolValuePointer(Module, node, _compilation.NameMangler, false); - //return addressOfAddress; - return LLVM.BuildLoad(_builder, addressOfAddress, "LoadAddressOfSymbolNode"); - } - - private void ImportLoadString(int token) - { - TypeDesc stringType = this._compilation.TypeSystemContext.GetWellKnownType(WellKnownType.String); - - string str = (string)_methodIL.GetObject(token); - ISymbolNode node = _compilation.NodeFactory.SerializedStringObject(str); - LLVMValueRef stringDataPointer = LoadAddressOfSymbolNode(node); - _dependencies.Add(node); - _stack.Push(new ExpressionEntry(GetStackValueKind(stringType), String.Empty, stringDataPointer, stringType)); - } - - private void ImportInitObj(int token) - { - TypeDesc type = ResolveTypeToken(token); - var valueEntry = _stack.Pop(); - var llvmType = GetLLVMTypeForTypeDesc(type); - if (llvmType.TypeKind == LLVMTypeKind.LLVMArrayTypeKind) - ImportCallMemset(valueEntry.ValueAsType(LLVM.PointerType(LLVM.Int8Type(), 0), _builder), 0, type.GetElementSize().AsInt); - else if (llvmType.TypeKind == LLVMTypeKind.LLVMIntegerTypeKind) - LLVM.BuildStore(_builder, LLVM.ConstInt(llvmType, 0, LLVMMisc.False), valueEntry.ValueAsType(LLVM.PointerType(llvmType, 0), _builder)); - else if (llvmType.TypeKind == LLVMTypeKind.LLVMPointerTypeKind) - LLVM.BuildStore(_builder, LLVM.ConstNull(llvmType), valueEntry.ValueAsType(LLVM.PointerType(llvmType, 0), _builder)); - else if (llvmType.TypeKind == LLVMTypeKind.LLVMFloatTypeKind) - LLVM.BuildStore(_builder, LLVM.ConstReal(llvmType, 0.0), valueEntry.ValueAsType(LLVM.PointerType(llvmType, 0), _builder)); - else - throw new NotImplementedException(); - } - - private void ImportBox(int token) - { - TypeDesc type = ResolveTypeToken(token); - if (type.IsValueType) - { - if (type.IsNullable) - throw new NotImplementedException(); - - var value = _stack.Pop(); - ExpressionEntry boxTarget = AllocateObject(type); - LLVMValueRef boxData = LLVM.BuildGEP(_builder, boxTarget.RawLLVMValue, new LLVMValueRef[] { BuildConstInt32(type.Context.Target.PointerSize) }, "boxData"); - LLVMValueRef typedBoxData = LLVM.BuildPointerCast(_builder, boxData, LLVM.PointerType(GetLLVMTypeForTypeDesc(type), 0), "typedBoxData"); - LLVM.BuildStore(_builder, value.ValueAsType(type, _builder), typedBoxData); - _stack.Push(boxTarget); - } - } - - private void ImportLeave(BasicBlock target) - { - for (int i = 0; i < _exceptionRegions.Length; i++) - { - var r = _exceptionRegions[i]; - - if (r.ILRegion.Kind == ILExceptionRegionKind.Finally && - IsOffsetContained(_currentOffset - 1, r.ILRegion.TryOffset, r.ILRegion.TryLength) && - !IsOffsetContained(target.StartOffset, r.ILRegion.TryOffset, r.ILRegion.TryLength)) - { - MarkBasicBlock(_basicBlocks[r.ILRegion.HandlerOffset]); - } - } - - MarkBasicBlock(target); - LLVM.BuildBr(_builder, GetLLVMBasicBlockForBlock(target)); - } - - private static bool IsOffsetContained(int offset, int start, int length) - { - return start <= offset && offset < start + length; - } - - private void ImportNewArray(int token) - { - } - - private void ImportLoadElement(int token) - { - } - - private void ImportLoadElement(TypeDesc elementType) - { - } - - private void ImportStoreElement(int token) - { - } - - private void ImportStoreElement(TypeDesc elementType) - { - } - - private void ImportLoadLength() - { - } - - private void ImportAddressOfElement(int token) - { - } - - private void ImportEndFinally() - { - } - - private void ImportFallthrough(BasicBlock next) - { - EvaluationStack entryStack = next.EntryStack; - - if (entryStack != null) - { - if (entryStack.Length != _stack.Length) - throw new InvalidProgramException(); - - for (int i = 0; i < entryStack.Length; i++) - { - // TODO: Do we need to allow conversions? - if (entryStack[i].Kind != _stack[i].Kind) - throw new InvalidProgramException(); - - if (entryStack[i].Kind == StackValueKind.ValueType) - { - if (entryStack[i].Type != _stack[i].Type) - throw new InvalidProgramException(); - } - } - } - else - { - if (_stack.Length > 0) - { - entryStack = new EvaluationStack(_stack.Length); - for (int i = 0; i < _stack.Length; i++) - { - entryStack.Push(NewSpillSlot(_stack[i])); - } - } - next.EntryStack = entryStack; - } - - if (entryStack != null) - { - for (int i = 0; i < entryStack.Length; i++) - { - var currentEntry = _stack[i]; - var entry = entryStack[i] as SpilledExpressionEntry; - if (entry == null) - throw new InvalidProgramException(); - - if (currentEntry is SpilledExpressionEntry) - continue; //this is already a sharable value - - StoreTemp(entry.LocalIndex, currentEntry.ValueAsType(entry.Type, _builder)); - } - } - - MarkBasicBlock(next); - - } - - private void CallRuntimeExport(TypeSystemContext context, string methodName) - { - MetadataType helperType = context.SystemModule.GetKnownType("System.Runtime", "RuntimeExports"); - MethodDesc helperMethod = helperType.GetKnownMethod(methodName, null); - HandleCall(helperMethod); - } - - private StackEntry NewSpillSlot(StackEntry entry) - { - if (entry is SpilledExpressionEntry) - return entry; - else - { - var entryType = entry.Type ?? GetWellKnownType(WellKnownType.Object); //type is required here, currently the only time entry.Type is null is if someone has pushed a null literal - var entryIndex = _spilledExpressions.Count; - var newEntry = new SpilledExpressionEntry(entry.Kind, entry is ExpressionEntry ? ((ExpressionEntry)entry).Name : "spilled" + entryIndex, entryType, entryIndex, this); - _spilledExpressions.Add(newEntry); - return newEntry; - } - } - - private TypeDesc ResolveTypeToken(int token) - { - return (TypeDesc)_methodIL.GetObject(token); - } - - private TypeDesc GetWellKnownType(WellKnownType wellKnownType) - { - return _compilation.TypeSystemContext.GetWellKnownType(wellKnownType); - } - - private void ReportInvalidBranchTarget(int targetOffset) - { - ThrowHelper.ThrowInvalidProgramException(); - } - - private void ReportFallthroughAtEndOfMethod() - { - ThrowHelper.ThrowInvalidProgramException(); - } - - private void ReportMethodEndInsideInstruction() - { - ThrowHelper.ThrowInvalidProgramException(); - } - - private void ReportInvalidInstruction(ILOpcode opcode) - { - ThrowHelper.ThrowInvalidProgramException(); - } - - private void EmitTrapCall() - { - if (TrapFunction.Pointer == IntPtr.Zero) - { - TrapFunction = LLVM.AddFunction(Module, "llvm.trap", LLVM.FunctionType(LLVM.VoidType(), Array.Empty(), false)); - } - LLVM.BuildCall(_builder, TrapFunction, Array.Empty(), string.Empty); - } - - private void EmitDoNothingCall() - { - if (DoNothingFunction.Pointer == IntPtr.Zero) - { - DoNothingFunction = LLVM.AddFunction(Module, "llvm.donothing", LLVM.FunctionType(LLVM.VoidType(), Array.Empty(), false)); - } - LLVM.BuildCall(_builder, DoNothingFunction, Array.Empty(), string.Empty); - } - - public override string ToString() - { - return _method.ToString(); - } - } -} diff --git a/external/corert/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs.REMOVED.git-id b/external/corert/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs.REMOVED.git-id new file mode 100644 index 0000000000..9b3bc33d22 --- /dev/null +++ b/external/corert/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs.REMOVED.git-id @@ -0,0 +1 @@ +8b0936d1e35484835afc47737fadb2882caef023 \ No newline at end of file diff --git a/external/corert/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter_Statics.cs b/external/corert/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter_Statics.cs index 002e5e916e..ad6bc1c78d 100644 --- a/external/corert/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter_Statics.cs +++ b/external/corert/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter_Statics.cs @@ -100,6 +100,7 @@ namespace Internal.IL methodCodeNodeNeedingCode.SetDependencies(ilImporter.GetDependencies()); } + static LLVMValueRef DebugtrapFunction = default(LLVMValueRef); static LLVMValueRef TrapFunction = default(LLVMValueRef); static LLVMValueRef DoNothingFunction = default(LLVMValueRef); diff --git a/external/corert/src/ILCompiler.WebAssembly/src/CodeGen/WebAssemblyObjectWriter.cs b/external/corert/src/ILCompiler.WebAssembly/src/CodeGen/WebAssemblyObjectWriter.cs index 9cb9b26d50..8808a2e028 100644 --- a/external/corert/src/ILCompiler.WebAssembly/src/CodeGen/WebAssemblyObjectWriter.cs +++ b/external/corert/src/ILCompiler.WebAssembly/src/CodeGen/WebAssemblyObjectWriter.cs @@ -183,9 +183,9 @@ namespace ILCompiler.DependencyAnalysis EmitNativeMain(); LLVM.WriteBitcodeToFile(Module, _objectFilePath); #if DEBUG - LLVM.PrintModuleToFile(Module, Path.ChangeExtension(_objectFilePath, ".txt"), out IntPtr unused2); + LLVM.PrintModuleToFile(Module, Path.ChangeExtension(_objectFilePath, ".txt"), out string unused2); #endif //DEBUG - LLVM.VerifyModule(Module, LLVMVerifierFailureAction.LLVMAbortProcessAction, out IntPtr unused); + LLVM.VerifyModule(Module, LLVMVerifierFailureAction.LLVMAbortProcessAction, out string unused); //throw new NotImplementedException(); // This function isn't complete } diff --git a/external/corert/src/ILCompiler.WebAssembly/src/Compiler/WebAssemblyCodegenCompilation.cs b/external/corert/src/ILCompiler.WebAssembly/src/Compiler/WebAssemblyCodegenCompilation.cs index 94b35a3f47..5a32248a7d 100644 --- a/external/corert/src/ILCompiler.WebAssembly/src/Compiler/WebAssemblyCodegenCompilation.cs +++ b/external/corert/src/ILCompiler.WebAssembly/src/Compiler/WebAssemblyCodegenCompilation.cs @@ -26,7 +26,6 @@ namespace ILCompiler : base(dependencyGraph, nodeFactory, GetCompilationRoots(roots, nodeFactory), null, null, logger) { NodeFactory = nodeFactory; - LLVM.LoadLibrary_libLLVM("./libLLVM-x64.dll"); Module = LLVM.ModuleCreateWithName("netscripten"); LLVM.SetTarget(Module, "asmjs-unknown-emscripten"); Options = options; diff --git a/external/corert/src/ILCompiler.WebAssembly/src/ILCompiler.WebAssembly.csproj b/external/corert/src/ILCompiler.WebAssembly/src/ILCompiler.WebAssembly.csproj index cd88923c71..58b4c14ebf 100644 --- a/external/corert/src/ILCompiler.WebAssembly/src/ILCompiler.WebAssembly.csproj +++ b/external/corert/src/ILCompiler.WebAssembly/src/ILCompiler.WebAssembly.csproj @@ -10,14 +10,13 @@ 8002 $(BaseOutputPath)$(OSPlatformConfig)/tools + - 3.9.1-rc3 - - - 3.9.1 - + 5.0.0 + + @@ -52,11 +51,18 @@ + - + PreserveNewest - + + PreserveNewest + + + PreserveNewest + + PreserveNewest diff --git a/external/corert/src/ILCompiler.WebAssembly/src/libLLVMdep.depproj b/external/corert/src/ILCompiler.WebAssembly/src/libLLVMdep.depproj new file mode 100644 index 0000000000..5c1bac3da7 --- /dev/null +++ b/external/corert/src/ILCompiler.WebAssembly/src/libLLVMdep.depproj @@ -0,0 +1,21 @@ + + + + + $(BaseOutputPath)$(OSPlatformConfig)/tools + + + + netstandard1.3 + $(NuPkgRid) + true + + + + + 4.0.0 + + + + + diff --git a/external/corert/src/ILCompiler/ILCompiler.sln b/external/corert/src/ILCompiler/ILCompiler.sln index c210088aa8..b8f37a7b38 100644 --- a/external/corert/src/ILCompiler/ILCompiler.sln +++ b/external/corert/src/ILCompiler/ILCompiler.sln @@ -38,11 +38,15 @@ Global Debug|Any CPU = Debug|Any CPU Debug|arm = Debug|arm Debug|arm64 = Debug|arm64 + Debug|armel = Debug|armel + Debug|wasm = Debug|wasm Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU Release|arm = Release|arm Release|arm64 = Release|arm64 + Release|armel = Release|armel + Release|wasm = Release|wasm Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection @@ -52,25 +56,37 @@ Global {DD5B6BAA-D41A-4A6E-9E7D-83060F394B10}.Debug|arm.Build.0 = Debug|arm {DD5B6BAA-D41A-4A6E-9E7D-83060F394B10}.Debug|arm64.ActiveCfg = Debug|arm64 {DD5B6BAA-D41A-4A6E-9E7D-83060F394B10}.Debug|arm64.Build.0 = Debug|arm64 + {DD5B6BAA-D41A-4A6E-9E7D-83060F394B10}.Debug|armel.ActiveCfg = Debug|Any CPU + {DD5B6BAA-D41A-4A6E-9E7D-83060F394B10}.Debug|armel.Build.0 = Debug|Any CPU + {DD5B6BAA-D41A-4A6E-9E7D-83060F394B10}.Debug|wasm.ActiveCfg = Debug|Any CPU + {DD5B6BAA-D41A-4A6E-9E7D-83060F394B10}.Debug|wasm.Build.0 = Debug|Any CPU {DD5B6BAA-D41A-4A6E-9E7D-83060F394B10}.Debug|x64.ActiveCfg = Debug|x64 {DD5B6BAA-D41A-4A6E-9E7D-83060F394B10}.Debug|x64.Build.0 = Debug|x64 {DD5B6BAA-D41A-4A6E-9E7D-83060F394B10}.Debug|x86.ActiveCfg = Debug|x86 {DD5B6BAA-D41A-4A6E-9E7D-83060F394B10}.Debug|x86.Build.0 = Debug|x86 {DD5B6BAA-D41A-4A6E-9E7D-83060F394B10}.Release|Any CPU.ActiveCfg = Release|Any CPU {DD5B6BAA-D41A-4A6E-9E7D-83060F394B10}.Release|Any CPU.Build.0 = Release|Any CPU - {DD5B6BAA-D41A-4A6E-9E7D-83060F394B10}.Release|arm.ActiveCfg = Debug|arm - {DD5B6BAA-D41A-4A6E-9E7D-83060F394B10}.Release|arm.Build.0 = Debug|arm - {DD5B6BAA-D41A-4A6E-9E7D-83060F394B10}.Release|arm64.ActiveCfg = Debug|arm64 - {DD5B6BAA-D41A-4A6E-9E7D-83060F394B10}.Release|arm64.Build.0 = Debug|arm64 - {DD5B6BAA-D41A-4A6E-9E7D-83060F394B10}.Release|x64.ActiveCfg = Debug|x64 - {DD5B6BAA-D41A-4A6E-9E7D-83060F394B10}.Release|x64.Build.0 = Debug|x64 - {DD5B6BAA-D41A-4A6E-9E7D-83060F394B10}.Release|x86.ActiveCfg = Debug|x86 - {DD5B6BAA-D41A-4A6E-9E7D-83060F394B10}.Release|x86.Build.0 = Debug|x86 + {DD5B6BAA-D41A-4A6E-9E7D-83060F394B10}.Release|arm.ActiveCfg = Release|arm + {DD5B6BAA-D41A-4A6E-9E7D-83060F394B10}.Release|arm.Build.0 = Release|arm + {DD5B6BAA-D41A-4A6E-9E7D-83060F394B10}.Release|arm64.ActiveCfg = Release|arm64 + {DD5B6BAA-D41A-4A6E-9E7D-83060F394B10}.Release|arm64.Build.0 = Release|arm64 + {DD5B6BAA-D41A-4A6E-9E7D-83060F394B10}.Release|armel.ActiveCfg = Release|Any CPU + {DD5B6BAA-D41A-4A6E-9E7D-83060F394B10}.Release|armel.Build.0 = Release|Any CPU + {DD5B6BAA-D41A-4A6E-9E7D-83060F394B10}.Release|wasm.ActiveCfg = Release|Any CPU + {DD5B6BAA-D41A-4A6E-9E7D-83060F394B10}.Release|wasm.Build.0 = Release|Any CPU + {DD5B6BAA-D41A-4A6E-9E7D-83060F394B10}.Release|x64.ActiveCfg = Release|x64 + {DD5B6BAA-D41A-4A6E-9E7D-83060F394B10}.Release|x64.Build.0 = Release|x64 + {DD5B6BAA-D41A-4A6E-9E7D-83060F394B10}.Release|x86.ActiveCfg = Release|x86 + {DD5B6BAA-D41A-4A6E-9E7D-83060F394B10}.Release|x86.Build.0 = Release|x86 {FBA029C3-B184-4457-AEEC-38D0C2523067}.Debug|Any CPU.ActiveCfg = Debug|x86 {FBA029C3-B184-4457-AEEC-38D0C2523067}.Debug|arm.ActiveCfg = Debug|arm {FBA029C3-B184-4457-AEEC-38D0C2523067}.Debug|arm.Build.0 = Debug|arm {FBA029C3-B184-4457-AEEC-38D0C2523067}.Debug|arm64.ActiveCfg = Debug|arm64 {FBA029C3-B184-4457-AEEC-38D0C2523067}.Debug|arm64.Build.0 = Debug|arm64 + {FBA029C3-B184-4457-AEEC-38D0C2523067}.Debug|armel.ActiveCfg = Debug|Any CPU + {FBA029C3-B184-4457-AEEC-38D0C2523067}.Debug|armel.Build.0 = Debug|Any CPU + {FBA029C3-B184-4457-AEEC-38D0C2523067}.Debug|wasm.ActiveCfg = Debug|Any CPU + {FBA029C3-B184-4457-AEEC-38D0C2523067}.Debug|wasm.Build.0 = Debug|Any CPU {FBA029C3-B184-4457-AEEC-38D0C2523067}.Debug|x64.ActiveCfg = Debug|x64 {FBA029C3-B184-4457-AEEC-38D0C2523067}.Debug|x64.Build.0 = Debug|x64 {FBA029C3-B184-4457-AEEC-38D0C2523067}.Debug|x86.ActiveCfg = Debug|x86 @@ -80,6 +96,10 @@ Global {FBA029C3-B184-4457-AEEC-38D0C2523067}.Release|arm.Build.0 = Release|arm {FBA029C3-B184-4457-AEEC-38D0C2523067}.Release|arm64.ActiveCfg = Release|arm64 {FBA029C3-B184-4457-AEEC-38D0C2523067}.Release|arm64.Build.0 = Release|arm64 + {FBA029C3-B184-4457-AEEC-38D0C2523067}.Release|armel.ActiveCfg = Release|Any CPU + {FBA029C3-B184-4457-AEEC-38D0C2523067}.Release|armel.Build.0 = Release|Any CPU + {FBA029C3-B184-4457-AEEC-38D0C2523067}.Release|wasm.ActiveCfg = Release|Any CPU + {FBA029C3-B184-4457-AEEC-38D0C2523067}.Release|wasm.Build.0 = Release|Any CPU {FBA029C3-B184-4457-AEEC-38D0C2523067}.Release|x64.ActiveCfg = Release|x64 {FBA029C3-B184-4457-AEEC-38D0C2523067}.Release|x64.Build.0 = Release|x64 {FBA029C3-B184-4457-AEEC-38D0C2523067}.Release|x86.ActiveCfg = Release|x86 @@ -89,6 +109,10 @@ Global {1A9DF196-43A9-44BB-B2C6-D62AA56B0E49}.Debug|arm.Build.0 = Debug|arm {1A9DF196-43A9-44BB-B2C6-D62AA56B0E49}.Debug|arm64.ActiveCfg = Debug|arm64 {1A9DF196-43A9-44BB-B2C6-D62AA56B0E49}.Debug|arm64.Build.0 = Debug|arm64 + {1A9DF196-43A9-44BB-B2C6-D62AA56B0E49}.Debug|armel.ActiveCfg = Debug|Any CPU + {1A9DF196-43A9-44BB-B2C6-D62AA56B0E49}.Debug|armel.Build.0 = Debug|Any CPU + {1A9DF196-43A9-44BB-B2C6-D62AA56B0E49}.Debug|wasm.ActiveCfg = Debug|Any CPU + {1A9DF196-43A9-44BB-B2C6-D62AA56B0E49}.Debug|wasm.Build.0 = Debug|Any CPU {1A9DF196-43A9-44BB-B2C6-D62AA56B0E49}.Debug|x64.ActiveCfg = Debug|x64 {1A9DF196-43A9-44BB-B2C6-D62AA56B0E49}.Debug|x64.Build.0 = Debug|x64 {1A9DF196-43A9-44BB-B2C6-D62AA56B0E49}.Debug|x86.ActiveCfg = Debug|x86 @@ -98,6 +122,10 @@ Global {1A9DF196-43A9-44BB-B2C6-D62AA56B0E49}.Release|arm.Build.0 = Release|arm {1A9DF196-43A9-44BB-B2C6-D62AA56B0E49}.Release|arm64.ActiveCfg = Release|arm64 {1A9DF196-43A9-44BB-B2C6-D62AA56B0E49}.Release|arm64.Build.0 = Release|arm64 + {1A9DF196-43A9-44BB-B2C6-D62AA56B0E49}.Release|armel.ActiveCfg = Release|Any CPU + {1A9DF196-43A9-44BB-B2C6-D62AA56B0E49}.Release|armel.Build.0 = Release|Any CPU + {1A9DF196-43A9-44BB-B2C6-D62AA56B0E49}.Release|wasm.ActiveCfg = Release|Any CPU + {1A9DF196-43A9-44BB-B2C6-D62AA56B0E49}.Release|wasm.Build.0 = Release|Any CPU {1A9DF196-43A9-44BB-B2C6-D62AA56B0E49}.Release|x64.ActiveCfg = Release|x64 {1A9DF196-43A9-44BB-B2C6-D62AA56B0E49}.Release|x64.Build.0 = Release|x64 {1A9DF196-43A9-44BB-B2C6-D62AA56B0E49}.Release|x86.ActiveCfg = Release|x86 @@ -107,6 +135,10 @@ Global {DAC23E9F-F826-4577-AE7A-0849FF83280C}.Debug|arm.Build.0 = Debug|arm {DAC23E9F-F826-4577-AE7A-0849FF83280C}.Debug|arm64.ActiveCfg = Debug|arm64 {DAC23E9F-F826-4577-AE7A-0849FF83280C}.Debug|arm64.Build.0 = Debug|arm64 + {DAC23E9F-F826-4577-AE7A-0849FF83280C}.Debug|armel.ActiveCfg = Debug|Any CPU + {DAC23E9F-F826-4577-AE7A-0849FF83280C}.Debug|armel.Build.0 = Debug|Any CPU + {DAC23E9F-F826-4577-AE7A-0849FF83280C}.Debug|wasm.ActiveCfg = Debug|Any CPU + {DAC23E9F-F826-4577-AE7A-0849FF83280C}.Debug|wasm.Build.0 = Debug|Any CPU {DAC23E9F-F826-4577-AE7A-0849FF83280C}.Debug|x64.ActiveCfg = Debug|x64 {DAC23E9F-F826-4577-AE7A-0849FF83280C}.Debug|x64.Build.0 = Debug|x64 {DAC23E9F-F826-4577-AE7A-0849FF83280C}.Debug|x86.ActiveCfg = Debug|x86 @@ -116,6 +148,10 @@ Global {DAC23E9F-F826-4577-AE7A-0849FF83280C}.Release|arm.Build.0 = Release|arm {DAC23E9F-F826-4577-AE7A-0849FF83280C}.Release|arm64.ActiveCfg = Release|arm64 {DAC23E9F-F826-4577-AE7A-0849FF83280C}.Release|arm64.Build.0 = Release|arm64 + {DAC23E9F-F826-4577-AE7A-0849FF83280C}.Release|armel.ActiveCfg = Release|Any CPU + {DAC23E9F-F826-4577-AE7A-0849FF83280C}.Release|armel.Build.0 = Release|Any CPU + {DAC23E9F-F826-4577-AE7A-0849FF83280C}.Release|wasm.ActiveCfg = Release|Any CPU + {DAC23E9F-F826-4577-AE7A-0849FF83280C}.Release|wasm.Build.0 = Release|Any CPU {DAC23E9F-F826-4577-AE7A-0849FF83280C}.Release|x64.ActiveCfg = Release|x64 {DAC23E9F-F826-4577-AE7A-0849FF83280C}.Release|x64.Build.0 = Release|x64 {DAC23E9F-F826-4577-AE7A-0849FF83280C}.Release|x86.ActiveCfg = Release|x86 @@ -125,6 +161,10 @@ Global {13BB3788-C3EB-4046-8105-A95F8AE49404}.Debug|arm.Build.0 = Debug|arm {13BB3788-C3EB-4046-8105-A95F8AE49404}.Debug|arm64.ActiveCfg = Debug|arm64 {13BB3788-C3EB-4046-8105-A95F8AE49404}.Debug|arm64.Build.0 = Debug|arm64 + {13BB3788-C3EB-4046-8105-A95F8AE49404}.Debug|armel.ActiveCfg = Debug|Any CPU + {13BB3788-C3EB-4046-8105-A95F8AE49404}.Debug|armel.Build.0 = Debug|Any CPU + {13BB3788-C3EB-4046-8105-A95F8AE49404}.Debug|wasm.ActiveCfg = Debug|Any CPU + {13BB3788-C3EB-4046-8105-A95F8AE49404}.Debug|wasm.Build.0 = Debug|Any CPU {13BB3788-C3EB-4046-8105-A95F8AE49404}.Debug|x64.ActiveCfg = Debug|x64 {13BB3788-C3EB-4046-8105-A95F8AE49404}.Debug|x64.Build.0 = Debug|x64 {13BB3788-C3EB-4046-8105-A95F8AE49404}.Debug|x86.ActiveCfg = Debug|x86 @@ -134,6 +174,10 @@ Global {13BB3788-C3EB-4046-8105-A95F8AE49404}.Release|arm.Build.0 = Release|arm {13BB3788-C3EB-4046-8105-A95F8AE49404}.Release|arm64.ActiveCfg = Release|arm64 {13BB3788-C3EB-4046-8105-A95F8AE49404}.Release|arm64.Build.0 = Release|arm64 + {13BB3788-C3EB-4046-8105-A95F8AE49404}.Release|armel.ActiveCfg = Release|Any CPU + {13BB3788-C3EB-4046-8105-A95F8AE49404}.Release|armel.Build.0 = Release|Any CPU + {13BB3788-C3EB-4046-8105-A95F8AE49404}.Release|wasm.ActiveCfg = Release|Any CPU + {13BB3788-C3EB-4046-8105-A95F8AE49404}.Release|wasm.Build.0 = Release|Any CPU {13BB3788-C3EB-4046-8105-A95F8AE49404}.Release|x64.ActiveCfg = Release|x64 {13BB3788-C3EB-4046-8105-A95F8AE49404}.Release|x64.Build.0 = Release|x64 {13BB3788-C3EB-4046-8105-A95F8AE49404}.Release|x86.ActiveCfg = Release|x86 @@ -143,6 +187,10 @@ Global {BE95C560-B508-4588-8907-F9FC5BC1A0CF}.Debug|arm.Build.0 = Debug|arm {BE95C560-B508-4588-8907-F9FC5BC1A0CF}.Debug|arm64.ActiveCfg = Debug|arm64 {BE95C560-B508-4588-8907-F9FC5BC1A0CF}.Debug|arm64.Build.0 = Debug|arm64 + {BE95C560-B508-4588-8907-F9FC5BC1A0CF}.Debug|armel.ActiveCfg = Debug|armel + {BE95C560-B508-4588-8907-F9FC5BC1A0CF}.Debug|armel.Build.0 = Debug|armel + {BE95C560-B508-4588-8907-F9FC5BC1A0CF}.Debug|wasm.ActiveCfg = Debug|wasm + {BE95C560-B508-4588-8907-F9FC5BC1A0CF}.Debug|wasm.Build.0 = Debug|wasm {BE95C560-B508-4588-8907-F9FC5BC1A0CF}.Debug|x64.ActiveCfg = Debug|x64 {BE95C560-B508-4588-8907-F9FC5BC1A0CF}.Debug|x86.ActiveCfg = Debug|x86 {BE95C560-B508-4588-8907-F9FC5BC1A0CF}.Debug|x86.Build.0 = Debug|x86 @@ -151,6 +199,10 @@ Global {BE95C560-B508-4588-8907-F9FC5BC1A0CF}.Release|arm.Build.0 = Release|arm {BE95C560-B508-4588-8907-F9FC5BC1A0CF}.Release|arm64.ActiveCfg = Release|arm64 {BE95C560-B508-4588-8907-F9FC5BC1A0CF}.Release|arm64.Build.0 = Release|arm64 + {BE95C560-B508-4588-8907-F9FC5BC1A0CF}.Release|armel.ActiveCfg = Release|armel + {BE95C560-B508-4588-8907-F9FC5BC1A0CF}.Release|armel.Build.0 = Release|armel + {BE95C560-B508-4588-8907-F9FC5BC1A0CF}.Release|wasm.ActiveCfg = Release|wasm + {BE95C560-B508-4588-8907-F9FC5BC1A0CF}.Release|wasm.Build.0 = Release|wasm {BE95C560-B508-4588-8907-F9FC5BC1A0CF}.Release|x64.ActiveCfg = Release|x64 {BE95C560-B508-4588-8907-F9FC5BC1A0CF}.Release|x64.Build.0 = Release|x64 {BE95C560-B508-4588-8907-F9FC5BC1A0CF}.Release|x86.ActiveCfg = Release|x86 @@ -161,6 +213,10 @@ Global {D66338D4-F9E4-4051-B302-232C6BFB6EF6}.Debug|arm.Build.0 = Debug|Any CPU {D66338D4-F9E4-4051-B302-232C6BFB6EF6}.Debug|arm64.ActiveCfg = Debug|Any CPU {D66338D4-F9E4-4051-B302-232C6BFB6EF6}.Debug|arm64.Build.0 = Debug|Any CPU + {D66338D4-F9E4-4051-B302-232C6BFB6EF6}.Debug|armel.ActiveCfg = Debug|Any CPU + {D66338D4-F9E4-4051-B302-232C6BFB6EF6}.Debug|armel.Build.0 = Debug|Any CPU + {D66338D4-F9E4-4051-B302-232C6BFB6EF6}.Debug|wasm.ActiveCfg = Debug|Any CPU + {D66338D4-F9E4-4051-B302-232C6BFB6EF6}.Debug|wasm.Build.0 = Debug|Any CPU {D66338D4-F9E4-4051-B302-232C6BFB6EF6}.Debug|x64.ActiveCfg = Debug|Any CPU {D66338D4-F9E4-4051-B302-232C6BFB6EF6}.Debug|x64.Build.0 = Debug|Any CPU {D66338D4-F9E4-4051-B302-232C6BFB6EF6}.Debug|x86.ActiveCfg = Debug|Any CPU @@ -171,6 +227,10 @@ Global {D66338D4-F9E4-4051-B302-232C6BFB6EF6}.Release|arm.Build.0 = Release|Any CPU {D66338D4-F9E4-4051-B302-232C6BFB6EF6}.Release|arm64.ActiveCfg = Release|Any CPU {D66338D4-F9E4-4051-B302-232C6BFB6EF6}.Release|arm64.Build.0 = Release|Any CPU + {D66338D4-F9E4-4051-B302-232C6BFB6EF6}.Release|armel.ActiveCfg = Release|Any CPU + {D66338D4-F9E4-4051-B302-232C6BFB6EF6}.Release|armel.Build.0 = Release|Any CPU + {D66338D4-F9E4-4051-B302-232C6BFB6EF6}.Release|wasm.ActiveCfg = Release|Any CPU + {D66338D4-F9E4-4051-B302-232C6BFB6EF6}.Release|wasm.Build.0 = Release|Any CPU {D66338D4-F9E4-4051-B302-232C6BFB6EF6}.Release|x64.ActiveCfg = Release|Any CPU {D66338D4-F9E4-4051-B302-232C6BFB6EF6}.Release|x64.Build.0 = Release|Any CPU {D66338D4-F9E4-4051-B302-232C6BFB6EF6}.Release|x86.ActiveCfg = Release|Any CPU @@ -181,6 +241,10 @@ Global {A965EA82-219D-48F7-AD51-BC030C16CC6F}.Debug|arm.Build.0 = Debug|Any CPU {A965EA82-219D-48F7-AD51-BC030C16CC6F}.Debug|arm64.ActiveCfg = Debug|Any CPU {A965EA82-219D-48F7-AD51-BC030C16CC6F}.Debug|arm64.Build.0 = Debug|Any CPU + {A965EA82-219D-48F7-AD51-BC030C16CC6F}.Debug|armel.ActiveCfg = Debug|Any CPU + {A965EA82-219D-48F7-AD51-BC030C16CC6F}.Debug|armel.Build.0 = Debug|Any CPU + {A965EA82-219D-48F7-AD51-BC030C16CC6F}.Debug|wasm.ActiveCfg = Debug|Any CPU + {A965EA82-219D-48F7-AD51-BC030C16CC6F}.Debug|wasm.Build.0 = Debug|Any CPU {A965EA82-219D-48F7-AD51-BC030C16CC6F}.Debug|x64.ActiveCfg = Debug|Any CPU {A965EA82-219D-48F7-AD51-BC030C16CC6F}.Debug|x64.Build.0 = Debug|Any CPU {A965EA82-219D-48F7-AD51-BC030C16CC6F}.Debug|x86.ActiveCfg = Debug|Any CPU @@ -191,6 +255,10 @@ Global {A965EA82-219D-48F7-AD51-BC030C16CC6F}.Release|arm.Build.0 = Release|Any CPU {A965EA82-219D-48F7-AD51-BC030C16CC6F}.Release|arm64.ActiveCfg = Release|Any CPU {A965EA82-219D-48F7-AD51-BC030C16CC6F}.Release|arm64.Build.0 = Release|Any CPU + {A965EA82-219D-48F7-AD51-BC030C16CC6F}.Release|armel.ActiveCfg = Release|Any CPU + {A965EA82-219D-48F7-AD51-BC030C16CC6F}.Release|armel.Build.0 = Release|Any CPU + {A965EA82-219D-48F7-AD51-BC030C16CC6F}.Release|wasm.ActiveCfg = Release|Any CPU + {A965EA82-219D-48F7-AD51-BC030C16CC6F}.Release|wasm.Build.0 = Release|Any CPU {A965EA82-219D-48F7-AD51-BC030C16CC6F}.Release|x64.ActiveCfg = Release|Any CPU {A965EA82-219D-48F7-AD51-BC030C16CC6F}.Release|x64.Build.0 = Release|Any CPU {A965EA82-219D-48F7-AD51-BC030C16CC6F}.Release|x86.ActiveCfg = Release|Any CPU @@ -201,6 +269,10 @@ Global {971AE7E7-08C6-48B4-902A-63851E6DAC66}.Debug|arm.Build.0 = Debug|Any CPU {971AE7E7-08C6-48B4-902A-63851E6DAC66}.Debug|arm64.ActiveCfg = Debug|Any CPU {971AE7E7-08C6-48B4-902A-63851E6DAC66}.Debug|arm64.Build.0 = Debug|Any CPU + {971AE7E7-08C6-48B4-902A-63851E6DAC66}.Debug|armel.ActiveCfg = Debug|Any CPU + {971AE7E7-08C6-48B4-902A-63851E6DAC66}.Debug|armel.Build.0 = Debug|Any CPU + {971AE7E7-08C6-48B4-902A-63851E6DAC66}.Debug|wasm.ActiveCfg = Debug|Any CPU + {971AE7E7-08C6-48B4-902A-63851E6DAC66}.Debug|wasm.Build.0 = Debug|Any CPU {971AE7E7-08C6-48B4-902A-63851E6DAC66}.Debug|x64.ActiveCfg = Debug|Any CPU {971AE7E7-08C6-48B4-902A-63851E6DAC66}.Debug|x64.Build.0 = Debug|Any CPU {971AE7E7-08C6-48B4-902A-63851E6DAC66}.Debug|x86.ActiveCfg = Debug|Any CPU @@ -211,6 +283,10 @@ Global {971AE7E7-08C6-48B4-902A-63851E6DAC66}.Release|arm.Build.0 = Release|Any CPU {971AE7E7-08C6-48B4-902A-63851E6DAC66}.Release|arm64.ActiveCfg = Release|Any CPU {971AE7E7-08C6-48B4-902A-63851E6DAC66}.Release|arm64.Build.0 = Release|Any CPU + {971AE7E7-08C6-48B4-902A-63851E6DAC66}.Release|armel.ActiveCfg = Release|Any CPU + {971AE7E7-08C6-48B4-902A-63851E6DAC66}.Release|armel.Build.0 = Release|Any CPU + {971AE7E7-08C6-48B4-902A-63851E6DAC66}.Release|wasm.ActiveCfg = Release|Any CPU + {971AE7E7-08C6-48B4-902A-63851E6DAC66}.Release|wasm.Build.0 = Release|Any CPU {971AE7E7-08C6-48B4-902A-63851E6DAC66}.Release|x64.ActiveCfg = Release|Any CPU {971AE7E7-08C6-48B4-902A-63851E6DAC66}.Release|x64.Build.0 = Release|Any CPU {971AE7E7-08C6-48B4-902A-63851E6DAC66}.Release|x86.ActiveCfg = Release|Any CPU @@ -221,6 +297,10 @@ Global {5D796936-CCC1-4E9D-B1A9-36A5ABA9B499}.Debug|arm.Build.0 = Debug|arm {5D796936-CCC1-4E9D-B1A9-36A5ABA9B499}.Debug|arm64.ActiveCfg = Debug|arm64 {5D796936-CCC1-4E9D-B1A9-36A5ABA9B499}.Debug|arm64.Build.0 = Debug|arm64 + {5D796936-CCC1-4E9D-B1A9-36A5ABA9B499}.Debug|armel.ActiveCfg = Debug|Any CPU + {5D796936-CCC1-4E9D-B1A9-36A5ABA9B499}.Debug|armel.Build.0 = Debug|Any CPU + {5D796936-CCC1-4E9D-B1A9-36A5ABA9B499}.Debug|wasm.ActiveCfg = Debug|Any CPU + {5D796936-CCC1-4E9D-B1A9-36A5ABA9B499}.Debug|wasm.Build.0 = Debug|Any CPU {5D796936-CCC1-4E9D-B1A9-36A5ABA9B499}.Debug|x64.ActiveCfg = Debug|x64 {5D796936-CCC1-4E9D-B1A9-36A5ABA9B499}.Debug|x64.Build.0 = Debug|x64 {5D796936-CCC1-4E9D-B1A9-36A5ABA9B499}.Debug|x86.ActiveCfg = Debug|x86 @@ -231,6 +311,10 @@ Global {5D796936-CCC1-4E9D-B1A9-36A5ABA9B499}.Release|arm.Build.0 = Release|arm {5D796936-CCC1-4E9D-B1A9-36A5ABA9B499}.Release|arm64.ActiveCfg = Release|arm64 {5D796936-CCC1-4E9D-B1A9-36A5ABA9B499}.Release|arm64.Build.0 = Release|arm64 + {5D796936-CCC1-4E9D-B1A9-36A5ABA9B499}.Release|armel.ActiveCfg = Release|Any CPU + {5D796936-CCC1-4E9D-B1A9-36A5ABA9B499}.Release|armel.Build.0 = Release|Any CPU + {5D796936-CCC1-4E9D-B1A9-36A5ABA9B499}.Release|wasm.ActiveCfg = Release|Any CPU + {5D796936-CCC1-4E9D-B1A9-36A5ABA9B499}.Release|wasm.Build.0 = Release|Any CPU {5D796936-CCC1-4E9D-B1A9-36A5ABA9B499}.Release|x64.ActiveCfg = Release|x64 {5D796936-CCC1-4E9D-B1A9-36A5ABA9B499}.Release|x64.Build.0 = Release|x64 {5D796936-CCC1-4E9D-B1A9-36A5ABA9B499}.Release|x86.ActiveCfg = Release|x86 @@ -241,6 +325,10 @@ Global {CE9781B1-0028-4039-A48C-8193F0D28467}.Debug|arm.Build.0 = Debug|Any CPU {CE9781B1-0028-4039-A48C-8193F0D28467}.Debug|arm64.ActiveCfg = Debug|Any CPU {CE9781B1-0028-4039-A48C-8193F0D28467}.Debug|arm64.Build.0 = Debug|Any CPU + {CE9781B1-0028-4039-A48C-8193F0D28467}.Debug|armel.ActiveCfg = Debug|Any CPU + {CE9781B1-0028-4039-A48C-8193F0D28467}.Debug|armel.Build.0 = Debug|Any CPU + {CE9781B1-0028-4039-A48C-8193F0D28467}.Debug|wasm.ActiveCfg = Debug|Any CPU + {CE9781B1-0028-4039-A48C-8193F0D28467}.Debug|wasm.Build.0 = Debug|Any CPU {CE9781B1-0028-4039-A48C-8193F0D28467}.Debug|x64.ActiveCfg = Debug|x64 {CE9781B1-0028-4039-A48C-8193F0D28467}.Debug|x64.Build.0 = Debug|x64 {CE9781B1-0028-4039-A48C-8193F0D28467}.Debug|x86.ActiveCfg = Debug|Any CPU @@ -251,6 +339,10 @@ Global {CE9781B1-0028-4039-A48C-8193F0D28467}.Release|arm.Build.0 = Release|Any CPU {CE9781B1-0028-4039-A48C-8193F0D28467}.Release|arm64.ActiveCfg = Release|Any CPU {CE9781B1-0028-4039-A48C-8193F0D28467}.Release|arm64.Build.0 = Release|Any CPU + {CE9781B1-0028-4039-A48C-8193F0D28467}.Release|armel.ActiveCfg = Release|Any CPU + {CE9781B1-0028-4039-A48C-8193F0D28467}.Release|armel.Build.0 = Release|Any CPU + {CE9781B1-0028-4039-A48C-8193F0D28467}.Release|wasm.ActiveCfg = Release|Any CPU + {CE9781B1-0028-4039-A48C-8193F0D28467}.Release|wasm.Build.0 = Release|Any CPU {CE9781B1-0028-4039-A48C-8193F0D28467}.Release|x64.ActiveCfg = Release|x64 {CE9781B1-0028-4039-A48C-8193F0D28467}.Release|x64.Build.0 = Release|x64 {CE9781B1-0028-4039-A48C-8193F0D28467}.Release|x86.ActiveCfg = Release|Any CPU @@ -261,6 +353,10 @@ Global {44DE7F7B-AD73-40EA-87CC-554F2F57C38A}.Debug|arm.Build.0 = Debug|arm {44DE7F7B-AD73-40EA-87CC-554F2F57C38A}.Debug|arm64.ActiveCfg = Debug|arm64 {44DE7F7B-AD73-40EA-87CC-554F2F57C38A}.Debug|arm64.Build.0 = Debug|arm64 + {44DE7F7B-AD73-40EA-87CC-554F2F57C38A}.Debug|armel.ActiveCfg = Debug|Any CPU + {44DE7F7B-AD73-40EA-87CC-554F2F57C38A}.Debug|armel.Build.0 = Debug|Any CPU + {44DE7F7B-AD73-40EA-87CC-554F2F57C38A}.Debug|wasm.ActiveCfg = Debug|Any CPU + {44DE7F7B-AD73-40EA-87CC-554F2F57C38A}.Debug|wasm.Build.0 = Debug|Any CPU {44DE7F7B-AD73-40EA-87CC-554F2F57C38A}.Debug|x64.ActiveCfg = Debug|x64 {44DE7F7B-AD73-40EA-87CC-554F2F57C38A}.Debug|x64.Build.0 = Debug|x64 {44DE7F7B-AD73-40EA-87CC-554F2F57C38A}.Debug|x86.ActiveCfg = Debug|x86 @@ -271,6 +367,10 @@ Global {44DE7F7B-AD73-40EA-87CC-554F2F57C38A}.Release|arm.Build.0 = Release|arm {44DE7F7B-AD73-40EA-87CC-554F2F57C38A}.Release|arm64.ActiveCfg = Release|arm64 {44DE7F7B-AD73-40EA-87CC-554F2F57C38A}.Release|arm64.Build.0 = Release|arm64 + {44DE7F7B-AD73-40EA-87CC-554F2F57C38A}.Release|armel.ActiveCfg = Release|Any CPU + {44DE7F7B-AD73-40EA-87CC-554F2F57C38A}.Release|armel.Build.0 = Release|Any CPU + {44DE7F7B-AD73-40EA-87CC-554F2F57C38A}.Release|wasm.ActiveCfg = Release|Any CPU + {44DE7F7B-AD73-40EA-87CC-554F2F57C38A}.Release|wasm.Build.0 = Release|Any CPU {44DE7F7B-AD73-40EA-87CC-554F2F57C38A}.Release|x64.ActiveCfg = Release|x64 {44DE7F7B-AD73-40EA-87CC-554F2F57C38A}.Release|x64.Build.0 = Release|x64 {44DE7F7B-AD73-40EA-87CC-554F2F57C38A}.Release|x86.ActiveCfg = Release|x86 diff --git a/external/corert/src/ILCompiler/ObjectWriter/ObjectWriter.depproj b/external/corert/src/ILCompiler/ObjectWriter/ObjectWriter.depproj index 95fed28328..d1f46b4ae0 100644 --- a/external/corert/src/ILCompiler/ObjectWriter/ObjectWriter.depproj +++ b/external/corert/src/ILCompiler/ObjectWriter/ObjectWriter.depproj @@ -8,7 +8,9 @@ .NETCoreApp,Version=v2.0 netcoreapp2.0 $(NuPkgRid) - ubuntu.14.04-x64 + win7-x64 + osx.10.10-x64 + ubuntu.14.04-x64 true diff --git a/external/corert/src/ILCompiler/RyuJIT/RyuJIT.depproj b/external/corert/src/ILCompiler/RyuJIT/RyuJIT.depproj index 5e543ee5b9..1eb94f741f 100644 --- a/external/corert/src/ILCompiler/RyuJIT/RyuJIT.depproj +++ b/external/corert/src/ILCompiler/RyuJIT/RyuJIT.depproj @@ -8,9 +8,6 @@ .NETCoreApp,Version=v2.0 netcoreapp2.0 $(NuPkgRid) - win-x64 - osx-x64 - linux-x64 true diff --git a/external/corert/src/ILCompiler/repro/repro.csproj b/external/corert/src/ILCompiler/repro/repro.csproj index 15ed06b830..5e3e753125 100644 --- a/external/corert/src/ILCompiler/repro/repro.csproj +++ b/external/corert/src/ILCompiler/repro/repro.csproj @@ -7,6 +7,7 @@ true true false + false diff --git a/external/corert/src/ILCompiler/reproNative/reproNative.vcxproj b/external/corert/src/ILCompiler/reproNative/reproNative.vcxproj index 654438da27..9d9f6eed2a 100644 --- a/external/corert/src/ILCompiler/reproNative/reproNative.vcxproj +++ b/external/corert/src/ILCompiler/reproNative/reproNative.vcxproj @@ -13,7 +13,7 @@ {ECB5D162-A31B-45FF-87C7-2E92BD445F5A} Win32Proj reproNative - 10.0.14393.0 + 10.0.16299.0 @@ -104,4 +104,4 @@ - + \ No newline at end of file diff --git a/external/corert/src/ILVerification/README.md b/external/corert/src/ILVerification/README.md new file mode 100644 index 0000000000..6056ba59ae --- /dev/null +++ b/external/corert/src/ILVerification/README.md @@ -0,0 +1,3 @@ +# ILVerification + +The ILVerification library is part of the ILVerify project. See details under [src/ILVerify/](https://github.com/dotnet/corert/tree/master/src/ILVerify). \ No newline at end of file diff --git a/external/corert/src/ILVerification/StrongNameKeys/ILVerify.snk b/external/corert/src/ILVerification/StrongNameKeys/ILVerify.snk new file mode 100644 index 0000000000..e5534f1a9e Binary files /dev/null and b/external/corert/src/ILVerification/StrongNameKeys/ILVerify.snk differ diff --git a/external/corert/src/ILVerify/src/AccessVerificationHelpers.cs b/external/corert/src/ILVerification/src/AccessVerificationHelpers.cs similarity index 99% rename from external/corert/src/ILVerify/src/AccessVerificationHelpers.cs rename to external/corert/src/ILVerification/src/AccessVerificationHelpers.cs index 8966432731..b27affb071 100644 --- a/external/corert/src/ILVerify/src/AccessVerificationHelpers.cs +++ b/external/corert/src/ILVerification/src/AccessVerificationHelpers.cs @@ -149,7 +149,7 @@ namespace ILVerify break; case MethodAttributes.Family: case MethodAttributes.FamANDAssem: - // Assembly acces was already checked earlier, so only need to check family access + // Assembly access was already checked earlier, so only need to check family access if (CanAccessFamily(currentType, targetTypeDef, instance)) return true; break; diff --git a/external/corert/src/ILVerification/src/AssemblyInfo.cs b/external/corert/src/ILVerification/src/AssemblyInfo.cs new file mode 100644 index 0000000000..cd0ba8baaa --- /dev/null +++ b/external/corert/src/ILVerification/src/AssemblyInfo.cs @@ -0,0 +1,4 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("ILVerification.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010015c01ae1f50e8cc09ba9eac9147cf8fd9fce2cfe9f8dce4f7301c4132ca9fb50ce8cbf1df4dc18dd4d210e4345c744ecb3365ed327efdbc52603faa5e21daa11234c8c4a73e51f03bf192544581ebe107adee3a34928e39d04e524a9ce729d5090bfd7dad9d10c722c0def9ccc08ff0a03790e48bcd1f9b6c476063e1966a1c4")] +[assembly: InternalsVisibleTo("ILVerify, PublicKey=0024000004800000940000000602000000240000525341310004000001000100314e026e409db99b50d61628136c49095e67f782a3032832cfe1e61ba2af8264d2cf7d9228bdf611c1027f61b0ca4c87ee1c248cd58241a695520ba78e76d1c672c2b597cfa0ab4526dcae2b5b6f36936c126e59ada3500d656f3424826d0dab452ea407039d2846cf0e4820905eee537fe904a86097b5b2f3aaae000fc08fc3")] diff --git a/external/corert/src/ILVerify/src/ILImporter.StackValue.cs b/external/corert/src/ILVerification/src/ILImporter.StackValue.cs similarity index 100% rename from external/corert/src/ILVerify/src/ILImporter.StackValue.cs rename to external/corert/src/ILVerification/src/ILImporter.StackValue.cs diff --git a/external/corert/src/ILVerify/src/ILImporter.Verify.cs b/external/corert/src/ILVerification/src/ILImporter.Verify.cs similarity index 99% rename from external/corert/src/ILVerify/src/ILImporter.Verify.cs rename to external/corert/src/ILVerification/src/ILImporter.Verify.cs index 5dde3d6f39..cb168b88ac 100644 --- a/external/corert/src/ILVerify/src/ILImporter.Verify.cs +++ b/external/corert/src/ILVerification/src/ILImporter.Verify.cs @@ -26,13 +26,11 @@ namespace Internal.IL } } - struct VerificationErrorArgs + class VerifierException : Exception { - public VerifierError Code; - public int Offset; - public int Token; - public string Found; - public string Expected; + internal VerifierException(string message) : base(message) + { + } } partial class ILImporter diff --git a/external/corert/src/ILVerification/src/ILVerification.csproj b/external/corert/src/ILVerification/src/ILVerification.csproj new file mode 100644 index 0000000000..efa6e53495 --- /dev/null +++ b/external/corert/src/ILVerification/src/ILVerification.csproj @@ -0,0 +1,302 @@ + + + + Library + AnyCPU + false + true + false + netstandard1.3 + + ..\StrongNameKeys\ILVerify.snk + + + + + + + + + + + + + + + + + + + TypeSystem\CodeGen\MethodDesc.CodeGen.cs + + + Utilities\AlignmentHelper.cs + + + TypeSystem\Common\CastingHelper.cs + + + TypeSystem\Common\FunctionPointerType.cs + + + TypeSystem\Common\IAssemblyDesc.cs + + + TypeSystem\Common\Instantiation.cs + + + TypeSystem\Common\ModuleDesc.cs + + + TypeSystem\Common\TypeSystemEntity.cs + + + TypeSystem\Common\TypeSystemException.cs + + + Utilities\CustomAttributeTypeNameParser.cs + + + Utilities\LockFreeReaderHashtable.cs + + + TypeSystem\Common\ArrayType.cs + + + TypeSystem\Common\ArrayOfTRuntimeInterfacesAlgorithm.cs + + + TypeSystem\Common\BaseTypeRuntimeInterfacesAlgorithm.cs + + + TypeSystem\Common\ByRefType.cs + + + TypeSystem\Common\GenericParameterDesc.cs + + + TypeSystem\Common\ExceptionStringID.cs + + + TypeSystem\Common\FieldForInstantiatedType.cs + + + TypeSystem\Common\FieldDesc.cs + + + TypeSystem\Common\FieldDesc.FieldLayout.cs + + + TypeSystem\Common\FieldLayoutAlgorithm.cs + + + TypeSystem\Common\InstantiatedMethod.cs + + + TypeSystem\Common\InstantiatedType.cs + + + TypeSystem\Common\InstantiatedType.Interfaces.cs + + + TypeSystem\Common\InstantiatedType.MethodImpls.cs + + + TypeSystem\Common\LayoutInt.cs + + + TypeSystem\Common\MetadataType.cs + + + TypeSystem\Common\MetadataType.Interfaces.cs + + + TypeSystem\Common\MetadataType.MethodImpls.cs + + + TypeSystem\Common\MetadataFieldLayoutAlgorithm.cs + + + TypeSystem\Common\MetadataRuntimeInterfacesAlgorithm.cs + + + TypeSystem\Common\MetadataTypeSystemContext.cs + + + TypeSystem\Common\MethodForInstantiatedType.cs + + + TypeSystem\Common\ParameterizedType.cs + + + TypeSystem\Common\PointerType.cs + + + TypeSystem\Common\PropertySignature.cs + + + TypeSystem\Common\SignatureVariable.cs + + + TypeSystem\Common\TargetDetails.cs + + + TypeSystem\Common\ThreadSafeFlags.cs + + + TypeSystem\Common\TypeFlags.cs + + + TypeSystem\Common\TypeHashingAlgorithms.cs + + + TypeSystem\Common\TypeSystemContext.cs + + + TypeSystem\Common\TypeSystemHelpers.cs + + + Utilities\TypeNameFormatter.cs + + + TypeSystem\Common\WellKnownType.cs + + + TypeSystem\Common\VirtualMethodAlgorithm.cs + + + TypeSystem\Common\MethodDesc.cs + + + TypeSystem\Common\StandardVirtualMethodAlgorithm.cs + + + TypeSystem\Common\TypeDesc.cs + + + TypeSystem\Common\TypeDesc.Interfaces.cs + + + TypeSystem\Common\DefType.cs + + + TypeSystem\Common\DefType.FieldLayout.cs + + + TypeSystem\Common\RuntimeInterfacesAlgorithm.cs + + + TypeSystem\Common\ThrowHelper.Common.cs + + + TypeSystem\Common\ThrowHelper.cs + + + TypeSystem\Common\Utilities\ExceptionTypeNameFormatter.cs + + + TypeSystem\Common\Utilities\ExceptionTypeNameFormatter.Metadata.cs + + + Ecma\CustomAttributeTypeProvider.cs + + + Ecma\EcmaAssembly.cs + + + Ecma\EcmaField.cs + + + Ecma\EcmaGenericParameter.cs + + + Ecma\EcmaMethod.cs + + + Ecma\EcmaModule.cs + + + Ecma\EcmaSignatureParser.cs + + + Ecma\EcmaType.cs + + + Ecma\EcmaType.MethodImpls.cs + + + Ecma\EcmaType.Interfaces.cs + + + Ecma\MetadataExtensions.cs + + + Ecma\IMetadataStringDecoderProvider.cs + + + Ecma\CachingMetadataStringDecoder.cs + + + Ecma\PrimitiveTypeProvider.cs + + + IL\EcmaMethodIL.cs + + + IL\MethodIL.cs + + + IL\MethodILDebugView.cs + + + IL\ILDisassembler.cs + + + IL\InstantiatedMethodIL.cs + + + IL\ILOpcode.cs + + + IL\ILImporter.cs + + + Interop\InstantiatedType.Interop.cs + + + Interop\MetadataType.Interop.cs + + + Interop\MethodDesc.Interop.cs + + + TypeSystem\Interop\MarshalAsDescriptor.cs + + + Utilities\ArrayBuilder.cs + + + TypeSystem\Common\LocalVariableDefinition.cs + + + Common\System\FormattingHelpers.cs + + + TypeSystem\Common\TypeSystemConstraintsHelpers.cs + + + + + System\NotImplemented.cs + + + + + + + + + + + + diff --git a/external/corert/src/ILVerification/src/ILVerifyTypeSystemContext.cs b/external/corert/src/ILVerification/src/ILVerifyTypeSystemContext.cs new file mode 100644 index 0000000000..528dc6a90c --- /dev/null +++ b/external/corert/src/ILVerification/src/ILVerifyTypeSystemContext.cs @@ -0,0 +1,88 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Metadata; +using System.Reflection.PortableExecutable; +using Internal.IL; +using Internal.TypeSystem; +using Internal.TypeSystem.Ecma; + +namespace ILVerify +{ + class ILVerifyTypeSystemContext : MetadataTypeSystemContext + { + internal readonly IResolver _resolver; + + private RuntimeInterfacesAlgorithm _arrayOfTRuntimeInterfacesAlgorithm; + private MetadataRuntimeInterfacesAlgorithm _metadataRuntimeInterfacesAlgorithm = new MetadataRuntimeInterfacesAlgorithm(); + + private readonly Dictionary _modulesCache = new Dictionary(); + + public ILVerifyTypeSystemContext(IResolver resolver) + { + _resolver = resolver; + } + + public override ModuleDesc ResolveAssembly(AssemblyName name, bool throwIfNotFound = true) + { + PEReader peReader = _resolver.Resolve(name); + if (peReader == null && throwIfNotFound) + { + throw new VerifierException("Assembly or module not found: " + name.Name); + } + + var module = GetModule(peReader); + VerifyModuleName(name, module); + return module; + } + + private static void VerifyModuleName(AssemblyName name, EcmaModule module) + { + MetadataReader metadataReader = module.MetadataReader; + StringHandle nameHandle = metadataReader.IsAssembly + ? metadataReader.GetAssemblyDefinition().Name + : metadataReader.GetModuleDefinition().Name; + + string actualSimpleName = metadataReader.GetString(nameHandle); + if (!actualSimpleName.Equals(name.Name, StringComparison.OrdinalIgnoreCase)) + { + throw new VerifierException($"Actual PE name '{actualSimpleName}' does not match provided name '{name}'"); + } + } + + protected override RuntimeInterfacesAlgorithm GetRuntimeInterfacesAlgorithmForNonPointerArrayType(ArrayType type) + { + if (_arrayOfTRuntimeInterfacesAlgorithm == null) + { + _arrayOfTRuntimeInterfacesAlgorithm = new SimpleArrayOfTRuntimeInterfacesAlgorithm(SystemModule); + } + return _arrayOfTRuntimeInterfacesAlgorithm; + } + + protected override RuntimeInterfacesAlgorithm GetRuntimeInterfacesAlgorithmForDefType(DefType type) + { + return _metadataRuntimeInterfacesAlgorithm; + } + + internal EcmaModule GetModule(PEReader peReader) + { + if (peReader == null) + { + return null; + } + + if (_modulesCache.TryGetValue(peReader, out EcmaModule existingModule)) + { + return existingModule; + } + + EcmaModule module = EcmaModule.Create(this, peReader); + _modulesCache.Add(peReader, module); + return module; + } + } +} diff --git a/external/corert/src/ILVerification/src/IResolver.cs b/external/corert/src/ILVerification/src/IResolver.cs new file mode 100644 index 0000000000..f3706cf3b9 --- /dev/null +++ b/external/corert/src/ILVerification/src/IResolver.cs @@ -0,0 +1,47 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.PortableExecutable; + +namespace ILVerify +{ + public interface IResolver + { + /// + /// This method should return the same instance when queried multiple times. + /// + PEReader Resolve(AssemblyName name); + } + + /// + /// Provides caching logic for implementations of IResolver + /// + public abstract class ResolverBase : IResolver + { + private readonly Dictionary _resolverCache = new Dictionary(); + + public PEReader Resolve(AssemblyName name) + { + // Note: we use simple names instead of full names to resolve, because we can't get a full name from an assembly without reading it + string simpleName = name.Name; + if (_resolverCache.TryGetValue(simpleName, out PEReader peReader)) + { + return peReader; + } + + PEReader result = ResolveCore(name); + if (result != null) + { + _resolverCache.Add(simpleName, result); + return result; + } + + return null; + } + + protected abstract PEReader ResolveCore(AssemblyName name); + } +} diff --git a/external/corert/src/ILVerify/src/InstantiatedGenericParameter.cs b/external/corert/src/ILVerification/src/InstantiatedGenericParameter.cs similarity index 100% rename from external/corert/src/ILVerify/src/InstantiatedGenericParameter.cs rename to external/corert/src/ILVerification/src/InstantiatedGenericParameter.cs diff --git a/external/corert/src/ILVerify/src/Resources/Strings.resx b/external/corert/src/ILVerification/src/Resources/Strings.resx similarity index 100% rename from external/corert/src/ILVerify/src/Resources/Strings.resx rename to external/corert/src/ILVerification/src/Resources/Strings.resx diff --git a/external/corert/src/ILVerify/src/SimpleArrayOfTRuntimeInterfacesAlgorithm.cs b/external/corert/src/ILVerification/src/SimpleArrayOfTRuntimeInterfacesAlgorithm.cs similarity index 100% rename from external/corert/src/ILVerify/src/SimpleArrayOfTRuntimeInterfacesAlgorithm.cs rename to external/corert/src/ILVerification/src/SimpleArrayOfTRuntimeInterfacesAlgorithm.cs diff --git a/external/corert/src/ILVerify/src/TypeSystemHelpers.cs b/external/corert/src/ILVerification/src/TypeSystemHelpers.cs similarity index 100% rename from external/corert/src/ILVerify/src/TypeSystemHelpers.cs rename to external/corert/src/ILVerification/src/TypeSystemHelpers.cs diff --git a/external/corert/src/ILVerification/src/VerificationResult.cs b/external/corert/src/ILVerification/src/VerificationResult.cs new file mode 100644 index 0000000000..e642088321 --- /dev/null +++ b/external/corert/src/ILVerification/src/VerificationResult.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Reflection.Metadata; + +namespace ILVerify +{ + public class VerificationResult + { + public MethodDefinitionHandle Method { get; internal set; } + public VerificationErrorArgs Error { get; internal set; } + public string Message { get; internal set; } + } + + public struct VerificationErrorArgs + { + public VerifierError Code { get; internal set; } + public int Offset { get; internal set; } + public int Token { get; internal set; } + public string Found { get; internal set; } + public string Expected { get; internal set; } + } +} diff --git a/external/corert/src/ILVerification/src/Verifier.cs b/external/corert/src/ILVerification/src/Verifier.cs new file mode 100644 index 0000000000..9341ef3958 --- /dev/null +++ b/external/corert/src/ILVerification/src/Verifier.cs @@ -0,0 +1,234 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Reflection; +using System.Reflection.Metadata; +using System.Reflection.PortableExecutable; +using System.Resources; +using Internal.IL; +using Internal.TypeSystem; +using Internal.TypeSystem.Ecma; + +namespace ILVerify +{ + public class Verifier + { + private Lazy _stringResourceManager = + new Lazy(() => new ResourceManager("FxResources.ILVerification.SR", typeof(Verifier).GetTypeInfo().Assembly)); + + private ILVerifyTypeSystemContext _typeSystemContext; + + public Verifier(IResolver resolver) + { + _typeSystemContext = new ILVerifyTypeSystemContext(resolver); + } + + internal Verifier(ILVerifyTypeSystemContext context) + { + _typeSystemContext = context; + } + + public void SetSystemModuleName(AssemblyName name) + { + _typeSystemContext.SetSystemModule(_typeSystemContext.GetModule(_typeSystemContext._resolver.Resolve(name))); + } + + internal EcmaModule GetModule(PEReader peReader) + { + return _typeSystemContext.GetModule(peReader); + } + + public IEnumerable Verify(PEReader peReader) + { + if (peReader == null) + { + throw new ArgumentNullException(nameof(peReader)); + } + + if (_typeSystemContext.SystemModule == null) + { + ThrowMissingSystemModule(); + } + + IEnumerable results; + try + { + EcmaModule module = GetModule(peReader); + results = VerifyMethods(module, module.MetadataReader.MethodDefinitions); + } + catch (VerifierException e) + { + results = new[] { new VerificationResult() { Message = e.Message } }; + } + + foreach (var result in results) + { + yield return result; + } + } + + public IEnumerable Verify(PEReader peReader, TypeDefinitionHandle typeHandle) + { + if (peReader == null) + { + throw new ArgumentNullException(nameof(peReader)); + } + + if (typeHandle.IsNil) + { + throw new ArgumentNullException(nameof(typeHandle)); + } + + if (_typeSystemContext.SystemModule == null) + { + ThrowMissingSystemModule(); + } + + IEnumerable results; + try + { + EcmaModule module = GetModule(peReader); + TypeDefinition typeDef = peReader.GetMetadataReader().GetTypeDefinition(typeHandle); + results = VerifyMethods(module, typeDef.GetMethods()); + } + catch (VerifierException e) + { + results = new[] { new VerificationResult() { Message = e.Message } }; + } + + foreach (var result in results) + { + yield return result; + } + } + + public IEnumerable Verify(PEReader peReader, MethodDefinitionHandle methodHandle) + { + if (peReader == null) + { + throw new ArgumentNullException(nameof(peReader)); + } + + if (methodHandle.IsNil) + { + throw new ArgumentNullException(nameof(methodHandle)); + } + + if (_typeSystemContext.SystemModule == null) + { + ThrowMissingSystemModule(); + } + + IEnumerable results; + try + { + EcmaModule module = GetModule(peReader); + results = VerifyMethods(module, new[] { methodHandle }); + } + catch (VerifierException e) + { + results = new[] { new VerificationResult() { Message = e.Message } }; + } + + foreach (var result in results) + { + yield return result; + } + } + + private IEnumerable VerifyMethods(EcmaModule module, IEnumerable methodHandles) + { + foreach (var methodHandle in methodHandles) + { + var method = (EcmaMethod)module.GetMethod(methodHandle); + var methodIL = EcmaMethodIL.Create(method); + + if (methodIL != null) + { + var results = VerifyMethod(module, methodIL, methodHandle); + foreach (var result in results) + { + yield return result; + } + } + } + } + + private IEnumerable VerifyMethod(EcmaModule module, MethodIL methodIL, MethodDefinitionHandle methodHandle) + { + var builder = new ArrayBuilder(); + MethodDesc method = methodIL.OwningMethod; + + try + { + var importer = new ILImporter(method, methodIL); + + importer.ReportVerificationError = (args) => + { + var codeResource = _stringResourceManager.Value.GetString(args.Code.ToString(), CultureInfo.InvariantCulture); + + builder.Add(new VerificationResult() + { + Method = methodHandle, + Error = args, + Message = string.IsNullOrEmpty(codeResource) ? args.Code.ToString() : codeResource + }); + }; + + importer.Verify(); + } + catch (VerificationException) + { + // a result was reported already (before aborting) + } + catch (BadImageFormatException) + { + builder.Add(new VerificationResult() + { + Method = methodHandle, + Message = "Unable to resolve token" + }); + } + catch (NotImplementedException e) + { + reportException(e); + } + catch (InvalidProgramException e) + { + reportException(e); + } + catch (PlatformNotSupportedException e) + { + reportException(e); + } + catch (VerifierException e) + { + reportException(e); + } + catch (TypeSystemException e) + { + reportException(e); + } + + return builder.ToArray(); + + void reportException(Exception e) + { + builder.Add(new VerificationResult() + { + Method = methodHandle, + Message = e.Message + }); + } + } + + private void ThrowMissingSystemModule() + { + throw new VerifierException("No system module specified"); + } + } +} diff --git a/external/corert/src/ILVerify/src/VerifierError.cs b/external/corert/src/ILVerification/src/VerifierError.cs similarity index 99% rename from external/corert/src/ILVerify/src/VerifierError.cs rename to external/corert/src/ILVerification/src/VerifierError.cs index 8b2db48312..508fe51546 100644 --- a/external/corert/src/ILVerify/src/VerifierError.cs +++ b/external/corert/src/ILVerification/src/VerifierError.cs @@ -2,16 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - namespace ILVerify { - enum VerifierError + public enum VerifierError { + None = 0, //E_HRESULT "[HRESULT 0x%08X]" //E_OFFSET "[offset 0x%08X]" //E_OPCODE "[opcode %s]" diff --git a/external/corert/src/ILVerify/tests/ILMethodTester.cs b/external/corert/src/ILVerification/tests/ILMethodTester.cs similarity index 54% rename from external/corert/src/ILVerify/tests/ILMethodTester.cs rename to external/corert/src/ILVerification/tests/ILMethodTester.cs index 671bd3f915..eb92c3dcb2 100644 --- a/external/corert/src/ILVerify/tests/ILMethodTester.cs +++ b/external/corert/src/ILVerification/tests/ILMethodTester.cs @@ -2,15 +2,15 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Generic; using System.Linq; +using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; -using Internal.IL; +using ILVerify; using Internal.TypeSystem.Ecma; using Xunit; -namespace ILVerify.Tests +namespace ILVerification.Tests { public class ILMethodTester { @@ -19,16 +19,8 @@ namespace ILVerify.Tests [Trait("", "Valid IL Tests")] void TestMethodsWithValidIL(ValidILTestCase validIL) { - ILImporter importer = ConstructILImporter(validIL); - - var verifierErrors = new List(); - importer.ReportVerificationError = new Action((err) => - { - verifierErrors.Add(err.Code); - }); - - importer.Verify(); - Assert.Equal(0, verifierErrors.Count); + var results = Verify(validIL); + Assert.Equal(0, results.Count()); } [Theory(DisplayName = "")] @@ -36,17 +28,11 @@ namespace ILVerify.Tests [Trait("", "Invalid IL Tests")] void TestMethodsWithInvalidIL(InvalidILTestCase invalidIL) { - ILImporter importer = ConstructILImporter(invalidIL); - - var verifierErrors = new List(); - importer.ReportVerificationError = new Action((err) => - { - verifierErrors.Add(err.Code); - }); + IEnumerable results = null; try { - importer.Verify(); + results = Verify(invalidIL); } catch { @@ -57,23 +43,24 @@ namespace ILVerify.Tests } finally { - Assert.Equal(invalidIL.ExpectedVerifierErrors.Count, verifierErrors.Count); + Assert.NotNull(results); + Assert.Equal(invalidIL.ExpectedVerifierErrors.Count, results.Count()); foreach (var item in invalidIL.ExpectedVerifierErrors) { - var actual = verifierErrors.Select(e => e.ToString()); - Assert.True(verifierErrors.Contains(item), $"Actual errors where: {string.Join(',', actual)}"); + var actual = results.Select(e => e.ToString()); + Assert.True(results.Where(r => r.Error.Code == item).Count() > 0, $"Actual errors where: {string.Join(",", actual)}"); } } } - private ILImporter ConstructILImporter(TestCase testCase) + private static IEnumerable Verify(TestCase testCase) { - var module = TestDataLoader.GetModuleForTestAssembly(testCase.ModuleName); - var method = (EcmaMethod)module.GetMethod(MetadataTokens.EntityHandle(testCase.MetadataToken)); - var methodIL = EcmaMethodIL.Create(method); - - return new ILImporter(method, methodIL); + EcmaModule module = TestDataLoader.GetModuleForTestAssembly(testCase.ModuleName); + var methodHandle = (MethodDefinitionHandle) MetadataTokens.EntityHandle(testCase.MetadataToken); + var method = (EcmaMethod)module.GetMethod(methodHandle); + var verifier = new Verifier((ILVerifyTypeSystemContext)method.Context); + return verifier.Verify(module.PEReader, methodHandle); } } } diff --git a/external/corert/src/ILVerify/tests/ILTests/AccessTests.il b/external/corert/src/ILVerification/tests/ILTests/AccessTests.il similarity index 100% rename from external/corert/src/ILVerify/tests/ILTests/AccessTests.il rename to external/corert/src/ILVerification/tests/ILTests/AccessTests.il diff --git a/external/corert/src/ILVerify/tests/ILTests/AccessTestsExtern.il b/external/corert/src/ILVerification/tests/ILTests/AccessTestsExtern.il similarity index 100% rename from external/corert/src/ILVerify/tests/ILTests/AccessTestsExtern.il rename to external/corert/src/ILVerification/tests/ILTests/AccessTestsExtern.il diff --git a/external/corert/src/ILVerify/tests/ILTests/AccessTestsFriend.il b/external/corert/src/ILVerification/tests/ILTests/AccessTestsFriend.il similarity index 100% rename from external/corert/src/ILVerify/tests/ILTests/AccessTestsFriend.il rename to external/corert/src/ILVerification/tests/ILTests/AccessTestsFriend.il diff --git a/external/corert/src/ILVerify/tests/ILTests/ArrayTests.il b/external/corert/src/ILVerification/tests/ILTests/ArrayTests.il similarity index 100% rename from external/corert/src/ILVerify/tests/ILTests/ArrayTests.il rename to external/corert/src/ILVerification/tests/ILTests/ArrayTests.il diff --git a/external/corert/src/ILVerify/tests/ILTests/BasicArithmeticTests.il b/external/corert/src/ILVerification/tests/ILTests/BasicArithmeticTests.il similarity index 100% rename from external/corert/src/ILVerify/tests/ILTests/BasicArithmeticTests.il rename to external/corert/src/ILVerification/tests/ILTests/BasicArithmeticTests.il diff --git a/external/corert/src/ILVerify/tests/ILTests/BranchingTests.il b/external/corert/src/ILVerification/tests/ILTests/BranchingTests.il similarity index 100% rename from external/corert/src/ILVerify/tests/ILTests/BranchingTests.il rename to external/corert/src/ILVerification/tests/ILTests/BranchingTests.il diff --git a/external/corert/src/ILVerify/tests/ILTests/CallTests.il b/external/corert/src/ILVerification/tests/ILTests/CallTests.il similarity index 100% rename from external/corert/src/ILVerify/tests/ILTests/CallTests.il rename to external/corert/src/ILVerification/tests/ILTests/CallTests.il diff --git a/external/corert/src/ILVerify/tests/ILTests/CastingTests.il b/external/corert/src/ILVerification/tests/ILTests/CastingTests.il similarity index 100% rename from external/corert/src/ILVerify/tests/ILTests/CastingTests.il rename to external/corert/src/ILVerification/tests/ILTests/CastingTests.il diff --git a/external/corert/src/ILVerify/tests/ILTests/ComparisonTests.il b/external/corert/src/ILVerification/tests/ILTests/ComparisonTests.il similarity index 100% rename from external/corert/src/ILVerify/tests/ILTests/ComparisonTests.il rename to external/corert/src/ILVerification/tests/ILTests/ComparisonTests.il diff --git a/external/corert/src/ILVerify/tests/ILTests/DelegateTests.il b/external/corert/src/ILVerification/tests/ILTests/DelegateTests.il similarity index 100% rename from external/corert/src/ILVerify/tests/ILTests/DelegateTests.il rename to external/corert/src/ILVerification/tests/ILTests/DelegateTests.il diff --git a/external/corert/src/ILVerify/tests/ILTests/ExceptionRegionTests.il b/external/corert/src/ILVerification/tests/ILTests/ExceptionRegionTests.il similarity index 100% rename from external/corert/src/ILVerify/tests/ILTests/ExceptionRegionTests.il rename to external/corert/src/ILVerification/tests/ILTests/ExceptionRegionTests.il diff --git a/external/corert/src/ILVerify/tests/ILTests/FieldTests.il b/external/corert/src/ILVerification/tests/ILTests/FieldTests.il similarity index 100% rename from external/corert/src/ILVerify/tests/ILTests/FieldTests.il rename to external/corert/src/ILVerification/tests/ILTests/FieldTests.il diff --git a/external/corert/src/ILVerify/tests/ILTests/FtnTests.il b/external/corert/src/ILVerification/tests/ILTests/FtnTests.il similarity index 100% rename from external/corert/src/ILVerify/tests/ILTests/FtnTests.il rename to external/corert/src/ILVerification/tests/ILTests/FtnTests.il diff --git a/external/corert/src/ILVerify/tests/ILTests/LoadStoreIndirectTests.il b/external/corert/src/ILVerification/tests/ILTests/LoadStoreIndirectTests.il similarity index 100% rename from external/corert/src/ILVerify/tests/ILTests/LoadStoreIndirectTests.il rename to external/corert/src/ILVerification/tests/ILTests/LoadStoreIndirectTests.il diff --git a/external/corert/src/ILVerify/tests/ILTests/NewobjTests.il b/external/corert/src/ILVerification/tests/ILTests/NewobjTests.il similarity index 100% rename from external/corert/src/ILVerify/tests/ILTests/NewobjTests.il rename to external/corert/src/ILVerification/tests/ILTests/NewobjTests.il diff --git a/external/corert/src/ILVerify/tests/ILTests/PrefixTests.il b/external/corert/src/ILVerification/tests/ILTests/PrefixTests.il similarity index 100% rename from external/corert/src/ILVerify/tests/ILTests/PrefixTests.il rename to external/corert/src/ILVerification/tests/ILTests/PrefixTests.il diff --git a/external/corert/src/ILVerify/tests/ILTests/ReturnTests.il b/external/corert/src/ILVerification/tests/ILTests/ReturnTests.il similarity index 100% rename from external/corert/src/ILVerify/tests/ILTests/ReturnTests.il rename to external/corert/src/ILVerification/tests/ILTests/ReturnTests.il diff --git a/external/corert/src/ILVerify/tests/ILTests/ShiftTests.il b/external/corert/src/ILVerification/tests/ILTests/ShiftTests.il similarity index 100% rename from external/corert/src/ILVerify/tests/ILTests/ShiftTests.il rename to external/corert/src/ILVerification/tests/ILTests/ShiftTests.il diff --git a/external/corert/src/ILVerify/tests/ILTests/SwitchTests.il b/external/corert/src/ILVerification/tests/ILTests/SwitchTests.il similarity index 100% rename from external/corert/src/ILVerify/tests/ILTests/SwitchTests.il rename to external/corert/src/ILVerification/tests/ILTests/SwitchTests.il diff --git a/external/corert/src/ILVerify/tests/ILTests/ThisStateTests.il b/external/corert/src/ILVerification/tests/ILTests/ThisStateTests.il similarity index 100% rename from external/corert/src/ILVerify/tests/ILTests/ThisStateTests.il rename to external/corert/src/ILVerification/tests/ILTests/ThisStateTests.il diff --git a/external/corert/src/ILVerify/tests/ILTests/ValueTypeTests.il b/external/corert/src/ILVerification/tests/ILTests/ValueTypeTests.il similarity index 100% rename from external/corert/src/ILVerify/tests/ILTests/ValueTypeTests.il rename to external/corert/src/ILVerification/tests/ILTests/ValueTypeTests.il diff --git a/external/corert/src/ILVerification/tests/ILVerification.Tests.csproj b/external/corert/src/ILVerification/tests/ILVerification.Tests.csproj new file mode 100644 index 0000000000..4d5f17abf5 --- /dev/null +++ b/external/corert/src/ILVerification/tests/ILVerification.Tests.csproj @@ -0,0 +1,39 @@ + + + + + Library + netstandard1.5 + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/corert/src/ILVerify/tests/TestDataLoader.cs b/external/corert/src/ILVerification/tests/TestDataLoader.cs similarity index 84% rename from external/corert/src/ILVerify/tests/TestDataLoader.cs rename to external/corert/src/ILVerification/tests/TestDataLoader.cs index 15dc8efde2..91a1195f80 100644 --- a/external/corert/src/ILVerify/tests/TestDataLoader.cs +++ b/external/corert/src/ILVerification/tests/TestDataLoader.cs @@ -8,15 +8,15 @@ using System.IO; using System.Reflection; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; +using System.Reflection.PortableExecutable; using System.Text; -using Internal.IL; -using Internal.TypeSystem; +using ILVerify; using Internal.TypeSystem.Ecma; using Newtonsoft.Json; using Xunit; using Xunit.Abstractions; -namespace ILVerify.Tests +namespace ILVerification.Tests { /// /// Parses the methods in the test assemblies. @@ -96,7 +96,7 @@ namespace ILVerify.Tests private static TheoryData GetTestMethodsFromDll(Func methodSelector) { - var retVal = new Xunit.TheoryData(); + var retVal = new TheoryData(); foreach (var testDllName in GetAllTestDlls()) { @@ -152,33 +152,54 @@ namespace ILVerify.Tests private static IEnumerable GetAllTestDlls() { - foreach (var item in System.IO.Directory.GetFiles(TESTASSEMBLYPATH)) + foreach (var item in Directory.GetFiles(TESTASSEMBLYPATH)) { if (item.ToLower().EndsWith(".dll")) { - yield return System.IO.Path.GetFileName(item); + yield return Path.GetFileName(item); } } } public static EcmaModule GetModuleForTestAssembly(string assemblyName) { - var typeSystemContext = new SimpleTypeSystemContext(); - var coreAssembly = typeof(Object).Assembly; - var systemRuntime = Assembly.Load("System.Runtime"); + var simpleNameToPathMap = new Dictionary(); - typeSystemContext.InputFilePaths = new Dictionary - { - { coreAssembly.GetName().Name, coreAssembly.Location }, - { systemRuntime.GetName().Name, systemRuntime.Location } - }; - - typeSystemContext.ReferenceFilePaths = new Dictionary(); foreach (var fileName in GetAllTestDlls()) - typeSystemContext.ReferenceFilePaths.Add(Path.GetFileNameWithoutExtension(fileName), TESTASSEMBLYPATH + fileName); + { + simpleNameToPathMap.Add(Path.GetFileNameWithoutExtension(fileName), TESTASSEMBLYPATH + fileName); + } - typeSystemContext.SetSystemModule(typeSystemContext.GetModuleForSimpleName(coreAssembly.GetName().Name)); - return typeSystemContext.GetModuleFromPath(TESTASSEMBLYPATH + assemblyName); + Assembly coreAssembly = typeof(object).GetTypeInfo().Assembly; + simpleNameToPathMap.Add(coreAssembly.GetName().Name, coreAssembly.Location); + + Assembly systemRuntime = Assembly.Load(new AssemblyName("System.Runtime")); + simpleNameToPathMap.Add(systemRuntime.GetName().Name, systemRuntime.Location); + + var resolver = new TestResolver(simpleNameToPathMap); + var typeSystemContext = new ILVerifyTypeSystemContext(resolver); + typeSystemContext.SetSystemModule(typeSystemContext.GetModule(resolver.Resolve(coreAssembly.GetName()))); + + return typeSystemContext.GetModule(resolver.Resolve(new AssemblyName(Path.GetFileNameWithoutExtension(assemblyName)))); + } + + private sealed class TestResolver : ResolverBase + { + Dictionary _simpleNameToPathMap; + public TestResolver(Dictionary simpleNameToPathMap) + { + _simpleNameToPathMap = simpleNameToPathMap; + } + + protected override PEReader ResolveCore(AssemblyName name) + { + if (_simpleNameToPathMap.TryGetValue(name.Name, out string path)) + { + return new PEReader(File.OpenRead(path)); + } + + return null; + } } } diff --git a/external/corert/src/ILVerify/ILVerify.sln b/external/corert/src/ILVerify/ILVerify.sln index a26a9be5c1..ce368247dc 100644 --- a/external/corert/src/ILVerify/ILVerify.sln +++ b/external/corert/src/ILVerify/ILVerify.sln @@ -5,7 +5,9 @@ VisualStudioVersion = 15.0.26510.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ILVerify", "src\ILVerify.csproj", "{56AA4730-39A4-4B48-95E9-89E8A29F0A06}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ILVerify.Tests", "tests\ILVerify.Tests.csproj", "{1228E4B6-E5E5-414A-94EC-69B792984FAB}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ILVerification", "..\ILVerification\src\ILVerification.csproj", "{6166B258-3D41-4431-88D9-510FAF5E6927}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ILVerification.Tests", "..\ILVerification\tests\ILVerification.Tests.csproj", "{894F0BC9-31D1-42D0-9C3F-4FC9A41CD07E}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -17,12 +19,19 @@ Global {56AA4730-39A4-4B48-95E9-89E8A29F0A06}.Debug|Any CPU.Build.0 = Debug|Any CPU {56AA4730-39A4-4B48-95E9-89E8A29F0A06}.Release|Any CPU.ActiveCfg = Release|Any CPU {56AA4730-39A4-4B48-95E9-89E8A29F0A06}.Release|Any CPU.Build.0 = Release|Any CPU - {1228E4B6-E5E5-414A-94EC-69B792984FAB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1228E4B6-E5E5-414A-94EC-69B792984FAB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1228E4B6-E5E5-414A-94EC-69B792984FAB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1228E4B6-E5E5-414A-94EC-69B792984FAB}.Release|Any CPU.Build.0 = Release|Any CPU + {6166B258-3D41-4431-88D9-510FAF5E6927}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6166B258-3D41-4431-88D9-510FAF5E6927}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6166B258-3D41-4431-88D9-510FAF5E6927}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6166B258-3D41-4431-88D9-510FAF5E6927}.Release|Any CPU.Build.0 = Release|Any CPU + {894F0BC9-31D1-42D0-9C3F-4FC9A41CD07E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {894F0BC9-31D1-42D0-9C3F-4FC9A41CD07E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {894F0BC9-31D1-42D0-9C3F-4FC9A41CD07E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {894F0BC9-31D1-42D0-9C3F-4FC9A41CD07E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {3B6C08A7-1F82-4EC0-9CA7-1F07716F36B1} + EndGlobalSection EndGlobal diff --git a/external/corert/src/ILVerify/README.md b/external/corert/src/ILVerify/README.md index 662bf8ca2e..ef4d0d81f6 100644 --- a/external/corert/src/ILVerify/README.md +++ b/external/corert/src/ILVerify/README.md @@ -14,16 +14,20 @@ Historically on Full Framework IL generators used PEVerify to make sure that the - No coupling with CoreLib: ILVerify can point to any assembly and verify it. This also includes the full framework base assemblies (especially mscorlib). - Cross-platform, Open-Source - It should be easy to add new verification rules -- Fast spin up/tear down. +- Fast spin up/tear down. ## The codebase -The project targets netcoreapp2.0 and uses the new .csproj based project format. If you want to open and compile it with Visual Studio then you need a version, which supports .NET Core 2.0 tooling. This is supported in Visual Studio 2017 Update 3 (Version 15.3) or later. The other option is to use command (with .NET Core 2.0 tooling). +The project targets netcoreapp2.0 and uses the new .csproj based project format. If you want to open and compile it with Visual Studio then you need a version, which supports .NET Core 2.0 tooling. This is supported in Visual Studio 2017 Update 3 (Version 15.3) or later. The other option is to use command (with .NET Core 2.0 tooling). +The code is split into three projects: +- ILVerification is the library with the core verification logic, +- ILVerification.Tests contains the tests for ILVerification, +- ILVerify is an application that provides a command-line interface on top of ILVerification. ## Tests -To test ILVerify we have small methods checked in as .il files testing specific verification scenarios. These tests live under [src/ILVerify/tests/ILTests](https://github.com/dotnet/corert/tree/master/src/ILVerify/tests/ILTests). Tests are grouped into .il files based on functionalities they test. There is no strict policy here, the goal is to have a few dozen .il files instead of thousands containing each only a single method. +To test the ILVerification library we have small methods checked in as .il files testing specific verification scenarios. These tests live under [src/ILVerification/tests/ILTests](../ILVerification/tests/ILTests). Tests are grouped into .il files based on functionalities they test. There is no strict policy here, the goal is to have a few dozen .il files instead of thousands containing each only a single method. -Currently the IL files are NOT compiled automatically. You have to compile manually (We want to automatize this step later): +Currently the IL files are NOT compiled automatically. You have to compile manually (We want to automate this step later): ``` ilasm [filename.il] /dll /ERROR @@ -35,7 +39,7 @@ Note: if you run the tests and get an error similar to this then it means that t Result Message: System.InvalidOperationException : No data found for ILVerify.Tests.ILMethodTester.TestMethodsWithInvalidIL ``` -The test project itself is under [src/ILVerify/tests](https://github.com/dotnet/corert/tree/master/src/ILVerify/tests) +The test project itself is under [src/ILVerification/tests](../ILVerification/tests) Method names in the .il files must follow the following naming convention: @@ -44,9 +48,9 @@ The test project itself is under [src/ILVerify/tests](https://github.com/dotnet/ ``` [FriendlyName]_Valid ``` -The method must contain 1 '`_`'. +The method must contain 1 '`_`'. - The part before the `_` is a friendly name describing what the method does. - - The word after the `_` must be 'Valid' (Case sensitive) + - The word after the `_` must be 'Valid' (Case sensitive) E.g.: ```SimpleAdd_Valid``` @@ -58,10 +62,10 @@ E.g.: ```SimpleAdd_Valid``` The method name must contain 2 '`_`' characters. 1. part: a friendly name 2. part: must be the word 'Invalid' (Case sensitive) - 3. part: the expected [VerifierErrors](https://github.com/dotnet/corert/blob/master/src/ILVerify/src/VerifierError.cs) as string separated by '.'. We assert on these errors; the test fails if ILVerify does not report these errors. - + 3. part: the expected [VerifierErrors](../ILVerification/src/VerifierError.cs) as string separated by '.'. We assert on these errors; the test fails if ILVerify does not report these errors. + E.g.: ```SimpleAdd_Invalid_ExpectedNumericType``` - + ### Methods with special names: In order to test methods with special names (e.g. '.ctor'), the specialname method is defined as usual and a separate empty method is added to the type: @@ -92,7 +96,7 @@ Currently every IL command falls into one of these categories: - Not implemented: the implementation is completely missing. The easiest way is to pick one of them (look for NotImplentedException in the code) and implement it. First you should 100% understand the spec. (see [ECMA-335](https://www.ecma-international.org/publications/standards/Ecma-335.htm)), then try to port an existing implementation (sources below). - Partially implemented: These are typically methods with TODOs in it. As the first phase we want to make sure that for every command the stack is correctly maintained, therefore for some commands we either have no verification or we have only a not complete verification. You can also pick one of these and finish it. - - Implemented: find and fix bugs ;) . + - Implemented: find and fix bugs ;) . Another option to contribute is to write tests (see Tests section). @@ -100,4 +104,4 @@ Useful sources: - [PEVerify source code](https://github.com/lewischeng-ms/sscli/blob/master/clr/src/jit64/newverify.cpp) - [RyuJIT source code](https://github.com/dotnet/coreclr/blob/master/src/jit), specifically: [exception handling specific part](https://github.com/dotnet/coreclr/blob/master/src/jit/jiteh.cpp), [importer.cpp](https://github.com/dotnet/coreclr/blob/master/src/jit/importer.cpp) (look for `Compiler::ver`, `Verify`, `VerifyOrReturn`, and `VerifyOrReturnSpeculative`), [_typeinfo.h](https://github.com/dotnet/coreclr/blob/master/src/jit/_typeinfo.h), [typeinfo.cpp](https://github.com/dotnet/coreclr/blob/master/src/jit/typeinfo.cpp) - [ECMA-335 standard](https://www.ecma-international.org/publications/standards/Ecma-335.htm) - - [Expert .NET 2.0 IL Assembler book](http://www.apress.com/us/book/9781590596463) by Serge Lidin + - [Expert .NET 2.0 IL Assembler book](http://www.apress.com/us/book/9781590596463) by Serge Lidin diff --git a/external/corert/src/ILVerify/netcoreapp/ILVerify.cs b/external/corert/src/ILVerify/netcoreapp/ILVerify.cs new file mode 100644 index 0000000000..6158bb2541 --- /dev/null +++ b/external/corert/src/ILVerify/netcoreapp/ILVerify.cs @@ -0,0 +1,9 @@ +using System; + +class Program +{ + static void Main() + { + Console.WriteLine("Hello world!"); + } +} diff --git a/external/corert/src/ILVerify/netcoreapp/ILVerify.csproj b/external/corert/src/ILVerify/netcoreapp/ILVerify.csproj new file mode 100644 index 0000000000..47b7d31450 --- /dev/null +++ b/external/corert/src/ILVerify/netcoreapp/ILVerify.csproj @@ -0,0 +1,14 @@ + + + + Exe + netcoreapp2.0 + + + + + 0.1.0-e160909-1 + + + + diff --git a/external/corert/src/ILVerify/src/AssemblyInfo.cs b/external/corert/src/ILVerify/src/AssemblyInfo.cs index 8e392ff7bc..83d0e55a12 100644 --- a/external/corert/src/ILVerify/src/AssemblyInfo.cs +++ b/external/corert/src/ILVerify/src/AssemblyInfo.cs @@ -1,3 +1,3 @@ using System.Runtime.CompilerServices; -[assembly: InternalsVisibleTo("ILVerify.Tests")] +[assembly: InternalsVisibleTo("ILVerification.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100314e026e409db99b50d61628136c49095e67f782a3032832cfe1e61ba2af8264d2cf7d9228bdf611c1027f61b0ca4c87ee1c248cd58241a695520ba78e76d1c672c2b597cfa0ab4526dcae2b5b6f36936c126e59ada3500d656f3424826d0dab452ea407039d2846cf0e4820905eee537fe904a86097b5b2f3aaae000fc08fc3")] diff --git a/external/corert/src/ILVerify/src/ILVerify.csproj b/external/corert/src/ILVerify/src/ILVerify.csproj index 27ce4fc9e9..0f5d1e9903 100644 --- a/external/corert/src/ILVerify/src/ILVerify.csproj +++ b/external/corert/src/ILVerify/src/ILVerify.csproj @@ -1,286 +1,23 @@ - - + + Exe - netcoreapp2.0;net46 - AnyCPU - false - true - false + ILVerify + ILVerify + + ..\..\ILVerification\StrongNameKeys\ILVerify.snk + netcoreapp2.0 + false + + .dll - + - - - - - - - - - - - - TypeSystem\CodeGen\MethodDesc.CodeGen.cs - - - Utilities\AlignmentHelper.cs - - - TypeSystem\Common\CastingHelper.cs - - - TypeSystem\Common\FunctionPointerType.cs - - - TypeSystem\Common\IAssemblyDesc.cs - - - TypeSystem\Common\Instantiation.cs - - - TypeSystem\Common\ModuleDesc.cs - - - TypeSystem\Common\TypeSystemEntity.cs - - - TypeSystem\Common\TypeSystemException.cs - - - Utilities\CustomAttributeTypeNameParser.cs - - - Utilities\LockFreeReaderHashtable.cs - - - TypeSystem\Common\ArrayType.cs - - - TypeSystem\Common\ArrayOfTRuntimeInterfacesAlgorithm.cs - - - TypeSystem\Common\BaseTypeRuntimeInterfacesAlgorithm.cs - - - TypeSystem\Common\ByRefType.cs - - - TypeSystem\Common\GenericParameterDesc.cs - - - TypeSystem\Common\ExceptionStringID.cs - - - TypeSystem\Common\FieldForInstantiatedType.cs - - - TypeSystem\Common\FieldDesc.cs - - - TypeSystem\Common\FieldDesc.FieldLayout.cs - - - TypeSystem\Common\FieldLayoutAlgorithm.cs - - - TypeSystem\Common\InstantiatedMethod.cs - - - TypeSystem\Common\InstantiatedType.cs - - - TypeSystem\Common\InstantiatedType.Interfaces.cs - - - TypeSystem\Common\InstantiatedType.MethodImpls.cs - - - TypeSystem\Common\LayoutInt.cs - - - TypeSystem\Common\MetadataType.cs - - - TypeSystem\Common\MetadataType.Interfaces.cs - - - TypeSystem\Common\MetadataType.MethodImpls.cs - - - TypeSystem\Common\MetadataFieldLayoutAlgorithm.cs - - - TypeSystem\Common\MetadataRuntimeInterfacesAlgorithm.cs - - - TypeSystem\Common\MetadataTypeSystemContext.cs - - - TypeSystem\Common\MethodForInstantiatedType.cs - - - TypeSystem\Common\ParameterizedType.cs - - - TypeSystem\Common\PointerType.cs - - - TypeSystem\Common\PropertySignature.cs - - - TypeSystem\Common\SignatureVariable.cs - - - TypeSystem\Common\TargetDetails.cs - - - TypeSystem\Common\ThreadSafeFlags.cs - - - TypeSystem\Common\TypeFlags.cs - - - TypeSystem\Common\TypeHashingAlgorithms.cs - - - TypeSystem\Common\TypeSystemContext.cs - - - TypeSystem\Common\TypeSystemHelpers.cs - - - Utilities\TypeNameFormatter.cs - - - TypeSystem\Common\WellKnownType.cs - - - TypeSystem\Common\VirtualMethodAlgorithm.cs - - - TypeSystem\Common\MethodDesc.cs - - - TypeSystem\Common\StandardVirtualMethodAlgorithm.cs - - - TypeSystem\Common\TypeDesc.cs - - - TypeSystem\Common\TypeDesc.Interfaces.cs - - - TypeSystem\Common\DefType.cs - - - TypeSystem\Common\DefType.FieldLayout.cs - - - TypeSystem\Common\RuntimeInterfacesAlgorithm.cs - - - TypeSystem\Common\ThrowHelper.Common.cs - - - TypeSystem\Common\ThrowHelper.cs - - - TypeSystem\Common\Utilities\ExceptionTypeNameFormatter.cs - - - TypeSystem\Common\Utilities\ExceptionTypeNameFormatter.Metadata.cs - - - Ecma\CustomAttributeTypeProvider.cs - - - Ecma\EcmaAssembly.cs - - - Ecma\EcmaField.cs - - - Ecma\EcmaGenericParameter.cs - - - Ecma\EcmaMethod.cs - - - Ecma\EcmaModule.cs - - - Ecma\EcmaSignatureParser.cs - - - Ecma\EcmaType.cs - - - Ecma\EcmaType.MethodImpls.cs - - - Ecma\EcmaType.Interfaces.cs - - - Ecma\MetadataExtensions.cs - - - Ecma\IMetadataStringDecoderProvider.cs - - - Ecma\CachingMetadataStringDecoder.cs - - - Ecma\PrimitiveTypeProvider.cs - - - IL\EcmaMethodIL.cs - - - IL\MethodIL.cs - - - IL\MethodILDebugView.cs - - - IL\ILDisassembler.cs - - - IL\InstantiatedMethodIL.cs - - - IL\ILOpcode.cs - - - IL\ILImporter.cs - - - Interop\InstantiatedType.Interop.cs - - - Interop\MetadataType.Interop.cs - - - Interop\MethodDesc.Interop.cs - - - TypeSystem\Interop\MarshalAsDescriptor.cs - - - Utilities\ArrayBuilder.cs - - - TypeSystem\Common\LocalVariableDefinition.cs - - - Common\System\FormattingHelpers.cs - - - TypeSystem\Common\TypeSystemConstraintsHelpers.cs - + + @@ -295,8 +32,20 @@ - - - + - \ No newline at end of file + + + + Always + + + + + + $(TargetDir)$(AssemblyName).exe + $(TargetDir)$(AssemblyName) + $(StartArguments) + + + diff --git a/external/corert/src/ILVerify/src/ILVerify.runtimeconfig.json b/external/corert/src/ILVerify/src/ILVerify.runtimeconfig.json new file mode 100644 index 0000000000..76e1770766 --- /dev/null +++ b/external/corert/src/ILVerify/src/ILVerify.runtimeconfig.json @@ -0,0 +1,7 @@ +{ + "runtimeOptions": { + "configProperties": { + "Microsoft.NETCore.DotNetHostPolicy.SetAppPaths": true + } + } +} diff --git a/external/corert/src/ILVerify/src/Program.cs b/external/corert/src/ILVerify/src/Program.cs index aec3b5c18a..d748084b81 100644 --- a/external/corert/src/ILVerify/src/Program.cs +++ b/external/corert/src/ILVerify/src/Program.cs @@ -3,42 +3,31 @@ // See the LICENSE file in the project root for more information. using System; -using System.IO; using System.Collections.Generic; using System.CommandLine; -using System.Reflection; +using System.IO; using System.Linq; +using System.Reflection; using System.Reflection.Metadata; -using System.Reflection.Metadata.Ecma335; using System.Reflection.PortableExecutable; -using System.Text; - -using Internal.TypeSystem; -using Internal.TypeSystem.Ecma; -using Internal.IL; - -using Internal.CommandLine; using System.Text.RegularExpressions; -using System.Globalization; -using System.Resources; +using Internal.CommandLine; +using Internal.TypeSystem.Ecma; +using static System.Console; namespace ILVerify { - class Program + class Program : ResolverBase { - private const string DefaultSystemModuleName = "mscorlib"; private bool _help; - private string _systemModule = DefaultSystemModuleName; - private Dictionary _inputFilePaths = new Dictionary(StringComparer.OrdinalIgnoreCase); - private Dictionary _referenceFilePaths = new Dictionary(StringComparer.OrdinalIgnoreCase); + private AssemblyName _systemModule = new AssemblyName("mscorlib"); + private Dictionary _inputFilePaths = new Dictionary(StringComparer.OrdinalIgnoreCase); // map of simple name to file path + private Dictionary _referenceFilePaths = new Dictionary(StringComparer.OrdinalIgnoreCase); // map of simple name to file path private IReadOnlyList _includePatterns = Array.Empty(); private IReadOnlyList _excludePatterns = Array.Empty(); - private SimpleTypeSystemContext _typeSystemContext; - private ResourceManager _stringResourceManager; - - private int _numErrors; + private Verifier _verifier; private Program() { @@ -46,9 +35,9 @@ namespace ILVerify private void Help(string helpText) { - Console.WriteLine("ILVerify version " + typeof(Program).GetTypeInfo().Assembly.GetName().Version.ToString()); - Console.WriteLine(); - Console.WriteLine(helpText); + WriteLine("ILVerify version " + typeof(Program).GetTypeInfo().Assembly.GetName().Version.ToString()); + WriteLine(); + WriteLine(helpText); } public static IReadOnlyList StringPatternsToRegexList(IReadOnlyList patterns) @@ -78,7 +67,7 @@ namespace ILVerify syntax.HandleErrors = true; syntax.DefineOption("h|help", ref _help, "Display this usage message"); - syntax.DefineOption("s|system-module", ref _systemModule, "System module name (default: mscorlib)"); + syntax.DefineOption("s|system-module", ref _systemModule, s => new AssemblyName(s), "System module name (default: mscorlib)"); syntax.DefineOptionList("r|reference", ref referenceFiles, "Reference metadata from the specified assembly"); syntax.DefineOptionList("i|include", ref includePatterns, "Use only methods/types/namespaces, which match the given regular expression(s)"); syntax.DefineOption("include-file", ref includeFile, "Same as --include, but the regular expression(s) are declared line by line in the specified file."); @@ -97,7 +86,7 @@ namespace ILVerify if (!string.IsNullOrEmpty(includeFile)) { if (includePatterns.Count > 0) - Console.WriteLine("[Warning] --include-file takes precedence over --include"); + WriteLine("[Warning] --include-file takes precedence over --include"); includePatterns = File.ReadAllLines(includeFile); } _includePatterns = StringPatternsToRegexList(includePatterns); @@ -105,7 +94,7 @@ namespace ILVerify if (!string.IsNullOrEmpty(excludeFile)) { if (excludePatterns.Count > 0) - Console.WriteLine("[Warning] --exclude-file takes precedence over --exclude"); + WriteLine("[Warning] --exclude-file takes precedence over --exclude"); excludePatterns = File.ReadAllLines(excludeFile); } _excludePatterns = StringPatternsToRegexList(excludePatterns); @@ -113,122 +102,6 @@ namespace ILVerify return argSyntax; } - private void VerifyMethod(MethodDesc method, MethodIL methodIL) - { - // Console.WriteLine("Verifying: " + method.ToString()); - - try - { - var importer = new ILImporter(method, methodIL); - - importer.ReportVerificationError = (args) => - { - var message = new StringBuilder(); - - message.Append("[IL]: Error: "); - - message.Append("["); - message.Append(_typeSystemContext.GetModulePath(((EcmaMethod)method).Module)); - message.Append(" : "); - message.Append(((EcmaType)method.OwningType).Name); - message.Append("::"); - message.Append(method.Name); - message.Append("("); - if (method.Signature._parameters != null && method.Signature._parameters.Length > 0) - { - foreach (TypeDesc parameter in method.Signature._parameters) - { - message.Append(parameter.ToString()); - message.Append(", "); - } - message.Remove(message.Length - 2, 2); - } - message.Append(")"); - message.Append("]"); - - message.Append("[offset 0x"); - message.Append(args.Offset.ToString("X8")); - message.Append("]"); - - if (args.Found != null) - { - message.Append("[found "); - message.Append(args.Found); - message.Append("]"); - } - - if (args.Expected != null) - { - message.Append("[expected "); - message.Append(args.Expected); - message.Append("]"); - } - - if (args.Token != 0) - { - message.Append("[token 0x"); - message.Append(args.Token.ToString("X8")); - message.Append("]"); - } - - message.Append(" "); - - if (_stringResourceManager == null) - { - _stringResourceManager = new ResourceManager("ILVerify.Resources.Strings", Assembly.GetExecutingAssembly()); - } - - var str = _stringResourceManager.GetString(args.Code.ToString(), CultureInfo.InvariantCulture); - message.Append(string.IsNullOrEmpty(str) ? args.Code.ToString() : str); - - Console.WriteLine(message); - - _numErrors++; - }; - - importer.Verify(); - } - catch (NotImplementedException e) - { - Console.Error.WriteLine($"Error in {method}: {e.Message}"); - } - catch (InvalidProgramException e) - { - Console.Error.WriteLine($"Error in {method}: {e.Message}"); - } - catch (VerificationException) - { - } - catch (BadImageFormatException) - { - Console.WriteLine("Unable to resolve token"); - } - catch (PlatformNotSupportedException e) - { - Console.WriteLine(e.Message); - } - } - - private void VerifyModule(EcmaModule module) - { - foreach (var methodHandle in module.MetadataReader.MethodDefinitions) - { - var method = (EcmaMethod)module.GetMethod(methodHandle); - - var methodIL = EcmaMethodIL.Create(method); - if (methodIL == null) - continue; - - var methodName = method.ToString(); - if (_includePatterns.Count > 0 && !_includePatterns.Any(p => p.IsMatch(methodName))) - continue; - if (_excludePatterns.Any(p => p.IsMatch(methodName))) - continue; - - VerifyMethod(method, methodIL); - } - } - private int Run(string[] args) { ArgumentSyntax syntax = ParseCommandLine(args); @@ -241,27 +114,162 @@ namespace ILVerify if (_inputFilePaths.Count == 0) throw new CommandLineException("No input files specified"); - _typeSystemContext = new SimpleTypeSystemContext(); - _typeSystemContext.InputFilePaths = _inputFilePaths; - _typeSystemContext.ReferenceFilePaths = _referenceFilePaths; + _verifier = new Verifier(this); + _verifier.SetSystemModuleName(_systemModule); - _typeSystemContext.SetSystemModule(_typeSystemContext.GetModuleForSimpleName(_systemModule)); - - foreach (var inputPath in _inputFilePaths.Values) + foreach (var kvp in _inputFilePaths) { - _numErrors = 0; + var results = VerifyAssembly(new AssemblyName(kvp.Key), out EcmaModule module); + int numErrors = 0; - VerifyModule(_typeSystemContext.GetModuleFromPath(inputPath)); + foreach (var result in results) + { + numErrors++; + PrintResult(result, module, kvp.Value); + } - if (_numErrors > 0) - Console.WriteLine(_numErrors + " Error(s) Verifying " + inputPath); + if (numErrors > 0) + WriteLine(numErrors + " Error(s) Verifying " + kvp.Value); else - Console.WriteLine("All Classes and Methods in " + inputPath + " Verified."); + WriteLine("All Classes and Methods in " + kvp.Value + " Verified."); } return 0; } + private void PrintResult(VerificationResult result, EcmaModule module, string pathOrModuleName) + { + Write("[IL]: Error: "); + + Write("["); + Write(pathOrModuleName); + Write(" : "); + + MetadataReader metadataReader = module.MetadataReader; + + TypeDefinition typeDef = metadataReader.GetTypeDefinition(metadataReader.GetMethodDefinition(result.Method).GetDeclaringType()); + string typeName = metadataReader.GetString(typeDef.Name); + Write(typeName); + + Write("::"); + var method = (EcmaMethod)module.GetMethod(result.Method); + PrintMethod(method); + Write("]"); + + var args = result.Error; + if (args.Code != VerifierError.None) + { + Write("[offset 0x"); + Write(args.Offset.ToString("X8")); + Write("]"); + + if (args.Found != null) + { + Write("[found "); + Write(args.Found); + Write("]"); + } + + if (args.Expected != null) + { + Write("[expected "); + Write(args.Expected); + Write("]"); + } + + if (args.Token != 0) + { + Write("[token 0x"); + Write(args.Token.ToString("X8")); + Write("]"); + } + } + + Write(" "); + WriteLine(result.Message); + } + + private static void PrintMethod(EcmaMethod method) + { + Write(method.Name); + Write("("); + + if (method.Signature.Length > 0) + { + bool first = true; + for(int i = 0; i < method.Signature.Length; i++) + { + Internal.TypeSystem.TypeDesc parameter = method.Signature[0]; + if (first) + { + first = false; + } + else + { + Write(", "); + } + + Write(parameter.ToString()); + } + } + + Write(")"); + } + + private IEnumerable VerifyAssembly(AssemblyName name, out EcmaModule module) + { + PEReader peReader = Resolve(name); + module = _verifier.GetModule(peReader); + + return VerifyAssembly(peReader); + } + + private IEnumerable VerifyAssembly(PEReader peReader) + { + MetadataReader metadataReader = peReader.GetMetadataReader(); + foreach (var methodHandle in metadataReader.MethodDefinitions) + { + var methodName = metadataReader.GetString(metadataReader.GetMethodDefinition(methodHandle).Name); + if (ShouldVerifyMethod(methodName)) + { + var results = _verifier.Verify(peReader, methodHandle); + foreach (var result in results) + { + yield return result; + } + } + } + } + + private bool ShouldVerifyMethod(string methodName) + { + if (_includePatterns.Count > 0 && !_includePatterns.Any(p => p.IsMatch(methodName))) + { + return false; + } + + if (_excludePatterns.Any(p => p.IsMatch(methodName))) + { + return false; + } + + return true; + } + + protected override PEReader ResolveCore(AssemblyName name) + { + // Note: we use simple names instead of full names to resolve, because we can't get a full name from an assembly without reading it + string simpleName = name.Name; + + string path = null; + if (_inputFilePaths.TryGetValue(simpleName, out path) || _referenceFilePaths.TryGetValue(simpleName, out path)) + { + return new PEReader(File.OpenRead(path)); + } + + return null; + } + private static int Main(string[] args) { try diff --git a/external/corert/src/ILVerify/src/SimpleTypeSystemContext.cs b/external/corert/src/ILVerify/src/SimpleTypeSystemContext.cs deleted file mode 100644 index 123e2e0d27..0000000000 --- a/external/corert/src/ILVerify/src/SimpleTypeSystemContext.cs +++ /dev/null @@ -1,134 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.IO; -using System.Collections.Generic; -using System.Reflection; -using System.Reflection.Metadata; -using System.Reflection.Metadata.Ecma335; -using System.Reflection.PortableExecutable; - -using Internal.TypeSystem; -using Internal.TypeSystem.Ecma; - -using Internal.CommandLine; - -namespace ILVerify -{ - class SimpleTypeSystemContext : MetadataTypeSystemContext - { - private RuntimeInterfacesAlgorithm _arrayOfTRuntimeInterfacesAlgorithm; - private MetadataRuntimeInterfacesAlgorithm _metadataRuntimeInterfacesAlgorithm = new MetadataRuntimeInterfacesAlgorithm(); - - Dictionary _modules = new Dictionary(StringComparer.OrdinalIgnoreCase); - - class ModuleData - { - public string Path; - } - Dictionary _moduleData = new Dictionary(); - - public SimpleTypeSystemContext() - { - } - - public IDictionary InputFilePaths - { - get; - set; - } - - public IDictionary ReferenceFilePaths - { - get; - set; - } - - public override ModuleDesc ResolveAssembly(AssemblyName name, bool throwIfNotFound = true) - { - return GetModuleForSimpleName(name.Name); - } - - public EcmaModule GetModuleForSimpleName(string simpleName) - { - EcmaModule existingModule; - if (_modules.TryGetValue(simpleName, out existingModule)) - return existingModule; - - return CreateModuleForSimpleName(simpleName); - } - - private EcmaModule CreateModuleForSimpleName(string simpleName) - { - string filePath; - if (!InputFilePaths.TryGetValue(simpleName, out filePath)) - { - if (!ReferenceFilePaths.TryGetValue(simpleName, out filePath)) - throw new CommandLineException("Assembly not found: " + simpleName); - } - - PEReader peReader = new PEReader(File.OpenRead(filePath)); - EcmaModule module = EcmaModule.Create(this, peReader); - - MetadataReader metadataReader = module.MetadataReader; - string actualSimpleName = metadataReader.GetString(metadataReader.GetAssemblyDefinition().Name); - if (!actualSimpleName.Equals(simpleName, StringComparison.OrdinalIgnoreCase)) - throw new CommandLineException("Assembly name does not match filename " + filePath); - - _modules.Add(simpleName, module); - - ModuleData moduleData = new ModuleData() { Path = filePath }; - _moduleData.Add(module, moduleData); - - return module; - } - - public EcmaModule GetModuleFromPath(string filePath) - { - // This is called once for every assembly that should be verified, so linear search is acceptable. - foreach (KeyValuePair entry in _moduleData) - { - EcmaModule curModule = entry.Key; - ModuleData curData = entry.Value; - if (curData.Path == filePath) - return curModule; - } - - PEReader peReader = new PEReader(File.OpenRead(filePath)); - EcmaModule module = EcmaModule.Create(this, peReader); - - MetadataReader metadataReader = module.MetadataReader; - string simpleName = metadataReader.GetString(metadataReader.GetAssemblyDefinition().Name); - if (_modules.ContainsKey(simpleName)) - throw new CommandLineException("Module with same simple name already exists " + filePath); - - _modules.Add(simpleName, module); - - ModuleData moduleData = new ModuleData() { Path = filePath }; - _moduleData.Add(module, moduleData); - - return module; - } - - public string GetModulePath(EcmaModule module) - { - return _moduleData[module].Path; - } - - protected override RuntimeInterfacesAlgorithm GetRuntimeInterfacesAlgorithmForNonPointerArrayType(ArrayType type) - { - if (_arrayOfTRuntimeInterfacesAlgorithm == null) - { - _arrayOfTRuntimeInterfacesAlgorithm = new SimpleArrayOfTRuntimeInterfacesAlgorithm(SystemModule); - } - return _arrayOfTRuntimeInterfacesAlgorithm; - } - - protected override RuntimeInterfacesAlgorithm GetRuntimeInterfacesAlgorithmForDefType(DefType type) - { - return _metadataRuntimeInterfacesAlgorithm; - } - } -} diff --git a/external/corert/src/ILVerify/tests/ILVerify.Tests.csproj b/external/corert/src/ILVerify/tests/ILVerify.Tests.csproj deleted file mode 100644 index 94c21cd159..0000000000 --- a/external/corert/src/ILVerify/tests/ILVerify.Tests.csproj +++ /dev/null @@ -1,27 +0,0 @@ - - - - netcoreapp2.0 - - false - - - - - - - - - - - - - - - - - - - - - diff --git a/external/corert/src/JitInterface/src/CorInfoHelpFunc.cs b/external/corert/src/JitInterface/src/CorInfoHelpFunc.cs index 392f59f96f..ababdf60e3 100644 --- a/external/corert/src/JitInterface/src/CorInfoHelpFunc.cs +++ b/external/corert/src/JitInterface/src/CorInfoHelpFunc.cs @@ -300,6 +300,7 @@ namespace Internal.JitInterface CORINFO_HELP_THROW_ARGUMENTEXCEPTION, // throw ArgumentException CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION, // throw ArgumentOutOfRangeException CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, // throw PlatformNotSupportedException + CORINFO_HELP_THROW_TYPE_NOT_SUPPORTED, // throw TypeNotSupportedException CORINFO_HELP_JIT_PINVOKE_BEGIN, // Transition to preemptive mode before a P/Invoke, frame is the first argument CORINFO_HELP_JIT_PINVOKE_END, // Transition to cooperative mode after a P/Invoke, frame is the first argument diff --git a/external/corert/src/JitInterface/src/CorInfoImpl.Intrinsics.cs b/external/corert/src/JitInterface/src/CorInfoImpl.Intrinsics.cs index 18bb742dd5..888957b322 100644 --- a/external/corert/src/JitInterface/src/CorInfoImpl.Intrinsics.cs +++ b/external/corert/src/JitInterface/src/CorInfoImpl.Intrinsics.cs @@ -19,8 +19,8 @@ namespace Internal.JitInterface public bool Equals(IntrinsicKey other) { - return (MethodName == other.MethodName) && - (TypeNamespace == other.TypeNamespace) && + return (MethodName == other.MethodName) && + (TypeNamespace == other.TypeNamespace) && (TypeName == other.TypeName); } @@ -78,27 +78,49 @@ namespace Internal.JitInterface IntrinsicHashtable table = new IntrinsicHashtable(); table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Sin, "Sin", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Sin, "Sin", "System", "MathF"); table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Cos, "Cos", "System", "Math"); - // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Cbrt, "Cbrt", "System", "Math"); // not in CoreRT yet + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Cos, "Cos", "System", "MathF"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Cbrt, "Cbrt", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Cbrt, "Cbrt", "System", "MathF"); table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Sqrt, "Sqrt", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Sqrt, "Sqrt", "System", "MathF"); table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Abs, "Abs", "System", "Math"); + // No System.MathF entry for CORINFO_INTRTINSIC_Abs as System.Math exposes and handles both float and double table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Round, "Round", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Round, "Round", "System", "MathF"); table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Cosh, "Cosh", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Cosh, "Cosh", "System", "MathF"); table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Sinh, "Sinh", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Sinh, "Sinh", "System", "MathF"); table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Tan, "Tan", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Tan, "Tan", "System", "MathF"); table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Tanh, "Tanh", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Tanh, "Tanh", "System", "MathF"); table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Asin, "Asin", "System", "Math"); - // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Asinh, "Asinh", "System", "Math"); // not in CoreRT yet + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Asin, "Asin", "System", "MathF"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Asinh, "Asinh", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Asinh, "Asinh", "System", "MathF"); table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Acos, "Acos", "System", "Math"); - // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Acosh, "Acosh", "System", "Math"); // not in CoreRT yet + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Acos, "Acos", "System", "MathF"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Acosh, "Acosh", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Acosh, "Acosh", "System", "MathF"); table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Atan, "Atan", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Atan, "Atan", "System", "MathF"); table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Atan2, "Atan2", "System", "Math"); - // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Atanh, "Atanh", "System", "Math"); // not in CoreRT yet + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Atan2, "Atan2", "System", "MathF"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Atanh, "Atanh", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Atanh, "Atanh", "System", "MathF"); table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Log10, "Log10", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Log10, "Log10", "System", "MathF"); table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Pow, "Pow", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Pow, "Pow", "System", "MathF"); table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Exp, "Exp", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Exp, "Exp", "System", "MathF"); table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Ceiling, "Ceiling", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Ceiling, "Ceiling", "System", "MathF"); table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Floor, "Floor", "System", "Math"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Floor, "Floor", "System", "MathF"); // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_GetChar, null, null, null); // unused // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Array_GetDimLength, "GetLength", "System", "Array"); // not handled table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Array_Get, "Get", null, null); @@ -109,8 +131,8 @@ namespace Internal.JitInterface table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_InitializeArray, "InitializeArray", "System.Runtime.CompilerServices", "RuntimeHelpers"); //table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_GetTypeFromHandle, "GetTypeFromHandle", "System", "Type"); // RuntimeTypeHandle has to be RuntimeType table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_RTH_GetValueInternal, "GetValueInternal", "System", "RuntimeTypeHandle"); - // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_TypeEQ, "op_Equality", "System", "Type"); // not in .NET Core - // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_TypeNEQ, "op_Inequality", "System", "Type"); // not in .NET Core + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_TypeEQ, "op_Equality", "System", "Type"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_TypeNEQ, "op_Inequality", "System", "Type"); table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_Object_GetType, "GetType", "System", "Object"); // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_StubHelpers_GetStubContext, "GetStubContext", "System.StubHelpers", "StubHelpers"); // interop-specific // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_StubHelpers_GetStubContextAddr, "GetStubContextAddr", "System.StubHelpers", "StubHelpers"); // interop-specific diff --git a/external/corert/src/JitInterface/src/CorInfoImpl.cs.REMOVED.git-id b/external/corert/src/JitInterface/src/CorInfoImpl.cs.REMOVED.git-id index 2e29f3d762..4350779b07 100644 --- a/external/corert/src/JitInterface/src/CorInfoImpl.cs.REMOVED.git-id +++ b/external/corert/src/JitInterface/src/CorInfoImpl.cs.REMOVED.git-id @@ -1 +1 @@ -c06bd6b5ca3c766fa47c733d9c925a3946798fb6 \ No newline at end of file +a9eaceaabddd739f9ab20745add8ddcffb771683 \ No newline at end of file diff --git a/external/corert/src/JitInterface/src/CorInfoTypes.cs b/external/corert/src/JitInterface/src/CorInfoTypes.cs index b427f44761..b0ceda6134 100644 --- a/external/corert/src/JitInterface/src/CorInfoTypes.cs +++ b/external/corert/src/JitInterface/src/CorInfoTypes.cs @@ -1464,7 +1464,7 @@ namespace Internal.JitInterface CORJIT_FLAG_UNUSED3 = 10, CORJIT_FLAG_UNUSED4 = 11, CORJIT_FLAG_UNUSED5 = 12, - CORJIT_FLAG_USE_SSE3_4 = 13, + CORJIT_FLAG_UNUSED6 = 13, CORJIT_FLAG_USE_AVX = 14, CORJIT_FLAG_USE_AVX2 = 15, CORJIT_FLAG_USE_AVX_512 = 16, diff --git a/external/corert/src/JitInterface/src/ThunkGenerator/corinfo.h.REMOVED.git-id b/external/corert/src/JitInterface/src/ThunkGenerator/corinfo.h.REMOVED.git-id index 61624f2c00..90413a9157 100644 --- a/external/corert/src/JitInterface/src/ThunkGenerator/corinfo.h.REMOVED.git-id +++ b/external/corert/src/JitInterface/src/ThunkGenerator/corinfo.h.REMOVED.git-id @@ -1 +1 @@ -c79dd3f4c65fd8c9e4bedce829279a67a086cc82 \ No newline at end of file +f3b509c5ad764568b7ac3c43714b64b8d6ee0f54 \ No newline at end of file diff --git a/external/corert/src/JitInterface/src/ThunkGenerator/corjitflags.h b/external/corert/src/JitInterface/src/ThunkGenerator/corjitflags.h index 2598c26acf..da303b6a03 100644 --- a/external/corert/src/JitInterface/src/ThunkGenerator/corjitflags.h +++ b/external/corert/src/JitInterface/src/ThunkGenerator/corjitflags.h @@ -52,16 +52,16 @@ public: #endif // !defined(_TARGET_X86_) + CORJIT_FLAG_UNUSED6 = 13, + #if defined(_TARGET_X86_) || defined(_TARGET_AMD64_) - CORJIT_FLAG_USE_SSE3_4 = 13, CORJIT_FLAG_USE_AVX = 14, CORJIT_FLAG_USE_AVX2 = 15, CORJIT_FLAG_USE_AVX_512 = 16, #else // !defined(_TARGET_X86_) && !defined(_TARGET_AMD64_) - CORJIT_FLAG_UNUSED6 = 13, CORJIT_FLAG_UNUSED7 = 14, CORJIT_FLAG_UNUSED8 = 15, CORJIT_FLAG_UNUSED9 = 16, diff --git a/external/corert/src/Native/Bootstrap/common.h b/external/corert/src/Native/Bootstrap/common.h index 06a1ac5e6a..fb804e459c 100644 --- a/external/corert/src/Native/Bootstrap/common.h +++ b/external/corert/src/Native/Bootstrap/common.h @@ -47,6 +47,7 @@ extern "C" Object * __allocate_array(size_t elements, MethodTable * pMT); extern "C" Object * __castclass(void * obj, MethodTable * pMT); extern "C" Object * __isinst(void * obj, MethodTable * pMT); extern "C" __NORETURN void __throw_exception(void * pEx); +extern "C" void __debug_break(); Object * __load_string_literal(const char * string); diff --git a/external/corert/src/Native/Bootstrap/main.cpp b/external/corert/src/Native/Bootstrap/main.cpp index 1f482795a1..43860640d4 100644 --- a/external/corert/src/Native/Bootstrap/main.cpp +++ b/external/corert/src/Native/Bootstrap/main.cpp @@ -98,6 +98,7 @@ extern "C" void * RhTypeCast_CheckCast(void * pObject, MethodTable * pMT); extern "C" void RhpStelemRef(void * pArray, int index, void * pObj); extern "C" void * RhpLdelemaRef(void * pArray, int index, MethodTable * pMT); extern "C" __NORETURN void RhpThrowEx(void * pEx); +extern "C" void RhDebugBreak(); extern "C" Object * __allocate_object(MethodTable * pMT) { @@ -134,6 +135,11 @@ extern "C" void __throw_exception(void * pEx) RhpThrowEx(pEx); } +extern "C" void __debug_break() +{ + RhDebugBreak(); +} + void __range_check_fail() { throw "ThrowRangeOverflowException"; @@ -288,7 +294,9 @@ static const pfn c_classlibFunctions[] = { &AppendExceptionStackFrame, nullptr, // &CheckStaticClassConstruction, &GetSystemArrayEEType, - &OnFirstChanceException + &OnFirstChanceException, + nullptr, // &DebugFuncEvalHelper, + nullptr, // &DebugFuncEvalAbortHelper, }; #endif // !CPPCODEGEN diff --git a/external/corert/src/Native/ObjWriter/llvm.patch b/external/corert/src/Native/ObjWriter/llvm.patch index 2dde952d54..fd8420125e 100644 --- a/external/corert/src/Native/ObjWriter/llvm.patch +++ b/external/corert/src/Native/ObjWriter/llvm.patch @@ -1,5 +1,5 @@ diff --git a/include/llvm/MC/MCObjectStreamer.h b/include/llvm/MC/MCObjectStreamer.h -index 7c1189e46ab..d1d77c97311 100644 +index 7c1189e..d1d77c9 100644 --- a/include/llvm/MC/MCObjectStreamer.h +++ b/include/llvm/MC/MCObjectStreamer.h @@ -101,6 +101,11 @@ public: @@ -14,8 +14,20 @@ index 7c1189e46ab..d1d77c97311 100644 /// \brief Emit an instruction to a special fragment, because this instruction /// can change its size during relaxation. virtual void EmitInstToFragment(const MCInst &Inst, const MCSubtargetInfo &); +diff --git a/include/llvm/MC/MCStreamer.h b/include/llvm/MC/MCStreamer.h +index 5390e79..e28a3cc 100644 +--- a/include/llvm/MC/MCStreamer.h ++++ b/include/llvm/MC/MCStreamer.h +@@ -115,6 +115,7 @@ public: + virtual void emitPad(int64_t Offset); + virtual void emitRegSave(const SmallVectorImpl &RegList, + bool isVector); ++ virtual void emitLsda(const MCSymbol *Symbol); + virtual void emitUnwindRaw(int64_t StackOffset, + const SmallVectorImpl &Opcodes); + diff --git a/lib/MC/MCObjectStreamer.cpp b/lib/MC/MCObjectStreamer.cpp -index 174397e2739..ef7161fb56c 100644 +index 174397e..ef7161f 100644 --- a/lib/MC/MCObjectStreamer.cpp +++ b/lib/MC/MCObjectStreamer.cpp @@ -122,7 +122,7 @@ void MCObjectStreamer::EmitCFISections(bool EH, bool Debug) { @@ -46,7 +58,7 @@ index 174397e2739..ef7161fb56c 100644 // We need to create a local symbol to avoid relocations. Frame.Begin = getContext().createTempSymbol(); diff --git a/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp b/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp -index a77df7a2598..e1aa7526f9b 100644 +index a77df7a..e1aa752 100644 --- a/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp +++ b/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp @@ -48,6 +48,14 @@ public: @@ -84,7 +96,7 @@ index a77df7a2598..e1aa7526f9b 100644 return 2; case FK_SecRel_4: diff --git a/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.h b/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.h -index 02374966daf..01676a01683 100644 +index 0237496..01676a0 100644 --- a/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.h +++ b/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.h @@ -36,6 +36,7 @@ public: @@ -96,7 +108,7 @@ index 02374966daf..01676a01683 100644 bool shouldForceRelocation(const MCAssembler &Asm, const MCFixup &Fixup, diff --git a/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp b/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp -index 59f31be69d5..9b95598f99f 100644 +index 59f31be..9b95598 100644 --- a/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp +++ b/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp @@ -103,6 +103,9 @@ unsigned ARMELFObjectWriter::GetRelocTypeInner(const MCValue &Target, @@ -109,8 +121,102 @@ index 59f31be69d5..9b95598f99f 100644 case ARM::fixup_arm_blx: case ARM::fixup_arm_uncondbl: switch (Modifier) { +diff --git a/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp b/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp +index 93f4006..67ae439 100644 +--- a/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp ++++ b/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp +@@ -396,6 +396,7 @@ private: + void emitPad(int64_t Offset) override; + void emitRegSave(const SmallVectorImpl &RegList, + bool isVector) override; ++ void emitLsda(const MCSymbol *Symbol) override; + void emitUnwindRaw(int64_t Offset, + const SmallVectorImpl &Opcodes) override; + +@@ -461,6 +462,7 @@ public: + void emitMovSP(unsigned Reg, int64_t Offset = 0); + void emitPad(int64_t Offset); + void emitRegSave(const SmallVectorImpl &RegList, bool isVector); ++ void emitLsda(const MCSymbol *Symbol); + void emitUnwindRaw(int64_t Offset, const SmallVectorImpl &Opcodes); + + void ChangeSection(MCSection *Section, const MCExpr *Subsection) override { +@@ -698,6 +700,7 @@ private: + bool CantUnwind; + SmallVector Opcodes; + UnwindOpcodeAssembler UnwindOpAsm; ++ const MCSymbol *Lsda; + }; + + } // end anonymous namespace +@@ -740,6 +743,10 @@ void ARMTargetELFStreamer::emitRegSave(const SmallVectorImpl &RegList, + getStreamer().emitRegSave(RegList, isVector); + } + ++void ARMTargetELFStreamer::emitLsda(const MCSymbol *Symbol) { ++ getStreamer().emitLsda(Symbol); ++} ++ + void ARMTargetELFStreamer::emitUnwindRaw(int64_t Offset, + const SmallVectorImpl &Opcodes) { + getStreamer().emitUnwindRaw(Offset, Opcodes); +@@ -1233,6 +1240,7 @@ void ARMELFStreamer::EHReset() { + PendingOffset = 0; + UsedFP = false; + CantUnwind = false; ++ Lsda = nullptr; + + Opcodes.clear(); + UnwindOpAsm.Reset(); +@@ -1330,6 +1338,8 @@ void ARMELFStreamer::FlushUnwindOpcodes(bool NoHandlerData) { + } + + // Finalize the unwind opcode sequence ++ if (Lsda != nullptr && Opcodes.size() <= 4u) ++ PersonalityIndex = ARM::EHABI::AEABI_UNWIND_CPP_PR1; + UnwindOpAsm.Finalize(PersonalityIndex, Opcodes); + + // For compact model 0, we have to emit the unwind opcodes in the .ARM.exidx +@@ -1374,7 +1384,13 @@ void ARMELFStreamer::FlushUnwindOpcodes(bool NoHandlerData) { + // + // In case that the .handlerdata directive is not specified by the + // programmer, we should emit zero to terminate the handler data. +- if (NoHandlerData && !Personality) ++ if (Lsda != nullptr) { ++ const MCSymbolRefExpr *LsdaRef = ++ MCSymbolRefExpr::create(Lsda, ++ MCSymbolRefExpr::VK_None, ++ getContext()); ++ EmitValue(LsdaRef, 4); ++ } else if (NoHandlerData && !Personality) + EmitIntValue(0, 4); + } + +@@ -1457,6 +1473,10 @@ void ARMELFStreamer::emitRegSave(const SmallVectorImpl &RegList, + UnwindOpAsm.EmitRegSave(Mask); + } + ++void ARMELFStreamer::emitLsda(const MCSymbol *Symbol) { ++ Lsda = Symbol; ++} ++ + void ARMELFStreamer::emitUnwindRaw(int64_t Offset, + const SmallVectorImpl &Opcodes) { + FlushPendingOffset(); +diff --git a/lib/Target/ARM/MCTargetDesc/ARMTargetStreamer.cpp b/lib/Target/ARM/MCTargetDesc/ARMTargetStreamer.cpp +index 4a94318..f4f5aa1 100644 +--- a/lib/Target/ARM/MCTargetDesc/ARMTargetStreamer.cpp ++++ b/lib/Target/ARM/MCTargetDesc/ARMTargetStreamer.cpp +@@ -61,6 +61,7 @@ void ARMTargetStreamer::emitMovSP(unsigned Reg, int64_t Offset) {} + void ARMTargetStreamer::emitPad(int64_t Offset) {} + void ARMTargetStreamer::emitRegSave(const SmallVectorImpl &RegList, + bool isVector) {} ++void ARMTargetStreamer::emitLsda(const MCSymbol *Symbol) {} + void ARMTargetStreamer::emitUnwindRaw(int64_t StackOffset, + const SmallVectorImpl &Opcodes) { + } diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt -index b654b8c5cb8..58d25159af8 100644 +index b654b8c..58d2515 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -46,6 +46,7 @@ add_llvm_external_project(clang) diff --git a/external/corert/src/Native/ObjWriter/llvmCap/CMakeLists.txt b/external/corert/src/Native/ObjWriter/llvmCap/CMakeLists.txt index fd2e66ea16..a749ea8782 100644 --- a/external/corert/src/Native/ObjWriter/llvmCap/CMakeLists.txt +++ b/external/corert/src/Native/ObjWriter/llvmCap/CMakeLists.txt @@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.6) project(ObjWriter) include(ExternalProject) +set(LLVM_VERSION "5") set(OBJWRITER_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../) set(OBJWRITER_LLVM_POINT tools/ObjWriter) @@ -36,12 +37,11 @@ if(USE_ARM_TARGET_TRIPLE) list(APPEND LLVM_CMAKE_EXTRA_ARGS "-DLLVM_DEFAULT_TARGET_TRIPLE=thumbv7-linux-gnueabi") endif() -list(REMOVE_DUPLICATES CORERT_NATIVE_COMPILE_OPTIONS) - # Make sure to remove debug flags from general build flags for LLVM set(LLVM_COMPILE_OPTIONS "${CORERT_NATIVE_COMPILE_OPTIONS}") list(REMOVE_ITEM LLVM_COMPILE_OPTIONS "-g") list(REMOVE_ITEM LLVM_COMPILE_OPTIONS "-O0") +list(REMOVE_ITEM LLVM_COMPILE_OPTIONS "-Werror") string(REPLACE ";" "\ " CORERT_NATIVE_COMPILE_OPTIONS "${CORERT_NATIVE_COMPILE_OPTIONS}") string(REPLACE ";" "\ " LLVM_COMPILE_OPTIONS "${LLVM_COMPILE_OPTIONS}") @@ -49,19 +49,32 @@ string(REPLACE ";" "\ " LLVM_COMPILE_OPTIONS "${LLVM_COMPILE_OPTIONS}") # If host and target are the same, we could use llvm-tblgen from LLVM itself. # Otherwise we use host llvm-tblgen. It's universal way for cross-building. if(NOT ${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL ${CMAKE_SYSTEM_PROCESSOR}) - execute_process ( - COMMAND bash -c "echo -n `which llvm-tblgen`" - OUTPUT_VARIABLE LLVM_TBLGEN_TOOL - ) + # Find llvm-tblgen tool if(NOT LLVM_TBLGEN_TOOL) - message(FATAL_ERROR "Can't find llvm-tblgen. You need to make sure that you have installed LLVM") + execute_process ( + COMMAND bash -c "echo -n `which llvm-tblgen`" + OUTPUT_VARIABLE LLVM_TBLGEN_TOOL + ) + if(NOT LLVM_TBLGEN_TOOL) + message(FATAL_ERROR "Can't find llvm-tblgen! You need to make sure that you have installed LLVM version $LLVM_VERSION") + endif() endif() + + # Check compatibility + execute_process ( + COMMAND bash -c "echo -n `${LLVM_TBLGEN_TOOL} --version | grep -i 'version ${LLVM_VERSION}'`" + OUTPUT_VARIABLE IS_LLVM_TBLGEN_TOOL_COMPATIBLE + ) + if(NOT IS_LLVM_TBLGEN_TOOL_COMPATIBLE) + message(FATAL_ERROR "LLVM version incompatibility! You need to make sure that you have installed LLVM version ${LLVM_VERSION}") + endif() + list(APPEND LLVM_CMAKE_EXTRA_ARGS "-DLLVM_TABLEGEN=${LLVM_TBLGEN_TOOL}") endif() ExternalProject_Add(LLVM GIT_REPOSITORY https://github.com/llvm-mirror/llvm - GIT_TAG release_50 + GIT_TAG release_${LLVM_VERSION}0 GIT_SHALLOW 1 GIT_PROGRESS 1 PATCH_COMMAND "" diff --git a/external/corert/src/Native/ObjWriter/objwriter.cpp b/external/corert/src/Native/ObjWriter/objwriter.cpp index 7f81e070c3..55f79aa479 100644 --- a/external/corert/src/Native/ObjWriter/objwriter.cpp +++ b/external/corert/src/Native/ObjWriter/objwriter.cpp @@ -32,6 +32,7 @@ #include "llvm/MC/MCObjectStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCTargetOptionsCommandFlags.h" +#include "llvm/MC/MCELFStreamer.h" #include "llvm/BinaryFormat/COFF.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compression.h" @@ -373,6 +374,11 @@ int ObjectWriter::EmitSymbolRef(const char *SymbolName, Size = 4; IsPCRel = true; break; + case RelocType::IMAGE_REL_BASED_RELPTR32: + Size = 4; + IsPCRel = true; + Delta += 4; // size of C# (int) type is always 4 bytes + break; case RelocType::IMAGE_REL_BASED_THUMB_MOV32: { const unsigned Offset = GetDFSize(); const MCExpr *TargetExpr = GenTargetExpr(SymbolName, Kind, Delta); @@ -837,3 +843,56 @@ ObjectWriter::GetMemberFunctionId(const MemberFunctionIdTypeDescriptor& MemberId return TypeBuilder.GetMemberFunctionId(MemberIdDescriptor); } +void +ObjectWriter::EmitARMFnStart() { + MCTargetStreamer &TS = *(Streamer->getTargetStreamer()); + ARMTargetStreamer &ATS = static_cast(TS); + + ATS.emitFnStart(); +} + +void ObjectWriter::EmitARMFnEnd() { + MCTargetStreamer &TS = *(Streamer->getTargetStreamer()); + ARMTargetStreamer &ATS = static_cast(TS); + + ATS.emitFnEnd(); +} + +void ObjectWriter::EmitARMExIdxLsda(const char *LsdaBlobSymbolName) +{ + MCTargetStreamer &TS = *(Streamer->getTargetStreamer()); + ARMTargetStreamer &ATS = static_cast(TS); + + MCSymbol *T = OutContext->getOrCreateSymbol(LsdaBlobSymbolName); + Assembler->registerSymbol(*T); + + ATS.emitLsda(T); +} + +void ObjectWriter::EmitARMExIdxCode(int Offset, const char *Blob) +{ + MCTargetStreamer &TS = *(Streamer->getTargetStreamer()); + ARMTargetStreamer &ATS = static_cast(TS); + SmallVector RegList; + + const CFI_CODE *CfiCode = (const CFI_CODE *)Blob; + switch (CfiCode->CfiOpCode) { + case CFI_ADJUST_CFA_OFFSET: + assert(CfiCode->DwarfReg == DWARF_REG_ILLEGAL && + "Unexpected Register Value for OpAdjustCfaOffset"); + ATS.emitPad(CfiCode->Offset); + break; + case CFI_REL_OFFSET: + RegList.push_back(CfiCode->DwarfReg); + ATS.emitRegSave(RegList, false); + break; + case CFI_DEF_CFA_REGISTER: + assert(CfiCode->Offset == 0 && + "Unexpected Offset Value for OpDefCfaRegister"); + ATS.emitMovSP(CfiCode->DwarfReg, 0); + break; + default: + assert(false && "Unrecognized CFI"); + break; + } +} diff --git a/external/corert/src/Native/ObjWriter/objwriter.exports b/external/corert/src/Native/ObjWriter/objwriter.exports index c42c465df8..460b227381 100644 --- a/external/corert/src/Native/ObjWriter/objwriter.exports +++ b/external/corert/src/Native/ObjWriter/objwriter.exports @@ -23,4 +23,8 @@ GetCompleteClassTypeIndex GetArrayTypeIndex GetPointerTypeIndex GetMemberFunctionTypeIndex -GetMemberFunctionIdTypeIndex \ No newline at end of file +GetMemberFunctionIdTypeIndex +EmitARMFnStart +EmitARMFnEnd +EmitARMExIdxCode +EmitARMExIdxLsda \ No newline at end of file diff --git a/external/corert/src/Native/ObjWriter/objwriter.h b/external/corert/src/Native/ObjWriter/objwriter.h index 46b6bbd9ff..21327b3be9 100644 --- a/external/corert/src/Native/ObjWriter/objwriter.h +++ b/external/corert/src/Native/ObjWriter/objwriter.h @@ -24,6 +24,12 @@ using namespace llvm; using namespace llvm::codeview; +#ifdef _WIN32 +#define DLL_EXPORT extern "C" __declspec(dllexport) +#else +#define DLL_EXPORT extern "C" __attribute((visibility("default"))) +#endif + enum CustomSectionAttributes : int32_t { CustomSectionAttributes_ReadOnly = 0x0000, CustomSectionAttributes_Writeable = 0x0001, @@ -38,6 +44,7 @@ enum class RelocType { IMAGE_REL_BASED_DIR64 = 0x0A, IMAGE_REL_BASED_REL32 = 0x10, IMAGE_REL_BASED_THUMB_BRANCH24 = 0x13, + IMAGE_REL_BASED_RELPTR32 = 0x7C, }; class ObjectWriter { @@ -91,6 +98,11 @@ public: unsigned GetMemberFunctionId(const MemberFunctionIdTypeDescriptor& MemberIdDescriptor); + void EmitARMFnStart(); + void EmitARMFnEnd(); + void EmitARMExIdxCode(int Offset, const char *Blob); + void EmitARMExIdxLsda(const char *Blob); + private: void EmitLabelDiff(const MCSymbol *From, const MCSymbol *To, unsigned int Size = 4); @@ -155,7 +167,7 @@ private: // When object writer is created/initialized successfully, it is returned. // Or null object is returned. Client should check this. -extern "C" ObjectWriter *InitObjWriter(const char *ObjectFilePath) { +DLL_EXPORT ObjectWriter *InitObjWriter(const char *ObjectFilePath) { ObjectWriter *OW = new ObjectWriter(); if (OW->Init(ObjectFilePath)) { return OW; @@ -164,20 +176,20 @@ extern "C" ObjectWriter *InitObjWriter(const char *ObjectFilePath) { return nullptr; } -extern "C" void FinishObjWriter(ObjectWriter *OW) { +DLL_EXPORT void FinishObjWriter(ObjectWriter *OW) { assert(OW && "ObjWriter is null"); OW->Finish(); delete OW; } -extern "C" void SwitchSection(ObjectWriter *OW, const char *SectionName, +DLL_EXPORT void SwitchSection(ObjectWriter *OW, const char *SectionName, CustomSectionAttributes attributes, const char *ComdatName) { assert(OW && "ObjWriter is null"); OW->SwitchSection(SectionName, attributes, ComdatName); } -extern "C" void SetCodeSectionAttribute(ObjectWriter *OW, +DLL_EXPORT void SetCodeSectionAttribute(ObjectWriter *OW, const char *SectionName, CustomSectionAttributes attributes, const char *ComdatName) { @@ -185,80 +197,80 @@ extern "C" void SetCodeSectionAttribute(ObjectWriter *OW, OW->SetCodeSectionAttribute(SectionName, attributes, ComdatName); } -extern "C" void EmitAlignment(ObjectWriter *OW, int ByteAlignment) { +DLL_EXPORT void EmitAlignment(ObjectWriter *OW, int ByteAlignment) { assert(OW && "ObjWriter is null"); OW->EmitAlignment(ByteAlignment); } -extern "C" void EmitBlob(ObjectWriter *OW, int BlobSize, const char *Blob) { +DLL_EXPORT void EmitBlob(ObjectWriter *OW, int BlobSize, const char *Blob) { assert(OW && "ObjWriter null"); OW->EmitBlob(BlobSize, Blob); } -extern "C" void EmitIntValue(ObjectWriter *OW, uint64_t Value, unsigned Size) { +DLL_EXPORT void EmitIntValue(ObjectWriter *OW, uint64_t Value, unsigned Size) { assert(OW && "ObjWriter is null"); OW->EmitIntValue(Value, Size); } -extern "C" void EmitSymbolDef(ObjectWriter *OW, const char *SymbolName) { +DLL_EXPORT void EmitSymbolDef(ObjectWriter *OW, const char *SymbolName) { assert(OW && "ObjWriter is null"); OW->EmitSymbolDef(SymbolName); } -extern "C" int EmitSymbolRef(ObjectWriter *OW, const char *SymbolName, +DLL_EXPORT int EmitSymbolRef(ObjectWriter *OW, const char *SymbolName, RelocType RelocType, int Delta) { assert(OW && "ObjWriter is null"); return OW->EmitSymbolRef(SymbolName, RelocType, Delta); } -extern "C" void EmitWinFrameInfo(ObjectWriter *OW, const char *FunctionName, +DLL_EXPORT void EmitWinFrameInfo(ObjectWriter *OW, const char *FunctionName, int StartOffset, int EndOffset, const char *BlobSymbolName) { assert(OW && "ObjWriter is null"); OW->EmitWinFrameInfo(FunctionName, StartOffset, EndOffset, BlobSymbolName); } -extern "C" void EmitCFIStart(ObjectWriter *OW, int Offset) { +DLL_EXPORT void EmitCFIStart(ObjectWriter *OW, int Offset) { assert(OW && "ObjWriter is null"); OW->EmitCFIStart(Offset); } -extern "C" void EmitCFIEnd(ObjectWriter *OW, int Offset) { +DLL_EXPORT void EmitCFIEnd(ObjectWriter *OW, int Offset) { assert(OW && "ObjWriter is null"); OW->EmitCFIEnd(Offset); } -extern "C" void EmitCFILsda(ObjectWriter *OW, const char *LsdaBlobSymbolName) { +DLL_EXPORT void EmitCFILsda(ObjectWriter *OW, const char *LsdaBlobSymbolName) { assert(OW && "ObjWriter is null"); OW->EmitCFILsda(LsdaBlobSymbolName); } -extern "C" void EmitCFICode(ObjectWriter *OW, int Offset, const char *Blob) { +DLL_EXPORT void EmitCFICode(ObjectWriter *OW, int Offset, const char *Blob) { assert(OW && "ObjWriter is null"); OW->EmitCFICode(Offset, Blob); } -extern "C" void EmitDebugFileInfo(ObjectWriter *OW, int FileId, +DLL_EXPORT void EmitDebugFileInfo(ObjectWriter *OW, int FileId, const char *FileName) { assert(OW && "ObjWriter is null"); OW->EmitDebugFileInfo(FileId, FileName); } -extern "C" void EmitDebugFunctionInfo(ObjectWriter *OW, +DLL_EXPORT void EmitDebugFunctionInfo(ObjectWriter *OW, const char *FunctionName, int FunctionSize) { assert(OW && "ObjWriter is null"); OW->EmitDebugFunctionInfo(FunctionName, FunctionSize); } -extern "C" void EmitDebugVar(ObjectWriter *OW, char *Name, int TypeIndex, +DLL_EXPORT void EmitDebugVar(ObjectWriter *OW, char *Name, int TypeIndex, bool IsParam, int RangeCount, ICorDebugInfo::NativeVarInfo *Ranges) { assert(OW && "ObjWriter is null"); OW->EmitDebugVar(Name, TypeIndex, IsParam, RangeCount, Ranges); } -extern "C" void EmitDebugLoc(ObjectWriter *OW, int NativeOffset, int FileId, +DLL_EXPORT void EmitDebugLoc(ObjectWriter *OW, int NativeOffset, int FileId, int LineNumber, int ColNumber) { assert(OW && "ObjWriter is null"); OW->EmitDebugLoc(NativeOffset, FileId, LineNumber, ColNumber); @@ -266,25 +278,25 @@ extern "C" void EmitDebugLoc(ObjectWriter *OW, int NativeOffset, int FileId, // This should be invoked at the end of module emission to finalize // debug module info. -extern "C" void EmitDebugModuleInfo(ObjectWriter *OW) { +DLL_EXPORT void EmitDebugModuleInfo(ObjectWriter *OW) { assert(OW && "ObjWriter is null"); OW->EmitDebugModuleInfo(); } -extern "C" unsigned GetEnumTypeIndex(ObjectWriter *OW, +DLL_EXPORT unsigned GetEnumTypeIndex(ObjectWriter *OW, EnumTypeDescriptor TypeDescriptor, EnumRecordTypeDescriptor *TypeRecords) { assert(OW && "ObjWriter is null"); return OW->GetEnumTypeIndex(TypeDescriptor, TypeRecords); } -extern "C" unsigned GetClassTypeIndex(ObjectWriter *OW, +DLL_EXPORT unsigned GetClassTypeIndex(ObjectWriter *OW, ClassTypeDescriptor ClassDescriptor) { assert(OW && "ObjWriter is null"); return OW->GetClassTypeIndex(ClassDescriptor); } -extern "C" unsigned +DLL_EXPORT unsigned GetCompleteClassTypeIndex(ObjectWriter *OW, ClassTypeDescriptor ClassDescriptor, ClassFieldsTypeDescriptior ClassFieldsDescriptor, DataFieldDescriptor *FieldsDescriptors) { @@ -293,28 +305,48 @@ GetCompleteClassTypeIndex(ObjectWriter *OW, ClassTypeDescriptor ClassDescriptor, FieldsDescriptors); } -extern "C" unsigned GetArrayTypeIndex(ObjectWriter *OW, +DLL_EXPORT unsigned GetArrayTypeIndex(ObjectWriter *OW, ClassTypeDescriptor ClassDescriptor, ArrayTypeDescriptor ArrayDescriptor) { assert(OW && "ObjWriter is null"); return OW->GetArrayTypeIndex(ClassDescriptor, ArrayDescriptor); } -extern "C" unsigned GetPointerTypeIndex(ObjectWriter *OW, +DLL_EXPORT unsigned GetPointerTypeIndex(ObjectWriter *OW, PointerTypeDescriptor PointerDescriptor) { assert(OW && "ObjWriter is null"); return OW->GetPointerTypeIndex(PointerDescriptor); } -extern "C" unsigned GetMemberFunctionTypeIndex(ObjectWriter *OW, +DLL_EXPORT unsigned GetMemberFunctionTypeIndex(ObjectWriter *OW, MemberFunctionTypeDescriptor MemberDescriptor, uint32_t *ArgumentTypes) { assert(OW && "ObjWriter is null"); return OW->GetMemberFunctionTypeIndex(MemberDescriptor, ArgumentTypes); } -extern "C" unsigned GetMemberFunctionIdTypeIndex(ObjectWriter *OW, +DLL_EXPORT unsigned GetMemberFunctionIdTypeIndex(ObjectWriter *OW, MemberFunctionIdTypeDescriptor MemberIdDescriptor) { assert(OW && "ObjWriter is null"); return OW->GetMemberFunctionId(MemberIdDescriptor); } + +DLL_EXPORT void EmitARMFnStart(ObjectWriter *OW) { + assert(OW && "ObjWriter is null"); + return OW->EmitARMFnStart(); +} + +DLL_EXPORT void EmitARMFnEnd(ObjectWriter *OW) { + assert(OW && "ObjWriter is null"); + return OW->EmitARMFnEnd(); +} + +DLL_EXPORT void EmitARMExIdxLsda(ObjectWriter *OW, const char *Blob) { + assert(OW && "ObjWriter is null"); + return OW->EmitARMExIdxLsda(Blob); +} + +DLL_EXPORT void EmitARMExIdxCode(ObjectWriter *OW, int Offset, const char *Blob) { + assert(OW && "ObjWriter is null"); + return OW->EmitARMExIdxCode(Offset, Blob); +} diff --git a/external/corert/src/Native/Runtime/AsmOffsets.h b/external/corert/src/Native/Runtime/AsmOffsets.h index 299454a287..34b8e5fd81 100644 --- a/external/corert/src/Native/Runtime/AsmOffsets.h +++ b/external/corert/src/Native/Runtime/AsmOffsets.h @@ -50,8 +50,11 @@ ASM_OFFSET( 2c, 40, Thread, m_pTransitionFrame) ASM_OFFSET( 30, 48, Thread, m_pHackPInvokeTunnel) ASM_OFFSET( 40, 68, Thread, m_ppvHijackedReturnAddressLocation) ASM_OFFSET( 44, 70, Thread, m_pvHijackedReturnAddress) -ASM_OFFSET( 48, 78, Thread, m_pExInfoStackHead) -ASM_OFFSET( 4c, 80, Thread, m_threadAbortException) +#ifdef BIT64 +ASM_OFFSET( 0, 78, Thread, m_uHijackedReturnValueFlags) +#endif +ASM_OFFSET( 48, 80, Thread, m_pExInfoStackHead) +ASM_OFFSET( 4c, 88, Thread, m_threadAbortException) ASM_SIZEOF( 14, 20, EHEnum) diff --git a/external/corert/src/Native/Runtime/AsmOffsetsVerify.cpp b/external/corert/src/Native/Runtime/AsmOffsetsVerify.cpp index 2e7343ce1e..13793b7e6c 100644 --- a/external/corert/src/Native/Runtime/AsmOffsetsVerify.cpp +++ b/external/corert/src/Native/Runtime/AsmOffsetsVerify.cpp @@ -44,3 +44,7 @@ class AsmOffsets #include "AsmOffsets.h" }; + +#ifdef _MSC_VER +namespace { char WorkaroundLNK4221Warning; }; +#endif diff --git a/external/corert/src/Native/Runtime/CachedInterfaceDispatch.cpp b/external/corert/src/Native/Runtime/CachedInterfaceDispatch.cpp index c49d13129e..63a506bafc 100644 --- a/external/corert/src/Native/Runtime/CachedInterfaceDispatch.cpp +++ b/external/corert/src/Native/Runtime/CachedInterfaceDispatch.cpp @@ -510,7 +510,7 @@ COOP_PINVOKE_HELPER(PTR_Code, RhpUpdateDispatchCellCache, (InterfaceDispatchCell // Publish the new cache by atomically updating both the cache and stub pointers in the indirection // cell. This returns us a cache to discard which may be NULL (no previous cache), the previous cache - // value or the cache we just allocated (another thread peformed an update first). + // value or the cache we just allocated (another thread performed an update first). InterfaceDispatchCache * pDiscardedCache = UpdateCellStubAndCache(pCell, pStub, newCacheValue); if (pDiscardedCache) DiscardCache(pDiscardedCache); diff --git a/external/corert/src/Native/Runtime/DebugFuncEval.cpp b/external/corert/src/Native/Runtime/DebugFuncEval.cpp index ae920a46a4..e5362eaa4f 100644 --- a/external/corert/src/Native/Runtime/DebugFuncEval.cpp +++ b/external/corert/src/Native/Runtime/DebugFuncEval.cpp @@ -5,11 +5,14 @@ #include "common.h" #include "CommonTypes.h" #include "DebugFuncEval.h" +#include "rhassert.h" +#include "RWLock.h" +#include "slist.h" +#include "RuntimeInstance.h" GVAL_IMPL_INIT(UInt32, g_FuncEvalMode, 0); GVAL_IMPL_INIT(UInt32, g_FuncEvalParameterBufferSize, 0); GVAL_IMPL_INIT(UInt64, g_MostRecentFuncEvalHijackInstructionPointer, 0); -GPTR_IMPL_INIT(PTR_VOID, g_HighLevelDebugFuncEvalAbortHelperAddr, 0); #ifndef DACCESS_COMPILE @@ -28,16 +31,6 @@ GPTR_IMPL_INIT(PTR_VOID, g_HighLevelDebugFuncEvalAbortHelperAddr, 0); return g_MostRecentFuncEvalHijackInstructionPointer; } -/* static */ HighLevelDebugFuncEvalAbortHelperType DebugFuncEval::GetHighLevelDebugFuncEvalAbortHelper() -{ - return (HighLevelDebugFuncEvalAbortHelperType)g_HighLevelDebugFuncEvalAbortHelperAddr; -} - -/* static */ void DebugFuncEval::SetHighLevelDebugFuncEvalAbortHelper(HighLevelDebugFuncEvalAbortHelperType highLevelDebugFuncEvalAbortHelper) -{ - g_HighLevelDebugFuncEvalAbortHelperAddr = (PTR_PTR_VOID)highLevelDebugFuncEvalAbortHelper; -} - /// /// Retrieve the global FuncEval parameter buffer size. /// @@ -73,22 +66,12 @@ EXTERN_C REDHAWK_API UInt32 __cdecl RhpGetFuncEvalMode() /// /// This is the entry point of FuncEval abort /// When the debugger decides to abort the FuncEval, it will create a remote thread calling this function. -/// This function will call back into the highLevelDebugFuncEvalAbortHelper to perform the abort. +/// This function will call back into the DebugFuncEvalAbortHelper to perform the abort. EXTERN_C REDHAWK_API void __cdecl RhpInitiateFuncEvalAbort(void* pointerFromDebugger) { - HighLevelDebugFuncEvalAbortHelperType highLevelDebugFuncEvalAbortHelper = DebugFuncEval::GetHighLevelDebugFuncEvalAbortHelper(); - highLevelDebugFuncEvalAbortHelper((UInt64)pointerFromDebugger); -} - -/// -/// Set the high level debug func eval abort helper -/// -/// -/// The high level debug func eval abort helper is a function that perform the actual func eval abort -/// It is implemented in System.Private.Debug.dll -EXTERN_C REDHAWK_API void __cdecl RhpSetHighLevelDebugFuncEvalAbortHelper(HighLevelDebugFuncEvalAbortHelperType highLevelDebugFuncEvalAbortHelper) -{ - DebugFuncEval::SetHighLevelDebugFuncEvalAbortHelper(highLevelDebugFuncEvalAbortHelper); + DebugFuncEvalAbortHelperFunctionType debugFuncEvalAbortHelperFunction = (DebugFuncEvalAbortHelperFunctionType)GetRuntimeInstance()->GetClasslibFunctionFromCodeAddress((void*)g_MostRecentFuncEvalHijackInstructionPointer, ClasslibFunctionId::DebugFuncEvalAbortHelper); + ASSERT(debugFuncEvalAbortHelperFunction != nullptr); + debugFuncEvalAbortHelperFunction((Int64)pointerFromDebugger); } #else @@ -103,4 +86,4 @@ UInt64 DebugFuncEval::GetMostRecentFuncEvalHijackInstructionPointer() EXTERN_C void * RhpDebugFuncEvalHelper; GPTR_IMPL_INIT(PTR_VOID, g_RhpDebugFuncEvalHelperAddr, &RhpDebugFuncEvalHelper); -GPTR_IMPL_INIT(PTR_VOID, g_RhpInitiateFuncEvalAbortAddr, (void**)&RhpInitiateFuncEvalAbort); \ No newline at end of file +GPTR_IMPL_INIT(PTR_VOID, g_RhpInitiateFuncEvalAbortAddr, (void**)&RhpInitiateFuncEvalAbort); diff --git a/external/corert/src/Native/Runtime/DebugFuncEval.h b/external/corert/src/Native/Runtime/DebugFuncEval.h index 20315c35a7..dc9c25efca 100644 --- a/external/corert/src/Native/Runtime/DebugFuncEval.h +++ b/external/corert/src/Native/Runtime/DebugFuncEval.h @@ -15,7 +15,7 @@ #ifndef DACCESS_COMPILE -typedef void(*HighLevelDebugFuncEvalAbortHelperType)(UInt64); +typedef void(*DebugFuncEvalAbortHelperFunctionType)(UInt64); class DebugFuncEval { @@ -51,18 +51,6 @@ public: /// It is used for the stack walker to understand the hijack frame /// static UInt64 GetMostRecentFuncEvalHijackInstructionPointer(); - - /// - /// Retrieve the high level debug func eval abort helper - /// - static HighLevelDebugFuncEvalAbortHelperType GetHighLevelDebugFuncEvalAbortHelper(); - - - /// - /// Set the high level debug func eval abort helper - /// - static void SetHighLevelDebugFuncEvalAbortHelper(HighLevelDebugFuncEvalAbortHelperType highLevelDebugFuncEvalAbortHelper); - }; #else diff --git a/external/corert/src/Native/Runtime/EHHelpers.cpp b/external/corert/src/Native/Runtime/EHHelpers.cpp index fd3c2f7a69..4a8adf62ea 100644 --- a/external/corert/src/Native/Runtime/EHHelpers.cpp +++ b/external/corert/src/Native/Runtime/EHHelpers.cpp @@ -28,29 +28,6 @@ #include "rhbinder.h" #include "eetype.h" -// Find the code manager containing the given address, which might be a return address from a managed function. The -// address may be to another managed function, or it may be to an unmanaged function. The address may also refer to -// an EEType. -static ICodeManager * FindCodeManagerForClasslibFunction(void * address) -{ - RuntimeInstance * pRI = GetRuntimeInstance(); - - // Try looking up the code manager assuming the address is for code first. This is expected to be most common. - ICodeManager * pCodeManager = pRI->FindCodeManagerByAddress(address); - if (pCodeManager != NULL) - return pCodeManager; - - // Less common, we will look for the address in any of the sections of the module. This is slower, but is - // necessary for EEType pointers and jump stubs. - Module * pModule = pRI->FindModuleByAddress(address); - if (pModule != NULL) - return pModule; - - ASSERT_MSG(!Thread::IsHijackTarget(address), "not expected to be called with hijacked return address"); - - return NULL; -} - COOP_PINVOKE_HELPER(Boolean, RhpEHEnumInitFromStackFrameIterator, ( StackFrameIterator* pFrameIter, void ** pMethodStartAddressOut, EHEnum* pEHEnum)) { @@ -70,18 +47,7 @@ COOP_PINVOKE_HELPER(Boolean, RhpEHEnumNext, (EHEnum* pEHEnum, EHClause* pEHClaus // found via the provided address does not have the necessary exports. COOP_PINVOKE_HELPER(void *, RhpGetClasslibFunctionFromCodeAddress, (void * address, ClasslibFunctionId functionId)) { - // Find the code manager for the given address, which is an address into some managed module. It could - // be code, or it could be an EEType. No matter what, it's an address into a managed module in some non-Rtm - // type system. - ICodeManager * pCodeManager = FindCodeManagerForClasslibFunction(address); - - // If the address isn't in a managed module then we have no classlib function. - if (pCodeManager == NULL) - { - return NULL; - } - - return pCodeManager->GetClasslibFunction(functionId); + return GetRuntimeInstance()->GetClasslibFunctionFromCodeAddress(address, functionId); } // Unmanaged helper to locate one of two classlib-provided functions that the runtime needs to @@ -139,8 +105,7 @@ COOP_PINVOKE_HELPER(Int32, RhGetModuleFileName, (HANDLE moduleHandle, _Out_ cons return PalGetModuleFileName(pModuleNameOut, moduleHandle); } -COOP_PINVOKE_HELPER(void, RhpCopyContextFromExInfo, - (void * pOSContext, Int32 cbOSContext, PAL_LIMITED_CONTEXT * pPalContext)) +COOP_PINVOKE_HELPER(void, RhpCopyContextFromExInfo, (void * pOSContext, Int32 cbOSContext, PAL_LIMITED_CONTEXT * pPalContext)) { UNREFERENCED_PARAMETER(cbOSContext); ASSERT(cbOSContext >= sizeof(CONTEXT)); @@ -214,9 +179,7 @@ COOP_PINVOKE_HELPER(void, RhpCopyContextFromExInfo, #endif } - #if defined(_AMD64_) || defined(_ARM_) || defined(_X86_) || defined(_ARM64_) -// ARM64TODO struct DISPATCHER_CONTEXT { UIntNative ControlPc; @@ -238,9 +201,9 @@ EXTERN_C void REDHAWK_CALLCONV RhpFailFastForPInvokeExceptionCoop(IntNative PInv Int32 __stdcall RhpVectoredExceptionHandler(PEXCEPTION_POINTERS pExPtrs); EXTERN_C Int32 __stdcall RhpPInvokeExceptionGuard(PEXCEPTION_RECORD pExceptionRecord, - UIntNative EstablisherFrame, - PCONTEXT pContextRecord, - DISPATCHER_CONTEXT * pDispatcherContext) + UIntNative EstablisherFrame, + PCONTEXT pContextRecord, + DISPATCHER_CONTEXT * pDispatcherContext) { UNREFERENCED_PARAMETER(EstablisherFrame); #ifdef APP_LOCAL_RUNTIME @@ -268,7 +231,6 @@ EXTERN_C Int32 __stdcall RhpPInvokeExceptionGuard(PEXCEPTION_RECORD pExcep if (pThread->IsDoNotTriggerGcSet()) RhFailFast(); - // We promote exceptions that were not converted to managed exceptions to a FailFast. However, we have to // be careful because we got here via OS SEH infrastructure and, therefore, don't know what GC mode we're // currently in. As a result, since we're calling back into managed code to handle the FailFast, we must @@ -423,7 +385,8 @@ static UIntNative UnwindWriteBarrierToCaller( #ifdef PLATFORM_UNIX -Int32 __stdcall RhpHardwareExceptionHandler(UIntNative faultCode, UIntNative faultAddress, PAL_LIMITED_CONTEXT* palContext, UIntNative* arg0Reg, UIntNative* arg1Reg) +Int32 __stdcall RhpHardwareExceptionHandler(UIntNative faultCode, UIntNative faultAddress, + PAL_LIMITED_CONTEXT* palContext, UIntNative* arg0Reg, UIntNative* arg1Reg) { UIntNative faultingIP = palContext->GetIp(); @@ -545,5 +508,4 @@ COOP_PINVOKE_HELPER(void, RhpFallbackFailFast, ()) RhFailFast(); } - #endif // !DACCESS_COMPILE diff --git a/external/corert/src/Native/Runtime/ICodeManager.h b/external/corert/src/Native/Runtime/ICodeManager.h index efd5054d28..fe4eb6ce99 100644 --- a/external/corert/src/Native/Runtime/ICodeManager.h +++ b/external/corert/src/Native/Runtime/ICodeManager.h @@ -3,6 +3,8 @@ // See the LICENSE file in the project root for more information. #pragma once +#define ICODEMANAGER_INCLUDED + // TODO: Debugger/DAC support (look for TODO: JIT) struct REGDISPLAY; @@ -23,14 +25,43 @@ struct GCEnumContext GCEnumCallback pCallback; }; +// All values but GCRK_Unknown must correspond to MethodReturnKind enumeration in gcinfo.h enum GCRefKind : unsigned char -{ - GCRK_Scalar = 0x00, - GCRK_Object = 0x01, - GCRK_Byref = 0x02, - GCRK_Unknown = 0xFF, +{ + GCRK_Scalar = 0x00, + GCRK_Object = 0x01, + GCRK_Byref = 0x02, +#ifdef _TARGET_ARM64_ + // Composite return kinds for value types returned in two registers (encoded with two bits per register) + GCRK_Scalar_Obj = (GCRK_Object << 2) | GCRK_Scalar, + GCRK_Obj_Obj = (GCRK_Object << 2) | GCRK_Object, + GCRK_Byref_Obj = (GCRK_Object << 2) | GCRK_Byref, + GCRK_Scalar_Byref = (GCRK_Byref << 2) | GCRK_Scalar, + GCRK_Obj_Byref = (GCRK_Byref << 2) | GCRK_Object, + GCRK_Byref_Byref = (GCRK_Byref << 2) | GCRK_Byref, + + GCRK_LastValid = GCRK_Byref_Byref, +#else // _TARGET_ARM64_ + GCRK_LastValid = GCRK_Byref, +#endif // _TARGET_ARM64_ + GCRK_Unknown = 0xFF, }; +#ifdef _TARGET_ARM64_ +// Extract individual GCRefKind components from a composite return kind +inline GCRefKind ExtractReg0ReturnKind(GCRefKind returnKind) +{ + ASSERT(returnKind <= GCRK_LastValid); + return (GCRefKind)(returnKind & (GCRK_Object | GCRK_Byref)); +} + +inline GCRefKind ExtractReg1ReturnKind(GCRefKind returnKind) +{ + ASSERT(returnKind <= GCRK_LastValid); + return (GCRefKind)(returnKind >> 2); +} +#endif // _TARGET_ARM64_ + // // MethodInfo is placeholder type used to allocate space for MethodInfo. Maximum size // of the actual method should be less or equal to the placeholder size. @@ -66,9 +97,7 @@ struct EHClause void* m_pTargetType; }; -// Constants used with RhpGetClasslibFunction, to indicate which classlib function -// we are interested in. -// Note: make sure you change the def in System\Runtime\exceptionhandling.cs if you change this! +// Note: make sure you change the def in System\Runtime\InternalCalls.cs if you change this! enum class ClasslibFunctionId { GetRuntimeException = 0, @@ -78,6 +107,8 @@ enum class ClasslibFunctionId CheckStaticClassConstruction = 4, GetSystemArrayEEType = 5, OnFirstChanceException = 6, + DebugFuncEvalHelper = 7, + DebugFuncEvalAbortHelper = 8, }; enum class AssociatedDataFlags : unsigned char diff --git a/external/corert/src/Native/Runtime/MiscHelpers.cpp b/external/corert/src/Native/Runtime/MiscHelpers.cpp index 05811e91da..c745715876 100644 --- a/external/corert/src/Native/Runtime/MiscHelpers.cpp +++ b/external/corert/src/Native/Runtime/MiscHelpers.cpp @@ -553,9 +553,19 @@ COOP_PINVOKE_HELPER(UInt8 *, RhGetCodeTarget, (UInt8 * pCodeOrg)) pCode++; } // is this an indirect jump? - if (/* ARM64TODO */ false) + // adrp xip0,#imm21; ldr xip0,[xip0,#imm12]; br xip0 + if ((pCode[0] & 0x9f00001f) == 0x90000010 && + (pCode[1] & 0xffc003ff) == 0xf9400210 && + pCode[2] == 0xd61f0200) { - // ARM64TODO + // normal import stub - dist to IAT cell is relative to (PC & ~0xfff) + // adrp: imm = SignExtend(immhi:immlo:Zeros(12), 64); + Int64 distToIatCell = (((((Int64)pCode[0] & ~0x1f) << 40) >> 31) | ((pCode[0] >> 17) & 0x3000)); + // ldr: offset = LSL(ZeroExtend(imm12, 64), 3); + distToIatCell += (pCode[1] >> 7) & 0x7ff8; + UInt8 ** pIatCell = (UInt8 **)(((Int64)pCode & ~0xfff) + distToIatCell); + ASSERT(pModule == NULL || pModule->ContainsDataAddress(pIatCell)); + return *pIatCell; } // is this an unboxing stub followed by a relative jump? else if (unboxingStub && (pCode[0] >> 26) == 0x5) @@ -697,7 +707,7 @@ COOP_PINVOKE_HELPER(Boolean, RhpArrayCopy, (Array * pSourceArray, Int32 sourceIn // // This function handles all cases of Array.Clear that do not require conversions. It returns false if the operation cannot be performed, leaving -// the handling of the complex cases or throwing apppropriate exception to the higher level framework. It is only allowed to return false for illegal +// the handling of the complex cases or throwing appropriate exception to the higher level framework. It is only allowed to return false for illegal // calls as the BCL side has fallback for "complex cases" only. // COOP_PINVOKE_HELPER(Boolean, RhpArrayClear, (Array * pArray, Int32 index, Int32 length)) diff --git a/external/corert/src/Native/Runtime/Portable/CMakeLists.txt b/external/corert/src/Native/Runtime/Portable/CMakeLists.txt index f191db46d3..21dbb7d7c9 100644 --- a/external/corert/src/Native/Runtime/Portable/CMakeLists.txt +++ b/external/corert/src/Native/Runtime/Portable/CMakeLists.txt @@ -26,9 +26,9 @@ else() endif() add_custom_command( - # The AsmOffsets.cs is consumed later by the managed build + # The AsmOffsetsPortable.cs is consumed later by the managed build TARGET PortableRuntime - COMMAND ${CMAKE_CXX_COMPILER} ${COMPILER_LANGUAGE} ${DEFINITIONS} ${PREPROCESSOR_FLAGS} -I"${ARCH_SOURCES_DIR}" "${ASM_OFFSETS_CSPP}" >"${CMAKE_CURRENT_BINARY_DIR}/AsmOffsets.cs" + COMMAND ${CMAKE_CXX_COMPILER} ${COMPILER_LANGUAGE} ${DEFINITIONS} ${PREPROCESSOR_FLAGS} -I"${ARCH_SOURCES_DIR}" "${ASM_OFFSETS_CSPP}" >"${CMAKE_CURRENT_BINARY_DIR}/AsmOffsetsPortable.cs" DEPENDS "${RUNTIME_DIR}/AsmOffsets.cpp" "${RUNTIME_DIR}/AsmOffsets.h" ) diff --git a/external/corert/src/Native/Runtime/RHCodeMan.cpp b/external/corert/src/Native/Runtime/RHCodeMan.cpp index 9eefba4e06..b6a173bb27 100644 --- a/external/corert/src/Native/Runtime/RHCodeMan.cpp +++ b/external/corert/src/Native/Runtime/RHCodeMan.cpp @@ -97,7 +97,7 @@ void ReportRegisterSet(UInt8 regSet, REGDISPLAY * pContext, GCEnumContext * hCal { // 2. 00lRRRRR - normal "register set" encoding, pinned and interior attributes both false // a. l - this is the last descriptor - // b. RRRRR - this is the register mask for { r4, r5, r6, r7, r8 } + // b. RRRRR - this is the register mask for { r4-r8 } if (regSet & CSR_MASK_R4) { ReportObject(hCallback, GetRegObjectAddr(pContext), 0); } if (regSet & CSR_MASK_R5) { ReportObject(hCallback, GetRegObjectAddr(pContext), 0); } @@ -373,9 +373,10 @@ void ReportLocalSlots(UInt8 localsEnc, REGDISPLAY * pContext, GCEnumContext * hC { // 4. 10l1SSSS - "local stack slot set" encoding, pinned and interior attributes both false // a. l - last descriptor - // b. SSSS - set of "local slots" #0 - #3 - local slot 0 is at offset -8 from the last pushed - // callee saved register, local slot 1 is at offset - 16, etc - in other words, these are the - // slots normally used for locals + // b. SSSS - set of "local slots" #0-#3 - local slot #0 is at offset -POINTER_SIZE from + // the last pushed callee saved register, local slot #1 is at offset -2*POINTER_SIZE, + // etc - in other words, these are the slots normally used for locals. The non-sensical + // encoding with SSSS = 0000 is reserved for the "common vars" case 8 below. if (localsEnc & 0x01) { ReportLocalSlot(0, pContext, hCallback, pHeader); } if (localsEnc & 0x02) { ReportLocalSlot(1, pContext, hCallback, pHeader); } if (localsEnc & 0x04) { ReportLocalSlot(2, pContext, hCallback, pHeader); } @@ -385,7 +386,7 @@ void ReportLocalSlots(UInt8 localsEnc, REGDISPLAY * pContext, GCEnumContext * hC { // 5. 10l0ssss - "local slot" encoding, pinned and interior attributes are both false // a. l - last descriptor - // b. ssss - "local slot" #4 - #19 + // b. ssss - "local slot" #4-#19 (#0-#3 are encoded by case 4 above) UInt32 localNum = (localsEnc & 0xF) + 4; ReportLocalSlot(localNum, pContext, hCallback, pHeader); } @@ -401,10 +402,10 @@ void ReportStackSlots(UInt8 firstEncByte, REGDISPLAY * pContext, GCEnumContext * // e. s - offset sign // f. m - mask follows // g. offset - variable length unsigned integer - // h. mask - variable length unsigned integer (only present if m-bit is 1) - this can describe - // multiple stack locations with the same attributes. E.g., if you want to describe stack - // locations 0x20, 0x28, 0x38, you would give a (starting) offset of 0x20 and a mask of - // 000000101 = 0x05. Up to 33 stack locations can be described. + // h. mask - variable length unsigned integer (only present if m-bit is 1) - describes multiple + // (up to 33) stack locations having the same attributes. E.g., to describe stack locations + // 0x20, 0x28, 0x38, you specify the starting offset 0x20 and the mask 000000101 = 0x5. + // The mask describes the next 32 stack locations after the first one. UInt32 flags = 0; if (firstEncByte & 0x08) { flags |= GC_CALL_PINNED; } @@ -478,7 +479,7 @@ void ReportScratchRegs(UInt8 firstEncByte, REGDISPLAY * pContext, GCEnumContext // e. IIIIIII - interior scratch register mask for { rax, rcx, rdx, r8, r9, r10, r11 } iff 'i' is 1 // f. PPPPPPP - pinned scratch register mask for { rax, rcx, rdx, r8, r9, r10, r11 } iff 'p' is 1 // - // For ARM64 the scheme above is extended to support the bigger register set: + // For ARM64 the scheme above is extended to support the larger register set: // - 11lip010 0RRRRRRR [0IIIIIII] [0PPPPPPP] for { x0-x6 } // - 11lip010 1RRRRRRR 0RRRRRRR [[1IIIIIII] 0IIIIIII] [[1PPPPPPP] 0PPPPPPP] for { x0-x13 } // - 11lip010 1RRRRRRR 1RRRRRRR 000RRRRR [0*2(1IIIIIII) 000IIIII] [0*2(1PPPPPPP) 000PPPPP] for { x0-x15, xip0, xip1, lr } @@ -505,7 +506,7 @@ void ReportScratchRegs(UInt8 firstEncByte, REGDISPLAY * pContext, GCEnumContext } // Enumerate all live object references in that function using the virtual register set. Same reference -// location cannot be enumerated multiple times (but all differenct references pointing to the same object +// location cannot be enumerated multiple times (but all different references pointing to the same object // have to be individually enumerated). // Returns success of operation. void EECodeManager::EnumGcRefs(MethodGcInfoPointers * pMethodInfo, @@ -632,7 +633,7 @@ ContinueUnconditionally: // a. l - this is the last descriptor // b. RRRRR - this is the register mask for { rbx, rsi, rdi, rbp, r12 }, ARM = { r4-r8 } // - // For ARM64 the scheme above is extended to support the bigger register set: + // For ARM64 the scheme above is extended to support the larger register set: // 00lvRRRR [RRRRRRRR] - normal "register set" encoding, pinned and interior attributes both false // a. l - this is the last descriptor // b. v - extra byte follows @@ -648,14 +649,14 @@ ContinueUnconditionally: // // 4. 10l1SSSS - "local stack slot set" encoding, pinned and interior attributes both false // a. l - last descriptor - // b. SSSS - set of "local slots" #0 - #3 - local slot 0 is at offset -8 from the last pushed - // callee saved register, local slot 1 is at offset - 16, etc - in other words, these are the - // slots normally used for locals. The non-sensical encoding with SSSS = 0000 is reserved for - // the "common vars" case under 8 below. + // b. SSSS - set of "local slots" #0-#3 - local slot #0 is at offset -POINTER_SIZE from + // the last pushed callee saved register, local slot #1 is at offset -2*POINTER_SIZE, + // etc - in other words, these are the slots normally used for locals. The non-sensical + // encoding with SSSS = 0000 is reserved for the "common vars" case 8 below. // - // 5. 10l0ssss - "local slot" encoding + // 5. 10l0ssss - "local slot" encoding, pinned and interior attributes are both false // a. l - last descriptor - // b. ssss - "local slot" #4 - #19 + // b. ssss - "local slot" #4-#19 (#0-#3 are encoded by case 4 above) // // 6. 11lipfsm {offset} [mask] - [multiple] stack slot encoding // a. l - last descriptor @@ -665,10 +666,10 @@ ContinueUnconditionally: // e. s - offset sign // f. m - mask follows // g. offset - variable length unsigned integer - // h. mask - variable length unsigned integer (only present if m-bit is 1) - this can describe - // multiple stack locations with the same attributes. E.g., if you want to describe stack - // locations 0x20, 0x28, 0x38, you would give a (starting) offset of 0x20 and a mask of - // 000000101 = 0x05. Up to 33 stack locations can be described. + // h. mask - variable length unsigned integer (only present if m-bit is 1) - describes multiple + // (up to 33) stack locations having the same attributes. E.g., to describe stack locations + // 0x20, 0x28, 0x38, you specify the starting offset 0x20 and the mask 000000101 = 0x5. + // The mask describes the next 32 stack locations after the first one. // // 7. 11lip010 0RRRRRRR [0IIIIIII] [0PPPPPPP] - live scratch reg reporting, this uses the SP-xxx encoding // from #6 since we cannot have stack locations at negative @@ -680,7 +681,7 @@ ContinueUnconditionally: // e. IIIIIII - interior scratch register mask for { rax, rcx, rdx, r8, r9, r10, r11 } iff 'i' is 1 // f. PPPPPPP - pinned scratch register mask for { rax, rcx, rdx, r8, r9, r10, r11 } iff 'p' is 1 // - // For ARM64 the scheme above is extended to support the bigger register set: + // For ARM64 the scheme above is extended to support the larger register set: // - 11lip010 0RRRRRRR [0IIIIIII] [0PPPPPPP] for { x0-x6 } // - 11lip010 1RRRRRRR 0RRRRRRR [[1IIIIIII] 0IIIIIII] [[1PPPPPPP] 0PPPPPPP] for { x0-x13 } // - 11lip010 1RRRRRRR 1RRRRRRR 000RRRRR [0*2(1IIIIIII) 000IIIII] [0*2(1PPPPPPP) 000PPPPP] for { x0-x15, xip0, xip1, lr } @@ -792,7 +793,7 @@ bool EECodeManager::UnwindStackFrame(GCInfoHeader * pInfoHeader, REGDISPLAY * pContext) { // We could implement this unwind if we wanted, but there really isn't any reason - ASSERT(pInfoHeader->GetReturnKind() != GCInfoHeader::MRK_ReturnsToNative); + ASSERT(!pInfoHeader->ReturnsToNative()); bool ebpFrame = pInfoHeader->HasFramePointer(); @@ -988,12 +989,14 @@ bool EECodeManager::UnwindStackFrame(GCInfoHeader * pInfoHeader, } PTR_UIntNative RSP = (PTR_UIntNative)rawRSP; + bool restoredIP = false; if (ebpFrame) { pContext->pFP = RSP++; pContext->SetAddrOfIP((PTR_PCODE)RSP); // save off the return address location pContext->SetIP(*RSP++); // pop the return address + restoredIP = true; } if (!pInfoHeader->AreFPLROnTop()) @@ -1002,6 +1005,8 @@ bool EECodeManager::UnwindStackFrame(GCInfoHeader * pInfoHeader, ASSERT(!pInfoHeader->HasGSCookie()); } + ASSERT_MSG(pInfoHeader->IsFunclet() || !(dac_cast(RSP) & 0xf), "Callee save area must be 16-byte aligned"); + if (saveSize > 0) { CalleeSavedRegMask regMask = pInfoHeader->GetSavedRegs(); @@ -1010,6 +1015,7 @@ bool EECodeManager::UnwindStackFrame(GCInfoHeader * pInfoHeader, ASSERT_MSG(!ebpFrame, "Chained frame cannot have CSR_MASK_LR mask set"); pContext->SetAddrOfIP((PTR_PCODE)RSP); // save off the return address location pContext->SetIP(*RSP++); // pop the return address + restoredIP = true; } if (regMask & CSR_MASK_X19) { pContext->pX19 = RSP++; } if (regMask & CSR_MASK_X20) { pContext->pX20 = RSP++; } @@ -1024,6 +1030,12 @@ bool EECodeManager::UnwindStackFrame(GCInfoHeader * pInfoHeader, if (regMask & CSR_MASK_FP ) { ASSERT(!ebpFrame); pContext->pFP = RSP++; } } + if (!restoredIP) + { + pContext->SetAddrOfIP((PTR_PCODE)pContext->pLR); + pContext->SetIP(*pContext->pLR); + } + UInt8 vfpRegMask = (UInt8)pInfoHeader->GetVfpRegsPushedMask(); if (vfpRegMask) { @@ -1048,6 +1060,10 @@ bool EECodeManager::UnwindStackFrame(GCInfoHeader * pInfoHeader, RSP += pInfoHeader->ParmRegsPushedCount(); + // Excluding funclets, the total size of the callee save area and the param home area is always a multiple of 16. + // The compiler enforces that by placing an 8-byte padding between those areas if needed. + // Account for that padding and ensure that the unwound SP is 16-byte aligned. + RSP = dac_cast((dac_cast(RSP) + 0xf) & ~0xf); #else #error NYI - For this arch @@ -1060,7 +1076,7 @@ bool EECodeManager::UnwindStackFrame(GCInfoHeader * pInfoHeader, PTR_VOID EECodeManager::GetReversePInvokeSaveFrame(GCInfoHeader * pHeader, REGDISPLAY * pContext) { - if (pHeader->GetReturnKind() != GCInfoHeader::MRK_ReturnsToNative) + if (!pHeader->ReturnsToNative()) return NULL; Int32 frameOffset = pHeader->GetReversePinvokeFrameOffset(); @@ -1078,7 +1094,7 @@ UIntNative EECodeManager::GetConservativeUpperBoundForOutgoingArgs(GCInfoHeader { UIntNative upperBound; - if (pInfoHeader->GetReturnKind() == GCInfoHeader::MRK_ReturnsToNative) + if (pInfoHeader->ReturnsToNative()) { // Reverse PInvoke case. The embedded reverse PInvoke frame is guaranteed to reside above // all outgoing arguments. @@ -1098,7 +1114,9 @@ UIntNative EECodeManager::GetConservativeUpperBoundForOutgoingArgs(GCInfoHeader #elif defined(_TARGET_ARM64_) - PORTABILITY_ASSERT("@TODO: FIXME:ARM64"); + // ARM64 frame pointer case. The pushed FP value is guaranteed to reside above + // all outgoing arguments. + upperBound = pContext->GetFP(); #elif defined(_TARGET_X86_) @@ -1169,7 +1187,7 @@ PTR_PTR_VOID EECodeManager::GetReturnAddressLocationForHijack( // We *could* hijack a reverse-pinvoke method, but it doesn't get us much because we already synchronize // with the GC on the way back to native code. - if (pHeader->GetReturnKind() == GCInfoHeader::MRK_ReturnsToNative) + if (pHeader->ReturnsToNative()) return NULL; if (pHeader->IsFunclet()) @@ -1273,21 +1291,18 @@ GCRefKind EECodeManager::GetReturnValueKind(GCInfoHeader * pInfoHeader) static_assert((GCRefKind)GCInfoHeader::MRK_ReturnsScalar == GCRK_Scalar, "GCInfoHeader::MRK_ReturnsScalar does not match GCRK_Scalar"); static_assert((GCRefKind)GCInfoHeader::MRK_ReturnsObject == GCRK_Object, "GCInfoHeader::MRK_ReturnsObject does not match GCRK_Object"); static_assert((GCRefKind)GCInfoHeader::MRK_ReturnsByref == GCRK_Byref, "GCInfoHeader::MRK_ReturnsByref does not match GCRK_Byref"); +#ifdef _TARGET_ARM64_ + static_assert((GCRefKind)GCInfoHeader::MRK_Scalar_Obj == GCRK_Scalar_Obj, "GCRefKind and MethodReturnKind enumerations do not match"); + static_assert((GCRefKind)GCInfoHeader::MRK_Obj_Obj == GCRK_Obj_Obj, "GCRefKind and MethodReturnKind enumerations do not match"); + static_assert((GCRefKind)GCInfoHeader::MRK_Byref_Obj == GCRK_Byref_Obj, "GCRefKind and MethodReturnKind enumerations do not match"); + static_assert((GCRefKind)GCInfoHeader::MRK_Scalar_Byref == GCRK_Scalar_Byref, "GCRefKind and MethodReturnKind enumerations do not match"); + static_assert((GCRefKind)GCInfoHeader::MRK_Obj_Byref == GCRK_Obj_Byref, "GCRefKind and MethodReturnKind enumerations do not match"); + static_assert((GCRefKind)GCInfoHeader::MRK_Byref_Byref == GCRK_Byref_Byref, "GCRefKind and MethodReturnKind enumerations do not match"); +#endif GCInfoHeader::MethodReturnKind retKind = pInfoHeader->GetReturnKind(); - switch (retKind) - { - case GCInfoHeader::MRK_ReturnsScalar: - case GCInfoHeader::MRK_ReturnsToNative: - return GCRK_Scalar; - case GCInfoHeader::MRK_ReturnsObject: - return GCRK_Object; - case GCInfoHeader::MRK_ReturnsByref: - return GCRK_Byref; - default: - break; - } - UNREACHABLE_MSG("unexpected return kind"); + ASSERT_MSG(retKind <= GCInfoHeader::MRK_LastValid, "unexpected return kind"); + return (retKind == GCInfoHeader::MRK_ReturnsToNative) ? GCRK_Scalar : (GCRefKind)retKind; } bool EECodeManager::GetEpilogOffset( @@ -1345,7 +1360,7 @@ void ** EECodeManager::GetReturnAddressLocationFromEpilog(GCInfoHeader * pInfoHe //ASSERT(VerifyEpilogBytes(pInfoHeader, (Code *)pbEpilogStart)); // We could find the return address of a native-callable method, but it's not very useful at the moment. - ASSERT(pInfoHeader->GetReturnKind() != GCInfoHeader::MRK_ReturnsToNative); + ASSERT(!pInfoHeader->ReturnsToNative()); UInt8 * pbEpilog = pbEpilogStart; #ifdef _X86_ @@ -1796,7 +1811,7 @@ inline bool IsFramelessArm64(void) void CheckHijackInEpilog(GCInfoHeader * pInfoHeader, Code * pEpilog, Code * pEpilogStart, UInt32 epilogSize) { - ASSERT(pInfoHeader->GetReturnKind() != GCInfoHeader::MRK_ReturnsToNative); + ASSERT(!pInfoHeader->ReturnsToNative()); if (IS_FRAMELESS()) return; @@ -1852,8 +1867,7 @@ bool VerifyEpilogBytesX86(GCInfoHeader * pInfoHeader, Code * pEpilogStart, UInt3 Code * pEpilog = pEpilogStart; // NativeCallable methods aren't return-address-hijacked, so we don't care about the epilog format. - bool returnsToNative = (pInfoHeader->GetReturnKind() == GCInfoHeader::MRK_ReturnsToNative); - if (returnsToNative) + if (pInfoHeader->ReturnsToNative()) return true; if (pInfoHeader->HasFramePointer()) @@ -2047,8 +2061,7 @@ bool VerifyEpilogBytesAMD64(GCInfoHeader * pInfoHeader, Code * pEpilogStart, UIn Code * pEpilog = pEpilogStart; // NativeCallable methods aren't return-address-hijacked, so we don't care about the epilog format. - bool returnsToNative = (pInfoHeader->GetReturnKind() == GCInfoHeader::MRK_ReturnsToNative); - if (returnsToNative) + if (pInfoHeader->ReturnsToNative()) return true; CHECK_HIJACK_IN_EPILOG(); @@ -2217,8 +2230,7 @@ bool VerifyEpilogBytesARM(GCInfoHeader * pInfoHeader, Code * pEpilogStart, UInt3 UInt16 * pEpilog = (UInt16 *)pEpilogStart; // NativeCallable methods aren't return-address-hijacked, so we don't care about the epilog format. - bool returnsToNative = (pInfoHeader->GetReturnKind() == GCInfoHeader::MRK_ReturnsToNative); - if (returnsToNative) + if (pInfoHeader->ReturnsToNative()) return true; CHECK_HIJACK_IN_EPILOG(); diff --git a/external/corert/src/Native/Runtime/RhConfig.cpp b/external/corert/src/Native/Runtime/RhConfig.cpp index b36f304798..f1879ab104 100644 --- a/external/corert/src/Native/Runtime/RhConfig.cpp +++ b/external/corert/src/Native/Runtime/RhConfig.cpp @@ -68,12 +68,12 @@ UInt32 RhConfig::ReadConfigValue(_In_z_ const TCHAR *wszName, UInt32 uiDefaultVa //reads a config value from rhconfig.ini into outputBuffer buffer returning the length of the value. //lazily reads the file so if the file is not yet read, it will read it on first called //if the file is not avaliable, or unreadable zero will always be returned -//cchOuputBuffer is the maximum number of characters to write to outputBuffer +//cchOutputBuffer is the maximum number of characters to write to outputBuffer //cchOutputBuffer must be a size >= CONFIG_VAL_MAXLEN + 1 -UInt32 RhConfig::GetIniVariable(_In_z_ const TCHAR* configName, _Out_writes_all_(cchOuputBuffer) TCHAR* outputBuffer, _In_ UInt32 cchOuputBuffer) +UInt32 RhConfig::GetIniVariable(_In_z_ const TCHAR* configName, _Out_writes_all_(cchOutputBuffer) TCHAR* outputBuffer, _In_ UInt32 cchOutputBuffer) { //the buffer needs to be big enough to read the value buffer + null terminator - if (cchOuputBuffer < CONFIG_VAL_MAXLEN + 1) + if (cchOutputBuffer < CONFIG_VAL_MAXLEN + 1) { return 0; } @@ -99,7 +99,7 @@ UInt32 RhConfig::GetIniVariable(_In_z_ const TCHAR* configName, _Out_writes_all_ UInt32 iValue; - for (iValue = 0; (iValue < CONFIG_VAL_MAXLEN + 1) && (iValue < (Int32)cchOuputBuffer); iValue++) + for (iValue = 0; (iValue < CONFIG_VAL_MAXLEN + 1) && (iValue < (Int32)cchOutputBuffer); iValue++) { outputBuffer[iValue] = ((ConfigPair*)g_iniSettings)[iSettings].Value[iValue]; diff --git a/external/corert/src/Native/Runtime/RhConfig.h b/external/corert/src/Native/Runtime/RhConfig.h index c033ed6c82..677d97516d 100644 --- a/external/corert/src/Native/Runtime/RhConfig.h +++ b/external/corert/src/Native/Runtime/RhConfig.h @@ -120,8 +120,8 @@ private: //reads a config value from rhconfig.ini into outputBuffer buffer returning the length of the value. //lazily reads the file so if the file is not yet read, it will read it on first called //if the file is not avaliable, or unreadable zero will always be returned - //cchOuputBuffer is the maximum number of characters to write to outputBuffer - UInt32 GetIniVariable(_In_z_ const TCHAR* configName, _Out_writes_all_(cchOuputBuffer) TCHAR* outputBuffer, _In_ UInt32 cchOuputBuffer); + //cchOutputBuffer is the maximum number of characters to write to outputBuffer + UInt32 GetIniVariable(_In_z_ const TCHAR* configName, _Out_writes_all_(cchOutputBuffer) TCHAR* outputBuffer, _In_ UInt32 cchOutputBuffer); static bool priv_isspace(char c) { diff --git a/external/corert/src/Native/Runtime/RuntimeInstance.cpp b/external/corert/src/Native/Runtime/RuntimeInstance.cpp index 277e75c13b..d2efcf3bd2 100644 --- a/external/corert/src/Native/Runtime/RuntimeInstance.cpp +++ b/external/corert/src/Native/Runtime/RuntimeInstance.cpp @@ -179,6 +179,47 @@ ICodeManager * RuntimeInstance::FindCodeManagerByAddress(PTR_VOID pvAddress) return NULL; } +#ifndef DACCESS_COMPILE + +// Find the code manager containing the given address, which might be a return address from a managed function. The +// address may be to another managed function, or it may be to an unmanaged function. The address may also refer to +// an EEType. +ICodeManager * RuntimeInstance::FindCodeManagerForClasslibFunction(PTR_VOID address) +{ + // Try looking up the code manager assuming the address is for code first. This is expected to be most common. + ICodeManager * pCodeManager = FindCodeManagerByAddress(address); + if (pCodeManager != NULL) + return pCodeManager; + + // Less common, we will look for the address in any of the sections of the module. This is slower, but is + // necessary for EEType pointers and jump stubs. + Module * pModule = FindModuleByAddress(address); + if (pModule != NULL) + return pModule; + + ASSERT_MSG(!Thread::IsHijackTarget(address), "not expected to be called with hijacked return address"); + + return NULL; +} + +void * RuntimeInstance::GetClasslibFunctionFromCodeAddress(PTR_VOID address, ClasslibFunctionId functionId) +{ + // Find the code manager for the given address, which is an address into some managed module. It could + // be code, or it could be an EEType. No matter what, it's an address into a managed module in some non-Rtm + // type system. + ICodeManager * pCodeManager = FindCodeManagerForClasslibFunction(address); + + // If the address isn't in a managed module then we have no classlib function. + if (pCodeManager == NULL) + { + return NULL; + } + + return pCodeManager->GetClasslibFunction(functionId); +} + +#endif // DACCESS_COMPILE + PTR_UInt8 RuntimeInstance::GetTargetOfUnboxingAndInstantiatingStub(PTR_VOID ControlPC) { ICodeManager * pCodeManager = FindCodeManagerByAddress(ControlPC); @@ -576,22 +617,22 @@ void RuntimeInstance::Destroy() bool RuntimeInstance::ShouldHijackLoopForGcStress(UIntNative CallsiteIP) { -#if defined(FEATURE_GC_STRESS) & !defined(DACCESS_COMPILE) +#ifdef FEATURE_GC_STRESS return ShouldHijackForGcStress(CallsiteIP, htLoop); -#else // FEATURE_GC_STRESS & !DACCESS_COMPILE +#else // FEATURE_GC_STRESS UNREFERENCED_PARAMETER(CallsiteIP); return false; -#endif // FEATURE_GC_STRESS & !DACCESS_COMPILE +#endif // FEATURE_GC_STRESS } bool RuntimeInstance::ShouldHijackCallsiteForGcStress(UIntNative CallsiteIP) { -#if defined(FEATURE_GC_STRESS) & !defined(DACCESS_COMPILE) +#ifdef FEATURE_GC_STRESS return ShouldHijackForGcStress(CallsiteIP, htCallsite); -#else // FEATURE_GC_STRESS & !DACCESS_COMPILE +#else // FEATURE_GC_STRESS UNREFERENCED_PARAMETER(CallsiteIP); return false; -#endif // FEATURE_GC_STRESS & !DACCESS_COMPILE +#endif // FEATURE_GC_STRESS } // This method should only be called during DllMain for modules with GcStress enabled. The locking done by @@ -889,7 +930,7 @@ COOP_PINVOKE_HELPER(void *, RhNewInterfaceDispatchCell, (EEType * pInterface, In return NULL; // Due to the synchronization mechanism used to update this indirection cell we must ensure the cell's alignment is twice that of a pointer. - // Fortunately, Windows heap guarantees this aligment. + // Fortunately, Windows heap guarantees this alignment. ASSERT(IS_ALIGNED(pCell, 2 * POINTER_SIZE)); ASSERT(IS_ALIGNED(pInterface, (InterfaceDispatchCell::IDC_CachePointerMask + 1))); @@ -914,4 +955,4 @@ COOP_PINVOKE_HELPER(PTR_UInt8, RhGetThreadLocalStorageForDynamicType, (UInt32 uO return pCurrentThread->AllocateThreadLocalStorageForDynamicType(uOffset, tlsStorageSize, numTlsCells); } -#endif +#endif // DACCESS_COMPILE diff --git a/external/corert/src/Native/Runtime/RuntimeInstance.h b/external/corert/src/Native/Runtime/RuntimeInstance.h index 639a3f9a19..5bbc096510 100644 --- a/external/corert/src/Native/Runtime/RuntimeInstance.h +++ b/external/corert/src/Native/Runtime/RuntimeInstance.h @@ -14,6 +14,8 @@ enum GenericVarianceType : UInt8; struct GenericUnificationDesc; class GenericUnificationHashtable; +#include "ICodeManager.h" + class RuntimeInstance { friend class AsmOffsets; @@ -149,6 +151,8 @@ private: bool BuildGenericTypeHashTable(); + ICodeManager * FindCodeManagerForClasslibFunction(PTR_VOID address); + public: class ModuleIterator { @@ -180,6 +184,7 @@ public: void UnregisterCodeManager(ICodeManager * pCodeManager); ICodeManager * FindCodeManagerByAddress(PTR_VOID ControlPC); + PTR_VOID GetClasslibFunctionFromCodeAddress(PTR_VOID address, ClasslibFunctionId functionId); bool RegisterTypeManager(TypeManager * pTypeManager); TypeManagerList& GetTypeManagerList(); diff --git a/external/corert/src/Native/Runtime/StackFrameIterator.cpp b/external/corert/src/Native/Runtime/StackFrameIterator.cpp index 5909416d8d..54773b0b59 100644 --- a/external/corert/src/Native/Runtime/StackFrameIterator.cpp +++ b/external/corert/src/Native/Runtime/StackFrameIterator.cpp @@ -250,15 +250,11 @@ void StackFrameIterator::InternalInit(Thread * pThreadToWalk, PTR_PInvokeTransit if (pFrame->m_Flags & PTFF_SAVE_LR) { m_RegDisplay.pLR = pPreservedRegsCursor++; } - if (pFrame->m_Flags & PTFF_X0_IS_GCREF) + GCRefKind retValueKind = TransitionFrameFlagsToReturnKind(pFrame->m_Flags); + if (retValueKind != GCRK_Scalar) { m_pHijackedReturnValue = (PTR_RtuObjectRef)m_RegDisplay.pX0; - m_HijackedReturnValueKind = GCRK_Object; - } - if (pFrame->m_Flags & PTFF_X0_IS_BYREF) - { - m_pHijackedReturnValue = (PTR_RtuObjectRef)m_RegDisplay.pX0; - m_HijackedReturnValueKind = GCRK_Byref; + m_HijackedReturnValueKind = retValueKind; } #else // _TARGET_ARM_ @@ -1728,7 +1724,7 @@ bool StackFrameIterator::GetHijackedReturnValueLocation(PTR_RtuObjectRef * pLoca if (GCRK_Unknown == m_HijackedReturnValueKind) return false; - ASSERT((GCRK_Object == m_HijackedReturnValueKind) || (GCRK_Byref == m_HijackedReturnValueKind)); + ASSERT((GCRK_Scalar < m_HijackedReturnValueKind) && (m_HijackedReturnValueKind <= GCRK_LastValid)); *pLocation = m_pHijackedReturnValue; *pKind = m_HijackedReturnValueKind; @@ -1874,7 +1870,7 @@ COOP_PINVOKE_HELPER(Boolean, RhpSfiInit, (StackFrameIterator* pThis, PAL_LIMITED // The stackwalker is intolerant to hijacked threads, as it is largely expecting to be called from C++ // where the hijack state of the thread is invariant. Because we've exposed the iterator out to C#, we // need to unhijack every time we callback into C++ because the thread could have been hijacked during our - // time exectuing C#. + // time executing C#. pCurThread->Unhijack(); // Passing NULL is a special-case to request a standard managed stack trace for the current thread. @@ -1894,7 +1890,7 @@ COOP_PINVOKE_HELPER(Boolean, RhpSfiNext, (StackFrameIterator* pThis, UInt32* puE // The stackwalker is intolerant to hijacked threads, as it is largely expecting to be called from C++ // where the hijack state of the thread is invariant. Because we've exposed the iterator out to C#, we // need to unhijack every time we callback into C++ because the thread could have been hijacked during our - // time exectuing C#. + // time executing C#. ThreadStore::GetCurrentThread()->Unhijack(); const UInt32 MaxTryRegionIdx = 0xFFFFFFFF; diff --git a/external/corert/src/Native/Runtime/amd64/GcProbe.asm b/external/corert/src/Native/Runtime/amd64/GcProbe.asm index a07e08a08d..ac07653d99 100644 --- a/external/corert/src/Native/Runtime/amd64/GcProbe.asm +++ b/external/corert/src/Native/Runtime/amd64/GcProbe.asm @@ -841,16 +841,12 @@ NESTED_ENTRY RhpTrapToGC, _TEXT sizeof_XmmAlignPad equ 8 sizeof_XmmSave equ FXSAVE_SIZE sizeof_MachineFrame equ 6*8 - sizeof_InitialPushedArgs equ 3*8 ;; eflags, rcx, return value + sizeof_InitialPushedArgs equ 2*8 ;; eflags, return value sizeof_FixedFrame equ sizeof_OutgoingScratchSpace + sizeof_PInvokeFrame + sizeof_XmmAlignPad + sizeof_XmmSave + sizeof_MachineFrame ;; On the stack on entry: ;; [rsp ] -> Return address - ;; Prepare for our return by stashing a scratch register where we can pop it just before returning - ;; The scratch register will be used as PSP in the epilog - push rcx - ;; save eflags before we trash them pushfq @@ -889,26 +885,27 @@ NESTED_ENTRY RhpTrapToGC, _TEXT ;; [rsp +2e0] | SS | ;; [rsp +2e8] | padding | ;; - ;; [rsp +2f0] [optional stack alignment] + ;; [rsp +2f0] [PSP] + ;; [rsp +2f8] [optional stack alignment] ;; - ;; [PSP - 18] -> eflags save - ;; [PSP - 10] -> rcx save + ;; [PSP - 10] -> eflags save ;; [PSP - 8] -> Return address ;; [PSP] -> caller's frame test rsp, 0Fh jz AlreadyAligned - sub rsp, sizeof_XmmAlignPad + sizeof_XmmSave + sizeof_MachineFrame + 8 ; +8 to align RSP + sub rsp, sizeof_XmmAlignPad + sizeof_XmmSave + sizeof_MachineFrame + 8 ; +8 to save PSP, push r11 ; save incoming R11 into save location lea r11, [rsp + 8 + sizeof_XmmAlignPad + sizeof_XmmSave + sizeof_MachineFrame + 8 + sizeof_InitialPushedArgs] jmp PspCalculated AlreadyAligned: - sub rsp, sizeof_XmmAlignPad + sizeof_XmmSave + sizeof_MachineFrame - push r11 ; save incoming R11 into save location - lea r11, [rsp + 8 + sizeof_XmmAlignPad + sizeof_XmmSave + sizeof_MachineFrame + sizeof_InitialPushedArgs] + sub rsp, sizeof_XmmAlignPad + sizeof_XmmSave + sizeof_MachineFrame + 16 ; +8 to save RSP, +8 to re-align PSP, + push r11 ; save incoming R11 into save location + lea r11, [rsp + 8 + sizeof_XmmAlignPad + sizeof_XmmSave + sizeof_MachineFrame + 16 + sizeof_InitialPushedArgs] + PspCalculated: push r10 ; save incoming R10 into save location xor r10d, r10d @@ -923,6 +920,7 @@ NESTED_ENTRY RhpTrapToGC, _TEXT mov [rsp + 2d0h - 0a8h], r10 ; init EFLAGS to zero mov [rsp + 2d8h - 0a8h], r11 ; save PSP in the 'machine frame' mov [rsp + 2e0h - 0a8h], r10 ; init SS to zero + mov [rsp + 2f0h - 0a8h], r11 ; save PSP .pushframe .allocstack sizeof_XmmAlignPad + sizeof_XmmSave + 2*8 ;; only 2 of the regs from the PInvokeTransitionFrame are on the stack @@ -1023,7 +1021,6 @@ endif ;; FEATURE_GC_STRESS call RhpWaitForGCNoAbort DoneWaitingForGc: - mov rcx, rbx ; RCX <- PSP fxrstor [rsp + 0c0h] @@ -1064,33 +1061,34 @@ DontRestoreXmmAgain: pop r15 pop rax ; RSP pop rax ; RAX save - pop rdx ; RCX save (intentionally discarding it) + pop rcx pop rdx pop r8 pop r9 pop r10 pop r11 + ;; restore PSP + ;; 2F0h -> offset of the PSP area + ;; 0B8h -> offset of the end of the integer register area which is already popped + mov rsp, [rsp + 2f0h - 0b8h] - ;; RCX is PSP at this point and the stack looks like this: - ;; [PSP - 18] -> eflags save - ;; [PSP - 10] -> rcx save + ;; RSP is PSP at this point and the stack looks like this: + ;; [PSP - 10] -> eflags save ;; [PSP - 8] -> return address ;; [PSP] -> caller's frame ;; - ;; The final step is to restore eflags, rcx, and return back to the loop target location. - - lea rsp, [rcx - 18h] + ;; The final step is to restore eflags and return + + lea rsp, [rsp - 10h] jz @f ;; result of the test instruction before the pops above popfq ;; restore flags - pop rcx ;; restore rcx mov rcx, STATUS_REDHAWK_THREAD_ABORT pop rdx ;; return address as exception RIP jmp RhpThrowHwEx ;; Throw the ThreadAbortException as a special kind of hardware exception @@: popfq ;; restore flags - pop rcx ;; restore rcx ret NESTED_END RhpTrapToGC, _TEXT diff --git a/external/corert/src/Native/Runtime/arm64/ExceptionHandling.asm b/external/corert/src/Native/Runtime/arm64/ExceptionHandling.asm index 5df131bbe6..e08118516b 100644 --- a/external/corert/src/Native/Runtime/arm64/ExceptionHandling.asm +++ b/external/corert/src/Native/Runtime/arm64/ExceptionHandling.asm @@ -8,28 +8,39 @@ #define STACKSIZEOF_ExInfo ((SIZEOF__ExInfo + 15)&(~15)) +#define HARDWARE_EXCEPTION 1 +#define SOFTWARE_EXCEPTION 0 + ;; ----------------------------------------------------------------------------- ;; Macro used to create frame of exception throwing helpers (RhpThrowEx, RhpThrowHwEx) MACRO - ALLOC_THROW_FRAME + ALLOC_THROW_FRAME $exceptionType + + PROLOG_NOP mov x3, sp ;; Setup a PAL_LIMITED_CONTEXT on the stack { - PROLOG_SAVE_REG_PAIR fp, lr, #-SIZEOF__PAL_LIMITED_CONTEXT! - PROLOG_NOP stp x0, x1, [sp, #0x10] + PROLOG_STACK_ALLOC 0x50 + IF $exceptionType == HARDWARE_EXCEPTION + PROLOG_NOP stp x3, x1, [sp] ; x3 is the SP and x1 is the IP of the fault site + PROLOG_PUSH_MACHINE_FRAME + ELSE + PROLOG_NOP stp x3, lr, [sp] ; x3 is the SP and lr is the IP of the fault site + ENDIF + PROLOG_NOP stp d8, d9, [sp, #0x10] + PROLOG_NOP stp d10, d11, [sp, #0x20] + PROLOG_NOP stp d12, d13, [sp, #0x30] + PROLOG_NOP stp d14, d15, [sp, #0x40] + PROLOG_SAVE_REG_PAIR fp, lr, #-0x70! + PROLOG_NOP stp xzr, xzr, [sp, #0x10] ; locations reserved for return value, not used for exception handling PROLOG_SAVE_REG_PAIR x19, x20, #0x20 PROLOG_SAVE_REG_PAIR x21, x22, #0x30 PROLOG_SAVE_REG_PAIR x23, x24, #0x40 PROLOG_SAVE_REG_PAIR x25, x26, #0x50 PROLOG_SAVE_REG_PAIR x27, x28, #0x60 - PROLOG_NOP stp x0, lr, [sp, #0x70] ; x0 is the SP and lr is the IP of the fault site - PROLOG_NOP stp d8, d9, [sp, #0x80] - PROLOG_NOP stp d10, d11, [sp, #0x90] - PROLOG_NOP stp d12, d13, [sp, #0xA0] - PROLOG_NOP stp d14, d15, [sp, #0xB0] ;; } end PAL_LIMITED_CONTEXT - + PROLOG_STACK_ALLOC STACKSIZEOF_ExInfo - MEND + MEND ;; ----------------------------------------------------------------------------- ;; Macro used to create frame of funclet calling helpers (RhpCallXXXXFunclet) @@ -199,19 +210,7 @@ #define rsp_offsetof_ExInfo 0 #define rsp_offsetof_Context STACKSIZEOF_ExInfo - PROLOG_NOP mov w2, w0 ;; save exception code into x2 - PROLOG_NOP mov x0, sp ;; get SP of fault site - - PROLOG_NOP mov lr, x1 ;; set IP of fault site - - ALLOC_THROW_FRAME - - ; x0: SP of fault site - ; x1: IP of fault site - ; x2: exception code of fault - ; lr: IP of fault site (as a 'return address') - - mov w0, w2 ;; w0 <- exception code of fault + ALLOC_THROW_FRAME HARDWARE_EXCEPTION ;; x2 = GetThread(), TRASHES x1 INLINE_GETTHREAD x2, x1 @@ -256,11 +255,7 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; NESTED_ENTRY RhpThrowEx - ALLOC_THROW_FRAME - - ;; Compute and save SP at callsite. - add x1, sp, #(STACKSIZEOF_ExInfo + SIZEOF__PAL_LIMITED_CONTEXT) - str x1, [sp, #(rsp_offsetof_Context + OFFSETOF__PAL_LIMITED_CONTEXT__SP)] + ALLOC_THROW_FRAME SOFTWARE_EXCEPTION ;; x2 = GetThread(), TRASHES x1 INLINE_GETTHREAD x2, x1 @@ -351,11 +346,7 @@ NotHijacked ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; NESTED_ENTRY RhpRethrow - ALLOC_THROW_FRAME - - ;; Compute and save SP at callsite. - add x1, sp, #(STACKSIZEOF_ExInfo + SIZEOF__PAL_LIMITED_CONTEXT) - str x1, [sp, #(rsp_offsetof_Context + OFFSETOF__PAL_LIMITED_CONTEXT__SP)] + ALLOC_THROW_FRAME SOFTWARE_EXCEPTION ;; x2 = GetThread(), TRASHES x1 INLINE_GETTHREAD x2, x1 @@ -599,7 +590,11 @@ SetSuccess ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; NESTED_ENTRY RhpCallFilterFunclet - ALLOC_CALL_FUNCLET_FRAME 0 + ALLOC_CALL_FUNCLET_FRAME 0x40 + stp d8, d9, [sp, #0x00] + stp d10, d11, [sp, #0x10] + stp d12, d13, [sp, #0x20] + stp d14, d15, [sp, #0x30] ldr x12, [x2, #OFFSETOF__REGDISPLAY__pFP] ldr fp, [x12] @@ -612,7 +607,12 @@ SetSuccess EXPORT_POINTER_TO_ADDRESS PointerToRhpCallFilterFunclet2 - FREE_CALL_FUNCLET_FRAME 0 + ldp d8, d9, [sp, #0x00] + ldp d10, d11, [sp, #0x10] + ldp d12, d13, [sp, #0x20] + ldp d14, d15, [sp, #0x30] + + FREE_CALL_FUNCLET_FRAME 0x40 EPILOG_RETURN NESTED_END RhpCallFilterFunclet diff --git a/external/corert/src/Native/Runtime/arm64/GcProbe.asm b/external/corert/src/Native/Runtime/arm64/GcProbe.asm index a6ee43c566..051b4158dc 100644 --- a/external/corert/src/Native/Runtime/arm64/GcProbe.asm +++ b/external/corert/src/Native/Runtime/arm64/GcProbe.asm @@ -20,7 +20,7 @@ PROBE_SAVE_FLAGS_EVERYTHING equ DEFAULT_FRAME_SAVE_FLAGS + PTFF_SAVE_ALL_SCRATCH ;; Build a map of symbols representing offsets into the transition frame (see PInvokeTransitionFrame in - ;; rhbinder.h and keep these two in sync. + ;; rhbinder.h) and keep these two in sync. map 0 field OFFSETOF__PInvokeTransitionFrame__m_PreservedRegs field 10 * 8 ; x19..x28 @@ -41,7 +41,7 @@ PROBE_FRAME_SIZE field 0 ;; ;; Note that we currently employ a significant simplification of frame setup: we always allocate a ;; maximally-sized PInvokeTransitionFrame and save all of the registers. Depending on the caller this can - ;; lead to upto 20 additional register saves (x0-x18, lr) or 160 bytes of stack space. I have done no + ;; lead to up to 20 additional register saves (x0-x18, lr) or 160 bytes of stack space. I have done no ;; analysis to see whether any of the worst cases occur on performance sensitive paths and whether the ;; additional saves will show any measurable degradation. @@ -82,7 +82,7 @@ PROBE_FRAME_SIZE field 0 ; Save the floating return registers PROLOG_NOP stp d0, d1, [sp, #0x120] - PROLOG_NOP stp d2, d3, [sp, #0x130] + PROLOG_NOP stp d2, d3, [sp, #0x130] MEND @@ -106,9 +106,9 @@ PROBE_FRAME_SIZE field 0 ; Restore the floating return registers EPILOG_NOP ldp d0, d1, [sp, #0x120] - EPILOG_NOP ldp d2, d3, [sp, #0x130] + EPILOG_NOP ldp d2, d3, [sp, #0x130] - ;; Resttore callee saved registers + ;; Restore callee saved registers EPILOG_RESTORE_REG_PAIR x19, x20, #0x20 EPILOG_RESTORE_REG_PAIR x21, x22, #0x30 EPILOG_RESTORE_REG_PAIR x23, x24, #0x40 @@ -135,12 +135,13 @@ BitmaskStr SETS "$savedRegsMask" str $threadReg, [sp, #OFFSETOF__PInvokeTransitionFrame__m_pThread] ; Thread * IF BitmaskStr:LEFT:1 == "#" - ;; The savedRegsMask is a constant, remove the leading "#" since the MOVL64 doesn't expect it -BitmaskStr SETS BitmaskStr:RIGHT:(:LEN:BitmaskStr - 1) - MOVL64 $trashReg, $BitmaskStr, $gcFlags + ;; The savedRegsMask is a constant, remove the leading "#" since the MOVL64 doesn't expect it +BitmaskStr SETS BitmaskStr:RIGHT:(:LEN:BitmaskStr - 1) + MOVL64 $trashReg, $BitmaskStr, $gcFlags ELSE - ;; The savedRegsMask is a register - mov $trashReg, $savedRegsMask + ASSERT "$gcFlags" == "" + ;; The savedRegsMask is a register + mov $trashReg, $savedRegsMask ENDIF str $trashReg, [sp, #OFFSETOF__PInvokeTransitionFrame__m_Flags] add $trashReg, sp, #$frameSize @@ -178,7 +179,7 @@ __PPF_ThreadReg SETS "x2" ; Perform the rest of the PInvokeTransitionFrame initialization. INIT_PROBE_FRAME $__PPF_ThreadReg, $trashReg, $savedRegsMask, $gcFlags, PROBE_FRAME_SIZE - add $trashReg, sp, xzr + mov $trashReg, sp str $trashReg, [$__PPF_ThreadReg, #OFFSETOF__Thread__m_pHackPInvokeTunnel] MEND @@ -255,8 +256,11 @@ EXTRA_SAVE_SIZE equ (28*8) MACRO ClearHijackState - str xzr, [x2, #OFFSETOF__Thread__m_ppvHijackedReturnAddressLocation] - str xzr, [x2, #OFFSETOF__Thread__m_pvHijackedReturnAddress] + ASSERT OFFSETOF__Thread__m_pvHijackedReturnAddress == (OFFSETOF__Thread__m_ppvHijackedReturnAddressLocation + 8) + ;; Clear m_ppvHijackedReturnAddressLocation and m_pvHijackedReturnAddress + stp xzr, xzr, [x2, #OFFSETOF__Thread__m_ppvHijackedReturnAddressLocation] + ;; Clear m_uHijackedReturnValueFlags + str xzr, [x2, #OFFSETOF__Thread__m_uHijackedReturnValueFlags] MEND ;; @@ -269,6 +273,7 @@ EXTRA_SAVE_SIZE equ (28*8) ;; Register state on exit: ;; x2: thread pointer ;; x3: trashed +;; x12: transition frame flags for the return registers x0 and x1 ;; MACRO FixupHijackedCallstack @@ -279,7 +284,9 @@ EXTRA_SAVE_SIZE equ (28*8) ;; ;; Fix the stack by restoring the original return address ;; - ldr lr, [x2, #OFFSETOF__Thread__m_pvHijackedReturnAddress] + ASSERT OFFSETOF__Thread__m_uHijackedReturnValueFlags == (OFFSETOF__Thread__m_pvHijackedReturnAddress + 8) + ;; Load m_pvHijackedReturnAddress and m_uHijackedReturnValueFlags + ldp lr, x12, [x2, #OFFSETOF__Thread__m_pvHijackedReturnAddress] ClearHijackState MEND @@ -330,39 +337,15 @@ EXTRA_SAVE_SIZE equ (28*8) ;; EXTERN RhpPInvokeExceptionGuard - - NESTED_ENTRY RhpGcProbeHijackScalarWrapper, .text, RhpPInvokeExceptionGuard - brk 0xf000 ;; TODO: remove after debugging/testing stub + NESTED_ENTRY RhpGcProbeHijackWrapper, .text, RhpPInvokeExceptionGuard HijackTargetFakeProlog - LABELED_RETURN_ADDRESS RhpGcProbeHijackScalar + LABELED_RETURN_ADDRESS RhpGcProbeHijack FixupHijackedCallstack - MOVL64 x12, DEFAULT_FRAME_SAVE_FLAGS, 0 + orr x12, x12, #DEFAULT_FRAME_SAVE_FLAGS b RhpGcProbe - NESTED_END RhpGcProbeHijackScalarWrapper - - NESTED_ENTRY RhpGcProbeHijackObjectWrapper, .text, RhpPInvokeExceptionGuard - brk 0xf000 ;; TODO: remove after debugging/testing stub - HijackTargetFakeProlog - - LABELED_RETURN_ADDRESS RhpGcProbeHijackObject - - FixupHijackedCallstack - MOVL64 x12, (DEFAULT_FRAME_SAVE_FLAGS + PTFF_SAVE_X0), PTFF_X0_IS_GCREF_HI - b RhpGcProbe - NESTED_END RhpGcProbeHijackObjectWrapper - - NESTED_ENTRY RhpGcProbeHijackByrefWrapper, .text, RhpPInvokeExceptionGuard - brk 0xf000 ;; TODO: remove after debugging/testing stub - HijackTargetFakeProlog - - LABELED_RETURN_ADDRESS RhpGcProbeHijackByref - - FixupHijackedCallstack - MOVL64 x12, (DEFAULT_FRAME_SAVE_FLAGS + PTFF_SAVE_X0) , PTFF_X0_IS_BYREF_HI - b RhpGcProbe - NESTED_END RhpGcProbeHijackByrefWrapper + NESTED_END RhpGcProbeHijackWrapper #ifdef FEATURE_GC_STRESS ;; @@ -370,25 +353,11 @@ EXTRA_SAVE_SIZE equ (28*8) ;; GC Stress Hijack targets ;; ;; - LEAF_ENTRY RhpGcStressHijackScalar + LEAF_ENTRY RhpGcStressHijack FixupHijackedCallstack - MOVL64 x12, DEFAULT_FRAME_SAVE_FLAGS, 0 + orr x12, x12, #DEFAULT_FRAME_SAVE_FLAGS b RhpGcStressProbe - LEAF_END RhpGcStressHijackScalar - - LEAF_ENTRY RhpGcStressHijackObject - FixupHijackedCallstack - MOVL64 x12, (DEFAULT_FRAME_SAVE_FLAGS + PTFF_SAVE_X0), PTFF_X0_IS_GCREF_HI - b RhpGcStressProbe - LEAF_END RhpGcStressHijackObject - - LEAF_ENTRY RhpGcStressHijackByref - FixupHijackedCallstack - MOVL64 x12, (DEFAULT_FRAME_SAVE_FLAGS + PTFF_SAVE_X0), PTFF_X0_IS_BYREF_HI - b RhpGcStressProbe - LEAF_END RhpGcStressHijackByref - - + LEAF_END RhpGcStressHijack ;; ;; Worker for our GC stress probes. Do not call directly!! ;; Instead, go through RhpGcStressHijack{Scalar|Object|Byref}. @@ -595,7 +564,7 @@ EXTRA_SAVE_SIZE equ (28*8) #endif ;; FEATURE_GC_STRESS - +#if 0 // used by the binder only ;; ;; The following functions are _jumped_ to when we need to transfer control from one method to another for EH ;; dispatch. These are needed to properly coordinate with the GC hijacking logic. We are essentially replacing @@ -605,10 +574,10 @@ EXTRA_SAVE_SIZE equ (28*8) ;; after a real return from the throwing method. Then, if we are not hijacked we can simply jump to the ;; handler in the caller. ;; -;; If we are hijacked, then we jump to a routine that will unhijack appropriatley and wait for the GC to +;; If we are hijacked, then we jump to a routine that will unhijack appropriately and wait for the GC to ;; complete. There are also variants for GC stress. ;; -;; Note that at this point we are eiher hijacked or we are not, and this will not change until we return to +;; Note that at this point we are either hijacked or we are not, and this will not change until we return to ;; managed code. It is an invariant of the system that a thread will only attempt to hijack or unhijack ;; another thread while the target thread is suspended in managed code, and this is _not_ managed code. ;; @@ -634,13 +603,13 @@ EXTRA_SAVE_SIZE equ (28*8) MEND ;; We need an instance of the helper for each possible hijack function. The binder has enough ;; information to determine which one we need to use for any function. - RTU_EH_JUMP_HELPER RhpEHJumpScalar, RhpGcProbeHijackScalar, {false}, 0 - RTU_EH_JUMP_HELPER RhpEHJumpObject, RhpGcProbeHijackObject, {false}, 0 - RTU_EH_JUMP_HELPER RhpEHJumpByref, RhpGcProbeHijackByref, {false}, 0 + RTU_EH_JUMP_HELPER RhpEHJumpScalar, RhpGcProbeHijack, {false}, 0 + RTU_EH_JUMP_HELPER RhpEHJumpObject, RhpGcProbeHijack, {false}, 0 + RTU_EH_JUMP_HELPER RhpEHJumpByref, RhpGcProbeHijack, {false}, 0 #ifdef FEATURE_GC_STRESS - RTU_EH_JUMP_HELPER RhpEHJumpScalarGCStress, RhpGcProbeHijackScalar, {true}, RhpGcStressHijackScalar - RTU_EH_JUMP_HELPER RhpEHJumpObjectGCStress, RhpGcProbeHijackObject, {true}, RhpGcStressHijackObject - RTU_EH_JUMP_HELPER RhpEHJumpByrefGCStress, RhpGcProbeHijackByref, {true}, RhpGcStressHijackByref + RTU_EH_JUMP_HELPER RhpEHJumpScalarGCStress, RhpGcProbeHijack, {true}, RhpGcStressHijack + RTU_EH_JUMP_HELPER RhpEHJumpObjectGCStress, RhpGcProbeHijack, {true}, RhpGcStressHijack + RTU_EH_JUMP_HELPER RhpEHJumpByrefGCStress, RhpGcProbeHijack, {true}, RhpGcStressHijack #endif ;; @@ -757,7 +726,10 @@ EXTRA_SAVE_SIZE equ (28*8) EHJumpProbeEpilog NESTED_END RhpGCStressProbeForEHJump +#endif ;; FEATURE_GC_STRESS +#endif ;; 0 +#ifdef FEATURE_GC_STRESS ;; ;; INVARIANT: Don't trash the argument registers, the binder codegen depends on this. ;; diff --git a/external/corert/src/Native/Runtime/arm64/PInvoke.asm b/external/corert/src/Native/Runtime/arm64/PInvoke.asm index c05328314b..01decb3c50 100644 --- a/external/corert/src/Native/Runtime/arm64/PInvoke.asm +++ b/external/corert/src/Native/Runtime/arm64/PInvoke.asm @@ -23,12 +23,13 @@ ;; FP and LR registers PROLOG_SAVE_REG_PAIR fp, lr, #-0xA0! ;; Push down stack pointer and store FP and LR - ;; Need to save argument registers x0-x7 and the return buffer register x8 (twice just for 16B alignment) + ;; Need to save argument registers x0-x7 and the return buffer register x8 + ;; Also save x9 which may be used for saving indirect call target stp x0, x1, [sp, #0x10] stp x2, x3, [sp, #0x20] stp x4, x5, [sp, #0x30] stp x6, x7, [sp, #0x40] - stp x8, x8, [sp, #0x50] + stp x8, x9, [sp, #0x50] ;; Save float argument registers as well since they're volatile stp d0, d1, [sp, #0x60] @@ -49,7 +50,7 @@ ldp x2, x3, [sp, #0x20] ldp x4, x5, [sp, #0x30] ldp x6, x7, [sp, #0x40] - ldr x8, [sp, #0x50] + ldp x8, x9, [sp, #0x50] ;; Restore FP and LR registers, and free the allocated stack block EPILOG_RESTORE_REG_PAIR fp, lr, #0xA0! diff --git a/external/corert/src/Native/Runtime/arm64/UniversalTransition.asm b/external/corert/src/Native/Runtime/arm64/UniversalTransition.asm index 4c21397f7a..fe47637405 100644 --- a/external/corert/src/Native/Runtime/arm64/UniversalTransition.asm +++ b/external/corert/src/Native/Runtime/arm64/UniversalTransition.asm @@ -110,7 +110,7 @@ stp x2, x3, [sp, #(ARGUMENT_REGISTERS_OFFSET + 0x10)] stp x4, x5, [sp, #(ARGUMENT_REGISTERS_OFFSET + 0x20)] stp x6, x7, [sp, #(ARGUMENT_REGISTERS_OFFSET + 0x30)] - str x8, [sp, #(ARGUMENT_REGISTERS_OFFSET + 0x40)] + stp x8, xzr, [sp, #(ARGUMENT_REGISTERS_OFFSET + 0x40)] #ifdef TRASH_SAVED_ARGUMENT_REGISTERS ;; ARM64TODO diff --git a/external/corert/src/Native/Runtime/coreclr/gcinfodecoder.cpp b/external/corert/src/Native/Runtime/coreclr/gcinfodecoder.cpp index a7bc3d2047..266e7045a5 100644 --- a/external/corert/src/Native/Runtime/coreclr/gcinfodecoder.cpp +++ b/external/corert/src/Native/Runtime/coreclr/gcinfodecoder.cpp @@ -166,7 +166,7 @@ GcInfoDecoder::GcInfoDecoder( if (hasGSCookie) { // Note that normalization as a code offset can be different than - // normalization as code legnth + // normalization as code length UINT32 normCodeLength = NORMALIZE_CODE_OFFSET(m_CodeLength); // Decode prolog/epilog information @@ -330,7 +330,7 @@ GcInfoDecoder::GcInfoDecoder( else if(flags & DECODE_FOR_RANGES_CALLBACK) { // Note that normalization as a code offset can be different than - // normalization as code legnth + // normalization as code length UINT32 normCodeLength = NORMALIZE_CODE_OFFSET(m_CodeLength); UINT32 numBitsPerOffset = CeilOfLog2(normCodeLength); @@ -453,7 +453,7 @@ void GcInfoDecoder::EnumerateInterruptibleRanges ( EnumerateInterruptibleRangesCallback *pCallback, void * hCallback) { - // If no info is found for the call site, we default to fully-interruptbile + // If no info is found for the call site, we default to fully-interruptible LOG((LF_GCROOTS, LL_INFO1000000, "No GC info found for call site at offset %x. Defaulting to fully-interruptible information.\n", (int) m_InstructionOffset)); UINT32 lastInterruptibleRangeStopOffsetNormalized = 0; @@ -793,7 +793,7 @@ bool GcInfoDecoder::EnumerateLiveSlots( _ASSERTE(m_NumInterruptibleRanges); _ASSERTE(numInterruptibleLength); - // If no info is found for the call site, we default to fully-interruptbile + // If no info is found for the call site, we default to fully-interruptible LOG((LF_GCROOTS, LL_INFO1000000, "No GC info found for call site at offset %x. Defaulting to fully-interruptible information.\n", (int) m_InstructionOffset)); UINT32 numChunks = (numInterruptibleLength + NUM_NORM_CODE_OFFSETS_PER_CHUNK - 1) / NUM_NORM_CODE_OFFSETS_PER_CHUNK; diff --git a/external/corert/src/Native/Runtime/gcdump.cpp b/external/corert/src/Native/Runtime/gcdump.cpp index 20eeae53c9..d5022b44c8 100644 --- a/external/corert/src/Native/Runtime/gcdump.cpp +++ b/external/corert/src/Native/Runtime/gcdump.cpp @@ -42,7 +42,21 @@ GCDump::GCDump() static const char * const calleeSaveRegMaskBitNumberToName[] = { -#ifdef _ARM_ +#if defined(_TARGET_X86_) + "EBX", + "ESI", + "EDI", + "EBP", +#elif defined(_TARGET_AMD64_) + "RBX", + "RSI", + "RDI", + "RBP", + "R12", + "R13", + "R14", + "R15" +#elif defined(_TARGET_ARM_) "R4", "R5", "R6", @@ -52,18 +66,72 @@ static const char * const calleeSaveRegMaskBitNumberToName[] = "R10", "R11", "LR", -#else // _ARM_ - "EBX", - "ESI", - "EDI", - "EBP", - "R12", - "R13", - "R14", - "R15" -#endif // _ARM_ +#elif defined(_TARGET_ARM64_) + "LR", + "X19", + "X20", + "X21", + "X22", + "X23", + "X24", + "X25", + "X26", + "X27", + "X28", + "FP", +#else +#error unknown architecture +#endif }; +char const * GetReturnKindString(GCInfoHeader::MethodReturnKind returnKind) +{ + switch (returnKind) + { + case GCInfoHeader::MRK_ReturnsScalar: return "scalar"; + case GCInfoHeader::MRK_ReturnsObject: return "object"; + case GCInfoHeader::MRK_ReturnsByref: return "byref"; + case GCInfoHeader::MRK_ReturnsToNative: return "native"; +#if defined(_TARGET_ARM64_) + case GCInfoHeader::MRK_Scalar_Obj: return "{scalar, object}"; + case GCInfoHeader::MRK_Obj_Obj: return "{object, object}"; + case GCInfoHeader::MRK_Byref_Obj: return "{byref, object}"; + case GCInfoHeader::MRK_Scalar_Byref: return "{scalar, byref}"; + case GCInfoHeader::MRK_Obj_Byref: return "{object, byref}"; + case GCInfoHeader::MRK_Byref_Byref: return "{byref, byref}"; +#endif // defined(_TARGET_ARM64_) + default: return "???"; + } +} + +char const * GetFramePointerRegister() +{ +#if defined(_TARGET_X86_) + return "EBP"; +#elif defined(_TARGET_AMD64_) + return "RBP"; +#elif defined(_TARGET_ARM_) + return "R7"; +#elif defined(_TARGET_ARM64_) + return "FP"; +#else +#error unknown architecture +#endif +} + +char const * GetStackPointerRegister() +{ +#if defined(_TARGET_X86_) + return "ESP"; +#elif defined(_TARGET_AMD64_) + return "RSP"; +#elif defined(_TARGET_ARM_) || defined(_TARGET_ARM64_) + return "SP"; +#else +#error unknown architecture +#endif +} + size_t FASTCALL GCDump::DumpInfoHeader (PTR_UInt8 gcInfo, Tables * pTables, GCInfoHeader * pHeader /* OUT */ @@ -105,23 +173,8 @@ size_t FASTCALL GCDump::DumpInfoHeader (PTR_UInt8 gcInfo, gcPrintf(" epilogSize: %d\n", pHeader->GetFixedEpilogSize()); gcPrintf(" epilogCount: %d %s\n", epilogCount, epilogAtEnd ? "[end]" : ""); - const char * returnKind = "????"; - unsigned reversePinvokeFrameOffset = 0; // it can't be 0 because [ebp+0] is the previous ebp - switch (pHeader->GetReturnKind()) - { - case GCInfoHeader::MRK_ReturnsScalar: returnKind = "scalar"; break; - case GCInfoHeader::MRK_ReturnsObject: returnKind = "object"; break; - case GCInfoHeader::MRK_ReturnsByref: returnKind = "byref"; break; - case GCInfoHeader::MRK_ReturnsToNative: - returnKind = "to native"; - reversePinvokeFrameOffset = pHeader->GetReversePinvokeFrameOffset(); - break; - case GCInfoHeader::MRK_Unknown: - //ASSERT("Unexpected return kind") - break; - } - gcPrintf(" returnKind: %s\n", returnKind); - gcPrintf(" frameKind: %s", pHeader->HasFramePointer() ? "EBP" : "ESP"); + gcPrintf(" returnKind: %s\n", GetReturnKindString(pHeader->GetReturnKind())); + gcPrintf(" frameKind: %s", pHeader->HasFramePointer() ? GetFramePointerRegister() : GetStackPointerRegister()); #ifdef _TARGET_AMD64_ if (pHeader->HasFramePointer()) gcPrintf(" offset: %d", pHeader->GetFramePointerOffset()); @@ -162,13 +215,13 @@ size_t FASTCALL GCDump::DumpInfoHeader (PTR_UInt8 gcInfo, } #endif - if (reversePinvokeFrameOffset != 0) + if (pHeader->ReturnsToNative()) { - gcPrintf(" reversePinvokeFrameOffset: 0x%02x\n", reversePinvokeFrameOffset); + gcPrintf(" reversePinvokeFrameOffset: 0x%02x\n", pHeader->GetReversePinvokeFrameOffset()); } - if (!epilogAtEnd || (epilogCount > 2)) + if (!epilogAtEnd && !pHeader->IsFunclet()) { gcPrintf(" epilog offsets: "); unsigned previousOffset = 0; @@ -186,31 +239,92 @@ size_t FASTCALL GCDump::DumpInfoHeader (PTR_UInt8 gcInfo, return gcInfo - gcInfoStart; } +// TODO: Can we unify this code with ReportLocalSlot in RHCodeMan.cpp? void GCDump::PrintLocalSlot(UInt32 slotNum, GCInfoHeader const * pHeader) { - // @TODO: print both EBP/ESP offsets where appropriate -#ifdef _TARGET_ARM_ - gcPrintf("local slot 0n%d, [R7+%02X] \n", slotNum, - ((GCInfoHeader*)pHeader)->GetFrameSize() - ((slotNum + 1) * POINTER_SIZE)); -#else - const char* regAndSign = "EBP-"; - size_t offset = pHeader->GetPreservedRegsSaveSize() + (slotNum * POINTER_SIZE); -# ifdef _TARGET_AMD64_ - if (((GCInfoHeader*)pHeader)->GetFramePointerOffset() == 0) + char const * baseReg; + Int32 offset; + + if (pHeader->HasFramePointer()) { - regAndSign = "RBP-"; + baseReg = GetFramePointerRegister(); +#ifdef _TARGET_ARM_ + offset = pHeader->GetFrameSize() - ((slotNum + 1) * POINTER_SIZE); +#elif defined(_TARGET_ARM64_) + if (pHeader->AreFPLROnTop()) + { + offset = -(Int32)((slotNum + 1) * POINTER_SIZE); + } + else + { + offset = (slotNum + 2) * POINTER_SIZE; + } +#elif defined(_TARGET_X86_) + offset = -pHeader->GetPreservedRegsSaveSize() - (slotNum * POINTER_SIZE); +#elif defined(_TARGET_AMD64_) + if (pHeader->GetFramePointerOffset() == 0) + { + offset = -pHeader->GetPreservedRegsSaveSize() - (slotNum * POINTER_SIZE); + } + else + { + offset = (slotNum * POINTER_SIZE); + } +#else +#error unknown architecture +#endif } else { - regAndSign = "RBP+"; - offset = (slotNum * POINTER_SIZE); + baseReg = GetStackPointerRegister(); + offset = pHeader->GetFrameSize() - ((slotNum + 1) * POINTER_SIZE); } -# endif - gcPrintf("local slot 0n%d, [%s%02X] \n", slotNum, regAndSign, offset); -#endif + + char const * sign = "+"; + if (offset < 0) + { + sign = "-"; + offset = -offset; + } + gcPrintf("local slot 0n%d, [%s%s%02X]\n", slotNum, baseReg, sign, offset); } -void GCDump::DumpCallsiteString(UInt32 callsiteOffset, PTR_UInt8 pbCallsiteString, +// Reads a 7-bit-encoded register mask: +// - 0RRRRRRR for non-ARM64 registers and { x0-x6 } ARM64 registers +// - 1RRRRRRR 0RRRRRRR for { x0-x13 } ARM64 registers +// - 1RRRRRRR 1RRRRRRR 000RRRRR for { x0-x15, xip0, xip1, lr } ARM64 registers +// Returns the number of bytes read. +size_t ReadRegisterMaskBy7Bit(PTR_UInt8 pCursor, UInt32* pMask) +{ + UInt32 byte0 = *pCursor; + if (!(byte0 & 0x80)) + { + *pMask = byte0; + return 1; + } + +#if defined(_TARGET_ARM64_) + UInt32 byte1 = *(pCursor + 1); + if (!(byte1 & 0x80)) + { + // XOR with 0x80 discards the most significant bit of byte0 + *pMask = (byte1 << 7) ^ byte0 ^ 0x80; + return 2; + } + + UInt32 byte2 = *(pCursor + 2); + if (!(byte2 & 0x80)) + { + // XOR with 0x4080 discards the most significant bits of byte0 and byte1 + *pMask = (byte2 << 14) ^ (byte1 << 7) ^ byte0 ^ 0x4080; + return 3; + } +#endif + + UNREACHABLE_MSG("Register mask is too long"); +} + +void GCDump::DumpCallsiteString(UInt32 callsiteOffset, PTR_UInt8 pbCallsiteString, GCInfoHeader const * pHeader) { gcPrintf("%04x: ", callsiteOffset); @@ -245,24 +359,35 @@ void GCDump::DumpCallsiteString(UInt32 callsiteOffset, PTR_UInt8 pbCallsiteStrin if (b & CSR_MASK_R7) { gcPrintf("R7 "); count++; } if (b & CSR_MASK_R8) { gcPrintf("R8 "); count++; } #elif defined(_TARGET_ARM64_) - // ARM64TODO: not all of these are needed? - if (b & CSR_MASK_X19) { gcPrintf("X19 "); count++; } - if (b & CSR_MASK_X20) { gcPrintf("X20 "); count++; } - if (b & CSR_MASK_X21) { gcPrintf("X21 "); count++; } - if (b & CSR_MASK_X22) { gcPrintf("X22 "); count++; } - if (b & CSR_MASK_X23) { gcPrintf("X23 "); count++; } - if (b & CSR_MASK_X24) { gcPrintf("X24 "); count++; } - if (b & CSR_MASK_X25) { gcPrintf("X25 "); count++; } - if (b & CSR_MASK_X26) { gcPrintf("X26 "); count++; } - if (b & CSR_MASK_X27) { gcPrintf("X27 "); count++; } - if (b & CSR_MASK_X28) { gcPrintf("X28 "); count++; } -#else // _ARM_ + UInt16 regs = (b & 0xF); + if (b & 0x10) { regs |= (*pCursor++ << 4); } + + ASSERT(!(regs & CSR_MASK_LR)); + if (regs & CSR_MASK_X19) { gcPrintf("X19 "); count++; } + if (regs & CSR_MASK_X20) { gcPrintf("X20 "); count++; } + if (regs & CSR_MASK_X21) { gcPrintf("X21 "); count++; } + if (regs & CSR_MASK_X22) { gcPrintf("X22 "); count++; } + if (regs & CSR_MASK_X23) { gcPrintf("X23 "); count++; } + if (regs & CSR_MASK_X24) { gcPrintf("X24 "); count++; } + if (regs & CSR_MASK_X25) { gcPrintf("X25 "); count++; } + if (regs & CSR_MASK_X26) { gcPrintf("X26 "); count++; } + if (regs & CSR_MASK_X27) { gcPrintf("X27 "); count++; } + if (regs & CSR_MASK_X28) { gcPrintf("X28 "); count++; } + if (regs & CSR_MASK_FP ) { gcPrintf("FP " ); count++; } +#elif defined(_TARGET_AMD64_) if (b & CSR_MASK_RBX) { gcPrintf("RBX "); count++; } if (b & CSR_MASK_RSI) { gcPrintf("RSI "); count++; } if (b & CSR_MASK_RDI) { gcPrintf("RDI "); count++; } if (b & CSR_MASK_RBP) { gcPrintf("RBP "); count++; } if (b & CSR_MASK_R12) { gcPrintf("R12 "); count++; } -#endif // _ARM_ +#elif defined(_TARGET_X86_) + if (b & CSR_MASK_RBX) { gcPrintf("EBX "); count++; } + if (b & CSR_MASK_RSI) { gcPrintf("ESI "); count++; } + if (b & CSR_MASK_RDI) { gcPrintf("EDI "); count++; } + if (b & CSR_MASK_RBP) { gcPrintf("EBP "); count++; } +#else +#error unknown architecture +#endif gcPrintf("\n"); } break; @@ -293,21 +418,32 @@ void GCDump::DumpCallsiteString(UInt32 callsiteOffset, PTR_UInt8 pbCallsiteStrin case CSR_NUM_X23: regName = "X23"; break; case CSR_NUM_X24: regName = "X24"; break; case CSR_NUM_X25: regName = "X25"; break; - case CSR_NUM_X26: regName = "X26"; break; - case CSR_NUM_X27: regName = "X27"; break; - case CSR_NUM_X28: regName = "X28"; break; -#else // _ARM_ + case 0: + switch (*pCursor++) + { + case CSR_NUM_X26: regName = "X26"; break; + case CSR_NUM_X27: regName = "X27"; break; + case CSR_NUM_X28: regName = "X28"; break; + case CSR_NUM_FP : regName = "FP" ; break; + } + break; +#elif defined(_TARGET_AMD64_) case CSR_NUM_RBX: regName = "RBX"; break; case CSR_NUM_RSI: regName = "RSI"; break; case CSR_NUM_RDI: regName = "RDI"; break; case CSR_NUM_RBP: regName = "RBP"; break; -#ifdef _TARGET_AMD64_ case CSR_NUM_R12: regName = "R12"; break; case CSR_NUM_R13: regName = "R13"; break; case CSR_NUM_R14: regName = "R14"; break; case CSR_NUM_R15: regName = "R15"; break; -#endif // _TARGET_AMD64_ -#endif // _ARM_ +#elif defined(_TARGET_X86_) + case CSR_NUM_RBX: regName = "EBX"; break; + case CSR_NUM_RSI: regName = "ESI"; break; + case CSR_NUM_RDI: regName = "EDI"; break; + case CSR_NUM_RBP: regName = "EBP"; break; +#else +#error unknown architecture +#endif } gcPrintf("%02x | 3 %s%s%s \n", b, regName, interior, pinned); count++; @@ -318,30 +454,41 @@ void GCDump::DumpCallsiteString(UInt32 callsiteOffset, PTR_UInt8 pbCallsiteStrin { if (b & 0x10) { - // case 4 -- "local slot set" - gcPrintf("%02x | 4 ", b); - bool isFirst = true; - - int mask = 0x01; - int slotNum = 0; - while (mask <= 0x08) + // case 4 -- "local slot set" or "common var tail" + if ((b & 0x0f) != 0) { - if (b & mask) + gcPrintf("%02x | 4 ", b); + bool isFirst = true; + + int mask = 0x01; + int slotNum = 0; + while (mask <= 0x08) { - if (!isFirst) + if (b & mask) { - if (!first) - gcPrintf(" "); - gcPrintf(" | "); + if (!isFirst) + { + if (!first) + gcPrintf(" "); + gcPrintf(" | "); + } + + PrintLocalSlot(slotNum, pHeader); + + isFirst = false; + count++; } - - PrintLocalSlot(slotNum, pHeader); - - isFirst = false; - count++; + mask <<= 1; + slotNum++; } - mask <<= 1; - slotNum++; + } + else + { + unsigned commonVarInx = 0; + if ((b & 0x20) == 0) + commonVarInx = VarInt::ReadUnsigned(pCursor); + + gcPrintf("%02x | 8 set #%04u\n", b, commonVarInx); } } else @@ -357,50 +504,124 @@ void GCDump::DumpCallsiteString(UInt32 callsiteOffset, PTR_UInt8 pbCallsiteStrin break; case 0xC0: { - gcPrintf("%02x ", b); - unsigned mask = 0; - PTR_UInt8 pInts = pCursor; - unsigned offset = VarInt::ReadUnsigned(pCursor); - const char* interior = (b & 0x10) ? "+" : ""; - const char* pinned = (b & 0x08) ? "!" : ""; -#ifdef _TARGET_ARM_ - const char* baseReg = (b & 0x04) ? "R7" : "SP"; -#else - const char* baseReg = (b & 0x04) ? "EBP" : "ESP"; -#endif - const char* sign = (b & 0x02) ? "-" : "+"; - if (b & 0x01) + if ((b & 0xC7) == 0xC2) { - mask = VarInt::ReadUnsigned(pCursor); - } + // case 7 - live scratch regs + gcPrintf("%02x | 7 ", b); - int c = 1; - while (pInts != pCursor) - { - gcPrintf("%02x ", *pInts++); - c++; - } + UInt32 regs, byrefRegs = 0, pinnedRegs = 0; + pCursor += ReadRegisterMaskBy7Bit(pCursor, ®s); + if (b & 0x10) + pCursor += ReadRegisterMaskBy7Bit(pCursor, &byrefRegs); + if (b & 0x08) + pCursor += ReadRegisterMaskBy7Bit(pCursor, &pinnedRegs); - for (; c < 4; c++) - { - gcPrintf(" "); - } - - gcPrintf("| 6 [%s%s%02X]%s%s\n", baseReg, sign, offset, interior, pinned); - count++; - - while (mask > 0) - { - offset += POINTER_SIZE; - if (mask & 1) + for (UInt32 reg = 0; ; reg++) { - if (!first) - gcPrintf(" "); + UInt32 regMask = (1 << reg); + if (regMask > regs) + break; - gcPrintf(" | [%s%s%02X]%s%s\n", baseReg, sign, offset, interior, pinned); - count++; + if (regs & regMask) + { + char* pinned = (pinnedRegs & regMask) ? "!" : ""; + char* interior = (byrefRegs & regMask) ? "+" : ""; + char* regStr = "???"; + + switch (reg) + { +#if defined(_TARGET_ARM_) + case SR_NUM_R0: regStr = "R0"; break; + case SR_NUM_R1: regStr = "R1"; break; + case SR_NUM_R2: regStr = "R2"; break; + case SR_NUM_R3: regStr = "R3"; break; + case SR_NUM_R12: regStr = "R12"; break; + case SR_NUM_LR: regStr = "LR"; break; +#elif defined(_TARGET_ARM64_) + case SR_NUM_X0: regStr = "X0"; break; + case SR_NUM_X1: regStr = "X1"; break; + case SR_NUM_X2: regStr = "X2"; break; + case SR_NUM_X3: regStr = "X3"; break; + case SR_NUM_X4: regStr = "X4"; break; + case SR_NUM_X5: regStr = "X5"; break; + case SR_NUM_X6: regStr = "X6"; break; + case SR_NUM_X7: regStr = "X7"; break; + case SR_NUM_X8: regStr = "X8"; break; + case SR_NUM_X9: regStr = "X9"; break; + case SR_NUM_X10: regStr = "X10"; break; + case SR_NUM_X11: regStr = "X11"; break; + case SR_NUM_X12: regStr = "X12"; break; + case SR_NUM_X13: regStr = "X13"; break; + case SR_NUM_X14: regStr = "X14"; break; + case SR_NUM_X15: regStr = "X15"; break; + case SR_NUM_XIP0: regStr = "XIP0"; break; + case SR_NUM_XIP1: regStr = "XIP1"; break; + case SR_NUM_LR: regStr = "LR"; break; +#elif defined(_TARGET_AMD64_) + case SR_NUM_RAX: regStr = "RAX"; break; + case SR_NUM_RCX: regStr = "RCX"; break; + case SR_NUM_RDX: regStr = "RDX"; break; + case SR_NUM_R8: regStr = "R8"; break; + case SR_NUM_R9: regStr = "R9"; break; + case SR_NUM_R10: regStr = "R10"; break; + case SR_NUM_R11: regStr = "R11"; break; +#elif defined(_TARGET_X86_) + case SR_NUM_RAX: regStr = "EAX"; break; + case SR_NUM_RCX: regStr = "ECX"; break; + case SR_NUM_RDX: regStr = "EDX"; break; +#else +#error unknown architecture +#endif + } + gcPrintf("%s%s%s ", regStr, interior, pinned); + count++; + } + } + } + else + { + // case 6 - stack slot / stack slot set + gcPrintf("%02x ", b); + unsigned mask = 0; + PTR_UInt8 pInts = pCursor; + unsigned offset = VarInt::ReadUnsigned(pCursor); + const char* interior = (b & 0x10) ? "+" : ""; + const char* pinned = (b & 0x08) ? "!" : ""; + const char* baseReg = (b & 0x04) ? GetFramePointerRegister() : GetStackPointerRegister(); + const char* sign = (b & 0x02) ? "-" : "+"; + if (b & 0x01) + { + mask = VarInt::ReadUnsigned(pCursor); + } + + int c = 1; + while (pInts != pCursor) + { + gcPrintf("%02x ", *pInts++); + c++; + } + + for (; c < 4; c++) + { + gcPrintf(" "); + } + + gcPrintf("| 6 [%s%s%02X]%s%s\n", baseReg, sign, offset, interior, pinned); + count++; + + while (mask > 0) + { + offset += POINTER_SIZE; + if (mask & 1) + { + if (!first) + gcPrintf(" "); + + gcPrintf(" | [%s%s%02X]%s%s\n", baseReg, sign, offset, interior, pinned); + count++; + } + mask >>= 1; } - mask >>= 1; } } break; @@ -411,13 +632,21 @@ void GCDump::DumpCallsiteString(UInt32 callsiteOffset, PTR_UInt8 pbCallsiteStrin //gcPrintf("\n"); } - - - size_t FASTCALL GCDump::DumpGCTable (PTR_UInt8 gcInfo, Tables * pTables, const GCInfoHeader& header) { + PTR_UInt8 pCursor = gcInfo; + + if (header.HasCommonVars()) + { + UInt32 commonVarCount = VarInt::ReadUnsigned(pCursor); + for (UInt32 i = 0; i < commonVarCount; i++) + { + VarInt::SkipUnsigned(pCursor); + } + } + // // Decode the method GC info // @@ -439,7 +668,6 @@ size_t FASTCALL GCDump::DumpGCTable (PTR_UInt8 gcInfo, // 11111111 -- STRING TERMINATOR // - PTR_UInt8 pCursor = gcInfo; UInt32 curOffset = 0; for (;;) diff --git a/external/corert/src/Native/Runtime/inc/WellKnownMethodList.h b/external/corert/src/Native/Runtime/inc/WellKnownMethodList.h index 567764bbc4..e4079e6ca0 100644 --- a/external/corert/src/Native/Runtime/inc/WellKnownMethodList.h +++ b/external/corert/src/Native/Runtime/inc/WellKnownMethodList.h @@ -9,3 +9,5 @@ DEFINE_WELL_KNOWN_METHOD(AppendExceptionStackFrame) DEFINE_WELL_KNOWN_METHOD(CheckStaticClassConstruction) DEFINE_WELL_KNOWN_METHOD(InitializeFinalizerThread) DEFINE_WELL_KNOWN_METHOD(OnFirstChanceException) +DEFINE_WELL_KNOWN_METHOD(DebugFuncEvalHelper) +DEFINE_WELL_KNOWN_METHOD(DebugFuncEvalAbortHelper) \ No newline at end of file diff --git a/external/corert/src/Native/Runtime/inc/WellKnownMethods.h b/external/corert/src/Native/Runtime/inc/WellKnownMethods.h index 18ca5b82dd..9e9614719d 100644 --- a/external/corert/src/Native/Runtime/inc/WellKnownMethods.h +++ b/external/corert/src/Native/Runtime/inc/WellKnownMethods.h @@ -22,6 +22,8 @@ enum WellKnownMethodIds }; #undef DEFINE_WELL_KNOWN_METHOD +#ifdef BINDER + // Define an array of well known method names which are indexed by the enums defined above. #define DEFINE_WELL_KNOWN_METHOD(_name) #_name, extern __declspec(selectany) const char * const g_rgWellKnownMethodNames[] = @@ -30,4 +32,6 @@ extern __declspec(selectany) const char * const g_rgWellKnownMethodNames[] = }; #undef DEFINE_WELL_KNOWN_METHOD +#endif // BINDER + #endif // !__WELLKNOWNMETHODS_INCLUDED diff --git a/external/corert/src/Native/Runtime/inc/gcinfo.h b/external/corert/src/Native/Runtime/inc/gcinfo.h index eb04978613..803cb9f6bc 100644 --- a/external/corert/src/Native/Runtime/inc/gcinfo.h +++ b/external/corert/src/Native/Runtime/inc/gcinfo.h @@ -128,7 +128,7 @@ enum RegMask RBM_X5 = 0x00000020, RBM_X6 = 0x00000040, RBM_X7 = 0x00000080, - RBM_X8 = 0x00000100, // ARM64TODO: ARM64 ABI: indirect result register + RBM_X8 = 0x00000100, // ARM64 ABI: indirect result register RBM_X9 = 0x00000200, RBM_X10 = 0x00000400, RBM_X11 = 0x00000800, @@ -535,15 +535,19 @@ private: { struct { +#if defined(_TARGET_ARM64_) + UInt8 FPLRAreOnTop : 1; // [0] 1: FP and LR are saved on top of locals, not at the bottom (see MdmSaveFPAndLRAtTopOfLocalsArea) + UInt8 reg1ReturnKind : 2; // [1:2] One of MRK_Returns{Scalar|Object|Byref} constants describing value returned in x1 if any + UInt8 hasGSCookie : 1; // [3] 1: frame uses GS cookie + UInt8 hasCommonVars : 1; // [4] 1: method has a list of "common vars" + // as an optimization for methods with many call sites and variables + UInt8 : 3; // [5:7] unused bits +#else UInt8 logStackAlignment : 4; // [0:3] binary logarithm of frame alignment (3..15) or 0 UInt8 hasGSCookie : 1; // [4] 1: frame uses GS cookie UInt8 hasCommonVars : 1; // [5] 1: method has a list of "common vars" // as an optimization for methods with many call sites and variables -#if defined(_TARGET_ARM64_) - UInt8 FPLRAreOnTop : 1; // [6] 1: FP and LR are saved on top of locals, not at the bottom (see MdmSaveFPAndLRAtTopOfLocalsArea) - UInt8 extraDataUnused : 1; // [7] unused bits -#else - UInt8 extraDataUnused : 2; // [6:7] unused bits + UInt8 : 2; // [6:7] unused bits #endif #pragma warning(suppress:4201) // nameless struct }; @@ -608,7 +612,28 @@ public: MRK_ReturnsObject = 1, MRK_ReturnsByref = 2, MRK_ReturnsToNative = 3, + +#if defined(_TARGET_ARM64_) + // Cases for structs returned in two registers. + // Naming scheme: MRK_reg0Kind_reg1Kind. + // Encoding scheme: . + // We do not distinguish returning a scalar in reg1 and no return value in reg1, + // which means we can use MRK_ReturnsObject for MRK_Obj_Scalar, etc. + MRK_Scalar_Obj = (MRK_ReturnsObject << 2) | MRK_ReturnsScalar, + MRK_Obj_Obj = (MRK_ReturnsObject << 2) | MRK_ReturnsObject, + MRK_Byref_Obj = (MRK_ReturnsObject << 2) | MRK_ReturnsByref, + MRK_Scalar_Byref = (MRK_ReturnsByref << 2) | MRK_ReturnsScalar, + MRK_Obj_Byref = (MRK_ReturnsByref << 2) | MRK_ReturnsObject, + MRK_Byref_Byref = (MRK_ReturnsByref << 2) | MRK_ReturnsByref, + + MRK_LastValid = MRK_Byref_Byref, + // Illegal or uninitialized value. Never written to the image. + MRK_Unknown = 0xff, +#else + MRK_LastValid = MRK_ReturnsToNative, + // Illegal or uninitialized value. Never written to the image. MRK_Unknown = 4, +#endif }; enum EncodingConstants @@ -672,7 +697,15 @@ public: else { ASSERT(sizeInBytes != 0); - PokeFixedEpilogSize(sizeInBytes); +#if defined (_TARGET_ARM64_) + // For arm64 we encode multiples of 4, rather than raw bytes, since instructions are all same size. + ASSERT((sizeInBytes & 3) == 0); + fixedEpilogSize = sizeInBytes >> 2; + ASSERT(fixedEpilogSize == sizeInBytes >> 2); +#else + fixedEpilogSize = sizeInBytes; + ASSERT(fixedEpilogSize == sizeInBytes); +#endif } } @@ -686,9 +719,10 @@ public: epilogCountSmall = count < EC_MaxEpilogCountSmall ? count : EC_MaxEpilogCountSmall; } +#if !defined(_TARGET_ARM64_) void SetReturnKind(MethodReturnKind kind) { - ASSERT(kind < MRK_Unknown); // not enough bits to encode 'unknown' + ASSERT(kind <= MRK_ReturnsToNative); // not enough bits to encode 'unknown' returnKind = kind; } @@ -705,6 +739,7 @@ public: ASSERT(logStackAlignment == logByteAlignment); paramPointerReg = RN_NONE; } +#endif // !defined(_TARGET_ARM64_) #if defined(_TARGET_ARM64_) void SetFPLROnTop(void) @@ -931,7 +966,11 @@ public: UInt32 GetFixedEpilogSize() { ASSERT(!HasVaryingEpilogSizes()); - return PeekFixedEpilogSize(); +#if defined (_TARGET_ARM64_) + return fixedEpilogSize << 2; +#else + return fixedEpilogSize; +#endif } UInt32 GetEpilogCount() @@ -946,7 +985,11 @@ public: MethodReturnKind GetReturnKind() { +#if defined(_TARGET_ARM64_) + return (MethodReturnKind)((reg1ReturnKind << 2) | returnKind); +#else return (MethodReturnKind)returnKind; +#endif } bool ReturnsToNative() @@ -954,7 +997,7 @@ public: return (GetReturnKind() == MRK_ReturnsToNative); } - bool HasFramePointer() + bool HasFramePointer() const { return !!ebpFrame; } @@ -989,12 +1032,21 @@ public: bool HasDynamicAlignment() { +#if defined(_TARGET_ARM64_) + return false; +#else return !!logStackAlignment; +#endif } UInt32 GetDynamicAlignment() { +#if defined(_TARGET_ARM64_) + ASSERT(!"Not supported"); + return 1; +#else return 1 << logStackAlignment; +#endif } bool HasGSCookie() @@ -1003,7 +1055,7 @@ public: } #if defined(_TARGET_ARM64_) - bool AreFPLROnTop() + bool AreFPLROnTop() const { return FPLRAreOnTop; } @@ -1015,7 +1067,7 @@ public: return gsCookieOffset * POINTER_SIZE; } - bool HasCommonVars() + bool HasCommonVars() const { return hasCommonVars; } @@ -1028,7 +1080,7 @@ public: #ifdef _TARGET_AMD64_ static const UInt32 SKEW_FOR_OFFSET_FROM_SP = 0x10; - int GetFramePointerOffset() // returned in bytes + int GetFramePointerOffset() const // returned in bytes { // traditional frames where FP points to the pushed FP have fp offset == 0 if (x64_framePtrOffset == 0) @@ -1048,12 +1100,12 @@ public: return offsetFromSP - preservedRegsSaveSize - GetFrameSize(); } - bool IsFramePointerOffsetFromSP() + bool IsFramePointerOffsetFromSP() const { return x64_framePtrOffset != 0; } - int GetFramePointerOffsetFromSP() + int GetFramePointerOffsetFromSP() const { ASSERT(IsFramePointerOffsetFromSP()); int offsetFromSP; @@ -1095,7 +1147,7 @@ public: } #endif - int GetFrameSize() + int GetFrameSize() const { return frameSize * POINTER_SIZE; } @@ -1126,7 +1178,7 @@ public: return (CalleeSavedRegMask) calleeSavedRegMask; } - bool IsRegSaved(CalleeSavedRegMask reg) + bool IsRegSaved(CalleeSavedRegMask reg) const { return (0 != (calleeSavedRegMask & reg)); } @@ -1449,7 +1501,7 @@ public: // the per-method epilog table, so at least we're consistent with what is encoded. UInt8 mainEpilogAtEnd = epilogAtEnd; UInt16 mainEpilogCount = epilogCount; - UInt16 mainFixedEpilogSize = (UInt16) PeekFixedEpilogSize(); + UInt16 mainFixedEpilogSize = fixedEpilogSize; // Either in bytes or in instructions UInt8 mainHasCommonVars = hasCommonVars; // ------- @@ -1589,15 +1641,24 @@ public: #ifdef RHDUMP char const * GetBoolStr(bool val) { return val ? " true" : "false"; } - char const * GetRetKindStr(int k) + + char const * GetRetKindStr(MethodReturnKind kind) { - switch (k) + switch (kind) { case MRK_ReturnsScalar: return "scalar"; case MRK_ReturnsObject: return "object"; - case MRK_ReturnsByref: return " byref"; + case MRK_ReturnsByref: return "byref"; case MRK_ReturnsToNative: return "native"; - default: return "unknwn"; +#if defined(_TARGET_ARM64_) + case MRK_Scalar_Obj: return "{scalar, object}"; + case MRK_Scalar_Byref: return "{scalar, byref}"; + case MRK_Obj_Obj: return "{object, object}"; + case MRK_Obj_Byref: return "{object, byref}"; + case MRK_Byref_Obj: return "{byref, object}"; + case MRK_Byref_Byref: return "{byref, byref}"; +#endif // defined(_TARGET_ARM64_) + default: return "unknown"; } } @@ -1739,10 +1800,10 @@ public: void Dump() { - printf(" | prologSize: %02X"" | epilogSize: %02X"" | epilogCount: %02X"" | epilogAtEnd: %s\n", - GetPrologSize(), PeekFixedEpilogSize(), epilogCount, GetBoolStr(epilogAtEnd)); - printf(" | frameSize: %04X"" | ebpFrame: %s"" | hasFunclets: %s"" | returnKind: %s\n", - GetFrameSize(), GetBoolStr(ebpFrame), GetBoolStr(hasFunclets), GetRetKindStr(returnKind)); + printf(" | prologSize: %02X"" | epilogSize: %02X"" | epilogCount: %02X"" | epilogAtEnd: %s\n", + GetPrologSize(), HasVaryingEpilogSizes() ? 0 : GetFixedEpilogSize(), epilogCount, GetBoolStr(epilogAtEnd)); + printf(" | frameSize: %04X"" | ebpFrame: %s"" | hasFunclets: %s"" | returnKind: %s\n", + GetFrameSize(), GetBoolStr(ebpFrame), GetBoolStr(hasFunclets), GetRetKindStr(GetReturnKind())); printf(" | regMask: %04X" " {", calleeSavedRegMask); PrintCalleeSavedRegs(calleeSavedRegMask); printf(" }\n"); diff --git a/external/corert/src/Native/Runtime/inc/rhbinder.h b/external/corert/src/Native/Runtime/inc/rhbinder.h index 1dee732023..01fbbfcf6a 100644 --- a/external/corert/src/Native/Runtime/inc/rhbinder.h +++ b/external/corert/src/Native/Runtime/inc/rhbinder.h @@ -62,7 +62,8 @@ struct ModuleHeader // breaking changes DELTA_SHORTCUT_TABLE_SIZE = 16, MAX_REGIONS = 8, // Max number of regions described by the Regions array - MAX_WELL_KNOWN_METHODS = 8, // Max number of methods described by the WellKnownMethods array + MAX_WELL_KNOWN_METHODS = 8, // Max number of methods described by the WellKnownMethods array + MAX_EXTRA_WELL_KNOWN_METHODS= 8, // Max number of methods described by the ExtraWellKnownMethods array NULL_RRA = 0xffffffff, // NULL value for region relative addresses (0 is often a // legal RRA) }; @@ -141,6 +142,9 @@ struct ModuleHeader UInt32 RraColdToHotMappingInfo; + UInt32 ExtraWellKnownMethods[MAX_EXTRA_WELL_KNOWN_METHODS]; // Array of methods with well known semantics defined + // in this module + // Macro to generate an inline accessor for RRA-based fields. #ifdef RHDUMP #define DEFINE_GET_ACCESSOR(_field, _region)\ @@ -202,10 +206,19 @@ struct ModuleHeader #ifndef RHDUMP // Macro to generate an inline accessor for well known methods (these are all TEXT-based RRAs since they // point to code). -#define DEFINE_WELL_KNOWN_METHOD(_name) \ - inline PTR_VOID Get_##_name() \ - { \ - return WellKnownMethods[WKM_##_name] == NULL_RRA ? NULL : RegionPtr[TEXT_REGION] + WellKnownMethods[WKM_##_name]; \ +#define DEFINE_WELL_KNOWN_METHOD(_name) \ + inline PTR_VOID Get_##_name() \ + { \ + unsigned int index = (unsigned int)WKM_##_name; \ + if (index >= MAX_WELL_KNOWN_METHODS) \ + { \ + index = index - MAX_WELL_KNOWN_METHODS; \ + return ExtraWellKnownMethods[index] == NULL_RRA ? NULL : RegionPtr[TEXT_REGION] + ExtraWellKnownMethods[index]; \ + } \ + else \ + { \ + return WellKnownMethods[index] == NULL_RRA ? NULL : RegionPtr[TEXT_REGION] + WellKnownMethods[index]; \ + } \ } #include "WellKnownMethodList.h" #undef DEFINE_WELL_KNOWN_METHOD @@ -649,14 +662,38 @@ enum PInvokeTransitionFrameFlags : UInt64 // a return address pointing into the hijacked method and that method's // lr register, which may hold a gc pointer - // Other flags - PTFF_X0_IS_GCREF = 0x0000000100000000, // used by hijack handler to report return value of hijacked method - PTFF_X0_IS_BYREF = 0x0000000200000000, // used by hijack handler to report return value of hijacked method - PTFF_X1_IS_GCREF = 0x0000000400000000, // used by hijack handler to report return value of hijacked method - PTFF_X1_IS_BYREF = 0x0000000800000000, // used by hijack handler to report return value of hijacked method + // used by hijack handler to report return value of hijacked method + PTFF_X0_IS_GCREF = 0x0000000100000000, + PTFF_X0_IS_BYREF = 0x0000000200000000, + PTFF_X1_IS_GCREF = 0x0000000400000000, + PTFF_X1_IS_BYREF = 0x0000000800000000, PTFF_THREAD_ABORT = 0x0000001000000000, // indicates that ThreadAbortException should be thrown when returning from the transition }; + +// TODO: Consider moving the PInvokeTransitionFrameFlags definition to a separate file to simplify header dependencies +#ifdef ICODEMANAGER_INCLUDED +// Verify that we can use bitwise shifts to convert from GCRefKind to PInvokeTransitionFrameFlags and back +C_ASSERT(PTFF_X0_IS_GCREF == ((UInt64)GCRK_Object << 32)); +C_ASSERT(PTFF_X0_IS_BYREF == ((UInt64)GCRK_Byref << 32)); +C_ASSERT(PTFF_X1_IS_GCREF == ((UInt64)GCRK_Scalar_Obj << 32)); +C_ASSERT(PTFF_X1_IS_BYREF == ((UInt64)GCRK_Scalar_Byref << 32)); + +inline UInt64 ReturnKindToTransitionFrameFlags(GCRefKind returnKind) +{ + if (returnKind == GCRK_Scalar) + return 0; + + return PTFF_SAVE_X0 | PTFF_SAVE_X1 | ((UInt64)returnKind << 32); +} + +inline GCRefKind TransitionFrameFlagsToReturnKind(UInt64 transFrameFlags) +{ + GCRefKind returnKind = (GCRefKind)((transFrameFlags & (PTFF_X0_IS_GCREF | PTFF_X0_IS_BYREF | PTFF_X1_IS_GCREF | PTFF_X1_IS_BYREF)) >> 32); + ASSERT((returnKind == GCRK_Scalar) || ((transFrameFlags & PTFF_SAVE_X0) && (transFrameFlags & PTFF_SAVE_X1))); + return returnKind; +} +#endif // ICODEMANAGER_INCLUDED #else // _TARGET_ARM_ enum PInvokeTransitionFrameFlags { diff --git a/external/corert/src/Native/Runtime/module.cpp b/external/corert/src/Native/Runtime/module.cpp index 6cfa13f953..067f361b80 100644 --- a/external/corert/src/Native/Runtime/module.cpp +++ b/external/corert/src/Native/Runtime/module.cpp @@ -824,6 +824,12 @@ void * Module::GetClasslibFunction(ClasslibFunctionId functionId) case ClasslibFunctionId::OnFirstChanceException: pMethod = m_pModuleHeader->Get_OnFirstChanceException(); break; + case ClasslibFunctionId::DebugFuncEvalHelper: + pMethod = m_pModuleHeader->Get_DebugFuncEvalHelper(); + break; + case ClasslibFunctionId::DebugFuncEvalAbortHelper: + pMethod = m_pModuleHeader->Get_DebugFuncEvalAbortHelper(); + break; default: pMethod = NULL; break; @@ -1165,7 +1171,7 @@ void Module::DoCustomImports(ModuleHeader * pModuleHeader) // obtain address of indirection cell pointing to the EAT for the exporting module UInt32 **ptrPtrEAT = (UInt32 **)(thisBaseAddress + customImportTable[i].RvaEATAddr); - // obtain the EAT by derefencing + // obtain the EAT by dereferencing UInt32 *ptrEAT = *ptrPtrEAT; // obtain the exporting module diff --git a/external/corert/src/Native/Runtime/stressLog.cpp b/external/corert/src/Native/Runtime/stressLog.cpp index 5e62780910..a0b097c897 100644 --- a/external/corert/src/Native/Runtime/stressLog.cpp +++ b/external/corert/src/Native/Runtime/stressLog.cpp @@ -71,7 +71,7 @@ unsigned __int64 getTimeStamp() { #endif // _X86_ else /*********************************************************************************/ -/* Get the the frequency cooresponding to 'getTimeStamp'. For non-x86 +/* Get the the frequency corresponding to 'getTimeStamp'. For non-x86 architectures, this is just the performance counter frequency. */ unsigned __int64 getTickFrequency() diff --git a/external/corert/src/Native/Runtime/thread.cpp b/external/corert/src/Native/Runtime/thread.cpp index 059ec5abee..994c21dad8 100644 --- a/external/corert/src/Native/Runtime/thread.cpp +++ b/external/corert/src/Native/Runtime/thread.cpp @@ -450,12 +450,27 @@ bool Thread::GcScanRoots(GcScanRootsCallbackFunc * pfnEnumCallback, void * token void Thread::GcScanRootsWorker(void * pfnEnumCallback, void * pvCallbackData, StackFrameIterator & frameIterator) { - PTR_RtuObjectRef pHijackedReturnValue = NULL; - GCRefKind ReturnValueKind = GCRK_Unknown; + PTR_RtuObjectRef pHijackedReturnValue = NULL; + GCRefKind returnValueKind = GCRK_Unknown; - if (frameIterator.GetHijackedReturnValueLocation(&pHijackedReturnValue, &ReturnValueKind)) + if (frameIterator.GetHijackedReturnValueLocation(&pHijackedReturnValue, &returnValueKind)) { - RedhawkGCInterface::EnumGcRef(pHijackedReturnValue, ReturnValueKind, pfnEnumCallback, pvCallbackData); +#ifdef _TARGET_ARM64_ + GCRefKind reg0Kind = ExtractReg0ReturnKind(returnValueKind); + GCRefKind reg1Kind = ExtractReg1ReturnKind(returnValueKind); + + // X0 and X1 are saved next to each other in this order + if (reg0Kind != GCRK_Scalar) + { + RedhawkGCInterface::EnumGcRef(pHijackedReturnValue, reg0Kind, pfnEnumCallback, pvCallbackData); + } + if (reg1Kind != GCRK_Scalar) + { + RedhawkGCInterface::EnumGcRef(pHijackedReturnValue + 1, reg1Kind, pfnEnumCallback, pvCallbackData); + } +#else + RedhawkGCInterface::EnumGcRef(pHijackedReturnValue, returnValueKind, pfnEnumCallback, pvCallbackData); +#endif } #ifndef DACCESS_COMPILE @@ -507,7 +522,7 @@ void Thread::GcScanRootsWorker(void * pfnEnumCallback, void * pvCallbackData, St // interface invocation slow paths for instance. Since the original managed call may have passed GC // references which are unreported by any managed method on the stack at the time of the GC we // identify (again conservatively) the range of the stack that might contain these references and - // report everything. Since it should be a very rare occurance indeed that we actually have to do + // report everything. Since it should be a very rare occurrence indeed that we actually have to do // this this, it's considered a better trade-off than storing signature metadata for every potential // callsite of the type described above. if (frameIterator.HasStackRangeToReportConservatively()) @@ -544,40 +559,58 @@ void Thread::GcScanRootsWorker(void * pfnEnumCallback, void * pvCallbackData, St #ifndef DACCESS_COMPILE +#ifndef _TARGET_ARM64_ EXTERN_C void FASTCALL RhpGcProbeHijackScalar(); EXTERN_C void FASTCALL RhpGcProbeHijackObject(); EXTERN_C void FASTCALL RhpGcProbeHijackByref(); -static void* NormalHijackTargets[3] = +static void* NormalHijackTargets[3] = { reinterpret_cast(RhpGcProbeHijackScalar), // GCRK_Scalar = 0, - reinterpret_cast(RhpGcProbeHijackObject), // GCRK_Object = 1, + reinterpret_cast(RhpGcProbeHijackObject), // GCRK_Object = 1, reinterpret_cast(RhpGcProbeHijackByref) // GCRK_Byref = 2, }; +#else // _TARGET_ARM64_ +EXTERN_C void FASTCALL RhpGcProbeHijack(); + +static void* NormalHijackTargets[1] = +{ + reinterpret_cast(RhpGcProbeHijack) +}; +#endif // _TARGET_ARM64_ #ifdef FEATURE_GC_STRESS +#ifndef _TARGET_ARM64_ EXTERN_C void FASTCALL RhpGcStressHijackScalar(); EXTERN_C void FASTCALL RhpGcStressHijackObject(); EXTERN_C void FASTCALL RhpGcStressHijackByref(); -static void* GcStressHijackTargets[3] = -{ +static void* GcStressHijackTargets[3] = +{ reinterpret_cast(RhpGcStressHijackScalar), // GCRK_Scalar = 0, - reinterpret_cast(RhpGcStressHijackObject), // GCRK_Object = 1, + reinterpret_cast(RhpGcStressHijackObject), // GCRK_Object = 1, reinterpret_cast(RhpGcStressHijackByref) // GCRK_Byref = 2, }; +#else // _TARGET_ARM64_ +EXTERN_C void FASTCALL RhpGcStressHijack(); + +static void* GcStressHijackTargets[1] = +{ + reinterpret_cast(RhpGcStressHijack) +}; +#endif // _TARGET_ARM64_ #endif // FEATURE_GC_STRESS // static bool Thread::IsHijackTarget(void * address) { - for (int i = 0; i < 3; i++) + for (int i = 0; i < COUNTOF(NormalHijackTargets); i++) { if (NormalHijackTargets[i] == address) return true; } #ifdef FEATURE_GC_STRESS - for (int i = 0; i < 3; i++) + for (int i = 0; i < COUNTOF(GcStressHijackTargets); i++) { if (GcStressHijackTargets[i] == address) return true; @@ -683,7 +716,7 @@ void Thread::HijackForGcStress(PAL_LIMITED_CONTEXT * pSuspendCtx) // 2) from another thread to place a return hijack onto this thread's stack. In this case the target // thread is OS suspended someplace in managed code. The only constraint on the suspension is that the // stack be crawlable enough to yield the location of the return address. -bool Thread::InternalHijack(PAL_LIMITED_CONTEXT * pSuspendCtx, void* HijackTargets[3]) +bool Thread::InternalHijack(PAL_LIMITED_CONTEXT * pSuspendCtx, void * pvHijackTargets[]) { bool fSuccess = false; @@ -716,10 +749,14 @@ bool Thread::InternalHijack(PAL_LIMITED_CONTEXT * pSuspendCtx, void* HijackTarge m_ppvHijackedReturnAddressLocation = ppvRetAddrLocation; m_pvHijackedReturnAddress = pvRetAddr; - void* pvHijackTarget = HijackTargets[retValueKind]; +#ifdef _TARGET_ARM64_ + m_uHijackedReturnValueFlags = ReturnKindToTransitionFrameFlags(retValueKind); + *ppvRetAddrLocation = pvHijackTargets[0]; +#else + void* pvHijackTarget = pvHijackTargets[retValueKind]; ASSERT_MSG(IsHijackTarget(pvHijackTarget), "unexpected method used as hijack target"); *ppvRetAddrLocation = pvHijackTarget; - +#endif fSuccess = true; } } @@ -768,6 +805,9 @@ void Thread::UnhijackWorker() // Clear the hijack state. m_ppvHijackedReturnAddressLocation = NULL; m_pvHijackedReturnAddress = NULL; +#ifdef _TARGET_ARM64_ + m_uHijackedReturnValueFlags = 0; +#endif } #if _DEBUG diff --git a/external/corert/src/Native/Runtime/thread.h b/external/corert/src/Native/Runtime/thread.h index 930114ba4a..c3934c823d 100644 --- a/external/corert/src/Native/Runtime/thread.h +++ b/external/corert/src/Native/Runtime/thread.h @@ -14,19 +14,19 @@ class Thread; // runtime build. #define KEEP_THREAD_LAYOUT_CONSTANT -#if defined(_X86_) || defined(_ARM_) || defined(_WASM_) +#ifndef BIT64 # if defined(FEATURE_SVR_GC) || defined(KEEP_THREAD_LAYOUT_CONSTANT) # define SIZEOF_ALLOC_CONTEXT 40 -# else // FEATURE_SVR_GC +# else # define SIZEOF_ALLOC_CONTEXT 28 -# endif // FEATURE_SVR_GC -#elif defined(_AMD64_) || defined(_ARM64_) +# endif +#else // BIT64 # if defined(FEATURE_SVR_GC) || defined(KEEP_THREAD_LAYOUT_CONSTANT) # define SIZEOF_ALLOC_CONTEXT 56 -# else // FEATURE_SVR_GC +# else # define SIZEOF_ALLOC_CONTEXT 40 -# endif // FEATURE_SVR_GC -#endif // _AMD64_ +# endif +#endif // BIT64 #define TOP_OF_STACK_MARKER ((PTR_VOID)(UIntNative)(IntNative)-1) @@ -60,8 +60,6 @@ struct ExInfo volatile void* m_notifyDebuggerSP; }; - - struct ThreadBuffer { UInt8 m_rgbAllocContextBuffer[SIZEOF_ALLOC_CONTEXT]; @@ -77,6 +75,9 @@ struct ThreadBuffer HANDLE m_hPalThread; // WARNING: this may legitimately be INVALID_HANDLE_VALUE void ** m_ppvHijackedReturnAddressLocation; void * m_pvHijackedReturnAddress; +#ifdef BIT64 + UIntNative m_uHijackedReturnValueFlags; // used on ARM64 only; however, ARM64 and AMD64 share field offsets +#endif // BIT64 PTR_ExInfo m_pExInfoStackHead; Object* m_threadAbortException; // ThreadAbortException instance -set only during thread abort PTR_VOID m_pStackLow; @@ -136,7 +137,7 @@ private: bool IsStateSet(ThreadStateFlags flags); static UInt32_BOOL HijackCallback(HANDLE hThread, PAL_LIMITED_CONTEXT* pThreadContext, void* pCallbackContext); - bool InternalHijack(PAL_LIMITED_CONTEXT * pCtx, void* HijackTargets[3]); + bool InternalHijack(PAL_LIMITED_CONTEXT * pSuspendCtx, void * pvHijackTargets[]); bool CacheTransitionFrameForSuspend(); void ResetCachedTransitionFrame(); @@ -161,7 +162,7 @@ public: bool IsInitialized(); - gc_alloc_context * GetAllocContext(); // @TODO: I would prefer to not expose this in this way + gc_alloc_context * GetAllocContext(); // @TODO: I would prefer to not expose this in this way #ifndef DACCESS_COMPILE UInt64 GetPalThreadIdForLogging(); @@ -176,7 +177,7 @@ public: bool Hijack(); void Unhijack(); #ifdef FEATURE_GC_STRESS - static void HijackForGcStress(PAL_LIMITED_CONTEXT * pCtx); + static void HijackForGcStress(PAL_LIMITED_CONTEXT * pSuspendCtx); #endif // FEATURE_GC_STRESS bool IsHijacked(); void * GetHijackedReturnAddress(); diff --git a/external/corert/src/Native/Runtime/threadstore.cpp b/external/corert/src/Native/Runtime/threadstore.cpp index d359c681d6..f3a019ae34 100644 --- a/external/corert/src/Native/Runtime/threadstore.cpp +++ b/external/corert/src/Native/Runtime/threadstore.cpp @@ -410,11 +410,7 @@ EXTERN_C DECLSPEC_THREAD ThreadBuffer tls_CurrentThread = INVALID_HANDLE_VALUE, // m_hPalThread 0, // m_ppvHijackedReturnAddressLocation 0, // m_pvHijackedReturnAddress - 0, // m_pExInfoStackHead - 0, // m_pStackLow - 0, // m_pStackHigh - 0, // m_pTEB - 0, // m_uPalThreadIdForLogging + 0, // all other fields are initialized by zeroes }; #endif // !DACCESS_COMPILE diff --git a/external/corert/src/Native/Runtime/unix/PalRedhawkUnix.cpp b/external/corert/src/Native/Runtime/unix/PalRedhawkUnix.cpp index 6d151657e1..0807d80041 100644 --- a/external/corert/src/Native/Runtime/unix/PalRedhawkUnix.cpp +++ b/external/corert/src/Native/Runtime/unix/PalRedhawkUnix.cpp @@ -308,7 +308,7 @@ public: TimeSpecAdd(&endTime, milliseconds); } #else -#error Don't know how to perfom timed wait on this platform +#error Don't know how to perform timed wait on this platform #endif int st = 0; @@ -1044,8 +1044,13 @@ extern "C" void LeaveCriticalSection(CRITICAL_SECTION * lpCriticalSection) extern "C" UInt32_BOOL IsDebuggerPresent() { +#ifdef _WASM_ + // For now always true since the browser will handle it in case of WASM. + return UInt32_TRUE; +#else // UNIXTODO: Implement this function return UInt32_FALSE; +#endif } extern "C" void TerminateProcess(HANDLE arg1, UInt32 arg2) diff --git a/external/corert/src/Native/Runtime/unix/UnixContext.cpp b/external/corert/src/Native/Runtime/unix/UnixContext.cpp index cf88a59943..18fff0ccbd 100644 --- a/external/corert/src/Native/Runtime/unix/UnixContext.cpp +++ b/external/corert/src/Native/Runtime/unix/UnixContext.cpp @@ -591,7 +591,12 @@ bool FindProcInfo(UIntNative controlPC, UIntNative* startAddress, UIntNative* ls assert((procInfo.start_ip <= controlPC) && (controlPC < procInfo.end_ip)); +#if defined(_ARM_) + // libunwind fills by reference not by value for ARM + *lsda = *((UIntNative *)procInfo.lsda); +#else *lsda = procInfo.lsda; +#endif *startAddress = procInfo.start_ip; return true; diff --git a/external/corert/src/Native/Runtime/unix/UnwindHelpers.cpp b/external/corert/src/Native/Runtime/unix/UnwindHelpers.cpp index ed5100bd86..c77de82009 100644 --- a/external/corert/src/Native/Runtime/unix/UnwindHelpers.cpp +++ b/external/corert/src/Native/Runtime/unix/UnwindHelpers.cpp @@ -4,6 +4,7 @@ #include "common.h" #include "daccess.h" +#include "rhassert.h" #define UNW_STEP_SUCCESS 1 #define UNW_STEP_END 0 @@ -20,12 +21,23 @@ #include #include #include +#if defined(_TARGET_ARM_) +#include +#endif #include +#if defined(_TARGET_AMD64_) using libunwind::Registers_x86_64; +#elif defined(_TARGET_ARM_) +using libunwind::Registers_arm; +#else +#error "Unwinding is not implemented for this architecture yet." +#endif using libunwind::LocalAddressSpace; using libunwind::EHHeaderParser; +#if _LIBUNWIND_SUPPORT_DWARF_UNWIND using libunwind::DwarfInstructions; +#endif using libunwind::UnwindInfoSections; LocalAddressSpace _addressSpace; @@ -43,6 +55,7 @@ struct dyld_unwind_sections #else // __APPLE__ +#if defined(_TARGET_AMD64_) // Passed to the callback function called by dl_iterate_phdr struct dl_iterate_cb_data { @@ -108,6 +121,7 @@ static int LocateSectionsCallback(struct dl_phdr_info *info, size_t size, void * return 0; } +#endif #endif // __APPLE__ @@ -289,6 +303,7 @@ bool DoTheStep(uintptr_t pc, UnwindInfoSections uwInfoSections, REGDISPLAY *regs #error "Unwinding is not implemented for this architecture yet." #endif +#if _LIBUNWIND_SUPPORT_DWARF_UNWIND bool retVal = uc.getInfoFromDwarfSection(pc, uwInfoSections, 0 /* fdeSectionOffsetHint */); if (!retVal) { @@ -307,6 +322,9 @@ bool DoTheStep(uintptr_t pc, UnwindInfoSections uwInfoSections, REGDISPLAY *regs } regs->pIP = PTR_PCODE(regs->SP - sizeof(TADDR)); +#else + PORTABILITY_ASSERT("DoTheStep"); +#endif return true; } @@ -333,8 +351,12 @@ UnwindInfoSections LocateUnwindSections(uintptr_t pc) } #else // __APPLE__ +#if _LIBUNWIND_SUPPORT_DWARF_UNWIND dl_iterate_cb_data cb_data = {&uwInfoSections, pc }; dl_iterate_phdr(LocateSectionsCallback, &cb_data); +#else + PORTABILITY_ASSERT("LocateUnwindSections"); +#endif #endif @@ -346,10 +368,15 @@ bool UnwindHelpers::StepFrame(REGDISPLAY *regs) uintptr_t pc = regs->GetIP(); UnwindInfoSections uwInfoSections = LocateUnwindSections(pc); + +#if _LIBUNWIND_SUPPORT_DWARF_UNWIND if (uwInfoSections.dwarf_section == NULL) { return false; } +#else + PORTABILITY_ASSERT("StepFrame"); +#endif return DoTheStep(pc, uwInfoSections, regs); } diff --git a/external/corert/src/Native/Runtime/windows/CoffNativeCodeManager.cpp b/external/corert/src/Native/Runtime/windows/CoffNativeCodeManager.cpp index e024129042..22a37bb928 100644 --- a/external/corert/src/Native/Runtime/windows/CoffNativeCodeManager.cpp +++ b/external/corert/src/Native/Runtime/windows/CoffNativeCodeManager.cpp @@ -528,7 +528,7 @@ bool CoffNativeCodeManager::GetReturnAddressHijackInfo(MethodInfo * pMethodIn if ((unwindBlockFlags & UBF_FUNC_HAS_EHINFO) != 0) p += sizeof(int32_t); - // Decode the GC info for the current method to detemine its return type + // Decode the GC info for the current method to determine its return type GcInfoDecoder decoder( GCInfoToken(p), GcInfoDecoderFlags(DECODE_RETURN_KIND), diff --git a/external/corert/src/Native/Runtime/windows/PalRedhawkMinWin.cpp b/external/corert/src/Native/Runtime/windows/PalRedhawkMinWin.cpp index 366afce8fe..95095e1db8 100644 --- a/external/corert/src/Native/Runtime/windows/PalRedhawkMinWin.cpp +++ b/external/corert/src/Native/Runtime/windows/PalRedhawkMinWin.cpp @@ -1056,8 +1056,7 @@ UInt32 CountBits(size_t bfBitfield) // 'answers' between the current implementation and the CLR implementation. // //#define TRACE_CACHE_TOPOLOGY -#if defined(_DEBUG) && !defined(_ARM64_) -// ARM64TODO: restore +#ifdef _DEBUG void DumpCacheTopology(_In_reads_(cRecords) SYSTEM_LOGICAL_PROCESSOR_INFORMATION * pProcInfos, UInt32 cRecords) { printf("----------------\n"); @@ -1101,6 +1100,7 @@ void DumpCacheTopology(_In_reads_(cRecords) SYSTEM_LOGICAL_PROCESSOR_INFORMATION } printf("----------------\n"); } + void DumpCacheTopologyResults(UInt32 maxCpuId, CpuVendor cpuVendor, _In_reads_(cRecords) SYSTEM_LOGICAL_PROCESSOR_INFORMATION * pProcInfos, UInt32 cRecords) { DumpCacheTopology(pProcInfos, cRecords); @@ -1109,7 +1109,7 @@ void DumpCacheTopologyResults(UInt32 maxCpuId, CpuVendor cpuVendor, _In_reads_(c printf(" g_cbLargestOnDieCache: 0x%08zx 0x%08zx :CLR_LargestOnDieCache(TRUE)\n", g_cbLargestOnDieCache, CLR_GetLargestOnDieCacheSize(TRUE, pProcInfos, cRecords)); printf("g_cbLargestOnDieCacheAdjusted: 0x%08zx 0x%08zx :CLR_LargestOnDieCache(FALSE)\n", g_cbLargestOnDieCacheAdjusted, CLR_GetLargestOnDieCacheSize(FALSE, pProcInfos, cRecords)); } -#endif // defined(_DEBUG) && !defined(_ARM64_) +#endif // _DEBUG // Method used to initialize the above values. bool PalQueryProcessorTopology() @@ -1282,21 +1282,18 @@ bool PalQueryProcessorTopology() g_cbLargestOnDieCache = cbCache; g_cbLargestOnDieCacheAdjusted = cbCacheAdjusted; -#if defined(_DEBUG) -#if defined(TRACE_CACHE_TOPOLOGY) && !defined(_ARM64_) -// ARM64TODO: restore +#ifdef _DEBUG +#ifdef TRACE_CACHE_TOPOLOGY DumpCacheTopologyResults(maxCpuId, cpuVendor, pProcInfos, cRecords); -#endif // defined(TRACE_CACHE_TOPOLOGY) && !defined(_ARM64_) +#endif if ((CLR_GetLargestOnDieCacheSize(TRUE, pProcInfos, cRecords) != g_cbLargestOnDieCache) || (CLR_GetLargestOnDieCacheSize(FALSE, pProcInfos, cRecords) != g_cbLargestOnDieCacheAdjusted) || (CLR_GetLogicalCpuCount(pProcInfos, cRecords) != g_cLogicalCpus)) { -#if !defined(_ARM64_) DumpCacheTopologyResults(maxCpuId, cpuVendor, pProcInfos, cRecords); -#endif assert(!"QueryProcessorTopology doesn't match CLR's results. See stdout for more info."); } -#endif +#endif // _DEBUG } if (pProcInfos) diff --git a/external/corert/src/Native/System.Private.CoreLib.Native/pal_threading.cpp b/external/corert/src/Native/System.Private.CoreLib.Native/pal_threading.cpp index 3f9f372766..e3c2dd7979 100644 --- a/external/corert/src/Native/System.Private.CoreLib.Native/pal_threading.cpp +++ b/external/corert/src/Native/System.Private.CoreLib.Native/pal_threading.cpp @@ -28,7 +28,7 @@ extern "C" void CoreLibNative_LowLevelMutex_Release(LowLevelMutex *mutex) // LowLevelMonitor #if !(HAVE_MACH_ABSOLUTE_TIME || HAVE_PTHREAD_CONDATTR_SETCLOCK && HAVE_CLOCK_MONOTONIC) -#error Don't know how to perfom timed wait on this platform +#error Don't know how to perform timed wait on this platform #endif LowLevelMonitor::LowLevelMonitor(bool abortOnFailure, bool *successRef) : LowLevelMutex(abortOnFailure, successRef) diff --git a/external/corert/src/Native/gc/gc.cpp.REMOVED.git-id b/external/corert/src/Native/gc/gc.cpp.REMOVED.git-id index 8c88549a14..bca1a86f64 100644 --- a/external/corert/src/Native/gc/gc.cpp.REMOVED.git-id +++ b/external/corert/src/Native/gc/gc.cpp.REMOVED.git-id @@ -1 +1 @@ -649f2cdd8e76243cb9f2b5ef198b008d75beaf78 \ No newline at end of file +5c673c0be456a05ff7800344fbd9e8a2b0dae42e \ No newline at end of file diff --git a/external/corert/src/Native/gc/handletable.cpp b/external/corert/src/Native/gc/handletable.cpp index 3be1c1611d..2b598528c5 100644 --- a/external/corert/src/Native/gc/handletable.cpp +++ b/external/corert/src/Native/gc/handletable.cpp @@ -1056,7 +1056,7 @@ void HndScanHandlesForGC(HHANDLETABLE hTable, HANDLESCANPROC scanProc, uintptr_t /* * HndResetAgeMap * - * Service to forceably reset the age map for a set of handles. + * Service to forcibly reset the age map for a set of handles. * * Provided for GC-time resetting the handle table's write barrier. This is not * normally advisable, as it increases the amount of work that will be done in diff --git a/external/corert/src/Native/gc/handletablecore.cpp b/external/corert/src/Native/gc/handletablecore.cpp index 5776c26ace..4137c16454 100644 --- a/external/corert/src/Native/gc/handletablecore.cpp +++ b/external/corert/src/Native/gc/handletablecore.cpp @@ -129,7 +129,7 @@ void QuickSort(uintptr_t *pData, int left, int right, PFNCOMPARE pfnCompare) * * Returns: * <0 - handle P should be freed before handle Q - * =0 - handles are eqivalent for free order purposes + * =0 - handles are equivalent for free order purposes * >0 - handle Q should be freed before handle P * */ @@ -242,7 +242,7 @@ BOOL TableCanFreeSegmentNow(HandleTable *pTable, TableSegment *pSegment) _ASSERTE(threadId.IsCurrentThread()); #endif // _DEBUG - // deterine if any segment is currently being scanned asynchronously + // determine if any segment is currently being scanned asynchronously TableSegment *pSegmentAsync = NULL; // do we have async info? @@ -1852,7 +1852,7 @@ void SegmentTrimExcessPages(TableSegment *pSegment) // compute the address for the new decommit line size_t dwDecommitAddr = dwLo - g_SystemInfo.dwPageSize; - // assume a decommit line of zero until we know otheriwse + // assume a decommit line of zero until we know otherwise uDecommitLine = 0; // if the address is within the handle area then compute the line from the address @@ -1869,7 +1869,7 @@ void SegmentTrimExcessPages(TableSegment *pSegment) /* * BlockAllocHandlesInMask * - * Attempts to allocate the requested number of handes of the specified type, + * Attempts to allocate the requested number of handles of the specified type, * from the specified mask of the specified handle block. * * Returns the number of available handles actually allocated. @@ -2029,7 +2029,7 @@ uint32_t BlockAllocHandlesInitial(TableSegment *pSegment, uint32_t uType, uint32 /* * BlockAllocHandles * - * Attempts to allocate the requested number of handes of the specified type, + * Attempts to allocate the requested number of handles of the specified type, * from the specified handle block. * * Returns the number of available handles actually allocated. @@ -2087,7 +2087,7 @@ uint32_t BlockAllocHandles(TableSegment *pSegment, uint32_t uBlock, OBJECTHANDLE /* * SegmentAllocHandlesFromTypeChain * - * Attempts to allocate the requested number of handes of the specified type, + * Attempts to allocate the requested number of handles of the specified type, * from the specified segment's block chain for the specified type. This routine * ONLY scavenges existing blocks in the type chain. No new blocks are committed. * @@ -2171,7 +2171,7 @@ uint32_t SegmentAllocHandlesFromTypeChain(TableSegment *pSegment, uint32_t uType /* * SegmentAllocHandlesFromFreeList * - * Attempts to allocate the requested number of handes of the specified type, + * Attempts to allocate the requested number of handles of the specified type, * by committing blocks from the free list to that type's type chain. * * Returns the number of available handles actually allocated. @@ -2230,7 +2230,7 @@ uint32_t SegmentAllocHandlesFromFreeList(TableSegment *pSegment, uint32_t uType, /* * SegmentAllocHandles * - * Attempts to allocate the requested number of handes of the specified type, + * Attempts to allocate the requested number of handles of the specified type, * from the specified segment. * * Returns the number of available handles actually allocated. @@ -2268,7 +2268,7 @@ uint32_t SegmentAllocHandles(TableSegment *pSegment, uint32_t uType, OBJECTHANDL /* * TableAllocBulkHandles * - * Attempts to allocate the requested number of handes of the specified type. + * Attempts to allocate the requested number of handles of the specified type. * * Returns the number of handles that were actually allocated. This is always * the same as the number of handles requested except in out-of-memory conditions, diff --git a/external/corert/src/Native/gc/handletablescan.cpp b/external/corert/src/Native/gc/handletablescan.cpp index 86ce62d5b1..504630b9a4 100644 --- a/external/corert/src/Native/gc/handletablescan.cpp +++ b/external/corert/src/Native/gc/handletablescan.cpp @@ -46,7 +46,7 @@ MaskDWORD is also non-zero. 2. AgeEphemeral. When Ephemeral GC happens, ages for handles which belong to the GC condemned generation should be incremented by 1. The operation is done by calculating a new uint32_t using the old uint32_t value: NewGenerationDWORD = COMPUTE_AGED_CLUMPS(OldGenerationDWORD, BuildAgeMask(condemnedGeneration, MaxGen)) -so that if a byte in OldGenerationDWORD is smaller than or equals to condemnedGeneration. the coresponding byte in +so that if a byte in OldGenerationDWORD is smaller than or equals to condemnedGeneration. the corresponding byte in NewGenerationDWORD is 1 bigger than the old value, otherwise it remains unchanged. 3. Age. Similar as AgeEphemeral, but we use a special mask if condemned generation is max gen (2): @@ -118,7 +118,7 @@ If you change any of those algorithm, please verify it by this program: assert (mask == 0); return; } - //any generaion bigger than 2 is actually 2 + //any generation bigger than 2 is actually 2 if (gen > 2) gen = 2; @@ -716,10 +716,10 @@ void CALLBACK BlockScanBlocksEphemeral(PTR_TableSegment pSegment, uint32_t uBloc uint32_t *pdwGen = (uint32_t *)pSegment->rgGeneration + uBlock; uint32_t *pdwGenLast = pdwGen + uCount; - // loop over all the blocks, checking for elligible clumps as we go + // loop over all the blocks, checking for eligible clumps as we go do { - // determine if any clumps in this block are elligible + // determine if any clumps in this block are eligible uint32_t dwClumpMask = COMPUTE_CLUMP_MASK(*pdwGen, dwAgeMask); // if there are any clumps to scan then scan them now @@ -1434,7 +1434,7 @@ PTR_TableSegment CALLBACK StandardSegmentIterator(PTR_HandleTable pTable, PTR_Ta PTR_TableSegment pNextSegment = QuickSegmentIterator(pTable, pPrevSegment); #ifndef DACCESS_COMPILE - // re-sort the block chains if neccessary + // re-sort the block chains if necessary if (pNextSegment && pNextSegment->fResortChains) SegmentResortChains(pNextSegment); #endif @@ -1630,7 +1630,7 @@ void SegmentScanByTypeChain(PTR_TableSegment pSegment, uint32_t uType, BLOCKSCAN } while ((uNext == uLast) && (uNext != uHead)); - // call the calback for this group of blocks + // call the callback for this group of blocks pfnBlockHandler(pSegment, uBlock, (uLast - uBlock), pInfo); // advance to the next block @@ -1694,7 +1694,7 @@ void SegmentScanByTypeMap(PTR_TableSegment pSegment, const BOOL *rgTypeInclusion break; } - // call the calback for the group of blocks we found + // call the callback for the group of blocks we found pfnBlockHandler(pSegment, uFirst, (uBlock - uFirst), pInfo); // look for another range starting with the next block diff --git a/external/corert/src/Native/gc/objecthandle.cpp b/external/corert/src/Native/gc/objecthandle.cpp index e8eed93006..28dcc52222 100644 --- a/external/corert/src/Native/gc/objecthandle.cpp +++ b/external/corert/src/Native/gc/objecthandle.cpp @@ -84,7 +84,7 @@ void CALLBACK PromoteRefCounted(_UNCHECKED_OBJECTREF *pObjRef, uintptr_t *pExtra WRAPPER_NO_CONTRACT; UNREFERENCED_PARAMETER(pExtraInfo); - // there are too many races when asychnronously scanning ref-counted handles so we no longer support it + // there are too many races when asynchronously scanning ref-counted handles so we no longer support it _ASSERTE(!((ScanContext*)lp1)->concurrent); LOG((LF_GC, LL_INFO1000, LOG_HANDLE_OBJECT_CLASS("", pObjRef, "causes promotion of ", *pObjRef))); @@ -1247,7 +1247,7 @@ void Ref_CheckReachable(uint32_t condemned, uint32_t maxgen, uintptr_t lp1) // strong handle to refer to the secondary as this could case a cycle in the graph if the secondary somehow // pointed back to the primary. Can't use weak handle because that would not keep the secondary object alive. // -// The result is that a dependenHandle has the EFFECT of +// The result is that a dependentHandle has the EFFECT of // * long weak handles in both the primary and secondary objects // * a strong reference from the primary object to the secondary one // diff --git a/external/corert/src/Native/gc/unix/gcenv.unix.cpp b/external/corert/src/Native/gc/unix/gcenv.unix.cpp index 0b4ab0ed1e..07259c0f24 100644 --- a/external/corert/src/Native/gc/unix/gcenv.unix.cpp +++ b/external/corert/src/Native/gc/unix/gcenv.unix.cpp @@ -11,7 +11,7 @@ // This isn't something we want, because we're totally fine using non-posix functions. #if defined(__APPLE__) #define _DARWIN_C_SOURCE -#endif // definfed(__APPLE__) +#endif // defined(__APPLE__) #include #include @@ -69,7 +69,7 @@ static const int tccMilliSecondsToMicroSeconds = 1000; // The number of nanoseconds in a millisecond. static const int tccMilliSecondsToNanoSeconds = 1000000; -// The cachced number of logical CPUs observed. +// The cached number of logical CPUs observed. static uint32_t g_logicalCpuCount = 0; // Helper memory page used by the FlushProcessWriteBuffers diff --git a/external/corert/src/Native/gen-buildsys-clang.sh b/external/corert/src/Native/gen-buildsys-clang.sh index 0c2441f774..fed57d1226 100755 --- a/external/corert/src/Native/gen-buildsys-clang.sh +++ b/external/corert/src/Native/gen-buildsys-clang.sh @@ -117,6 +117,7 @@ if [ $build_arch == "wasm" ]; then emcmake cmake \ "-DEMSCRIPTEN_GENERATE_BITCODE_STATIC_LIBRARIES=1" \ "-DCMAKE_TOOLCHAIN_FILE=$EMSCRIPTEN/cmake/Modules/Platform/Emscripten.cmake" \ + "-DCLR_CMAKE_TARGET_ARCH=$build_arch" \ "-DCMAKE_BUILD_TYPE=$build_type" \ "$1/src/Native" else diff --git a/external/corert/src/Native/jitinterface/jitwrapper.cpp b/external/corert/src/Native/jitinterface/jitwrapper.cpp index 3b15321244..ac5264b7db 100644 --- a/external/corert/src/Native/jitinterface/jitwrapper.cpp +++ b/external/corert/src/Native/jitinterface/jitwrapper.cpp @@ -27,11 +27,11 @@ private: unsigned __int64 corJitFlags; }; -static const GUID JITEEVersionIdentifier = { /* a6860f80-01cb-4f87-82c2-a8e5a744f2fa */ - 0xa6860f80, - 0x01cb, - 0x4f87, - {0x82, 0xc2, 0xa8, 0xe5, 0xa7, 0x44, 0xf2, 0xfa} +static const GUID JITEEVersionIdentifier = { /* 0ba106c8-81a0-407f-99a1-928448c1eb62 */ + 0x0ba106c8, + 0x81a0, + 0x407f, + {0x99, 0xa1, 0x92, 0x84, 0x48, 0xc1, 0xeb, 0x62} }; class Jit diff --git a/external/corert/src/Native/libunwind/src/Unwind-EHABI.cpp b/external/corert/src/Native/libunwind/src/Unwind-EHABI.cpp index 863953eb2c..18b82f8c81 100644 --- a/external/corert/src/Native/libunwind/src/Unwind-EHABI.cpp +++ b/external/corert/src/Native/libunwind/src/Unwind-EHABI.cpp @@ -695,7 +695,7 @@ _LIBUNWIND_EXPORT void _Unwind_Complete(_Unwind_Exception* exception_object) { /// may force a jump to a landing pad in that function, the landing /// pad code may then call _Unwind_Resume() to continue with the /// unwinding. Note: the call to _Unwind_Resume() is from compiler -/// geneated user code. All other _Unwind_* routines are called +/// generated user code. All other _Unwind_* routines are called /// by the C++ runtime __cxa_* routines. /// /// Note: re-throwing an exception (as opposed to continuing the unwind) diff --git a/external/corert/src/Native/libunwind/src/Unwind_AppleExtras.cpp b/external/corert/src/Native/libunwind/src/Unwind_AppleExtras.cpp index d8301c057f..dcde35eec0 100644 --- a/external/corert/src/Native/libunwind/src/Unwind_AppleExtras.cpp +++ b/external/corert/src/Native/libunwind/src/Unwind_AppleExtras.cpp @@ -191,7 +191,7 @@ bool checkKeyMgrRegisteredFDEs(uintptr_t pc, void *&fde) { _Unwind_FunctionContext *fc_ = nullptr; #endif -// Accessors to get get/set linked list of frames for sjlj based execeptions. +// Accessors to get get/set linked list of frames for sjlj based exceptions. _LIBUNWIND_HIDDEN struct _Unwind_FunctionContext *__Unwind_SjLj_GetTopOfFunctionStack() { #ifndef _LIBUNWIND_HAS_NO_THREADS diff --git a/external/corert/src/Native/probe-win.ps1 b/external/corert/src/Native/probe-win.ps1 index 70030b14d3..55f3d329fd 100644 --- a/external/corert/src/Native/probe-win.ps1 +++ b/external/corert/src/Native/probe-win.ps1 @@ -6,7 +6,7 @@ function GetCMakeVersions $items = @() $items += @(Get-ChildItem hklm:\SOFTWARE\Wow6432Node\Kitware -ErrorAction SilentlyContinue) $items += @(Get-ChildItem hklm:\SOFTWARE\Kitware -ErrorAction SilentlyContinue) - return $items | where { $_.PSChildName.StartsWith("CMake ") } + return $items | where { $_.PSChildName.StartsWith("CMake") } } function GetCMakeInfo($regKey) @@ -17,7 +17,13 @@ function GetCMakeInfo($regKey) catch { return $null } - $cmakeDir = (Get-ItemProperty $regKey.PSPath).'(default)' + $itemProperty = Get-ItemProperty $regKey.PSPath; + if (Get-Member -inputobject $itemProperty -name "InstallDir" -Membertype Properties) { + $cmakeDir = $itemProperty.InstallDir + } + else { + $cmakeDir = $itemProperty.'(default)' + } $cmakePath = [System.IO.Path]::Combine($cmakeDir, "bin\cmake.exe") if (![System.IO.File]::Exists($cmakePath)) { return $null @@ -28,9 +34,13 @@ function GetCMakeInfo($regKey) function LocateCMake { $errorMsg = "CMake is a pre-requisite to build this repository but it was not found on the path. Please install CMake from http://www.cmake.org/download/ and ensure it is on your path." - $inPathPath = (get-command cmake.exe -ErrorAction SilentlyContinue).Path + $inPathPath = (get-command cmake.exe -ErrorAction SilentlyContinue) if ($inPathPath -ne $null) { - return $inPathPath + # Resolve the first version of CMake if multiple commands are found + if ($inPathPath.Length -gt 1) { + return $inPathPath[0].Path + } + return $inPathPath.Path } # Let us hope that CMake keep using their current version scheme $validVersions = @() diff --git a/external/corert/src/Runtime.Base/src/Runtime.Base.csproj b/external/corert/src/Runtime.Base/src/Runtime.Base.csproj index ffae8483fb..daa602215a 100644 --- a/external/corert/src/Runtime.Base/src/Runtime.Base.csproj +++ b/external/corert/src/Runtime.Base/src/Runtime.Base.csproj @@ -112,7 +112,7 @@ - + diff --git a/external/corert/src/Runtime.Base/src/System/Diagnostics/Eval.cs b/external/corert/src/Runtime.Base/src/System/Diagnostics/Eval.cs index eaa76dfe41..ecb5358761 100644 --- a/external/corert/src/Runtime.Base/src/System/Diagnostics/Eval.cs +++ b/external/corert/src/Runtime.Base/src/System/Diagnostics/Eval.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Diagnostics; using System.Runtime; using System.Runtime.CompilerServices; @@ -10,20 +11,13 @@ namespace System.Diagnostics { public static class Eval { - private static IntPtr s_highLevelDebugFuncEvalHelper; - - [MethodImpl(MethodImplOptions.NoInlining)] - [RuntimeExport("RhpSetHighLevelDebugFuncEvalHelper")] - public static void SetHighLevelDebugFuncEvalHelper(IntPtr ptr) - { - s_highLevelDebugFuncEvalHelper = ptr; - } - [MethodImpl(MethodImplOptions.NoInlining)] [RuntimeExport("RhpDebugFuncEvalHelper")] - public static void RhpDebugFuncEvalHelper() + public unsafe static void RhpDebugFuncEvalHelper(IntPtr unusedTransitionBlock, IntPtr classlibAddress) { - CalliIntrinsics.CallVoid(s_highLevelDebugFuncEvalHelper); + IntPtr pDebugFuncEvalHelper = (IntPtr)InternalCalls.RhpGetClasslibFunctionFromCodeAddress(classlibAddress, ClassLibFunctionId.DebugFuncEvalHelper); + Debug.Assert(pDebugFuncEvalHelper != IntPtr.Zero); + CalliIntrinsics.CallVoid(pDebugFuncEvalHelper); } } } \ No newline at end of file diff --git a/external/corert/src/Runtime.Base/src/System/Runtime/CalliIntrinsics.cs b/external/corert/src/Runtime.Base/src/System/Runtime/CalliIntrinsics.cs index d23b9636ac..af520c824b 100644 --- a/external/corert/src/Runtime.Base/src/System/Runtime/CalliIntrinsics.cs +++ b/external/corert/src/Runtime.Base/src/System/Runtime/CalliIntrinsics.cs @@ -11,12 +11,14 @@ namespace System.Runtime internal static unsafe partial class CalliIntrinsics { internal static void CallVoid(IntPtr pfn) { Call(pfn); } + internal static void CallVoid(IntPtr pfn, long arg0) { Call(pfn, arg0); } internal static void CallVoid(IntPtr pfn, object arg0) { Call(pfn, arg0); } internal static void CallVoid(IntPtr pfn, IntPtr arg0, object arg1) { Call(pfn, arg0, arg1); } internal static void CallVoid(IntPtr pfn, RhFailFastReason arg0, object arg1, IntPtr arg2, IntPtr arg3) { Call(pfn, arg0, arg1, arg2, arg3); } internal static void CallVoid(IntPtr pfn, object arg0, IntPtr arg1, int arg2) { Call(pfn, arg0, arg1, arg2); } internal static T Call(IntPtr pfn) { throw new NotImplementedException(); } + internal static T Call(IntPtr pfn, long arg0) { throw new NotImplementedException(); } internal static T Call(IntPtr pfn, object arg0) { throw new NotImplementedException(); } internal static T Call(IntPtr pfn, IntPtr arg0) { throw new NotImplementedException(); } internal static T Call(IntPtr pfn, IntPtr arg0, object arg1) { throw new NotImplementedException(); } diff --git a/external/corert/src/Runtime.Base/src/System/Runtime/EEType.Runtime.cs b/external/corert/src/Runtime.Base/src/System/Runtime/EEType.Runtime.cs index 3a1e8a9544..f3b4ff4d49 100644 --- a/external/corert/src/Runtime.Base/src/System/Runtime/EEType.Runtime.cs +++ b/external/corert/src/Runtime.Base/src/System/Runtime/EEType.Runtime.cs @@ -25,7 +25,7 @@ namespace Internal.Runtime { fixed (EEType* pThis = &this) { - IntPtr pGetArrayEEType = (IntPtr)InternalCalls.RhpGetClasslibFunctionFromEEType(new IntPtr(pThis), EH.ClassLibFunctionId.GetSystemArrayEEType); + IntPtr pGetArrayEEType = (IntPtr)InternalCalls.RhpGetClasslibFunctionFromEEType(new IntPtr(pThis), ClassLibFunctionId.GetSystemArrayEEType); if (pGetArrayEEType != IntPtr.Zero) return (EEType*)CalliIntrinsics.Call(pGetArrayEEType); } diff --git a/external/corert/src/Runtime.Base/src/System/Runtime/ExceptionHandling.cs b/external/corert/src/Runtime.Base/src/System/Runtime/ExceptionHandling.cs index 761ad5319b..4d3cdf674f 100644 --- a/external/corert/src/Runtime.Base/src/System/Runtime/ExceptionHandling.cs +++ b/external/corert/src/Runtime.Base/src/System/Runtime/ExceptionHandling.cs @@ -9,6 +9,9 @@ using System.Runtime.InteropServices; using Internal.Runtime; +// Disable: Filter expression is a constant. We know. We just can't do an unfiltered catch. +#pragma warning disable 7095 + namespace System.Runtime { public enum RhFailFastReason @@ -144,20 +147,6 @@ namespace System.Runtime InternalCalls.RhpFallbackFailFast(); } - // Constants used with RhpGetClasslibFunction, to indicate which classlib function - // we are interested in. - // Note: make sure you change the def in EHHelpers.cpp if you change this! - internal enum ClassLibFunctionId - { - GetRuntimeException = 0, - FailFast = 1, - // UnhandledExceptionHandler = 2, // unused - AppendExceptionStackFrame = 3, - CheckStaticClassConstruction = 4, - GetSystemArrayEEType = 5, - OnFirstChance = 6, - } - // Given an address pointing somewhere into a managed module, get the classlib-defined fail-fast // function and invoke it. Any failure to find and invoke the function, or if it returns, results in // MRT-defined fail-fast behavior. @@ -180,7 +169,7 @@ namespace System.Runtime // Invoke the classlib fail fast function. CalliIntrinsics.CallVoid(pFailFastFunction, reason, unhandledException, IntPtr.Zero, IntPtr.Zero); } - catch + catch when (true) { // disallow all exceptions leaking out of callbacks } @@ -228,7 +217,7 @@ namespace System.Runtime { CalliIntrinsics.CallVoid(pOnFirstChanceFunction, exception); } - catch + catch when (true) { // disallow all exceptions leaking out of callbacks } @@ -260,7 +249,7 @@ namespace System.Runtime { CalliIntrinsics.CallVoid(pFailFastFunction, reason, unhandledException, exInfo._pExContext->IP, (IntPtr)pContext); } - catch + catch when (true) { // disallow all exceptions leaking out of callbacks } @@ -290,7 +279,7 @@ namespace System.Runtime { CalliIntrinsics.CallVoid(pAppendStackFrame, exception, IP, flags); } - catch + catch when (true) { // disallow all exceptions leaking out of callbacks } @@ -317,7 +306,7 @@ namespace System.Runtime { e = CalliIntrinsics.Call(pGetRuntimeExceptionFunction, id); } - catch + catch when (true) { // disallow all exceptions leaking out of callbacks } @@ -353,7 +342,7 @@ namespace System.Runtime { e = CalliIntrinsics.Call(pGetRuntimeExceptionFunction, id); } - catch + catch when (true) { // disallow all exceptions leaking out of callbacks } @@ -875,28 +864,38 @@ namespace System.Runtime return false; } +#if DEBUG && !INPLACE_RUNTIME private static EEType* s_pLowLevelObjectType; - - private static bool ShouldTypedClauseCatchThisException(object exception, EEType* pClauseType) + private static void AssertNotRuntimeObject(EEType* pClauseType) { - if (TypeCast.IsInstanceOfClass(exception, pClauseType) != null) - return true; + // + // The C# try { } catch { } clause expands into a typed catch of System.Object. + // Since runtime has its own definition of System.Object, try { } catch { } might not do what + // was intended (catch all exceptions). + // + // This assertion is making sure we don't use try { } catch { } within the runtime. + // The runtime codebase should either use try { } catch (Exception) { } for exception types + // from the runtime or a try { } catch when (true) { } to catch all exceptions. + // if (s_pLowLevelObjectType == null) { - // TODO: Avoid allocating here as that may fail + // Allocating might fail, but since this is just a debug assert, it's probably fine. s_pLowLevelObjectType = new System.Object().EEType; } - // This allows the typical try { } catch { }--which expands to a typed catch of System.Object--to work on - // all objects when the clause is in the low level runtime code. This special case is needed because - // objects from foreign type systems are sometimes throw back up at runtime code and this is the only way - // to catch them outside of having a filter with no type check in it, which isn't currently possible to - // write in C#. See https://github.com/dotnet/roslyn/issues/4388 - if (pClauseType->IsEquivalentTo(s_pLowLevelObjectType)) - return true; + Debug.Assert(!pClauseType->IsEquivalentTo(s_pLowLevelObjectType)); + } +#endif // DEBUG && !INPLACE_RUNTIME - return false; + + private static bool ShouldTypedClauseCatchThisException(object exception, EEType* pClauseType) + { +#if DEBUG && !INPLACE_RUNTIME + AssertNotRuntimeObject(pClauseType); +#endif + + return TypeCast.IsInstanceOfClass(exception, pClauseType) != null; } private static void InvokeSecondPass(ref ExInfo exInfo, uint idxStart) diff --git a/external/corert/src/Runtime.Base/src/System/Runtime/InternalCalls.cs b/external/corert/src/Runtime.Base/src/System/Runtime/InternalCalls.cs index 0c4cc3ebf7..e647e3ab03 100644 --- a/external/corert/src/Runtime.Base/src/System/Runtime/InternalCalls.cs +++ b/external/corert/src/Runtime.Base/src/System/Runtime/InternalCalls.cs @@ -30,6 +30,22 @@ namespace System.Runtime public uint VTableOffset; } + // Constants used with RhpGetClasslibFunction, to indicate which classlib function + // we are interested in. + // Note: make sure you change the def in ICodeManager.h if you change this! + internal enum ClassLibFunctionId + { + GetRuntimeException = 0, + FailFast = 1, + // UnhandledExceptionHandler = 2, // unused + AppendExceptionStackFrame = 3, + CheckStaticClassConstruction = 4, + GetSystemArrayEEType = 5, + OnFirstChance = 6, + DebugFuncEvalHelper = 7, + DebugFuncEvalAbortHelper = 8, + } + internal static class InternalCalls { // @@ -232,12 +248,12 @@ namespace System.Runtime [RuntimeImport(Redhawk.BaseName, "RhpGetClasslibFunctionFromCodeAddress")] [MethodImpl(MethodImplOptions.InternalCall)] [ManuallyManaged(GcPollPolicy.Never)] - internal extern static unsafe void* RhpGetClasslibFunctionFromCodeAddress(IntPtr address, EH.ClassLibFunctionId id); + internal extern static unsafe void* RhpGetClasslibFunctionFromCodeAddress(IntPtr address, ClassLibFunctionId id); [RuntimeImport(Redhawk.BaseName, "RhpGetClasslibFunctionFromEEType")] [MethodImpl(MethodImplOptions.InternalCall)] [ManuallyManaged(GcPollPolicy.Never)] - internal extern static unsafe void* RhpGetClasslibFunctionFromEEType(IntPtr pEEType, EH.ClassLibFunctionId id); + internal extern static unsafe void* RhpGetClasslibFunctionFromEEType(IntPtr pEEType, ClassLibFunctionId id); // // StackFrameIterator diff --git a/external/corert/src/Runtime.Base/src/System/Runtime/ThunkPool.cs b/external/corert/src/Runtime.Base/src/System/Runtime/ThunkPool.cs index 404494451e..76df73e4dc 100644 --- a/external/corert/src/Runtime.Base/src/System/Runtime/ThunkPool.cs +++ b/external/corert/src/Runtime.Base/src/System/Runtime/ThunkPool.cs @@ -135,7 +135,7 @@ namespace System.Runtime if (newHeap._nextAvailableThunkPtr != IntPtr.Zero) return newHeap; } - catch { } + catch (Exception) { } return null; } @@ -156,7 +156,7 @@ namespace System.Runtime { newBlockInfo = new AllocatedBlock(); } - catch + catch (Exception) { return false; } diff --git a/external/corert/src/System.Private.CoreLib/shared/Internal/IO/File.Unix.cs b/external/corert/src/System.Private.CoreLib/shared/Internal/IO/File.Unix.cs new file mode 100644 index 0000000000..50fa0f0d0c --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/shared/Internal/IO/File.Unix.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Internal.IO +{ + internal static partial class File + { + internal static bool InternalExists(string fullPath) + { + Interop.Sys.FileStatus fileinfo; + + // First use stat, as we want to follow symlinks. If that fails, it could be because the symlink + // is broken, we don't have permissions, etc., in which case fall back to using LStat to evaluate + // based on the symlink itself. + if (Interop.Sys.Stat(fullPath, out fileinfo) < 0 && + Interop.Sys.LStat(fullPath, out fileinfo) < 0) + { + return false; + } + + return ((fileinfo.Mode & Interop.Sys.FileTypes.S_IFMT) != Interop.Sys.FileTypes.S_IFDIR); + } + } +} diff --git a/external/corert/src/System.Private.CoreLib/shared/Internal/IO/File.Windows.cs b/external/corert/src/System.Private.CoreLib/shared/Internal/IO/File.Windows.cs new file mode 100644 index 0000000000..0acae3b457 --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/shared/Internal/IO/File.Windows.cs @@ -0,0 +1,77 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Win32; +using Microsoft.Win32.SafeHandles; +using System.IO; +using System.Runtime.InteropServices; + +namespace Internal.IO +{ + internal static partial class File + { + internal static bool InternalExists(string fullPath) + { + Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA data = new Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA(); + int errorCode = FillAttributeInfo(fullPath, ref data, returnErrorOnNotFound: true); + + return (errorCode == 0) && (data.dwFileAttributes != -1) + && ((data.dwFileAttributes & Interop.Kernel32.FileAttributes.FILE_ATTRIBUTE_DIRECTORY) == 0); + } + + /// + /// Returns 0 on success, otherwise a Win32 error code. Note that + /// classes should use -1 as the uninitialized state for dataInitialized. + /// + /// Return the error code for not found errors? + internal static int FillAttributeInfo(string path, ref Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA data, bool returnErrorOnNotFound) + { + int errorCode = Interop.Errors.ERROR_SUCCESS; + + using (DisableMediaInsertionPrompt.Create()) + { + if (!Interop.Kernel32.GetFileAttributesEx(path, Interop.Kernel32.GET_FILEEX_INFO_LEVELS.GetFileExInfoStandard, ref data)) + { + errorCode = Marshal.GetLastWin32Error(); + if (errorCode == Interop.Errors.ERROR_ACCESS_DENIED) + { + // Files that are marked for deletion will not let you GetFileAttributes, + // ERROR_ACCESS_DENIED is given back without filling out the data struct. + // FindFirstFile, however, will. Historically we always gave back attributes + // for marked-for-deletion files. + + var findData = new Interop.Kernel32.WIN32_FIND_DATA(); + using (SafeFindHandle handle = Interop.Kernel32.FindFirstFile(path, ref findData)) + { + if (handle.IsInvalid) + { + errorCode = Marshal.GetLastWin32Error(); + } + else + { + errorCode = Interop.Errors.ERROR_SUCCESS; + data.PopulateFrom(ref findData); + } + } + } + } + } + + if (errorCode != Interop.Errors.ERROR_SUCCESS && !returnErrorOnNotFound) + { + switch (errorCode) + { + case Interop.Errors.ERROR_FILE_NOT_FOUND: + case Interop.Errors.ERROR_PATH_NOT_FOUND: + case Interop.Errors.ERROR_NOT_READY: // Removable media not ready + // Return default value for backward compatibility + data.dwFileAttributes = -1; + return Interop.Errors.ERROR_SUCCESS; + } + } + + return errorCode; + } + } +} diff --git a/external/corert/src/System.Private.CoreLib/src/System/IO/InternalFile.cs b/external/corert/src/System.Private.CoreLib/shared/Internal/IO/File.cs similarity index 56% rename from external/corert/src/System.Private.CoreLib/src/System/IO/InternalFile.cs rename to external/corert/src/System.Private.CoreLib/shared/Internal/IO/File.cs index 726e25419f..2fcc0f391f 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/IO/InternalFile.cs +++ b/external/corert/src/System.Private.CoreLib/shared/Internal/IO/File.cs @@ -2,18 +2,24 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Diagnostics; using System.Security; +using System.IO; -namespace System.IO +namespace Internal.IO { - internal static partial class InternalFile + // + // Subsetted clone of System.IO.File for internal runtime use. + // Keep in sync with https://github.com/dotnet/corefx/tree/master/src/System.IO.FileSystem. + // + internal static partial class File { // Tests if a file exists. The result is true if the file // given by the specified path exists; otherwise, the result is // false. Note that if path describes a directory, // Exists will return true. - public static bool Exists(String path) + public static bool Exists(string path) { try { @@ -43,5 +49,29 @@ namespace System.IO return false; } + + public static byte[] ReadAllBytes(string path) + { + // bufferSize == 1 used to avoid unnecessary buffer in FileStream + using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 1)) + { + long fileLength = fs.Length; + if (fileLength > int.MaxValue) + throw new IOException(SR.IO_FileTooLong2GB); + + int index = 0; + int count = (int)fileLength; + byte[] bytes = new byte[count]; + while (count > 0) + { + int n = fs.Read(bytes, index, count); + if (n == 0) + throw Error.GetEndOfFile(); + index += n; + count -= n; + } + return bytes; + } + } } } diff --git a/external/corert/src/System.Private.CoreLib/shared/Internal/Runtime/CompilerServices/Unsafe.cs b/external/corert/src/System.Private.CoreLib/shared/Internal/Runtime/CompilerServices/Unsafe.cs index cd3dd052a2..aeff3ce2ca 100644 --- a/external/corert/src/System.Private.CoreLib/shared/Internal/Runtime/CompilerServices/Unsafe.cs +++ b/external/corert/src/System.Private.CoreLib/shared/Internal/Runtime/CompilerServices/Unsafe.cs @@ -168,6 +168,46 @@ namespace Internal.Runtime.CompilerServices // ret } + /// + /// Determines whether the memory address referenced by is greater than + /// the memory address referenced by . + /// + /// + /// This check is conceptually similar to "(void*)(&left) > (void*)(&right)". + /// + [Intrinsic] + [NonVersionable] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsAddressGreaterThan(ref T left, ref T right) + { + throw new PlatformNotSupportedException(); + + // ldarg.0 + // ldarg.1 + // cgt.un + // ret + } + + /// + /// Determines whether the memory address referenced by is less than + /// the memory address referenced by . + /// + /// + /// This check is conceptually similar to "(void*)(&left) < (void*)(&right)". + /// + [Intrinsic] + [NonVersionable] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsAddressLessThan(ref T left, ref T right) + { + throw new PlatformNotSupportedException(); + + // ldarg.0 + // ldarg.1 + // clt.un + // ret + } + /// /// Initializes a block of memory at the given location with a given initial value /// without assuming architecture dependent alignment of the address. diff --git a/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/Interop.Libraries.cs b/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/Interop.Libraries.cs index 7b3dea453d..02d0092445 100644 --- a/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/Interop.Libraries.cs +++ b/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/Interop.Libraries.cs @@ -6,7 +6,7 @@ internal static partial class Interop { internal static partial class Libraries { - internal const string GlobalizationInterop = "System.Globalization.Native"; + internal const string GlobalizationNative = "System.Globalization.Native"; internal const string SystemNative = "System.Native"; } } diff --git a/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.Calendar.cs b/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.Calendar.cs index 7b3caeabdd..55553cc7ea 100644 --- a/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.Calendar.cs +++ b/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.Calendar.cs @@ -9,25 +9,25 @@ using System.Text; internal static partial class Interop { - internal static partial class GlobalizationInterop + internal static partial class Globalization { internal delegate void EnumCalendarInfoCallback( [MarshalAs(UnmanagedType.LPWStr)] string calendarString, IntPtr context); - [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetCalendars")] + [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetCalendars")] internal static extern int GetCalendars(string localeName, CalendarId[] calendars, int calendarsCapacity); - [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetCalendarInfo")] + [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetCalendarInfo")] internal static extern ResultCode GetCalendarInfo(string localeName, CalendarId calendarId, CalendarDataType calendarDataType, [Out] StringBuilder result, int resultCapacity); - [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_EnumCalendarInfo")] + [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_EnumCalendarInfo")] internal static extern bool EnumCalendarInfo(EnumCalendarInfoCallback callback, string localeName, CalendarId calendarId, CalendarDataType calendarDataType, IntPtr context); - [DllImport(Libraries.GlobalizationInterop, EntryPoint = "GlobalizationNative_GetLatestJapaneseEra")] + [DllImport(Libraries.GlobalizationNative, EntryPoint = "GlobalizationNative_GetLatestJapaneseEra")] internal static extern int GetLatestJapaneseEra(); - [DllImport(Libraries.GlobalizationInterop, EntryPoint = "GlobalizationNative_GetJapaneseEraStartDate")] + [DllImport(Libraries.GlobalizationNative, EntryPoint = "GlobalizationNative_GetJapaneseEraStartDate")] internal static extern bool GetJapaneseEraStartDate(int era, out int startYear, out int startMonth, out int startDay); } } diff --git a/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.Casing.cs b/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.Casing.cs index 769506b8f6..25536d483a 100644 --- a/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.Casing.cs +++ b/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.Casing.cs @@ -9,15 +9,15 @@ using System.Text; internal static partial class Interop { - internal static partial class GlobalizationInterop + internal static partial class Globalization { - [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_ChangeCase")] + [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_ChangeCase")] internal unsafe static extern void ChangeCase(char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper); - [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_ChangeCaseInvariant")] + [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_ChangeCaseInvariant")] internal unsafe static extern void ChangeCaseInvariant(char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper); - [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_ChangeCaseTurkish")] + [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_ChangeCaseTurkish")] internal unsafe static extern void ChangeCaseTurkish(char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper); } } diff --git a/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.Collation.cs b/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.Collation.cs index 683845dbc1..08aa6113d7 100644 --- a/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.Collation.cs +++ b/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.Collation.cs @@ -9,41 +9,53 @@ using System.Security; internal static partial class Interop { - internal static partial class GlobalizationInterop + internal static partial class Globalization { - [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetSortHandle")] + [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetSortHandle")] internal unsafe static extern ResultCode GetSortHandle(byte[] localeName, out SafeSortHandle sortHandle); - [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_CloseSortHandle")] + [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_CloseSortHandle")] internal unsafe static extern void CloseSortHandle(IntPtr handle); - [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_CompareString")] + [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_CompareString")] internal unsafe static extern int CompareString(SafeSortHandle sortHandle, char* lpStr1, int cwStr1Len, char* lpStr2, int cwStr2Len, CompareOptions options); - [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_IndexOf")] + [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_IndexOf")] internal unsafe static extern int IndexOf(SafeSortHandle sortHandle, string target, int cwTargetLength, char* pSource, int cwSourceLength, CompareOptions options, int* matchLengthPtr); + [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_IndexOf")] + internal unsafe static extern int IndexOf(SafeSortHandle sortHandle, char* target, int cwTargetLength, char* pSource, int cwSourceLength, CompareOptions options, int* matchLengthPtr); - [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_LastIndexOf")] + [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_LastIndexOf")] internal unsafe static extern int LastIndexOf(SafeSortHandle sortHandle, string target, int cwTargetLength, char* pSource, int cwSourceLength, CompareOptions options); - [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_IndexOfOrdinalIgnoreCase")] + [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_IndexOfOrdinalIgnoreCase")] internal unsafe static extern int IndexOfOrdinalIgnoreCase(string target, int cwTargetLength, char* pSource, int cwSourceLength, bool findLast); + [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_IndexOfOrdinalIgnoreCase")] + internal unsafe static extern int IndexOfOrdinalIgnoreCase(char* target, int cwTargetLength, char* pSource, int cwSourceLength, bool findLast); - [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_StartsWith")] + [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_StartsWith")] + [return: MarshalAs(UnmanagedType.Bool)] + internal unsafe static extern bool StartsWith(SafeSortHandle sortHandle, char* target, int cwTargetLength, char* source, int cwSourceLength, CompareOptions options); + + [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_EndsWith")] + [return: MarshalAs(UnmanagedType.Bool)] + internal unsafe static extern bool EndsWith(SafeSortHandle sortHandle, char* target, int cwTargetLength, char* source, int cwSourceLength, CompareOptions options); + + [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_StartsWith")] [return: MarshalAs(UnmanagedType.Bool)] internal unsafe static extern bool StartsWith(SafeSortHandle sortHandle, string target, int cwTargetLength, string source, int cwSourceLength, CompareOptions options); - [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_EndsWith")] + [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_EndsWith")] [return: MarshalAs(UnmanagedType.Bool)] internal unsafe static extern bool EndsWith(SafeSortHandle sortHandle, string target, int cwTargetLength, string source, int cwSourceLength, CompareOptions options); - [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetSortKey")] + [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetSortKey")] internal unsafe static extern int GetSortKey(SafeSortHandle sortHandle, string str, int strLength, byte* sortKey, int sortKeyLength, CompareOptions options); - [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_CompareStringOrdinalIgnoreCase")] + [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_CompareStringOrdinalIgnoreCase")] internal unsafe static extern int CompareStringOrdinalIgnoreCase(char* lpStr1, int cwStr1Len, char* lpStr2, int cwStr2Len); - [DllImport(Libraries.GlobalizationInterop, EntryPoint = "GlobalizationNative_GetSortVersion")] + [DllImport(Libraries.GlobalizationNative, EntryPoint = "GlobalizationNative_GetSortVersion")] internal static extern int GetSortVersion(SafeSortHandle sortHandle); internal class SafeSortHandle : SafeHandle diff --git a/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.ICU.cs b/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.ICU.cs index c690884145..a16c813b2f 100644 --- a/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.ICU.cs +++ b/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.ICU.cs @@ -8,9 +8,9 @@ using System.Runtime.CompilerServices; internal static partial class Interop { - internal static partial class GlobalizationInterop + internal static partial class Globalization { - [DllImport(Libraries.GlobalizationInterop, EntryPoint = "GlobalizationNative_LoadICU")] + [DllImport(Libraries.GlobalizationNative, EntryPoint = "GlobalizationNative_LoadICU")] internal static extern int LoadICU(); } } diff --git a/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.Idna.cs b/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.Idna.cs index 43c72281ae..af2373946c 100644 --- a/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.Idna.cs +++ b/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.Idna.cs @@ -7,15 +7,15 @@ using System.Runtime.InteropServices; internal static partial class Interop { - internal static partial class GlobalizationInterop + internal static partial class Globalization { internal const int AllowUnassigned = 0x1; internal const int UseStd3AsciiRules = 0x2; - [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_ToAscii")] + [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_ToAscii")] internal static unsafe extern int ToAscii(uint flags, char* src, int srcLen, char* dstBuffer, int dstBufferCapacity); - [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_ToUnicode")] + [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_ToUnicode")] internal static unsafe extern int ToUnicode(uint flags, char* src, int srcLen, char* dstBuffer, int dstBufferCapacity); } } diff --git a/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.Locale.cs b/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.Locale.cs index fcea708ee8..09527f0a08 100644 --- a/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.Locale.cs +++ b/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.Locale.cs @@ -8,33 +8,33 @@ using System.Text; internal static partial class Interop { - internal static partial class GlobalizationInterop + internal static partial class Globalization { - [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetLocaleName")] + [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetLocaleName")] [return: MarshalAs(UnmanagedType.Bool)] internal unsafe static extern bool GetLocaleName(string localeName, [Out] StringBuilder value, int valueLength); - [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetLocaleInfoString")] + [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetLocaleInfoString")] [return: MarshalAs(UnmanagedType.Bool)] internal unsafe static extern bool GetLocaleInfoString(string localeName, uint localeStringData, [Out] StringBuilder value, int valueLength); - [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetDefaultLocaleName")] + [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetDefaultLocaleName")] [return: MarshalAs(UnmanagedType.Bool)] internal unsafe static extern bool GetDefaultLocaleName([Out] StringBuilder value, int valueLength); - [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetLocaleTimeFormat")] + [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetLocaleTimeFormat")] [return: MarshalAs(UnmanagedType.Bool)] internal unsafe static extern bool GetLocaleTimeFormat(string localeName, bool shortFormat, [Out] StringBuilder value, int valueLength); - [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetLocaleInfoInt")] + [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetLocaleInfoInt")] [return: MarshalAs(UnmanagedType.Bool)] internal unsafe static extern bool GetLocaleInfoInt(string localeName, uint localeNumberData, ref int value); - [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetLocaleInfoGroupingSizes")] + [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetLocaleInfoGroupingSizes")] [return: MarshalAs(UnmanagedType.Bool)] internal unsafe static extern bool GetLocaleInfoGroupingSizes(string localeName, uint localeGroupingData, ref int primaryGroupSize, ref int secondaryGroupSize); - [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetLocales")] + [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetLocales")] internal unsafe static extern int GetLocales([Out] Char[] value, int valueLength); } } diff --git a/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.Normalization.cs b/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.Normalization.cs index c4cb9fb851..d442da0ea1 100644 --- a/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.Normalization.cs +++ b/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.Normalization.cs @@ -8,12 +8,12 @@ using System.Text; internal static partial class Interop { - internal static partial class GlobalizationInterop + internal static partial class Globalization { - [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_IsNormalized")] + [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_IsNormalized")] internal static extern int IsNormalized(NormalizationForm normalizationForm, string src, int srcLen); - [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_NormalizeString")] + [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_NormalizeString")] internal static extern int NormalizeString(NormalizationForm normalizationForm, string src, int srcLen, [Out] char[] dstBuffer, int dstBufferCapacity); } } diff --git a/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.ResultCode.cs b/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.ResultCode.cs index cca6ae4dcb..4a9933f929 100644 --- a/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.ResultCode.cs +++ b/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.ResultCode.cs @@ -4,7 +4,7 @@ internal static partial class Interop { - internal static partial class GlobalizationInterop + internal static partial class Globalization { // needs to be kept in sync with ResultCode in System.Globalization.Native internal enum ResultCode diff --git a/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.TimeZoneInfo.cs b/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.TimeZoneInfo.cs index 271ec3f9dc..47cf26662b 100644 --- a/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.TimeZoneInfo.cs +++ b/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.TimeZoneInfo.cs @@ -7,7 +7,7 @@ using System.Text; internal static partial class Interop { - internal static partial class GlobalizationInterop + internal static partial class Globalization { // needs to be kept in sync with TimeZoneDisplayNameType in System.Globalization.Native internal enum TimeZoneDisplayNameType @@ -17,7 +17,7 @@ internal static partial class Interop DaylightSavings = 2, } - [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetTimeZoneDisplayName")] + [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetTimeZoneDisplayName")] internal static extern ResultCode GetTimeZoneDisplayName( string localeName, string timeZoneId, diff --git a/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.Utils.cs b/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.Utils.cs index 33b10c0d74..9887bd4f0b 100644 --- a/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.Utils.cs +++ b/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Globalization.Native/Interop.Utils.cs @@ -13,7 +13,7 @@ internal static partial class Interop /// increasing buffer until the size is big enough. /// internal static bool CallStringMethod( - Func interopCall, + Func interopCall, TArg1 arg1, TArg2 arg2, TArg3 arg3, @@ -26,14 +26,14 @@ internal static partial class Interop for (int i = 0; i < maxDoubleAttempts; i++) { - GlobalizationInterop.ResultCode resultCode = interopCall(arg1, arg2, arg3, stringBuilder); + Interop.Globalization.ResultCode resultCode = interopCall(arg1, arg2, arg3, stringBuilder); - if (resultCode == GlobalizationInterop.ResultCode.Success) + if (resultCode == Interop.Globalization.ResultCode.Success) { result = StringBuilderCache.GetStringAndRelease(stringBuilder); return true; } - else if (resultCode == GlobalizationInterop.ResultCode.InsufficentBuffer) + else if (resultCode == Interop.Globalization.ResultCode.InsufficentBuffer) { // increase the string size and loop stringBuilder.EnsureCapacity(stringBuilder.Capacity * 2); diff --git a/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Native/Interop.PathConf.cs b/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Native/Interop.PathConf.cs index eb9e32db0c..7213cb0264 100644 --- a/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Native/Interop.PathConf.cs +++ b/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Native/Interop.PathConf.cs @@ -9,8 +9,6 @@ internal static partial class Interop { internal static partial class Sys { - internal static int DEFAULT_PC_NAME_MAX = 255; - internal enum PathConfName : int { PC_LINK_MAX = 1, diff --git a/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Native/Interop.ReadDir.cs b/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Native/Interop.ReadDir.cs new file mode 100644 index 0000000000..d98c4285c0 --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Native/Interop.ReadDir.cs @@ -0,0 +1,102 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.InteropServices; +using System.Threading; +using Microsoft.Win32.SafeHandles; + +internal static partial class Interop +{ + internal static partial class Sys + { + private static readonly int s_readBufferSize = GetReadDirRBufferSize(); + + internal enum NodeType : int + { + DT_UNKNOWN = 0, + DT_FIFO = 1, + DT_CHR = 2, + DT_DIR = 4, + DT_BLK = 6, + DT_REG = 8, + DT_LNK = 10, + DT_SOCK = 12, + DT_WHT = 14 + } + + [StructLayout(LayoutKind.Sequential)] + private unsafe struct InternalDirectoryEntry + { + internal IntPtr Name; + internal int NameLength; + internal NodeType InodeType; + } + + internal struct DirectoryEntry + { + internal NodeType InodeType; + internal string InodeName; + } + + [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_OpenDir", SetLastError = true)] + internal static extern Microsoft.Win32.SafeHandles.SafeDirectoryHandle OpenDir(string path); + + [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetReadDirRBufferSize", SetLastError = false)] + internal static extern int GetReadDirRBufferSize(); + + [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_ReadDirR", SetLastError = false)] + private static extern unsafe int ReadDirR(IntPtr dir, byte* buffer, int bufferSize, out InternalDirectoryEntry outputEntry); + + [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_CloseDir", SetLastError = true)] + internal static extern int CloseDir(IntPtr dir); + + // The calling pattern for ReadDir is described in src/Native/System.Native/pal_readdir.cpp + internal static int ReadDir(SafeDirectoryHandle dir, out DirectoryEntry outputEntry) + { + bool addedRef = false; + try + { + // We avoid a native string copy into InternalDirectoryEntry. + // - If the platform suppors reading into a buffer, the data is read directly into the buffer. The + // data can be read as long as the buffer is valid. + // - If the platform does not support reading into a buffer, the information returned in + // InternalDirectoryEntry points to native memory owned by the SafeDirectoryHandle. The data is only + // valid until the next call to CloseDir/ReadDir. We extend the reference until we have copied all data + // to ensure it does not become invalid by a CloseDir; and we copy the data so our caller does not + // use the native memory held by the SafeDirectoryHandle. + dir.DangerousAddRef(ref addedRef); + + unsafe + { + // s_readBufferSize is zero when the native implementation does not support reading into a buffer. + byte* buffer = stackalloc byte[s_readBufferSize]; + InternalDirectoryEntry temp; + int ret = ReadDirR(dir.DangerousGetHandle(), buffer, s_readBufferSize, out temp); + // We copy data into DirectoryEntry to ensure there are no dangling references. + outputEntry = ret == 0 ? + new DirectoryEntry() { InodeName = GetDirectoryEntryName(temp), InodeType = temp.InodeType } : + default(DirectoryEntry); + + return ret; + } + } + finally + { + if (addedRef) + { + dir.DangerousRelease(); + } + } + } + + private static unsafe string GetDirectoryEntryName(InternalDirectoryEntry dirEnt) + { + if (dirEnt.NameLength == -1) + return Marshal.PtrToStringAnsi(dirEnt.Name); + else + return Marshal.PtrToStringAnsi(dirEnt.Name, dirEnt.NameLength); + } + } +} diff --git a/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Native/Interop.Stat.cs b/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Native/Interop.Stat.cs index cda00ac6c3..0ca199b70d 100644 --- a/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Native/Interop.Stat.cs +++ b/external/corert/src/System.Private.CoreLib/shared/Interop/Unix/System.Native/Interop.Stat.cs @@ -24,9 +24,13 @@ internal static partial class Interop internal uint Gid; internal long Size; internal long ATime; + internal long ATimeNsec; internal long MTime; + internal long MTimeNsec; internal long CTime; + internal long CTimeNsec; internal long BirthTime; + internal long BirthTimeNsec; internal long Dev; internal long Ino; } @@ -49,13 +53,13 @@ internal static partial class Interop HasBirthTime = 1, } - [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_FStat", SetLastError = true)] + [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_FStat2", SetLastError = true)] internal static extern int FStat(SafeFileHandle fd, out FileStatus output); - [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_Stat", SetLastError = true)] + [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_Stat2", SetLastError = true)] internal static extern int Stat(string path, out FileStatus output); - [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_LStat", SetLastError = true)] + [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_LStat2", SetLastError = true)] internal static extern int LStat(string path, out FileStatus output); } } diff --git a/external/corert/src/System.Private.CoreLib/shared/Interop/Windows/Interop.Errors.cs b/external/corert/src/System.Private.CoreLib/shared/Interop/Windows/Interop.Errors.cs index ec52a81bf6..7f907fb6ca 100644 --- a/external/corert/src/System.Private.CoreLib/shared/Interop/Windows/Interop.Errors.cs +++ b/external/corert/src/System.Private.CoreLib/shared/Interop/Windows/Interop.Errors.cs @@ -39,6 +39,7 @@ internal partial class Interop internal const int ERROR_NO_UNICODE_TRANSLATION = 0x459; internal const int ERROR_NOT_FOUND = 0x490; internal const int ERROR_BAD_IMPERSONATION_LEVEL = 0x542; + internal const int ERROR_NO_SYSTEM_RESOURCES = 0x5AA; internal const int E_FILENOTFOUND = unchecked((int)0x80070002); internal const int ERROR_TIMEOUT = 0x000005B4; } diff --git a/external/corert/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.GetFileAttributesEx.cs b/external/corert/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.GetFileAttributesEx.cs index 4cce56bd05..181fb10105 100644 --- a/external/corert/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.GetFileAttributesEx.cs +++ b/external/corert/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.GetFileAttributesEx.cs @@ -31,7 +31,7 @@ internal partial class Interop internal struct WIN32_FILE_ATTRIBUTE_DATA { - internal int fileAttributes; + internal int dwFileAttributes; internal uint ftCreationTimeLow; internal uint ftCreationTimeHigh; internal uint ftLastAccessTimeLow; @@ -44,7 +44,7 @@ internal partial class Interop internal void PopulateFrom(ref WIN32_FIND_DATA findData) { // Copy the information to data - fileAttributes = (int)findData.dwFileAttributes; + dwFileAttributes = (int)findData.dwFileAttributes; ftCreationTimeLow = findData.ftCreationTime.dwLowDateTime; ftCreationTimeHigh = findData.ftCreationTime.dwHighDateTime; ftLastAccessTimeLow = findData.ftLastAccessTime.dwLowDateTime; diff --git a/external/corert/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.GetFullPathNameW.cs b/external/corert/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.GetFullPathNameW.cs index 15dd581113..06030450ca 100644 --- a/external/corert/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.GetFullPathNameW.cs +++ b/external/corert/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.GetFullPathNameW.cs @@ -13,6 +13,17 @@ internal partial class Interop /// WARNING: This method does not implicitly handle long paths. Use GetFullPathName or PathHelper. /// [DllImport(Libraries.Kernel32, SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false, ExactSpelling = true)] - unsafe internal static extern uint GetFullPathNameW(char* path, uint numBufferChars, char[] buffer, IntPtr mustBeZero); +#if PROJECTN + internal static extern unsafe uint GetFullPathNameW(string path, uint numBufferChars, char* buffer, IntPtr mustBeZero); + + // Works around https://devdiv.visualstudio.com/web/wi.aspx?pcguid=011b8bdf-6d56-4f87-be0d-0092136884d9&id=575202 + internal static unsafe uint GetFullPathNameW(string path, uint numBufferChars, ref char buffer, IntPtr mustBeZero) + { + fixed (char* pBuffer = &buffer) + return GetFullPathNameW(path, numBufferChars, pBuffer, mustBeZero); + } +#else + internal static extern uint GetFullPathNameW(string path, uint numBufferChars, ref char buffer, IntPtr mustBeZero); +#endif } } diff --git a/external/corert/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.GetLongPathNameW.cs b/external/corert/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.GetLongPathNameW.cs index ce04078af5..09e98d0c95 100644 --- a/external/corert/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.GetLongPathNameW.cs +++ b/external/corert/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.GetLongPathNameW.cs @@ -13,6 +13,17 @@ internal partial class Interop /// WARNING: This method does not implicitly handle long paths. Use GetFullPath/PathHelper. /// [DllImport(Libraries.Kernel32, SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false, ExactSpelling = true)] - internal static extern uint GetLongPathNameW(char[] lpszShortPath, char[] lpszLongPath, uint cchBuffer); +#if PROJECTN + internal static extern unsafe uint GetLongPathNameW(ref char lpszShortPath, char* lpszLongPath, uint cchBuffer); + + // Works around https://devdiv.visualstudio.com/web/wi.aspx?pcguid=011b8bdf-6d56-4f87-be0d-0092136884d9&id=575202 + internal static unsafe uint GetLongPathNameW(ref char lpszShortPath, ref char lpszLongPath, uint cchBuffer) + { + fixed (char* plpszLongPath = &lpszLongPath) + return GetLongPathNameW(ref lpszShortPath, plpszLongPath, cchBuffer); + } +#else + internal static extern uint GetLongPathNameW(ref char lpszShortPath, ref char lpszLongPath, uint cchBuffer); +#endif } } diff --git a/external/corert/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.Globalization.cs b/external/corert/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.Globalization.cs index 00bec5d3e2..ed0ada8411 100644 --- a/external/corert/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.Globalization.cs +++ b/external/corert/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.Globalization.cs @@ -85,10 +85,10 @@ internal static partial class Interop char* lpString, int cchStr); -#if !PROJECTN +#if !ENABLE_WINRT [DllImport("Kernel32.dll", CharSet = CharSet.Auto)] internal static extern bool GetUserPreferredUILanguages(uint dwFlags, out uint pulNumLanguages, char [] pwszLanguagesBuffer, ref uint pcchLanguagesBuffer); -#endif //!PROJECTN +#endif //!ENABLE_WINRT [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] internal static extern int GetLocaleInfoEx(string lpLocaleName, uint LCType, void* lpLCData, int cchData); diff --git a/external/corert/src/System.Private.CoreLib/src/System/IO/InternalFile.Unix.cs b/external/corert/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.MAX_PATH.cs similarity index 53% rename from external/corert/src/System.Private.CoreLib/src/System/IO/InternalFile.Unix.cs rename to external/corert/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.MAX_PATH.cs index a51c69bce1..f7fa32669b 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/IO/InternalFile.Unix.cs +++ b/external/corert/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.MAX_PATH.cs @@ -2,13 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -namespace System.IO +internal partial class Interop { - internal static partial class InternalFile + internal partial class Kernel32 { - internal static bool InternalExists(String path) - { - throw new NotImplementedException(); - } + internal const int MAX_PATH = 260; } } diff --git a/external/corert/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.MUI.cs b/external/corert/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.MUI.cs new file mode 100644 index 0000000000..6ed7aa2dc4 --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.MUI.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.InteropServices; +using System.Text; + +internal static partial class Interop +{ + internal static partial class Kernel32 + { + internal const uint MUI_PREFERRED_UI_LANGUAGES = 0x10; + + [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)] + internal static extern bool GetFileMUIPath(uint flags, String filePath, [Out] StringBuilder language, ref int languageLength, [Out] StringBuilder fileMuiPath, ref int fileMuiPathLength, ref Int64 enumerator); + } +} diff --git a/external/corert/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.TimeZone.Registry.cs b/external/corert/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.TimeZone.Registry.cs new file mode 100644 index 0000000000..062d1caeba --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.TimeZone.Registry.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + internal static partial class Kernel32 + { + [StructLayout(LayoutKind.Sequential)] + internal struct REG_TZI_FORMAT + { + internal int Bias; + internal int StandardBias; + internal int DaylightBias; + internal SYSTEMTIME StandardDate; + internal SYSTEMTIME DaylightDate; + + internal REG_TZI_FORMAT(in TIME_ZONE_INFORMATION tzi) + { + Bias = tzi.Bias; + StandardDate = tzi.StandardDate; + StandardBias = tzi.StandardBias; + DaylightDate = tzi.DaylightDate; + DaylightBias = tzi.DaylightBias; + } + } + } +} diff --git a/external/corert/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.TimeZone.cs b/external/corert/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.TimeZone.cs new file mode 100644 index 0000000000..05f13ac8ed --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.TimeZone.cs @@ -0,0 +1,94 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + internal static partial class Kernel32 + { + internal struct SYSTEMTIME + { + internal ushort Year; + internal ushort Month; + internal ushort DayOfWeek; + internal ushort Day; + internal ushort Hour; + internal ushort Minute; + internal ushort Second; + internal ushort Milliseconds; + + internal bool Equals(in SYSTEMTIME other) => + Year == other.Year && + Month == other.Month && + DayOfWeek == other.DayOfWeek && + Day == other.Day && + Hour == other.Hour && + Minute == other.Minute && + Second == other.Second && + Milliseconds == other.Milliseconds; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + internal unsafe struct TIME_DYNAMIC_ZONE_INFORMATION + { + internal int Bias; + internal fixed char StandardName[32]; + internal SYSTEMTIME StandardDate; + internal int StandardBias; + internal fixed char DaylightName[32]; + internal SYSTEMTIME DaylightDate; + internal int DaylightBias; + internal fixed char TimeZoneKeyName[128]; + internal byte DynamicDaylightTimeDisabled; + + internal string GetTimeZoneKeyName() + { + fixed (char* p = TimeZoneKeyName) + return new string(p); + } + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + internal unsafe struct TIME_ZONE_INFORMATION + { + internal int Bias; + internal fixed char StandardName[32]; + internal SYSTEMTIME StandardDate; + internal int StandardBias; + internal fixed char DaylightName[32]; + internal SYSTEMTIME DaylightDate; + internal int DaylightBias; + + internal TIME_ZONE_INFORMATION(in TIME_DYNAMIC_ZONE_INFORMATION dtzi) + { + // The start of TIME_DYNAMIC_ZONE_INFORMATION has identical layout as TIME_ZONE_INFORMATION + fixed (TIME_ZONE_INFORMATION* pTo = &this) + fixed (TIME_DYNAMIC_ZONE_INFORMATION* pFrom = &dtzi) + *pTo = *(TIME_ZONE_INFORMATION*)pFrom; + } + + internal string GetStandardName() + { + fixed (char* p = StandardName) + return new string(p); + } + + internal string GetDaylightName() + { + fixed (char* p = DaylightName) + return new string(p); + } + } + + internal const uint TIME_ZONE_ID_INVALID = unchecked((uint)-1); + + [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)] + internal extern static uint GetDynamicTimeZoneInformation(out TIME_DYNAMIC_ZONE_INFORMATION pTimeZoneInformation); + + [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)] + internal static extern uint GetTimeZoneInformation(out TIME_ZONE_INFORMATION lpTimeZoneInformation); + } +} diff --git a/external/corert/src/System.Private.CoreLib/shared/Microsoft/Win32/SafeHandles/SafeDirectoryHandle.Unix.cs b/external/corert/src/System.Private.CoreLib/shared/Microsoft/Win32/SafeHandles/SafeDirectoryHandle.Unix.cs new file mode 100644 index 0000000000..f7435eaae1 --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/shared/Microsoft/Win32/SafeHandles/SafeDirectoryHandle.Unix.cs @@ -0,0 +1,26 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.InteropServices; + +namespace Microsoft.Win32.SafeHandles +{ + internal sealed class SafeDirectoryHandle : SafeHandle + { + private SafeDirectoryHandle() : base(IntPtr.Zero, true) + { + } + + protected override bool ReleaseHandle() + { + return Interop.Sys.CloseDir(handle) == 0; + } + + public override bool IsInvalid + { + get { return handle == IntPtr.Zero; } + } + } +} diff --git a/external/corert/src/System.Private.CoreLib/shared/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs b/external/corert/src/System.Private.CoreLib/shared/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs index f28f44fdad..b284c116ba 100644 --- a/external/corert/src/System.Private.CoreLib/shared/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs +++ b/external/corert/src/System.Private.CoreLib/shared/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs @@ -83,10 +83,7 @@ namespace Microsoft.Win32.SafeHandles private static bool DirectoryExists(string fullPath) { - int fileType = Interop.Sys.FileTypes.S_IFDIR; - Interop.Sys.FileStatus fileinfo; - Interop.ErrorInfo errorInfo = default(Interop.ErrorInfo); // First use stat, as we want to follow symlinks. If that fails, it could be because the symlink // is broken, we don't have permissions, etc., in which case fall back to using LStat to evaluate @@ -94,16 +91,10 @@ namespace Microsoft.Win32.SafeHandles if (Interop.Sys.Stat(fullPath, out fileinfo) < 0 && Interop.Sys.LStat(fullPath, out fileinfo) < 0) { - errorInfo = Interop.Sys.GetLastErrorInfo(); return false; } - // Something exists at this path. If the caller is asking for a directory, return true if it's - // a directory and false for everything else. If the caller is asking for a file, return false for - // a directory and true for everything else. - return - (fileType == Interop.Sys.FileTypes.S_IFDIR) == - ((fileinfo.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFDIR); + return ((fileinfo.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFDIR); } /// Opens a SafeFileHandle for a file descriptor created by a provided delegate. diff --git a/external/corert/src/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFindHandle.cs b/external/corert/src/System.Private.CoreLib/shared/Microsoft/Win32/SafeHandles/SafeFindHandle.Windows.cs similarity index 75% rename from external/corert/src/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFindHandle.cs rename to external/corert/src/System.Private.CoreLib/shared/Microsoft/Win32/SafeHandles/SafeFindHandle.Windows.cs index 1c30841da4..4ba05409fd 100644 --- a/external/corert/src/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFindHandle.cs +++ b/external/corert/src/System.Private.CoreLib/shared/Microsoft/Win32/SafeHandles/SafeFindHandle.Windows.cs @@ -2,20 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -/*============================================================ -** -** -** -** A wrapper for find handles -** -** -===========================================================*/ - using System; using System.Security; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; -using System.Runtime.ConstrainedExecution; using Microsoft.Win32; namespace Microsoft.Win32.SafeHandles diff --git a/external/corert/src/System.Private.CoreLib/shared/README.md b/external/corert/src/System.Private.CoreLib/shared/README.md index d55f32576d..beda969ff7 100644 --- a/external/corert/src/System.Private.CoreLib/shared/README.md +++ b/external/corert/src/System.Private.CoreLib/shared/README.md @@ -1,12 +1,12 @@ # System.Private.CoreLib Shared Sources -This directory contains the shared sources for System.Private.CoreLib. These are shared between [dotnet/corert](https://github.com/dotnet/corert/tree/master/src/System.Private.CoreLib/shared) and [dotnet/coreclr](https://github.com/dotnet/coreclr/tree/master/src/mscorlib/shared). +This directory contains the shared sources for System.Private.CoreLib. These are shared between [dotnet/corert](https://github.com/dotnet/corert/tree/master/src/System.Private.CoreLib/shared), [dotnet/coreclr](https://github.com/dotnet/coreclr/tree/master/src/mscorlib/shared) and [dotnet/corefx](https://github.com/dotnet/corefx/tree/master/src/Common/src/CoreLib). The sources are synchronized with a mirroring tool that watches for new commits on either side and creates new pull requests (as @dotnet-bot) in the other repository. ## Conventions -Code in the shared directory should have no code specific to CoreCLR or CoreRT. Parts of classes that need to have different implementations on different runtimes should use partial classes and *.CoreRT.cs/*.CoreCLR.cs files in the non shared portion. Code that is different based on platform (Windows/Unix) is fine to leave in the shared portion. Remember to follow the [style guidelines](https://github.com/dotnet/corefx/blob/master/Documentation/coding-guidelines/coding-style.md). +Code in the shared directory should have no code specific to CoreCLR, CoreRT or CoreFX. Parts of classes that need to have different implementations on different runtimes should use partial classes and *.CoreRT.cs/*.CoreCLR.cs/*.CoreFX.cs files in the non shared portion. Code that is different based on platform (Windows/Unix) is fine to leave in the shared portion. Remember to follow the [style guidelines](https://github.com/dotnet/corefx/blob/master/Documentation/coding-guidelines/coding-style.md). ## Getting clean CI and merging the mirror PRs diff --git a/external/corert/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems b/external/corert/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems index aaf6bfcf7c..0b3f971b17 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems +++ b/external/corert/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems @@ -19,6 +19,7 @@ + @@ -54,6 +55,7 @@ + @@ -71,6 +73,7 @@ + @@ -131,6 +134,7 @@ + @@ -145,6 +149,7 @@ + @@ -214,6 +219,10 @@ + + + + @@ -232,6 +241,8 @@ + + @@ -257,6 +268,7 @@ + @@ -407,6 +419,7 @@ + @@ -428,12 +441,12 @@ + - @@ -473,8 +486,13 @@ + - + + + + + @@ -532,6 +550,7 @@ + @@ -544,6 +563,10 @@ + + + + @@ -561,7 +584,7 @@ - + @@ -607,6 +630,37 @@ + + + True + True + ConstantHelper.tt + + + TextTemplatingFileGenerator + ConstantHelper.cs + + + + True + True + Register.tt + + + TextTemplatingFileGenerator + Register.cs + + + True + True + Vector.tt + + + TextTemplatingFileGenerator + Vector.cs + + + @@ -632,6 +686,7 @@ + @@ -646,11 +701,15 @@ + + + + @@ -663,17 +722,19 @@ - + + + @@ -717,11 +778,14 @@ + + + @@ -738,5 +802,6 @@ + diff --git a/external/corert/src/System.Private.CoreLib/shared/System/AggregateException.cs b/external/corert/src/System.Private.CoreLib/shared/System/AggregateException.cs index 36b9494980..99ba703a52 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/AggregateException.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/AggregateException.cs @@ -453,12 +453,12 @@ namespace System for (int i = 0; i < m_innerExceptions.Count; i++) { - text.Append(Environment.NewLine); + text.AppendLine(); text.Append("---> "); - text.Append(string.Format(CultureInfo.InvariantCulture, SR.AggregateException_InnerException, i)); + text.AppendFormat(CultureInfo.InvariantCulture, SR.AggregateException_InnerException, i); text.Append(m_innerExceptions[i].ToString()); text.Append("<---"); - text.Append(Environment.NewLine); + text.AppendLine(); } return text.ToString(); diff --git a/external/corert/src/System.Private.CoreLib/shared/System/ArraySegment.cs b/external/corert/src/System.Private.CoreLib/shared/System/ArraySegment.cs index d45fb0dc2b..3a13595e83 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/ArraySegment.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/ArraySegment.cs @@ -192,7 +192,7 @@ namespace System return !(a == b); } - public static implicit operator ArraySegment(T[] array) => new ArraySegment(array); + public static implicit operator ArraySegment(T[] array) => array != null ? new ArraySegment(array) : default; #region IList T IList.this[int index] diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Boolean.cs b/external/corert/src/System.Private.CoreLib/shared/System/Boolean.cs index 896e5f18e5..fd56082f9b 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Boolean.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Boolean.cs @@ -100,10 +100,8 @@ namespace System { string s = m_value ? TrueLiteral : FalseLiteral; - if (s.Length <= destination.Length) + if (s.AsSpan().TryCopyTo(destination)) { - bool copied = s.AsReadOnlySpan().TryCopyTo(destination); - Debug.Assert(copied); charsWritten = s.Length; return true; } @@ -183,7 +181,7 @@ namespace System public static Boolean Parse(String value) { if (value == null) throw new ArgumentNullException(nameof(value)); - return Parse(value.AsReadOnlySpan()); + return Parse(value.AsSpan()); } public static bool Parse(ReadOnlySpan value) => @@ -199,19 +197,19 @@ namespace System return false; } - return TryParse(value.AsReadOnlySpan(), out result); + return TryParse(value.AsSpan(), out result); } public static bool TryParse(ReadOnlySpan value, out bool result) { - ReadOnlySpan trueSpan = TrueLiteral.AsReadOnlySpan(); + ReadOnlySpan trueSpan = TrueLiteral.AsSpan(); if (StringSpanHelpers.Equals(trueSpan, value, StringComparison.OrdinalIgnoreCase)) { result = true; return true; } - ReadOnlySpan falseSpan = FalseLiteral.AsReadOnlySpan(); + ReadOnlySpan falseSpan = FalseLiteral.AsSpan(); if (StringSpanHelpers.Equals(falseSpan, value, StringComparison.OrdinalIgnoreCase)) { result = false; diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Buffers/ArrayPoolEventSource.cs b/external/corert/src/System.Private.CoreLib/shared/System/Buffers/ArrayPoolEventSource.cs index 9482744144..b2d0dbd32d 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Buffers/ArrayPoolEventSource.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Buffers/ArrayPoolEventSource.cs @@ -6,7 +6,7 @@ using System.Diagnostics.Tracing; namespace System.Buffers { - [EventSource(Name = "System.Buffers.ArrayPoolEventSource")] + [EventSource(Guid = "0866B2B8-5CEF-5DB9-2612-0C0FFD814A44", Name = "System.Buffers.ArrayPoolEventSource")] internal sealed class ArrayPoolEventSource : EventSource { internal readonly static ArrayPoolEventSource Log = new ArrayPoolEventSource(); @@ -22,6 +22,9 @@ namespace System.Buffers PoolExhausted } + // The ArrayPoolEventSource GUID is {0866b2b8-5cef-5db9-2612-0c0ffd814a44} + private ArrayPoolEventSource() : base(new Guid(0x0866b2b8, 0x5cef, 0x5db9, 0x26, 0x12, 0x0c, 0x0f, 0xfd, 0x81, 0x4a, 0x44), "System.Buffers.ArrayPoolEventSource") { } + /// /// Event for when a buffer is rented. This is invoked once for every successful call to Rent, /// regardless of whether a buffer is allocated or a buffer is taken from the pool. In a @@ -36,12 +39,16 @@ namespace System.Buffers EventData* payload = stackalloc EventData[4]; payload[0].Size = sizeof(int); payload[0].DataPointer = ((IntPtr)(&bufferId)); + payload[0].Reserved = 0; payload[1].Size = sizeof(int); payload[1].DataPointer = ((IntPtr)(&bufferSize)); + payload[1].Reserved = 0; payload[2].Size = sizeof(int); payload[2].DataPointer = ((IntPtr)(&poolId)); + payload[2].Reserved = 0; payload[3].Size = sizeof(int); payload[3].DataPointer = ((IntPtr)(&bucketId)); + payload[3].Reserved = 0; WriteEventCore(1, 4, payload); } @@ -56,14 +63,19 @@ namespace System.Buffers EventData* payload = stackalloc EventData[5]; payload[0].Size = sizeof(int); payload[0].DataPointer = ((IntPtr)(&bufferId)); + payload[0].Reserved = 0; payload[1].Size = sizeof(int); payload[1].DataPointer = ((IntPtr)(&bufferSize)); + payload[1].Reserved = 0; payload[2].Size = sizeof(int); payload[2].DataPointer = ((IntPtr)(&poolId)); + payload[2].Reserved = 0; payload[3].Size = sizeof(int); payload[3].DataPointer = ((IntPtr)(&bucketId)); + payload[3].Reserved = 0; payload[4].Size = sizeof(BufferAllocatedReason); payload[4].DataPointer = ((IntPtr)(&reason)); + payload[4].Reserved = 0; WriteEventCore(2, 5, payload); } diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Buffers/IRetainable.cs b/external/corert/src/System.Private.CoreLib/shared/System/Buffers/IRetainable.cs index 8d71fc614a..6ac508859c 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Buffers/IRetainable.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Buffers/IRetainable.cs @@ -7,9 +7,20 @@ using System.Runtime.CompilerServices; namespace System.Buffers { + /// + /// Provides a mechanism for manual lifetime management. + /// public interface IRetainable { + /// + /// Call this method to indicate that the IRetainable object is in use. + /// Do not dispose until Release is called. + /// void Retain(); + /// + /// Call this method to indicate that the IRetainable object is no longer in use. + /// The object can now be disposed. + /// bool Release(); } } \ No newline at end of file diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Buffers/MemoryHandle.cs b/external/corert/src/System.Private.CoreLib/shared/System/Buffers/MemoryHandle.cs index 60592144a5..7544038629 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Buffers/MemoryHandle.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Buffers/MemoryHandle.cs @@ -7,52 +7,58 @@ using System.Runtime.InteropServices; namespace System.Buffers { + /// + /// A handle for the memory. + /// public unsafe struct MemoryHandle : IDisposable { - private IRetainable _owner; + private IRetainable _retainable; private void* _pointer; private GCHandle _handle; + /// + /// Creates a new memory handle for the memory. + /// + /// reference to manually managed object + /// pointer to memory, or null if a pointer was not provided when the handle was created + /// handle used to pin array buffers [CLSCompliant(false)] - public MemoryHandle(IRetainable owner, void* pointer = null, GCHandle handle = default(GCHandle)) + public MemoryHandle(IRetainable retainable, void* pointer = null, GCHandle handle = default(GCHandle)) { - _owner = owner; + _retainable = retainable; _pointer = pointer; _handle = handle; } - internal void AddOffset(int offset) - { - if (_pointer == null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.pointer); - } - else - { - _pointer = (void*)((byte*)_pointer + offset); - } - } - + /// + /// Returns the pointer to memory, or null if a pointer was not provided when the handle was created. + /// [CLSCompliant(false)] public void* Pointer => _pointer; + /// + /// Returns false if the pointer to memory is null. + /// public bool HasPointer => _pointer != null; - public void Dispose() - { - if (_handle.IsAllocated) + /// + /// Frees the pinned handle and releases IRetainable. + /// + public void Dispose() + { + if (_handle.IsAllocated) { _handle.Free(); } - if (_owner != null) + if (_retainable != null) { - _owner.Release(); - _owner = null; + _retainable.Release(); + _retainable = null; } - _pointer = null; + _pointer = null; } - + } } \ No newline at end of file diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Buffers/OwnedMemory.cs b/external/corert/src/System.Private.CoreLib/shared/System/Buffers/OwnedMemory.cs index 116767073d..eade1feff3 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Buffers/OwnedMemory.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Buffers/OwnedMemory.cs @@ -7,46 +7,88 @@ using System.Runtime.CompilerServices; namespace System.Buffers { + /// + /// Owner of Memory that provides appropriate lifetime management mechanisms for it. + /// public abstract class OwnedMemory : IDisposable, IRetainable { + /// + /// The number of items in the Memory. + /// public abstract int Length { get; } + /// + /// Returns a span wrapping the underlying memory. + /// public abstract Span Span { get; } + /// + /// Returns a Memory if the underlying memory has not been freed. + /// + /// + /// Thrown when the underlying memory has already been disposed. + /// public Memory Memory { - get + get { - if (IsDisposed) + if (IsDisposed) { - ThrowHelper.ThrowObjectDisposedException(nameof(OwnedMemory), ExceptionResource.Memory_ThrowIfDisposed); + ThrowHelper.ThrowObjectDisposedException_MemoryDisposed(); } return new Memory(owner: this, 0, Length); } } - public abstract MemoryHandle Pin(); + /// + /// Returns a handle for the array that has been pinned and hence its address can be taken + /// + public abstract MemoryHandle Pin(int byteOffset = 0); + /// + /// Returns an array segment. + /// protected internal abstract bool TryGetArray(out ArraySegment arraySegment); + /// + /// Implements IDisposable. + /// + /// + /// Throw when there are still retained references to the memory + /// public void Dispose() { - if (IsRetained) + if (IsRetained) { - ThrowHelper.ThrowInvalidOperationException(ExceptionResource.Memory_OutstandingReferences); + ThrowHelper.ThrowInvalidOperationException_OutstandingReferences(); } Dispose(true); GC.SuppressFinalize(this); } + /// + /// Clean up of any leftover managed and unmanaged resources. + /// protected abstract void Dispose(bool disposing); + /// + /// Return true if someone is holding a reference to the memory. + /// protected abstract bool IsRetained { get; } + /// + /// Return true if the underlying memory has been freed. + /// public abstract bool IsDisposed { get; } + /// + /// Implements IRetainable. Prevent accidental disposal of the memory. + /// public abstract void Retain(); + /// + /// Implements IRetainable. The memory can now be diposed. + /// public abstract bool Release(); } diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Char.cs b/external/corert/src/System.Private.CoreLib/shared/System/Char.cs index 6059830fbd..d3ed1f5b68 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Char.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Char.cs @@ -401,14 +401,14 @@ namespace System // public static char ToUpper(char c) { - return ToUpper(c, CultureInfo.CurrentCulture); + return CultureInfo.CurrentCulture.TextInfo.ToUpper(c); } // Converts a character to upper-case for invariant culture. public static char ToUpperInvariant(char c) { - return ToUpper(c, CultureInfo.InvariantCulture); + return CultureInfo.InvariantCulture.TextInfo.ToUpper(c); } @@ -432,14 +432,14 @@ namespace System // Converts a character to lower-case for the default culture. public static char ToLower(char c) { - return ToLower(c, CultureInfo.CurrentCulture); + return CultureInfo.CurrentCulture.TextInfo.ToLower(c); } // Converts a character to lower-case for invariant culture. public static char ToLowerInvariant(char c) { - return ToLower(c, CultureInfo.InvariantCulture); + return CultureInfo.InvariantCulture.TextInfo.ToLower(c); } @@ -853,7 +853,7 @@ namespace System { return (GetLatin1UnicodeCategory(c)); } - return CharUnicodeInfo.InternalGetUnicodeCategory(c); + return CharUnicodeInfo.GetUnicodeCategory((int)c); } public static UnicodeCategory GetUnicodeCategory(String s, int index) diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Collections/Comparer.cs b/external/corert/src/System.Private.CoreLib/shared/System/Collections/Comparer.cs new file mode 100644 index 0000000000..6fcedc09ab --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/shared/System/Collections/Comparer.cs @@ -0,0 +1,77 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*============================================================ +** +** Purpose: Default IComparer implementation. +** +===========================================================*/ + +using System.Globalization; +using System.Runtime.Serialization; + +namespace System.Collections +{ + [Serializable] + [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] + public sealed class Comparer : IComparer, ISerializable + { + private CompareInfo _compareInfo; + + public static readonly Comparer Default = new Comparer(CultureInfo.CurrentCulture); + public static readonly Comparer DefaultInvariant = new Comparer(CultureInfo.InvariantCulture); + + public Comparer(CultureInfo culture) + { + if (culture == null) + throw new ArgumentNullException(nameof(culture)); + + _compareInfo = culture.CompareInfo; + } + + private Comparer(SerializationInfo info, StreamingContext context) + { + if (info == null) + throw new ArgumentNullException(nameof(info)); + + _compareInfo = (CompareInfo)info.GetValue("CompareInfo", typeof(CompareInfo)); + } + + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + if (info == null) + throw new ArgumentNullException(nameof(info)); + + info.AddValue("CompareInfo", _compareInfo); + } + + // Compares two Objects by calling CompareTo. + // If a == b, 0 is returned. + // If a implements IComparable, a.CompareTo(b) is returned. + // If a doesn't implement IComparable and b does, -(b.CompareTo(a)) is returned. + // Otherwise an exception is thrown. + // + public int Compare(Object a, Object b) + { + if (a == b) return 0; + if (a == null) return -1; + if (b == null) return 1; + + string sa = a as string; + string sb = b as string; + if (sa != null && sb != null) + return _compareInfo.Compare(sa, sb); + + IComparable ia = a as IComparable; + if (ia != null) + return ia.CompareTo(b); + + IComparable ib = b as IComparable; + if (ib != null) + return -ib.CompareTo(a); + + throw new ArgumentException(SR.Argument_ImplementIComparable); + } + } +} diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Collections/Generic/Dictionary.cs b/external/corert/src/System.Private.CoreLib/shared/System/Collections/Generic/Dictionary.cs index ab7f0dba8f..8fd8d91f0a 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Collections/Generic/Dictionary.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Collections/Generic/Dictionary.cs @@ -77,11 +77,15 @@ namespace System.Collections.Generic { if (capacity < 0) ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.capacity); if (capacity > 0) Initialize(capacity); - _comparer = comparer ?? EqualityComparer.Default; + if (comparer != EqualityComparer.Default) + { + _comparer = comparer; + } #if !MONO - if (_comparer == EqualityComparer.Default) + if (typeof(TKey) == typeof(string) && _comparer == null) { + // To start, move off default comparer for string which is randomised _comparer = (IEqualityComparer)NonRandomizedStringEqualityComparer.Default; } #endif @@ -150,7 +154,7 @@ namespace System.Collections.Generic { get { - return _comparer; + return (_comparer == null || _comparer is NonRandomizedStringEqualityComparer) ? EqualityComparer.Default : _comparer; } } @@ -266,11 +270,7 @@ namespace System.Collections.Generic int count = _count; if (count > 0) { - int[] buckets = _buckets; - for (int i = 0; i < buckets.Length; i++) - { - buckets[i] = -1; - } + Array.Clear(_buckets, 0, _buckets.Length); _count = 0; _freeList = -1; @@ -296,10 +296,9 @@ namespace System.Collections.Generic } else { - EqualityComparer c = EqualityComparer.Default; for (int i = 0; i < _count; i++) { - if (_entries[i].hashCode >= 0 && c.Equals(_entries[i].value, value)) return true; + if (_entries[i].hashCode >= 0 && EqualityComparer.Default.Equals(_entries[i].value, value)) return true; } } return false; @@ -351,7 +350,7 @@ namespace System.Collections.Generic } info.AddValue(VersionName, _version); - info.AddValue(ComparerName, _comparer, typeof(IEqualityComparer)); + info.AddValue(ComparerName, _comparer ?? EqualityComparer.Default, typeof(IEqualityComparer)); info.AddValue(HashSizeName, _buckets == null ? 0 : _buckets.Length); // This is the length of the bucket array if (_buckets != null) @@ -369,29 +368,61 @@ namespace System.Collections.Generic ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key); } - if (_buckets != null) + int i = -1; + int[] buckets = _buckets; + Entry[] entries = _entries; + if (buckets != null) { - int hashCode = _comparer.GetHashCode(key) & 0x7FFFFFFF; - for (int i = _buckets[hashCode % _buckets.Length]; i >= 0; i = _entries[i].next) + IEqualityComparer comparer = _comparer; + if (comparer == null) { - if (_entries[i].hashCode == hashCode && _comparer.Equals(_entries[i].key, key)) return i; + int hashCode = key.GetHashCode() & 0x7FFFFFFF; + // Value in _buckets is 1-based + i = buckets[hashCode % buckets.Length] - 1; + do + { + // Should be a while loop https://github.com/dotnet/coreclr/issues/15476 + // Test in if to drop range check for following array access + if ((uint)i >= (uint)entries.Length || (entries[i].hashCode == hashCode && EqualityComparer.Default.Equals(entries[i].key, key))) + { + break; + } + + i = entries[i].next; + } while (true); + } + else + { + int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF; + // Value in _buckets is 1-based + i = buckets[hashCode % buckets.Length] - 1; + do + { + // Should be a while loop https://github.com/dotnet/coreclr/issues/15476 + // Test in if to drop range check for following array access + if ((uint)i >= (uint)entries.Length || + (entries[i].hashCode == hashCode && comparer.Equals(entries[i].key, key))) + { + break; + } + + i = entries[i].next; + } while (true); } } - return -1; + + return i; } - private void Initialize(int capacity) + private int Initialize(int capacity) { int size = HashHelpers.GetPrime(capacity); - int[] buckets = new int[size]; - for (int i = 0; i < buckets.Length; i++) - { - buckets[i] = -1; - } _freeList = -1; - _buckets = buckets; + _buckets = new int[size]; _entries = new Entry[size]; + + return size; } private bool TryInsert(TKey key, TValue value, InsertionBehavior behavior) @@ -401,65 +432,135 @@ namespace System.Collections.Generic ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key); } - if (_buckets == null) Initialize(0); - int hashCode = _comparer.GetHashCode(key) & 0x7FFFFFFF; - int targetBucket = hashCode % _buckets.Length; - int collisionCount = 0; - - for (int i = _buckets[targetBucket]; i >= 0; i = _entries[i].next) + if (_buckets == null) { - if (_entries[i].hashCode == hashCode && _comparer.Equals(_entries[i].key, key)) - { - if (behavior == InsertionBehavior.OverwriteExisting) - { - _entries[i].value = value; - _version++; - return true; - } - - if (behavior == InsertionBehavior.ThrowOnExisting) - { - ThrowHelper.ThrowAddingDuplicateWithKeyArgumentException(key); - } - - return false; - } - collisionCount++; + Initialize(0); } + Entry[] entries = _entries; + IEqualityComparer comparer = _comparer; + + int hashCode = ((comparer == null) ? key.GetHashCode() : comparer.GetHashCode(key)) & 0x7FFFFFFF; + + int collisionCount = 0; + ref int bucket = ref _buckets[hashCode % _buckets.Length]; + // Value in _buckets is 1-based + int i = bucket - 1; + + if (comparer == null) + { + do + { + // Should be a while loop https://github.com/dotnet/coreclr/issues/15476 + // Test uint in if rather than loop condition to drop range check for following array access + if ((uint)i >= (uint)entries.Length) + { + break; + } + + if (entries[i].hashCode == hashCode && EqualityComparer.Default.Equals(entries[i].key, key)) + { + if (behavior == InsertionBehavior.OverwriteExisting) + { + entries[i].value = value; + _version++; + return true; + } + + if (behavior == InsertionBehavior.ThrowOnExisting) + { + ThrowHelper.ThrowAddingDuplicateWithKeyArgumentException(key); + } + + return false; + } + + i = entries[i].next; + collisionCount++; + } while (true); + } + else + { + do + { + // Should be a while loop https://github.com/dotnet/coreclr/issues/15476 + // Test uint in if rather than loop condition to drop range check for following array access + if ((uint)i >= (uint)entries.Length) + { + break; + } + + if (entries[i].hashCode == hashCode && comparer.Equals(entries[i].key, key)) + { + if (behavior == InsertionBehavior.OverwriteExisting) + { + entries[i].value = value; + _version++; + return true; + } + + if (behavior == InsertionBehavior.ThrowOnExisting) + { + ThrowHelper.ThrowAddingDuplicateWithKeyArgumentException(key); + } + + return false; + } + + i = entries[i].next; + collisionCount++; + } while (true); + + } + + // Can be improved with "Ref Local Reassignment" + // https://github.com/dotnet/csharplang/blob/master/proposals/ref-local-reassignment.md + bool resized = false; + bool updateFreeList = false; int index; if (_freeCount > 0) { index = _freeList; - _freeList = _entries[index].next; + updateFreeList = true; _freeCount--; } else { - if (_count == _entries.Length) + int count = _count; + if (count == entries.Length) { Resize(); - targetBucket = hashCode % _buckets.Length; + resized = true; } - index = _count; - _count++; + index = count; + _count = count + 1; + entries = _entries; } - _entries[index].hashCode = hashCode; - _entries[index].next = _buckets[targetBucket]; - _entries[index].key = key; - _entries[index].value = value; - _buckets[targetBucket] = index; + ref int targetBucket = ref resized ? ref _buckets[hashCode % _buckets.Length] : ref bucket; + ref Entry entry = ref entries[index]; + + if (updateFreeList) + { + _freeList = entry.next; + } + entry.hashCode = hashCode; + // Value in _buckets is 1-based + entry.next = targetBucket - 1; + entry.key = key; + entry.value = value; + // Value in _buckets is 1-based + targetBucket = index + 1; _version++; #if !MONO - // If we hit the collision threshold we'll need to switch to the comparer which is using randomized string hashing - // i.e. EqualityComparer.Default. - - if (collisionCount > HashHelpers.HashCollisionThreshold && _comparer is NonRandomizedStringEqualityComparer) + // Value types never rehash + if (default(TKey) == null && collisionCount > HashHelpers.HashCollisionThreshold && comparer is NonRandomizedStringEqualityComparer) { - _comparer = (IEqualityComparer)EqualityComparer.Default; - Resize(_entries.Length, true); + // If we hit the collision threshold we'll need to switch to the comparer which is using randomized string hashing + // i.e. EqualityComparer.Default. + _comparer = null; + Resize(entries.Length, true); } #endif @@ -519,25 +620,24 @@ namespace System.Collections.Generic private void Resize(int newSize, bool forceNewHashCodes) { + // Value types never rehash + Debug.Assert(!forceNewHashCodes || default(TKey) == null); Debug.Assert(newSize >= _entries.Length); int[] buckets = new int[newSize]; - for (int i = 0; i < buckets.Length; i++) - { - buckets[i] = -1; - } Entry[] entries = new Entry[newSize]; int count = _count; Array.Copy(_entries, 0, entries, 0, count); - if (forceNewHashCodes) + if (default(TKey) == null && forceNewHashCodes) { for (int i = 0; i < count; i++) { - if (entries[i].hashCode != -1) + if (entries[i].hashCode >= 0) { - entries[i].hashCode = (_comparer.GetHashCode(entries[i].key) & 0x7FFFFFFF); + Debug.Assert(_comparer == null); + entries[i].hashCode = (entries[i].key.GetHashCode() & 0x7FFFFFFF); } } } @@ -547,8 +647,10 @@ namespace System.Collections.Generic if (entries[i].hashCode >= 0) { int bucket = entries[i].hashCode % newSize; - entries[i].next = buckets[bucket]; - buckets[bucket] = i; + // Value in _buckets is 1-based + entries[i].next = buckets[bucket] - 1; + // Value in _buckets is 1-based + buckets[bucket] = i + 1; } } @@ -568,19 +670,21 @@ namespace System.Collections.Generic if (_buckets != null) { - int hashCode = _comparer.GetHashCode(key) & 0x7FFFFFFF; + int hashCode = (_comparer?.GetHashCode(key) ?? key.GetHashCode()) & 0x7FFFFFFF; int bucket = hashCode % _buckets.Length; int last = -1; - int i = _buckets[bucket]; + // Value in _buckets is 1-based + int i = _buckets[bucket] - 1; while (i >= 0) { ref Entry entry = ref _entries[i]; - if (entry.hashCode == hashCode && _comparer.Equals(entry.key, key)) + if (entry.hashCode == hashCode && (_comparer?.Equals(entry.key, key) ?? EqualityComparer.Default.Equals(entry.key, key))) { if (last < 0) { - _buckets[bucket] = entry.next; + // Value in _buckets is 1-based + _buckets[bucket] = entry.next + 1; } else { @@ -622,19 +726,21 @@ namespace System.Collections.Generic if (_buckets != null) { - int hashCode = _comparer.GetHashCode(key) & 0x7FFFFFFF; + int hashCode = (_comparer?.GetHashCode(key) ?? key.GetHashCode()) & 0x7FFFFFFF; int bucket = hashCode % _buckets.Length; int last = -1; - int i = _buckets[bucket]; + // Value in _buckets is 1-based + int i = _buckets[bucket] - 1; while (i >= 0) { ref Entry entry = ref _entries[i]; - if (entry.hashCode == hashCode && _comparer.Equals(entry.key, key)) + if (entry.hashCode == hashCode && (_comparer?.Equals(entry.key, key) ?? EqualityComparer.Default.Equals(entry.key, key))) { if (last < 0) { - _buckets[bucket] = entry.next; + // Value in _buckets is 1-based + _buckets[bucket] = entry.next + 1; } else { @@ -768,6 +874,80 @@ namespace System.Collections.Generic return new Enumerator(this, Enumerator.KeyValuePair); } + /// + /// Ensures that the dictionary can hold up to 'capacity' entries without any further expansion of its backing storage + /// + public int EnsureCapacity(int capacity) + { + if (capacity < 0) + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.capacity); + int currentCapacity = _entries == null ? 0 : _entries.Length; + if (currentCapacity >= capacity) + return currentCapacity; + if (_buckets == null) + return Initialize(capacity); + int newSize = HashHelpers.GetPrime(capacity); + Resize(newSize, forceNewHashCodes: false); + return newSize; + } + + /// + /// Sets the capacity of this dictionary to what it would be if it had been originally initialized with all its entries + /// + /// This method can be used to minimize the memory overhead + /// once it is known that no new elements will be added. + /// + /// To allocate minimum size storage array, execute the following statements: + /// + /// dictionary.Clear(); + /// dictionary.TrimExcess(); + /// + public void TrimExcess() + { + TrimExcess(Count); + } + + /// + /// Sets the capacity of this dictionary to hold up 'capacity' entries without any further expansion of its backing storage + /// + /// This method can be used to minimize the memory overhead + /// once it is known that no new elements will be added. + /// + public void TrimExcess(int capacity) + { + if (capacity < Count) + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.capacity); + int newSize = HashHelpers.GetPrime(capacity); + + Entry[] oldEntries = _entries; + int currentCapacity = oldEntries == null ? 0 : oldEntries.Length; + if (newSize >= currentCapacity) + return; + + int oldCount = _count; + Initialize(newSize); + Entry[] entries = _entries; + int[] buckets = _buckets; + int count = 0; + for (int i = 0; i < oldCount; i++) + { + int hashCode = oldEntries[i].hashCode; + if (hashCode >= 0) + { + ref Entry entry = ref entries[count]; + entry = oldEntries[i]; + int bucket = hashCode % newSize; + // Value in _buckets is 1-based + entry.next = buckets[bucket] - 1; + // Value in _buckets is 1-based + buckets[bucket] = count + 1; + count++; + } + } + _count = count; + _freeCount = 0; + } + bool ICollection.IsSynchronized { get { return false; } diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Collections/Generic/NonRandomizedStringEqualityComparer.cs b/external/corert/src/System.Private.CoreLib/shared/System/Collections/Generic/NonRandomizedStringEqualityComparer.cs index ef44fefc8e..72f62c2b9a 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Collections/Generic/NonRandomizedStringEqualityComparer.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Collections/Generic/NonRandomizedStringEqualityComparer.cs @@ -11,10 +11,10 @@ namespace System.Collections.Generic // keeps the performance not affected till we hit collision threshold and then we switch to the comparer which is using // randomized string hashing. [Serializable] // Required for compatibility with .NET Core 2.0 as we exposed the NonRandomizedStringEqualityComparer inside the serialization blob -#if CORECLR - internal -#else +#if CORERT public +#else + internal #endif sealed class NonRandomizedStringEqualityComparer : EqualityComparer, ISerializable { diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Collections/Generic/ValueListBuilder.cs b/external/corert/src/System.Private.CoreLib/shared/System/Collections/Generic/ValueListBuilder.cs new file mode 100644 index 0000000000..5fbeeec9c3 --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/shared/System/Collections/Generic/ValueListBuilder.cs @@ -0,0 +1,76 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Buffers; +using System.Diagnostics.Private; +using System.Runtime.CompilerServices; + +namespace System.Collections.Generic +{ + internal ref partial struct ValueListBuilder + { + private Span _span; + private T[] _arrayFromPool; + private int _pos; + + public ValueListBuilder(Span initialSpan) + { + _span = initialSpan; + _arrayFromPool = null; + _pos = 0; + } + + public int Length => _pos; + + public ref T this[int index] + { + get + { + Debug.Assert(index < _pos); + return ref _span[index]; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Append(T item) + { + int pos = _pos; + if (pos >= _span.Length) + Grow(); + + _span[pos] = item; + _pos = pos + 1; + } + + public ReadOnlySpan AsSpan() + { + return _span.Slice(0, _pos); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_arrayFromPool != null) + { + ArrayPool.Shared.Return(_arrayFromPool); + _arrayFromPool = null; + } + } + + private void Grow() + { + T[] array = ArrayPool.Shared.Rent(_span.Length * 2); + + bool success = _span.TryCopyTo(array); + Debug.Assert(success); + + T[] toReturn = _arrayFromPool; + _span = _arrayFromPool = array; + if (toReturn != null) + { + ArrayPool.Shared.Return(toReturn); + } + } + } +} diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Convert.cs.REMOVED.git-id b/external/corert/src/System.Private.CoreLib/shared/System/Convert.cs.REMOVED.git-id index 72b7d96440..a7b7b7cce8 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Convert.cs.REMOVED.git-id +++ b/external/corert/src/System.Private.CoreLib/shared/System/Convert.cs.REMOVED.git-id @@ -1 +1 @@ -488ea773387e0c95bf1e04d9917242c88b9dcbbe \ No newline at end of file +756bf17fc55349ef4fae1a22d3ed7414f4f1e484 \ No newline at end of file diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Diagnostics/Debug.Unix.cs b/external/corert/src/System.Private.CoreLib/shared/System/Diagnostics/Debug.Unix.cs index 495f2f713c..627ea4ab7e 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Diagnostics/Debug.Unix.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Diagnostics/Debug.Unix.cs @@ -10,7 +10,7 @@ namespace System.Diagnostics { private static readonly bool s_shouldWriteToStdErr = Environment.GetEnvironmentVariable("COMPlus_DebugWriteToStdErr") == "1"; - private static void ShowAssertDialog(string stackTrace, string message, string detailMessage) + private static void ShowDialog(string stackTrace, string message, string detailMessage, string errorSource) { if (Debugger.IsAttached) { @@ -21,8 +21,20 @@ namespace System.Diagnostics // In Core, we do not show a dialog. // Fail in order to avoid anyone catching an exception and masking // an assert failure. - var ex = new DebugAssertException(message, detailMessage, stackTrace); - Environment.FailFast(ex.Message, ex); + DebugAssertException ex; + if (message == String.Empty) + { + ex = new DebugAssertException(stackTrace); + } + else if (detailMessage == String.Empty) + { + ex = new DebugAssertException(message, stackTrace); + } + else + { + ex = new DebugAssertException(message, detailMessage, stackTrace); + } + Environment.FailFast(ex.Message, ex, errorSource); } } diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Diagnostics/Debug.cs b/external/corert/src/System.Private.CoreLib/shared/System/Diagnostics/Debug.cs index 4efb4432a0..45f31928d2 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Diagnostics/Debug.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Diagnostics/Debug.cs @@ -4,6 +4,8 @@ // Do not remove this, it is needed to retain calls to these conditional methods in release builds #define DEBUG +using System.Diagnostics.Contracts; +using System.Runtime.CompilerServices; #if MONO namespace System.Diagnostics.Private @@ -98,18 +100,34 @@ namespace System.Diagnostics if (!condition) { string stackTrace; - try { - stackTrace = Internal.Runtime.Augments.EnvironmentAugments.StackTrace; + stackTrace = new StackTrace(0, true).ToString(System.Diagnostics.StackTrace.TraceFormat.Normal); } catch { stackTrace = ""; } - WriteLine(FormatAssert(stackTrace, message, detailMessage)); - s_ShowAssertDialog(stackTrace, message, detailMessage); + s_ShowDialog(stackTrace, message, detailMessage, "Assertion Failed"); + } + } + + internal static void ContractFailure(bool condition, string message, string detailMessage, string failureKindMessage) + { + if (!condition) + { + string stackTrace; + try + { + stackTrace = new StackTrace(2, true).ToString(System.Diagnostics.StackTrace.TraceFormat.Normal); + } + catch + { + stackTrace = ""; + } + WriteLine(FormatAssert(stackTrace, message, detailMessage)); + s_ShowDialog(stackTrace, message, detailMessage, SR.GetResourceString(failureKindMessage)); } } @@ -315,14 +333,25 @@ namespace System.Diagnostics private sealed class DebugAssertException : Exception { + internal DebugAssertException(string stackTrace) : + base(Environment.NewLine + stackTrace) + { + } + + internal DebugAssertException(string message, string stackTrace) : + base(message + Environment.NewLine + Environment.NewLine + stackTrace) + { + } + internal DebugAssertException(string message, string detailMessage, string stackTrace) : - base(message + Environment.NewLine + detailMessage + Environment.NewLine + stackTrace) + base(message + Environment.NewLine + detailMessage + Environment.NewLine + Environment.NewLine + stackTrace) { } } // internal and not readonly so that the tests can swap this out. - internal static Action s_ShowAssertDialog = ShowAssertDialog; + internal static Action s_ShowDialog = ShowDialog; + internal static Action s_WriteCore = WriteCore; } } diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventProvider.cs b/external/corert/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventProvider.cs index 64c2491769..fafdd7c6da 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventProvider.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventProvider.cs @@ -182,7 +182,7 @@ namespace System.Diagnostics.Tracing // // - // check if the object has been allready disposed + // check if the object has been already disposed // if (m_disposed) return; @@ -259,12 +259,6 @@ namespace System.Diagnostics.Tracing m_anyKeywordMask = anyKeyword; m_allKeywordMask = allKeyword; - // ES_SESSION_INFO is a marker for additional places we #ifdeffed out to remove - // references to EnumerateTraceGuidsEx. This symbol is actually not used because - // today we use FEATURE_ACTIVITYSAMPLING to determine if this code is there or not. - // However we put it in the #if so that we don't lose the fact that this feature - // switch is at least partially independent of FEATURE_ACTIVITYSAMPLING - List> sessionsChanged = GetSessions(); foreach (var session in sessionsChanged) { @@ -567,7 +561,7 @@ namespace System.Diagnostics.Tracing if (filterData == null) { #if (!ES_BUILD_PCL && !ES_BUILD_PN && PLATFORM_WINDOWS) - string regKey = @"\Microsoft\Windows\CurrentVersion\Winevt\Publishers\{" + m_providerName + "}"; + string regKey = @"\Microsoft\Windows\CurrentVersion\Winevt\Publishers\{" + m_providerId + "}"; if (System.Runtime.InteropServices.Marshal.SizeOf(typeof(IntPtr)) == 8) regKey = @"HKEY_LOCAL_MACHINE\Software" + @"\Wow6432Node" + regKey; else @@ -964,6 +958,8 @@ namespace System.Diagnostics.Tracing List refObjPosition = new List(s_etwAPIMaxRefObjCount); List dataRefObj = new List(s_etwAPIMaxRefObjCount); EventData* userData = stackalloc EventData[2 * argCount]; + for (int i = 0; i < 2 * argCount; i++) + userData[i] = default(EventData); EventData* userDataPtr = (EventData*)userData; byte* dataBuffer = stackalloc byte[s_basicTypeAllocationBufferSize * 2 * argCount]; // Assume 16 chars for non-string argument byte* currentBuffer = dataBuffer; diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventSource.cs.REMOVED.git-id b/external/corert/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventSource.cs.REMOVED.git-id index 4f26205c3c..73a2b101ef 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventSource.cs.REMOVED.git-id +++ b/external/corert/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventSource.cs.REMOVED.git-id @@ -1 +1 @@ -f6d48998436a4b293130436942ccb5891b740605 \ No newline at end of file +40d39ced76cfdabda2badc2e397fd02dab3e243d \ No newline at end of file diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/SimpleTypeInfos.cs b/external/corert/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/SimpleTypeInfos.cs index 901a0ed1a2..9b58d82519 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/SimpleTypeInfos.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/SimpleTypeInfos.cs @@ -187,8 +187,14 @@ namespace System.Diagnostics.Tracing public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value) { - var ticks = value.ScalarValue.AsDateTime.Ticks; - collector.AddScalar(ticks < 504911232000000000 ? 0 : ticks - 504911232000000000); + DateTime dateTime = value.ScalarValue.AsDateTime; + const long UTCMinTicks = 504911232000000000; + long dateTimeTicks = 0; + // We cannot translate dates sooner than 1/1/1601 in UTC. + // To avoid getting an ArgumentOutOfRangeException we compare with 1/1/1601 DateTime ticks + if (dateTime.Ticks > UTCMinTicks) + dateTimeTicks = dateTime.ToFileTimeUtc(); + collector.AddScalar(dateTimeTicks); } } diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventSource.cs b/external/corert/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventSource.cs index bf29d71844..4348df7d64 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventSource.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventSource.cs @@ -7,10 +7,6 @@ #if PLATFORM_WINDOWS #define FEATURE_MANAGED_ETW - -#if !ES_BUILD_STANDALONE -#define FEATURE_ACTIVITYSAMPLING -#endif #endif // PLATFORM_WINDOWS #if ES_BUILD_STANDALONE @@ -438,6 +434,8 @@ namespace System.Diagnostics.Tracing var pinCount = eventTypes.pinCount; var scratch = stackalloc byte[eventTypes.scratchSize]; var descriptors = stackalloc EventData[eventTypes.dataCount + 3]; + for(int i = 0; i < eventTypes.dataCount + 3; i++) + descriptors[i] = default(EventData); var pins = stackalloc GCHandle[pinCount]; for (int i = 0; i < pinCount; i++) @@ -542,7 +540,10 @@ namespace System.Diagnostics.Tracing // We make a descriptor for each EventData, and because we morph strings to counted strings // we may have 2 for each arg, so we allocate enough for this. - var descriptors = stackalloc EventData[eventTypes.dataCount + eventTypes.typeInfos.Length * 2 + 3]; + var descriptorsLength = eventTypes.dataCount + eventTypes.typeInfos.Length * 2 + 3; + var descriptors = stackalloc EventData[descriptorsLength]; + for(int i = 0; i < descriptorsLength; i++) + descriptors[i] = default(EventData); fixed (byte* pMetadata0 = this.providerMetadata, @@ -618,6 +619,8 @@ namespace System.Diagnostics.Tracing var pinCount = eventTypes.pinCount; var scratch = stackalloc byte[eventTypes.scratchSize]; var descriptors = stackalloc EventData[eventTypes.dataCount + 3]; + for(int i=0; i(ref m_value); + + // Optimized check for IsNan() || IsZero() + if (((bits - 1) & 0x7FFFFFFFFFFFFFFF) >= 0x7FF0000000000000) { - // Ensure that 0 and -0 have the same hash code - return 0; + // Ensure that all NaNs and both zeros have the same hash code + bits &= 0x7FF0000000000000; } - long value = *(long*)(&d); - return unchecked((int)value) ^ ((int)(value >> 32)); + + return unchecked((int)bits) ^ ((int)(bits >> 32)); } public override String ToString() @@ -340,7 +345,7 @@ namespace System bool success = Number.TryParseDouble(s, style, info, out result); if (!success) { - ReadOnlySpan sTrim = StringSpanHelpers.Trim(s); + ReadOnlySpan sTrim = s.Trim(); if (StringSpanHelpers.Equals(sTrim, info.PositiveInfinitySymbol)) { result = PositiveInfinity; diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/CalendarData.Unix.cs b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/CalendarData.Unix.cs index 3a8029d9a0..17d6ed7a01 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/CalendarData.Unix.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/CalendarData.Unix.cs @@ -4,9 +4,9 @@ using System.Collections.Generic; using System.Diagnostics; -using System.Runtime.InteropServices; using System.Security; using System.Text; +using Internal.Runtime.CompilerServices; namespace System.Globalization { @@ -45,10 +45,27 @@ namespace System.Globalization result &= EnumCalendarInfo(localeName, calendarId, CalendarDataType.DayNames, out this.saDayNames); result &= EnumCalendarInfo(localeName, calendarId, CalendarDataType.AbbrevDayNames, out this.saAbbrevDayNames); result &= EnumCalendarInfo(localeName, calendarId, CalendarDataType.SuperShortDayNames, out this.saSuperShortDayNames); - result &= EnumMonthNames(localeName, calendarId, CalendarDataType.MonthNames, out this.saMonthNames); - result &= EnumMonthNames(localeName, calendarId, CalendarDataType.AbbrevMonthNames, out this.saAbbrevMonthNames); - result &= EnumMonthNames(localeName, calendarId, CalendarDataType.MonthGenitiveNames, out this.saMonthGenitiveNames); - result &= EnumMonthNames(localeName, calendarId, CalendarDataType.AbbrevMonthGenitiveNames, out this.saAbbrevMonthGenitiveNames); + + string leapHebrewMonthName = null; + result &= EnumMonthNames(localeName, calendarId, CalendarDataType.MonthNames, out this.saMonthNames, ref leapHebrewMonthName); + if (leapHebrewMonthName != null) + { + // In Hebrew calendar, get the leap month name Adar II and override the non-leap month 7 + Debug.Assert(calendarId == CalendarId.HEBREW && saMonthNames.Length == 13); + saLeapYearMonthNames = (string[]) saMonthNames.Clone(); + saLeapYearMonthNames[6] = leapHebrewMonthName; + + // The returned data from ICU has 6th month name as 'Adar I' and 7th month name as 'Adar' + // We need to adjust that in the list used with non-leap year to have 6th month as 'Adar' and 7th month as 'Adar II' + // note that when formatting non-leap year dates, 7th month shouldn't get used at all. + saMonthNames[5] = saMonthNames[6]; + saMonthNames[6] = leapHebrewMonthName; + + } + result &= EnumMonthNames(localeName, calendarId, CalendarDataType.AbbrevMonthNames, out this.saAbbrevMonthNames, ref leapHebrewMonthName); + result &= EnumMonthNames(localeName, calendarId, CalendarDataType.MonthGenitiveNames, out this.saMonthGenitiveNames, ref leapHebrewMonthName); + result &= EnumMonthNames(localeName, calendarId, CalendarDataType.AbbrevMonthGenitiveNames, out this.saAbbrevMonthGenitiveNames, ref leapHebrewMonthName); + result &= EnumEraNames(localeName, calendarId, CalendarDataType.EraNames, out this.saEraNames); result &= EnumEraNames(localeName, calendarId, CalendarDataType.AbbrevEraNames, out this.saAbbrevEraNames); @@ -68,7 +85,7 @@ namespace System.Globalization Debug.Assert(!GlobalizationMode.Invariant); // NOTE: there are no 'user overrides' on Linux - int count = Interop.GlobalizationInterop.GetCalendars(localeName, calendars, calendars.Length); + int count = Interop.Globalization.GetCalendars(localeName, calendars, calendars.Length); // ensure there is at least 1 calendar returned if (count == 0 && calendars.Length > 0) @@ -93,7 +110,7 @@ namespace System.Globalization return Interop.CallStringMethod( (locale, calId, type, stringBuilder) => - Interop.GlobalizationInterop.GetCalendarInfo( + Interop.Globalization.GetCalendarInfo( locale, calId, type, @@ -109,9 +126,10 @@ namespace System.Globalization { datePatterns = null; - CallbackContext callbackContext = new CallbackContext(); + EnumCalendarsData callbackContext = new EnumCalendarsData(); + callbackContext.Results = new List(); callbackContext.DisallowDuplicates = true; - bool result = EnumCalendarInfo(localeName, calendarId, dataType, callbackContext); + bool result = EnumCalendarInfo(localeName, calendarId, dataType, ref callbackContext); if (result) { List datePatternsList = callbackContext.Results; @@ -240,12 +258,13 @@ namespace System.Globalization return index - startIndex; } - private static bool EnumMonthNames(string localeName, CalendarId calendarId, CalendarDataType dataType, out string[] monthNames) + private static bool EnumMonthNames(string localeName, CalendarId calendarId, CalendarDataType dataType, out string[] monthNames, ref string leapHebrewMonthName) { monthNames = null; - CallbackContext callbackContext = new CallbackContext(); - bool result = EnumCalendarInfo(localeName, calendarId, dataType, callbackContext); + EnumCalendarsData callbackContext = new EnumCalendarsData(); + callbackContext.Results = new List(); + bool result = EnumCalendarInfo(localeName, calendarId, dataType, ref callbackContext); if (result) { // the month-name arrays are expected to have 13 elements. If ICU only returns 12, add an @@ -255,6 +274,17 @@ namespace System.Globalization callbackContext.Results.Add(string.Empty); } + if (callbackContext.Results.Count > 13) + { + Debug.Assert(calendarId == CalendarId.HEBREW && callbackContext.Results.Count == 14); + + if (calendarId == CalendarId.HEBREW) + { + leapHebrewMonthName = callbackContext.Results[13]; + } + callbackContext.Results.RemoveRange(13, callbackContext.Results.Count - 13); + } + monthNames = callbackContext.Results.ToArray(); } @@ -280,8 +310,9 @@ namespace System.Globalization { calendarData = null; - CallbackContext callbackContext = new CallbackContext(); - bool result = EnumCalendarInfo(localeName, calendarId, dataType, callbackContext); + EnumCalendarsData callbackContext = new EnumCalendarsData(); + callbackContext.Results = new List(); + bool result = EnumCalendarInfo(localeName, calendarId, dataType, ref callbackContext); if (result) { calendarData = callbackContext.Results.ToArray(); @@ -290,24 +321,16 @@ namespace System.Globalization return result; } - private static bool EnumCalendarInfo(string localeName, CalendarId calendarId, CalendarDataType dataType, CallbackContext callbackContext) + private static unsafe bool EnumCalendarInfo(string localeName, CalendarId calendarId, CalendarDataType dataType, ref EnumCalendarsData callbackContext) { - GCHandle context = GCHandle.Alloc(callbackContext); - try - { - return Interop.GlobalizationInterop.EnumCalendarInfo(EnumCalendarInfoCallback, localeName, calendarId, dataType, (IntPtr)context); - } - finally - { - context.Free(); - } + return Interop.Globalization.EnumCalendarInfo(EnumCalendarInfoCallback, localeName, calendarId, dataType, (IntPtr)Unsafe.AsPointer(ref callbackContext)); } - private static void EnumCalendarInfoCallback(string calendarString, IntPtr context) + private static unsafe void EnumCalendarInfoCallback(string calendarString, IntPtr context) { try { - CallbackContext callbackContext = (CallbackContext)((GCHandle)context).Target; + ref EnumCalendarsData callbackContext = ref Unsafe.As(ref *(byte*)context); if (callbackContext.DisallowDuplicates) { @@ -331,17 +354,10 @@ namespace System.Globalization } } - private class CallbackContext + private struct EnumCalendarsData { - private List _results = new List(); - - public CallbackContext() - { - } - - public List Results { get { return _results; } } - - public bool DisallowDuplicates { get; set; } + public List Results; + public bool DisallowDuplicates; } } } diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/CalendarData.Windows.cs b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/CalendarData.Windows.cs index a67761ac6a..03f9088d62 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/CalendarData.Windows.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/CalendarData.Windows.cs @@ -274,7 +274,7 @@ namespace System.Globalization } // Context for EnumCalendarInfoExEx callback. - private class EnumData + private struct EnumData { public string userOverride; public List strings; @@ -427,7 +427,7 @@ namespace System.Globalization // // struct to help our calendar data enumaration callback // - private class EnumCalendarsData + private struct EnumCalendarsData { public int userOverride; // user override value (if found) public List calendars; // list of calendars found so far diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/CharUnicodeInfo.cs b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/CharUnicodeInfo.cs index 3881272287..0cd8429bbc 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/CharUnicodeInfo.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/CharUnicodeInfo.cs @@ -276,7 +276,7 @@ namespace System.Globalization public static UnicodeCategory GetUnicodeCategory(char ch) { - return (InternalGetUnicodeCategory(ch)); + return (GetUnicodeCategory((int)ch)); } public static UnicodeCategory GetUnicodeCategory(String s, int index) @@ -290,9 +290,9 @@ namespace System.Globalization return InternalGetUnicodeCategory(s, index); } - internal static unsafe UnicodeCategory InternalGetUnicodeCategory(int ch) + public static UnicodeCategory GetUnicodeCategory(int codePoint) { - return ((UnicodeCategory)InternalGetCategoryValue(ch, UNICODE_CATEGORY_OFFSET)); + return ((UnicodeCategory)InternalGetCategoryValue(codePoint, UNICODE_CATEGORY_OFFSET)); } @@ -352,7 +352,7 @@ namespace System.Globalization Debug.Assert(value != null, "value can not be null"); Debug.Assert(index < value.Length, "index < value.Length"); - return (InternalGetUnicodeCategory(InternalConvertToUtf32(value, index))); + return (GetUnicodeCategory(InternalConvertToUtf32(value, index))); } internal static BidiCategory GetBidiCategory(String s, int index) @@ -381,7 +381,7 @@ namespace System.Globalization Debug.Assert(str.Length > 0, "str.Length > 0"); ; Debug.Assert(index >= 0 && index < str.Length, "index >= 0 && index < str.Length"); - return (InternalGetUnicodeCategory(InternalConvertToUtf32(str, index, out charLength))); + return (GetUnicodeCategory(InternalConvertToUtf32(str, index, out charLength))); } internal static bool IsCombiningCategory(UnicodeCategory uc) diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.Invariant.cs b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.Invariant.cs index 13725bcc51..29e4f53212 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.Invariant.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.Invariant.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Runtime.InteropServices; namespace System.Globalization { @@ -26,6 +27,18 @@ namespace System.Globalization } } + internal static unsafe int InvariantIndexOf(ReadOnlySpan source, ReadOnlySpan value, bool ignoreCase) + { + Debug.Assert(source.Length != 0); + Debug.Assert(value.Length != 0); + + fixed (char* pSource = &MemoryMarshal.GetReference(source)) + fixed (char* pValue = &MemoryMarshal.GetReference(value)) + { + return InvariantFindString(pSource, source.Length, pValue, value.Length, ignoreCase, start: true); + } + } + internal static unsafe int InvariantLastIndexOf(string source, string value, int startIndex, int count, bool ignoreCase) { Debug.Assert(source != null); diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.cs b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.cs index e088a82ded..c369c816b0 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.cs @@ -57,6 +57,9 @@ namespace System.Globalization ~(CompareOptions.IgnoreCase | CompareOptions.IgnoreSymbols | CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreWidth | CompareOptions.IgnoreKanaType | CompareOptions.StringSort); + // Cache the invariant CompareInfo + internal static readonly CompareInfo Invariant = CultureInfo.InvariantCulture.CompareInfo; + // // CompareInfos have an interesting identity. They are attached to the locale that created them, // ie: en-US would have an en-US sort. For haw-US (custom), then we serialize it as haw-US. @@ -91,7 +94,7 @@ namespace System.Globalization ** culture the ID of the culture ** assembly the assembly which contains the sorting table. **Exceptions: - ** ArugmentNullException when the assembly is null + ** ArgumentNullException when the assembly is null ** ArgumentException if culture is invalid. ============================================================================*/ // Assembly constructor should be deprecated, we don't act on the assembly information any more @@ -118,7 +121,7 @@ namespace System.Globalization ** name the name of the culture ** assembly the assembly which contains the sorting table. **Exceptions: - ** ArugmentNullException when the assembly is null + ** ArgumentNullException when the assembly is null ** ArgumentException if name is invalid. ============================================================================*/ // Assembly constructor should be deprecated, we don't act on the assembly information any more @@ -295,7 +298,7 @@ namespace System.Globalization return (Compare(string1, string2, CompareOptions.None)); } - public unsafe virtual int Compare(string string1, string string2, CompareOptions options) + public virtual int Compare(string string1, string string2, CompareOptions options) { if (options == CompareOptions.OrdinalIgnoreCase) { @@ -341,17 +344,17 @@ namespace System.Globalization return String.CompareOrdinal(string1, string2); } - return CompareString(string1.AsReadOnlySpan(), string2.AsReadOnlySpan(), options); + return CompareString(string1.AsSpan(), string2.AsSpan(), options); } // TODO https://github.com/dotnet/coreclr/issues/13827: // This method shouldn't be necessary, as we should be able to just use the overload // that takes two spans. But due to this issue, that's adding significant overhead. - internal unsafe int Compare(ReadOnlySpan string1, string string2, CompareOptions options) + internal int Compare(ReadOnlySpan string1, string string2, CompareOptions options) { if (options == CompareOptions.OrdinalIgnoreCase) { - return CompareOrdinalIgnoreCase(string1, string2.AsReadOnlySpan()); + return CompareOrdinalIgnoreCase(string1, string2.AsSpan()); } // Verify the options before we do any real comparison. @@ -362,7 +365,7 @@ namespace System.Globalization throw new ArgumentException(SR.Argument_CompareOptionOrdinal, nameof(options)); } - return string.CompareOrdinal(string1, string2.AsReadOnlySpan()); + return string.CompareOrdinal(string1, string2.AsSpan()); } if ((options & ValidCompareMaskOffFlags) != 0) @@ -379,15 +382,15 @@ namespace System.Globalization if (_invariantMode) { return (options & CompareOptions.IgnoreCase) != 0 ? - CompareOrdinalIgnoreCase(string1, string2.AsReadOnlySpan()) : - string.CompareOrdinal(string1, string2.AsReadOnlySpan()); + CompareOrdinalIgnoreCase(string1, string2.AsSpan()) : + string.CompareOrdinal(string1, string2.AsSpan()); } return CompareString(string1, string2, options); } // TODO https://github.com/dotnet/corefx/issues/21395: Expose this publicly? - internal unsafe virtual int Compare(ReadOnlySpan string1, ReadOnlySpan string2, CompareOptions options) + internal virtual int Compare(ReadOnlySpan string1, ReadOnlySpan string2, CompareOptions options) { if (options == CompareOptions.OrdinalIgnoreCase) { @@ -433,7 +436,7 @@ namespace System.Globalization //////////////////////////////////////////////////////////////////////// - public unsafe virtual int Compare(string string1, int offset1, int length1, string string2, int offset2, int length2) + public virtual int Compare(string string1, int offset1, int length1, string string2, int offset2, int length2) { return Compare(string1, offset1, length1, string2, offset2, length2, 0); } @@ -523,8 +526,8 @@ namespace System.Globalization } return CompareString( - string1.AsReadOnlySpan().Slice(offset1, length1), - string2.AsReadOnlySpan().Slice(offset2, length2), + string1.AsSpan().Slice(offset1, length1), + string2.AsSpan().Slice(offset2, length2), options); } @@ -544,11 +547,11 @@ namespace System.Globalization // it assumes the strings are Ascii string till we hit non Ascii character in strA or strB and then we continue the comparison by // calling the OS. // - internal static unsafe int CompareOrdinalIgnoreCase(string strA, int indexA, int lengthA, string strB, int indexB, int lengthB) + internal static int CompareOrdinalIgnoreCase(string strA, int indexA, int lengthA, string strB, int indexB, int lengthB) { Debug.Assert(indexA + lengthA <= strA.Length); Debug.Assert(indexB + lengthB <= strB.Length); - return CompareOrdinalIgnoreCase(strA.AsReadOnlySpan().Slice(indexA, lengthA), strB.AsReadOnlySpan().Slice(indexB, lengthB)); + return CompareOrdinalIgnoreCase(strA.AsSpan().Slice(indexA, lengthA), strB.AsSpan().Slice(indexB, lengthB)); } internal static unsafe int CompareOrdinalIgnoreCase(ReadOnlySpan strA, ReadOnlySpan strB) @@ -563,7 +566,7 @@ namespace System.Globalization char* b = bp; // in InvariantMode we support all range and not only the ascii characters. - char maxChar = (char) (GlobalizationMode.Invariant ? 0xFFFF : 0x80); + char maxChar = (char) (GlobalizationMode.Invariant ? 0xFFFF : 0x7F); while (length != 0 && (*a <= maxChar) && (*b <= maxChar)) { @@ -650,6 +653,17 @@ namespace System.Globalization return StartsWith(source, prefix, options); } + internal bool IsPrefix(ReadOnlySpan source, ReadOnlySpan prefix, CompareOptions options) + { + Debug.Assert(prefix.Length != 0); + Debug.Assert(source.Length != 0); + Debug.Assert((options & ValidIndexMaskOffFlags) == 0); + Debug.Assert(!_invariantMode); + Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); + + return StartsWith(source, prefix, options); + } + public virtual bool IsPrefix(string source, string prefix) { return (IsPrefix(source, prefix, 0)); @@ -704,6 +718,17 @@ namespace System.Globalization return EndsWith(source, suffix, options); } + internal bool IsSuffix(ReadOnlySpan source, ReadOnlySpan suffix, CompareOptions options) + { + Debug.Assert(suffix.Length != 0); + Debug.Assert(source.Length != 0); + Debug.Assert((options & ValidIndexMaskOffFlags) == 0); + Debug.Assert(!_invariantMode); + Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); + + return EndsWith(source, suffix, options); + } + public virtual bool IsSuffix(string source, string suffix) { @@ -816,6 +841,11 @@ namespace System.Globalization if (count < 0 || startIndex > source.Length - count) throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count); + if (source.Length == 0) + { + return -1; + } + if (options == CompareOptions.OrdinalIgnoreCase) { return source.IndexOf(value.ToString(), startIndex, count, StringComparison.OrdinalIgnoreCase); @@ -825,7 +855,7 @@ namespace System.Globalization // Ordinal can't be selected with other flags if ((options & ValidIndexMaskOffFlags) != 0 && (options != CompareOptions.Ordinal)) throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); - + if (_invariantMode) return IndexOfOrdinal(source, new string(value, 1), startIndex, count, ignoreCase: (options & (CompareOptions.IgnoreCase | CompareOptions.OrdinalIgnoreCase)) != 0); @@ -880,6 +910,18 @@ namespace System.Globalization return IndexOfCore(source, value, startIndex, count, options, null); } + internal virtual int IndexOfOrdinal(ReadOnlySpan source, ReadOnlySpan value, bool ignoreCase) + { + Debug.Assert(!_invariantMode); + return IndexOfOrdinalCore(source, value, ignoreCase); + } + + internal unsafe virtual int IndexOf(ReadOnlySpan source, ReadOnlySpan value, CompareOptions options) + { + Debug.Assert(!_invariantMode); + return IndexOfCore(source, value, options, null); + } + // The following IndexOf overload is mainly used by String.Replace. This overload assumes the parameters are already validated // and the caller is passing a valid matchLengthPtr pointer. internal unsafe int IndexOf(string source, string value, int startIndex, int count, CompareOptions options, int* matchLengthPtr) @@ -1256,7 +1298,7 @@ namespace System.Globalization } // - // GetHashCodeOfString does more parameters validation. basically will throw when + // GetHashCodeOfString does more parameters validation. basically will throw when // having Ordinal, OrdinalIgnoreCase and StringSort // diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/CultureData.Unix.cs b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/CultureData.Unix.cs index 3b4b60fc8a..3fce527929 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/CultureData.Unix.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/CultureData.Unix.cs @@ -33,7 +33,7 @@ namespace System.Globalization string realNameBuffer = _sRealName; // Basic validation - if (realNameBuffer.Contains("@")) + if (realNameBuffer.Contains('@')) { return false; // don't allow ICU variants to come in directly } @@ -43,7 +43,7 @@ namespace System.Globalization if (index > 0) { if (index >= (realNameBuffer.Length - 1) // must have characters after _ - || realNameBuffer.Substring(index + 1).Contains("_")) // only one _ allowed + || realNameBuffer.Substring(index + 1).Contains('_')) // only one _ allowed { return false; // fail } @@ -91,7 +91,7 @@ namespace System.Globalization { // Get the locale name from ICU StringBuilder sb = StringBuilderCache.Acquire(ICU_ULOC_FULLNAME_CAPACITY); - if (!Interop.GlobalizationInterop.GetLocaleName(localeName, sb, sb.Capacity)) + if (!Interop.Globalization.GetLocaleName(localeName, sb, sb.Capacity)) { StringBuilderCache.Release(sb); windowsName = null; @@ -107,7 +107,7 @@ namespace System.Globalization { // Get the default (system) locale name from ICU StringBuilder sb = StringBuilderCache.Acquire(ICU_ULOC_FULLNAME_CAPACITY); - if (!Interop.GlobalizationInterop.GetDefaultLocaleName(sb, sb.Capacity)) + if (!Interop.Globalization.GetDefaultLocaleName(sb, sb.Capacity)) { StringBuilderCache.Release(sb); windowsName = null; @@ -143,7 +143,7 @@ namespace System.Globalization StringBuilder sb = StringBuilderCache.Acquire(ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY); - bool result = Interop.GlobalizationInterop.GetLocaleInfoString(localeName, (uint)type, sb, sb.Capacity); + bool result = Interop.Globalization.GetLocaleInfoString(localeName, (uint)type, sb, sb.Capacity); if (!result) { // Failed, just use empty string @@ -169,7 +169,7 @@ namespace System.Globalization int value = 0; - bool result = Interop.GlobalizationInterop.GetLocaleInfoInt(_sWindowsName, (uint)type, ref value); + bool result = Interop.Globalization.GetLocaleInfoInt(_sWindowsName, (uint)type, ref value); if (!result) { // Failed, just use 0 @@ -185,7 +185,7 @@ namespace System.Globalization int primaryGroupingSize = 0; int secondaryGroupingSize = 0; - bool result = Interop.GlobalizationInterop.GetLocaleInfoGroupingSizes(_sWindowsName, (uint)type, ref primaryGroupingSize, ref secondaryGroupingSize); + bool result = Interop.Globalization.GetLocaleInfoGroupingSizes(_sWindowsName, (uint)type, ref primaryGroupingSize, ref secondaryGroupingSize); if (!result) { Debug.Fail("[CultureData.GetLocaleInfo(LocaleGroupingData type)] failed"); @@ -210,7 +210,7 @@ namespace System.Globalization StringBuilder sb = StringBuilderCache.Acquire(ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY); - bool result = Interop.GlobalizationInterop.GetLocaleTimeFormat(_sWindowsName, shortFormat, sb, sb.Capacity); + bool result = Interop.Globalization.GetLocaleTimeFormat(_sWindowsName, shortFormat, sb, sb.Capacity); if (!result) { // Failed, just use empty string @@ -365,7 +365,7 @@ namespace System.Globalization return Array.Empty(); } - int bufferLength = Interop.GlobalizationInterop.GetLocales(null, 0); + int bufferLength = Interop.Globalization.GetLocales(null, 0); if (bufferLength <= 0) { return Array.Empty(); @@ -373,7 +373,7 @@ namespace System.Globalization Char [] chars = new Char[bufferLength]; - bufferLength = Interop.GlobalizationInterop.GetLocales(chars, bufferLength); + bufferLength = Interop.Globalization.GetLocales(chars, bufferLength); if (bufferLength <= 0) { return Array.Empty(); diff --git a/external/corert/src/System.Private.CoreLib/src/System/Globalization/CultureData.Windows.cs b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/CultureData.Windows.cs similarity index 92% rename from external/corert/src/System.Private.CoreLib/src/System/Globalization/CultureData.Windows.cs rename to external/corert/src/System.Private.CoreLib/shared/System/Globalization/CultureData.Windows.cs index 373fd26a89..393f983bba 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Globalization/CultureData.Windows.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/CultureData.Windows.cs @@ -7,7 +7,6 @@ using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; - using Internal.Runtime.CompilerServices; #if ENABLE_WINRT @@ -59,7 +58,7 @@ namespace System.Globalization /// private unsafe bool InitCultureData() { - const int LOCALE_NAME_MAX_LENGTH = 85; + Debug.Assert(!GlobalizationMode.Invariant); const uint LOCALE_ILANGUAGE = 0x00000001; const uint LOCALE_INEUTRAL = 0x00000071; @@ -80,7 +79,7 @@ namespace System.Globalization // It worked, note that the name is the locale name, so use that (even for neutrals) // We need to clean up our "real" name, which should look like the windows name right now // so overwrite the input with the cleaned up name - _sRealName = new String(pBuffer, 0, result - 1); + _sRealName = new string(pBuffer, 0, result - 1); realNameBuffer = _sRealName; // Check for neutrality, don't expect to fail @@ -97,8 +96,8 @@ namespace System.Globalization // Note: Parents will be set dynamically - // Start by assuming the windows name'll be the same as the specific name since windows knows - // about specifics on all versions. Only for downlevel Neutral locales does this have to change. + // Start by assuming the windows name will be the same as the specific name since windows knows + // about specifics on all versions. Only for downlevel Neutral locales does this have to change. _sWindowsName = realNameBuffer; // Neutrals and non-neutrals are slightly different @@ -120,7 +119,7 @@ namespace System.Globalization } // We found a locale name, so use it. // In vista this should look like a sort name (de-DE_phoneb) or a specific culture (en-US) and be in the "pretty" form - _sSpecificCulture = new String(pBuffer, 0, result - 1); + _sSpecificCulture = new string(pBuffer, 0, result - 1); } else { @@ -163,8 +162,8 @@ namespace System.Globalization } // Wrappers around the GetLocaleInfoEx APIs which handle marshalling the returned - // data as either and Int or String. - internal static unsafe String GetLocaleInfoEx(String localeName, uint field) + // data as either and Int or string. + internal static unsafe string GetLocaleInfoEx(string localeName, uint field) { // REVIEW: Determine the maximum size for the buffer const int BUFFER_SIZE = 530; @@ -173,22 +172,22 @@ namespace System.Globalization int resultCode = GetLocaleInfoEx(localeName, field, pBuffer, BUFFER_SIZE); if (resultCode > 0) { - return new String(pBuffer); + return new string(pBuffer); } return null; } - internal static unsafe int GetLocaleInfoExInt(String localeName, uint field) + internal static unsafe int GetLocaleInfoExInt(string localeName, uint field) { const uint LOCALE_RETURN_NUMBER = 0x20000000; field |= LOCALE_RETURN_NUMBER; int value = 0; - GetLocaleInfoEx(localeName, field, (char*)&value, sizeof(int)); + GetLocaleInfoEx(localeName, field, (char*) &value, sizeof(int)); return value; } - internal static unsafe int GetLocaleInfoEx(string lpLocaleName, uint lcType, void* lpLCData, int cchData) + internal static unsafe int GetLocaleInfoEx(string lpLocaleName, uint lcType, char* lpLCData, int cchData) { Debug.Assert(!GlobalizationMode.Invariant); @@ -223,7 +222,7 @@ namespace System.Globalization // Ask OS for data, note that we presume it returns success, so we have to know that // sWindowsName is valid before calling. Debug.Assert(_sWindowsName != null, "[CultureData.DoGetLocaleInfoInt] Expected _sWindowsName to be populated by already"); - return GetLocaleInfoExInt(_sWindowsName, lctype); + return GetLocaleInfoExInt(_sWindowsName, lctype); } private int[] GetLocaleInfo(LocaleGroupingData type) @@ -250,28 +249,29 @@ namespace System.Globalization return ConvertFirstDayOfWeekMonToSun(result); } - private String[] GetTimeFormats() + private string[] GetTimeFormats() { // Note that this gets overrides for us all the time Debug.Assert(_sWindowsName != null, "[CultureData.DoEnumTimeFormats] Expected _sWindowsName to be populated by already"); - String[] result = ReescapeWin32Strings(nativeEnumTimeFormats(_sWindowsName, 0, UseUserOverride)); + string[] result = ReescapeWin32Strings(nativeEnumTimeFormats(_sWindowsName, 0, UseUserOverride)); return result; } - private String[] GetShortTimeFormats() + private string[] GetShortTimeFormats() { // Note that this gets overrides for us all the time Debug.Assert(_sWindowsName != null, "[CultureData.DoEnumShortTimeFormats] Expected _sWindowsName to be populated by already"); - String[] result = ReescapeWin32Strings(nativeEnumTimeFormats(_sWindowsName, TIME_NOSECONDS, UseUserOverride)); + string[] result = ReescapeWin32Strings(nativeEnumTimeFormats(_sWindowsName, TIME_NOSECONDS, UseUserOverride)); return result; } - // Enumerate all system cultures and then try to find out which culture has + // Enumerate all system cultures and then try to find out which culture has // region name match the requested region name - private static CultureData GetCultureDataFromRegionName(String regionName) + private static CultureData GetCultureDataFromRegionName(string regionName) { + Debug.Assert(!GlobalizationMode.Invariant); Debug.Assert(regionName != null); const uint LOCALE_SUPPLEMENTAL = 0x00000002; @@ -322,20 +322,14 @@ namespace System.Globalization #if ENABLE_WINRT return WinRTInterop.Callbacks.GetRegionDisplayName(isoCountryCode); #else - // Usually the UI culture shouldn't be different than what we got from WinRT except - // if DefaultThreadCurrentUICulture was set - CultureInfo ci; - - if (CultureInfo.DefaultThreadCurrentUICulture != null && - ((ci = GetUserDefaultCulture()) != null) && - !CultureInfo.DefaultThreadCurrentUICulture.Name.Equals(ci.Name)) - { - return SNATIVECOUNTRY; - } - else + // If the current UI culture matching the OS UI language, we'll get the display name from the OS. + // otherwise, we use the native name as we don't carry resources for the region display names anyway. + if (CultureInfo.CurrentUICulture.Name.Equals(CultureInfo.UserDefaultUICulture.Name)) { return GetLocaleInfo(LocaleStringData.LocalizedCountryName); } + + return SNATIVECOUNTRY; #endif // ENABLE_WINRT } @@ -365,7 +359,7 @@ namespace System.Globalization if (result == null) { // Failed, just use empty string - result = String.Empty; + result = string.Empty; } return result; @@ -385,7 +379,7 @@ namespace System.Globalization // // We don't build the stringbuilder unless we find something to change //////////////////////////////////////////////////////////////////////////// - internal static String ReescapeWin32String(String str) + internal static string ReescapeWin32String(string str) { // If we don't have data, then don't try anything if (str == null) @@ -451,7 +445,7 @@ namespace System.Globalization return result.ToString(); } - internal static String[] ReescapeWin32Strings(String[] array) + internal static string[] ReescapeWin32Strings(string[] array) { if (array != null) { @@ -467,7 +461,7 @@ namespace System.Globalization // If we get a group from windows, then its in 3;0 format with the 0 backwards // of how NLS+ uses it (ie: if the string has a 0, then the int[] shouldn't and vice versa) // EXCEPT in the case where the list only contains 0 in which NLS and NLS+ have the same meaning. - private static int[] ConvertWin32GroupString(String win32Str) + private static int[] ConvertWin32GroupString(string win32Str) { // None of these cases make any sense if (win32Str == null || win32Str.Length == 0) @@ -552,6 +546,7 @@ namespace System.Globalization } } + // EnumSystemLocaleEx callback. // [NativeCallable(CallingConvention = CallingConvention.StdCall)] private static unsafe Interop.BOOL EnumAllSystemLocalesProc(char* lpLocaleString, uint flags, void* contextHandle) { @@ -570,7 +565,7 @@ namespace System.Globalization // Context for EnumTimeFormatsEx callback. private struct EnumData { - public LowLevelList strings; + public List strings; } // EnumTimeFormatsEx callback itself. @@ -589,13 +584,13 @@ namespace System.Globalization } } - private static unsafe String[] nativeEnumTimeFormats(String localeName, uint dwFlags, bool useUserOverride) + private static unsafe string[] nativeEnumTimeFormats(string localeName, uint dwFlags, bool useUserOverride) { const uint LOCALE_SSHORTTIME = 0x00000079; const uint LOCALE_STIMEFORMAT = 0x00001003; EnumData data = new EnumData(); - data.strings = new LowLevelList(); + data.strings = new List(); // Now call the enumeration API. Work is done by our callback function Interop.Kernel32.EnumTimeFormatsEx(EnumTimeCallback, localeName, (uint)dwFlags, Unsafe.AsPointer(ref data)); @@ -648,7 +643,7 @@ namespace System.Globalization if (length > 0) { - return new String(pBuffer); + return new string(pBuffer); } return null; @@ -723,14 +718,14 @@ namespace System.Globalization } EnumData context = new EnumData(); - context.strings = new LowLevelList(); + context.strings = new List(); unsafe { Interop.Kernel32.EnumSystemLocalesEx(EnumAllSystemLocalesProc, flags, Unsafe.AsPointer(ref context), IntPtr.Zero); } - CultureInfo[] cultures = new CultureInfo[context.strings.Count]; + CultureInfo [] cultures = new CultureInfo[context.strings.Count]; for (int i = 0; i < cultures.Length; i++) { cultures[i] = new CultureInfo(context.strings[i]); @@ -759,16 +754,16 @@ namespace System.Globalization get { EnumData context = new EnumData(); - context.strings = new LowLevelList(); + context.strings = new List(); unsafe { Interop.Kernel32.EnumSystemLocalesEx(EnumAllSystemLocalesProc, Interop.Kernel32.LOCALE_REPLACEMENT, Unsafe.AsPointer(ref context), IntPtr.Zero); } - for (int i = 0; i < context.strings.Count; i++) + for (int i=0; i= 0 && nextChar != '%') { char nextCharChar = (char)nextChar; - StringBuilder origStringBuilder = FormatCustomized(dateTime, ReadOnlySpan.DangerousCreate(null, ref nextCharChar, 1), dtfi, offset, result); + StringBuilder origStringBuilder = FormatCustomized(dateTime, MemoryMarshal.CreateReadOnlySpan(ref nextCharChar, 1), dtfi, offset, result); Debug.Assert(ReferenceEquals(origStringBuilder, result)); tokenLen = 2; } diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/DateTimeFormatInfo.cs.REMOVED.git-id b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/DateTimeFormatInfo.cs.REMOVED.git-id index 86188236ad..4fa6f09a2e 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/DateTimeFormatInfo.cs.REMOVED.git-id +++ b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/DateTimeFormatInfo.cs.REMOVED.git-id @@ -1 +1 @@ -b6a4621508c3d6e89c5d852f98f883758ac459b2 \ No newline at end of file +faa0deac3d757d164a1195fb50966eb92a8af93b \ No newline at end of file diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/DateTimeFormatInfoScanner.cs b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/DateTimeFormatInfoScanner.cs index c38e7a26b8..d3c3aac84e 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/DateTimeFormatInfoScanner.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/DateTimeFormatInfoScanner.cs @@ -24,14 +24,6 @@ using System.Text; namespace System.Globalization { -#if CORECLR - using StringStringDictionary = Dictionary; - using StringList = List; -#else - using StringStringDictionary = LowLevelDictionary; - using StringList = LowLevelList; -#endif - // // from LocaleEx.txt header // @@ -121,17 +113,17 @@ namespace System.Globalization internal const String CJKSecondSuff = "\u79d2"; // The collection fo date words & postfix. - internal StringList m_dateWords = new StringList(); + internal List m_dateWords = new List(); // Hashtable for the known words. - private static volatile StringStringDictionary s_knownWords; + private static volatile Dictionary s_knownWords; - static StringStringDictionary KnownWords + static Dictionary KnownWords { get { if (s_knownWords == null) { - StringStringDictionary temp = new StringStringDictionary(); + Dictionary temp = new Dictionary(); // Add known words into the hash table. // Skip these special symbols. @@ -234,7 +226,7 @@ namespace System.Globalization { if (m_dateWords == null) { - m_dateWords = new StringList(); + m_dateWords = new List(); } if (formatPostfix == "MMMM") { @@ -380,7 +372,7 @@ namespace System.Globalization if (m_dateWords == null) { // Create the date word array. - m_dateWords = new StringList(); + m_dateWords = new List(); } // Add the ignorable symbol into the ArrayList. String temp = IgnorableSymbolChar + text; @@ -735,4 +727,3 @@ namespace System.Globalization } } } - diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/DateTimeParse.cs.REMOVED.git-id b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/DateTimeParse.cs.REMOVED.git-id index 4a1ad61c3f..22ef7ed746 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/DateTimeParse.cs.REMOVED.git-id +++ b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/DateTimeParse.cs.REMOVED.git-id @@ -1 +1 @@ -cbf90945c82ee66e157e3d872a92dc3dc4c2e4c6 \ No newline at end of file +5b285eb5df11142cbb449db54de9d03ef59ffd04 \ No newline at end of file diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/DateTimeStyles.cs b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/DateTimeStyles.cs index 79232ff199..bf68ac91d5 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/DateTimeStyles.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/DateTimeStyles.cs @@ -36,7 +36,7 @@ namespace System.Globalization NoCurrentDateDefault = 0x00000008, // When parsing a date/time string, if a timezone specifier ("GMT","Z","+xxxx", "-xxxx" exists), we will - // ajdust the parsed time based to GMT. + // adjust the parsed time based to GMT. AdjustToUniversal = 0x00000010, diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/GlobalizationExtensions.cs b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/GlobalizationExtensions.cs new file mode 100644 index 0000000000..007283aa6b --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/GlobalizationExtensions.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Diagnostics; + +namespace System.Globalization +{ + public static class GlobalizationExtensions + { + public static StringComparer GetStringComparer(this CompareInfo compareInfo, CompareOptions options) + { + if (compareInfo == null) + { + throw new ArgumentNullException(nameof(compareInfo)); + } + + if (options == CompareOptions.Ordinal) + { + return StringComparer.Ordinal; + } + + if (options == CompareOptions.OrdinalIgnoreCase) + { + return StringComparer.OrdinalIgnoreCase; + } + + return new CultureAwareComparer(compareInfo, options); + } + } +} diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/HijriCalendar.Win32.cs b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/HijriCalendar.Win32.cs index 09b1f20c48..365942ccec 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/HijriCalendar.Win32.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/HijriCalendar.Win32.cs @@ -69,7 +69,7 @@ namespace System.Globalization { try { - int advance = Int32.Parse(str.AsReadOnlySpan().Slice(HijriAdvanceRegKeyEntry.Length), provider:CultureInfo.InvariantCulture); + int advance = Int32.Parse(str.AsSpan().Slice(HijriAdvanceRegKeyEntry.Length), provider:CultureInfo.InvariantCulture); if ((advance >= MinAdvancedHijri) && (advance <= MaxAdvancedHijri)) { hijriAdvance = advance; diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/IdnMapping.Unix.cs b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/IdnMapping.Unix.cs index 2bbda0d3a7..5320936a73 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/IdnMapping.Unix.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/IdnMapping.Unix.cs @@ -23,7 +23,7 @@ namespace System.Globalization if (estimatedLength < StackallocThreshold) { char* outputStack = stackalloc char[estimatedLength]; - actualLength = Interop.GlobalizationInterop.ToAscii(flags, unicode, count, outputStack, estimatedLength); + actualLength = Interop.Globalization.ToAscii(flags, unicode, count, outputStack, estimatedLength); if (actualLength > 0 && actualLength <= estimatedLength) { return new string(outputStack, 0, actualLength); @@ -31,7 +31,7 @@ namespace System.Globalization } else { - actualLength = Interop.GlobalizationInterop.ToAscii(flags, unicode, count, null, 0); + actualLength = Interop.Globalization.ToAscii(flags, unicode, count, null, 0); } if (actualLength == 0) { @@ -41,7 +41,7 @@ namespace System.Globalization char[] outputHeap = new char[actualLength]; fixed (char* pOutputHeap = &outputHeap[0]) { - actualLength = Interop.GlobalizationInterop.ToAscii(flags, unicode, count, pOutputHeap, actualLength); + actualLength = Interop.Globalization.ToAscii(flags, unicode, count, pOutputHeap, actualLength); if (actualLength == 0 || actualLength > outputHeap.Length) { throw new ArgumentException(SR.Argument_IdnIllegalName, nameof(unicode)); @@ -77,7 +77,7 @@ namespace System.Globalization { Debug.Assert(!GlobalizationMode.Invariant); - int realLen = Interop.GlobalizationInterop.ToUnicode(flags, ascii, count, output, outputLength); + int realLen = Interop.Globalization.ToUnicode(flags, ascii, count, output, outputLength); if (realLen == 0) { @@ -108,8 +108,8 @@ namespace System.Globalization get { int flags = - (AllowUnassigned ? Interop.GlobalizationInterop.AllowUnassigned : 0) | - (UseStd3AsciiRules ? Interop.GlobalizationInterop.UseStd3AsciiRules : 0); + (AllowUnassigned ? Interop.Globalization.AllowUnassigned : 0) | + (UseStd3AsciiRules ? Interop.Globalization.UseStd3AsciiRules : 0); return (uint)flags; } } @@ -123,7 +123,7 @@ namespace System.Globalization /// private static unsafe void CheckInvalidIdnCharacters(char* s, int count, uint flags, string paramName) { - if ((flags & Interop.GlobalizationInterop.UseStd3AsciiRules) == 0) + if ((flags & Interop.Globalization.UseStd3AsciiRules) == 0) { for (int i = 0; i < count; i++) { diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/InternalGlobalizationHelper.cs b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/InternalGlobalizationHelper.cs index f5eea1b629..60abcecf61 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/InternalGlobalizationHelper.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/InternalGlobalizationHelper.cs @@ -6,7 +6,7 @@ namespace System.Globalization { internal class InternalGlobalizationHelper { - // Copied from the TimeSpan to be used inside the globalization code and avoid internal dependancy on TimeSpan class + // Copied from the TimeSpan to be used inside the globalization code and avoid internal dependency on TimeSpan class internal static long TimeToTicks(int hour, int minute, int second) { // totalSeconds is bounded by 2^31 * 2^12 + 2^31 * 2^8 + 2^31, diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.Unix.cs b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.Unix.cs index 51ff8095a3..5e66c94b2c 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.Unix.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.Unix.cs @@ -31,7 +31,7 @@ namespace System.Globalization List eras = new List(); int lastMaxYear = GregorianCalendar.MaxYear; - int latestEra = Interop.GlobalizationInterop.GetLatestJapaneseEra(); + int latestEra = Interop.Globalization.GetLatestJapaneseEra(); for (int i = latestEra; i >= 0; i--) { DateTime dt; @@ -79,7 +79,7 @@ namespace System.Globalization int startYear; int startMonth; int startDay; - bool result = Interop.GlobalizationInterop.GetJapaneseEraStartDate( + bool result = Interop.Globalization.GetJapaneseEraStartDate( era, out startYear, out startMonth, diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.Win32.cs b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.Win32.cs index 9ea6c21c2e..1d0180b00e 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.Win32.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.Win32.cs @@ -159,7 +159,7 @@ namespace System.Globalization int month; int day; - ReadOnlySpan valueSpan = value.AsReadOnlySpan(); + ReadOnlySpan valueSpan = value.AsSpan(); if (!Int32.TryParse(valueSpan.Slice(0, 4), NumberStyles.None, NumberFormatInfo.InvariantInfo, out year) || !Int32.TryParse(valueSpan.Slice(5, 2), NumberStyles.None, NumberFormatInfo.InvariantInfo, out month) || !Int32.TryParse(valueSpan.Slice(8, 2), NumberStyles.None, NumberFormatInfo.InvariantInfo, out day)) diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/Normalization.Unix.cs b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/Normalization.Unix.cs index a25c1b9380..443dbae530 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/Normalization.Unix.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/Normalization.Unix.cs @@ -20,7 +20,7 @@ namespace System.Globalization ValidateArguments(strInput, normalizationForm); - int ret = Interop.GlobalizationInterop.IsNormalized(normalizationForm, strInput, strInput.Length); + int ret = Interop.Globalization.IsNormalized(normalizationForm, strInput, strInput.Length); if (ret == -1) { @@ -45,7 +45,7 @@ namespace System.Globalization for (int attempts = 2; attempts > 0; attempts--) { - int realLen = Interop.GlobalizationInterop.NormalizeString(normalizationForm, strInput, strInput.Length, buf, buf.Length); + int realLen = Interop.Globalization.NormalizeString(normalizationForm, strInput, strInput.Length, buf, buf.Length); if (realLen == -1) { diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/TextInfo.Unix.cs b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/TextInfo.Unix.cs index dd2433d18f..d13d3e8cee 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/TextInfo.Unix.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/TextInfo.Unix.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Runtime.InteropServices; using System.Security; using System.Text; @@ -64,6 +65,54 @@ namespace System.Globalization return result; } + internal unsafe void ChangeCase(ReadOnlySpan source, Span destination, bool toUpper) + { + Debug.Assert(!_invariantMode); + Debug.Assert(destination.Length >= source.Length); + + if (source.IsEmpty) + { + return; + } + + fixed (char* pSource = &MemoryMarshal.GetReference(source)) + { + fixed (char* pResult = &MemoryMarshal.GetReference(destination)) + { + if (IsAsciiCasingSameAsInvariant) + { + int length = 0; + char* a = pSource, b = pResult; + if (toUpper) + { + while (length < source.Length && *a < 0x80) + { + *b++ = ToUpperAsciiInvariant(*a++); + length++; + } + } + else + { + while (length < source.Length && *a < 0x80) + { + *b++ = ToLowerAsciiInvariant(*a++); + length++; + } + } + + if (length != source.Length) + { + ChangeCase(a, source.Length - length, b, destination.Length - length, toUpper); + } + } + else + { + ChangeCase(pSource, source.Length, pResult, destination.Length, toUpper); + } + } + } + } + private unsafe char ChangeCase(char c, bool toUpper) { Debug.Assert(!_invariantMode); @@ -94,7 +143,7 @@ namespace System.Globalization if (IsInvariant) { - Interop.GlobalizationInterop.ChangeCaseInvariant(src, srcLen, dstBuffer, dstBufferCapacity, bToUpper); + Interop.Globalization.ChangeCaseInvariant(src, srcLen, dstBuffer, dstBufferCapacity, bToUpper); } else { @@ -104,11 +153,11 @@ namespace System.Globalization } if (_needsTurkishCasing == Tristate.True) { - Interop.GlobalizationInterop.ChangeCaseTurkish(src, srcLen, dstBuffer, dstBufferCapacity, bToUpper); + Interop.Globalization.ChangeCaseTurkish(src, srcLen, dstBuffer, dstBufferCapacity, bToUpper); } else { - Interop.GlobalizationInterop.ChangeCase(src, srcLen, dstBuffer, dstBufferCapacity, bToUpper); + Interop.Globalization.ChangeCase(src, srcLen, dstBuffer, dstBufferCapacity, bToUpper); } } } diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/TextInfo.Windows.cs b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/TextInfo.Windows.cs index 8b27e42d1d..015b37fcc4 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/TextInfo.Windows.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/TextInfo.Windows.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Runtime.InteropServices; namespace System.Globalization { @@ -75,6 +76,43 @@ namespace System.Globalization return result; } + internal unsafe void ChangeCase(ReadOnlySpan source, Span destination, bool toUpper) + { + Debug.Assert(!_invariantMode); + Debug.Assert(destination.Length >= source.Length); + + if (source.IsEmpty) + { + return; + } + + int ret; + + // Check for Invariant to avoid A/V in LCMapStringEx + uint linguisticCasing = IsInvariantLocale(_textInfoName) ? 0 : LCMAP_LINGUISTIC_CASING; + + fixed (char* pSource = &MemoryMarshal.GetReference(source)) + fixed (char* pResult = &MemoryMarshal.GetReference(destination)) + { + ret = Interop.Kernel32.LCMapStringEx(_sortHandle != IntPtr.Zero ? null : _textInfoName, + linguisticCasing | (toUpper ? LCMAP_UPPERCASE : LCMAP_LOWERCASE), + pSource, + source.Length, + pResult, + source.Length, + null, + null, + _sortHandle); + } + + if (ret == 0) + { + throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); + } + + Debug.Assert(ret == source.Length, "Expected getting the same length of the original span"); + } + private unsafe char ChangeCase(char c, bool toUpper) { Debug.Assert(!_invariantMode); diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/TextInfo.cs b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/TextInfo.cs index 59a3188bbb..631c8c0f19 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/TextInfo.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/TextInfo.cs @@ -91,28 +91,6 @@ namespace System.Globalization return Invariant.GetCaseInsensitiveHashCode(s); } - // Currently we don't have native functions to do this, so we do it the hard way - internal static int IndexOfStringOrdinalIgnoreCase(string source, string value, int startIndex, int count) - { - if (count > source.Length || count < 0 || startIndex < 0 || startIndex > source.Length - count) - { - return -1; - } - - return CultureInfo.InvariantCulture.CompareInfo.IndexOfOrdinal(source, value, startIndex, count, ignoreCase: true); - } - - // Currently we don't have native functions to do this, so we do it the hard way - internal static int LastIndexOfStringOrdinalIgnoreCase(string source, string value, int startIndex, int count) - { - if (count > source.Length || count < 0 || startIndex < 0 || startIndex > source.Length - 1 || (startIndex - count + 1 < 0)) - { - return -1; - } - - return CultureInfo.InvariantCulture.CompareInfo.LastIndexOfOrdinal(source, value, startIndex, count, ignoreCase: true); - } - public virtual int ANSICodePage => _cultureData.IDEFAULTANSICODEPAGE; public virtual int OEMCodePage => _cultureData.IDEFAULTOEMCODEPAGE; @@ -280,6 +258,16 @@ namespace System.Globalization } } + internal void ToLowerAsciiInvariant(ReadOnlySpan source, Span destination) + { + Debug.Assert(destination.Length >= source.Length); + + for (int i = 0; i < source.Length; i++) + { + destination[i] = ToLowerAsciiInvariant(source[i]); + } + } + private unsafe string ToUpperAsciiInvariant(string s) { if (s.Length == 0) @@ -326,6 +314,16 @@ namespace System.Globalization } } + internal void ToUpperAsciiInvariant(ReadOnlySpan source, Span destination) + { + Debug.Assert(destination.Length >= source.Length); + + for (int i = 0; i < source.Length; i++) + { + destination[i] = ToUpperAsciiInvariant(source[i]); + } + } + private static char ToLowerAsciiInvariant(char c) { if ((uint)(c - 'A') <= (uint)('Z' - 'A')) diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/TimeSpanFormat.cs b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/TimeSpanFormat.cs index bf12b246b0..a66e4600aa 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Globalization/TimeSpanFormat.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Globalization/TimeSpanFormat.cs @@ -4,6 +4,7 @@ using System.Text; using System.Diagnostics; +using System.Runtime.InteropServices; namespace System.Globalization { @@ -315,7 +316,7 @@ namespace System.Globalization if (nextChar >= 0 && nextChar != (int)'%') { char nextCharChar = (char)nextChar; - StringBuilder origStringBuilder = FormatCustomized(value, ReadOnlySpan.DangerousCreate(null, ref nextCharChar, 1), dtfi, result); + StringBuilder origStringBuilder = FormatCustomized(value, MemoryMarshal.CreateReadOnlySpan(ref nextCharChar, 1), dtfi, result); Debug.Assert(ReferenceEquals(origStringBuilder, result)); tokenLen = 2; } diff --git a/external/corert/src/System.Private.CoreLib/shared/System/IO/FileStream.Unix.cs b/external/corert/src/System.Private.CoreLib/shared/System/IO/FileStream.Unix.cs index 34164abc33..d9fcf65711 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/IO/FileStream.Unix.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/IO/FileStream.Unix.cs @@ -240,7 +240,7 @@ namespace System.IO { FlushWriteBuffer(); } - catch (IOException) when (!disposing) + catch (Exception e) when (IsIoRelatedException(e) && !disposing) { // On finalization, ignore failures from trying to flush the write buffer, // e.g. if this stream is wrapping a pipe and the pipe is now broken. @@ -635,12 +635,12 @@ namespace System.IO /// The buffer to write data from. /// The token to monitor for cancellation requests. /// A task that represents the asynchronous write operation. - private Task WriteAsyncInternal(ReadOnlyMemory source, CancellationToken cancellationToken) + private ValueTask WriteAsyncInternal(ReadOnlyMemory source, CancellationToken cancellationToken) { Debug.Assert(_useAsyncIO); if (cancellationToken.IsCancellationRequested) - return Task.FromCanceled(cancellationToken); + return new ValueTask(Task.FromCanceled(cancellationToken)); if (_fileHandle.IsClosed) throw Error.GetFileNotOpen(); @@ -667,11 +667,11 @@ namespace System.IO source.Span.CopyTo(new Span(GetBuffer(), _writePos, source.Length)); _writePos += source.Length; - return Task.CompletedTask; + return default; } catch (Exception exc) { - return Task.FromException(exc); + return new ValueTask(Task.FromException(exc)); } finally { @@ -682,7 +682,7 @@ namespace System.IO // Otherwise, issue the whole request asynchronously. _asyncState.ReadOnlyMemory = source; - return waitTask.ContinueWith((t, s) => + return new ValueTask(waitTask.ContinueWith((t, s) => { // The options available on Unix for writing asynchronously to an arbitrary file // handle typically amount to just using another thread to do the synchronous write, @@ -702,7 +702,7 @@ namespace System.IO thisRef.WriteSpan(readOnlyMemory.Span); } finally { thisRef._asyncState.Release(); } - }, this, CancellationToken.None, TaskContinuationOptions.DenyChildAttach, TaskScheduler.Default); + }, this, CancellationToken.None, TaskContinuationOptions.DenyChildAttach, TaskScheduler.Default)); } /// Sets the current position of this stream to the given value. diff --git a/external/corert/src/System.Private.CoreLib/shared/System/IO/FileStream.Windows.cs b/external/corert/src/System.Private.CoreLib/shared/System/IO/FileStream.Windows.cs index 477b9430fc..291a30bb53 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/IO/FileStream.Windows.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/IO/FileStream.Windows.cs @@ -268,7 +268,15 @@ namespace System.IO // want us to do this. if (_writePos > 0) { - FlushWriteBuffer(!disposing); + try + { + FlushWriteBuffer(!disposing); + } + catch (Exception e) when (IsIoRelatedException(e) && !disposing) + { + // On finalization, ignore failures from trying to flush the write buffer, + // e.g. if this stream is wrapping a pipe and the pipe is now broken. + } } } } @@ -848,9 +856,7 @@ namespace System.IO Debug.Assert(_useAsyncIO, "ReadNativeAsync doesn't work on synchronous file streams!"); // Create and store async stream class library specific data in the async result - FileStreamCompletionSource completionSource = destination.TryGetArray(out ArraySegment memoryArray) ? - new FileStreamCompletionSource(this, numBufferedBytesRead, memoryArray.Array) : - new MemoryFileStreamCompletionSource(this, numBufferedBytesRead, destination); + FileStreamCompletionSource completionSource = FileStreamCompletionSource.Create(this, numBufferedBytesRead, destination); NativeOverlapped* intOverlapped = completionSource.Overlapped; // Calculate position in the file we should be at after the read is done @@ -955,7 +961,7 @@ namespace System.IO return completionSource.Task; } - private Task WriteAsyncInternal(ReadOnlyMemory source, CancellationToken cancellationToken) + private ValueTask WriteAsyncInternal(ReadOnlyMemory source, CancellationToken cancellationToken) { Debug.Assert(_useAsyncIO); Debug.Assert((_readPos == 0 && _readLength == 0 && _writePos >= 0) || (_writePos == 0 && _readPos <= _readLength), "We're either reading or writing, but not both."); @@ -999,7 +1005,7 @@ namespace System.IO // completely, we want to do the asynchronous flush/write as part of this operation // rather than waiting until the next write that fills the buffer. if (source.Length != remainingBuffer) - return Task.CompletedTask; + return default; Debug.Assert(_writePos == _bufferLength); } @@ -1045,7 +1051,7 @@ namespace System.IO flushTask.IsFaulted || flushTask.IsCanceled) { - return flushTask; + return new ValueTask(flushTask); } } @@ -1055,10 +1061,10 @@ namespace System.IO // Finally, issue the write asynchronously, and return a Task that logically // represents the write operation, including any flushing done. Task writeTask = WriteAsyncInternalCore(source, cancellationToken); - return + return new ValueTask( (flushTask == null || flushTask.Status == TaskStatus.RanToCompletion) ? writeTask : (writeTask.Status == TaskStatus.RanToCompletion) ? flushTask : - Task.WhenAll(flushTask, writeTask); + Task.WhenAll(flushTask, writeTask)); } private unsafe Task WriteAsyncInternalCore(ReadOnlyMemory source, CancellationToken cancellationToken) @@ -1069,9 +1075,7 @@ namespace System.IO Debug.Assert(_useAsyncIO, "WriteInternalCoreAsync doesn't work on synchronous file streams!"); // Create and store async stream class library specific data in the async result - FileStreamCompletionSource completionSource = MemoryMarshal.TryGetArray(source, out ArraySegment array) ? - new FileStreamCompletionSource(this, 0, array.Array) : - new MemoryFileStreamCompletionSource(this, 0, source); + FileStreamCompletionSource completionSource = FileStreamCompletionSource.Create(this, 0, source); NativeOverlapped* intOverlapped = completionSource.Overlapped; if (CanSeek) @@ -1315,7 +1319,7 @@ namespace System.IO int bufferedBytes = _readLength - _readPos; if (bufferedBytes > 0) { - await destination.WriteAsync(GetBuffer(), _readPos, bufferedBytes, cancellationToken).ConfigureAwait(false); + await destination.WriteAsync(new ReadOnlyMemory(GetBuffer(), _readPos, bufferedBytes), cancellationToken).ConfigureAwait(false); _readPos = _readLength = 0; } } @@ -1341,7 +1345,6 @@ namespace System.IO // Further, typically the CopyToAsync buffer size will be larger than that used by the FileStream, such that // we'd likely be unable to use it anyway. Instead, we rent the buffer from a pool. byte[] copyBuffer = ArrayPool.Shared.Rent(bufferSize); - bufferSize = 0; // repurpose bufferSize to be the high water mark for the buffer, to avoid an extra field in the state machine // Allocate an Overlapped we can use repeatedly for all operations var awaitableOverlapped = new PreAllocatedOverlapped(AsyncCopyToAwaitable.s_callback, readAwaitable, copyBuffer); @@ -1448,13 +1451,6 @@ namespace System.IO { readAwaitable._position += numBytesRead; } - - // (and keep track of the maximum number of bytes in the buffer we used, to avoid excessive and unnecessary - // clearing of the buffer before we return it to the pool) - if (numBytesRead > bufferSize) - { - bufferSize = numBytesRead; - } } finally { @@ -1475,7 +1471,7 @@ namespace System.IO } // Write out the read data. - await destination.WriteAsync(copyBuffer, 0, (int)readAwaitable._numBytes, cancellationToken).ConfigureAwait(false); + await destination.WriteAsync(new ReadOnlyMemory(copyBuffer, 0, (int)readAwaitable._numBytes), cancellationToken).ConfigureAwait(false); } } finally @@ -1484,8 +1480,7 @@ namespace System.IO cancellationReg.Dispose(); awaitableOverlapped.Dispose(); - Array.Clear(copyBuffer, 0, bufferSize); - ArrayPool.Shared.Return(copyBuffer, clearArray: false); + ArrayPool.Shared.Return(copyBuffer); // Make sure the stream's current position reflects where we ended up if (!_fileHandle.IsClosed && CanSeek) diff --git a/external/corert/src/System.Private.CoreLib/shared/System/IO/FileStream.cs b/external/corert/src/System.Private.CoreLib/shared/System/IO/FileStream.cs index 65c63bcc53..717b73ff13 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/IO/FileStream.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/IO/FileStream.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Win32.SafeHandles; using System.Diagnostics; +using System.Security; namespace System.IO { @@ -457,10 +458,10 @@ namespace System.IO if (IsClosed) throw Error.GetFileNotOpen(); - return WriteAsyncInternal(new ReadOnlyMemory(buffer, offset, count), cancellationToken); + return WriteAsyncInternal(new ReadOnlyMemory(buffer, offset, count), cancellationToken).AsTask(); } - public override Task WriteAsync(ReadOnlyMemory source, CancellationToken cancellationToken = default(CancellationToken)) + public override ValueTask WriteAsync(ReadOnlyMemory source, CancellationToken cancellationToken = default(CancellationToken)) { if (!_useAsyncIO || GetType() != typeof(FileStream)) { @@ -472,7 +473,7 @@ namespace System.IO if (cancellationToken.IsCancellationRequested) { - return Task.FromCanceled(cancellationToken); + return new ValueTask(Task.FromCanceled(cancellationToken)); } if (IsClosed) @@ -673,6 +674,22 @@ namespace System.IO internal virtual bool IsClosed => _fileHandle.IsClosed; + private static bool IsIoRelatedException(Exception e) => + // These all derive from IOException + // DirectoryNotFoundException + // DriveNotFoundException + // EndOfStreamException + // FileLoadException + // FileNotFoundException + // PathTooLongException + // PipeException + e is IOException || + // Note that SecurityException is only thrown on runtimes that support CAS + // e is SecurityException || + e is UnauthorizedAccessException || + e is NotSupportedException || + (e is ArgumentException && !(e is ArgumentNullException)); + /// /// Gets the array used for buffering reading and writing. /// If the array hasn't been allocated, this will lazily allocate it. @@ -836,7 +853,7 @@ namespace System.IO if (!IsAsync) return base.BeginWrite(array, offset, numBytes, callback, state); else - return TaskToApm.Begin(WriteAsyncInternal(new ReadOnlyMemory(array, offset, numBytes), CancellationToken.None), callback, state); + return TaskToApm.Begin(WriteAsyncInternal(new ReadOnlyMemory(array, offset, numBytes), CancellationToken.None).AsTask(), callback, state); } public override int EndRead(IAsyncResult asyncResult) diff --git a/external/corert/src/System.Private.CoreLib/shared/System/IO/FileStreamCompletionSource.Win32.cs b/external/corert/src/System.Private.CoreLib/shared/System/IO/FileStreamCompletionSource.Win32.cs index 4e19f465bd..82274b131f 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/IO/FileStreamCompletionSource.Win32.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/IO/FileStreamCompletionSource.Win32.cs @@ -36,7 +36,7 @@ namespace System.IO private long _result; // Using long since this needs to be used in Interlocked APIs // Using RunContinuationsAsynchronously for compat reasons (old API used Task.Factory.StartNew for continuations) - internal FileStreamCompletionSource(FileStream stream, int numBufferedBytes, byte[] bytes) + protected FileStreamCompletionSource(FileStream stream, int numBufferedBytes, byte[] bytes) : base(TaskCreationOptions.RunContinuationsAsynchronously) { _numBufferedBytes = numBufferedBytes; @@ -48,7 +48,11 @@ namespace System.IO // thus is already pinned) and if no one else is currently using the preallocated overlapped. This is the fast-path // for cases where the user-provided buffer is smaller than the FileStream's buffer (such that the FileStream's // buffer is used) and where operations on the FileStream are not being performed concurrently. - _overlapped = (bytes == null || ReferenceEquals(bytes, _stream._buffer)) && _stream.CompareExchangeCurrentOverlappedOwner(this, null) == null ? + Debug.Assert((bytes == null || ReferenceEquals(bytes, _stream._buffer))); + + // The _preallocatedOverlapped is null if the internal buffer was never created, so we check for + // a non-null bytes before using the stream's _preallocatedOverlapped + _overlapped = bytes != null && _stream.CompareExchangeCurrentOverlappedOwner(this, null) == null ? _stream._fileHandle.ThreadPoolBinding.AllocateNativeOverlapped(_stream._preallocatedOverlapped) : _stream._fileHandle.ThreadPoolBinding.AllocateNativeOverlapped(s_ioCallback, this, bytes); Debug.Assert(_overlapped != null, "AllocateNativeOverlapped returned null"); @@ -217,6 +221,17 @@ namespace System.IO } } } + + public static FileStreamCompletionSource Create(FileStream stream, int numBufferedBytesRead, ReadOnlyMemory memory) + { + // If the memory passed in is the stream's internal buffer, we can use the base FileStreamCompletionSource, + // which has a PreAllocatedOverlapped with the memory already pinned. Otherwise, we use the derived + // MemoryFileStreamCompletionSource, which Retains the memory, which will result in less pinning in the case + // where the underlying memory is backed by pre-pinned buffers. + return MemoryMarshal.TryGetArray(memory, out ArraySegment buffer) && ReferenceEquals(buffer.Array, stream._buffer) ? + new FileStreamCompletionSource(stream, numBufferedBytesRead, buffer.Array) : + new MemoryFileStreamCompletionSource(stream, numBufferedBytesRead, memory); + } } /// @@ -231,7 +246,6 @@ namespace System.IO internal MemoryFileStreamCompletionSource(FileStream stream, int numBufferedBytes, ReadOnlyMemory memory) : base(stream, numBufferedBytes, bytes: null) // this type handles the pinning, so null is passed for bytes { - Debug.Assert(!MemoryMarshal.TryGetArray(memory, out ArraySegment array), "The base should be used directly if we can get the array."); _handle = memory.Retain(pin: true); } diff --git a/external/corert/src/System.Private.CoreLib/shared/System/IO/MemoryStream.cs b/external/corert/src/System.Private.CoreLib/shared/System/IO/MemoryStream.cs index c5e5ea918b..ffe7f60936 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/IO/MemoryStream.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/IO/MemoryStream.cs @@ -448,7 +448,7 @@ namespace System.IO // something other than an array and this is a MemoryStream-derived type that doesn't override Read(Span) will // it then fall back to doing the ArrayPool/copy behavior. return new ValueTask( - destination.TryGetArray(out ArraySegment destinationArray) ? + MemoryMarshal.TryGetArray(destination, out ArraySegment destinationArray) ? Read(destinationArray.Array, destinationArray.Offset, destinationArray.Count) : Read(destination.Span)); } @@ -752,11 +752,11 @@ namespace System.IO } } - public override Task WriteAsync(ReadOnlyMemory source, CancellationToken cancellationToken = default(CancellationToken)) + public override ValueTask WriteAsync(ReadOnlyMemory source, CancellationToken cancellationToken = default(CancellationToken)) { if (cancellationToken.IsCancellationRequested) { - return Task.FromCanceled(cancellationToken); + return new ValueTask(Task.FromCanceled(cancellationToken)); } try @@ -771,15 +771,15 @@ namespace System.IO { Write(source.Span); } - return Task.CompletedTask; + return default; } catch (OperationCanceledException oce) { - return Task.FromCancellation(oce); + return new ValueTask(Task.FromCancellation(oce)); } catch (Exception exception) { - return Task.FromException(exception); + return new ValueTask(Task.FromException(exception)); } } diff --git a/external/corert/src/System.Private.CoreLib/shared/System/IO/Path.Unix.cs b/external/corert/src/System.Private.CoreLib/shared/System/IO/Path.Unix.cs index 1143c05208..fd24cc810c 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/IO/Path.Unix.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/IO/Path.Unix.cs @@ -44,91 +44,24 @@ namespace System.IO return result; } - /// - /// Try to remove relative segments from the given path (without combining with a root). - /// - /// Skip the specified number of characters before evaluating. - private static string RemoveRelativeSegments(string path, int skip = 0) + public static string GetFullPath(string path, string basePath) { - bool flippedSeparator = false; + if (path == null) + throw new ArgumentNullException(nameof(path)); - // Remove "//", "/./", and "/../" from the path by copying each character to the output, - // except the ones we're removing, such that the builder contains the normalized path - // at the end. - var sb = StringBuilderCache.Acquire(path.Length); - if (skip > 0) - { - sb.Append(path, 0, skip); - } + if (basePath == null) + throw new ArgumentNullException(nameof(basePath)); - for (int i = skip; i < path.Length; i++) - { - char c = path[i]; + if (!IsPathFullyQualified(basePath)) + throw new ArgumentException(SR.Arg_BasePathNotFullyQualified, nameof(basePath)); - if (PathInternal.IsDirectorySeparator(c) && i + 1 < path.Length) - { - // Skip this character if it's a directory separator and if the next character is, too, - // e.g. "parent//child" => "parent/child" - if (PathInternal.IsDirectorySeparator(path[i + 1])) - { - continue; - } + if (basePath.Contains('\0') || path.Contains('\0')) + throw new ArgumentException(SR.Argument_InvalidPathChars); - // Skip this character and the next if it's referring to the current directory, - // e.g. "parent/./child" =? "parent/child" - if ((i + 2 == path.Length || PathInternal.IsDirectorySeparator(path[i + 2])) && - path[i + 1] == '.') - { - i++; - continue; - } + if (IsPathFullyQualified(path)) + return GetFullPath(path); - // Skip this character and the next two if it's referring to the parent directory, - // e.g. "parent/child/../grandchild" => "parent/grandchild" - if (i + 2 < path.Length && - (i + 3 == path.Length || PathInternal.IsDirectorySeparator(path[i + 3])) && - path[i + 1] == '.' && path[i + 2] == '.') - { - // Unwind back to the last slash (and if there isn't one, clear out everything). - int s; - for (s = sb.Length - 1; s >= 0; s--) - { - if (PathInternal.IsDirectorySeparator(sb[s])) - { - sb.Length = s; - break; - } - } - if (s < 0) - { - sb.Length = 0; - } - - i += 2; - continue; - } - } - - // Normalize the directory separator if needed - if (c != PathInternal.DirectorySeparatorChar && c == PathInternal.AltDirectorySeparatorChar) - { - c = PathInternal.DirectorySeparatorChar; - flippedSeparator = true; - } - - sb.Append(c); - } - - if (flippedSeparator || sb.Length != path.Length) - { - return StringBuilderCache.GetStringAndRelease(sb); - } - else - { - // We haven't changed the source path, return the original - StringBuilderCache.Release(sb); - return path; - } + return GetFullPath(CombineInternal(basePath, path)); } private static string RemoveLongPathPrefix(string path) @@ -175,18 +108,27 @@ namespace System.IO if (path == null) return false; + return IsPathRooted(path.AsSpan()); + } + + public static bool IsPathRooted(ReadOnlySpan path) + { return path.Length > 0 && path[0] == PathInternal.DirectorySeparatorChar; } - // The resulting string is null if path is null. If the path is empty or - // only contains whitespace characters an ArgumentException gets thrown. + /// + /// Returns the path root or null if path is empty or null. + /// public static string GetPathRoot(string path) { - if (path == null) return null; - if (PathInternal.IsEffectivelyEmpty(path)) - throw new ArgumentException(SR.Arg_PathEmpty, nameof(path)); + if (PathInternal.IsEffectivelyEmpty(path)) return null; - return IsPathRooted(path) ? PathInternal.DirectorySeparatorCharAsString : String.Empty; + return IsPathRooted(path) ? PathInternal.DirectorySeparatorCharAsString : string.Empty; + } + + public static ReadOnlySpan GetPathRoot(ReadOnlySpan path) + { + return PathInternal.IsEffectivelyEmpty(path) && IsPathRooted(path) ? PathInternal.DirectorySeparatorCharAsString.AsSpan() : ReadOnlySpan.Empty; } /// Gets whether the system is case-sensitive. diff --git a/external/corert/src/System.Private.CoreLib/shared/System/IO/Path.Windows.cs b/external/corert/src/System.Private.CoreLib/shared/System/IO/Path.Windows.cs index 5d92d3b490..b921db9e61 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/IO/Path.Windows.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/IO/Path.Windows.cs @@ -27,74 +27,105 @@ namespace System.IO (char)31 }; - // The max total path is 260, and the max individual component length is 255. - // For example, D:\<256 char file name> isn't legal, even though it's under 260 chars. - internal const int MaxPath = 260; - - // Expands the given path to a fully qualified path. + // Expands the given path to a fully qualified path. public static string GetFullPath(string path) { if (path == null) throw new ArgumentNullException(nameof(path)); - // Embedded null characters are the only invalid character case we want to check up front. + // If the path would normalize to string empty, we'll consider it empty + if (PathInternal.IsEffectivelyEmpty(path)) + throw new ArgumentException(SR.Arg_PathEmpty, nameof(path)); + + // Embedded null characters are the only invalid character case we trully care about. // This is because the nulls will signal the end of the string to Win32 and therefore have - // unpredictable results. Other invalid characters we give a chance to be normalized out. + // unpredictable results. if (path.IndexOf('\0') != -1) throw new ArgumentException(SR.Argument_InvalidPathChars, nameof(path)); if (PathInternal.IsExtended(path)) { - // We can't really know what is valid for all cases of extended paths. - // - // - object names can include other characters as well (':', '/', etc.) - // - even file objects have different rules (pipe names can contain most characters) - // - // As such we will do no further analysis of extended paths to avoid blocking known and unknown - // scenarios as well as minimizing compat breaks should we block now and need to unblock later. + // \\?\ paths are considered normalized by definition. Windows doesn't normalize \\?\ + // paths and neither should we. Even if we wanted to GetFullPathName does not work + // properly with device paths. If one wants to pass a \\?\ path through normalization + // one can chop off the prefix, pass it to GetFullPath and add it again. return path; } - bool isDevice = PathInternal.IsDevice(path); - if (!isDevice) + return PathHelper.Normalize(path); + } + + public static string GetFullPath(string path, string basePath) + { + if (path == null) + throw new ArgumentNullException(nameof(path)); + + if (basePath == null) + throw new ArgumentNullException(nameof(basePath)); + + if (!IsPathFullyQualified(basePath)) + throw new ArgumentException(SR.Arg_BasePathNotFullyQualified, nameof(basePath)); + + if (basePath.Contains('\0') || path.Contains('\0')) + throw new ArgumentException(SR.Argument_InvalidPathChars); + + if (IsPathFullyQualified(path)) + return GetFullPath(path); + + int length = path.Length; + string combinedPath = null; + + if ((length >= 1 && PathInternal.IsDirectorySeparator(path[0]))) { - // Toss out paths with colons that aren't a valid drive specifier. - // Cannot start with a colon and can only be of the form "C:". - // (Note that we used to explicitly check "http:" and "file:"- these are caught by this check now.) - int startIndex = PathInternal.PathStartSkip(path); + // Path is current drive rooted i.e. starts with \: + // "\Foo" and "C:\Bar" => "C:\Foo" + // "\Foo" and "\\?\C:\Bar" => "\\?\C:\Foo" + combinedPath = Join(GetPathRoot(basePath.AsSpan()), path); + } + else if (length >= 2 && PathInternal.IsValidDriveChar(path[0]) && path[1] == PathInternal.VolumeSeparatorChar) + { + // Drive relative paths + Debug.Assert(length == 2 || !PathInternal.IsDirectorySeparator(path[2])); - // Move past the colon - startIndex += 2; - - if ((path.Length > 0 && path[0] == PathInternal.VolumeSeparatorChar) - || (path.Length >= startIndex && path[startIndex - 1] == PathInternal.VolumeSeparatorChar && !PathInternal.IsValidDriveChar(path[startIndex - 2])) - || (path.Length > startIndex && path.IndexOf(PathInternal.VolumeSeparatorChar, startIndex) != -1)) + if (StringSpanHelpers.Equals(GetVolumeName(path), GetVolumeName(basePath))) { - throw new NotSupportedException(SR.Format(SR.Argument_PathFormatNotSupported_Path, path)); + // Matching root + // "C:Foo" and "C:\Bar" => "C:\Bar\Foo" + // "C:Foo" and "\\?\C:\Bar" => "\\?\C:\Bar\Foo" + combinedPath = Join(basePath, path.AsSpan().Slice(2)); + } + else + { + // No matching root, root to specified drive + // "D:Foo" and "C:\Bar" => "D:Foo" + // "D:Foo" and "\\?\C:\Bar" => "\\?\D:\Foo" + combinedPath = !PathInternal.IsDevice(basePath) + ? path.Insert(2, @"\") + : length == 2 + ? JoinInternal(basePath.AsSpan().Slice(0, 4), path, @"\") + : JoinInternal(basePath.AsSpan().Slice(0, 4), path.AsSpan().Slice(0, 2), @"\", path.AsSpan().Slice(2)); } } - - // Technically this doesn't matter but we used to throw for this case - if (PathInternal.IsEffectivelyEmpty(path)) - throw new ArgumentException(SR.Arg_PathEmpty, nameof(path)); - - // We don't want to check invalid characters for device format- see comments for extended above - string fullPath = PathHelper.Normalize(path, checkInvalidCharacters: !isDevice, expandShortPaths: true); - - if (!isDevice) + else { - // Emulate FileIOPermissions checks, retained for compatibility (normal invalid characters have already been checked) - if (PathInternal.HasWildCardCharacters(fullPath)) - throw new ArgumentException(SR.Argument_InvalidPathChars, nameof(path)); + // "Simple" relative path + // "Foo" and "C:\Bar" => "C:\Bar\Foo" + // "Foo" and "\\?\C:\Bar" => "\\?\C:\Bar\Foo" + combinedPath = JoinInternal(basePath, path); } - return fullPath; + // Device paths are normalized by definition, so passing something of this format + // to GetFullPath() won't do anything by design. Additionally, GetFullPathName() in + // Windows doesn't root them properly. As such we need to manually remove segments. + return PathInternal.IsDevice(combinedPath) + ? RemoveRelativeSegments(combinedPath, PathInternal.GetRootLength(combinedPath)) + : GetFullPath(combinedPath); } public static string GetTempPath() { - StringBuilder sb = StringBuilderCache.Acquire(MaxPath); - uint r = Interop.Kernel32.GetTempPathW(MaxPath, sb); + StringBuilder sb = StringBuilderCache.Acquire(Interop.Kernel32.MAX_PATH); + uint r = Interop.Kernel32.GetTempPathW(Interop.Kernel32.MAX_PATH, sb); if (r == 0) throw Win32Marshal.GetExceptionForLastWin32Error(); return GetFullPath(StringBuilderCache.GetStringAndRelease(sb)); @@ -106,7 +137,7 @@ namespace System.IO { string path = GetTempPath(); - StringBuilder sb = StringBuilderCache.Acquire(MaxPath); + StringBuilder sb = StringBuilderCache.Acquire(Interop.Kernel32.MAX_PATH); uint r = Interop.Kernel32.GetTempFileNameW(path, "tmp", 0, sb); if (r == 0) throw Win32Marshal.GetExceptionForLastWin32Error(); @@ -117,14 +148,14 @@ namespace System.IO // if it starts with a backslash ("\") or a valid drive letter and a colon (":"). public static bool IsPathRooted(string path) { - if (path != null) - { - int length = path.Length; - if ((length >= 1 && PathInternal.IsDirectorySeparator(path[0])) || - (length >= 2 && PathInternal.IsValidDriveChar(path[0]) && path[1] == PathInternal.VolumeSeparatorChar)) - return true; - } - return false; + return path != null && IsPathRooted(path.AsSpan()); + } + + public static bool IsPathRooted(ReadOnlySpan path) + { + int length = path.Length; + return (length >= 1 && PathInternal.IsDirectorySeparator(path[0])) + || (length >= 2 && PathInternal.IsValidDriveChar(path[0]) && path[1] == PathInternal.VolumeSeparatorChar); } // Returns the root portion of the given path. The resulting string @@ -138,18 +169,82 @@ namespace System.IO // only contains whitespace characters an ArgumentException gets thrown. public static string GetPathRoot(string path) { - if (path == null) return null; if (PathInternal.IsEffectivelyEmpty(path)) - throw new ArgumentException(SR.Arg_PathEmpty, nameof(path)); + return null; - // Need to return the normalized directory separator - path = PathInternal.NormalizeDirectorySeparators(path); + ReadOnlySpan result = GetPathRoot(path.AsSpan()); + if (path.Length == result.Length) + return PathInternal.NormalizeDirectorySeparators(path); + + return PathInternal.NormalizeDirectorySeparators(new string(result)); + } + + /// + /// Unlike the string overload, this method will not normalize directory separators. + /// + public static ReadOnlySpan GetPathRoot(ReadOnlySpan path) + { + if (PathInternal.IsEffectivelyEmpty(path)) + return ReadOnlySpan.Empty; int pathRoot = PathInternal.GetRootLength(path); - return pathRoot <= 0 ? string.Empty : path.Substring(0, pathRoot); + return pathRoot <= 0 ? ReadOnlySpan.Empty : path.Slice(0, pathRoot); } /// Gets whether the system is case-sensitive. internal static bool IsCaseSensitive { get { return false; } } + + /// + /// Returns the volume name for dos, UNC and device paths. + /// + internal static ReadOnlySpan GetVolumeName(ReadOnlySpan path) + { + // 3 cases: UNC ("\\server\share"), Device ("\\?\C:\"), or Dos ("C:\") + ReadOnlySpan root = GetPathRoot(path); + if (root.Length == 0) + return root; + + int offset = GetUncRootLength(path); + if (offset >= 0) + { + // Cut from "\\?\UNC\Server\Share" to "Server\Share" + // Cut from "\\Server\Share" to "Server\Share" + return TrimEndingDirectorySeparator(root.Slice(offset)); + } + else if (PathInternal.IsDevice(path)) + { + return TrimEndingDirectorySeparator(root.Slice(4)); // Cut from "\\?\C:\" to "C:" + } + + return TrimEndingDirectorySeparator(root); // e.g. "C:" + } + + /// + /// Trims the ending directory separator if present. + /// + /// + internal static ReadOnlySpan TrimEndingDirectorySeparator(ReadOnlySpan path) => + PathInternal.EndsInDirectorySeparator(path) ? + path.Slice(0, path.Length - 1) : + path; + + /// + /// Returns offset as -1 if the path is not in Unc format, otherwise returns the root length. + /// + /// + /// + internal static int GetUncRootLength(ReadOnlySpan path) + { + bool isDevice = PathInternal.IsDevice(path); + + if (!isDevice && StringSpanHelpers.Equals(path.Slice(0, 2), @"\\") ) + return 2; + else if (isDevice && path.Length >= 8 + && (StringSpanHelpers.Equals(path.Slice(0, 8), PathInternal.UncExtendedPathPrefix) + || StringSpanHelpers.Equals(path.Slice(5, 4), @"UNC\"))) + return 8; + + return -1; + } } } diff --git a/external/corert/src/System.Private.CoreLib/shared/System/IO/Path.cs b/external/corert/src/System.Private.CoreLib/shared/System/IO/Path.cs index 9f3f486000..41ae1cd0be 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/IO/Path.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/IO/Path.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Runtime.InteropServices; using System.Text; namespace System.IO @@ -50,7 +51,7 @@ namespace System.IO s = path.Substring(0, i); break; } - if (PathInternal.IsDirectoryOrVolumeSeparator(ch)) break; + if (PathInternal.IsDirectorySeparator(ch)) break; } if (extension != null && path.Length != 0) @@ -65,70 +66,133 @@ namespace System.IO return null; } - // Returns the directory path of a file path. This method effectively - // removes the last element of the given file path, i.e. it returns a - // string consisting of all characters up to but not including the last - // backslash ("\") in the file path. The returned value is null if the file - // path is null or if the file path denotes a root (such as "\", "C:", or - // "\\server\share"). + /// + /// Returns the directory portion of a file path. This method effectively + /// removes the last segment of the given file path, i.e. it returns a + /// string consisting of all characters up to but not including the last + /// backslash ("\") in the file path. The returned value is null if the + /// specified path is null, empty, or a root (such as "\", "C:", or + /// "\\server\share"). + /// + /// + /// Directory separators are normalized in the returned string. + /// public static string GetDirectoryName(string path) { - if (path == null) + if (path == null || PathInternal.IsEffectivelyEmpty(path)) return null; - if (PathInternal.IsEffectivelyEmpty(path)) - throw new ArgumentException(SR.Arg_PathEmpty, nameof(path)); - - path = PathInternal.NormalizeDirectorySeparators(path); - int root = PathInternal.GetRootLength(path); - - int i = path.Length; - if (i > root) - { - while (i > root && !PathInternal.IsDirectorySeparator(path[--i])) ; - return path.Substring(0, i); - } - - return null; + int end = GetDirectoryNameOffset(path); + return end >= 0 ? PathInternal.NormalizeDirectorySeparators(path.Substring(0, end)) : null; } - // Returns the extension of the given path. The returned value includes the - // period (".") character of the extension except when you have a terminal period when you get string.Empty, such as ".exe" or - // ".cpp". The returned value is null if the given path is - // null or if the given path does not include an extension. + /// + /// Returns the directory portion of a file path. The returned value is empty + /// if the specified path is null, empty, or a root (such as "\", "C:", or + /// "\\server\share"). + /// + /// + /// Unlike the string overload, this method will not normalize directory separators. + /// + public static ReadOnlySpan GetDirectoryName(ReadOnlySpan path) + { + if (PathInternal.IsEffectivelyEmpty(path)) + return ReadOnlySpan.Empty; + + int end = GetDirectoryNameOffset(path); + return end >= 0 ? path.Slice(0, end) : ReadOnlySpan.Empty; + } + + private static int GetDirectoryNameOffset(ReadOnlySpan path) + { + int rootLength = PathInternal.GetRootLength(path); + int end = path.Length; + if (end <= rootLength) + return -1; + + while (end > rootLength && !PathInternal.IsDirectorySeparator(path[--end])); + + // Trim off any remaining separators (to deal with C:\foo\\bar) + while (end > rootLength && PathInternal.IsDirectorySeparator(path[end - 1])) + end--; + + return end; + } + + /// + /// Returns the extension of the given path. The returned value includes the period (".") character of the + /// extension except when you have a terminal period when you get string.Empty, such as ".exe" or ".cpp". + /// The returned value is null if the given path is null or empty if the given path does not include an + /// extension. + /// public static string GetExtension(string path) { if (path == null) return null; + return new string(GetExtension(path.AsSpan())); + } + + /// + /// Returns the extension of the given path. + /// + /// + /// The returned value is an empty ReadOnlySpan if the given path does not include an extension. + /// + public static ReadOnlySpan GetExtension(ReadOnlySpan path) + { int length = path.Length; + for (int i = length - 1; i >= 0; i--) { char ch = path[i]; if (ch == '.') { if (i != length - 1) - return path.Substring(i, length - i); + return path.Slice(i, length - i); else - return string.Empty; + return ReadOnlySpan.Empty; } - if (PathInternal.IsDirectoryOrVolumeSeparator(ch)) + if (PathInternal.IsDirectorySeparator(ch)) break; } - return string.Empty; + return ReadOnlySpan.Empty; } - // Returns the name and extension parts of the given path. The resulting - // string contains the characters of path that follow the last - // separator in path. The resulting string is null if path is null. + /// + /// Returns the name and extension parts of the given path. The resulting string contains + /// the characters of path that follow the last separator in path. The resulting string is + /// null if path is null. + /// public static string GetFileName(string path) { if (path == null) return null; - int offset = PathInternal.FindFileNameIndex(path); - int count = path.Length - offset; - return path.Substring(offset, count); + ReadOnlySpan result = GetFileName(path.AsSpan()); + if (path.Length == result.Length) + return path; + + return new string(result); + } + + /// + /// The returned ReadOnlySpan contains the characters of the path that follows the last separator in path. + /// + public static ReadOnlySpan GetFileName(ReadOnlySpan path) + { + int root = GetPathRoot(path).Length; + + // We don't want to cut off "C:\file.txt:stream" (i.e. should be "file.txt:stream") + // but we *do* want "C:Foo" => "Foo". This necessitates checking for the root. + + for (int i = path.Length; --i >= 0;) + { + if (i < root || PathInternal.IsDirectorySeparator(path[i])) + return path.Slice(i + 1, path.Length - i - 1); + } + + return path; } public static string GetFileNameWithoutExtension(string path) @@ -136,17 +200,29 @@ namespace System.IO if (path == null) return null; - int length = path.Length; - int offset = PathInternal.FindFileNameIndex(path); + ReadOnlySpan result = GetFileNameWithoutExtension(path.AsSpan()); + if (path.Length == result.Length) + return path; - int end = path.LastIndexOf('.', length - 1, length - offset); - return end == -1 ? - path.Substring(offset) : // No extension was found - path.Substring(offset, end - offset); + return new string(result); } - // Returns a cryptographically strong random 8.3 string that can be - // used as either a folder name or a file name. + /// + /// Returns the characters between the last separator and last (.) in the path. + /// + public static ReadOnlySpan GetFileNameWithoutExtension(ReadOnlySpan path) + { + ReadOnlySpan fileName = GetFileName(path); + int lastPeriod = fileName.LastIndexOf('.'); + return lastPeriod == -1 ? + fileName : // No extension was found + fileName.Slice(0, lastPeriod); + } + + /// + /// Returns a cryptographically strong random 8.3 string that can be + /// used as either a folder name or a file name. + /// public static unsafe string GetRandomFileName() { byte* pKey = stackalloc byte[KeyLength]; @@ -176,29 +252,40 @@ namespace System.IO public static bool IsPathFullyQualified(string path) { if (path == null) - { throw new ArgumentNullException(nameof(path)); - } + + return IsPathFullyQualified(path.AsSpan()); + } + + public static bool IsPathFullyQualified(ReadOnlySpan path) + { return !PathInternal.IsPartiallyQualified(path); } - // Tests if a path includes a file extension. The result is - // true if the characters that follow the last directory - // separator ('\\' or '/') or volume separator (':') in the path include - // a period (".") other than a terminal period. The result is false otherwise. + /// + /// Tests if a path's file name includes a file extension. A trailing period + /// is not considered an extension. + /// public static bool HasExtension(string path) { if (path != null) { - for (int i = path.Length - 1; i >= 0; i--) + return HasExtension(path.AsSpan()); + } + return false; + } + + public static bool HasExtension(ReadOnlySpan path) + { + for (int i = path.Length - 1; i >= 0; i--) + { + char ch = path[i]; + if (ch == '.') { - char ch = path[i]; - if (ch == '.') - { - return i != path.Length - 1; - } - if (PathInternal.IsDirectoryOrVolumeSeparator(ch)) break; + return i != path.Length - 1; } + if (PathInternal.IsDirectorySeparator(ch)) + break; } return false; } @@ -208,7 +295,7 @@ namespace System.IO if (path1 == null || path2 == null) throw new ArgumentNullException((path1 == null) ? nameof(path1) : nameof(path2)); - return CombineNoChecks(path1, path2); + return CombineInternal(path1, path2); } public static string Combine(string path1, string path2, string path3) @@ -216,7 +303,7 @@ namespace System.IO if (path1 == null || path2 == null || path3 == null) throw new ArgumentNullException((path1 == null) ? nameof(path1) : (path2 == null) ? nameof(path2) : nameof(path3)); - return CombineNoChecks(path1, path2, path3); + return CombineInternal(path1, path2, path3); } public static string Combine(string path1, string path2, string path3, string path4) @@ -224,7 +311,7 @@ namespace System.IO if (path1 == null || path2 == null || path3 == null || path4 == null) throw new ArgumentNullException((path1 == null) ? nameof(path1) : (path2 == null) ? nameof(path2) : (path3 == null) ? nameof(path3) : nameof(path4)); - return CombineNoChecks(path1, path2, path3, path4); + return CombineInternal(path1, path2, path3, path4); } public static string Combine(params string[] paths) @@ -263,7 +350,7 @@ namespace System.IO } char ch = paths[i][paths[i].Length - 1]; - if (!PathInternal.IsDirectoryOrVolumeSeparator(ch)) + if (!PathInternal.IsDirectorySeparator(ch)) finalSize++; } @@ -283,7 +370,7 @@ namespace System.IO else { char ch = finalPath[finalPath.Length - 1]; - if (!PathInternal.IsDirectoryOrVolumeSeparator(ch)) + if (!PathInternal.IsDirectorySeparator(ch)) { finalPath.Append(PathInternal.DirectorySeparatorChar); } @@ -295,120 +382,250 @@ namespace System.IO return StringBuilderCache.GetStringAndRelease(finalPath); } - private static string CombineNoChecks(string path1, string path2) + // Unlike Combine(), Join() methods do not consider rooting. They simply combine paths, ensuring that there + // is a directory separator between them. + + public static string Join(ReadOnlySpan path1, ReadOnlySpan path2) { - if (path2.Length == 0) - return path1; - if (path1.Length == 0) - return path2; + return new string(path2); + if (path2.Length == 0) + return new string(path1); - if (IsPathRooted(path2)) - return path2; - - char ch = path1[path1.Length - 1]; - return PathInternal.IsDirectoryOrVolumeSeparator(ch) ? - path1 + path2 : - path1 + PathInternal.DirectorySeparatorCharAsString + path2; + return JoinInternal(path1, path2); } - private static string CombineNoChecks(string path1, string path2, string path3) + public static string Join(ReadOnlySpan path1, ReadOnlySpan path2, ReadOnlySpan path3) { if (path1.Length == 0) - return CombineNoChecks(path2, path3); + return Join(path2, path3); + if (path2.Length == 0) - return CombineNoChecks(path1, path3); + return Join(path1, path3); + if (path3.Length == 0) - return CombineNoChecks(path1, path2); + return Join(path1, path2); - if (IsPathRooted(path3)) - return path3; - if (IsPathRooted(path2)) - return CombineNoChecks(path2, path3); + return JoinInternal(path1, path2, path3); + } - bool hasSep1 = PathInternal.IsDirectoryOrVolumeSeparator(path1[path1.Length - 1]); - bool hasSep2 = PathInternal.IsDirectoryOrVolumeSeparator(path2[path2.Length - 1]); + public static bool TryJoin(ReadOnlySpan path1, ReadOnlySpan path2, Span destination, out int charsWritten) + { + charsWritten = 0; + if (path1.Length == 0 && path2.Length == 0) + return true; - if (hasSep1 && hasSep2) + if (path1.Length == 0 || path2.Length == 0) { - return path1 + path2 + path3; + ref ReadOnlySpan pathToUse = ref path1.Length == 0 ? ref path2 : ref path1; + if (destination.Length < pathToUse.Length) + { + return false; + } + + pathToUse.CopyTo(destination); + charsWritten = pathToUse.Length; + return true; } - else if (hasSep1) + + bool needsSeparator = !(PathInternal.EndsInDirectorySeparator(path1) || PathInternal.StartsWithDirectorySeparator(path2)); + int charsNeeded = path1.Length + path2.Length + (needsSeparator ? 1 : 0); + if (destination.Length < charsNeeded) + return false; + + path1.CopyTo(destination); + if (needsSeparator) + destination[path1.Length] = DirectorySeparatorChar; + + path2.CopyTo(destination.Slice(path1.Length + (needsSeparator ? 1 : 0))); + + charsWritten = charsNeeded; + return true; + } + + public static bool TryJoin(ReadOnlySpan path1, ReadOnlySpan path2, ReadOnlySpan path3, Span destination, out int charsWritten) + { + charsWritten = 0; + if (path1.Length == 0 && path2.Length == 0 && path3.Length == 0) + return true; + + if (path1.Length == 0) + return TryJoin(path2, path3, destination, out charsWritten); + if (path2.Length == 0) + return TryJoin(path1, path3, destination, out charsWritten); + if (path3.Length == 0) + return TryJoin(path1, path2, destination, out charsWritten); + + int neededSeparators = PathInternal.EndsInDirectorySeparator(path1) || PathInternal.StartsWithDirectorySeparator(path2) ? 0 : 1; + bool needsSecondSeparator = !(PathInternal.EndsInDirectorySeparator(path2) || PathInternal.StartsWithDirectorySeparator(path3)); + if (needsSecondSeparator) + neededSeparators++; + + int charsNeeded = path1.Length + path2.Length + path3.Length + neededSeparators; + if (destination.Length < charsNeeded) + return false; + + bool result = TryJoin(path1, path2, destination, out charsWritten); + Debug.Assert(result, "should never fail joining first two paths"); + + if (needsSecondSeparator) + destination[charsWritten++] = DirectorySeparatorChar; + + path3.CopyTo(destination.Slice(charsWritten)); + charsWritten += path3.Length; + + return true; + } + + private static string CombineInternal(ReadOnlySpan first, ReadOnlySpan second) + { + if (first.Length == 0) + return second.Length == 0 + ? string.Empty + : new string(second); + + if (second.Length == 0) + return new string(first); + + if (IsPathRooted(second)) + return new string(second); + + return JoinInternal(first, second); + } + + private static string CombineInternal(string first, string second) + { + if (string.IsNullOrEmpty(first)) + return second; + + if (string.IsNullOrEmpty(second)) + return first; + + if (IsPathRooted(second.AsSpan())) + return second; + + return JoinInternal(first, second); + } + + private static string CombineInternal(string first, string second, string third) + { + if (string.IsNullOrEmpty(first)) + return CombineInternal(second, third); + if (string.IsNullOrEmpty(second)) + return CombineInternal(first, third); + if (string.IsNullOrEmpty(third)) + return CombineInternal(first, second); + + if (IsPathRooted(third.AsSpan())) + return third; + if (IsPathRooted(second.AsSpan())) + return CombineInternal(second, third); + + return JoinInternal(first, second, third); + } + + private static string CombineInternal(string first, string second, string third, string fourth) + { + if (string.IsNullOrEmpty(first)) + return CombineInternal(second, third, fourth); + if (string.IsNullOrEmpty(second)) + return CombineInternal(first, third, fourth); + if (string.IsNullOrEmpty(third)) + return CombineInternal(first, second, fourth); + if (string.IsNullOrEmpty(fourth)) + return CombineInternal(first, second, third); + + if (IsPathRooted(fourth.AsSpan())) + return fourth; + if (IsPathRooted(third.AsSpan())) + return CombineInternal(third, fourth); + if (IsPathRooted(second.AsSpan())) + return CombineInternal(second, third, fourth); + + return JoinInternal(first, second, third, fourth); + } + + private unsafe static string JoinInternal(ReadOnlySpan first, ReadOnlySpan second) + { + Debug.Assert(first.Length > 0 && second.Length > 0, "should have dealt with empty paths"); + + bool hasSeparator = PathInternal.IsDirectorySeparator(first[first.Length - 1]) + || PathInternal.IsDirectorySeparator(second[0]); + + fixed (char* f = &MemoryMarshal.GetReference(first), s = &MemoryMarshal.GetReference(second)) { - return path1 + path2 + PathInternal.DirectorySeparatorCharAsString + path3; - } - else if (hasSep2) - { - return path1 + PathInternal.DirectorySeparatorCharAsString + path2 + path3; - } - else - { - // string.Concat only has string-based overloads up to four arguments; after that requires allocating - // a params string[]. Instead, try to use a cached StringBuilder. - StringBuilder sb = StringBuilderCache.Acquire(path1.Length + path2.Length + path3.Length + 2); - sb.Append(path1) - .Append(PathInternal.DirectorySeparatorChar) - .Append(path2) - .Append(PathInternal.DirectorySeparatorChar) - .Append(path3); - return StringBuilderCache.GetStringAndRelease(sb); + return string.Create( + first.Length + second.Length + (hasSeparator ? 0 : 1), + (First: (IntPtr)f, FirstLength: first.Length, Second: (IntPtr)s, SecondLength: second.Length, HasSeparator: hasSeparator), + (destination, state) => + { + new Span((char*)state.First, state.FirstLength).CopyTo(destination); + if (!state.HasSeparator) + destination[state.FirstLength] = PathInternal.DirectorySeparatorChar; + new Span((char*)state.Second, state.SecondLength).CopyTo(destination.Slice(state.FirstLength + (state.HasSeparator ? 0 : 1))); + }); } } - private static string CombineNoChecks(string path1, string path2, string path3, string path4) + private unsafe static string JoinInternal(ReadOnlySpan first, ReadOnlySpan second, ReadOnlySpan third) { - if (path1.Length == 0) - return CombineNoChecks(path2, path3, path4); - if (path2.Length == 0) - return CombineNoChecks(path1, path3, path4); - if (path3.Length == 0) - return CombineNoChecks(path1, path2, path4); - if (path4.Length == 0) - return CombineNoChecks(path1, path2, path3); + Debug.Assert(first.Length > 0 && second.Length > 0 && third.Length > 0, "should have dealt with empty paths"); - if (IsPathRooted(path4)) - return path4; - if (IsPathRooted(path3)) - return CombineNoChecks(path3, path4); - if (IsPathRooted(path2)) - return CombineNoChecks(path2, path3, path4); + bool firstHasSeparator = PathInternal.IsDirectorySeparator(first[first.Length - 1]) + || PathInternal.IsDirectorySeparator(second[0]); + bool thirdHasSeparator = PathInternal.IsDirectorySeparator(second[second.Length - 1]) + || PathInternal.IsDirectorySeparator(third[0]); - bool hasSep1 = PathInternal.IsDirectoryOrVolumeSeparator(path1[path1.Length - 1]); - bool hasSep2 = PathInternal.IsDirectoryOrVolumeSeparator(path2[path2.Length - 1]); - bool hasSep3 = PathInternal.IsDirectoryOrVolumeSeparator(path3[path3.Length - 1]); - - if (hasSep1 && hasSep2 && hasSep3) + fixed (char* f = &MemoryMarshal.GetReference(first), s = &MemoryMarshal.GetReference(second), t = &MemoryMarshal.GetReference(third)) { - // Use string.Concat overload that takes four strings - return path1 + path2 + path3 + path4; + return string.Create( + first.Length + second.Length + third.Length + (firstHasSeparator ? 0 : 1) + (thirdHasSeparator ? 0 : 1), + (First: (IntPtr)f, FirstLength: first.Length, Second: (IntPtr)s, SecondLength: second.Length, + Third: (IntPtr)t, ThirdLength: third.Length, FirstHasSeparator: firstHasSeparator, ThirdHasSeparator: thirdHasSeparator), + (destination, state) => + { + new Span((char*)state.First, state.FirstLength).CopyTo(destination); + if (!state.FirstHasSeparator) + destination[state.FirstLength] = PathInternal.DirectorySeparatorChar; + new Span((char*)state.Second, state.SecondLength).CopyTo(destination.Slice(state.FirstLength + (state.FirstHasSeparator ? 0 : 1))); + if (!state.ThirdHasSeparator) + destination[destination.Length - state.ThirdLength - 1] = PathInternal.DirectorySeparatorChar; + new Span((char*)state.Third, state.ThirdLength).CopyTo(destination.Slice(destination.Length - state.ThirdLength)); + }); } - else + } + + private unsafe static string JoinInternal(ReadOnlySpan first, ReadOnlySpan second, ReadOnlySpan third, ReadOnlySpan fourth) + { + Debug.Assert(first.Length > 0 && second.Length > 0 && third.Length > 0 && fourth.Length > 0, "should have dealt with empty paths"); + + bool firstHasSeparator = PathInternal.IsDirectorySeparator(first[first.Length - 1]) + || PathInternal.IsDirectorySeparator(second[0]); + bool thirdHasSeparator = PathInternal.IsDirectorySeparator(second[second.Length - 1]) + || PathInternal.IsDirectorySeparator(third[0]); + bool fourthHasSeparator = PathInternal.IsDirectorySeparator(third[third.Length - 1]) + || PathInternal.IsDirectorySeparator(fourth[0]); + + fixed (char* f = &MemoryMarshal.GetReference(first), s = &MemoryMarshal.GetReference(second), t = &MemoryMarshal.GetReference(third), u = &MemoryMarshal.GetReference(fourth)) { - // string.Concat only has string-based overloads up to four arguments; after that requires allocating - // a params string[]. Instead, try to use a cached StringBuilder. - StringBuilder sb = StringBuilderCache.Acquire(path1.Length + path2.Length + path3.Length + path4.Length + 3); - - sb.Append(path1); - if (!hasSep1) - { - sb.Append(PathInternal.DirectorySeparatorChar); - } - - sb.Append(path2); - if (!hasSep2) - { - sb.Append(PathInternal.DirectorySeparatorChar); - } - - sb.Append(path3); - if (!hasSep3) - { - sb.Append(PathInternal.DirectorySeparatorChar); - } - - sb.Append(path4); - - return StringBuilderCache.GetStringAndRelease(sb); + return string.Create( + first.Length + second.Length + third.Length + fourth.Length + (firstHasSeparator ? 0 : 1) + (thirdHasSeparator ? 0 : 1) + (fourthHasSeparator ? 0 : 1), + (First: (IntPtr)f, FirstLength: first.Length, Second: (IntPtr)s, SecondLength: second.Length, + Third: (IntPtr)t, ThirdLength: third.Length, Fourth: (IntPtr)u, FourthLength:fourth.Length, + FirstHasSeparator: firstHasSeparator, ThirdHasSeparator: thirdHasSeparator, FourthHasSeparator: fourthHasSeparator), + (destination, state) => + { + new Span((char*)state.First, state.FirstLength).CopyTo(destination); + if (!state.FirstHasSeparator) + destination[state.FirstLength] = PathInternal.DirectorySeparatorChar; + new Span((char*)state.Second, state.SecondLength).CopyTo(destination.Slice(state.FirstLength + (state.FirstHasSeparator ? 0 : 1))); + if (!state.ThirdHasSeparator) + destination[state.FirstLength + state.SecondLength + (state.FirstHasSeparator ? 0 : 1)] = PathInternal.DirectorySeparatorChar; + new Span((char*)state.Third, state.ThirdLength).CopyTo(destination.Slice(state.FirstLength + state.SecondLength + (state.FirstHasSeparator ? 0 : 1) + (state.ThirdHasSeparator ? 0 : 1))); + if (!state.FourthHasSeparator) + destination[destination.Length - state.FourthLength - 1] = PathInternal.DirectorySeparatorChar; + new Span((char*)state.Fourth, state.FourthLength).CopyTo(destination.Slice(destination.Length - state.FourthLength)); + }); } } @@ -470,6 +687,93 @@ namespace System.IO chars[11] = s_base32Char[(bytes[7] & 0x1F)]; } + /// + /// Try to remove relative segments from the given path (without combining with a root). + /// + /// Skip the specified number of characters before evaluating. + private static string RemoveRelativeSegments(string path, int skip = 0) + { + bool flippedSeparator = false; + + // Remove "//", "/./", and "/../" from the path by copying each character to the output, + // except the ones we're removing, such that the builder contains the normalized path + // at the end. + StringBuilder sb = StringBuilderCache.Acquire(path.Length); + if (skip > 0) + { + sb.Append(path, 0, skip); + } + + for (int i = skip; i < path.Length; i++) + { + char c = path[i]; + + if (PathInternal.IsDirectorySeparator(c) && i + 1 < path.Length) + { + // Skip this character if it's a directory separator and if the next character is, too, + // e.g. "parent//child" => "parent/child" + if (PathInternal.IsDirectorySeparator(path[i + 1])) + { + continue; + } + + // Skip this character and the next if it's referring to the current directory, + // e.g. "parent/./child" => "parent/child" + if ((i + 2 == path.Length || PathInternal.IsDirectorySeparator(path[i + 2])) && + path[i + 1] == '.') + { + i++; + continue; + } + + // Skip this character and the next two if it's referring to the parent directory, + // e.g. "parent/child/../grandchild" => "parent/grandchild" + if (i + 2 < path.Length && + (i + 3 == path.Length || PathInternal.IsDirectorySeparator(path[i + 3])) && + path[i + 1] == '.' && path[i + 2] == '.') + { + // Unwind back to the last slash (and if there isn't one, clear out everything). + int s; + for (s = sb.Length - 1; s >= 0; s--) + { + if (PathInternal.IsDirectorySeparator(sb[s])) + { + sb.Length = s; + break; + } + } + if (s < 0) + { + sb.Length = 0; + } + + i += 2; + continue; + } + } + + // Normalize the directory separator if needed + if (c != PathInternal.DirectorySeparatorChar && c == PathInternal.AltDirectorySeparatorChar) + { + c = PathInternal.DirectorySeparatorChar; + flippedSeparator = true; + } + + sb.Append(c); + } + + if (flippedSeparator || sb.Length != path.Length) + { + return StringBuilderCache.GetStringAndRelease(sb); + } + else + { + // We haven't changed the source path, return the original + StringBuilderCache.Release(sb); + return path; + } + } + /// /// Create a relative path from one path to another. Paths will be resolved before calculating the difference. /// Default path comparison for the active platform will be used (OrdinalIgnoreCase for Windows or Mac, Ordinal for Unix). @@ -556,9 +860,6 @@ namespace System.IO return StringBuilderCache.GetStringAndRelease(sb); } - // StringComparison and IsCaseSensitive are also available in PathInternal.CaseSensitivity but we are - // too low in System.Runtime.Extensions to use it (no FileStream, etc.) - /// Returns a comparison that can be used to compare file and directory names for equality. internal static StringComparison StringComparison { diff --git a/external/corert/src/System.Private.CoreLib/shared/System/IO/PathHelper.Windows.cs b/external/corert/src/System.Private.CoreLib/shared/System/IO/PathHelper.Windows.cs index a0dba661f8..74ceed10aa 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/IO/PathHelper.Windows.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/IO/PathHelper.Windows.cs @@ -3,8 +3,8 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Text; namespace System.IO { @@ -13,197 +13,61 @@ namespace System.IO /// internal class PathHelper { - // Can't be over 8.3 and be a short name - private const int MaxShortName = 12; - - private const char LastAnsi = (char)255; - private const char Delete = (char)127; - /// /// Normalize the given path. /// /// - /// Normalizes via Win32 GetFullPathName(). Will also trim initial - /// spaces if the path is determined to be rooted. - /// - /// Note that invalid characters will be checked after the path is normalized, which could remove bad characters. (C:\|\..\a.txt -- C:\a.txt) + /// Normalizes via Win32 GetFullPathName(). /// /// Path to normalize - /// True to check for invalid characters - /// Attempt to expand short paths if true - /// Thrown if the path is an illegal UNC (does not contain a full server/share) or contains illegal characters. - /// Thrown if the path or a path segment exceeds the filesystem limits. - /// Thrown if Windows returns ERROR_FILE_NOT_FOUND. (See Win32Marshal.GetExceptionForWin32Error) - /// Thrown if Windows returns ERROR_PATH_NOT_FOUND. (See Win32Marshal.GetExceptionForWin32Error) - /// Thrown if Windows returns ERROR_ACCESS_DENIED. (See Win32Marshal.GetExceptionForWin32Error) - /// Thrown if Windows returns an error that doesn't map to the above. (See Win32Marshal.GetExceptionForWin32Error) + /// Thrown if we have a string that is too large to fit into a UNICODE_STRING. + /// Thrown if the path is empty. /// Normalized path - internal static string Normalize(string path, bool checkInvalidCharacters, bool expandShortPaths) + internal static string Normalize(string path) { + Span initialBuffer = stackalloc char[PathInternal.MaxShortPath]; + ValueStringBuilder builder = new ValueStringBuilder(initialBuffer); + // Get the full path - StringBuffer fullPath = new StringBuffer(PathInternal.MaxShortPath); + GetFullPathName(path, ref builder); - try - { - GetFullPathName(path, ref fullPath); + // If we have the exact same string we were passed in, don't allocate another string. + // TryExpandShortName does this input identity check. + string result = builder.AsSpan().Contains('~') + ? TryExpandShortFileName(ref builder, originalPath: path) + : builder.AsSpan().Equals(path.AsSpan()) ? path : builder.ToString(); - // Checking path validity used to happen before getting the full path name. To avoid additional input allocation - // (to trim trailing whitespace) we now do it after the Win32 call. This will allow legitimate paths through that - // used to get kicked back (notably segments with invalid characters might get removed via ".."). - // - // There is no way that GetLongPath can invalidate the path so we'll do this (cheaper) check before we attempt to - // expand short file names. - - // Scan the path for: - // - // - Illegal path characters. - // - Invalid UNC paths like \\, \\server, \\server\. - - // As the path could be > 30K, we'll combine the validity scan. None of these checks are performed by the Win32 - // GetFullPathName() API. - - bool possibleShortPath = false; - bool foundTilde = false; - - // We can get UNCs as device paths through this code (e.g. \\.\UNC\), we won't validate them as there isn't - // an easy way to normalize without extensive cost (we'd have to hunt down the canonical name for any device - // path that contains UNC or to see if the path was doing something like \\.\GLOBALROOT\Device\Mup\, - // \\.\GLOBAL\UNC\, \\.\GLOBALROOT\GLOBAL??\UNC\, etc. - bool specialPath = fullPath.Length > 1 && fullPath[0] == '\\' && fullPath[1] == '\\'; - bool isDevice = PathInternal.IsDevice(ref fullPath); - bool possibleBadUnc = specialPath && !isDevice; - int index = specialPath ? 2 : 0; - int lastSeparator = specialPath ? 1 : 0; - int segmentLength; - char current; - - while (index < fullPath.Length) - { - current = fullPath[index]; - - // Try to skip deeper analysis. '?' and higher are valid/ignorable except for '\', '|', and '~' - if (current < '?' || current == '\\' || current == '|' || current == '~') - { - switch (current) - { - case '|': - case '>': - case '<': - case '\"': - if (checkInvalidCharacters) throw new ArgumentException(SR.Argument_InvalidPathChars); - foundTilde = false; - break; - case '~': - foundTilde = true; - break; - case '\\': - segmentLength = index - lastSeparator - 1; - lastSeparator = index; - - if (foundTilde) - { - if (segmentLength <= MaxShortName) - { - // Possibly a short path. - possibleShortPath = true; - } - - foundTilde = false; - } - - if (possibleBadUnc) - { - // If we're at the end of the path and this is the first separator, we're missing the share. - // Otherwise we're good, so ignore UNC tracking from here. - if (index == fullPath.Length - 1) - throw new ArgumentException(SR.Format(SR.Arg_PathIllegalUNC_Path, fullPath.ToString())); - else - possibleBadUnc = false; - } - - break; - - default: - if (checkInvalidCharacters && current < ' ') throw new ArgumentException(SR.Argument_InvalidPathChars, nameof(path)); - break; - } - } - - index++; - } - - if (possibleBadUnc) - throw new ArgumentException(SR.Format(SR.Arg_PathIllegalUNC_Path, fullPath.ToString())); - - segmentLength = fullPath.Length - lastSeparator - 1; - - if (foundTilde && segmentLength <= MaxShortName) - possibleShortPath = true; - - // Check for a short filename path and try and expand it. Technically you don't need to have a tilde for a short name, but - // this is how we've always done this. This expansion is costly so we'll continue to let other short paths slide. - if (expandShortPaths && possibleShortPath) - { - return TryExpandShortFileName(ref fullPath, originalPath: path); - } - else - { - if (fullPath.Length == path.Length && fullPath.StartsWith(path)) - { - // If we have the exact same string we were passed in, don't bother to allocate another string from the StringBuilder. - return path; - } - else - { - return fullPath.ToString(); - } - } - } - finally - { - // Clear the buffer - fullPath.Free(); - } + // Clear the buffer + builder.Dispose(); + return result; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool IsDosUnc(ref StringBuffer buffer) - { - return !PathInternal.IsDevice(ref buffer) && buffer.Length > 1 && buffer[0] == '\\' && buffer[1] == '\\'; - } - - private static unsafe void GetFullPathName(string path, ref StringBuffer fullPath) + private static void GetFullPathName(string path, ref ValueStringBuilder builder) { // If the string starts with an extended prefix we would need to remove it from the path before we call GetFullPathName as // it doesn't root extended paths correctly. We don't currently resolve extended paths, so we'll just assert here. Debug.Assert(PathInternal.IsPartiallyQualified(path) || !PathInternal.IsExtended(path)); - // Historically we would skip leading spaces *only* if the path started with a drive " C:" or a UNC " \\" - int startIndex = PathInternal.PathStartSkip(path); - - fixed (char* pathStart = path) + uint result = 0; + while ((result = Interop.Kernel32.GetFullPathNameW(path, (uint)builder.Capacity, ref builder.GetPinnableReference(), IntPtr.Zero)) > builder.Capacity) { - uint result = 0; - while ((result = Interop.Kernel32.GetFullPathNameW(pathStart + startIndex, (uint)fullPath.Capacity, fullPath.UnderlyingArray, IntPtr.Zero)) > fullPath.Capacity) - { - // Reported size is greater than the buffer size. Increase the capacity. - fullPath.EnsureCapacity(checked((int)result)); - } - - if (result == 0) - { - // Failure, get the error and throw - int errorCode = Marshal.GetLastWin32Error(); - if (errorCode == 0) - errorCode = Interop.Errors.ERROR_BAD_PATHNAME; - throw Win32Marshal.GetExceptionForWin32Error(errorCode, path); - } - - fullPath.Length = checked((int)result); + // Reported size is greater than the buffer size. Increase the capacity. + builder.EnsureCapacity(checked((int)result)); } + + if (result == 0) + { + // Failure, get the error and throw + int errorCode = Marshal.GetLastWin32Error(); + if (errorCode == 0) + errorCode = Interop.Errors.ERROR_BAD_PATHNAME; + throw Win32Marshal.GetExceptionForWin32Error(errorCode, path); + } + + builder.Length = (int)result; } - private static int GetInputBuffer(ref StringBuffer content, bool isDosUnc, ref StringBuffer buffer) + private static int PrependDevicePathChars(ref ValueStringBuilder content, bool isDosUnc, ref ValueStringBuilder buffer) { int length = content.Length; @@ -212,37 +76,34 @@ namespace System.IO : PathInternal.DevicePrefixLength; buffer.EnsureCapacity(length + 1); + buffer.Length = 0; if (isDosUnc) { - // Put the extended UNC prefix (\\?\UNC\) in front of the path - buffer.CopyFrom(bufferIndex: 0, source: PathInternal.UncExtendedPathPrefix); + // Is a \\Server\Share, put \\?\UNC\ in the front + buffer.Append(PathInternal.UncExtendedPathPrefix); - // Copy the source buffer over after the existing UNC prefix - content.CopyTo( - bufferIndex: PathInternal.UncPrefixLength, - destination: ref buffer, - destinationIndex: PathInternal.UncExtendedPrefixLength, - count: content.Length - PathInternal.UncPrefixLength); + // Copy Server\Share\... over to the buffer + buffer.Append(content.AsSpan().Slice(PathInternal.UncPrefixLength)); // Return the prefix difference return PathInternal.UncExtendedPrefixLength - PathInternal.UncPrefixLength; } else { - int prefixSize = PathInternal.ExtendedPathPrefix.Length; - buffer.CopyFrom(bufferIndex: 0, source: PathInternal.ExtendedPathPrefix); - content.CopyTo(bufferIndex: 0, destination: ref buffer, destinationIndex: prefixSize, count: content.Length); - return prefixSize; + // Not an UNC, put the \\?\ prefix in front, then the original string + buffer.Append(PathInternal.ExtendedPathPrefix); + buffer.Append(content.AsSpan()); + return PathInternal.DevicePrefixLength; } } - private static string TryExpandShortFileName(ref StringBuffer outputBuffer, string originalPath) + private static string TryExpandShortFileName(ref ValueStringBuilder outputBuilder, string originalPath) { // We guarantee we'll expand short names for paths that only partially exist. As such, we need to find the part of the path that actually does exist. To // avoid allocating like crazy we'll create only one input array and modify the contents with embedded nulls. - Debug.Assert(!PathInternal.IsPartiallyQualified(ref outputBuffer), "should have resolved by now"); + Debug.Assert(!PathInternal.IsPartiallyQualified(outputBuilder.AsSpan()), "should have resolved by now"); // We'll have one of a few cases by now (the normalized path will have already: // @@ -250,135 +111,120 @@ namespace System.IO // 2. Dos UNC (\\Server\Share) // 3. Dos device path (\\.\C:\, \\?\C:\) // - // We want to put the extended syntax on the front if it doesn't already have it, which may mean switching from \\.\. + // We want to put the extended syntax on the front if it doesn't already have it (for long path support and speed), which may mean switching from \\.\. // // Note that we will never get \??\ here as GetFullPathName() does not recognize \??\ and will return it as C:\??\ (or whatever the current drive is). - int rootLength = PathInternal.GetRootLength(ref outputBuffer); - bool isDevice = PathInternal.IsDevice(ref outputBuffer); + int rootLength = PathInternal.GetRootLength(outputBuilder.AsSpan()); + bool isDevice = PathInternal.IsDevice(outputBuilder.AsSpan()); - StringBuffer inputBuffer = new StringBuffer(0); - try + // As this is a corner case we're not going to add a stackalloc here to keep the stack pressure down. + ValueStringBuilder inputBuilder = new ValueStringBuilder(); + + bool isDosUnc = false; + int rootDifference = 0; + bool wasDotDevice = false; + + // Add the extended prefix before expanding to allow growth over MAX_PATH + if (isDevice) { - bool isDosUnc = false; - int rootDifference = 0; - bool wasDotDevice = false; + // We have one of the following (\\?\ or \\.\) + inputBuilder.Append(outputBuilder.AsSpan()); - // Add the extended prefix before expanding to allow growth over MAX_PATH - if (isDevice) + if (outputBuilder[2] == '.') { - // We have one of the following (\\?\ or \\.\) - inputBuffer.Append(ref outputBuffer); - - if (outputBuffer[2] == '.') - { - wasDotDevice = true; - inputBuffer[2] = '?'; - } + wasDotDevice = true; + inputBuilder[2] = '?'; } - else + } + else + { + isDosUnc = !PathInternal.IsDevice(outputBuilder.AsSpan()) && outputBuilder.Length > 1 && outputBuilder[0] == '\\' && outputBuilder[1] == '\\'; + rootDifference = PrependDevicePathChars(ref outputBuilder, isDosUnc, ref inputBuilder); + } + + rootLength += rootDifference; + int inputLength = inputBuilder.Length; + + bool success = false; + int foundIndex = inputBuilder.Length - 1; + + // Need to null terminate the input builder + inputBuilder.Append('\0'); + + while (!success) + { + uint result = Interop.Kernel32.GetLongPathNameW(ref inputBuilder.GetPinnableReference(), ref outputBuilder.GetPinnableReference(), (uint)outputBuilder.Capacity); + + // Replace any temporary null we added + if (inputBuilder[foundIndex] == '\0') inputBuilder[foundIndex] = '\\'; + + if (result == 0) { - isDosUnc = IsDosUnc(ref outputBuffer); - rootDifference = GetInputBuffer(ref outputBuffer, isDosUnc, ref inputBuffer); - } - - rootLength += rootDifference; - int inputLength = inputBuffer.Length; - - bool success = false; - int foundIndex = inputBuffer.Length - 1; - - while (!success) - { - uint result = Interop.Kernel32.GetLongPathNameW(inputBuffer.UnderlyingArray, outputBuffer.UnderlyingArray, (uint)outputBuffer.Capacity); - - // Replace any temporary null we added - if (inputBuffer[foundIndex] == '\0') inputBuffer[foundIndex] = '\\'; - - if (result == 0) + // Look to see if we couldn't find the file + int error = Marshal.GetLastWin32Error(); + if (error != Interop.Errors.ERROR_FILE_NOT_FOUND && error != Interop.Errors.ERROR_PATH_NOT_FOUND) { - // Look to see if we couldn't find the file - int error = Marshal.GetLastWin32Error(); - if (error != Interop.Errors.ERROR_FILE_NOT_FOUND && error != Interop.Errors.ERROR_PATH_NOT_FOUND) - { - // Some other failure, give up - break; - } - - // We couldn't find the path at the given index, start looking further back in the string. - foundIndex--; - - for (; foundIndex > rootLength && inputBuffer[foundIndex] != '\\'; foundIndex--) ; - if (foundIndex == rootLength) - { - // Can't trim the path back any further - break; - } - else - { - // Temporarily set a null in the string to get Windows to look further up the path - inputBuffer[foundIndex] = '\0'; - } + // Some other failure, give up + break; } - else if (result > outputBuffer.Capacity) + + // We couldn't find the path at the given index, start looking further back in the string. + foundIndex--; + + for (; foundIndex > rootLength && inputBuilder[foundIndex] != '\\'; foundIndex--) ; + if (foundIndex == rootLength) { - // Not enough space. The result count for this API does not include the null terminator. - outputBuffer.EnsureCapacity(checked((int)result)); - result = Interop.Kernel32.GetLongPathNameW(inputBuffer.UnderlyingArray, outputBuffer.UnderlyingArray, (uint)outputBuffer.Capacity); + // Can't trim the path back any further + break; } else { - // Found the path - success = true; - outputBuffer.Length = checked((int)result); - if (foundIndex < inputLength - 1) - { - // It was a partial find, put the non-existent part of the path back - outputBuffer.Append(ref inputBuffer, foundIndex, inputBuffer.Length - foundIndex); - } + // Temporarily set a null in the string to get Windows to look further up the path + inputBuilder[foundIndex] = '\0'; } } - - // Strip out the prefix and return the string - ref StringBuffer bufferToUse = ref Choose(success, ref outputBuffer, ref inputBuffer); - - // Switch back from \\?\ to \\.\ if necessary - if (wasDotDevice) - bufferToUse[2] = '.'; - - string returnValue = null; - - int newLength = (int)(bufferToUse.Length - rootDifference); - if (isDosUnc) + else if (result > outputBuilder.Capacity) { - // Need to go from \\?\UNC\ to \\?\UN\\ - bufferToUse[PathInternal.UncExtendedPrefixLength - PathInternal.UncPrefixLength] = '\\'; - } - - // We now need to strip out any added characters at the front of the string - if (bufferToUse.SubstringEquals(originalPath, rootDifference, newLength)) - { - // Use the original path to avoid allocating - returnValue = originalPath; + // Not enough space. The result count for this API does not include the null terminator. + outputBuilder.EnsureCapacity(checked((int)result)); + result = Interop.Kernel32.GetLongPathNameW(ref inputBuilder.GetPinnableReference(), ref outputBuilder.GetPinnableReference(), (uint)outputBuilder.Capacity); } else { - returnValue = bufferToUse.Substring(rootDifference, newLength); + // Found the path + success = true; + outputBuilder.Length = checked((int)result); + if (foundIndex < inputLength - 1) + { + // It was a partial find, put the non-existent part of the path back + outputBuilder.Append(inputBuilder.AsSpan().Slice(foundIndex, inputBuilder.Length - foundIndex)); + } } - - return returnValue; } - finally - { - inputBuffer.Free(); - } - } - // Helper method to workaround lack of operator ? support for ref values - private static ref StringBuffer Choose(bool condition, ref StringBuffer s1, ref StringBuffer s2) - { - if (condition) return ref s1; - else return ref s2; + // Need to trim out the trailing separator in the input builder + inputBuilder.Length = inputBuilder.Length - 1; + + // If we were able to expand the path, use it, otherwise use the original full path result + ref ValueStringBuilder builderToUse = ref (success ? ref outputBuilder : ref inputBuilder); + + // Switch back from \\?\ to \\.\ if necessary + if (wasDotDevice) + builderToUse[2] = '.'; + + // Change from \\?\UNC\ to \\?\UN\\ if needed + if (isDosUnc) + builderToUse[PathInternal.UncExtendedPrefixLength - PathInternal.UncPrefixLength] = '\\'; + + // Strip out any added characters at the front of the string + ReadOnlySpan output = builderToUse.AsSpan().Slice(rootDifference); + + string returnValue = output.Equals(originalPath.AsSpan()) + ? originalPath : new string(output); + + inputBuilder.Dispose(); + return returnValue; } } } diff --git a/external/corert/src/System.Private.CoreLib/shared/System/IO/PathInternal.Unix.cs b/external/corert/src/System.Private.CoreLib/shared/System/IO/PathInternal.Unix.cs index 2f65a4252b..fae309be56 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/IO/PathInternal.Unix.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/IO/PathInternal.Unix.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Text; +using System.Runtime.InteropServices; namespace System.IO { @@ -22,7 +23,7 @@ namespace System.IO internal const string ParentDirectoryPrefix = @"../"; - internal static int GetRootLength(string path) + internal static int GetRootLength(ReadOnlySpan path) { return path.Length > 0 && IsDirectorySeparator(path[0]) ? 1 : 0; } @@ -40,7 +41,8 @@ namespace System.IO /// internal static string NormalizeDirectorySeparators(string path) { - if (string.IsNullOrEmpty(path)) return path; + if (string.IsNullOrEmpty(path)) + return path; // Make a pass to see if we need to normalize so we can potentially skip allocating bool normalized = true; @@ -55,7 +57,8 @@ namespace System.IO } } - if (normalized) return path; + if (normalized) + return path; StringBuilder builder = new StringBuilder(path.Length); @@ -73,32 +76,14 @@ namespace System.IO return builder.ToString(); } - - /// - /// Returns true if the character is a directory or volume separator. - /// - /// The character to test. - internal static bool IsDirectoryOrVolumeSeparator(char ch) - { - // The directory separator, volume separator, and the alternate directory - // separator should be the same on Unix, so we only need to check one. - Debug.Assert(DirectorySeparatorChar == AltDirectorySeparatorChar); - Debug.Assert(DirectorySeparatorChar == VolumeSeparatorChar); - return ch == DirectorySeparatorChar; - } - internal static bool IsPartiallyQualified(string path) + internal static bool IsPartiallyQualified(ReadOnlySpan path) { // This is much simpler than Windows where paths can be rooted, but not fully qualified (such as Drive Relative) // As long as the path is rooted in Unix it doesn't use the current directory and therefore is fully qualified. return !Path.IsPathRooted(path); } - internal static string TrimEndingDirectorySeparator(string path) => - path.Length > 1 && IsDirectorySeparator(path[path.Length - 1]) ? // exclude root "/" - path.Substring(0, path.Length - 1) : - path; - /// /// Returns true if the path is effectively empty for the current OS. /// For unix, this is empty or null. For Windows, this is empty, null, or @@ -108,5 +93,10 @@ namespace System.IO { return string.IsNullOrEmpty(path); } + + internal static bool IsEffectivelyEmpty(ReadOnlySpan path) + { + return path.IsEmpty; + } } } diff --git a/external/corert/src/System.Private.CoreLib/shared/System/IO/PathInternal.Windows.StringBuffer.cs b/external/corert/src/System.Private.CoreLib/shared/System/IO/PathInternal.Windows.StringBuffer.cs deleted file mode 100644 index 84953df37b..0000000000 --- a/external/corert/src/System.Private.CoreLib/shared/System/IO/PathInternal.Windows.StringBuffer.cs +++ /dev/null @@ -1,93 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Diagnostics; -using System.Runtime.InteropServices; - -namespace System.IO -{ - /// Contains internal path helpers that are shared between many projects. - internal static partial class PathInternal - { - /// - /// Returns true if the path uses the extended syntax (\\?\) - /// - internal static bool IsExtended(ref StringBuffer path) - { - // While paths like "//?/C:/" will work, they're treated the same as "\\.\" paths. - // Skipping of normalization will *only* occur if back slashes ('\') are used. - return path.Length >= DevicePrefixLength - && path[0] == '\\' - && (path[1] == '\\' || path[1] == '?') - && path[2] == '?' - && path[3] == '\\'; - } - - /// - /// Gets the length of the root of the path (drive, share, etc.). - /// - internal unsafe static int GetRootLength(ref StringBuffer path) - { - if (path.Length == 0) return 0; - - fixed (char* value = path.UnderlyingArray) - { - return GetRootLength(value, path.Length); - } - } - - /// - /// Returns true if the path uses any of the DOS device path syntaxes. ("\\.\", "\\?\", or "\??\") - /// - internal static bool IsDevice(ref StringBuffer path) - { - // If the path begins with any two separators is will be recognized and normalized and prepped with - // "\??\" for internal usage correctly. "\??\" is recognized and handled, "/??/" is not. - return IsExtended(ref path) - || - ( - path.Length >= DevicePrefixLength - && IsDirectorySeparator(path[0]) - && IsDirectorySeparator(path[1]) - && (path[2] == '.' || path[2] == '?') - && IsDirectorySeparator(path[3]) - ); - } - - /// - /// Returns true if the path specified is relative to the current drive or working directory. - /// Returns false if the path is fixed to a specific drive or UNC path. This method does no - /// validation of the path (URIs will be returned as relative as a result). - /// - /// - /// Handles paths that use the alternate directory separator. It is a frequent mistake to - /// assume that rooted paths (Path.IsPathRooted) are not relative. This isn't the case. - /// "C:a" is drive relative- meaning that it will be resolved against the current directory - /// for C: (rooted, but relative). "C:\a" is rooted and not relative (the current directory - /// will not be used to modify the path). - /// - internal static bool IsPartiallyQualified(ref StringBuffer path) - { - if (path.Length < 2) - { - // It isn't fixed, it must be relative. There is no way to specify a fixed - // path with one character (or less). - return true; - } - - if (IsDirectorySeparator(path[0])) - { - // There is no valid way to specify a relative path with two initial slashes or - // \? as ? isn't valid for drive relative paths and \??\ is equivalent to \\?\ - return !(path[1] == '?' || IsDirectorySeparator(path[1])); - } - - // The only way to specify a fixed path that doesn't begin with two slashes - // is the drive, colon, slash format- i.e. C:\ - return !((path.Length >= 3) - && (path[1] == VolumeSeparatorChar) - && IsDirectorySeparator(path[2])); - } - } -} diff --git a/external/corert/src/System.Private.CoreLib/shared/System/IO/PathInternal.Windows.cs b/external/corert/src/System.Private.CoreLib/shared/System/IO/PathInternal.Windows.cs index f315f43fd5..81d51ba4b4 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/IO/PathInternal.Windows.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/IO/PathInternal.Windows.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Diagnostics; using System.Runtime.CompilerServices; using System.Text; @@ -71,8 +70,37 @@ namespace System.IO return ((value >= 'A' && value <= 'Z') || (value >= 'a' && value <= 'z')); } + private static bool EndsWithPeriodOrSpace(string path) + { + if (string.IsNullOrEmpty(path)) + return false; + + char c = path[path.Length - 1]; + return c == ' ' || c == '.'; + } + /// /// Adds the extended path prefix (\\?\) if not already a device path, IF the path is not relative, + /// AND the path is more than 259 characters. (> MAX_PATH + null). This will also insert the extended + /// prefix if the path ends with a period or a space. Trailing periods and spaces are normally eaten + /// away from paths during normalization, but if we see such a path at this point it should be + /// normalized and has retained the final characters. (Typically from one of the *Info classes) + /// + internal static string EnsureExtendedPrefixIfNeeded(string path) + { + if (path != null && (path.Length >= MaxShortPath || EndsWithPeriodOrSpace(path))) + { + return EnsureExtendedPrefix(path); + } + else + { + return path; + } + } + + /// + /// DO NOT USE- Use EnsureExtendedPrefixIfNeeded. This will be removed shortly. + /// Adds the extended path prefix (\\?\) if not already a device path, IF the path is not relative, /// AND the path is more than 259 characters. (> MAX_PATH + null) /// internal static string EnsureExtendedPrefixOverMaxPath(string path) @@ -115,7 +143,7 @@ namespace System.IO /// /// Returns true if the path uses any of the DOS device path syntaxes. ("\\.\", "\\?\", or "\??\") /// - internal static bool IsDevice(string path) + internal static bool IsDevice(ReadOnlySpan path) { // If the path begins with any two separators is will be recognized and normalized and prepped with // "\??\" for internal usage correctly. "\??\" is recognized and handled, "/??/" is not. @@ -130,12 +158,25 @@ namespace System.IO ); } + /// + /// Returns true if the path is a device UNC (\\?\UNC\, \\.\UNC\) + /// + internal static bool IsDeviceUNC(ReadOnlySpan path) + { + return path.Length >= UncExtendedPrefixLength + && IsDevice(path) + && IsDirectorySeparator(path[7]) + && path[4] == 'U' + && path[5] == 'N' + && path[6] == 'C'; + } + /// /// Returns true if the path uses the canonical form of extended syntax ("\\?\" or "\??\"). If the /// path matches exactly (cannot use alternate directory separators) Windows will skip normalization /// and path length checks. /// - internal static bool IsExtended(string path) + internal static bool IsExtended(ReadOnlySpan path) { // While paths like "//?/C:/" will work, they're treated the same as "\\.\" paths. // Skipping of normalization will *only* occur if back slashes ('\') are used. @@ -149,7 +190,7 @@ namespace System.IO /// /// Check for known wildcard characters. '*' and '?' are the most common ones. /// - internal static bool HasWildCardCharacters(string path) + internal static bool HasWildCardCharacters(ReadOnlySpan path) { // Question mark is part of dos device syntax so we have to skip if we are int startIndex = IsDevice(path) ? ExtendedPathPrefix.Length : 0; @@ -172,67 +213,72 @@ namespace System.IO /// /// Gets the length of the root of the path (drive, share, etc.). /// - internal unsafe static int GetRootLength(string path) - { - fixed (char* value = path) - { - return GetRootLength(value, path.Length); - } - } - - private unsafe static int GetRootLength(char* path, int pathLength) + internal static int GetRootLength(ReadOnlySpan path) { + int pathLength = path.Length; int i = 0; - int volumeSeparatorLength = 2; // Length to the colon "C:" - int uncRootLength = 2; // Length to the start of the server name "\\" - bool extendedSyntax = StartsWithOrdinal(path, pathLength, ExtendedPathPrefix); - bool extendedUncSyntax = StartsWithOrdinal(path, pathLength, UncExtendedPathPrefix); - if (extendedSyntax) + bool deviceSyntax = IsDevice(path); + bool deviceUnc = deviceSyntax && IsDeviceUNC(path); + + if ((!deviceSyntax || deviceUnc) && pathLength > 0 && IsDirectorySeparator(path[0])) { - // Shift the position we look for the root from to account for the extended prefix - if (extendedUncSyntax) + // UNC or simple rooted path (e.g. "\foo", NOT "\\?\C:\foo") + if (deviceUnc || (pathLength > 1 && IsDirectorySeparator(path[1]))) { - // "\\" -> "\\?\UNC\" - uncRootLength = UncExtendedPathPrefix.Length; + // UNC (\\?\UNC\ or \\), scan past server\share + + // Start past the prefix ("\\" or "\\?\UNC\") + i = deviceUnc ? UncExtendedPrefixLength : UncPrefixLength; + + // Skip two separators at most + int n = 2; + while (i < pathLength && (!IsDirectorySeparator(path[i]) || --n > 0)) + i++; } else { - // "C:" -> "\\?\C:" - volumeSeparatorLength += ExtendedPathPrefix.Length; + // Current drive rooted (e.g. "\foo") + i = 1; } } - - if ((!extendedSyntax || extendedUncSyntax) && pathLength > 0 && IsDirectorySeparator(path[0])) + else if (deviceSyntax) { - // UNC or simple rooted path (e.g. "\foo", NOT "\\?\C:\foo") + // Device path (e.g. "\\?\.", "\\.\") + // Skip any characters following the prefix that aren't a separator + i = DevicePrefixLength; + while (i < pathLength && !IsDirectorySeparator(path[i])) + i++; - i = 1; // Drive rooted (\foo) is one character - if (extendedUncSyntax || (pathLength > 1 && IsDirectorySeparator(path[1]))) - { - // UNC (\\?\UNC\ or \\), scan past the next two directory separators at most - // (e.g. to \\?\UNC\Server\Share or \\Server\Share\) - i = uncRootLength; - int n = 2; // Maximum separators to skip - while (i < pathLength && (!IsDirectorySeparator(path[i]) || --n > 0)) i++; - } + // If there is another separator take it, as long as we have had at least one + // non-separator after the prefix (e.g. don't take "\\?\\", but take "\\?\a\") + if (i < pathLength && i > DevicePrefixLength && IsDirectorySeparator(path[i])) + i++; } - else if (pathLength >= volumeSeparatorLength && path[volumeSeparatorLength - 1] == VolumeSeparatorChar) + else if (pathLength >= 2 + && path[1] == VolumeSeparatorChar + && IsValidDriveChar(path[0])) { - // Path is at least longer than where we expect a colon, and has a colon (\\?\A:, A:) - // If the colon is followed by a directory separator, move past it - i = volumeSeparatorLength; - if (pathLength >= volumeSeparatorLength + 1 && IsDirectorySeparator(path[volumeSeparatorLength])) i++; + // Valid drive specified path ("C:", "D:", etc.) + i = 2; + + // If the colon is followed by a directory separator, move past it (e.g "C:\") + if (pathLength > 2 && IsDirectorySeparator(path[2])) + i++; } + return i; } - private unsafe static bool StartsWithOrdinal(char* source, int sourceLength, string value) + private static bool StartsWithOrdinal(ReadOnlySpan source, string value) { - if (sourceLength < value.Length) return false; + if (source.Length < value.Length) + return false; + for (int i = 0; i < value.Length; i++) { - if (value[i] != source[i]) return false; + if (value[i] != source[i]) + return false; } return true; } @@ -249,7 +295,7 @@ namespace System.IO /// for C: (rooted, but relative). "C:\a" is rooted and not relative (the current directory /// will not be used to modify the path). /// - internal static bool IsPartiallyQualified(string path) + internal static bool IsPartiallyQualified(ReadOnlySpan path) { if (path.Length < 2) { @@ -275,29 +321,6 @@ namespace System.IO && IsValidDriveChar(path[0])); } - /// - /// Returns the characters to skip at the start of the path if it starts with space(s) and a drive or directory separator. - /// (examples are " C:", " \") - /// This is a legacy behavior of Path.GetFullPath(). - /// - /// - /// Note that this conflicts with IsPathRooted() which doesn't (and never did) such a skip. - /// - internal static int PathStartSkip(string path) - { - int startIndex = 0; - while (startIndex < path.Length && path[startIndex] == ' ') startIndex++; - - if (startIndex > 0 && (startIndex < path.Length && IsDirectorySeparator(path[startIndex])) - || (startIndex + 1 < path.Length && path[startIndex + 1] == ':' && IsValidDriveChar(path[startIndex]))) - { - // Go ahead and skip spaces as we're either " C:" or " \" - return startIndex; - } - - return 0; - } - /// /// True if the given character is a directory separator. /// @@ -341,34 +364,33 @@ namespace System.IO /// internal static string NormalizeDirectorySeparators(string path) { - if (string.IsNullOrEmpty(path)) return path; + if (string.IsNullOrEmpty(path)) + return path; char current; - int start = PathStartSkip(path); - if (start == 0) + // Make a pass to see if we need to normalize so we can potentially skip allocating + bool normalized = true; + + for (int i = 0; i < path.Length; i++) { - // Make a pass to see if we need to normalize so we can potentially skip allocating - bool normalized = true; - - for (int i = 0; i < path.Length; i++) + current = path[i]; + if (IsDirectorySeparator(current) + && (current != DirectorySeparatorChar + // Check for sequential separators past the first position (we need to keep initial two for UNC/extended) + || (i > 0 && i + 1 < path.Length && IsDirectorySeparator(path[i + 1])))) { - current = path[i]; - if (IsDirectorySeparator(current) - && (current != DirectorySeparatorChar - // Check for sequential separators past the first position (we need to keep initial two for UNC/extended) - || (i > 0 && i + 1 < path.Length && IsDirectorySeparator(path[i + 1])))) - { - normalized = false; - break; - } + normalized = false; + break; } - - if (normalized) return path; } + if (normalized) + return path; + StringBuilder builder = new StringBuilder(path.Length); + int start = 0; if (IsDirectorySeparator(path[start])) { start++; @@ -398,23 +420,14 @@ namespace System.IO return builder.ToString(); } - /// - /// Returns true if the character is a directory or volume separator. - /// - /// The character to test. - internal static bool IsDirectoryOrVolumeSeparator(char ch) - { - return IsDirectorySeparator(ch) || VolumeSeparatorChar == ch; - } - /// /// Returns true if the path is effectively empty for the current OS. /// For unix, this is empty or null. For Windows, this is empty, null, or /// just spaces ((char)32). /// - internal static bool IsEffectivelyEmpty(string path) + internal static bool IsEffectivelyEmpty(ReadOnlySpan path) { - if (string.IsNullOrEmpty(path)) + if (path.IsEmpty) return true; foreach (char c in path) diff --git a/external/corert/src/System.Private.CoreLib/shared/System/IO/PathInternal.cs b/external/corert/src/System.Private.CoreLib/shared/System/IO/PathInternal.cs index bfd69e9251..eb06c2608c 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/IO/PathInternal.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/IO/PathInternal.cs @@ -2,45 +2,37 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Diagnostics; -using System.Text; - namespace System.IO { /// Contains internal path helpers that are shared between many projects. internal static partial class PathInternal { - /// - /// Returns the start index of the filename - /// in the given path, or 0 if no directory - /// or volume separator is found. - /// - /// The path in which to find the index of the filename. - /// - /// This method returns path.Length for - /// inputs like "/usr/foo/" on Unix. As such, - /// it is not safe for being used to index - /// the string without additional verification. - /// - internal static int FindFileNameIndex(string path) - { - Debug.Assert(path != null); - - for (int i = path.Length - 1; i >= 0; i--) - { - char ch = path[i]; - if (IsDirectoryOrVolumeSeparator(ch)) - return i + 1; - } - - return 0; // the whole path is the filename - } - /// /// Returns true if the path ends in a directory separator. /// - internal static bool EndsInDirectorySeparator(string path) => - !string.IsNullOrEmpty(path) && IsDirectorySeparator(path[path.Length - 1]); + internal static bool EndsInDirectorySeparator(ReadOnlySpan path) + => path.Length > 0 && IsDirectorySeparator(path[path.Length - 1]); + + /// + /// Returns true if the path starts in a directory separator. + /// + internal static bool StartsWithDirectorySeparator(ReadOnlySpan path) => path.Length > 0 && IsDirectorySeparator(path[0]); + + internal static string EnsureTrailingSeparator(string path) + => EndsInDirectorySeparator(path) ? path : path + DirectorySeparatorCharAsString; + + internal static string TrimEndingDirectorySeparator(string path) => + EndsInDirectorySeparator(path) && !IsRoot(path) ? + path.Substring(0, path.Length - 1) : + path; + + internal static ReadOnlySpan TrimEndingDirectorySeparator(ReadOnlySpan path) => + EndsInDirectorySeparator(path) && !IsRoot(path) ? + path.Slice(0, path.Length - 1) : + path; + + internal static bool IsRoot(ReadOnlySpan path) + => path.Length == GetRootLength(path); /// /// Get the common path length from the start of the string. @@ -114,26 +106,5 @@ namespace System.IO length: firstRootLength, comparisonType: comparisonType) == 0; } - - /// - /// Returns false for ".." unless it is specified as a part of a valid File/Directory name. - /// (Used to avoid moving up directories.) - /// - /// Valid: a..b abc..d - /// Invalid: ..ab ab.. .. abc..d\abc.. - /// - internal static void CheckSearchPattern(string searchPattern) - { - int index; - while ((index = searchPattern.IndexOf("..", StringComparison.Ordinal)) != -1) - { - // Terminal ".." . Files names cannot end in ".." - if (index + 2 == searchPattern.Length - || IsDirectorySeparator(searchPattern[index + 2])) - throw new ArgumentException(SR.Format(SR.Arg_InvalidSearchPattern, searchPattern)); - - searchPattern = searchPattern.Substring(index + 2); - } - } } } diff --git a/external/corert/src/System.Private.CoreLib/shared/System/IO/StreamReader.cs b/external/corert/src/System.Private.CoreLib/shared/System/IO/StreamReader.cs new file mode 100644 index 0000000000..22ec6e645b --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/shared/System/IO/StreamReader.cs @@ -0,0 +1,1422 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace System.IO +{ + // This class implements a TextReader for reading characters to a Stream. + // This is designed for character input in a particular Encoding, + // whereas the Stream class is designed for byte input and output. + public class StreamReader : TextReader + { + // StreamReader.Null is threadsafe. + public new static readonly StreamReader Null = new NullStreamReader(); + + // Using a 1K byte buffer and a 4K FileStream buffer works out pretty well + // perf-wise. On even a 40 MB text file, any perf loss by using a 4K + // buffer is negated by the win of allocating a smaller byte[], which + // saves construction time. This does break adaptive buffering, + // but this is slightly faster. + private const int DefaultBufferSize = 1024; // Byte buffer size + private const int DefaultFileStreamBufferSize = 4096; + private const int MinBufferSize = 128; + + private Stream _stream; + private Encoding _encoding; + private Decoder _decoder; + private byte[] _byteBuffer; + private char[] _charBuffer; + private int _charPos; + private int _charLen; + // Record the number of valid bytes in the byteBuffer, for a few checks. + private int _byteLen; + // This is used only for preamble detection + private int _bytePos; + + // This is the maximum number of chars we can get from one call to + // ReadBuffer. Used so ReadBuffer can tell when to copy data into + // a user's char[] directly, instead of our internal char[]. + private int _maxCharsPerBuffer; + + // We will support looking for byte order marks in the stream and trying + // to decide what the encoding might be from the byte order marks, IF they + // exist. But that's all we'll do. + private bool _detectEncoding; + + // Whether we must still check for the encoding's given preamble at the + // beginning of this file. + private bool _checkPreamble; + + // Whether the stream is most likely not going to give us back as much + // data as we want the next time we call it. We must do the computation + // before we do any byte order mark handling and save the result. Note + // that we need this to allow users to handle streams used for an + // interactive protocol, where they block waiting for the remote end + // to send a response, like logging in on a Unix machine. + private bool _isBlocked; + + // The intent of this field is to leave open the underlying stream when + // disposing of this StreamReader. A name like _leaveOpen is better, + // but this type is serializable, and this field's name was _closable. + private bool _closable; // Whether to close the underlying stream. + + // We don't guarantee thread safety on StreamReader, but we should at + // least prevent users from trying to read anything while an Async + // read from the same thread is in progress. + private volatile Task _asyncReadTask; + + private void CheckAsyncTaskInProgress() + { + // We are not locking the access to _asyncReadTask because this is not meant to guarantee thread safety. + // We are simply trying to deter calling any Read APIs while an async Read from the same thread is in progress. + + Task t = _asyncReadTask; + + if (t != null && !t.IsCompleted) + { + throw new InvalidOperationException(SR.InvalidOperation_AsyncIOInProgress); + } + } + + // StreamReader by default will ignore illegal UTF8 characters. We don't want to + // throw here because we want to be able to read ill-formed data without choking. + // The high level goal is to be tolerant of encoding errors when we read and very strict + // when we write. Hence, default StreamWriter encoding will throw on error. + + internal StreamReader() + { + } + + public StreamReader(Stream stream) + : this(stream, true) + { + } + + public StreamReader(Stream stream, bool detectEncodingFromByteOrderMarks) + : this(stream, Encoding.UTF8, detectEncodingFromByteOrderMarks, DefaultBufferSize, false) + { + } + + public StreamReader(Stream stream, Encoding encoding) + : this(stream, encoding, true, DefaultBufferSize, false) + { + } + + public StreamReader(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks) + : this(stream, encoding, detectEncodingFromByteOrderMarks, DefaultBufferSize, false) + { + } + + // Creates a new StreamReader for the given stream. The + // character encoding is set by encoding and the buffer size, + // in number of 16-bit characters, is set by bufferSize. + // + // Note that detectEncodingFromByteOrderMarks is a very + // loose attempt at detecting the encoding by looking at the first + // 3 bytes of the stream. It will recognize UTF-8, little endian + // unicode, and big endian unicode text, but that's it. If neither + // of those three match, it will use the Encoding you provided. + // + public StreamReader(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize) + : this(stream, encoding, detectEncodingFromByteOrderMarks, bufferSize, false) + { + } + + public StreamReader(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize, bool leaveOpen) + { + if (stream == null || encoding == null) + { + throw new ArgumentNullException(stream == null ? nameof(stream) : nameof(encoding)); + } + if (!stream.CanRead) + { + throw new ArgumentException(SR.Argument_StreamNotReadable); + } + if (bufferSize <= 0) + { + throw new ArgumentOutOfRangeException(nameof(bufferSize), SR.ArgumentOutOfRange_NeedPosNum); + } + + Init(stream, encoding, detectEncodingFromByteOrderMarks, bufferSize, leaveOpen); + } + + public StreamReader(string path) + : this(path, true) + { + } + + public StreamReader(string path, bool detectEncodingFromByteOrderMarks) + : this(path, Encoding.UTF8, detectEncodingFromByteOrderMarks, DefaultBufferSize) + { + } + + public StreamReader(string path, Encoding encoding) + : this(path, encoding, true, DefaultBufferSize) + { + } + + public StreamReader(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks) + : this(path, encoding, detectEncodingFromByteOrderMarks, DefaultBufferSize) + { + } + + public StreamReader(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize) + { + if (path == null) + throw new ArgumentNullException(nameof(path)); + if (encoding == null) + throw new ArgumentNullException(nameof(encoding)); + if (path.Length == 0) + throw new ArgumentException(SR.Argument_EmptyPath); + if (bufferSize <= 0) + throw new ArgumentOutOfRangeException(nameof(bufferSize), SR.ArgumentOutOfRange_NeedPosNum); + + Stream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, + DefaultFileStreamBufferSize, FileOptions.SequentialScan); + Init(stream, encoding, detectEncodingFromByteOrderMarks, bufferSize, leaveOpen: false); + } + + private void Init(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize, bool leaveOpen) + { + _stream = stream; + _encoding = encoding; + _decoder = encoding.GetDecoder(); + if (bufferSize < MinBufferSize) + { + bufferSize = MinBufferSize; + } + + _byteBuffer = new byte[bufferSize]; + _maxCharsPerBuffer = encoding.GetMaxCharCount(bufferSize); + _charBuffer = new char[_maxCharsPerBuffer]; + _byteLen = 0; + _bytePos = 0; + _detectEncoding = detectEncodingFromByteOrderMarks; + _checkPreamble = encoding.Preamble.Length > 0; + _isBlocked = false; + _closable = !leaveOpen; + } + + // Init used by NullStreamReader, to delay load encoding + internal void Init(Stream stream) + { + _stream = stream; + _closable = true; + } + + public override void Close() + { + Dispose(true); + } + + protected override void Dispose(bool disposing) + { + // Dispose of our resources if this StreamReader is closable. + // Note that Console.In should be left open. + try + { + // Note that Stream.Close() can potentially throw here. So we need to + // ensure cleaning up internal resources, inside the finally block. + if (!LeaveOpen && disposing && (_stream != null)) + { + _stream.Close(); + } + } + finally + { + if (!LeaveOpen && (_stream != null)) + { + _stream = null; + _encoding = null; + _decoder = null; + _byteBuffer = null; + _charBuffer = null; + _charPos = 0; + _charLen = 0; + base.Dispose(disposing); + } + } + } + + public virtual Encoding CurrentEncoding + { + get { return _encoding; } + } + + public virtual Stream BaseStream + { + get { return _stream; } + } + + internal bool LeaveOpen + { + get { return !_closable; } + } + + // DiscardBufferedData tells StreamReader to throw away its internal + // buffer contents. This is useful if the user needs to seek on the + // underlying stream to a known location then wants the StreamReader + // to start reading from this new point. This method should be called + // very sparingly, if ever, since it can lead to very poor performance. + // However, it may be the only way of handling some scenarios where + // users need to re-read the contents of a StreamReader a second time. + public void DiscardBufferedData() + { + CheckAsyncTaskInProgress(); + + _byteLen = 0; + _charLen = 0; + _charPos = 0; + // in general we'd like to have an invariant that encoding isn't null. However, + // for startup improvements for NullStreamReader, we want to delay load encoding. + if (_encoding != null) + { + _decoder = _encoding.GetDecoder(); + } + _isBlocked = false; + } + + public bool EndOfStream + { + get + { + if (_stream == null) + { + throw new ObjectDisposedException(null, SR.ObjectDisposed_ReaderClosed); + } + + CheckAsyncTaskInProgress(); + + if (_charPos < _charLen) + { + return false; + } + + // This may block on pipes! + int numRead = ReadBuffer(); + return numRead == 0; + } + } + + public override int Peek() + { + if (_stream == null) + { + throw new ObjectDisposedException(null, SR.ObjectDisposed_ReaderClosed); + } + + CheckAsyncTaskInProgress(); + + if (_charPos == _charLen) + { + if (_isBlocked || ReadBuffer() == 0) + { + return -1; + } + } + return _charBuffer[_charPos]; + } + + public override int Read() + { + if (_stream == null) + { + throw new ObjectDisposedException(null, SR.ObjectDisposed_ReaderClosed); + } + + CheckAsyncTaskInProgress(); + + if (_charPos == _charLen) + { + if (ReadBuffer() == 0) + { + return -1; + } + } + int result = _charBuffer[_charPos]; + _charPos++; + return result; + } + + public override int Read(char[] buffer, int index, int count) + { + if (buffer == null) + { + throw new ArgumentNullException(nameof(buffer), SR.ArgumentNull_Buffer); + } + if (index < 0 || count < 0) + { + throw new ArgumentOutOfRangeException(index < 0 ? nameof(index) : nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); + } + if (buffer.Length - index < count) + { + throw new ArgumentException(SR.Argument_InvalidOffLen); + } + + return ReadSpan(new Span(buffer, index, count)); + } + + public override int Read(Span buffer) => + GetType() == typeof(StreamReader) ? ReadSpan(buffer) : + base.Read(buffer); // Defer to Read(char[], ...) if a derived type may have previously overridden it + + private int ReadSpan(Span buffer) + { + if (_stream == null) + { + throw new ObjectDisposedException(null, SR.ObjectDisposed_ReaderClosed); + } + + CheckAsyncTaskInProgress(); + + int charsRead = 0; + // As a perf optimization, if we had exactly one buffer's worth of + // data read in, let's try writing directly to the user's buffer. + bool readToUserBuffer = false; + int count = buffer.Length; + while (count > 0) + { + int n = _charLen - _charPos; + if (n == 0) + { + n = ReadBuffer(buffer.Slice(charsRead), out readToUserBuffer); + } + if (n == 0) + { + break; // We're at EOF + } + if (n > count) + { + n = count; + } + if (!readToUserBuffer) + { + new Span(_charBuffer, _charPos, n).CopyTo(buffer.Slice(charsRead)); + _charPos += n; + } + + charsRead += n; + count -= n; + // This function shouldn't block for an indefinite amount of time, + // or reading from a network stream won't work right. If we got + // fewer bytes than we requested, then we want to break right here. + if (_isBlocked) + { + break; + } + } + + return charsRead; + } + + public override string ReadToEnd() + { + if (_stream == null) + { + throw new ObjectDisposedException(null, SR.ObjectDisposed_ReaderClosed); + } + + CheckAsyncTaskInProgress(); + + // Call ReadBuffer, then pull data out of charBuffer. + StringBuilder sb = new StringBuilder(_charLen - _charPos); + do + { + sb.Append(_charBuffer, _charPos, _charLen - _charPos); + _charPos = _charLen; // Note we consumed these characters + ReadBuffer(); + } while (_charLen > 0); + return sb.ToString(); + } + + public override int ReadBlock(char[] buffer, int index, int count) + { + if (buffer == null) + { + throw new ArgumentNullException(nameof(buffer), SR.ArgumentNull_Buffer); + } + if (index < 0 || count < 0) + { + throw new ArgumentOutOfRangeException(index < 0 ? nameof(index) : nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); + } + if (buffer.Length - index < count) + { + throw new ArgumentException(SR.Argument_InvalidOffLen); + } + if (_stream == null) + { + throw new ObjectDisposedException(null, SR.ObjectDisposed_ReaderClosed); + } + + CheckAsyncTaskInProgress(); + + return base.ReadBlock(buffer, index, count); + } + + public override int ReadBlock(Span buffer) + { + if (GetType() != typeof(StreamReader)) + { + // Defer to Read(char[], ...) if a derived type may have previously overridden it. + return base.ReadBlock(buffer); + } + + int i, n = 0; + do + { + i = ReadSpan(buffer.Slice(n)); + n += i; + } while (i > 0 && n < buffer.Length); + return n; + } + + // Trims n bytes from the front of the buffer. + private void CompressBuffer(int n) + { + Debug.Assert(_byteLen >= n, "CompressBuffer was called with a number of bytes greater than the current buffer length. Are two threads using this StreamReader at the same time?"); + Buffer.BlockCopy(_byteBuffer, n, _byteBuffer, 0, _byteLen - n); + _byteLen -= n; + } + + private void DetectEncoding() + { + if (_byteLen < 2) + { + return; + } + _detectEncoding = false; + bool changedEncoding = false; + if (_byteBuffer[0] == 0xFE && _byteBuffer[1] == 0xFF) + { + // Big Endian Unicode + + _encoding = Encoding.BigEndianUnicode; + CompressBuffer(2); + changedEncoding = true; + } + + else if (_byteBuffer[0] == 0xFF && _byteBuffer[1] == 0xFE) + { + // Little Endian Unicode, or possibly little endian UTF32 + if (_byteLen < 4 || _byteBuffer[2] != 0 || _byteBuffer[3] != 0) + { + _encoding = Encoding.Unicode; + CompressBuffer(2); + changedEncoding = true; + } + else + { + _encoding = Encoding.UTF32; + CompressBuffer(4); + changedEncoding = true; + } + } + + else if (_byteLen >= 3 && _byteBuffer[0] == 0xEF && _byteBuffer[1] == 0xBB && _byteBuffer[2] == 0xBF) + { + // UTF-8 + _encoding = Encoding.UTF8; + CompressBuffer(3); + changedEncoding = true; + } + else if (_byteLen >= 4 && _byteBuffer[0] == 0 && _byteBuffer[1] == 0 && + _byteBuffer[2] == 0xFE && _byteBuffer[3] == 0xFF) + { + // Big Endian UTF32 + _encoding = new UTF32Encoding(bigEndian: true, byteOrderMark: true); + CompressBuffer(4); + changedEncoding = true; + } + else if (_byteLen == 2) + { + _detectEncoding = true; + } + // Note: in the future, if we change this algorithm significantly, + // we can support checking for the preamble of the given encoding. + + if (changedEncoding) + { + _decoder = _encoding.GetDecoder(); + int newMaxCharsPerBuffer = _encoding.GetMaxCharCount(_byteBuffer.Length); + if (newMaxCharsPerBuffer > _maxCharsPerBuffer) + { + _charBuffer = new char[newMaxCharsPerBuffer]; + } + _maxCharsPerBuffer = newMaxCharsPerBuffer; + } + } + + // Trims the preamble bytes from the byteBuffer. This routine can be called multiple times + // and we will buffer the bytes read until the preamble is matched or we determine that + // there is no match. If there is no match, every byte read previously will be available + // for further consumption. If there is a match, we will compress the buffer for the + // leading preamble bytes + private bool IsPreamble() + { + if (!_checkPreamble) + { + return _checkPreamble; + } + + ReadOnlySpan preamble = _encoding.Preamble; + + Debug.Assert(_bytePos <= preamble.Length, "_compressPreamble was called with the current bytePos greater than the preamble buffer length. Are two threads using this StreamReader at the same time?"); + int len = (_byteLen >= (preamble.Length)) ? (preamble.Length - _bytePos) : (_byteLen - _bytePos); + + for (int i = 0; i < len; i++, _bytePos++) + { + if (_byteBuffer[_bytePos] != preamble[_bytePos]) + { + _bytePos = 0; + _checkPreamble = false; + break; + } + } + + Debug.Assert(_bytePos <= preamble.Length, "possible bug in _compressPreamble. Are two threads using this StreamReader at the same time?"); + + if (_checkPreamble) + { + if (_bytePos == preamble.Length) + { + // We have a match + CompressBuffer(preamble.Length); + _bytePos = 0; + _checkPreamble = false; + _detectEncoding = false; + } + } + + return _checkPreamble; + } + + internal virtual int ReadBuffer() + { + _charLen = 0; + _charPos = 0; + + if (!_checkPreamble) + { + _byteLen = 0; + } + + do + { + if (_checkPreamble) + { + Debug.Assert(_bytePos <= _encoding.Preamble.Length, "possible bug in _compressPreamble. Are two threads using this StreamReader at the same time?"); + int len = _stream.Read(_byteBuffer, _bytePos, _byteBuffer.Length - _bytePos); + Debug.Assert(len >= 0, "Stream.Read returned a negative number! This is a bug in your stream class."); + + if (len == 0) + { + // EOF but we might have buffered bytes from previous + // attempt to detect preamble that needs to be decoded now + if (_byteLen > 0) + { + _charLen += _decoder.GetChars(_byteBuffer, 0, _byteLen, _charBuffer, _charLen); + // Need to zero out the byteLen after we consume these bytes so that we don't keep infinitely hitting this code path + _bytePos = _byteLen = 0; + } + + return _charLen; + } + + _byteLen += len; + } + else + { + Debug.Assert(_bytePos == 0, "bytePos can be non zero only when we are trying to _checkPreamble. Are two threads using this StreamReader at the same time?"); + _byteLen = _stream.Read(_byteBuffer, 0, _byteBuffer.Length); + Debug.Assert(_byteLen >= 0, "Stream.Read returned a negative number! This is a bug in your stream class."); + + if (_byteLen == 0) // We're at EOF + { + return _charLen; + } + } + + // _isBlocked == whether we read fewer bytes than we asked for. + // Note we must check it here because CompressBuffer or + // DetectEncoding will change byteLen. + _isBlocked = (_byteLen < _byteBuffer.Length); + + // Check for preamble before detect encoding. This is not to override the + // user supplied Encoding for the one we implicitly detect. The user could + // customize the encoding which we will loose, such as ThrowOnError on UTF8 + if (IsPreamble()) + { + continue; + } + + // If we're supposed to detect the encoding and haven't done so yet, + // do it. Note this may need to be called more than once. + if (_detectEncoding && _byteLen >= 2) + { + DetectEncoding(); + } + + _charLen += _decoder.GetChars(_byteBuffer, 0, _byteLen, _charBuffer, _charLen); + } while (_charLen == 0); + //Console.WriteLine("ReadBuffer called. chars: "+charLen); + return _charLen; + } + + + // This version has a perf optimization to decode data DIRECTLY into the + // user's buffer, bypassing StreamReader's own buffer. + // This gives a > 20% perf improvement for our encodings across the board, + // but only when asking for at least the number of characters that one + // buffer's worth of bytes could produce. + // This optimization, if run, will break SwitchEncoding, so we must not do + // this on the first call to ReadBuffer. + private int ReadBuffer(Span userBuffer, out bool readToUserBuffer) + { + _charLen = 0; + _charPos = 0; + + if (!_checkPreamble) + { + _byteLen = 0; + } + + int charsRead = 0; + + // As a perf optimization, we can decode characters DIRECTLY into a + // user's char[]. We absolutely must not write more characters + // into the user's buffer than they asked for. Calculating + // encoding.GetMaxCharCount(byteLen) each time is potentially very + // expensive - instead, cache the number of chars a full buffer's + // worth of data may produce. Yes, this makes the perf optimization + // less aggressive, in that all reads that asked for fewer than AND + // returned fewer than _maxCharsPerBuffer chars won't get the user + // buffer optimization. This affects reads where the end of the + // Stream comes in the middle somewhere, and when you ask for + // fewer chars than your buffer could produce. + readToUserBuffer = userBuffer.Length >= _maxCharsPerBuffer; + + do + { + Debug.Assert(charsRead == 0); + + if (_checkPreamble) + { + Debug.Assert(_bytePos <= _encoding.Preamble.Length, "possible bug in _compressPreamble. Are two threads using this StreamReader at the same time?"); + int len = _stream.Read(_byteBuffer, _bytePos, _byteBuffer.Length - _bytePos); + Debug.Assert(len >= 0, "Stream.Read returned a negative number! This is a bug in your stream class."); + + if (len == 0) + { + // EOF but we might have buffered bytes from previous + // attempt to detect preamble that needs to be decoded now + if (_byteLen > 0) + { + if (readToUserBuffer) + { + charsRead = _decoder.GetChars(new ReadOnlySpan(_byteBuffer, 0, _byteLen), userBuffer.Slice(charsRead), flush: false); + _charLen = 0; // StreamReader's buffer is empty. + } + else + { + charsRead = _decoder.GetChars(_byteBuffer, 0, _byteLen, _charBuffer, charsRead); + _charLen += charsRead; // Number of chars in StreamReader's buffer. + } + } + + return charsRead; + } + + _byteLen += len; + } + else + { + Debug.Assert(_bytePos == 0, "bytePos can be non zero only when we are trying to _checkPreamble. Are two threads using this StreamReader at the same time?"); + + _byteLen = _stream.Read(_byteBuffer, 0, _byteBuffer.Length); + + Debug.Assert(_byteLen >= 0, "Stream.Read returned a negative number! This is a bug in your stream class."); + + if (_byteLen == 0) // EOF + { + break; + } + } + + // _isBlocked == whether we read fewer bytes than we asked for. + // Note we must check it here because CompressBuffer or + // DetectEncoding will change byteLen. + _isBlocked = (_byteLen < _byteBuffer.Length); + + // Check for preamble before detect encoding. This is not to override the + // user supplied Encoding for the one we implicitly detect. The user could + // customize the encoding which we will loose, such as ThrowOnError on UTF8 + // Note: we don't need to recompute readToUserBuffer optimization as IsPreamble + // doesn't change the encoding or affect _maxCharsPerBuffer + if (IsPreamble()) + { + continue; + } + + // On the first call to ReadBuffer, if we're supposed to detect the encoding, do it. + if (_detectEncoding && _byteLen >= 2) + { + DetectEncoding(); + // DetectEncoding changes some buffer state. Recompute this. + readToUserBuffer = userBuffer.Length >= _maxCharsPerBuffer; + } + + _charPos = 0; + if (readToUserBuffer) + { + charsRead += _decoder.GetChars(new ReadOnlySpan(_byteBuffer, 0, _byteLen), userBuffer.Slice(charsRead), flush:false); + _charLen = 0; // StreamReader's buffer is empty. + } + else + { + charsRead = _decoder.GetChars(_byteBuffer, 0, _byteLen, _charBuffer, charsRead); + _charLen += charsRead; // Number of chars in StreamReader's buffer. + } + } while (charsRead == 0); + + _isBlocked &= charsRead < userBuffer.Length; + + //Console.WriteLine("ReadBuffer: charsRead: "+charsRead+" readToUserBuffer: "+readToUserBuffer); + return charsRead; + } + + + // Reads a line. A line is defined as a sequence of characters followed by + // a carriage return ('\r'), a line feed ('\n'), or a carriage return + // immediately followed by a line feed. The resulting string does not + // contain the terminating carriage return and/or line feed. The returned + // value is null if the end of the input stream has been reached. + // + public override string ReadLine() + { + if (_stream == null) + { + throw new ObjectDisposedException(null, SR.ObjectDisposed_ReaderClosed); + } + + CheckAsyncTaskInProgress(); + + if (_charPos == _charLen) + { + if (ReadBuffer() == 0) + { + return null; + } + } + + StringBuilder sb = null; + do + { + int i = _charPos; + do + { + char ch = _charBuffer[i]; + // Note the following common line feed chars: + // \n - UNIX \r\n - DOS \r - Mac + if (ch == '\r' || ch == '\n') + { + string s; + if (sb != null) + { + sb.Append(_charBuffer, _charPos, i - _charPos); + s = sb.ToString(); + } + else + { + s = new string(_charBuffer, _charPos, i - _charPos); + } + _charPos = i + 1; + if (ch == '\r' && (_charPos < _charLen || ReadBuffer() > 0)) + { + if (_charBuffer[_charPos] == '\n') + { + _charPos++; + } + } + return s; + } + i++; + } while (i < _charLen); + i = _charLen - _charPos; + if (sb == null) + { + sb = new StringBuilder(i + 80); + } + sb.Append(_charBuffer, _charPos, i); + } while (ReadBuffer() > 0); + return sb.ToString(); + } + + #region Task based Async APIs + public override Task ReadLineAsync() + { + // If we have been inherited into a subclass, the following implementation could be incorrect + // since it does not call through to Read() which a subclass might have overridden. + // To be safe we will only use this implementation in cases where we know it is safe to do so, + // and delegate to our base class (which will call into Read) when we are not sure. + if (GetType() != typeof(StreamReader)) + { + return base.ReadLineAsync(); + } + + if (_stream == null) + { + throw new ObjectDisposedException(null, SR.ObjectDisposed_ReaderClosed); + } + + CheckAsyncTaskInProgress(); + + Task task = ReadLineAsyncInternal(); + _asyncReadTask = task; + + return task; + } + + private async Task ReadLineAsyncInternal() + { + if (_charPos == _charLen && (await ReadBufferAsync().ConfigureAwait(false)) == 0) + { + return null; + } + + StringBuilder sb = null; + + do + { + char[] tmpCharBuffer = _charBuffer; + int tmpCharLen = _charLen; + int tmpCharPos = _charPos; + int i = tmpCharPos; + + do + { + char ch = tmpCharBuffer[i]; + + // Note the following common line feed chars: + // \n - UNIX \r\n - DOS \r - Mac + if (ch == '\r' || ch == '\n') + { + string s; + + if (sb != null) + { + sb.Append(tmpCharBuffer, tmpCharPos, i - tmpCharPos); + s = sb.ToString(); + } + else + { + s = new string(tmpCharBuffer, tmpCharPos, i - tmpCharPos); + } + + _charPos = tmpCharPos = i + 1; + + if (ch == '\r' && (tmpCharPos < tmpCharLen || (await ReadBufferAsync().ConfigureAwait(false)) > 0)) + { + tmpCharPos = _charPos; + if (_charBuffer[tmpCharPos] == '\n') + { + _charPos = ++tmpCharPos; + } + } + + return s; + } + + i++; + } while (i < tmpCharLen); + + i = tmpCharLen - tmpCharPos; + if (sb == null) + { + sb = new StringBuilder(i + 80); + } + sb.Append(tmpCharBuffer, tmpCharPos, i); + } while (await ReadBufferAsync().ConfigureAwait(false) > 0); + + return sb.ToString(); + } + + public override Task ReadToEndAsync() + { + // If we have been inherited into a subclass, the following implementation could be incorrect + // since it does not call through to Read() which a subclass might have overridden. + // To be safe we will only use this implementation in cases where we know it is safe to do so, + // and delegate to our base class (which will call into Read) when we are not sure. + if (GetType() != typeof(StreamReader)) + { + return base.ReadToEndAsync(); + } + + if (_stream == null) + { + throw new ObjectDisposedException(null, SR.ObjectDisposed_ReaderClosed); + } + + CheckAsyncTaskInProgress(); + + Task task = ReadToEndAsyncInternal(); + _asyncReadTask = task; + + return task; + } + + private async Task ReadToEndAsyncInternal() + { + // Call ReadBuffer, then pull data out of charBuffer. + StringBuilder sb = new StringBuilder(_charLen - _charPos); + do + { + int tmpCharPos = _charPos; + sb.Append(_charBuffer, tmpCharPos, _charLen - tmpCharPos); + _charPos = _charLen; // We consumed these characters + await ReadBufferAsync().ConfigureAwait(false); + } while (_charLen > 0); + + return sb.ToString(); + } + + public override Task ReadAsync(char[] buffer, int index, int count) + { + if (buffer == null) + { + throw new ArgumentNullException(nameof(buffer), SR.ArgumentNull_Buffer); + } + if (index < 0 || count < 0) + { + throw new ArgumentOutOfRangeException(index < 0 ? nameof(index) : nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); + } + if (buffer.Length - index < count) + { + throw new ArgumentException(SR.Argument_InvalidOffLen); + } + + // If we have been inherited into a subclass, the following implementation could be incorrect + // since it does not call through to Read() which a subclass might have overridden. + // To be safe we will only use this implementation in cases where we know it is safe to do so, + // and delegate to our base class (which will call into Read) when we are not sure. + if (GetType() != typeof(StreamReader)) + { + return base.ReadAsync(buffer, index, count); + } + + if (_stream == null) + { + throw new ObjectDisposedException(null, SR.ObjectDisposed_ReaderClosed); + } + + CheckAsyncTaskInProgress(); + + Task task = ReadAsyncInternal(new Memory(buffer, index, count), default).AsTask(); + _asyncReadTask = task; + + return task; + } + + public override ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default) + { + if (GetType() != typeof(StreamReader)) + { + // Ensure we use existing overrides if a class already overrode existing overloads. + return base.ReadAsync(buffer, cancellationToken); + } + + if (_stream == null) + { + throw new ObjectDisposedException(null, SR.ObjectDisposed_ReaderClosed); + } + + CheckAsyncTaskInProgress(); + + if (cancellationToken.IsCancellationRequested) + { + return new ValueTask(Task.FromCanceled(cancellationToken)); + } + + return ReadAsyncInternal(buffer, cancellationToken); + } + + internal override async ValueTask ReadAsyncInternal(Memory buffer, CancellationToken cancellationToken) + { + if (_charPos == _charLen && (await ReadBufferAsync().ConfigureAwait(false)) == 0) + { + return 0; + } + + int charsRead = 0; + + // As a perf optimization, if we had exactly one buffer's worth of + // data read in, let's try writing directly to the user's buffer. + bool readToUserBuffer = false; + + Byte[] tmpByteBuffer = _byteBuffer; + Stream tmpStream = _stream; + + int count = buffer.Length; + while (count > 0) + { + // n is the characters available in _charBuffer + int n = _charLen - _charPos; + + // charBuffer is empty, let's read from the stream + if (n == 0) + { + _charLen = 0; + _charPos = 0; + + if (!_checkPreamble) + { + _byteLen = 0; + } + + readToUserBuffer = count >= _maxCharsPerBuffer; + + // We loop here so that we read in enough bytes to yield at least 1 char. + // We break out of the loop if the stream is blocked (EOF is reached). + do + { + Debug.Assert(n == 0); + + if (_checkPreamble) + { + Debug.Assert(_bytePos <= _encoding.Preamble.Length, "possible bug in _compressPreamble. Are two threads using this StreamReader at the same time?"); + int tmpBytePos = _bytePos; + int len = await tmpStream.ReadAsync(new Memory(tmpByteBuffer, tmpBytePos, tmpByteBuffer.Length - tmpBytePos), cancellationToken).ConfigureAwait(false); + Debug.Assert(len >= 0, "Stream.Read returned a negative number! This is a bug in your stream class."); + + if (len == 0) + { + // EOF but we might have buffered bytes from previous + // attempts to detect preamble that needs to be decoded now + if (_byteLen > 0) + { + if (readToUserBuffer) + { + n = _decoder.GetChars(new ReadOnlySpan(tmpByteBuffer, 0, _byteLen), buffer.Span.Slice(charsRead), flush: false); + _charLen = 0; // StreamReader's buffer is empty. + } + else + { + n = _decoder.GetChars(tmpByteBuffer, 0, _byteLen, _charBuffer, 0); + _charLen += n; // Number of chars in StreamReader's buffer. + } + } + + // How can part of the preamble yield any chars? + Debug.Assert(n == 0); + + _isBlocked = true; + break; + } + else + { + _byteLen += len; + } + } + else + { + Debug.Assert(_bytePos == 0, "_bytePos can be non zero only when we are trying to _checkPreamble. Are two threads using this StreamReader at the same time?"); + + _byteLen = await tmpStream.ReadAsync(new Memory(tmpByteBuffer), cancellationToken).ConfigureAwait(false); + + Debug.Assert(_byteLen >= 0, "Stream.Read returned a negative number! This is a bug in your stream class."); + + if (_byteLen == 0) // EOF + { + _isBlocked = true; + break; + } + } + + // _isBlocked == whether we read fewer bytes than we asked for. + // Note we must check it here because CompressBuffer or + // DetectEncoding will change _byteLen. + _isBlocked = (_byteLen < tmpByteBuffer.Length); + + // Check for preamble before detect encoding. This is not to override the + // user supplied Encoding for the one we implicitly detect. The user could + // customize the encoding which we will loose, such as ThrowOnError on UTF8 + // Note: we don't need to recompute readToUserBuffer optimization as IsPreamble + // doesn't change the encoding or affect _maxCharsPerBuffer + if (IsPreamble()) + { + continue; + } + + // On the first call to ReadBuffer, if we're supposed to detect the encoding, do it. + if (_detectEncoding && _byteLen >= 2) + { + DetectEncoding(); + // DetectEncoding changes some buffer state. Recompute this. + readToUserBuffer = count >= _maxCharsPerBuffer; + } + + Debug.Assert(n == 0); + + _charPos = 0; + if (readToUserBuffer) + { + n += _decoder.GetChars(new ReadOnlySpan(tmpByteBuffer, 0, _byteLen), buffer.Span.Slice(charsRead), flush: false); + + // Why did the bytes yield no chars? + Debug.Assert(n > 0); + + _charLen = 0; // StreamReader's buffer is empty. + } + else + { + n = _decoder.GetChars(tmpByteBuffer, 0, _byteLen, _charBuffer, 0); + + // Why did the bytes yield no chars? + Debug.Assert(n > 0); + + _charLen += n; // Number of chars in StreamReader's buffer. + } + } while (n == 0); + + if (n == 0) + { + break; // We're at EOF + } + } // if (n == 0) + + // Got more chars in charBuffer than the user requested + if (n > count) + { + n = count; + } + + if (!readToUserBuffer) + { + new Span(_charBuffer, _charPos, n).CopyTo(buffer.Span.Slice(charsRead)); + _charPos += n; + } + + charsRead += n; + count -= n; + + // This function shouldn't block for an indefinite amount of time, + // or reading from a network stream won't work right. If we got + // fewer bytes than we requested, then we want to break right here. + if (_isBlocked) + { + break; + } + } // while (count > 0) + + return charsRead; + } + + public override Task ReadBlockAsync(char[] buffer, int index, int count) + { + if (buffer == null) + { + throw new ArgumentNullException(nameof(buffer), SR.ArgumentNull_Buffer); + } + if (index < 0 || count < 0) + { + throw new ArgumentOutOfRangeException(index < 0 ? nameof(index) : nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); + } + if (buffer.Length - index < count) + { + throw new ArgumentException(SR.Argument_InvalidOffLen); + } + + // If we have been inherited into a subclass, the following implementation could be incorrect + // since it does not call through to Read() which a subclass might have overridden. + // To be safe we will only use this implementation in cases where we know it is safe to do so, + // and delegate to our base class (which will call into Read) when we are not sure. + if (GetType() != typeof(StreamReader)) + { + return base.ReadBlockAsync(buffer, index, count); + } + + if (_stream == null) + { + throw new ObjectDisposedException(null, SR.ObjectDisposed_ReaderClosed); + } + + CheckAsyncTaskInProgress(); + + Task task = base.ReadBlockAsync(buffer, index, count); + _asyncReadTask = task; + + return task; + } + + public override ValueTask ReadBlockAsync(Memory buffer, CancellationToken cancellationToken = default) + { + if (GetType() != typeof(StreamReader)) + { + // If a derived type may have overridden ReadBlockAsync(char[], ...) before this overload + // was introduced, defer to it. + return base.ReadBlockAsync(buffer, cancellationToken); + } + + if (_stream == null) + { + throw new ObjectDisposedException(null, SR.ObjectDisposed_ReaderClosed); + } + + CheckAsyncTaskInProgress(); + + if (cancellationToken.IsCancellationRequested) + { + return new ValueTask(Task.FromCanceled(cancellationToken)); + } + + ValueTask vt = ReadBlockAsyncInternal(buffer, cancellationToken); + if (vt.IsCompletedSuccessfully) + { + return vt; + } + + Task t = vt.AsTask(); + _asyncReadTask = t; + return new ValueTask(t); + } + + private async Task ReadBufferAsync() + { + _charLen = 0; + _charPos = 0; + Byte[] tmpByteBuffer = _byteBuffer; + Stream tmpStream = _stream; + + if (!_checkPreamble) + { + _byteLen = 0; + } + do + { + if (_checkPreamble) + { + Debug.Assert(_bytePos <= _encoding.Preamble.Length, "possible bug in _compressPreamble. Are two threads using this StreamReader at the same time?"); + int tmpBytePos = _bytePos; + int len = await tmpStream.ReadAsync(new Memory(tmpByteBuffer, tmpBytePos, tmpByteBuffer.Length - tmpBytePos)).ConfigureAwait(false); + Debug.Assert(len >= 0, "Stream.Read returned a negative number! This is a bug in your stream class."); + + if (len == 0) + { + // EOF but we might have buffered bytes from previous + // attempt to detect preamble that needs to be decoded now + if (_byteLen > 0) + { + _charLen += _decoder.GetChars(tmpByteBuffer, 0, _byteLen, _charBuffer, _charLen); + // Need to zero out the _byteLen after we consume these bytes so that we don't keep infinitely hitting this code path + _bytePos = 0; _byteLen = 0; + } + + return _charLen; + } + + _byteLen += len; + } + else + { + Debug.Assert(_bytePos == 0, "_bytePos can be non zero only when we are trying to _checkPreamble. Are two threads using this StreamReader at the same time?"); + _byteLen = await tmpStream.ReadAsync(new Memory(tmpByteBuffer)).ConfigureAwait(false); + Debug.Assert(_byteLen >= 0, "Stream.Read returned a negative number! Bug in stream class."); + + if (_byteLen == 0) // We're at EOF + { + return _charLen; + } + } + + // _isBlocked == whether we read fewer bytes than we asked for. + // Note we must check it here because CompressBuffer or + // DetectEncoding will change _byteLen. + _isBlocked = (_byteLen < tmpByteBuffer.Length); + + // Check for preamble before detect encoding. This is not to override the + // user supplied Encoding for the one we implicitly detect. The user could + // customize the encoding which we will loose, such as ThrowOnError on UTF8 + if (IsPreamble()) + { + continue; + } + + // If we're supposed to detect the encoding and haven't done so yet, + // do it. Note this may need to be called more than once. + if (_detectEncoding && _byteLen >= 2) + { + DetectEncoding(); + } + + _charLen += _decoder.GetChars(tmpByteBuffer, 0, _byteLen, _charBuffer, _charLen); + } while (_charLen == 0); + + return _charLen; + } +#endregion + + + // No data, class doesn't need to be serializable. + // Note this class is threadsafe. + private class NullStreamReader : StreamReader + { + // Instantiating Encoding causes unnecessary perf hit. + internal NullStreamReader() + { + Init(Stream.Null); + } + + public override Stream BaseStream + { + get { return Stream.Null; } + } + + public override Encoding CurrentEncoding + { + get { return Encoding.Unicode; } + } + + protected override void Dispose(bool disposing) + { + // Do nothing - this is essentially unclosable. + } + + public override int Peek() + { + return -1; + } + + public override int Read() + { + return -1; + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override int Read(char[] buffer, int index, int count) + { + return 0; + } + + public override string ReadLine() + { + return null; + } + + public override string ReadToEnd() + { + return string.Empty; + } + + internal override int ReadBuffer() + { + return 0; + } + } + } +} diff --git a/external/corert/src/System.Private.CoreLib/shared/System/IO/StreamWriter.cs b/external/corert/src/System.Private.CoreLib/shared/System/IO/StreamWriter.cs new file mode 100644 index 0000000000..a376244280 --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/shared/System/IO/StreamWriter.cs @@ -0,0 +1,986 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace System.IO +{ + // This class implements a TextWriter for writing characters to a Stream. + // This is designed for character output in a particular Encoding, + // whereas the Stream class is designed for byte input and output. + public class StreamWriter : TextWriter + { + // For UTF-8, the values of 1K for the default buffer size and 4K for the + // file stream buffer size are reasonable & give very reasonable + // performance for in terms of construction time for the StreamWriter and + // write perf. Note that for UTF-8, we end up allocating a 4K byte buffer, + // which means we take advantage of adaptive buffering code. + // The performance using UnicodeEncoding is acceptable. + private const int DefaultBufferSize = 1024; // char[] + private const int DefaultFileStreamBufferSize = 4096; + private const int MinBufferSize = 128; + + private const int DontCopyOnWriteLineThreshold = 512; + + // Bit bucket - Null has no backing store. Non closable. + public new static readonly StreamWriter Null = new StreamWriter(Stream.Null, UTF8NoBOM, MinBufferSize, true); + + private Stream _stream; + private Encoding _encoding; + private Encoder _encoder; + private byte[] _byteBuffer; + private char[] _charBuffer; + private int _charPos; + private int _charLen; + private bool _autoFlush; + private bool _haveWrittenPreamble; + private bool _closable; + + // We don't guarantee thread safety on StreamWriter, but we should at + // least prevent users from trying to write anything while an Async + // write from the same thread is in progress. + private volatile Task _asyncWriteTask; + + private void CheckAsyncTaskInProgress() + { + // We are not locking the access to _asyncWriteTask because this is not meant to guarantee thread safety. + // We are simply trying to deter calling any Write APIs while an async Write from the same thread is in progress. + + Task t = _asyncWriteTask; + + if (t != null && !t.IsCompleted) + throw new InvalidOperationException(SR.InvalidOperation_AsyncIOInProgress); + } + + // The high level goal is to be tolerant of encoding errors when we read and very strict + // when we write. Hence, default StreamWriter encoding will throw on encoding error. + // Note: when StreamWriter throws on invalid encoding chars (for ex, high surrogate character + // D800-DBFF without a following low surrogate character DC00-DFFF), it will cause the + // internal StreamWriter's state to be irrecoverable as it would have buffered the + // illegal chars and any subsequent call to Flush() would hit the encoding error again. + // Even Close() will hit the exception as it would try to flush the unwritten data. + // Maybe we can add a DiscardBufferedData() method to get out of such situation (like + // StreamReader though for different reason). Either way, the buffered data will be lost! + private static Encoding UTF8NoBOM => EncodingCache.UTF8NoBOM; + + + internal StreamWriter() : base(null) + { // Ask for CurrentCulture all the time + } + + public StreamWriter(Stream stream) + : this(stream, UTF8NoBOM, DefaultBufferSize, false) + { + } + + public StreamWriter(Stream stream, Encoding encoding) + : this(stream, encoding, DefaultBufferSize, false) + { + } + + // Creates a new StreamWriter for the given stream. The + // character encoding is set by encoding and the buffer size, + // in number of 16-bit characters, is set by bufferSize. + // + public StreamWriter(Stream stream, Encoding encoding, int bufferSize) + : this(stream, encoding, bufferSize, false) + { + } + + public StreamWriter(Stream stream, Encoding encoding, int bufferSize, bool leaveOpen) + : base(null) // Ask for CurrentCulture all the time + { + if (stream == null || encoding == null) + { + throw new ArgumentNullException(stream == null ? nameof(stream) : nameof(encoding)); + } + if (!stream.CanWrite) + { + throw new ArgumentException(SR.Argument_StreamNotWritable); + } + if (bufferSize <= 0) + { + throw new ArgumentOutOfRangeException(nameof(bufferSize), SR.ArgumentOutOfRange_NeedPosNum); + } + + Init(stream, encoding, bufferSize, leaveOpen); + } + + public StreamWriter(string path) + : this(path, false, UTF8NoBOM, DefaultBufferSize) + { + } + + public StreamWriter(string path, bool append) + : this(path, append, UTF8NoBOM, DefaultBufferSize) + { + } + + public StreamWriter(string path, bool append, Encoding encoding) + : this(path, append, encoding, DefaultBufferSize) + { + } + + public StreamWriter(string path, bool append, Encoding encoding, int bufferSize) + { + if (path == null) + throw new ArgumentNullException(nameof(path)); + if (encoding == null) + throw new ArgumentNullException(nameof(encoding)); + if (path.Length == 0) + throw new ArgumentException(SR.Argument_EmptyPath); + if (bufferSize <= 0) + throw new ArgumentOutOfRangeException(nameof(bufferSize), SR.ArgumentOutOfRange_NeedPosNum); + + Stream stream = new FileStream(path, append ? FileMode.Append : FileMode.Create, FileAccess.Write, FileShare.Read, + DefaultFileStreamBufferSize, FileOptions.SequentialScan); + Init(stream, encoding, bufferSize, shouldLeaveOpen: false); + } + + private void Init(Stream streamArg, Encoding encodingArg, int bufferSize, bool shouldLeaveOpen) + { + _stream = streamArg; + _encoding = encodingArg; + _encoder = _encoding.GetEncoder(); + if (bufferSize < MinBufferSize) + { + bufferSize = MinBufferSize; + } + + _charBuffer = new char[bufferSize]; + _byteBuffer = new byte[_encoding.GetMaxByteCount(bufferSize)]; + _charLen = bufferSize; + // If we're appending to a Stream that already has data, don't write + // the preamble. + if (_stream.CanSeek && _stream.Position > 0) + { + _haveWrittenPreamble = true; + } + + _closable = !shouldLeaveOpen; + } + + public override void Close() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected override void Dispose(bool disposing) + { + try + { + // We need to flush any buffered data if we are being closed/disposed. + // Also, we never close the handles for stdout & friends. So we can safely + // write any buffered data to those streams even during finalization, which + // is generally the right thing to do. + if (_stream != null) + { + // Note: flush on the underlying stream can throw (ex., low disk space) + if (disposing /* || (LeaveOpen && stream is __ConsoleStream) */) + { + CheckAsyncTaskInProgress(); + + Flush(true, true); + } + } + } + finally + { + // Dispose of our resources if this StreamWriter is closable. + // Note: Console.Out and other such non closable streamwriters should be left alone + if (!LeaveOpen && _stream != null) + { + try + { + // Attempt to close the stream even if there was an IO error from Flushing. + // Note that Stream.Close() can potentially throw here (may or may not be + // due to the same Flush error). In this case, we still need to ensure + // cleaning up internal resources, hence the finally block. + if (disposing) + { + _stream.Close(); + } + } + finally + { + _stream = null; + _byteBuffer = null; + _charBuffer = null; + _encoding = null; + _encoder = null; + _charLen = 0; + base.Dispose(disposing); + } + } + } + } + + public override void Flush() + { + CheckAsyncTaskInProgress(); + + Flush(true, true); + } + + private void Flush(bool flushStream, bool flushEncoder) + { + // flushEncoder should be true at the end of the file and if + // the user explicitly calls Flush (though not if AutoFlush is true). + // This is required to flush any dangling characters from our UTF-7 + // and UTF-8 encoders. + if (_stream == null) + { + throw new ObjectDisposedException(null, SR.ObjectDisposed_WriterClosed); + } + + // Perf boost for Flush on non-dirty writers. + if (_charPos == 0 && !flushStream && !flushEncoder) + { + return; + } + + if (!_haveWrittenPreamble) + { + _haveWrittenPreamble = true; + ReadOnlySpan preamble = _encoding.Preamble; + if (preamble.Length > 0) + { + _stream.Write(preamble); + } + } + + int count = _encoder.GetBytes(_charBuffer, 0, _charPos, _byteBuffer, 0, flushEncoder); + _charPos = 0; + if (count > 0) + { + _stream.Write(_byteBuffer, 0, count); + } + // By definition, calling Flush should flush the stream, but this is + // only necessary if we passed in true for flushStream. The Web + // Services guys have some perf tests where flushing needlessly hurts. + if (flushStream) + { + _stream.Flush(); + } + } + + public virtual bool AutoFlush + { + get { return _autoFlush; } + + set + { + CheckAsyncTaskInProgress(); + + _autoFlush = value; + if (value) + { + Flush(true, false); + } + } + } + + public virtual Stream BaseStream + { + get { return _stream; } + } + + internal bool LeaveOpen + { + get { return !_closable; } + } + + internal bool HaveWrittenPreamble + { + set { _haveWrittenPreamble = value; } + } + + public override Encoding Encoding + { + get { return _encoding; } + } + + public override void Write(char value) + { + CheckAsyncTaskInProgress(); + + if (_charPos == _charLen) + { + Flush(false, false); + } + + _charBuffer[_charPos] = value; + _charPos++; + if (_autoFlush) + { + Flush(true, false); + } + } + + public override void Write(char[] buffer) + { + if (buffer != null) + { + WriteCore(buffer, _autoFlush); + } + } + + public override void Write(char[] buffer, int index, int count) + { + if (buffer == null) + { + throw new ArgumentNullException(nameof(buffer), SR.ArgumentNull_Buffer); + } + if (index < 0) + { + throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_NeedNonNegNum); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); + } + if (buffer.Length - index < count) + { + throw new ArgumentException(SR.Argument_InvalidOffLen); + } + + WriteCore(new ReadOnlySpan(buffer, index, count), _autoFlush); + } + + public override void Write(ReadOnlySpan buffer) + { + if (GetType() == typeof(StreamWriter)) + { + WriteCore(buffer, _autoFlush); + } + else + { + // If a derived class may have overridden existing Write behavior, + // we need to make sure we use it. + base.Write(buffer); + } + } + + private unsafe void WriteCore(ReadOnlySpan buffer, bool autoFlush) + { + CheckAsyncTaskInProgress(); + + if (buffer.Length <= 4 && // Threshold of 4 chosen based on perf experimentation + buffer.Length <= _charLen - _charPos) + { + // For very short buffers and when we don't need to worry about running out of space + // in the char buffer, just copy the chars individually. + for (int i = 0; i < buffer.Length; i++) + { + _charBuffer[_charPos++] = buffer[i]; + } + } + else + { + // For larger buffers or when we may run out of room in the internal char buffer, copy in chunks. + // Use unsafe code until https://github.com/dotnet/coreclr/issues/13827 is addressed, as spans are + // resulting in significant overhead (even when the if branch above is taken rather than this + // else) due to temporaries that need to be cleared. Given the use of unsafe code, we also + // make local copies of instance state to protect against potential concurrent misuse. + + char[] charBuffer = _charBuffer; + if (charBuffer == null) + { + throw new ObjectDisposedException(null, SR.ObjectDisposed_WriterClosed); + } + + fixed (char* bufferPtr = &MemoryMarshal.GetReference(buffer)) + fixed (char* dstPtr = &charBuffer[0]) + { + char* srcPtr = bufferPtr; + int count = buffer.Length; + int dstPos = _charPos; // use a local copy of _charPos for safety + while (count > 0) + { + if (dstPos == charBuffer.Length) + { + Flush(false, false); + dstPos = 0; + } + + int n = Math.Min(charBuffer.Length - dstPos, count); + int bytesToCopy = n * sizeof(char); + + Buffer.MemoryCopy(srcPtr, dstPtr + dstPos, bytesToCopy, bytesToCopy); + + _charPos += n; + dstPos += n; + srcPtr += n; + count -= n; + } + } + } + + if (autoFlush) + { + Flush(true, false); + } + } + + public override void Write(string value) + { + if (value != null) + { + WriteCore(value.AsSpan(), _autoFlush); + } + } + + // + // Optimize the most commonly used WriteLine overload. This optimization is important for System.Console in particular + // because of it will make one WriteLine equal to one call to the OS instead of two in the common case. + // + public override void WriteLine(string value) + { + CheckAsyncTaskInProgress(); + if (value != null) + { + WriteCore(value.AsSpan(), autoFlush: false); + } + WriteCore(new ReadOnlySpan(CoreNewLine), autoFlush: true); + } + + public override void WriteLine(ReadOnlySpan value) + { + if (GetType() == typeof(StreamWriter)) + { + CheckAsyncTaskInProgress(); + WriteCore(value, autoFlush: false); + WriteCore(new ReadOnlySpan(CoreNewLine), autoFlush: true); + } + else + { + // If a derived class may have overridden existing WriteLine behavior, + // we need to make sure we use it. + base.WriteLine(value); + } + } + + #region Task based Async APIs + public override Task WriteAsync(char value) + { + // If we have been inherited into a subclass, the following implementation could be incorrect + // since it does not call through to Write() which a subclass might have overridden. + // To be safe we will only use this implementation in cases where we know it is safe to do so, + // and delegate to our base class (which will call into Write) when we are not sure. + if (GetType() != typeof(StreamWriter)) + { + return base.WriteAsync(value); + } + + if (_stream == null) + { + throw new ObjectDisposedException(null, SR.ObjectDisposed_WriterClosed); + } + + CheckAsyncTaskInProgress(); + + Task task = WriteAsyncInternal(this, value, _charBuffer, _charPos, _charLen, CoreNewLine, _autoFlush, appendNewLine: false); + _asyncWriteTask = task; + + return task; + } + + // We pass in private instance fields of this MarshalByRefObject-derived type as local params + // to ensure performant access inside the state machine that corresponds this async method. + // Fields that are written to must be assigned at the end of the method *and* before instance invocations. + private static async Task WriteAsyncInternal(StreamWriter _this, char value, + char[] charBuffer, int charPos, int charLen, char[] coreNewLine, + bool autoFlush, bool appendNewLine) + { + if (charPos == charLen) + { + await _this.FlushAsyncInternal(false, false, charBuffer, charPos).ConfigureAwait(false); + Debug.Assert(_this._charPos == 0); + charPos = 0; + } + + charBuffer[charPos] = value; + charPos++; + + if (appendNewLine) + { + for (int i = 0; i < coreNewLine.Length; i++) // Expect 2 iterations, no point calling BlockCopy + { + if (charPos == charLen) + { + await _this.FlushAsyncInternal(false, false, charBuffer, charPos).ConfigureAwait(false); + Debug.Assert(_this._charPos == 0); + charPos = 0; + } + + charBuffer[charPos] = coreNewLine[i]; + charPos++; + } + } + + if (autoFlush) + { + await _this.FlushAsyncInternal(true, false, charBuffer, charPos).ConfigureAwait(false); + Debug.Assert(_this._charPos == 0); + charPos = 0; + } + + _this.CharPos_Prop = charPos; + } + + public override Task WriteAsync(string value) + { + // If we have been inherited into a subclass, the following implementation could be incorrect + // since it does not call through to Write() which a subclass might have overridden. + // To be safe we will only use this implementation in cases where we know it is safe to do so, + // and delegate to our base class (which will call into Write) when we are not sure. + if (GetType() != typeof(StreamWriter)) + { + return base.WriteAsync(value); + } + + if (value != null) + { + if (_stream == null) + { + throw new ObjectDisposedException(null, SR.ObjectDisposed_WriterClosed); + } + + CheckAsyncTaskInProgress(); + + Task task = WriteAsyncInternal(this, value, _charBuffer, _charPos, _charLen, CoreNewLine, _autoFlush, appendNewLine: false); + _asyncWriteTask = task; + + return task; + } + else + { + return Task.CompletedTask; + } + } + + // We pass in private instance fields of this MarshalByRefObject-derived type as local params + // to ensure performant access inside the state machine that corresponds this async method. + // Fields that are written to must be assigned at the end of the method *and* before instance invocations. + private static async Task WriteAsyncInternal(StreamWriter _this, string value, + char[] charBuffer, int charPos, int charLen, char[] coreNewLine, + bool autoFlush, bool appendNewLine) + { + Debug.Assert(value != null); + + int count = value.Length; + int index = 0; + + while (count > 0) + { + if (charPos == charLen) + { + await _this.FlushAsyncInternal(false, false, charBuffer, charPos).ConfigureAwait(false); + Debug.Assert(_this._charPos == 0); + charPos = 0; + } + + int n = charLen - charPos; + if (n > count) + { + n = count; + } + + Debug.Assert(n > 0, "StreamWriter::Write(String) isn't making progress! This is most likely a race condition in user code."); + + value.CopyTo(index, charBuffer, charPos, n); + + charPos += n; + index += n; + count -= n; + } + + if (appendNewLine) + { + for (int i = 0; i < coreNewLine.Length; i++) // Expect 2 iterations, no point calling BlockCopy + { + if (charPos == charLen) + { + await _this.FlushAsyncInternal(false, false, charBuffer, charPos).ConfigureAwait(false); + Debug.Assert(_this._charPos == 0); + charPos = 0; + } + + charBuffer[charPos] = coreNewLine[i]; + charPos++; + } + } + + if (autoFlush) + { + await _this.FlushAsyncInternal(true, false, charBuffer, charPos).ConfigureAwait(false); + Debug.Assert(_this._charPos == 0); + charPos = 0; + } + + _this.CharPos_Prop = charPos; + } + + public override Task WriteAsync(char[] buffer, int index, int count) + { + if (buffer == null) + { + throw new ArgumentNullException(nameof(buffer), SR.ArgumentNull_Buffer); + } + if (index < 0) + { + throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_NeedNonNegNum); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); + } + if (buffer.Length - index < count) + { + throw new ArgumentException(SR.Argument_InvalidOffLen); + } + + // If we have been inherited into a subclass, the following implementation could be incorrect + // since it does not call through to Write() which a subclass might have overridden. + // To be safe we will only use this implementation in cases where we know it is safe to do so, + // and delegate to our base class (which will call into Write) when we are not sure. + if (GetType() != typeof(StreamWriter)) + { + return base.WriteAsync(buffer, index, count); + } + + if (_stream == null) + { + throw new ObjectDisposedException(null, SR.ObjectDisposed_WriterClosed); + } + + CheckAsyncTaskInProgress(); + + Task task = WriteAsyncInternal(this, new ReadOnlyMemory(buffer, index, count), _charBuffer, _charPos, _charLen, CoreNewLine, _autoFlush, appendNewLine: false, cancellationToken: default); + _asyncWriteTask = task; + + return task; + } + + public override Task WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) + { + if (GetType() != typeof(StreamWriter)) + { + // If a derived type may have overridden existing WriteASync(char[], ...) behavior, make sure we use it. + return base.WriteAsync(buffer, cancellationToken); + } + + if (_stream == null) + { + throw new ObjectDisposedException(null, SR.ObjectDisposed_WriterClosed); + } + + CheckAsyncTaskInProgress(); + + if (cancellationToken.IsCancellationRequested) + { + return Task.FromCanceled(cancellationToken); + } + + Task task = WriteAsyncInternal(this, buffer, _charBuffer, _charPos, _charLen, CoreNewLine, _autoFlush, appendNewLine: false, cancellationToken: cancellationToken); + _asyncWriteTask = task; + return task; + } + + // We pass in private instance fields of this MarshalByRefObject-derived type as local params + // to ensure performant access inside the state machine that corresponds this async method. + // Fields that are written to must be assigned at the end of the method *and* before instance invocations. + private static async Task WriteAsyncInternal(StreamWriter _this, ReadOnlyMemory source, + char[] charBuffer, int charPos, int charLen, char[] coreNewLine, + bool autoFlush, bool appendNewLine, CancellationToken cancellationToken) + { + int copied = 0; + while (copied < source.Length) + { + if (charPos == charLen) + { + await _this.FlushAsyncInternal(false, false, charBuffer, charPos, cancellationToken).ConfigureAwait(false); + Debug.Assert(_this._charPos == 0); + charPos = 0; + } + + int n = Math.Min(charLen - charPos, source.Length - copied); + Debug.Assert(n > 0, "StreamWriter::Write(char[], int, int) isn't making progress! This is most likely a race condition in user code."); + + source.Span.Slice(copied, n).CopyTo(new Span(charBuffer, charPos, n)); + charPos += n; + copied += n; + } + + if (appendNewLine) + { + for (int i = 0; i < coreNewLine.Length; i++) // Expect 2 iterations, no point calling BlockCopy + { + if (charPos == charLen) + { + await _this.FlushAsyncInternal(false, false, charBuffer, charPos, cancellationToken).ConfigureAwait(false); + Debug.Assert(_this._charPos == 0); + charPos = 0; + } + + charBuffer[charPos] = coreNewLine[i]; + charPos++; + } + } + + if (autoFlush) + { + await _this.FlushAsyncInternal(true, false, charBuffer, charPos, cancellationToken).ConfigureAwait(false); + Debug.Assert(_this._charPos == 0); + charPos = 0; + } + + _this.CharPos_Prop = charPos; + } + + public override Task WriteLineAsync() + { + // If we have been inherited into a subclass, the following implementation could be incorrect + // since it does not call through to Write() which a subclass might have overridden. + // To be safe we will only use this implementation in cases where we know it is safe to do so, + // and delegate to our base class (which will call into Write) when we are not sure. + if (GetType() != typeof(StreamWriter)) + { + return base.WriteLineAsync(); + } + + if (_stream == null) + { + throw new ObjectDisposedException(null, SR.ObjectDisposed_WriterClosed); + } + + CheckAsyncTaskInProgress(); + + Task task = WriteAsyncInternal(this, ReadOnlyMemory.Empty, _charBuffer, _charPos, _charLen, CoreNewLine, _autoFlush, appendNewLine: true, cancellationToken: default); + _asyncWriteTask = task; + + return task; + } + + + public override Task WriteLineAsync(char value) + { + // If we have been inherited into a subclass, the following implementation could be incorrect + // since it does not call through to Write() which a subclass might have overridden. + // To be safe we will only use this implementation in cases where we know it is safe to do so, + // and delegate to our base class (which will call into Write) when we are not sure. + if (GetType() != typeof(StreamWriter)) + { + return base.WriteLineAsync(value); + } + + if (_stream == null) + { + throw new ObjectDisposedException(null, SR.ObjectDisposed_WriterClosed); + } + + CheckAsyncTaskInProgress(); + + Task task = WriteAsyncInternal(this, value, _charBuffer, _charPos, _charLen, CoreNewLine, _autoFlush, appendNewLine: true); + _asyncWriteTask = task; + + return task; + } + + + public override Task WriteLineAsync(string value) + { + if (value == null) + { + return WriteLineAsync(); + } + + // If we have been inherited into a subclass, the following implementation could be incorrect + // since it does not call through to Write() which a subclass might have overridden. + // To be safe we will only use this implementation in cases where we know it is safe to do so, + // and delegate to our base class (which will call into Write) when we are not sure. + if (GetType() != typeof(StreamWriter)) + { + return base.WriteLineAsync(value); + } + + if (_stream == null) + { + throw new ObjectDisposedException(null, SR.ObjectDisposed_WriterClosed); + } + + CheckAsyncTaskInProgress(); + + Task task = WriteAsyncInternal(this, value, _charBuffer, _charPos, _charLen, CoreNewLine, _autoFlush, appendNewLine: true); + _asyncWriteTask = task; + + return task; + } + + + public override Task WriteLineAsync(char[] buffer, int index, int count) + { + if (buffer == null) + { + throw new ArgumentNullException(nameof(buffer), SR.ArgumentNull_Buffer); + } + if (index < 0) + { + throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_NeedNonNegNum); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); + } + if (buffer.Length - index < count) + { + throw new ArgumentException(SR.Argument_InvalidOffLen); + } + + // If we have been inherited into a subclass, the following implementation could be incorrect + // since it does not call through to Write() which a subclass might have overridden. + // To be safe we will only use this implementation in cases where we know it is safe to do so, + // and delegate to our base class (which will call into Write) when we are not sure. + if (GetType() != typeof(StreamWriter)) + { + return base.WriteLineAsync(buffer, index, count); + } + + if (_stream == null) + { + throw new ObjectDisposedException(null, SR.ObjectDisposed_WriterClosed); + } + + CheckAsyncTaskInProgress(); + + Task task = WriteAsyncInternal(this, new ReadOnlyMemory(buffer, index, count), _charBuffer, _charPos, _charLen, CoreNewLine, _autoFlush, appendNewLine: true, cancellationToken: default); + _asyncWriteTask = task; + + return task; + } + + public override Task WriteLineAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) + { + if (GetType() != typeof(StreamWriter)) + { + return base.WriteLineAsync(buffer, cancellationToken); + } + + if (_stream == null) + { + throw new ObjectDisposedException(null, SR.ObjectDisposed_WriterClosed); + } + + CheckAsyncTaskInProgress(); + + if (cancellationToken.IsCancellationRequested) + { + return Task.FromCanceled(cancellationToken); + } + + Task task = WriteAsyncInternal(this, buffer, _charBuffer, _charPos, _charLen, CoreNewLine, _autoFlush, appendNewLine: true, cancellationToken: cancellationToken); + _asyncWriteTask = task; + + return task; + } + + + public override Task FlushAsync() + { + // If we have been inherited into a subclass, the following implementation could be incorrect + // since it does not call through to Flush() which a subclass might have overridden. To be safe + // we will only use this implementation in cases where we know it is safe to do so, + // and delegate to our base class (which will call into Flush) when we are not sure. + if (GetType() != typeof(StreamWriter)) + { + return base.FlushAsync(); + } + + // flushEncoder should be true at the end of the file and if + // the user explicitly calls Flush (though not if AutoFlush is true). + // This is required to flush any dangling characters from our UTF-7 + // and UTF-8 encoders. + if (_stream == null) + { + throw new ObjectDisposedException(null, SR.ObjectDisposed_WriterClosed); + } + + CheckAsyncTaskInProgress(); + + Task task = FlushAsyncInternal(true, true, _charBuffer, _charPos); + _asyncWriteTask = task; + + return task; + } + + private int CharPos_Prop + { + set { _charPos = value; } + } + + private bool HaveWrittenPreamble_Prop + { + set { _haveWrittenPreamble = value; } + } + + private Task FlushAsyncInternal(bool flushStream, bool flushEncoder, + char[] sCharBuffer, int sCharPos, CancellationToken cancellationToken = default) + { + if (cancellationToken.IsCancellationRequested) + { + return Task.FromCanceled(cancellationToken); + } + + // Perf boost for Flush on non-dirty writers. + if (sCharPos == 0 && !flushStream && !flushEncoder) + { + return Task.CompletedTask; + } + + Task flushTask = FlushAsyncInternal(this, flushStream, flushEncoder, sCharBuffer, sCharPos, _haveWrittenPreamble, + _encoding, _encoder, _byteBuffer, _stream, cancellationToken); + + _charPos = 0; + return flushTask; + } + + + // We pass in private instance fields of this MarshalByRefObject-derived type as local params + // to ensure performant access inside the state machine that corresponds this async method. + private static async Task FlushAsyncInternal(StreamWriter _this, bool flushStream, bool flushEncoder, + char[] charBuffer, int charPos, bool haveWrittenPreamble, + Encoding encoding, Encoder encoder, Byte[] byteBuffer, Stream stream, CancellationToken cancellationToken) + { + if (!haveWrittenPreamble) + { + _this.HaveWrittenPreamble_Prop = true; + byte[] preamble = encoding.GetPreamble(); + if (preamble.Length > 0) + { + await stream.WriteAsync(new ReadOnlyMemory(preamble), cancellationToken).ConfigureAwait(false); + } + } + + int count = encoder.GetBytes(charBuffer, 0, charPos, byteBuffer, 0, flushEncoder); + if (count > 0) + { + await stream.WriteAsync(new ReadOnlyMemory(byteBuffer, 0, count), cancellationToken).ConfigureAwait(false); + } + + // By definition, calling Flush should flush the stream, but this is + // only necessary if we passed in true for flushStream. The Web + // Services guys have some perf tests where flushing needlessly hurts. + if (flushStream) + { + await stream.FlushAsync(cancellationToken).ConfigureAwait(false); + } + } + #endregion + } // class StreamWriter +} // namespace diff --git a/external/corert/src/System.Private.CoreLib/shared/System/IO/TextReader.cs b/external/corert/src/System.Private.CoreLib/shared/System/IO/TextReader.cs new file mode 100644 index 0000000000..eb94dd7594 --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/shared/System/IO/TextReader.cs @@ -0,0 +1,412 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Buffers; + +namespace System.IO +{ + // This abstract base class represents a reader that can read a sequential + // stream of characters. This is not intended for reading bytes - + // there are methods on the Stream class to read bytes. + // A subclass must minimally implement the Peek() and Read() methods. + // + // This class is intended for character input, not bytes. + // There are methods on the Stream class for reading bytes. + public abstract partial class TextReader : MarshalByRefObject, IDisposable + { + public static readonly TextReader Null = new NullTextReader(); + + protected TextReader() { } + + public virtual void Close() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + } + + // Returns the next available character without actually reading it from + // the input stream. The current position of the TextReader is not changed by + // this operation. The returned value is -1 if no further characters are + // available. + // + // This default method simply returns -1. + // + public virtual int Peek() + { + return -1; + } + + // Reads the next character from the input stream. The returned value is + // -1 if no further characters are available. + // + // This default method simply returns -1. + // + public virtual int Read() + { + return -1; + } + + // Reads a block of characters. This method will read up to + // count characters from this TextReader into the + // buffer character array starting at position + // index. Returns the actual number of characters read. + // + public virtual int Read(char[] buffer, int index, int count) + { + if (buffer == null) + { + throw new ArgumentNullException(nameof(buffer), SR.ArgumentNull_Buffer); + } + if (index < 0) + { + throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_NeedNonNegNum); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); + } + if (buffer.Length - index < count) + { + throw new ArgumentException(SR.Argument_InvalidOffLen); + } + + int n; + for (n = 0; n < count; n++) + { + int ch = Read(); + if (ch == -1) break; + buffer[index + n] = (char)ch; + } + + return n; + } + + // Reads a span of characters. This method will read up to + // count characters from this TextReader into the + // span of characters Returns the actual number of characters read. + // + public virtual int Read(Span buffer) + { + char[] array = ArrayPool.Shared.Rent(buffer.Length); + + try + { + int numRead = Read(array, 0, buffer.Length); + if ((uint)numRead > buffer.Length) + { + throw new IOException(SR.IO_InvalidReadLength); + } + new Span(array, 0, numRead).CopyTo(buffer); + return numRead; + } + finally + { + ArrayPool.Shared.Return(array); + } + } + + // Reads all characters from the current position to the end of the + // TextReader, and returns them as one string. + public virtual string ReadToEnd() + { + char[] chars = new char[4096]; + int len; + StringBuilder sb = new StringBuilder(4096); + while ((len = Read(chars, 0, chars.Length)) != 0) + { + sb.Append(chars, 0, len); + } + return sb.ToString(); + } + + // Blocking version of read. Returns only when count + // characters have been read or the end of the file was reached. + // + public virtual int ReadBlock(char[] buffer, int index, int count) + { + int i, n = 0; + do + { + n += (i = Read(buffer, index + n, count - n)); + } while (i > 0 && n < count); + return n; + } + + // Blocking version of read for span of characters. Returns only when count + // characters have been read or the end of the file was reached. + // + public virtual int ReadBlock(Span buffer) + { + char[] array = ArrayPool.Shared.Rent(buffer.Length); + + try + { + int numRead = ReadBlock(array, 0, buffer.Length); + if ((uint)numRead > buffer.Length) + { + throw new IOException(SR.IO_InvalidReadLength); + } + new Span(array, 0, numRead).CopyTo(buffer); + return numRead; + } + finally + { + ArrayPool.Shared.Return(array); + } + } + + // Reads a line. A line is defined as a sequence of characters followed by + // a carriage return ('\r'), a line feed ('\n'), or a carriage return + // immediately followed by a line feed. The resulting string does not + // contain the terminating carriage return and/or line feed. The returned + // value is null if the end of the input stream has been reached. + // + public virtual string ReadLine() + { + StringBuilder sb = new StringBuilder(); + while (true) + { + int ch = Read(); + if (ch == -1) break; + if (ch == '\r' || ch == '\n') + { + if (ch == '\r' && Peek() == '\n') + { + Read(); + } + + return sb.ToString(); + } + sb.Append((char)ch); + } + if (sb.Length > 0) + { + return sb.ToString(); + } + + return null; + } + + #region Task based Async APIs + public virtual Task ReadLineAsync() + { + return Task.Factory.StartNew(state => + { + return ((TextReader)state).ReadLine(); + }, + this, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); + } + + public async virtual Task ReadToEndAsync() + { + var sb = new StringBuilder(4096); + char[] chars = ArrayPool.Shared.Rent(4096); + try + { + int len; + while ((len = await ReadAsyncInternal(chars, default).ConfigureAwait(false)) != 0) + { + sb.Append(chars, 0, len); + } + } + finally + { + ArrayPool.Shared.Return(chars); + } + return sb.ToString(); + } + + public virtual Task ReadAsync(char[] buffer, int index, int count) + { + if (buffer == null) + { + throw new ArgumentNullException(nameof(buffer), SR.ArgumentNull_Buffer); + } + if (index < 0 || count < 0) + { + throw new ArgumentOutOfRangeException((index < 0 ? nameof(index): nameof(count)), SR.ArgumentOutOfRange_NeedNonNegNum); + } + if (buffer.Length - index < count) + { + throw new ArgumentException(SR.Argument_InvalidOffLen); + } + + return ReadAsyncInternal(new Memory(buffer, index, count), default).AsTask(); + } + + public virtual ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default(CancellationToken)) => + new ValueTask(MemoryMarshal.TryGetArray(buffer, out ArraySegment array) ? + ReadAsync(array.Array, array.Offset, array.Count) : + Task.Factory.StartNew(state => + { + var t = (Tuple>)state; + return t.Item1.Read(t.Item2.Span); + }, Tuple.Create(this, buffer), cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default)); + + internal virtual ValueTask ReadAsyncInternal(Memory buffer, CancellationToken cancellationToken) + { + var tuple = new Tuple>(this, buffer); + return new ValueTask(Task.Factory.StartNew(state => + { + var t = (Tuple>)state; + return t.Item1.Read(t.Item2.Span); + }, + tuple, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default)); + } + + public virtual Task ReadBlockAsync(char[] buffer, int index, int count) + { + if (buffer == null) + { + throw new ArgumentNullException(nameof(buffer), SR.ArgumentNull_Buffer); + } + if (index < 0 || count < 0) + { + throw new ArgumentOutOfRangeException((index < 0 ? nameof(index): nameof(count)), SR.ArgumentOutOfRange_NeedNonNegNum); + } + if (buffer.Length - index < count) + { + throw new ArgumentException(SR.Argument_InvalidOffLen); + } + + return ReadBlockAsyncInternal(new Memory(buffer, index, count), default).AsTask(); + } + + public virtual ValueTask ReadBlockAsync(Memory buffer, CancellationToken cancellationToken = default(CancellationToken)) => + new ValueTask(MemoryMarshal.TryGetArray(buffer, out ArraySegment array) ? + ReadBlockAsync(array.Array, array.Offset, array.Count) : + Task.Factory.StartNew(state => + { + var t = (Tuple>)state; + return t.Item1.ReadBlock(t.Item2.Span); + }, Tuple.Create(this, buffer), cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default)); + + internal async ValueTask ReadBlockAsyncInternal(Memory buffer, CancellationToken cancellationToken) + { + int n = 0, i; + do + { + i = await ReadAsyncInternal(buffer.Slice(n), cancellationToken).ConfigureAwait(false); + n += i; + } while (i > 0 && n < buffer.Length); + + return n; + } + #endregion + + private sealed class NullTextReader : TextReader + { + public NullTextReader() { } + + public override int Read(char[] buffer, int index, int count) + { + return 0; + } + + public override string ReadLine() + { + return null; + } + } + + public static TextReader Synchronized(TextReader reader) + { + if (reader == null) + throw new ArgumentNullException(nameof(reader)); + + return reader is SyncTextReader ? reader : new SyncTextReader(reader); + } + + internal sealed class SyncTextReader : TextReader + { + internal readonly TextReader _in; + + internal SyncTextReader(TextReader t) + { + _in = t; + } + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void Close() => _in.Close(); + + [MethodImpl(MethodImplOptions.Synchronized)] + protected override void Dispose(bool disposing) + { + // Explicitly pick up a potentially methodimpl'ed Dispose + if (disposing) + ((IDisposable)_in).Dispose(); + } + + [MethodImpl(MethodImplOptions.Synchronized)] + public override int Peek() => _in.Peek(); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override int Read() => _in.Read(); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override int Read(char[] buffer, int index, int count) => _in.Read(buffer, index, count); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override int ReadBlock(char[] buffer, int index, int count) => _in.ReadBlock(buffer, index, count); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override string ReadLine() => _in.ReadLine(); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override string ReadToEnd() => _in.ReadToEnd(); + + // + // On SyncTextReader all APIs should run synchronously, even the async ones. + // + + [MethodImpl(MethodImplOptions.Synchronized)] + public override Task ReadLineAsync() => Task.FromResult(ReadLine()); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override Task ReadToEndAsync() => Task.FromResult(ReadToEnd()); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override Task ReadBlockAsync(char[] buffer, int index, int count) + { + if (buffer == null) + throw new ArgumentNullException(nameof(buffer), SR.ArgumentNull_Buffer); + if (index < 0 || count < 0) + throw new ArgumentOutOfRangeException((index < 0 ? nameof(index) : nameof(count)), SR.ArgumentOutOfRange_NeedNonNegNum); + if (buffer.Length - index < count) + throw new ArgumentException(SR.Argument_InvalidOffLen); + + return Task.FromResult(ReadBlock(buffer, index, count)); + } + + [MethodImpl(MethodImplOptions.Synchronized)] + public override Task ReadAsync(char[] buffer, int index, int count) + { + if (buffer == null) + throw new ArgumentNullException(nameof(buffer), SR.ArgumentNull_Buffer); + if (index < 0 || count < 0) + throw new ArgumentOutOfRangeException((index < 0 ? nameof(index) : nameof(count)), SR.ArgumentOutOfRange_NeedNonNegNum); + if (buffer.Length - index < count) + throw new ArgumentException(SR.Argument_InvalidOffLen); + + return Task.FromResult(Read(buffer, index, count)); + } + } + } +} diff --git a/external/corert/src/System.Private.CoreLib/shared/System/IO/TextWriter.cs b/external/corert/src/System.Private.CoreLib/shared/System/IO/TextWriter.cs new file mode 100644 index 0000000000..48e702be67 --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/shared/System/IO/TextWriter.cs @@ -0,0 +1,870 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text; +using System.Threading; +using System.Globalization; +using System.Threading.Tasks; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Buffers; + +namespace System.IO +{ + // This abstract base class represents a writer that can write a sequential + // stream of characters. A subclass must minimally implement the + // Write(char) method. + // + // This class is intended for character output, not bytes. + // There are methods on the Stream class for writing bytes. + public abstract partial class TextWriter : MarshalByRefObject, IDisposable + { + public static readonly TextWriter Null = new NullTextWriter(); + + // We don't want to allocate on every TextWriter creation, so cache the char array. + private static readonly char[] s_coreNewLine = Environment.NewLine.ToCharArray(); + + /// + /// This is the 'NewLine' property expressed as a char[]. + /// It is exposed to subclasses as a protected field for read-only + /// purposes. You should only modify it by using the 'NewLine' property. + /// In particular you should never modify the elements of the array + /// as they are shared among many instances of TextWriter. + /// + protected char[] CoreNewLine = s_coreNewLine; + private string CoreNewLineStr = Environment.NewLine; + + // Can be null - if so, ask for the Thread's CurrentCulture every time. + private IFormatProvider _internalFormatProvider; + + protected TextWriter() + { + _internalFormatProvider = null; // Ask for CurrentCulture all the time. + } + + protected TextWriter(IFormatProvider formatProvider) + { + _internalFormatProvider = formatProvider; + } + + public virtual IFormatProvider FormatProvider + { + get + { + if (_internalFormatProvider == null) + { + return CultureInfo.CurrentCulture; + } + else + { + return _internalFormatProvider; + } + } + } + + public virtual void Close() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + // Clears all buffers for this TextWriter and causes any buffered data to be + // written to the underlying device. This default method is empty, but + // descendant classes can override the method to provide the appropriate + // functionality. + public virtual void Flush() + { + } + + public abstract Encoding Encoding + { + get; + } + + /// + /// Returns the line terminator string used by this TextWriter. The default line + /// terminator string is Environment.NewLine, which is platform specific. + /// On Windows this is a carriage return followed by a line feed ("\r\n"). + /// On OSX and Linux this is a line feed ("\n"). + /// + /// + /// The line terminator string is written to the text stream whenever one of the + /// WriteLine methods are called. In order for text written by + /// the TextWriter to be readable by a TextReader, only one of the following line + /// terminator strings should be used: "\r", "\n", or "\r\n". + /// + public virtual string NewLine + { + get { return CoreNewLineStr; } + set + { + if (value == null) + { + value = Environment.NewLine; + } + + CoreNewLineStr = value; + CoreNewLine = value.ToCharArray(); + } + } + + + // Writes a character to the text stream. This default method is empty, + // but descendant classes can override the method to provide the + // appropriate functionality. + // + public virtual void Write(char value) + { + } + + // Writes a character array to the text stream. This default method calls + // Write(char) for each of the characters in the character array. + // If the character array is null, nothing is written. + // + public virtual void Write(char[] buffer) + { + if (buffer != null) + { + Write(buffer, 0, buffer.Length); + } + } + + // Writes a range of a character array to the text stream. This method will + // write count characters of data into this TextWriter from the + // buffer character array starting at position index. + // + public virtual void Write(char[] buffer, int index, int count) + { + if (buffer == null) + { + throw new ArgumentNullException(nameof(buffer), SR.ArgumentNull_Buffer); + } + if (index < 0) + { + throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_NeedNonNegNum); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); + } + if (buffer.Length - index < count) + { + throw new ArgumentException(SR.Argument_InvalidOffLen); + } + + for (int i = 0; i < count; i++) Write(buffer[index + i]); + } + + // Writes a span of characters to the text stream. + // + public virtual void Write(ReadOnlySpan buffer) + { + char[] array = ArrayPool.Shared.Rent(buffer.Length); + + try + { + buffer.CopyTo(new Span(array)); + Write(array, 0, buffer.Length); + } + finally + { + ArrayPool.Shared.Return(array); + } + } + + // Writes the text representation of a boolean to the text stream. This + // method outputs either Boolean.TrueString or Boolean.FalseString. + // + public virtual void Write(bool value) + { + Write(value ? "True" : "False"); + } + + // Writes the text representation of an integer to the text stream. The + // text representation of the given value is produced by calling the + // Int32.ToString() method. + // + public virtual void Write(int value) + { + Write(value.ToString(FormatProvider)); + } + + // Writes the text representation of an integer to the text stream. The + // text representation of the given value is produced by calling the + // UInt32.ToString() method. + // + [CLSCompliant(false)] + public virtual void Write(uint value) + { + Write(value.ToString(FormatProvider)); + } + + // Writes the text representation of a long to the text stream. The + // text representation of the given value is produced by calling the + // Int64.ToString() method. + // + public virtual void Write(long value) + { + Write(value.ToString(FormatProvider)); + } + + // Writes the text representation of an unsigned long to the text + // stream. The text representation of the given value is produced + // by calling the UInt64.ToString() method. + // + [CLSCompliant(false)] + public virtual void Write(ulong value) + { + Write(value.ToString(FormatProvider)); + } + + // Writes the text representation of a float to the text stream. The + // text representation of the given value is produced by calling the + // Float.toString(float) method. + // + public virtual void Write(float value) + { + Write(value.ToString(FormatProvider)); + } + + // Writes the text representation of a double to the text stream. The + // text representation of the given value is produced by calling the + // Double.toString(double) method. + // + public virtual void Write(double value) + { + Write(value.ToString(FormatProvider)); + } + + public virtual void Write(decimal value) + { + Write(value.ToString(FormatProvider)); + } + + // Writes a string to the text stream. If the given string is null, nothing + // is written to the text stream. + // + public virtual void Write(string value) + { + if (value != null) + { + Write(value.ToCharArray()); + } + } + + // Writes the text representation of an object to the text stream. If the + // given object is null, nothing is written to the text stream. + // Otherwise, the object's ToString method is called to produce the + // string representation, and the resulting string is then written to the + // output stream. + // + public virtual void Write(object value) + { + if (value != null) + { + IFormattable f = value as IFormattable; + if (f != null) + { + Write(f.ToString(null, FormatProvider)); + } + else + Write(value.ToString()); + } + } + + // Writes out a formatted string. Uses the same semantics as + // String.Format. + // + public virtual void Write(string format, object arg0) + { + Write(string.Format(FormatProvider, format, arg0)); + } + + // Writes out a formatted string. Uses the same semantics as + // String.Format. + // + public virtual void Write(string format, object arg0, object arg1) + { + Write(string.Format(FormatProvider, format, arg0, arg1)); + } + + // Writes out a formatted string. Uses the same semantics as + // String.Format. + // + public virtual void Write(string format, object arg0, object arg1, object arg2) + { + Write(string.Format(FormatProvider, format, arg0, arg1, arg2)); + } + + // Writes out a formatted string. Uses the same semantics as + // String.Format. + // + public virtual void Write(string format, params object[] arg) + { + Write(string.Format(FormatProvider, format, arg)); + } + + + // Writes a line terminator to the text stream. The default line terminator + // is Environment.NewLine, but this value can be changed by setting the NewLine property. + // + public virtual void WriteLine() + { + Write(CoreNewLine); + } + + // Writes a character followed by a line terminator to the text stream. + // + public virtual void WriteLine(char value) + { + Write(value); + WriteLine(); + } + + // Writes an array of characters followed by a line terminator to the text + // stream. + // + public virtual void WriteLine(char[] buffer) + { + Write(buffer); + WriteLine(); + } + + // Writes a range of a character array followed by a line terminator to the + // text stream. + // + public virtual void WriteLine(char[] buffer, int index, int count) + { + Write(buffer, index, count); + WriteLine(); + } + + public virtual void WriteLine(ReadOnlySpan buffer) + { + char[] array = ArrayPool.Shared.Rent(buffer.Length); + + try + { + buffer.CopyTo(new Span(array)); + WriteLine(array, 0, buffer.Length); + } + finally + { + ArrayPool.Shared.Return(array); + } + } + + // Writes the text representation of a boolean followed by a line + // terminator to the text stream. + // + public virtual void WriteLine(bool value) + { + Write(value); + WriteLine(); + } + + // Writes the text representation of an integer followed by a line + // terminator to the text stream. + // + public virtual void WriteLine(int value) + { + Write(value); + WriteLine(); + } + + // Writes the text representation of an unsigned integer followed by + // a line terminator to the text stream. + // + [CLSCompliant(false)] + public virtual void WriteLine(uint value) + { + Write(value); + WriteLine(); + } + + // Writes the text representation of a long followed by a line terminator + // to the text stream. + // + public virtual void WriteLine(long value) + { + Write(value); + WriteLine(); + } + + // Writes the text representation of an unsigned long followed by + // a line terminator to the text stream. + // + [CLSCompliant(false)] + public virtual void WriteLine(ulong value) + { + Write(value); + WriteLine(); + } + + // Writes the text representation of a float followed by a line terminator + // to the text stream. + // + public virtual void WriteLine(float value) + { + Write(value); + WriteLine(); + } + + // Writes the text representation of a double followed by a line terminator + // to the text stream. + // + public virtual void WriteLine(double value) + { + Write(value); + WriteLine(); + } + + public virtual void WriteLine(decimal value) + { + Write(value); + WriteLine(); + } + + // Writes a string followed by a line terminator to the text stream. + // + public virtual void WriteLine(string value) + { + if (value != null) + { + Write(value); + } + Write(CoreNewLineStr); + } + + // Writes the text representation of an object followed by a line + // terminator to the text stream. + // + public virtual void WriteLine(object value) + { + if (value == null) + { + WriteLine(); + } + else + { + // Call WriteLine(value.ToString), not Write(Object), WriteLine(). + // This makes calls to WriteLine(Object) atomic. + IFormattable f = value as IFormattable; + if (f != null) + { + WriteLine(f.ToString(null, FormatProvider)); + } + else + { + WriteLine(value.ToString()); + } + } + } + + // Writes out a formatted string and a new line. Uses the same + // semantics as String.Format. + // + public virtual void WriteLine(string format, object arg0) + { + WriteLine(string.Format(FormatProvider, format, arg0)); + } + + // Writes out a formatted string and a new line. Uses the same + // semantics as String.Format. + // + public virtual void WriteLine(string format, object arg0, object arg1) + { + WriteLine(string.Format(FormatProvider, format, arg0, arg1)); + } + + // Writes out a formatted string and a new line. Uses the same + // semantics as String.Format. + // + public virtual void WriteLine(string format, object arg0, object arg1, object arg2) + { + WriteLine(string.Format(FormatProvider, format, arg0, arg1, arg2)); + } + + // Writes out a formatted string and a new line. Uses the same + // semantics as String.Format. + // + public virtual void WriteLine(string format, params object[] arg) + { + WriteLine(string.Format(FormatProvider, format, arg)); + } + + #region Task based Async APIs + public virtual Task WriteAsync(char value) + { + var tuple = new Tuple(this, value); + return Task.Factory.StartNew(state => + { + var t = (Tuple)state; + t.Item1.Write(t.Item2); + }, + tuple, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); + } + + public virtual Task WriteAsync(string value) + { + var tuple = new Tuple(this, value); + return Task.Factory.StartNew(state => + { + var t = (Tuple)state; + t.Item1.Write(t.Item2); + }, + tuple, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); + } + + public Task WriteAsync(char[] buffer) + { + if (buffer == null) + { + return Task.CompletedTask; + } + + return WriteAsync(buffer, 0, buffer.Length); + } + + public virtual Task WriteAsync(char[] buffer, int index, int count) + { + var tuple = new Tuple(this, buffer, index, count); + return Task.Factory.StartNew(state => + { + var t = (Tuple)state; + t.Item1.Write(t.Item2, t.Item3, t.Item4); + }, + tuple, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); + } + + public virtual Task WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default(CancellationToken)) => + MemoryMarshal.TryGetArray(buffer, out ArraySegment array) ? + WriteAsync(array.Array, array.Offset, array.Count) : + Task.Factory.StartNew(state => + { + var t = (Tuple>)state; + t.Item1.Write(t.Item2.Span); + }, Tuple.Create(this, buffer), cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); + + public virtual Task WriteLineAsync(char value) + { + var tuple = new Tuple(this, value); + return Task.Factory.StartNew(state => + { + var t = (Tuple)state; + t.Item1.WriteLine(t.Item2); + }, + tuple, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); + } + + public virtual Task WriteLineAsync(string value) + { + var tuple = new Tuple(this, value); + return Task.Factory.StartNew(state => + { + var t = (Tuple)state; + t.Item1.WriteLine(t.Item2); + }, + tuple, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); + } + + public Task WriteLineAsync(char[] buffer) + { + if (buffer == null) + { + return WriteLineAsync(); + } + + return WriteLineAsync(buffer, 0, buffer.Length); + } + + public virtual Task WriteLineAsync(char[] buffer, int index, int count) + { + var tuple = new Tuple(this, buffer, index, count); + return Task.Factory.StartNew(state => + { + var t = (Tuple)state; + t.Item1.WriteLine(t.Item2, t.Item3, t.Item4); + }, + tuple, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); + } + + public virtual Task WriteLineAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default(CancellationToken)) => + MemoryMarshal.TryGetArray(buffer, out ArraySegment array) ? + WriteLineAsync(array.Array, array.Offset, array.Count) : + Task.Factory.StartNew(state => + { + var t = (Tuple>)state; + t.Item1.WriteLine(t.Item2.Span); + }, Tuple.Create(this, buffer), cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); + + public virtual Task WriteLineAsync() + { + return WriteAsync(CoreNewLine); + } + + public virtual Task FlushAsync() + { + return Task.Factory.StartNew(state => + { + ((TextWriter)state).Flush(); + }, + this, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); + } + #endregion + + private sealed class NullTextWriter : TextWriter + { + internal NullTextWriter() : base(CultureInfo.InvariantCulture) + { + } + + public override Encoding Encoding + { + get + { + return Encoding.Unicode; + } + } + + public override void Write(char[] buffer, int index, int count) + { + } + + public override void Write(string value) + { + } + + // Not strictly necessary, but for perf reasons + public override void WriteLine() + { + } + + // Not strictly necessary, but for perf reasons + public override void WriteLine(string value) + { + } + + public override void WriteLine(object value) + { + } + + public override void Write(char value) + { + } + } + + public static TextWriter Synchronized(TextWriter writer) + { + if (writer == null) + throw new ArgumentNullException(nameof(writer)); + + return writer is SyncTextWriter ? writer : new SyncTextWriter(writer); + } + + internal sealed class SyncTextWriter : TextWriter, IDisposable + { + private readonly TextWriter _out; + + internal SyncTextWriter(TextWriter t) : base(t.FormatProvider) + { + _out = t; + } + + public override Encoding Encoding => _out.Encoding; + + public override IFormatProvider FormatProvider => _out.FormatProvider; + + public override string NewLine + { + [MethodImpl(MethodImplOptions.Synchronized)] + get { return _out.NewLine; } + [MethodImpl(MethodImplOptions.Synchronized)] + set { _out.NewLine = value; } + } + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void Close() => _out.Close(); + + [MethodImpl(MethodImplOptions.Synchronized)] + protected override void Dispose(bool disposing) + { + // Explicitly pick up a potentially methodimpl'ed Dispose + if (disposing) + ((IDisposable)_out).Dispose(); + } + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void Flush() => _out.Flush(); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void Write(char value) => _out.Write(value); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void Write(char[] buffer) => _out.Write(buffer); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void Write(char[] buffer, int index, int count) => _out.Write(buffer, index, count); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void Write(bool value) => _out.Write(value); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void Write(int value) => _out.Write(value); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void Write(uint value) => _out.Write(value); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void Write(long value) => _out.Write(value); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void Write(ulong value) => _out.Write(value); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void Write(float value) => _out.Write(value); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void Write(double value) => _out.Write(value); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void Write(Decimal value) => _out.Write(value); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void Write(string value) => _out.Write(value); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void Write(object value) => _out.Write(value); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void Write(string format, object arg0) => _out.Write(format, arg0); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void Write(string format, object arg0, object arg1) => _out.Write(format, arg0, arg1); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void Write(string format, object arg0, object arg1, object arg2) => _out.Write(format, arg0, arg1, arg2); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void Write(string format, object[] arg) => _out.Write(format, arg); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void WriteLine() => _out.WriteLine(); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void WriteLine(char value) => _out.WriteLine(value); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void WriteLine(decimal value) => _out.WriteLine(value); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void WriteLine(char[] buffer) => _out.WriteLine(buffer); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void WriteLine(char[] buffer, int index, int count) => _out.WriteLine(buffer, index, count); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void WriteLine(bool value) => _out.WriteLine(value); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void WriteLine(int value) => _out.WriteLine(value); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void WriteLine(uint value) => _out.WriteLine(value); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void WriteLine(long value) => _out.WriteLine(value); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void WriteLine(ulong value) => _out.WriteLine(value); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void WriteLine(float value) => _out.WriteLine(value); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void WriteLine(double value) => _out.WriteLine(value); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void WriteLine(string value) => _out.WriteLine(value); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void WriteLine(object value) => _out.WriteLine(value); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void WriteLine(string format, object arg0) => _out.WriteLine(format, arg0); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void WriteLine(string format, object arg0, object arg1) => _out.WriteLine(format, arg0, arg1); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void WriteLine(string format, object arg0, object arg1, object arg2) => _out.WriteLine(format, arg0, arg1, arg2); + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void WriteLine(string format, object[] arg) => _out.WriteLine(format, arg); + + // + // On SyncTextWriter all APIs should run synchronously, even the async ones. + // + + [MethodImpl(MethodImplOptions.Synchronized)] + public override Task WriteAsync(char value) + { + Write(value); + return Task.CompletedTask; + } + + [MethodImpl(MethodImplOptions.Synchronized)] + public override Task WriteAsync(string value) + { + Write(value); + return Task.CompletedTask; + } + + [MethodImpl(MethodImplOptions.Synchronized)] + public override Task WriteAsync(char[] buffer, int index, int count) + { + Write(buffer, index, count); + return Task.CompletedTask; + } + + [MethodImpl(MethodImplOptions.Synchronized)] + public override Task WriteLineAsync(char value) + { + WriteLine(value); + return Task.CompletedTask; + } + + [MethodImpl(MethodImplOptions.Synchronized)] + public override Task WriteLineAsync(string value) + { + WriteLine(value); + return Task.CompletedTask; + } + + [MethodImpl(MethodImplOptions.Synchronized)] + public override Task WriteLineAsync(char[] buffer, int index, int count) + { + WriteLine(buffer, index, count); + return Task.CompletedTask; + } + + [MethodImpl(MethodImplOptions.Synchronized)] + public override Task FlushAsync() + { + Flush(); + return Task.CompletedTask; + } + } + } +} diff --git a/external/corert/src/System.Private.CoreLib/shared/System/IO/UnmanagedMemoryStream.cs b/external/corert/src/System.Private.CoreLib/shared/System/IO/UnmanagedMemoryStream.cs index 171113542f..d1a13156a8 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/IO/UnmanagedMemoryStream.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/IO/UnmanagedMemoryStream.cs @@ -510,7 +510,7 @@ namespace System.IO // something other than an array and this is an UnmanagedMemoryStream-derived type that doesn't override Read(Span) will // it then fall back to doing the ArrayPool/copy behavior. return new ValueTask( - destination.TryGetArray(out ArraySegment destinationArray) ? + MemoryMarshal.TryGetArray(destination, out ArraySegment destinationArray) ? Read(destinationArray.Array, destinationArray.Offset, destinationArray.Count) : Read(destination.Span)); } @@ -783,11 +783,11 @@ namespace System.IO /// /// Buffer that will be written. /// Token that can be used to cancel the operation. - public override Task WriteAsync(ReadOnlyMemory source, CancellationToken cancellationToken = default(CancellationToken)) + public override ValueTask WriteAsync(ReadOnlyMemory source, CancellationToken cancellationToken = default(CancellationToken)) { if (cancellationToken.IsCancellationRequested) { - return Task.FromCanceled(cancellationToken); + return new ValueTask(Task.FromCanceled(cancellationToken)); } try @@ -802,11 +802,11 @@ namespace System.IO { Write(source.Span); } - return Task.CompletedTask; + return default; } catch (Exception ex) { - return Task.FromException(ex); + return new ValueTask(Task.FromException(ex)); } } diff --git a/external/corert/src/System.Private.CoreLib/shared/System/IO/UnmanagedMemoryStreamWrapper.cs b/external/corert/src/System.Private.CoreLib/shared/System/IO/UnmanagedMemoryStreamWrapper.cs index 90bb21ac5b..f34c3c4137 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/IO/UnmanagedMemoryStreamWrapper.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/IO/UnmanagedMemoryStreamWrapper.cs @@ -217,7 +217,7 @@ namespace System.IO return _unmanagedStream.WriteAsync(buffer, offset, count, cancellationToken); } - public override Task WriteAsync(ReadOnlyMemory source, CancellationToken cancellationToken = default(CancellationToken)) + public override ValueTask WriteAsync(ReadOnlyMemory source, CancellationToken cancellationToken = default(CancellationToken)) { return _unmanagedStream.WriteAsync(source, cancellationToken); } diff --git a/external/corert/src/System.Private.CoreLib/shared/System/IO/Win32Marshal.cs b/external/corert/src/System.Private.CoreLib/shared/System/IO/Win32Marshal.cs index e25d3ccc37..f6dd5f3cd1 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/IO/Win32Marshal.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/IO/Win32Marshal.cs @@ -80,7 +80,7 @@ namespace System.IO return new PathTooLongException(SR.Format(SR.IO_PathTooLong_Path, path)); case Interop.Errors.ERROR_INVALID_DRIVE: - throw new DriveNotFoundException(SR.Format(SR.IO_DriveNotFound_Drive, path)); + throw new DriveNotFoundException(SR.Format(SR.IO_DriveNotFound_Drive, path)); case Interop.Errors.ERROR_INVALID_PARAMETER: return new IOException(Interop.Kernel32.GetMessage(errorCode), MakeHRFromErrorCode(errorCode)); diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Math.cs b/external/corert/src/System.Private.CoreLib/shared/System/Math.cs index bdb237da38..a175103f81 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Math.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Math.cs @@ -36,31 +36,73 @@ namespace System 1E9, 1E10, 1E11, 1E12, 1E13, 1E14, 1E15 }; + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static short Abs(short value) { - return (value >= 0) ? value : AbsHelper(value); + if (value < 0) + { + value = (short)-value; + if (value < 0) + { + ThrowAbsOverflow(); + } + } + return value; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Abs(int value) { - return (value >= 0) ? value : AbsHelper(value); + if (value < 0) + { + value = -value; + if (value < 0) + { + ThrowAbsOverflow(); + } + } + return value; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Abs(long value) { - return (value >= 0) ? value : AbsHelper(value); + if (value < 0) + { + value = -value; + if (value < 0) + { + ThrowAbsOverflow(); + } + } + return value; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] [CLSCompliant(false)] public static sbyte Abs(sbyte value) { - return (value >= 0) ? value : AbsHelper(value); + if (value < 0) + { + value = (sbyte)-value; + if (value < 0) + { + ThrowAbsOverflow(); + } + } + return value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static decimal Abs(decimal value) { - return decimal.Abs(value); + return decimal.Abs(ref value); + } + + [StackTraceHidden] + private static void ThrowAbsOverflow() + { + throw new OverflowException(SR.Overflow_NegateTwosCompNum); } public static long BigMul(int a, int b) @@ -411,7 +453,7 @@ namespace System [MethodImpl(MethodImplOptions.AggressiveInlining)] public static decimal Max(decimal val1, decimal val2) { - return decimal.Max(val1, val2); + return decimal.Max(ref val1, ref val2); } public static double Max(double val1, double val2) @@ -499,7 +541,7 @@ namespace System [MethodImpl(MethodImplOptions.AggressiveInlining)] public static decimal Min(decimal val1, decimal val2) { - return decimal.Min(val1, val2); + return decimal.Min(ref val1, ref val2); } public static double Min(double val1, double val2) @@ -758,54 +800,6 @@ namespace System return d; } - private static short AbsHelper(short value) - { - Debug.Assert(value < 0, "AbsHelper should only be called for negative values! (workaround for JIT inlining)"); - - if (value == short.MinValue) - { - throw new OverflowException(SR.Overflow_NegateTwosCompNum); - } - - return ((short)(-value)); - } - - private static int AbsHelper(int value) - { - Debug.Assert(value < 0, "AbsHelper should only be called for negative values! (workaround for JIT inlining)"); - - if (value == int.MinValue) - { - throw new OverflowException(SR.Overflow_NegateTwosCompNum); - } - - return -value; - } - - private static long AbsHelper(long value) - { - Debug.Assert(value < 0, "AbsHelper should only be called for negative values! (workaround for JIT inlining)"); - - if (value == long.MinValue) - { - throw new OverflowException(SR.Overflow_NegateTwosCompNum); - } - - return -value; - } - - private static sbyte AbsHelper(sbyte value) - { - Debug.Assert(value < 0, "AbsHelper should only be called for negative values! (workaround for JIT inlining)"); - - if (value == sbyte.MinValue) - { - throw new OverflowException(SR.Overflow_NegateTwosCompNum); - } - - return ((sbyte)(-value)); - } - private static unsafe double copysign(double x, double y) { var xbits = BitConverter.DoubleToInt64Bits(x); diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Memory.cs b/external/corert/src/System.Private.CoreLib/shared/System/Memory.cs index 2286d699d3..fca015f5e5 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Memory.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Memory.cs @@ -8,10 +8,16 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using EditorBrowsableAttribute = System.ComponentModel.EditorBrowsableAttribute; using EditorBrowsableState = System.ComponentModel.EditorBrowsableState; +#if !FEATURE_PORTABLE_SPAN using Internal.Runtime.CompilerServices; +#endif // FEATURE_PORTABLE_SPAN namespace System { + /// + /// Memory represents a contiguous region of arbitrary memory similar to . + /// Unlike , it is not a byref-like type. + /// [DebuggerDisplay("{DebuggerDisplay,nq}")] [DebuggerTypeProxy(typeof(MemoryDebugView<>))] public readonly struct Memory @@ -34,14 +40,16 @@ namespace System /// Creates a new memory over the entirety of the target array. /// /// The target array. - /// Thrown when is a null - /// reference (Nothing in Visual Basic). + /// Returns default when is null. /// Thrown when is covariant and array's type is not exactly T[]. [MethodImpl(MethodImplOptions.AggressiveInlining)] public Memory(T[] array) { if (array == null) - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); + { + this = default; + return; // returns default + } if (default(T) == null && array.GetType() != typeof(T[])) ThrowHelper.ThrowArrayTypeMismatchException(); @@ -50,6 +58,26 @@ namespace System _length = array.Length; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Memory(T[] array, int start) + { + if (array == null) + { + if (start != 0) + ThrowHelper.ThrowArgumentOutOfRangeException(); + this = default; + return; // returns default + } + if (default(T) == null && array.GetType() != typeof(T[])) + ThrowHelper.ThrowArrayTypeMismatchException(); + if ((uint)start > (uint)array.Length) + ThrowHelper.ThrowArgumentOutOfRangeException(); + + _object = array; + _index = start; + _length = array.Length - start; + } + /// /// Creates a new memory over the portion of the target array beginning /// at 'start' index and ending at 'end' index (exclusive). @@ -57,8 +85,7 @@ namespace System /// The target array. /// The index at which to begin the memory. /// The number of items in the memory. - /// Thrown when is a null - /// reference (Nothing in Visual Basic). + /// Returns default when is null. /// Thrown when is covariant and array's type is not exactly T[]. /// /// Thrown when the specified or end index is not in the range (<0 or >=Length). @@ -67,7 +94,12 @@ namespace System public Memory(T[] array, int start, int length) { if (array == null) - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); + { + if (start != 0 || length != 0) + ThrowHelper.ThrowArgumentOutOfRangeException(); + this = default; + return; // returns default + } if (default(T) == null && array.GetType() != typeof(T[])) ThrowHelper.ThrowArrayTypeMismatchException(); if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start)) @@ -77,16 +109,12 @@ namespace System _index = start; _length = length; } - + // Constructor for internal use only. [MethodImpl(MethodImplOptions.AggressiveInlining)] internal Memory(OwnedMemory owner, int index, int length) { - if (owner == null) - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.ownedMemory); - if (index < 0 || length < 0) - ThrowHelper.ThrowArgumentOutOfRangeException(); - + // No validation performed; caller must provide any necessary validation. _object = owner; _index = index | (1 << 31); // Before using _index, check if _index < 0, then 'and' it with RemoveOwnedFlagBitMask _length = length; @@ -105,7 +133,7 @@ namespace System /// Defines an implicit conversion of an array to a /// public static implicit operator Memory(T[] array) => new Memory(array); - + /// /// Defines an implicit conversion of a to a /// @@ -168,7 +196,7 @@ namespace System { ThrowHelper.ThrowArgumentOutOfRangeException(); } - + return new Memory(_object, _index + start, length); } @@ -191,7 +219,11 @@ namespace System // and then cast to a Memory. Such a cast can only be done with unsafe or marshaling code, // in which case that's the dangerous operation performed by the dev, and we're just following // suit here to make it work as best as possible. +#if FEATURE_PORTABLE_SPAN + return new Span(Unsafe.As>(s), MemoryExtensions.StringAdjustment, s.Length).Slice(_index, _length); +#else return new Span(ref Unsafe.As(ref s.GetRawStringData()), s.Length).Slice(_index, _length); +#endif // FEATURE_PORTABLE_SPAN } else if (_object != null) { @@ -227,6 +259,10 @@ namespace System /// The span to copy items into. public bool TryCopyTo(Memory destination) => Span.TryCopyTo(destination.Span); + /// + /// Returns a handle for the array. + /// If pin is true, the GC will not move the array and hence its address can be taken + /// public unsafe MemoryHandle Retain(bool pin = false) { MemoryHandle memoryHandle = default; @@ -234,8 +270,7 @@ namespace System { if (_index < 0) { - memoryHandle = ((OwnedMemory)_object).Pin(); - memoryHandle.AddOffset((_index & RemoveOwnedFlagBitMask) * Unsafe.SizeOf()); + memoryHandle = ((OwnedMemory)_object).Pin((_index & RemoveOwnedFlagBitMask) * Unsafe.SizeOf()); } else if (typeof(T) == typeof(char) && _object is string s) { @@ -245,13 +280,21 @@ namespace System // a readable ReadOnlyMemory or a writable Memory can still be pinned and // used for interop purposes. GCHandle handle = GCHandle.Alloc(s, GCHandleType.Pinned); +#if FEATURE_PORTABLE_SPAN + void* pointer = Unsafe.Add((void*)handle.AddrOfPinnedObject(), _index); +#else void* pointer = Unsafe.Add(Unsafe.AsPointer(ref s.GetRawStringData()), _index); +#endif // FEATURE_PORTABLE_SPAN memoryHandle = new MemoryHandle(null, pointer, handle); } else if (_object is T[] array) { var handle = GCHandle.Alloc(array, GCHandleType.Pinned); +#if FEATURE_PORTABLE_SPAN + void* pointer = Unsafe.Add((void*)handle.AddrOfPinnedObject(), _index); +#else void* pointer = Unsafe.Add(Unsafe.AsPointer(ref array.GetRawSzArrayData()), _index); +#endif // FEATURE_PORTABLE_SPAN memoryHandle = new MemoryHandle(null, pointer, handle); } } @@ -266,30 +309,6 @@ namespace System return memoryHandle; } - /// - /// Get an array segment from the underlying memory. - /// If unable to get the array segment, return false with a default array segment. - /// - public bool TryGetArray(out ArraySegment arraySegment) - { - if (_index < 0) - { - if (((OwnedMemory)_object).TryGetArray(out var segment)) - { - arraySegment = new ArraySegment(segment.Array, segment.Offset + (_index & RemoveOwnedFlagBitMask), _length); - return true; - } - } - else if (_object is T[] arr) - { - arraySegment = new ArraySegment(arr, _index, _length); - return true; - } - - arraySegment = default(ArraySegment); - return false; - } - /// /// Copies the contents from the memory into a new array. This heap /// allocates, so should generally be avoided, however it is sometimes @@ -297,6 +316,10 @@ namespace System /// public T[] ToArray() => Span.ToArray(); + /// + /// Determines whether the specified object is equal to the current object. + /// Returns true if the object is Memory or ReadOnlyMemory and if both objects point to the same array and have the same length. + /// [EditorBrowsable(EditorBrowsableState.Never)] public override bool Equals(object obj) { @@ -326,6 +349,9 @@ namespace System _length == other._length; } + /// + /// Serves as the default hash function. + /// [EditorBrowsable(EditorBrowsableState.Never)] public override int GetHashCode() { diff --git a/external/corert/src/System.Private.CoreLib/shared/System/MemoryDebugView.cs b/external/corert/src/System.Private.CoreLib/shared/System/MemoryDebugView.cs index 2706d09279..b1ed881990 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/MemoryDebugView.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/MemoryDebugView.cs @@ -36,12 +36,16 @@ namespace System } if (typeof(T) == typeof(char) && - ((ReadOnlyMemory)(object)_memory).TryGetString(out string text, out int start, out int length)) + MemoryMarshal.TryGetString((ReadOnlyMemory)(object)_memory, out string text, out int start, out int length)) { return (T[])(object)text.Substring(start, length).ToCharArray(); } +#if FEATURE_PORTABLE_SPAN + return SpanHelpers.PerTypeValues.EmptyArray; +#else return Array.Empty(); +#endif // FEATURE_PORTABLE_SPAN } } } diff --git a/external/corert/src/System.Private.CoreLib/shared/System/MemoryExtensions.Fast.cs b/external/corert/src/System.Private.CoreLib/shared/System/MemoryExtensions.Fast.cs new file mode 100644 index 0000000000..56dd203e1f --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/shared/System/MemoryExtensions.Fast.cs @@ -0,0 +1,516 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; +using System.Globalization; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using Internal.Runtime.CompilerServices; + +namespace System +{ + /// + /// Extension methods for Span{T}, Memory{T}, and friends. + /// + public static partial class MemoryExtensions + { + /// + /// Returns a value indicating whether the specified occurs within the . + /// The source span. + /// The value to seek within the source span. + /// One of the enumeration values that determines how the and are compared. + /// + public static bool Contains(this ReadOnlySpan span, ReadOnlySpan value, StringComparison comparisonType) + { + return (IndexOf(span, value, comparisonType) >= 0); + } + + /// + /// Determines whether this and the specified span have the same characters + /// when compared using the specified option. + /// The source span. + /// The value to compare with the source span. + /// One of the enumeration values that determines how the and are compared. + /// + public static bool Equals(this ReadOnlySpan span, ReadOnlySpan value, StringComparison comparisonType) + { + StringSpanHelpers.CheckStringComparison(comparisonType); + + switch (comparisonType) + { + case StringComparison.CurrentCulture: + return (CultureInfo.CurrentCulture.CompareInfo.Compare(span, value, CompareOptions.None) == 0); + + case StringComparison.CurrentCultureIgnoreCase: + return (CultureInfo.CurrentCulture.CompareInfo.Compare(span, value, CompareOptions.IgnoreCase) == 0); + + case StringComparison.InvariantCulture: + return (CompareInfo.Invariant.Compare(span, value, CompareOptions.None) == 0); + + case StringComparison.InvariantCultureIgnoreCase: + return (CompareInfo.Invariant.Compare(span, value, CompareOptions.IgnoreCase) == 0); + + case StringComparison.Ordinal: + if (span.Length != value.Length) + return false; + if (value.Length == 0) // span.Length == value.Length == 0 + return true; + return span.SequenceEqual(value); //TODO: Optimize - https://github.com/dotnet/corefx/issues/27487 + + case StringComparison.OrdinalIgnoreCase: + if (span.Length != value.Length) + return false; + if (value.Length == 0) // span.Length == value.Length == 0 + return true; + return (CompareInfo.CompareOrdinalIgnoreCase(span, value) == 0); + } + + Debug.Fail("StringComparison outside range"); + return false; + } + + /// + /// Compares the specified and using the specified , + /// and returns an integer that indicates their relative position in the sort order. + /// The source span. + /// The value to compare with the source span. + /// One of the enumeration values that determines how the and are compared. + /// + public static int CompareTo(this ReadOnlySpan span, ReadOnlySpan value, StringComparison comparisonType) + { + StringSpanHelpers.CheckStringComparison(comparisonType); + + switch (comparisonType) + { + case StringComparison.CurrentCulture: + return CultureInfo.CurrentCulture.CompareInfo.Compare(span, value, CompareOptions.None); + + case StringComparison.CurrentCultureIgnoreCase: + return CultureInfo.CurrentCulture.CompareInfo.Compare(span, value, CompareOptions.IgnoreCase); + + case StringComparison.InvariantCulture: + return CompareInfo.Invariant.Compare(span, value, CompareOptions.None); + + case StringComparison.InvariantCultureIgnoreCase: + return CompareInfo.Invariant.Compare(span, value, CompareOptions.IgnoreCase); + + case StringComparison.Ordinal: + if (span.Length == 0 || value.Length == 0) + return span.Length - value.Length; + return string.CompareOrdinal(span, value); + + case StringComparison.OrdinalIgnoreCase: + return CompareInfo.CompareOrdinalIgnoreCase(span, value); + } + + Debug.Fail("StringComparison outside range"); + return 0; + } + + /// + /// Reports the zero-based index of the first occurrence of the specified in the current . + /// The source span. + /// The value to seek within the source span. + /// One of the enumeration values that determines how the and are compared. + /// + public static int IndexOf(this ReadOnlySpan span, ReadOnlySpan value, StringComparison comparisonType) + { + StringSpanHelpers.CheckStringComparison(comparisonType); + + if (value.Length == 0) + { + return 0; + } + + if (span.Length == 0) + { + return -1; + } + + switch (comparisonType) + { + case StringComparison.CurrentCulture: + return SpanHelpers.IndexOfCultureHelper(span, value, CultureInfo.CurrentCulture.CompareInfo); + + case StringComparison.CurrentCultureIgnoreCase: + return SpanHelpers.IndexOfCultureIgnoreCaseHelper(span, value, CultureInfo.CurrentCulture.CompareInfo); + + case StringComparison.InvariantCulture: + return SpanHelpers.IndexOfCultureHelper(span, value, CompareInfo.Invariant); + + case StringComparison.InvariantCultureIgnoreCase: + return SpanHelpers.IndexOfCultureIgnoreCaseHelper(span, value, CompareInfo.Invariant); + + case StringComparison.Ordinal: + return SpanHelpers.IndexOfOrdinalHelper(span, value, ignoreCase: false); + + case StringComparison.OrdinalIgnoreCase: + return SpanHelpers.IndexOfOrdinalHelper(span, value, ignoreCase: true); + } + + Debug.Fail("StringComparison outside range"); + return -1; + } + + /// + /// Copies the characters from the source span into the destination, converting each character to lowercase, + /// using the casing rules of the specified culture. + /// + /// The source span. + /// The destination span which contains the transformed characters. + /// An object that supplies culture-specific casing rules. + /// If the source and destinations overlap, this method behaves as if the original values are in + /// a temporary location before the destination is overwritten. + /// + /// Thrown when is null. + /// + public static int ToLower(this ReadOnlySpan source, Span destination, CultureInfo culture) + { + if (culture == null) + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.culture); + + // Assuming that changing case does not affect length + if (destination.Length < source.Length) + return -1; + + if (GlobalizationMode.Invariant) + culture.TextInfo.ToLowerAsciiInvariant(source, destination); + else + culture.TextInfo.ChangeCase(source, destination, toUpper: false); + return source.Length; + } + + /// + /// Copies the characters from the source span into the destination, converting each character to lowercase, + /// using the casing rules of the invariant culture. + /// + /// The source span. + /// The destination span which contains the transformed characters. + /// If the source and destinations overlap, this method behaves as if the original values are in + /// a temporary location before the destination is overwritten. + public static int ToLowerInvariant(this ReadOnlySpan source, Span destination) + { + // Assuming that changing case does not affect length + if (destination.Length < source.Length) + return -1; + + if (GlobalizationMode.Invariant) + CultureInfo.InvariantCulture.TextInfo.ToLowerAsciiInvariant(source, destination); + else + CultureInfo.InvariantCulture.TextInfo.ChangeCase(source, destination, toUpper: false); + return source.Length; + } + + /// + /// Copies the characters from the source span into the destination, converting each character to uppercase, + /// using the casing rules of the specified culture. + /// + /// The source span. + /// The destination span which contains the transformed characters. + /// An object that supplies culture-specific casing rules. + /// If the source and destinations overlap, this method behaves as if the original values are in + /// a temporary location before the destination is overwritten. + /// + /// Thrown when is null. + /// + public static int ToUpper(this ReadOnlySpan source, Span destination, CultureInfo culture) + { + if (culture == null) + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.culture); + + // Assuming that changing case does not affect length + if (destination.Length < source.Length) + return -1; + + if (GlobalizationMode.Invariant) + culture.TextInfo.ToUpperAsciiInvariant(source, destination); + else + culture.TextInfo.ChangeCase(source, destination, toUpper: true); + return source.Length; + } + + /// + /// Copies the characters from the source span into the destination, converting each character to uppercase + /// using the casing rules of the invariant culture. + /// + /// The source span. + /// The destination span which contains the transformed characters. + /// If the source and destinations overlap, this method behaves as if the original values are in + /// a temporary location before the destination is overwritten. + public static int ToUpperInvariant(this ReadOnlySpan source, Span destination) + { + // Assuming that changing case does not affect length + if (destination.Length < source.Length) + return -1; + + if (GlobalizationMode.Invariant) + CultureInfo.InvariantCulture.TextInfo.ToUpperAsciiInvariant(source, destination); + else + CultureInfo.InvariantCulture.TextInfo.ChangeCase(source, destination, toUpper: true); + return source.Length; + } + + /// + /// Determines whether the end of the matches the specified when compared using the specified option. + /// + /// The source span. + /// The sequence to compare to the end of the source span. + /// One of the enumeration values that determines how the and are compared. + public static bool EndsWith(this ReadOnlySpan span, ReadOnlySpan value, StringComparison comparisonType) + { + if (value.Length == 0) + { + StringSpanHelpers.CheckStringComparison(comparisonType); + return true; + } + + switch (comparisonType) + { + case StringComparison.CurrentCulture: + return SpanHelpers.EndsWithCultureHelper(span, value, CultureInfo.CurrentCulture.CompareInfo); + + case StringComparison.CurrentCultureIgnoreCase: + return SpanHelpers.EndsWithCultureIgnoreCaseHelper(span, value, CultureInfo.CurrentCulture.CompareInfo); + + case StringComparison.InvariantCulture: + return SpanHelpers.EndsWithCultureHelper(span, value, CompareInfo.Invariant); + + case StringComparison.InvariantCultureIgnoreCase: + return SpanHelpers.EndsWithCultureIgnoreCaseHelper(span, value, CompareInfo.Invariant); + + case StringComparison.Ordinal: + return span.EndsWith(value); //TODO: Optimize - https://github.com/dotnet/corefx/issues/27487 + + case StringComparison.OrdinalIgnoreCase: + return SpanHelpers.EndsWithOrdinalIgnoreCaseHelper(span, value); + + default: + throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType)); + } + } + + /// + /// Determines whether the beginning of the matches the specified when compared using the specified option. + /// + /// The source span. + /// The sequence to compare to the beginning of the source span. + /// One of the enumeration values that determines how the and are compared. + public static bool StartsWith(this ReadOnlySpan span, ReadOnlySpan value, StringComparison comparisonType) + { + if (value.Length == 0) + { + StringSpanHelpers.CheckStringComparison(comparisonType); + return true; + } + + switch (comparisonType) + { + case StringComparison.CurrentCulture: + return SpanHelpers.StartsWithCultureHelper(span, value, CultureInfo.CurrentCulture.CompareInfo); + + case StringComparison.CurrentCultureIgnoreCase: + return SpanHelpers.StartsWithCultureIgnoreCaseHelper(span, value, CultureInfo.CurrentCulture.CompareInfo); + + case StringComparison.InvariantCulture: + return SpanHelpers.StartsWithCultureHelper(span, value, CompareInfo.Invariant); + + case StringComparison.InvariantCultureIgnoreCase: + return SpanHelpers.StartsWithCultureIgnoreCaseHelper(span, value, CompareInfo.Invariant); + + case StringComparison.Ordinal: + return span.StartsWith(value); //TODO: Optimize - https://github.com/dotnet/corefx/issues/27487 + + case StringComparison.OrdinalIgnoreCase: + return SpanHelpers.StartsWithOrdinalIgnoreCaseHelper(span, value); + + default: + throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType)); + } + } + + /// + /// Casts a Span of one primitive type to Span of bytes. + /// That type may not contain pointers or references. This is checked at runtime in order to preserve type safety. + /// + /// The source slice, of type . + /// + /// Thrown when contains pointers. + /// + /// + /// Thrown if the Length property of the new Span would exceed Int32.MaxValue. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Span AsBytes(this Span source) + where T : struct + { + if (RuntimeHelpers.IsReferenceOrContainsReferences()) + ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T)); + + return new Span( + ref Unsafe.As(ref MemoryMarshal.GetReference(source)), + checked(source.Length * Unsafe.SizeOf())); + } + + /// + /// Casts a ReadOnlySpan of one primitive type to ReadOnlySpan of bytes. + /// That type may not contain pointers or references. This is checked at runtime in order to preserve type safety. + /// + /// The source slice, of type . + /// + /// Thrown when contains pointers. + /// + /// + /// Thrown if the Length property of the new Span would exceed Int32.MaxValue. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ReadOnlySpan AsBytes(this ReadOnlySpan source) + where T : struct + { + if (RuntimeHelpers.IsReferenceOrContainsReferences()) + ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T)); + + return new ReadOnlySpan( + ref Unsafe.As(ref MemoryMarshal.GetReference(source)), + checked(source.Length * Unsafe.SizeOf())); + } + + /// + /// Creates a new span over the portion of the target array. + /// + public static Span AsSpan(this T[] array, int start) + { + if (array == null) + { + if (start != 0) + ThrowHelper.ThrowArgumentOutOfRangeException(); + return default; + } + if (default(T) == null && array.GetType() != typeof(T[])) + ThrowHelper.ThrowArrayTypeMismatchException(); + if ((uint)start > (uint)array.Length) + ThrowHelper.ThrowArgumentOutOfRangeException(); + + return new Span(ref Unsafe.Add(ref Unsafe.As(ref array.GetRawSzArrayData()), start), array.Length - start); + } + + /// + /// Creates a new readonly span over the portion of the target string. + /// + /// The target string. + /// Returns default when is null. + public static ReadOnlySpan AsSpan(this string text) + { + if (text == null) + return default; + + return new ReadOnlySpan(ref text.GetRawStringData(), text.Length); + } + + /// + /// Creates a new readonly span over the portion of the target string. + /// + /// The target string. + /// The index at which to begin this slice. + /// Thrown when is null. + /// + /// Thrown when the specified index is not in range (<0 or >text.Length). + /// + public static ReadOnlySpan AsSpan(this string text, int start) + { + if (text == null) + { + if (start != 0) + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start); + return default; + } + + if ((uint)start > (uint)text.Length) + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start); + + return new ReadOnlySpan(ref Unsafe.Add(ref text.GetRawStringData(), start), text.Length - start); + } + + /// + /// Creates a new readonly span over the portion of the target string. + /// + /// The target string. + /// The index at which to begin this slice. + /// The desired length for the slice (exclusive). + /// Returns default when is null. + /// + /// Thrown when the specified index or is not in range. + /// + public static ReadOnlySpan AsSpan(this string text, int start, int length) + { + if (text == null) + { + if (start != 0 || length != 0) + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start); + return default; + } + + if ((uint)start > (uint)text.Length || (uint)length > (uint)(text.Length - start)) + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start); + + return new ReadOnlySpan(ref Unsafe.Add(ref text.GetRawStringData(), start), length); + } + + /// Creates a new over the portion of the target string. + /// The target string. + /// Returns default when is null. + public static ReadOnlyMemory AsMemory(this string text) + { + if (text == null) + return default; + + return new ReadOnlyMemory(text, 0, text.Length); + } + + /// Creates a new over the portion of the target string. + /// The target string. + /// The index at which to begin this slice. + /// Returns default when is null. + /// + /// Thrown when the specified index is not in range (<0 or >text.Length). + /// + public static ReadOnlyMemory AsMemory(this string text, int start) + { + if (text == null) + { + if (start != 0) + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start); + return default; + } + + if ((uint)start > (uint)text.Length) + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start); + + return new ReadOnlyMemory(text, start, text.Length - start); + } + + /// Creates a new over the portion of the target string. + /// The target string. + /// The index at which to begin this slice. + /// The desired length for the slice (exclusive). + /// Returns default when is null. + /// + /// Thrown when the specified index or is not in range. + /// + public static ReadOnlyMemory AsMemory(this string text, int start, int length) + { + if (text == null) + { + if (start != 0 || length != 0) + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start); + return default; + } + + if ((uint)start > (uint)text.Length || (uint)length > (uint)(text.Length - start)) + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start); + + return new ReadOnlyMemory(text, start, length); + } + } +} diff --git a/external/corert/src/System.Private.CoreLib/shared/System/MemoryExtensions.cs b/external/corert/src/System.Private.CoreLib/shared/System/MemoryExtensions.cs new file mode 100644 index 0000000000..effdecf92c --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/shared/System/MemoryExtensions.cs @@ -0,0 +1,1170 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +#if !netstandard +using Internal.Runtime.CompilerServices; +#endif + +namespace System +{ + /// + /// Extension methods for Span{T}, Memory{T}, and friends. + /// + public static partial class MemoryExtensions + { + /// + /// Removes all leading and trailing white-space characters from the span. + /// + public static ReadOnlySpan Trim(this ReadOnlySpan span) + { + return span.TrimStart().TrimEnd(); + } + + /// + /// Removes all leading white-space characters from the span. + /// + public static ReadOnlySpan TrimStart(this ReadOnlySpan span) + { + int start = 0; + for (; start < span.Length; start++) + { + if (!char.IsWhiteSpace(span[start])) + break; + } + return span.Slice(start); + } + + /// + /// Removes all trailing white-space characters from the span. + /// + public static ReadOnlySpan TrimEnd(this ReadOnlySpan span) + { + int end = span.Length - 1; + for (; end >= 0; end--) + { + if (!char.IsWhiteSpace(span[end])) + break; + } + return span.Slice(0, end + 1); + } + + /// + /// Removes all leading and trailing occurrences of a specified character. + /// + /// The source span from which the character is removed. + /// The specified character to look for and remove. + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ReadOnlySpan Trim(this ReadOnlySpan span, char trimChar) + { + return span.TrimStart(trimChar).TrimEnd(trimChar); + } + + /// + /// Removes all leading occurrences of a specified character. + /// + /// The source span from which the character is removed. + /// The specified character to look for and remove. + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ReadOnlySpan TrimStart(this ReadOnlySpan span, char trimChar) + { + int start = 0; + for (; start < span.Length; start++) + { + if (span[start] != trimChar) + break; + } + return span.Slice(start); + } + + /// + /// Removes all trailing occurrences of a specified character. + /// + /// The source span from which the character is removed. + /// The specified character to look for and remove. + public static ReadOnlySpan TrimEnd(this ReadOnlySpan span, char trimChar) + { + int end = span.Length - 1; + for (; end >= 0; end--) + { + if (span[end] != trimChar) + break; + } + return span.Slice(0, end + 1); + } + + /// + /// Removes all leading and trailing occurrences of a set of characters specified + /// in a readonly span from the span. + /// + /// The source span from which the characters are removed. + /// The span which contains the set of characters to remove. + public static ReadOnlySpan Trim(this ReadOnlySpan span, ReadOnlySpan trimChars) + { + return span.TrimStart(trimChars).TrimEnd(trimChars); + } + + /// + /// Removes all leading occurrences of a set of characters specified + /// in a readonly span from the span. + /// + /// The source span from which the characters are removed. + /// The span which contains the set of characters to remove. + public static ReadOnlySpan TrimStart(this ReadOnlySpan span, ReadOnlySpan trimChars) + { + int start = 0; + for (; start < span.Length; start++) + { + for (int i = 0; i < trimChars.Length; i++) + { + if (span[start] == trimChars[i]) + goto Next; + } + break; + Next: + ; + } + return span.Slice(start); + } + + /// + /// Removes all trailing occurrences of a set of characters specified + /// in a readonly span from the span. + /// + /// The source span from which the characters are removed. + /// The span which contains the set of characters to remove. + public static ReadOnlySpan TrimEnd(this ReadOnlySpan span, ReadOnlySpan trimChars) + { + int end = span.Length - 1; + for (; end >= 0; end--) + { + for (int i = 0; i < trimChars.Length; i++) + { + if (span[end] == trimChars[i]) + goto Next; + } + break; + Next: + ; + } + return span.Slice(0, end + 1); + } + + /// + /// Indicates whether the specified span contains only white-space characters. + /// + public static bool IsWhiteSpace(this ReadOnlySpan span) + { + for (int i = 0; i < span.Length; i++) + { + if (!char.IsWhiteSpace(span[i])) + return false; + } + return true; + } + + /// + /// Searches for the specified value and returns the index of its first occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T). + /// + /// The span to search. + /// The value to search for. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int IndexOf(this Span span, T value) + where T : IEquatable + { + if (typeof(T) == typeof(byte)) + return SpanHelpers.IndexOf( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.As(ref value), + span.Length); + return SpanHelpers.IndexOf(ref MemoryMarshal.GetReference(span), value, span.Length); + } + + /// + /// Searches for the specified sequence and returns the index of its first occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T). + /// + /// The span to search. + /// The sequence to search for. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int IndexOf(this Span span, ReadOnlySpan value) + where T : IEquatable + { + if (typeof(T) == typeof(byte)) + return SpanHelpers.IndexOf( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + span.Length, + ref Unsafe.As(ref MemoryMarshal.GetReference(value)), + value.Length); + return SpanHelpers.IndexOf(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(value), value.Length); + } + + /// + /// Searches for the specified value and returns the index of its last occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T). + /// + /// The span to search. + /// The value to search for. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int LastIndexOf(this Span span, T value) + where T : IEquatable + { + if (typeof(T) == typeof(byte)) + return SpanHelpers.LastIndexOf( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.As(ref value), + span.Length); + return SpanHelpers.LastIndexOf(ref MemoryMarshal.GetReference(span), value, span.Length); + } + + /// + /// Searches for the specified sequence and returns the index of its last occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T). + /// + /// The span to search. + /// The sequence to search for. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int LastIndexOf(this Span span, ReadOnlySpan value) + where T : IEquatable + { + if (typeof(T) == typeof(byte)) + return SpanHelpers.LastIndexOf( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + span.Length, + ref Unsafe.As(ref MemoryMarshal.GetReference(value)), + value.Length); + return SpanHelpers.LastIndexOf(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(value), value.Length); + } + + /// + /// Determines whether two sequences are equal by comparing the elements using IEquatable{T}.Equals(T). + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool SequenceEqual(this Span first, ReadOnlySpan second) + where T : IEquatable + { + int length = first.Length; + if (typeof(T) == typeof(byte)) + return length == second.Length && + SpanHelpers.SequenceEqual( + ref Unsafe.As(ref MemoryMarshal.GetReference(first)), + ref Unsafe.As(ref MemoryMarshal.GetReference(second)), + length); + return length == second.Length && SpanHelpers.SequenceEqual(ref MemoryMarshal.GetReference(first), ref MemoryMarshal.GetReference(second), length); + } + + /// + /// Determines the relative order of the sequences being compared by comparing the elements using IComparable{T}.CompareTo(T). + /// + public static int SequenceCompareTo(this Span first, ReadOnlySpan second) + where T : IComparable + { + if (typeof(T) == typeof(byte)) + return SpanHelpers.SequenceCompareTo( + ref Unsafe.As(ref MemoryMarshal.GetReference(first)), + first.Length, + ref Unsafe.As(ref MemoryMarshal.GetReference(second)), + second.Length); + return SpanHelpers.SequenceCompareTo(ref MemoryMarshal.GetReference(first), first.Length, ref MemoryMarshal.GetReference(second), second.Length); + } + + /// + /// Reverses the sequence of the elements in the entire span. + /// + public static void Reverse(this Span span) + { + ref T p = ref MemoryMarshal.GetReference(span); + int i = 0; + int j = span.Length - 1; + while (i < j) + { + T temp = Unsafe.Add(ref p, i); + Unsafe.Add(ref p, i) = Unsafe.Add(ref p, j); + Unsafe.Add(ref p, j) = temp; + i++; + j--; + } + } + + /// + /// Searches for the specified value and returns the index of its first occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T). + /// + /// The span to search. + /// The value to search for. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int IndexOf(this ReadOnlySpan span, T value) + where T : IEquatable + { + if (typeof(T) == typeof(byte)) + return SpanHelpers.IndexOf( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.As(ref value), + span.Length); + return SpanHelpers.IndexOf(ref MemoryMarshal.GetReference(span), value, span.Length); + } + + /// + /// Searches for the specified sequence and returns the index of its first occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T). + /// + /// The span to search. + /// The sequence to search for. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int IndexOf(this ReadOnlySpan span, ReadOnlySpan value) + where T : IEquatable + { + if (typeof(T) == typeof(byte)) + return SpanHelpers.IndexOf( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + span.Length, + ref Unsafe.As(ref MemoryMarshal.GetReference(value)), + value.Length); + return SpanHelpers.IndexOf(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(value), value.Length); + } + + /// + /// Searches for the specified value and returns the index of its last occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T). + /// + /// The span to search. + /// The value to search for. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int LastIndexOf(this ReadOnlySpan span, T value) + where T : IEquatable + { + if (typeof(T) == typeof(byte)) + return SpanHelpers.LastIndexOf( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.As(ref value), + span.Length); + return SpanHelpers.LastIndexOf(ref MemoryMarshal.GetReference(span), value, span.Length); + } + + /// + /// Searches for the specified sequence and returns the index of its last occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T). + /// + /// The span to search. + /// The sequence to search for. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int LastIndexOf(this ReadOnlySpan span, ReadOnlySpan value) + where T : IEquatable + { + if (typeof(T) == typeof(byte)) + return SpanHelpers.LastIndexOf( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + span.Length, + ref Unsafe.As(ref MemoryMarshal.GetReference(value)), + value.Length); + return SpanHelpers.LastIndexOf(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(value), value.Length); + } + + /// + /// Searches for the first index of any of the specified values similar to calling IndexOf several times with the logical OR operator. If not found, returns -1. + /// + /// The span to search. + /// One of the values to search for. + /// One of the values to search for. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int IndexOfAny(this Span span, T value0, T value1) + where T : IEquatable + { + if (typeof(T) == typeof(byte)) + return SpanHelpers.IndexOfAny( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.As(ref value0), + Unsafe.As(ref value1), + span.Length); + + return SpanHelpers.IndexOfAny(ref MemoryMarshal.GetReference(span), value0, value1, span.Length); + } + + /// + /// Searches for the first index of any of the specified values similar to calling IndexOf several times with the logical OR operator. If not found, returns -1. + /// + /// The span to search. + /// One of the values to search for. + /// One of the values to search for. + /// One of the values to search for. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int IndexOfAny(this Span span, T value0, T value1, T value2) + where T : IEquatable + { + if (typeof(T) == typeof(byte)) + return SpanHelpers.IndexOfAny( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.As(ref value0), + Unsafe.As(ref value1), + Unsafe.As(ref value2), + span.Length); + + return SpanHelpers.IndexOfAny(ref MemoryMarshal.GetReference(span), value0, value1, value2, span.Length); + } + + /// + /// Searches for the first index of any of the specified values similar to calling IndexOf several times with the logical OR operator. If not found, returns -1. + /// + /// The span to search. + /// The set of values to search for. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int IndexOfAny(this Span span, ReadOnlySpan values) + where T : IEquatable + { + if (typeof(T) == typeof(byte)) + return SpanHelpers.IndexOfAny( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + span.Length, + ref Unsafe.As(ref MemoryMarshal.GetReference(values)), + values.Length); + + return SpanHelpers.IndexOfAny(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(values), values.Length); + } + + /// + /// Searches for the first index of any of the specified values similar to calling IndexOf several times with the logical OR operator. If not found, returns -1. + /// + /// The span to search. + /// One of the values to search for. + /// One of the values to search for. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int IndexOfAny(this ReadOnlySpan span, T value0, T value1) + where T : IEquatable + { + if (typeof(T) == typeof(byte)) + return SpanHelpers.IndexOfAny( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.As(ref value0), + Unsafe.As(ref value1), + span.Length); + + return SpanHelpers.IndexOfAny(ref MemoryMarshal.GetReference(span), value0, value1, span.Length); + } + + /// + /// Searches for the first index of any of the specified values similar to calling IndexOf several times with the logical OR operator. If not found, returns -1. + /// + /// The span to search. + /// One of the values to search for. + /// One of the values to search for. + /// One of the values to search for. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int IndexOfAny(this ReadOnlySpan span, T value0, T value1, T value2) + where T : IEquatable + { + if (typeof(T) == typeof(byte)) + return SpanHelpers.IndexOfAny( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.As(ref value0), + Unsafe.As(ref value1), + Unsafe.As(ref value2), + span.Length); + + return SpanHelpers.IndexOfAny(ref MemoryMarshal.GetReference(span), value0, value1, value2, span.Length); + } + + /// + /// Searches for the first index of any of the specified values similar to calling IndexOf several times with the logical OR operator. If not found, returns -1. + /// + /// The span to search. + /// The set of values to search for. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int IndexOfAny(this ReadOnlySpan span, ReadOnlySpan values) + where T : IEquatable + { + if (typeof(T) == typeof(byte)) + return SpanHelpers.IndexOfAny( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + span.Length, + ref Unsafe.As(ref MemoryMarshal.GetReference(values)), + values.Length); + + return SpanHelpers.IndexOfAny(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(values), values.Length); + } + + /// + /// Searches for the last index of any of the specified values similar to calling LastIndexOf several times with the logical OR operator. If not found, returns -1. + /// + /// The span to search. + /// One of the values to search for. + /// One of the values to search for. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int LastIndexOfAny(this Span span, T value0, T value1) + where T : IEquatable + { + if (typeof(T) == typeof(byte)) + return SpanHelpers.LastIndexOfAny( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.As(ref value0), + Unsafe.As(ref value1), + span.Length); + return SpanHelpers.LastIndexOfAny(ref MemoryMarshal.GetReference(span), value0, value1, span.Length); + } + + /// + /// Searches for the last index of any of the specified values similar to calling LastIndexOf several times with the logical OR operator. If not found, returns -1. + /// + /// The span to search. + /// One of the values to search for. + /// One of the values to search for. + /// One of the values to search for. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int LastIndexOfAny(this Span span, T value0, T value1, T value2) + where T : IEquatable + { + if (typeof(T) == typeof(byte)) + return SpanHelpers.LastIndexOfAny( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.As(ref value0), + Unsafe.As(ref value1), + Unsafe.As(ref value2), + span.Length); + return SpanHelpers.LastIndexOfAny(ref MemoryMarshal.GetReference(span), value0, value1, value2, span.Length); + } + + /// + /// Searches for the last index of any of the specified values similar to calling LastIndexOf several times with the logical OR operator. If not found, returns -1. + /// + /// The span to search. + /// The set of values to search for. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int LastIndexOfAny(this Span span, ReadOnlySpan values) + where T : IEquatable + { + if (typeof(T) == typeof(byte)) + return SpanHelpers.LastIndexOfAny( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + span.Length, + ref Unsafe.As(ref MemoryMarshal.GetReference(values)), + values.Length); + return SpanHelpers.LastIndexOfAny(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(values), values.Length); + } + + /// + /// Searches for the last index of any of the specified values similar to calling LastIndexOf several times with the logical OR operator. If not found, returns -1. + /// + /// The span to search. + /// One of the values to search for. + /// One of the values to search for. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int LastIndexOfAny(this ReadOnlySpan span, T value0, T value1) + where T : IEquatable + { + if (typeof(T) == typeof(byte)) + return SpanHelpers.LastIndexOfAny( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.As(ref value0), + Unsafe.As(ref value1), + span.Length); + return SpanHelpers.LastIndexOfAny(ref MemoryMarshal.GetReference(span), value0, value1, span.Length); + } + + /// + /// Searches for the last index of any of the specified values similar to calling LastIndexOf several times with the logical OR operator. If not found, returns -1. + /// + /// The span to search. + /// One of the values to search for. + /// One of the values to search for. + /// One of the values to search for. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int LastIndexOfAny(this ReadOnlySpan span, T value0, T value1, T value2) + where T : IEquatable + { + if (typeof(T) == typeof(byte)) + return SpanHelpers.LastIndexOfAny( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + Unsafe.As(ref value0), + Unsafe.As(ref value1), + Unsafe.As(ref value2), + span.Length); + return SpanHelpers.LastIndexOfAny(ref MemoryMarshal.GetReference(span), value0, value1, value2, span.Length); + } + + /// + /// Searches for the last index of any of the specified values similar to calling LastIndexOf several times with the logical OR operator. If not found, returns -1. + /// + /// The span to search. + /// The set of values to search for. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int LastIndexOfAny(this ReadOnlySpan span, ReadOnlySpan values) + where T : IEquatable + { + if (typeof(T) == typeof(byte)) + return SpanHelpers.LastIndexOfAny( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + span.Length, + ref Unsafe.As(ref MemoryMarshal.GetReference(values)), + values.Length); + return SpanHelpers.LastIndexOfAny(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(values), values.Length); + } + + /// + /// Determines whether two sequences are equal by comparing the elements using IEquatable{T}.Equals(T). + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool SequenceEqual(this ReadOnlySpan first, ReadOnlySpan second) + where T : IEquatable + { + int length = first.Length; + if (typeof(T) == typeof(byte)) + return length == second.Length && + SpanHelpers.SequenceEqual( + ref Unsafe.As(ref MemoryMarshal.GetReference(first)), + ref Unsafe.As(ref MemoryMarshal.GetReference(second)), + length); + return length == second.Length && SpanHelpers.SequenceEqual(ref MemoryMarshal.GetReference(first), ref MemoryMarshal.GetReference(second), length); + } + + /// + /// Determines the relative order of the sequences being compared by comparing the elements using IComparable{T}.CompareTo(T). + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SequenceCompareTo(this ReadOnlySpan first, ReadOnlySpan second) + where T : IComparable + { + if (typeof(T) == typeof(byte)) + return SpanHelpers.SequenceCompareTo( + ref Unsafe.As(ref MemoryMarshal.GetReference(first)), + first.Length, + ref Unsafe.As(ref MemoryMarshal.GetReference(second)), + second.Length); + return SpanHelpers.SequenceCompareTo(ref MemoryMarshal.GetReference(first), first.Length, ref MemoryMarshal.GetReference(second), second.Length); + } + + /// + /// Determines whether the specified sequence appears at the start of the span. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool StartsWith(this Span span, ReadOnlySpan value) + where T : IEquatable + { + int valueLength = value.Length; + if (typeof(T) == typeof(byte)) + return valueLength <= span.Length && + SpanHelpers.SequenceEqual( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + ref Unsafe.As(ref MemoryMarshal.GetReference(value)), + valueLength); + return valueLength <= span.Length && SpanHelpers.SequenceEqual(ref MemoryMarshal.GetReference(span), ref MemoryMarshal.GetReference(value), valueLength); + } + + /// + /// Determines whether the specified sequence appears at the start of the span. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool StartsWith(this ReadOnlySpan span, ReadOnlySpan value) + where T : IEquatable + { + int valueLength = value.Length; + if (typeof(T) == typeof(byte)) + return valueLength <= span.Length && + SpanHelpers.SequenceEqual( + ref Unsafe.As(ref MemoryMarshal.GetReference(span)), + ref Unsafe.As(ref MemoryMarshal.GetReference(value)), + valueLength); + return valueLength <= span.Length && SpanHelpers.SequenceEqual(ref MemoryMarshal.GetReference(span), ref MemoryMarshal.GetReference(value), valueLength); + } + + /// + /// Determines whether the specified sequence appears at the end of the span. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool EndsWith(this Span span, ReadOnlySpan value) + where T : IEquatable + { + int spanLength = span.Length; + int valueLength = value.Length; + if (typeof(T) == typeof(byte)) + return valueLength <= spanLength && + SpanHelpers.SequenceEqual( + ref Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetReference(span), spanLength - valueLength)), + ref Unsafe.As(ref MemoryMarshal.GetReference(value)), + valueLength); + return valueLength <= spanLength && + SpanHelpers.SequenceEqual( + ref Unsafe.Add(ref MemoryMarshal.GetReference(span), spanLength - valueLength), + ref MemoryMarshal.GetReference(value), + valueLength); + } + + /// + /// Determines whether the specified sequence appears at the end of the span. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool EndsWith(this ReadOnlySpan span, ReadOnlySpan value) + where T : IEquatable + { + int spanLength = span.Length; + int valueLength = value.Length; + if (typeof(T) == typeof(byte)) + return valueLength <= spanLength && + SpanHelpers.SequenceEqual( + ref Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetReference(span), spanLength - valueLength)), + ref Unsafe.As(ref MemoryMarshal.GetReference(value)), + valueLength); + return valueLength <= spanLength && + SpanHelpers.SequenceEqual( + ref Unsafe.Add(ref MemoryMarshal.GetReference(span), spanLength - valueLength), + ref MemoryMarshal.GetReference(value), + valueLength); + } + + /// + /// Creates a new span over the portion of the target array. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Span AsSpan(this T[] array) + { + return new Span(array); + } + + /// + /// Creates a new span over the portion of the target array segment. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Span AsSpan(this ArraySegment arraySegment) + { + return new Span(arraySegment.Array, arraySegment.Offset, arraySegment.Count); + } + + /// + /// Creates a new readonly span over the entire target array. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ReadOnlySpan AsReadOnlySpan(this T[] array) + { + return new ReadOnlySpan(array); + } + + /// + /// Creates a new readonly span over the entire target span. + /// + public static ReadOnlySpan AsReadOnlySpan(this Span span) => span; + + /// + /// Creates a new readonly span over the target array segment. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ReadOnlySpan AsReadOnlySpan(this ArraySegment arraySegment) + { + return new ReadOnlySpan(arraySegment.Array, arraySegment.Offset, arraySegment.Count); + } + + /// + /// Creates a new readonly memory over the entire target memory. + /// + public static ReadOnlyMemory AsReadOnlyMemory(this Memory memory) => memory; + + /// + /// Creates a new memory over the portion of the target array. + /// + public static Memory AsMemory(this T[] array, int start) => new Memory(array, start); + + /// + /// Copies the contents of the array into the span. If the source + /// and destinations overlap, this method behaves as if the original values in + /// a temporary location before the destination is overwritten. + /// + ///The array to copy items from. + /// The span to copy items into. + /// + /// Thrown when the destination Span is shorter than the source array. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void CopyTo(this T[] array, Span destination) + { + new ReadOnlySpan(array).CopyTo(destination); + } + + /// + /// Copies the contents of the array into the memory. If the source + /// and destinations overlap, this method behaves as if the original values are in + /// a temporary location before the destination is overwritten. + /// + ///The array to copy items from. + /// The memory to copy items into. + /// + /// Thrown when the destination is shorter than the source array. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void CopyTo(this T[] array, Memory destination) + { + array.CopyTo(destination.Span); + } + + // + // Overlaps + // ======== + // + // The following methods can be used to determine if two sequences + // overlap in memory. + // + // Two sequences overlap if they have positions in common and neither + // is empty. Empty sequences do not overlap with any other sequence. + // + // If two sequences overlap, the element offset is the number of + // elements by which the second sequence is offset from the first + // sequence (i.e., second minus first). An exception is thrown if the + // number is not a whole number, which can happen when a sequence of a + // smaller type is cast to a sequence of a larger type with unsafe code + // or NonPortableCast. If the sequences do not overlap, the offset is + // meaningless and arbitrarily set to zero. + // + // Implementation + // -------------- + // + // Implementing this correctly is quite tricky due of two problems: + // + // * If the sequences refer to two different objects on the managed + // heap, the garbage collector can move them freely around or change + // their relative order in memory. + // + // * The distance between two sequences can be greater than + // int.MaxValue (on a 32-bit system) or long.MaxValue (on a 64-bit + // system). + // + // (For simplicity, the following text assumes a 32-bit system, but + // everything also applies to a 64-bit system if every 32 is replaced a + // 64.) + // + // The first problem is solved by calculating the distance with exactly + // one atomic operation. If the garbage collector happens to move the + // sequences afterwards and the sequences overlapped before, they will + // still overlap after the move and their distance hasn't changed. If + // the sequences did not overlap, the distance can change but the + // sequences still won't overlap. + // + // The second problem is solved by making all addresses relative to the + // start of the first sequence and performing all operations in + // unsigned integer arithmetic modulo 2³². + // + // Example + // ------- + // + // Let's say there are two sequences, x and y. Let + // + // ref T xRef = MemoryMarshal.GetReference(x) + // uint xLength = x.Length * Unsafe.SizeOf() + // ref T yRef = MemoryMarshal.GetReference(y) + // uint yLength = y.Length * Unsafe.SizeOf() + // + // Visually, the two sequences are located somewhere in the 32-bit + // address space as follows: + // + // [----------------------------------------------) normal address space + // 0 2³² + // [------------------) first sequence + // xRef xRef + xLength + // [--------------------------) . second sequence + // yRef . yRef + yLength + // : . . . + // : . . . + // . . . + // . . . + // . . . + // [----------------------------------------------) relative address space + // 0 . . 2³² + // [------------------) : first sequence + // x1 . x2 : + // -------------) [------------- second sequence + // y2 y1 + // + // The idea is to make all addresses relative to xRef: Let x1 be the + // start address of x in this relative address space, x2 the end + // address of x, y1 the start address of y, and y2 the end address of + // y: + // + // nuint x1 = 0 + // nuint x2 = xLength + // nuint y1 = (nuint)Unsafe.ByteOffset(xRef, yRef) + // nuint y2 = y1 + yLength + // + // xRef relative to xRef is 0. + // + // x2 is simply x1 + xLength. This cannot overflow. + // + // yRef relative to xRef is (yRef - xRef). If (yRef - xRef) is + // negative, casting it to an unsigned 32-bit integer turns it into + // (yRef - xRef + 2³²). So, in the example above, y1 moves to the right + // of x2. + // + // y2 is simply y1 + yLength. Note that this can overflow, as in the + // example above, which must be avoided. + // + // The two sequences do *not* overlap if y is entirely in the space + // right of x in the relative address space. (It can't be left of it!) + // + // (y1 >= x2) && (y2 <= 2³²) + // + // Inversely, they do overlap if + // + // (y1 < x2) || (y2 > 2³²) + // + // After substituting x2 and y2 with their respective definition: + // + // == (y1 < xLength) || (y1 + yLength > 2³²) + // + // Since yLength can't be greater than the size of the address space, + // the overflow can be avoided as follows: + // + // == (y1 < xLength) || (y1 > 2³² - yLength) + // + // However, 2³² cannot be stored in an unsigned 32-bit integer, so one + // more change is needed to keep doing everything with unsigned 32-bit + // integers: + // + // == (y1 < xLength) || (y1 > -yLength) + // + // Due to modulo arithmetic, this gives exactly same result *except* if + // yLength is zero, since 2³² - 0 is 0 and not 2³². So the case + // y.IsEmpty must be handled separately first. + // + + /// + /// Determines whether two sequences overlap in memory. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool Overlaps(this Span first, ReadOnlySpan second) + { + return Overlaps((ReadOnlySpan)first, second); + } + + /// + /// Determines whether two sequences overlap in memory and outputs the element offset. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool Overlaps(this Span first, ReadOnlySpan second, out int elementOffset) + { + return Overlaps((ReadOnlySpan)first, second, out elementOffset); + } + + /// + /// Determines whether two sequences overlap in memory. + /// + public static bool Overlaps(this ReadOnlySpan first, ReadOnlySpan second) + { + if (first.IsEmpty || second.IsEmpty) + { + return false; + } + + IntPtr byteOffset = Unsafe.ByteOffset( + ref MemoryMarshal.GetReference(first), + ref MemoryMarshal.GetReference(second)); + + if (Unsafe.SizeOf() == sizeof(int)) + { + return (uint)byteOffset < (uint)(first.Length * Unsafe.SizeOf()) || + (uint)byteOffset > (uint)-(second.Length * Unsafe.SizeOf()); + } + else + { + return (ulong)byteOffset < (ulong)((long)first.Length * Unsafe.SizeOf()) || + (ulong)byteOffset > (ulong)-((long)second.Length * Unsafe.SizeOf()); + } + } + + /// + /// Determines whether two sequences overlap in memory and outputs the element offset. + /// + public static bool Overlaps(this ReadOnlySpan first, ReadOnlySpan second, out int elementOffset) + { + if (first.IsEmpty || second.IsEmpty) + { + elementOffset = 0; + return false; + } + + IntPtr byteOffset = Unsafe.ByteOffset( + ref MemoryMarshal.GetReference(first), + ref MemoryMarshal.GetReference(second)); + + if (Unsafe.SizeOf() == sizeof(int)) + { + if ((uint)byteOffset < (uint)(first.Length * Unsafe.SizeOf()) || + (uint)byteOffset > (uint)-(second.Length * Unsafe.SizeOf())) + { + if ((int)byteOffset % Unsafe.SizeOf() != 0) + ThrowHelper.ThrowArgumentException_OverlapAlignmentMismatch(); + + elementOffset = (int)byteOffset / Unsafe.SizeOf(); + return true; + } + else + { + elementOffset = 0; + return false; + } + } + else + { + if ((ulong)byteOffset < (ulong)((long)first.Length * Unsafe.SizeOf()) || + (ulong)byteOffset > (ulong)-((long)second.Length * Unsafe.SizeOf())) + { + if ((long)byteOffset % Unsafe.SizeOf() != 0) + ThrowHelper.ThrowArgumentException_OverlapAlignmentMismatch(); + + elementOffset = (int)((long)byteOffset / Unsafe.SizeOf()); + return true; + } + else + { + elementOffset = 0; + return false; + } + } + } + + /// + /// Searches an entire sorted for a value + /// using the specified generic interface. + /// + /// The element type of the span. + /// The sorted to search. + /// The to use when comparing. + /// + /// The zero-based index of in the sorted , + /// if is found; otherwise, a negative number that is the bitwise complement + /// of the index of the next element that is larger than or, if there is + /// no larger element, the bitwise complement of . + /// + /// + /// is . + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int BinarySearch( + this Span span, IComparable comparable) + { + return BinarySearch>(span, comparable); + } + + /// + /// Searches an entire sorted for a value + /// using the specified generic type. + /// + /// The element type of the span. + /// The specific type of . + /// The sorted to search. + /// The to use when comparing. + /// + /// The zero-based index of in the sorted , + /// if is found; otherwise, a negative number that is the bitwise complement + /// of the index of the next element that is larger than or, if there is + /// no larger element, the bitwise complement of . + /// + /// + /// is . + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int BinarySearch( + this Span span, TComparable comparable) + where TComparable : IComparable + { + return BinarySearch((ReadOnlySpan)span, comparable); + } + + /// + /// Searches an entire sorted for the specified + /// using the specified generic type. + /// + /// The element type of the span. + /// The specific type of . + /// The sorted to search. + /// The object to locate. The value can be null for reference types. + /// The to use when comparing. + /// /// + /// The zero-based index of in the sorted , + /// if is found; otherwise, a negative number that is the bitwise complement + /// of the index of the next element that is larger than or, if there is + /// no larger element, the bitwise complement of . + /// + /// + /// is . + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int BinarySearch( + this Span span, T value, TComparer comparer) + where TComparer : IComparer + { + return BinarySearch((ReadOnlySpan)span, value, comparer); + } + + /// + /// Searches an entire sorted for a value + /// using the specified generic interface. + /// + /// The element type of the span. + /// The sorted to search. + /// The to use when comparing. + /// + /// The zero-based index of in the sorted , + /// if is found; otherwise, a negative number that is the bitwise complement + /// of the index of the next element that is larger than or, if there is + /// no larger element, the bitwise complement of . + /// + /// + /// is . + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int BinarySearch( + this ReadOnlySpan span, IComparable comparable) + { + return BinarySearch>(span, comparable); + } + + /// + /// Searches an entire sorted for a value + /// using the specified generic type. + /// + /// The element type of the span. + /// The specific type of . + /// The sorted to search. + /// The to use when comparing. + /// + /// The zero-based index of in the sorted , + /// if is found; otherwise, a negative number that is the bitwise complement + /// of the index of the next element that is larger than or, if there is + /// no larger element, the bitwise complement of . + /// + /// + /// is . + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int BinarySearch( + this ReadOnlySpan span, TComparable comparable) + where TComparable : IComparable + { + return SpanHelpers.BinarySearch(span, comparable); + } + + /// + /// Searches an entire sorted for the specified + /// using the specified generic type. + /// + /// The element type of the span. + /// The specific type of . + /// The sorted to search. + /// The object to locate. The value can be null for reference types. + /// The to use when comparing. + /// /// + /// The zero-based index of in the sorted , + /// if is found; otherwise, a negative number that is the bitwise complement + /// of the index of the next element that is larger than or, if there is + /// no larger element, the bitwise complement of . + /// + /// + /// is . + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int BinarySearch( + this ReadOnlySpan span, T value, TComparer comparer) + where TComparer : IComparer + { + if (comparer == null) + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.comparer); + + var comparable = new SpanHelpers.ComparerComparable( + value, comparer); + return BinarySearch(span, comparable); + } + } +} diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Number.Formatting.cs b/external/corert/src/System.Private.CoreLib/shared/System/Number.Formatting.cs index 70b35a08aa..24d5db1da9 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Number.Formatting.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Number.Formatting.cs @@ -564,7 +564,7 @@ namespace System { Debug.Assert(source != null); - if (source.AsReadOnlySpan().TryCopyTo(destination)) + if (source.AsSpan().TryCopyTo(destination)) { charsWritten = source.Length; return true; @@ -1128,10 +1128,8 @@ namespace System [MethodImpl(MethodImplOptions.AggressiveInlining)] private static unsafe bool TryCopyTo(char* src, int length, Span destination, out int charsWritten) { - if (length <= destination.Length) + if (new ReadOnlySpan(src, length).TryCopyTo(destination)) { - bool copied = new ReadOnlySpan(src, length).TryCopyTo(destination); - Debug.Assert(copied); charsWritten = length; return true; } @@ -1708,8 +1706,7 @@ namespace System if (thousandsSepCtr >= thousandsSepPos.Length) { var newThousandsSepPos = new int[thousandsSepPos.Length * 2]; - bool copied = thousandsSepPos.TryCopyTo(newThousandsSepPos); - Debug.Assert(copied, "Expect copy to succeed, as the new array is larger than the original"); + thousandsSepPos.CopyTo(newThousandsSepPos); thousandsSepPos = newThousandsSepPos; } diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Numerics/ConstantHelper.cs b/external/corert/src/System.Private.CoreLib/shared/System/Numerics/ConstantHelper.cs new file mode 100644 index 0000000000..ea32ed3803 --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/shared/System/Numerics/ConstantHelper.cs @@ -0,0 +1,142 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.CompilerServices; + +namespace System.Numerics +{ + internal class ConstantHelper + { + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Byte GetByteWithAllBitsSet() + { + Byte value = 0; + unsafe + { + unchecked + { + *((Byte*)&value) = (Byte)0xff; + } + } + return value; + } + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static SByte GetSByteWithAllBitsSet() + { + SByte value = 0; + unsafe + { + unchecked + { + *((SByte*)&value) = (SByte)0xff; + } + } + return value; + } + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static UInt16 GetUInt16WithAllBitsSet() + { + UInt16 value = 0; + unsafe + { + unchecked + { + *((UInt16*)&value) = (UInt16)0xffff; + } + } + return value; + } + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Int16 GetInt16WithAllBitsSet() + { + Int16 value = 0; + unsafe + { + unchecked + { + *((Int16*)&value) = (Int16)0xffff; + } + } + return value; + } + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static UInt32 GetUInt32WithAllBitsSet() + { + UInt32 value = 0; + unsafe + { + unchecked + { + *((UInt32*)&value) = (UInt32)0xffffffff; + } + } + return value; + } + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Int32 GetInt32WithAllBitsSet() + { + Int32 value = 0; + unsafe + { + unchecked + { + *((Int32*)&value) = (Int32)0xffffffff; + } + } + return value; + } + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static UInt64 GetUInt64WithAllBitsSet() + { + UInt64 value = 0; + unsafe + { + unchecked + { + *((UInt64*)&value) = (UInt64)0xffffffffffffffff; + } + } + return value; + } + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Int64 GetInt64WithAllBitsSet() + { + Int64 value = 0; + unsafe + { + unchecked + { + *((Int64*)&value) = (Int64)0xffffffffffffffff; + } + } + return value; + } + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Single GetSingleWithAllBitsSet() + { + Single value = 0; + unsafe + { + unchecked + { + *((Int32*)&value) = (Int32)0xffffffff; + } + } + return value; + } + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Double GetDoubleWithAllBitsSet() + { + Double value = 0; + unsafe + { + unchecked + { + *((Int64*)&value) = (Int64)0xffffffffffffffff; + } + } + return value; + } + } +} diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Numerics/ConstantHelper.tt b/external/corert/src/System.Private.CoreLib/shared/System/Numerics/ConstantHelper.tt new file mode 100644 index 0000000000..4b1c677574 --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/shared/System/Numerics/ConstantHelper.tt @@ -0,0 +1,60 @@ +<#@ template debug="true" hostSpecific="true" #> +<#@ output extension=".cs" #> +<#@ Assembly Name="System.Core.dll" #> +<#@ Assembly Name="System.Xml.dll" #> +<#@ Assembly Name="System.Xml.Linq.dll" #> +<#@ Assembly Name="System.Windows.Forms.dll" #> +<#@ import namespace="System" #> +<#@ import namespace="System.IO" #> +<#@ import namespace="System.Diagnostics" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Xml.Linq" #> +<#@ import namespace="System.Collections" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ import namespace="System.Runtime.InteropServices" #> +<#@ include file="GenerationConfig.ttinclude" #><# GenerateCopyrightHeader(); #> + +using System.Runtime.CompilerServices; + +namespace System.Numerics +{ + internal class ConstantHelper + { +<# foreach (var type in supportedTypes) + { + string hexValue = "0x" + new string('f', Marshal.SizeOf(type) * 2); +#> + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static <#= type.Name #> Get<#= type.Name #>WithAllBitsSet() + { + <#= type.Name #> value = 0; + unsafe + { + unchecked + { + *((<#= GetIntegralEquivalent(type).Name #>*)&value) = (<#=GetIntegralEquivalent(type).Name#>)<#= hexValue #>; + } + } + return value; + } +<# + } +#> + } +}<#+ + public Type GetIntegralEquivalent(Type type) + { + if (type == typeof(Single)) + { + return typeof(Int32); + } + else if (type == typeof(double)) + { + return typeof(Int64); + } + else + { + return type; + } + } +#> \ No newline at end of file diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Numerics/GenerationConfig.ttinclude b/external/corert/src/System.Private.CoreLib/shared/System/Numerics/GenerationConfig.ttinclude new file mode 100644 index 0000000000..cdd9c95213 --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/shared/System/Numerics/GenerationConfig.ttinclude @@ -0,0 +1,147 @@ +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Collections.Generic" #> +<#+ + /* This file includes static data used as compilation configuration for the rest of the code generation. + It is shared here to ensure that all generated code compiles with the same constants and configurations. */ + + // The set of supported numeric types to compile + public static Type[] supportedTypes = new[] + { + typeof(Byte), typeof(SByte), typeof(UInt16), typeof(Int16), + typeof(UInt32), typeof(Int32), typeof(UInt64), typeof(Int64), + typeof(Single), typeof(Double) + }; + + // The set of unsigned types, a subset of the above. Used for excluding from certain methods, i.e. Abs and Negate + public static Type[] unsignedTypes = new[] + { + typeof(Byte), typeof(UInt16), typeof(UInt32), typeof(UInt64) + }; + + public static Type[] integralTypes = new[] + { + typeof(Byte), typeof(SByte), typeof(UInt16), typeof(Int16), + typeof(UInt32), typeof(Int32), typeof(UInt64), typeof(Int64) + }; + + public static Type[] nonClsCompliantTypes = new[] + { + typeof(SByte), typeof(UInt16), + typeof(UInt32), typeof(UInt64) + }; + + // The total register size, in bytes. 16 for SSE2, 32 for AVX, 64 for AVX512 + public static int totalSize = 16; + + /* General template helper procedures */ + + // Returns the constructed register field name for the given type and index. + public string GetRegisterFieldName(Type t, int index) + { + return "register." + t.Name.ToLowerInvariant() + "_" + index; + } + + // Returns the number of fields for a given type, based on the current configuration's register size + public int GetNumFields(Type t, int totalSize) + { + return totalSize / Marshal.SizeOf(t); + } + + public static HashSet WidenableTypes { get; private set; } = new HashSet() + { + typeof(byte), + typeof(ushort), + typeof(uint), + typeof(sbyte), + typeof(short), + typeof(int), + typeof(float), + }; + + private static Dictionary s_widenTargets = new Dictionary() + { + { typeof(byte), typeof(ushort) }, + { typeof(ushort), typeof(uint) }, + { typeof(uint), typeof(ulong) }, + { typeof(sbyte), typeof(short) }, + { typeof(short), typeof(int) }, + { typeof(int), typeof(long) }, + { typeof(float), typeof(double) }, + }; + + public Type GetWidenTarget(Type t) + { + Type target; + if (!s_widenTargets.TryGetValue(t, out target)) + { + throw new InvalidOperationException("No widen target for " + t.Name); + } + + return target; + } + + public static HashSet NarrowableTypes { get; private set; } = new HashSet() + { + typeof(ushort), + typeof(uint), + typeof(ulong), + typeof(short), + typeof(int), + typeof(long), + typeof(double), + }; + + private static Dictionary s_narrowTargets = new Dictionary() + { + { typeof(ulong), typeof(uint) }, + { typeof(uint), typeof(ushort) }, + { typeof(ushort), typeof(byte) }, + { typeof(long), typeof(int) }, + { typeof(int), typeof(short) }, + { typeof(short), typeof(sbyte) }, + { typeof(double), typeof(float) }, + }; + + public Type GetNarrowTarget(Type t) + { + Type target; + if (!s_narrowTargets.TryGetValue(t, out target)) + { + throw new InvalidOperationException("No narrow target for " + t.Name); + } + + return target; + } + + public static List> SameSizeConversionPairs = new List>() + { + new KeyValuePair(typeof(int), typeof(float)), + new KeyValuePair(typeof(uint), typeof(float)), + new KeyValuePair(typeof(long), typeof(double)), + new KeyValuePair(typeof(ulong), typeof(double)), + new KeyValuePair(typeof(float), typeof(int)), + new KeyValuePair(typeof(float), typeof(uint)), + new KeyValuePair(typeof(double), typeof(long)), + new KeyValuePair(typeof(double), typeof(ulong)), + }; + + public void GenerateCopyrightHeader() + { +#>// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +<#+ + } + + public string GenerateIfStatementHeader(Type type) + { + string keyword = (type == supportedTypes[0]) ? "if" : "else if"; + return string.Format("{0} (typeof(T) == typeof({1}))", keyword, type.Name); + } + + public string GenerateIfStatementHeader(Type type, IEnumerable allTypes) + { + string keyword = (type == allTypes.ToArray()[0]) ? "if" : "else if"; + return string.Format("{0} (typeof(T) == typeof({1}))", keyword, type.Name); + } +#> \ No newline at end of file diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Numerics/Register.cs b/external/corert/src/System.Private.CoreLib/shared/System/Numerics/Register.cs new file mode 100644 index 0000000000..a27e922b9d --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/shared/System/Numerics/Register.cs @@ -0,0 +1,172 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.InteropServices; + +namespace System.Numerics +{ + /// + /// A structure describing the layout of an SSE2-sized register. + /// Contains overlapping fields representing the set of valid numeric types. + /// Allows the generic Vector'T struct to contain an explicit field layout. + /// + [StructLayout(LayoutKind.Explicit)] + internal struct Register + { + #region Internal Storage Fields + // Internal System.Byte Fields + [FieldOffset(0)] + internal Byte byte_0; + [FieldOffset(1)] + internal Byte byte_1; + [FieldOffset(2)] + internal Byte byte_2; + [FieldOffset(3)] + internal Byte byte_3; + [FieldOffset(4)] + internal Byte byte_4; + [FieldOffset(5)] + internal Byte byte_5; + [FieldOffset(6)] + internal Byte byte_6; + [FieldOffset(7)] + internal Byte byte_7; + [FieldOffset(8)] + internal Byte byte_8; + [FieldOffset(9)] + internal Byte byte_9; + [FieldOffset(10)] + internal Byte byte_10; + [FieldOffset(11)] + internal Byte byte_11; + [FieldOffset(12)] + internal Byte byte_12; + [FieldOffset(13)] + internal Byte byte_13; + [FieldOffset(14)] + internal Byte byte_14; + [FieldOffset(15)] + internal Byte byte_15; + + // Internal System.SByte Fields + [FieldOffset(0)] + internal SByte sbyte_0; + [FieldOffset(1)] + internal SByte sbyte_1; + [FieldOffset(2)] + internal SByte sbyte_2; + [FieldOffset(3)] + internal SByte sbyte_3; + [FieldOffset(4)] + internal SByte sbyte_4; + [FieldOffset(5)] + internal SByte sbyte_5; + [FieldOffset(6)] + internal SByte sbyte_6; + [FieldOffset(7)] + internal SByte sbyte_7; + [FieldOffset(8)] + internal SByte sbyte_8; + [FieldOffset(9)] + internal SByte sbyte_9; + [FieldOffset(10)] + internal SByte sbyte_10; + [FieldOffset(11)] + internal SByte sbyte_11; + [FieldOffset(12)] + internal SByte sbyte_12; + [FieldOffset(13)] + internal SByte sbyte_13; + [FieldOffset(14)] + internal SByte sbyte_14; + [FieldOffset(15)] + internal SByte sbyte_15; + + // Internal System.UInt16 Fields + [FieldOffset(0)] + internal UInt16 uint16_0; + [FieldOffset(2)] + internal UInt16 uint16_1; + [FieldOffset(4)] + internal UInt16 uint16_2; + [FieldOffset(6)] + internal UInt16 uint16_3; + [FieldOffset(8)] + internal UInt16 uint16_4; + [FieldOffset(10)] + internal UInt16 uint16_5; + [FieldOffset(12)] + internal UInt16 uint16_6; + [FieldOffset(14)] + internal UInt16 uint16_7; + + // Internal System.Int16 Fields + [FieldOffset(0)] + internal Int16 int16_0; + [FieldOffset(2)] + internal Int16 int16_1; + [FieldOffset(4)] + internal Int16 int16_2; + [FieldOffset(6)] + internal Int16 int16_3; + [FieldOffset(8)] + internal Int16 int16_4; + [FieldOffset(10)] + internal Int16 int16_5; + [FieldOffset(12)] + internal Int16 int16_6; + [FieldOffset(14)] + internal Int16 int16_7; + + // Internal System.UInt32 Fields + [FieldOffset(0)] + internal UInt32 uint32_0; + [FieldOffset(4)] + internal UInt32 uint32_1; + [FieldOffset(8)] + internal UInt32 uint32_2; + [FieldOffset(12)] + internal UInt32 uint32_3; + + // Internal System.Int32 Fields + [FieldOffset(0)] + internal Int32 int32_0; + [FieldOffset(4)] + internal Int32 int32_1; + [FieldOffset(8)] + internal Int32 int32_2; + [FieldOffset(12)] + internal Int32 int32_3; + + // Internal System.UInt64 Fields + [FieldOffset(0)] + internal UInt64 uint64_0; + [FieldOffset(8)] + internal UInt64 uint64_1; + + // Internal System.Int64 Fields + [FieldOffset(0)] + internal Int64 int64_0; + [FieldOffset(8)] + internal Int64 int64_1; + + // Internal System.Single Fields + [FieldOffset(0)] + internal Single single_0; + [FieldOffset(4)] + internal Single single_1; + [FieldOffset(8)] + internal Single single_2; + [FieldOffset(12)] + internal Single single_3; + + // Internal System.Double Fields + [FieldOffset(0)] + internal Double double_0; + [FieldOffset(8)] + internal Double double_1; + + #endregion Internal Storage Fields + } +} diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Numerics/Register.tt b/external/corert/src/System.Private.CoreLib/shared/System/Numerics/Register.tt new file mode 100644 index 0000000000..a9de3b9748 --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/shared/System/Numerics/Register.tt @@ -0,0 +1,46 @@ +<#@ template debug="true" hostSpecific="true" #> +<#@ output extension=".cs" #> +<#@ Assembly Name="System.Core.dll" #> +<#@ Assembly Name="System.Xml.dll" #> +<#@ import namespace="System" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Runtime.InteropServices" #> +<#@ import namespace="System.Diagnostics" #> +<#@ include file="GenerationConfig.ttinclude" #><# GenerateCopyrightHeader(); #> + +using System.Runtime.InteropServices; + +namespace System.Numerics +{ + /// + /// A structure describing the layout of an SSE2-sized register. + /// Contains overlapping fields representing the set of valid numeric types. + /// Allows the generic Vector'T struct to contain an explicit field layout. + /// + [StructLayout(LayoutKind.Explicit)] + internal struct Register + { + #region Internal Storage Fields +<# + foreach (var type in supportedTypes) + { + Debug.Assert( + totalSize % Marshal.SizeOf(type) == 0, + "The size of supported structs must be a factor of the supported register size."); +#> + // Internal <#= type.FullName #> Fields +<# + for (int g = 0; g < totalSize / Marshal.SizeOf(type); g++) + { +#> + [FieldOffset(<#=Marshal.SizeOf(type) * g#>)] + internal <#=type.Name#> <#= type.Name.ToLowerInvariant() + "_" + g #>; +<# + } +#> + +<# + } +#> #endregion Internal Storage Fields + } +} \ No newline at end of file diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Numerics/Vector.cs.REMOVED.git-id b/external/corert/src/System.Private.CoreLib/shared/System/Numerics/Vector.cs.REMOVED.git-id new file mode 100644 index 0000000000..130808fa2a --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/shared/System/Numerics/Vector.cs.REMOVED.git-id @@ -0,0 +1 @@ +5fd286732ee606b078187d0f1e85b14cb7d677fa \ No newline at end of file diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Numerics/Vector.tt b/external/corert/src/System.Private.CoreLib/shared/System/Numerics/Vector.tt new file mode 100644 index 0000000000..275f47350d --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/shared/System/Numerics/Vector.tt @@ -0,0 +1,1808 @@ +<#@ template debug="true" hostSpecific="true" #> +<#@ output extension=".cs" #> +<#@ Assembly Name="System.Core.dll" #> +<#@ Assembly Name="System.Xml.dll" #> +<#@ import namespace="System" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Runtime.InteropServices" #> +<#@ include file="GenerationConfig.ttinclude" #><# GenerateCopyrightHeader(); #> + +using System.Globalization; +using System.Numerics.Hashing; +using System.Runtime.CompilerServices; +using System.Text; + +namespace System.Numerics +{ + /* Note: The following patterns are used throughout the code here and are described here + * + * PATTERN: + * if (typeof(T) == typeof(Int32)) { ... } + * else if (typeof(T) == typeof(Single)) { ... } + * EXPLANATION: + * At runtime, each instantiation of Vector will be type-specific, and each of these typeof blocks will be eliminated, + * as typeof(T) is a (JIT) compile-time constant for each instantiation. This design was chosen to eliminate any overhead from + * delegates and other patterns. + * + * PATTERN: + * if (Vector.IsHardwareAccelerated) { ... } + * else { ... } + * EXPLANATION + * This pattern solves two problems: + * 1. Allows us to unroll loops when we know the size (when no hardware acceleration is present) + * 2. Allows reflection to work: + * - If a method is called via reflection, it will not be "intrinsified", which would cause issues if we did + * not provide an implementation for that case (i.e. if it only included a case which assumed 16-byte registers) + * (NOTE: It is assumed that Vector.IsHardwareAccelerated will be a compile-time constant, eliminating these checks + * from the JIT'd code.) + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + /// + /// A structure that represents a single Vector. The count of this Vector is fixed but CPU register dependent. + /// This struct only supports numerical types. This type is intended to be used as a building block for vectorizing + /// large algorithms. This type is immutable, individual elements cannot be modified. + /// + [Intrinsic] + public struct Vector : IEquatable>, IFormattable where T : struct + { + #region Fields + private Register register; + #endregion Fields + + #region Static Members + /// + /// Returns the number of elements stored in the vector. This value is hardware dependent. + /// + public static int Count + { + [Intrinsic] + get + { + return s_count; + } + } + private static readonly int s_count = InitializeCount(); + + /// + /// Returns a vector containing all zeroes. + /// + public static Vector Zero + { + [Intrinsic] + get + { + return s_zero; + } + } + private static readonly Vector s_zero = new Vector(); + + /// + /// Returns a vector containing all ones. + /// + public static Vector One + { + [Intrinsic] + get + { + return s_one; + } + } + private static readonly Vector s_one = new Vector(GetOneValue()); + + internal static Vector AllOnes { get { return s_allOnes; } } + private static readonly Vector s_allOnes = new Vector(GetAllBitsSetValue()); + #endregion Static Members + + #region Static Initialization + private struct VectorSizeHelper + { + internal Vector _placeholder; + internal byte _byte; + } + + // Calculates the size of this struct in bytes, by computing the offset of a field in a structure + private static unsafe int InitializeCount() + { + VectorSizeHelper vsh; + byte* vectorBase = &vsh._placeholder.register.byte_0; + byte* byteBase = &vsh._byte; + int vectorSizeInBytes = (int)(byteBase - vectorBase); + + int typeSizeInBytes = -1; +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { + typeSizeInBytes = sizeof(<#=type.Name#>); + } +<# + } +#> + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + + return vectorSizeInBytes / typeSizeInBytes; + } + #endregion Static Initialization + + #region Constructors + /// + /// Constructs a vector whose components are all value + /// + [Intrinsic] + public unsafe Vector(T value) + : this() + { + if (Vector.IsHardwareAccelerated) + { +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { + fixed (<#=type.Name#>* basePtr = &this.<#=GetRegisterFieldName(type, 0)#>) + { + for (int g = 0; g < Count; g++) + { + *(basePtr + g) = (<#=type.Name#>)(object)value; + } + } + } +<# + } +#> + } + else + { +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { +<# + for (int g = 0; g < totalSize / Marshal.SizeOf(type); g++) + { +#> + <#=GetRegisterFieldName(type, g)#> = (<#=type.Name#>)(object)value; +<# + } +#> + } +<# + } +#> + } + } + + /// + /// Constructs a vector from the given array. The size of the given array must be at least Vector'T.Count. + /// + [Intrinsic] + public unsafe Vector(T[] values) : this(values, 0) { } + + /// + /// Constructs a vector from the given array, starting from the given index. + /// The array must contain at least Vector'T.Count from the given index. + /// + public unsafe Vector(T[] values, int index) + : this() + { + if (values == null) + { + // Match the JIT's exception type here. For perf, a NullReference is thrown instead of an ArgumentNull. + throw new NullReferenceException(SR.Arg_NullArgumentNullRef); + } + if (index < 0 || (values.Length - index) < Count) + { + throw new IndexOutOfRangeException(); + } + + if (Vector.IsHardwareAccelerated) + { +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { + fixed (<#=type.Name#>* basePtr = &this.<#=GetRegisterFieldName(type, 0)#>) + { + for (int g = 0; g < Count; g++) + { + *(basePtr + g) = (<#=type.Name#>)(object)values[g + index]; + } + } + } +<# + } +#> + } + else + { +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { + fixed (<#=type.Name#>* basePtr = &this.<#=GetRegisterFieldName(type, 0)#>) + { +<# + for (int g = 0; g < GetNumFields(type, totalSize); g++) + { +#> + *(basePtr + <#=g#>) = (<#=type.Name#>)(object)values[<#=g#> + index]; +<# + } +#> + } + } +<# + } +#> + } + } + +#pragma warning disable 3001 // void* is not a CLS-Compliant argument type + internal unsafe Vector(void* dataPointer) : this(dataPointer, 0) { } +#pragma warning restore 3001 // void* is not a CLS-Compliant argument type + +#pragma warning disable 3001 // void* is not a CLS-Compliant argument type + // Implemented with offset if this API ever becomes public; an offset of 0 is used internally. + internal unsafe Vector(void* dataPointer, int offset) + : this() + { +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { + <#=type.Name#>* castedPtr = (<#=type.Name#>*)dataPointer; + castedPtr += offset; + fixed (<#=type.Name#>* registerBase = &this.<#=GetRegisterFieldName(type, 0)#>) + { + for (int g = 0; g < Count; g++) + { + registerBase[g] = castedPtr[g]; + } + } + } +<# + } +#> + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } +#pragma warning restore 3001 // void* is not a CLS-Compliant argument type + + private Vector(ref Register existingRegister) + { + this.register = existingRegister; + } + #endregion Constructors + + #region Public Instance Methods + /// + /// Copies the vector to the given destination array. The destination array must be at least size Vector'T.Count. + /// + /// The destination array which the values are copied into + /// If the destination array is null + /// If number of elements in source vector is greater than those available in destination array + [Intrinsic] + public unsafe void CopyTo(T[] destination) + { + CopyTo(destination, 0); + } + + /// + /// Copies the vector to the given destination array. The destination array must be at least size Vector'T.Count. + /// + /// The destination array which the values are copied into + /// The index to start copying to + /// If the destination array is null + /// If index is greater than end of the array or index is less than zero + /// If number of elements in source vector is greater than those available in destination array + [Intrinsic] + public unsafe void CopyTo(T[] destination, int startIndex) + { + if (destination == null) + { + // Match the JIT's exception type here. For perf, a NullReference is thrown instead of an ArgumentNull. + throw new NullReferenceException(SR.Arg_NullArgumentNullRef); + } + if (startIndex < 0 || startIndex >= destination.Length) + { + throw new ArgumentOutOfRangeException(nameof(startIndex), SR.Format(SR.Arg_ArgumentOutOfRangeException, startIndex)); + } + if ((destination.Length - startIndex) < Count) + { + throw new ArgumentException(SR.Format(SR.Arg_ElementsInSourceIsGreaterThanDestination, startIndex)); + } + + if (Vector.IsHardwareAccelerated) + { +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { + <#=type.Name#>[] <#=type.Name.ToLowerInvariant()#>Array = (<#=type.Name#>[])(object)destination; + fixed (<#=type.Name#>* destinationBase = <#=type.Name.ToLowerInvariant()#>Array) + { + for (int g = 0; g < Count; g++) + { + destinationBase[startIndex + g] = (<#=type.Name#>)(object)this[g]; + } + } + } +<# + } +#> + } + else + { +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { + <#=type.Name#>[] <#=type.Name.ToLowerInvariant()#>Array = (<#=type.Name#>[])(object)destination; + fixed (<#=type.Name#>* destinationBase = <#=type.Name.ToLowerInvariant()#>Array) + { +<# + for (int g = 0; g < GetNumFields(type, totalSize); g++) + { +#> + destinationBase[startIndex + <#=g#>] = this.<#=GetRegisterFieldName(type, g)#>; +<# + } +#> + } + } +<# + } +#> + } + } + + /// + /// Returns the element at the given index. + /// + public unsafe T this[int index] + { + [Intrinsic] + get + { + if (index >= Count || index < 0) + { + throw new IndexOutOfRangeException(SR.Format(SR.Arg_ArgumentOutOfRangeException, index)); + } +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { + fixed (<#=type.Name#>* basePtr = &this.<#=GetRegisterFieldName(type, 0)#>) + { + return (T)(object)*(basePtr + index); + } + } +<# + } +#> + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + } + + /// + /// Returns a boolean indicating whether the given Object is equal to this vector instance. + /// + /// The Object to compare against. + /// True if the Object is equal to this vector; False otherwise. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public override bool Equals(object obj) + { + if (!(obj is Vector)) + { + return false; + } + return Equals((Vector)obj); + } + + /// + /// Returns a boolean indicating whether the given vector is equal to this vector instance. + /// + /// The vector to compare this instance to. + /// True if the other vector is equal to this instance; False otherwise. + [Intrinsic] + public bool Equals(Vector other) + { + if (Vector.IsHardwareAccelerated) + { + for (int g = 0; g < Count; g++) + { + if (!ScalarEquals(this[g], other[g])) + { + return false; + } + } + return true; + } + else + { +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { + return +<# + for (int g = 0; g < GetNumFields(type, totalSize); g++) + { +#> +<# + if (g == 0) + { +#> + this.<#=GetRegisterFieldName(type, g)#> == other.<#=GetRegisterFieldName(type, g)#> +<# + } + else + { +#> + && this.<#=GetRegisterFieldName(type, g)#> == other.<#=GetRegisterFieldName(type, g)#><#=(g == (GetNumFields(type, totalSize) -1)) ? ";" : ""#> +<# + } +#> +<# + } +#> + } +<# + } +#> + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + } + + /// + /// Returns the hash code for this instance. + /// + /// The hash code. + public override int GetHashCode() + { + int hash = 0; + + if (Vector.IsHardwareAccelerated) + { +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { + for (int g = 0; g < Count; g++) + { + hash = HashHelpers.Combine(hash, ((<#=type.Name#>)(object)this[g]).GetHashCode()); + } + return hash; + } +<# + } +#> + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + else + { +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { +<# + for (int g = 0; g < GetNumFields(type, totalSize); g++) + { +#> + hash = HashHelpers.Combine(hash, this.<#=GetRegisterFieldName(type, g)#>.GetHashCode()); +<# + } +#> + return hash; + } +<# + } +#> + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + } + + /// + /// Returns a String representing this vector. + /// + /// The string representation. + public override string ToString() + { + return ToString("G", CultureInfo.CurrentCulture); + } + + /// + /// Returns a String representing this vector, using the specified format string to format individual elements. + /// + /// The format of individual elements. + /// The string representation. + public string ToString(string format) + { + return ToString(format, CultureInfo.CurrentCulture); + } + + /// + /// Returns a String representing this vector, using the specified format string to format individual elements + /// and the given IFormatProvider. + /// + /// The format of individual elements. + /// The format provider to use when formatting elements. + /// The string representation. + public string ToString(string format, IFormatProvider formatProvider) + { + StringBuilder sb = new StringBuilder(); + string separator = NumberFormatInfo.GetInstance(formatProvider).NumberGroupSeparator; + sb.Append('<'); + for (int g = 0; g < Count - 1; g++) + { + sb.Append(((IFormattable)this[g]).ToString(format, formatProvider)); + sb.Append(separator); + sb.Append(' '); + } + // Append last element w/out separator + sb.Append(((IFormattable)this[Count - 1]).ToString(format, formatProvider)); + sb.Append('>'); + return sb.ToString(); + } + #endregion Public Instance Methods + + #region Arithmetic Operators + /// + /// Adds two vectors together. + /// + /// The first source vector. + /// The second source vector. + /// The summed vector. + public static unsafe Vector operator +(Vector left, Vector right) + { + unchecked + { + if (Vector.IsHardwareAccelerated) + { +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { + <#=type.Name#>* dataPtr = stackalloc <#=type.Name#>[Count]; + for (int g = 0; g < Count; g++) + { + dataPtr[g] = (<#=type.Name#>)(object)ScalarAdd(left[g], right[g]); + } + return new Vector(dataPtr); + } +<# + } +#> + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + else + { + Vector sum = new Vector(); +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { +<# + for (int g = 0; g < GetNumFields(type, totalSize); g++) + { +#> + sum.<#= GetRegisterFieldName(type, g) #> = (<#=type.Name#>)(left.<#= GetRegisterFieldName(type, g) #> + right.<#= GetRegisterFieldName(type, g) #>); +<# + } +#> + } +<# + } +#> + return sum; + } + } + } + + /// + /// Subtracts the second vector from the first. + /// + /// The first source vector. + /// The second source vector. + /// The difference vector. + public static unsafe Vector operator -(Vector left, Vector right) + { + unchecked + { + if (Vector.IsHardwareAccelerated) + { +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { + <#=type.Name#>* dataPtr = stackalloc <#=type.Name#>[Count]; + for (int g = 0; g < Count; g++) + { + dataPtr[g] = (<#=type.Name#>)(object)ScalarSubtract(left[g], right[g]); + } + return new Vector(dataPtr); + } +<# + } +#> + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + else + { + Vector difference = new Vector(); +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { +<# + for (int g = 0; g < GetNumFields(type, totalSize); g++) + { +#> + difference.<#= GetRegisterFieldName(type, g) #> = (<#=type.Name#>)(left.<#= GetRegisterFieldName(type, g) #> - right.<#= GetRegisterFieldName(type, g) #>); +<# + } +#> + } +<# + } +#> + return difference; + } + } + } + + // This method is intrinsic only for certain types. It cannot access fields directly unless we are sure the context is unaccelerated. + /// + /// Multiplies two vectors together. + /// + /// The first source vector. + /// The second source vector. + /// The product vector. + public static unsafe Vector operator *(Vector left, Vector right) + { + unchecked + { + if (Vector.IsHardwareAccelerated) + { +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { + <#=type.Name#>* dataPtr = stackalloc <#=type.Name#>[Count]; + for (int g = 0; g < Count; g++) + { + dataPtr[g] = (<#=type.Name#>)(object)ScalarMultiply(left[g], right[g]); + } + return new Vector(dataPtr); + } +<# + } +#> + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + else + { + Vector product = new Vector(); +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { +<# + for (int g = 0; g < GetNumFields(type, totalSize); g++) + { +#> + product.<#= GetRegisterFieldName(type, g) #> = (<#=type.Name#>)(left.<#= GetRegisterFieldName(type, g) #> * right.<#= GetRegisterFieldName(type, g) #>); +<# + } +#> + } +<# + } +#> + return product; + } + } + } + + // This method is intrinsic only for certain types. It cannot access fields directly unless we are sure the context is unaccelerated. + /// + /// Multiplies a vector by the given scalar. + /// + /// The source vector. + /// The scalar value. + /// The scaled vector. + public static Vector operator *(Vector value, T factor) + { + unchecked + { + if (Vector.IsHardwareAccelerated) + { + return new Vector(factor) * value; + } + else + { + Vector product = new Vector(); +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { +<# + for (int g = 0; g < GetNumFields(type, totalSize); g++) + { +#> + product.<#= GetRegisterFieldName(type, g) #> = (<#=type.Name#>)(value.<#= GetRegisterFieldName(type, g) #> * (<#=type.Name#>)(object)factor); +<# + } +#> + } +<# + } +#> + return product; + } + } + } + + // This method is intrinsic only for certain types. It cannot access fields directly unless we are sure the context is unaccelerated. + /// + /// Multiplies a vector by the given scalar. + /// + /// The scalar value. + /// The source vector. + /// The scaled vector. + public static Vector operator *(T factor, Vector value) + { + unchecked + { + if (Vector.IsHardwareAccelerated) + { + return new Vector(factor) * value; + } + else + { + Vector product = new Vector(); +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { +<# + for (int g = 0; g < GetNumFields(type, totalSize); g++) + { +#> + product.<#= GetRegisterFieldName(type, g) #> = (<#=type.Name#>)(value.<#= GetRegisterFieldName(type, g) #> * (<#=type.Name#>)(object)factor); +<# + } +#> + } +<# + } +#> + return product; + } + } + } + + // This method is intrinsic only for certain types. It cannot access fields directly unless we are sure the context is unaccelerated. + /// + /// Divides the first vector by the second. + /// + /// The first source vector. + /// The second source vector. + /// The vector resulting from the division. + public static unsafe Vector operator /(Vector left, Vector right) + { + unchecked + { + if (Vector.IsHardwareAccelerated) + { +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { + <#=type.Name#>* dataPtr = stackalloc <#=type.Name#>[Count]; + for (int g = 0; g < Count; g++) + { + dataPtr[g] = (<#=type.Name#>)(object)ScalarDivide(left[g], right[g]); + } + return new Vector(dataPtr); + } +<# + } +#> + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + else + { + Vector quotient = new Vector(); +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { +<# + for (int g = 0; g < GetNumFields(type, totalSize); g++) + { +#> + quotient.<#= GetRegisterFieldName(type, g) #> = (<#=type.Name#>)(left.<#= GetRegisterFieldName(type, g) #> / right.<#= GetRegisterFieldName(type, g) #>); +<# + } +#> + } +<# + } +#> + return quotient; + } + } + } + + /// + /// Negates a given vector. + /// + /// The source vector. + /// The negated vector. + public static Vector operator -(Vector value) + { + return Zero - value; + } + #endregion Arithmetic Operators + + #region Bitwise Operators + /// + /// Returns a new vector by performing a bitwise-and operation on each of the elements in the given vectors. + /// + /// The first source vector. + /// The second source vector. + /// The resultant vector. + [Intrinsic] + public static unsafe Vector operator &(Vector left, Vector right) + { + Vector result = new Vector(); + unchecked + { + if (Vector.IsHardwareAccelerated) + { + Int64* resultBase = &result.register.int64_0; + Int64* leftBase = &left.register.int64_0; + Int64* rightBase = &right.register.int64_0; + for (int g = 0; g < Vector.Count; g++) + { + resultBase[g] = leftBase[g] & rightBase[g]; + } + } + else + { + result.<#=GetRegisterFieldName(typeof(Int64), 0)#> = left.<#=GetRegisterFieldName(typeof(Int64), 0)#> & right.<#=GetRegisterFieldName(typeof(Int64), 0)#>; + result.<#=GetRegisterFieldName(typeof(Int64), 1)#> = left.<#=GetRegisterFieldName(typeof(Int64), 1)#> & right.<#=GetRegisterFieldName(typeof(Int64), 1)#>; + } + } + return result; + } + + /// + /// Returns a new vector by performing a bitwise-or operation on each of the elements in the given vectors. + /// + /// The first source vector. + /// The second source vector. + /// The resultant vector. + [Intrinsic] + public static unsafe Vector operator |(Vector left, Vector right) + { + Vector result = new Vector(); + unchecked + { + if (Vector.IsHardwareAccelerated) + { + Int64* resultBase = &result.register.int64_0; + Int64* leftBase = &left.register.int64_0; + Int64* rightBase = &right.register.int64_0; + for (int g = 0; g < Vector.Count; g++) + { + resultBase[g] = leftBase[g] | rightBase[g]; + } + } + else + { + result.<#=GetRegisterFieldName(typeof(Int64), 0)#> = left.<#=GetRegisterFieldName(typeof(Int64), 0)#> | right.<#=GetRegisterFieldName(typeof(Int64), 0)#>; + result.<#=GetRegisterFieldName(typeof(Int64), 1)#> = left.<#=GetRegisterFieldName(typeof(Int64), 1)#> | right.<#=GetRegisterFieldName(typeof(Int64), 1)#>; + } + } + return result; + } + + /// + /// Returns a new vector by performing a bitwise-exclusive-or operation on each of the elements in the given vectors. + /// + /// The first source vector. + /// The second source vector. + /// The resultant vector. + [Intrinsic] + public static unsafe Vector operator ^(Vector left, Vector right) + { + Vector result = new Vector(); + unchecked + { + if (Vector.IsHardwareAccelerated) + { + Int64* resultBase = &result.register.int64_0; + Int64* leftBase = &left.register.int64_0; + Int64* rightBase = &right.register.int64_0; + for (int g = 0; g < Vector.Count; g++) + { + resultBase[g] = leftBase[g] ^ rightBase[g]; + } + } + else + { + result.<#=GetRegisterFieldName(typeof(Int64), 0)#> = left.<#=GetRegisterFieldName(typeof(Int64), 0)#> ^ right.<#=GetRegisterFieldName(typeof(Int64), 0)#>; + result.<#=GetRegisterFieldName(typeof(Int64), 1)#> = left.<#=GetRegisterFieldName(typeof(Int64), 1)#> ^ right.<#=GetRegisterFieldName(typeof(Int64), 1)#>; + } + } + return result; + } + + /// + /// Returns a new vector whose elements are obtained by taking the one's complement of the given vector's elements. + /// + /// The source vector. + /// The one's complement vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector operator ~(Vector value) + { + return s_allOnes ^ value; + } + #endregion Bitwise Operators + + #region Logical Operators + /// + /// Returns a boolean indicating whether each pair of elements in the given vectors are equal. + /// + /// The first vector to compare. + /// The first vector to compare. + /// True if all elements are equal; False otherwise. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(Vector left, Vector right) + { + return left.Equals(right); + } + + /// + /// Returns a boolean indicating whether any single pair of elements in the given vectors are not equal. + /// + /// The first vector to compare. + /// The second vector to compare. + /// True if left and right are not equal; False otherwise. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(Vector left, Vector right) + { + return !(left == right); + } + #endregion Logical Operators + + #region Conversions +<# foreach (Type type in supportedTypes) + { +#> + /// + /// Reinterprets the bits of the given vector into those of another type. + /// + /// The source vector + /// The reinterpreted vector. +<# + if (nonClsCompliantTypes.Contains(type)) + { +#> + [CLSCompliant(false)] +<# + } +#> + [Intrinsic] + public static explicit operator Vector<<#=type.Name#>>(Vector value) + { + return new Vector<<#=type.Name#>>(ref value.register); + } + +<# + } +#> + #endregion Conversions + + #region Internal Comparison Methods + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + internal static unsafe Vector Equals(Vector left, Vector right) + { + if (Vector.IsHardwareAccelerated) + { +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { + <#=type.Name#>* dataPtr = stackalloc <#=type.Name#>[Count]; + for (int g = 0; g < Count; g++) + { + dataPtr[g] = ScalarEquals(left[g], right[g]) ? ConstantHelper.Get<#=type.Name#>WithAllBitsSet() : (<#=type.Name#>)0; + } + return new Vector(dataPtr); + } +<# + } +#> + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + else + { + Register register = new Register(); +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { +<# + for (int g = 0; g < GetNumFields(type, totalSize); g++) + { +#> + <#= GetRegisterFieldName(type, g) #> = left.<#= GetRegisterFieldName(type, g) #> == right.<#= GetRegisterFieldName(type, g) #> ? ConstantHelper.Get<#=type.Name#>WithAllBitsSet() : (<#=type.Name#>)0; +<# + } +#> + return new Vector(ref register); + } +<# + } +#> + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + } + + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + internal static unsafe Vector LessThan(Vector left, Vector right) + { + if (Vector.IsHardwareAccelerated) + { +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { + <#=type.Name#>* dataPtr = stackalloc <#=type.Name#>[Count]; + for (int g = 0; g < Count; g++) + { + dataPtr[g] = ScalarLessThan(left[g], right[g]) ? ConstantHelper.Get<#=type.Name#>WithAllBitsSet() : (<#=type.Name#>)0; + } + return new Vector(dataPtr); + } +<# + } +#> + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + else + { + Register register = new Register(); +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { +<# + for (int g = 0; g < GetNumFields(type, totalSize); g++) + { +#> + <#= GetRegisterFieldName(type, g) #> = left.<#= GetRegisterFieldName(type, g) #> < right.<#= GetRegisterFieldName(type, g) #> ? ConstantHelper.Get<#=type.Name#>WithAllBitsSet() : (<#=type.Name#>)0; +<# + } +#> + return new Vector(ref register); + } +<# + } +#> + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + } + + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + internal static unsafe Vector GreaterThan(Vector left, Vector right) + { + if (Vector.IsHardwareAccelerated) + { +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { + <#=type.Name#>* dataPtr = stackalloc <#=type.Name#>[Count]; + for (int g = 0; g < Count; g++) + { + dataPtr[g] = ScalarGreaterThan(left[g], right[g]) ? ConstantHelper.Get<#=type.Name#>WithAllBitsSet() : (<#=type.Name#>)0; + } + return new Vector(dataPtr); + } +<# + } +#> + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + else + { + Register register = new Register(); +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { +<# + for (int g = 0; g < GetNumFields(type, totalSize); g++) + { +#> + <#= GetRegisterFieldName(type, g) #> = left.<#= GetRegisterFieldName(type, g) #> > right.<#= GetRegisterFieldName(type, g) #> ? ConstantHelper.Get<#=type.Name#>WithAllBitsSet() : (<#=type.Name#>)0; +<# + } +#> + return new Vector(ref register); + } +<# + } +#> + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + } + + [Intrinsic] + internal static Vector GreaterThanOrEqual(Vector left, Vector right) + { + return Equals(left, right) | GreaterThan(left, right); + } + + [Intrinsic] + internal static Vector LessThanOrEqual(Vector left, Vector right) + { + return Equals(left, right) | LessThan(left, right); + } + + [Intrinsic] + internal static Vector ConditionalSelect(Vector condition, Vector left, Vector right) + { + return (left & condition) | (Vector.AndNot(right, condition)); + } + #endregion Comparison Methods + + #region Internal Math Methods + [Intrinsic] + internal static unsafe Vector Abs(Vector value) + { +<# + foreach (Type type in supportedTypes) + { + if (unsignedTypes.Contains(type)) + { +#> + <#=GenerateIfStatementHeader(type, unsignedTypes)#> + { + return value; + } +<# + } + } +#> + if (Vector.IsHardwareAccelerated) + { +<# + foreach (Type type in supportedTypes.Except(unsignedTypes)) + { +#> + <#=GenerateIfStatementHeader(type, supportedTypes.Except(unsignedTypes))#> + { + <#=type.Name#>* dataPtr = stackalloc <#=type.Name#>[Count]; + for (int g = 0; g < Count; g++) + { + dataPtr[g] = (<#=type.Name#>)(object)(Math.Abs((<#=type.Name#>)(object)value[g])); + } + return new Vector(dataPtr); + } +<# + } +#> + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + else + { +<# + foreach (Type type in supportedTypes.Except(unsignedTypes)) + { +#> + <#=GenerateIfStatementHeader(type, supportedTypes.Except(unsignedTypes))#> + { +<# + for (int g = 0; g < GetNumFields(type, totalSize); g++) + { +#> + value.<#=GetRegisterFieldName(type, g)#> = (<#=type.Name#>)(Math.Abs(value.<#=GetRegisterFieldName(type, g)#>)); +<# + } +#> + return value; + } +<# + } +#> + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + } + + [Intrinsic] + internal static unsafe Vector Min(Vector left, Vector right) + { + if (Vector.IsHardwareAccelerated) + { +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { + <#=type.Name#>* dataPtr = stackalloc <#=type.Name#>[Count]; + for (int g = 0; g < Count; g++) + { + dataPtr[g] = ScalarLessThan(left[g], right[g]) ? (<#=type.Name#>)(object)left[g] : (<#=type.Name#>)(object)right[g]; + } + return new Vector(dataPtr); + } +<# + } +#> + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + else + { + Vector vec = new Vector(); +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { +<# + for (int g = 0; g < GetNumFields(type, totalSize); g++) + { +#> + vec.<#=GetRegisterFieldName(type, g)#> = left.<#=GetRegisterFieldName(type, g)#> < right.<#=GetRegisterFieldName(type, g)#> ? left.<#=GetRegisterFieldName(type, g)#> : right.<#=GetRegisterFieldName(type, g)#>; +<# + } +#> + return vec; + } +<# + } +#> + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + } + + [Intrinsic] + internal static unsafe Vector Max(Vector left, Vector right) + { + if (Vector.IsHardwareAccelerated) + { +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { + <#=type.Name#>* dataPtr = stackalloc <#=type.Name#>[Count]; + for (int g = 0; g < Count; g++) + { + dataPtr[g] = ScalarGreaterThan(left[g], right[g]) ? (<#=type.Name#>)(object)left[g] : (<#=type.Name#>)(object)right[g]; + } + return new Vector(dataPtr); + } +<# + } +#> + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + else + { + Vector vec = new Vector(); +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { +<# + for (int g = 0; g < GetNumFields(type, totalSize); g++) + { +#> + vec.<#=GetRegisterFieldName(type, g)#> = left.<#=GetRegisterFieldName(type, g)#> > right.<#=GetRegisterFieldName(type, g)#> ? left.<#=GetRegisterFieldName(type, g)#> : right.<#=GetRegisterFieldName(type, g)#>; +<# + } +#> + return vec; + } +<# + } +#> + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + } + + [Intrinsic] + internal static T DotProduct(Vector left, Vector right) + { + if (Vector.IsHardwareAccelerated) + { + T product = default; + for (int g = 0; g < Count; g++) + { + product = ScalarAdd(product, ScalarMultiply(left[g], right[g])); + } + return product; + } + else + { +<# foreach (Type type in supportedTypes) + { + #> + <#=GenerateIfStatementHeader(type)#> + { + <#=type.Name#> product = 0; +<# + for (int g = 0; g < GetNumFields(type, totalSize); g++) + { +#> + product += (<#=type.Name#>)(left.<#=GetRegisterFieldName(type, g)#> * right.<#=GetRegisterFieldName(type, g)#>); +<# + } +#> + return (T)(object)product; + } +<# + } +#> + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + } + + [Intrinsic] + internal static unsafe Vector SquareRoot(Vector value) + { + if (Vector.IsHardwareAccelerated) + { +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { + <#=type.Name#>* dataPtr = stackalloc <#=type.Name#>[Count]; + for (int g = 0; g < Count; g++) + { + dataPtr[g] = unchecked((<#=type.Name#>)Math.Sqrt((<#=type.Name#>)(object)value[g])); + } + return new Vector(dataPtr); + } +<# + } +#> + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + else + { +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { +<# + for (int g = 0; g < GetNumFields(type, totalSize); g++) + { +#> + value.<#=GetRegisterFieldName(type, g)#> = (<#=type.Name#>)Math.Sqrt(value.<#=GetRegisterFieldName(type, g)#>); +<# + } +#> + return value; + } +<# + } +#> + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + } + #endregion Internal Math Methods + + #region Helper Methods + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + private static bool ScalarEquals(T left, T right) + { +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { + return (<#=type.Name#>)(object)left == (<#=type.Name#>)(object)right; + } +<# + } +#> + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + private static bool ScalarLessThan(T left, T right) + { +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { + return (<#=type.Name#>)(object)left < (<#=type.Name#>)(object)right; + } +<# + } +#> + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + private static bool ScalarGreaterThan(T left, T right) + { +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { + return (<#=type.Name#>)(object)left > (<#=type.Name#>)(object)right; + } +<# + } +#> + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + private static T ScalarAdd(T left, T right) + { +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { + return (T)(object)unchecked((<#=type.Name#>)((<#=type.Name#>)(object)left + (<#=type.Name#>)(object)right)); + } +<# + } +#> + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + private static T ScalarSubtract(T left, T right) + { +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { + return (T)(object)(<#=type.Name#>)((<#=type.Name#>)(object)left - (<#=type.Name#>)(object)right); + } +<# + } +#> + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + private static T ScalarMultiply(T left, T right) + { +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { + return (T)(object)unchecked((<#=type.Name#>)((<#=type.Name#>)(object)left * (<#=type.Name#>)(object)right)); + } +<# + } +#> + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + private static T ScalarDivide(T left, T right) + { +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { + return (T)(object)(<#=type.Name#>)((<#=type.Name#>)(object)left / (<#=type.Name#>)(object)right); + } +<# + } +#> + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + private static T GetOneValue() + { +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { + <#=type.Name#> value = 1; + return (T)(object)value; + } +<# + } +#> + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + private static T GetAllBitsSetValue() + { +<# foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { + return (T)(object)ConstantHelper.Get<#=type.Name#>WithAllBitsSet(); + } +<# + } +#> + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + #endregion + } + + [Intrinsic] + public static partial class Vector + { + #region Widen/Narrow +<# foreach (Type type in WidenableTypes) + { + Type widenTarget = GetWidenTarget(type); +#> + /// + /// Widens a Vector{<#=type.Name#>} into two Vector{<#=widenTarget.Name#>}'s. + /// The source vector whose elements are widened into the outputs. + /// The first output vector, whose elements will contain the widened elements from lower indices in the source vector. + /// The second output vector, whose elements will contain the widened elements from higher indices in the source vector. + /// +<# + if (nonClsCompliantTypes.Contains(type) || nonClsCompliantTypes.Contains(widenTarget)) + { +#> + [CLSCompliant(false)] +<# + } +#> + [Intrinsic] + public static unsafe void Widen(Vector<<#=type.Name#>> source, out Vector<<#=widenTarget.Name#>> low, out Vector<<#=widenTarget.Name#>> high) + { + int elements = Vector<<#=type.Name#>>.Count; + <#=widenTarget.Name#>* lowPtr = stackalloc <#=widenTarget.Name#>[elements / 2]; + for (int i = 0; i < elements / 2; i++) + { + lowPtr[i] = (<#=widenTarget.Name#>)source[i]; + } + <#=widenTarget.Name#>* highPtr = stackalloc <#=widenTarget.Name#>[elements / 2]; + for (int i = 0; i < elements / 2; i++) + { + highPtr[i] = (<#=widenTarget.Name#>)source[i + (elements / 2)]; + } + + low = new Vector<<#=widenTarget.Name#>>(lowPtr); + high = new Vector<<#=widenTarget.Name#>>(highPtr); + } + +<# + } +#> +<# foreach (Type narrowSource in NarrowableTypes) + { + Type narrowTarget = GetNarrowTarget(narrowSource); +#> + /// + /// Narrows two Vector{<#=narrowSource.Name#>}'s into one Vector{<#=narrowTarget.Name#>}. + /// The first source vector, whose elements become the lower-index elements of the return value. + /// The second source vector, whose elements become the higher-index elements of the return value. + /// A Vector{<#=narrowTarget.Name#>} containing elements narrowed from the source vectors. + /// +<# + if (nonClsCompliantTypes.Contains(narrowSource) || nonClsCompliantTypes.Contains(narrowTarget)) + { +#> + [CLSCompliant(false)] +<# + } +#> + [Intrinsic] + public static unsafe Vector<<#=narrowTarget.Name#>> Narrow(Vector<<#=narrowSource.Name#>> low, Vector<<#=narrowSource.Name#>> high) + { + unchecked + { + int elements = Vector<<#=narrowTarget.Name#>>.Count; + <#=narrowTarget.Name#>* retPtr = stackalloc <#=narrowTarget.Name#>[elements]; + for (int i = 0; i < elements / 2; i++) + { + retPtr[i] = (<#=narrowTarget.Name#>)low[i]; + } + for (int i = 0; i < elements / 2; i++) + { + retPtr[i + (elements / 2)] = (<#=narrowTarget.Name#>)high[i]; + } + + return new Vector<<#=narrowTarget.Name#>>(retPtr); + } + } + +<# + } +#> + #endregion Widen/Narrow + + #region Same-Size Conversion +<# foreach (var pair in SameSizeConversionPairs) + { +#> + /// + /// Converts a Vector{<#=pair.Key.Name#>} to a Vector{<#=pair.Value.Name#>}. + /// + /// The source vector. + /// The converted vector. +<# + if (nonClsCompliantTypes.Contains(pair.Key) || nonClsCompliantTypes.Contains(pair.Value)) + { +#> + [CLSCompliant(false)] +<# + } +#> + [Intrinsic] + public static unsafe Vector<<#=pair.Value.Name#>> ConvertTo<#=pair.Value.Name#>(Vector<<#=pair.Key.Name#>> value) + { + unchecked + { + int elements = Vector<<#=pair.Value.Name#>>.Count; + <#=pair.Value.Name#>* retPtr = stackalloc <#=pair.Value.Name#>[elements]; + for (int i = 0; i < elements; i++) + { + retPtr[i] = (<#=pair.Value.Name#>)value[i]; + } + + return new Vector<<#=pair.Value.Name#>>(retPtr); + } + } + +<# } #> + #endregion Same-Size Conversion + } +} diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Numerics/Vector_Operations.cs b/external/corert/src/System.Private.CoreLib/shared/System/Numerics/Vector_Operations.cs new file mode 100644 index 0000000000..b69b058be9 --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/shared/System/Numerics/Vector_Operations.cs @@ -0,0 +1,865 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.CompilerServices; + +namespace System.Numerics +{ + /// + /// Contains various methods useful for creating, manipulating, combining, and converting generic vectors with one another. + /// + public static partial class Vector + { + // JIT is not looking at the Vector class methods + // all methods here should be inlined and they must be implemented in terms of Vector intrinsics + #region Select Methods + /// + /// Creates a new vector with elements selected between the two given source vectors, and based on a mask vector. + /// + /// The integral mask vector used to drive selection. + /// The first source vector. + /// The second source vector. + /// The new vector with elements selected based on the mask. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector ConditionalSelect(Vector condition, Vector left, Vector right) + { + return (Vector)Vector.ConditionalSelect((Vector)condition, left, right); + } + + /// + /// Creates a new vector with elements selected between the two given source vectors, and based on a mask vector. + /// + /// The integral mask vector used to drive selection. + /// The first source vector. + /// The second source vector. + /// The new vector with elements selected based on the mask. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector ConditionalSelect(Vector condition, Vector left, Vector right) + { + return (Vector)Vector.ConditionalSelect((Vector)condition, left, right); + } + + /// + /// Creates a new vector with elements selected between the two given source vectors, and based on a mask vector. + /// + /// The mask vector used to drive selection. + /// The first source vector. + /// The second source vector. + /// The new vector with elements selected based on the mask. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector ConditionalSelect(Vector condition, Vector left, Vector right) where T : struct + { + return Vector.ConditionalSelect(condition, left, right); + } + #endregion Select Methods + + #region Comparison methods + #region Equals methods + /// + /// Returns a new vector whose elements signal whether the elements in left and right were equal. + /// + /// The first vector to compare. + /// The second vector to compare. + /// The resultant vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector Equals(Vector left, Vector right) where T : struct + { + return Vector.Equals(left, right); + } + + /// + /// Returns an integral vector whose elements signal whether elements in the left and right floating point vectors were equal. + /// + /// The first vector to compare. + /// The second vector to compare. + /// The resultant vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector Equals(Vector left, Vector right) + { + return (Vector)Vector.Equals(left, right); + } + + /// + /// Returns a new vector whose elements signal whether the elements in left and right were equal. + /// + /// The first vector to compare. + /// The second vector to compare. + /// The resultant vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector Equals(Vector left, Vector right) + { + return Vector.Equals(left, right); + } + + /// + /// Returns an integral vector whose elements signal whether elements in the left and right floating point vectors were equal. + /// + /// The first vector to compare. + /// The second vector to compare. + /// The resultant vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector Equals(Vector left, Vector right) + { + return (Vector)Vector.Equals(left, right); + } + + /// + /// Returns a new vector whose elements signal whether the elements in left and right were equal. + /// + /// The first vector to compare. + /// The second vector to compare. + /// The resultant vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector Equals(Vector left, Vector right) + { + return Vector.Equals(left, right); + } + + /// + /// Returns a boolean indicating whether each pair of elements in the given vectors are equal. + /// + /// The first vector to compare. + /// The first vector to compare. + /// True if all elements are equal; False otherwise. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static bool EqualsAll(Vector left, Vector right) where T : struct + { + return left == right; + } + + /// + /// Returns a boolean indicating whether any single pair of elements in the given vectors are equal. + /// + /// The first vector to compare. + /// The second vector to compare. + /// True if any element pairs are equal; False if no element pairs are equal. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static bool EqualsAny(Vector left, Vector right) where T : struct + { + return !Vector.Equals(left, right).Equals(Vector.Zero); + } + #endregion Equals methods + + #region Lessthan Methods + /// + /// Returns a new vector whose elements signal whether the elements in left were less than their + /// corresponding elements in right. + /// + /// The first vector to compare. + /// The second vector to compare. + /// The resultant vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector LessThan(Vector left, Vector right) where T : struct + { + return Vector.LessThan(left, right); + } + + /// + /// Returns an integral vector whose elements signal whether the elements in left were less than their + /// corresponding elements in right. + /// + /// The first vector to compare. + /// The second vector to compare. + /// The resultant integral vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector LessThan(Vector left, Vector right) + { + return (Vector)Vector.LessThan(left, right); + } + + /// + /// Returns a new vector whose elements signal whether the elements in left were less than their + /// corresponding elements in right. + /// + /// The first vector to compare. + /// The second vector to compare. + /// The resultant vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector LessThan(Vector left, Vector right) + { + return Vector.LessThan(left, right); + } + + /// + /// Returns an integral vector whose elements signal whether the elements in left were less than their + /// corresponding elements in right. + /// + /// The first vector to compare. + /// The second vector to compare. + /// The resultant integral vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector LessThan(Vector left, Vector right) + { + return (Vector)Vector.LessThan(left, right); + } + + /// + /// Returns a new vector whose elements signal whether the elements in left were less than their + /// corresponding elements in right. + /// + /// The first vector to compare. + /// The second vector to compare. + /// The resultant vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector LessThan(Vector left, Vector right) + { + return Vector.LessThan(left, right); + } + + /// + /// Returns a boolean indicating whether all of the elements in left are less than their corresponding elements in right. + /// + /// The first vector to compare. + /// The second vector to compare. + /// True if all elements in left are less than their corresponding elements in right; False otherwise. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static bool LessThanAll(Vector left, Vector right) where T : struct + { + Vector cond = (Vector)Vector.LessThan(left, right); + return cond.Equals(Vector.AllOnes); + } + + /// + /// Returns a boolean indicating whether any element in left is less than its corresponding element in right. + /// + /// The first vector to compare. + /// The second vector to compare. + /// True if any elements in left are less than their corresponding elements in right; False otherwise. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static bool LessThanAny(Vector left, Vector right) where T : struct + { + Vector cond = (Vector)Vector.LessThan(left, right); + return !cond.Equals(Vector.Zero); + } + #endregion LessthanMethods + + #region Lessthanorequal methods + /// + /// Returns a new vector whose elements signal whether the elements in left were less than or equal to their + /// corresponding elements in right. + /// + /// The first vector to compare. + /// The second vector to compare. + /// The resultant vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector LessThanOrEqual(Vector left, Vector right) where T : struct + { + return Vector.LessThanOrEqual(left, right); + } + + /// + /// Returns an integral vector whose elements signal whether the elements in left were less than or equal to their + /// corresponding elements in right. + /// + /// The first vector to compare. + /// The second vector to compare. + /// The resultant integral vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector LessThanOrEqual(Vector left, Vector right) + { + return (Vector)Vector.LessThanOrEqual(left, right); + } + + /// + /// Returns a new vector whose elements signal whether the elements in left were less than or equal to their + /// corresponding elements in right. + /// + /// The first vector to compare. + /// The second vector to compare. + /// The resultant vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector LessThanOrEqual(Vector left, Vector right) + { + return Vector.LessThanOrEqual(left, right); + } + + /// + /// Returns a new vector whose elements signal whether the elements in left were less than or equal to their + /// corresponding elements in right. + /// + /// The first vector to compare. + /// The second vector to compare. + /// The resultant vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector LessThanOrEqual(Vector left, Vector right) + { + return Vector.LessThanOrEqual(left, right); + } + + /// + /// Returns an integral vector whose elements signal whether the elements in left were less than or equal to their + /// corresponding elements in right. + /// + /// The first vector to compare. + /// The second vector to compare. + /// The resultant integral vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector LessThanOrEqual(Vector left, Vector right) + { + return (Vector)Vector.LessThanOrEqual(left, right); + } + + /// + /// Returns a boolean indicating whether all elements in left are less than or equal to their corresponding elements in right. + /// + /// The first vector to compare. + /// The second vector to compare. + /// True if all elements in left are less than or equal to their corresponding elements in right; False otherwise. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static bool LessThanOrEqualAll(Vector left, Vector right) where T : struct + { + Vector cond = (Vector)Vector.LessThanOrEqual(left, right); + return cond.Equals(Vector.AllOnes); + } + + /// + /// Returns a boolean indicating whether any element in left is less than or equal to its corresponding element in right. + /// + /// The first vector to compare. + /// The second vector to compare. + /// True if any elements in left are less than their corresponding elements in right; False otherwise. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static bool LessThanOrEqualAny(Vector left, Vector right) where T : struct + { + Vector cond = (Vector)Vector.LessThanOrEqual(left, right); + return !cond.Equals(Vector.Zero); + } + #endregion Lessthanorequal methods + + #region Greaterthan methods + /// + /// Returns a new vector whose elements signal whether the elements in left were greater than their + /// corresponding elements in right. + /// + /// The first vector to compare. + /// The second vector to compare. + /// The resultant vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector GreaterThan(Vector left, Vector right) where T : struct + { + return Vector.GreaterThan(left, right); + } + + /// + /// Returns an integral vector whose elements signal whether the elements in left were greater than their + /// corresponding elements in right. + /// + /// The first vector to compare. + /// The second vector to compare. + /// The resultant integral vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector GreaterThan(Vector left, Vector right) + { + return (Vector)Vector.GreaterThan(left, right); + } + + /// + /// Returns a new vector whose elements signal whether the elements in left were greater than their + /// corresponding elements in right. + /// + /// The first vector to compare. + /// The second vector to compare. + /// The resultant vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector GreaterThan(Vector left, Vector right) + { + return Vector.GreaterThan(left, right); + } + + /// + /// Returns an integral vector whose elements signal whether the elements in left were greater than their + /// corresponding elements in right. + /// + /// The first vector to compare. + /// The second vector to compare. + /// The resultant integral vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector GreaterThan(Vector left, Vector right) + { + return (Vector)Vector.GreaterThan(left, right); + } + + /// + /// Returns a new vector whose elements signal whether the elements in left were greater than their + /// corresponding elements in right. + /// + /// The first vector to compare. + /// The second vector to compare. + /// The resultant vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector GreaterThan(Vector left, Vector right) + { + return Vector.GreaterThan(left, right); + } + + /// + /// Returns a boolean indicating whether all elements in left are greater than the corresponding elements in right. + /// elements in right. + /// + /// The first vector to compare. + /// The second vector to compare. + /// True if all elements in left are greater than their corresponding elements in right; False otherwise. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static bool GreaterThanAll(Vector left, Vector right) where T : struct + { + Vector cond = (Vector)Vector.GreaterThan(left, right); + return cond.Equals(Vector.AllOnes); + } + + /// + /// Returns a boolean indicating whether any element in left is greater than its corresponding element in right. + /// + /// The first vector to compare. + /// The second vector to compare. + /// True if any elements in left are greater than their corresponding elements in right; False otherwise. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static bool GreaterThanAny(Vector left, Vector right) where T : struct + { + Vector cond = (Vector)Vector.GreaterThan(left, right); + return !cond.Equals(Vector.Zero); + } + #endregion Greaterthan methods + + #region Greaterthanorequal methods + /// + /// Returns a new vector whose elements signal whether the elements in left were greater than or equal to their + /// corresponding elements in right. + /// + /// The first vector to compare. + /// The second vector to compare. + /// The resultant vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector GreaterThanOrEqual(Vector left, Vector right) where T : struct + { + return Vector.GreaterThanOrEqual(left, right); + } + + /// + /// Returns an integral vector whose elements signal whether the elements in left were greater than or equal to their + /// corresponding elements in right. + /// + /// The first vector to compare. + /// The second vector to compare. + /// The resultant integral vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector GreaterThanOrEqual(Vector left, Vector right) + { + return (Vector)Vector.GreaterThanOrEqual(left, right); + } + + /// + /// Returns a new vector whose elements signal whether the elements in left were greater than or equal to their + /// corresponding elements in right. + /// + /// The first vector to compare. + /// The second vector to compare. + /// The resultant vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector GreaterThanOrEqual(Vector left, Vector right) + { + return Vector.GreaterThanOrEqual(left, right); + } + + /// + /// Returns a new vector whose elements signal whether the elements in left were greater than or equal to their + /// corresponding elements in right. + /// + /// The first vector to compare. + /// The second vector to compare. + /// The resultant vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector GreaterThanOrEqual(Vector left, Vector right) + { + return Vector.GreaterThanOrEqual(left, right); + } + + /// + /// Returns an integral vector whose elements signal whether the elements in left were greater than or equal to + /// their corresponding elements in right. + /// + /// The first vector to compare. + /// The second vector to compare. + /// The resultant integral vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector GreaterThanOrEqual(Vector left, Vector right) + { + return (Vector)Vector.GreaterThanOrEqual(left, right); + } + + /// + /// Returns a boolean indicating whether all of the elements in left are greater than or equal to + /// their corresponding elements in right. + /// + /// The first vector to compare. + /// The second vector to compare. + /// True if all elements in left are greater than or equal to their corresponding elements in right; False otherwise. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static bool GreaterThanOrEqualAll(Vector left, Vector right) where T : struct + { + Vector cond = (Vector)Vector.GreaterThanOrEqual(left, right); + return cond.Equals(Vector.AllOnes); + } + + /// + /// Returns a boolean indicating whether any element in left is greater than or equal to its corresponding element in right. + /// + /// The first vector to compare. + /// The second vector to compare. + /// True if any elements in left are greater than or equal to their corresponding elements in right; False otherwise. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static bool GreaterThanOrEqualAny(Vector left, Vector right) where T : struct + { + Vector cond = (Vector)Vector.GreaterThanOrEqual(left, right); + return !cond.Equals(Vector.Zero); + } + #endregion Greaterthanorequal methods + #endregion Comparison methods + + #region Vector Math Methods + // Every operation must either be a JIT intrinsic or implemented over a JIT intrinsic + // as a thin wrapper + // Operations implemented over a JIT intrinsic should be inlined + // Methods that do not have a type parameter are recognized as intrinsics + /// + /// Returns whether or not vector operations are subject to hardware acceleration through JIT intrinsic support. + /// + public static bool IsHardwareAccelerated + { + [Intrinsic] + get + { + return false; + } + } + + // Vector + // Basic Math + // All Math operations for Vector are aggressively inlined here + + /// + /// Returns a new vector whose elements are the absolute values of the given vector's elements. + /// + /// The source vector. + /// The absolute value vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector Abs(Vector value) where T : struct + { + return Vector.Abs(value); + } + + /// + /// Returns a new vector whose elements are the minimum of each pair of elements in the two given vectors. + /// + /// The first source vector. + /// The second source vector. + /// The minimum vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector Min(Vector left, Vector right) where T : struct + { + return Vector.Min(left, right); + } + + /// + /// Returns a new vector whose elements are the maximum of each pair of elements in the two given vectors. + /// + /// The first source vector. + /// The second source vector. + /// The maximum vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector Max(Vector left, Vector right) where T : struct + { + return Vector.Max(left, right); + } + + // Specialized vector operations + + /// + /// Returns the dot product of two vectors. + /// + /// The first source vector. + /// The second source vector. + /// The dot product. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static T Dot(Vector left, Vector right) where T : struct + { + return Vector.DotProduct(left, right); + } + + /// + /// Returns a new vector whose elements are the square roots of the given vector's elements. + /// + /// The source vector. + /// The square root vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector SquareRoot(Vector value) where T : struct + { + return Vector.SquareRoot(value); + } + #endregion Vector Math Methods + + #region Named Arithmetic Operators + /// + /// Creates a new vector whose values are the sum of each pair of elements from the two given vectors. + /// + /// The first source vector. + /// The second source vector. + /// The summed vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector Add(Vector left, Vector right) where T : struct + { + return left + right; + } + + /// + /// Creates a new vector whose values are the difference between each pairs of elements in the given vectors. + /// + /// The first source vector. + /// The second source vector. + /// The difference vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector Subtract(Vector left, Vector right) where T : struct + { + return left - right; + } + + /// + /// Creates a new vector whose values are the product of each pair of elements from the two given vectors. + /// + /// The first source vector. + /// The second source vector. + /// The summed vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector Multiply(Vector left, Vector right) where T : struct + { + return left * right; + } + + /// + /// Returns a new vector whose values are the values of the given vector each multiplied by a scalar value. + /// + /// The source vector. + /// The scalar factor. + /// The scaled vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector Multiply(Vector left, T right) where T : struct + { + return left * right; + } + + /// + /// Returns a new vector whose values are the values of the given vector each multiplied by a scalar value. + /// + /// The scalar factor. + /// The source vector. + /// The scaled vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector Multiply(T left, Vector right) where T : struct + { + return left * right; + } + + /// + /// Returns a new vector whose values are the result of dividing the first vector's elements + /// by the corresponding elements in the second vector. + /// + /// The first source vector. + /// The second source vector. + /// The divided vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector Divide(Vector left, Vector right) where T : struct + { + return left / right; + } + + /// + /// Returns a new vector whose elements are the given vector's elements negated. + /// + /// The source vector. + /// The negated vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector Negate(Vector value) where T : struct + { + return -value; + } + #endregion Named Arithmetic Operators + + #region Named Bitwise Operators + /// + /// Returns a new vector by performing a bitwise-and operation on each of the elements in the given vectors. + /// + /// The first source vector. + /// The second source vector. + /// The resultant vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector BitwiseAnd(Vector left, Vector right) where T : struct + { + return left & right; + } + + /// + /// Returns a new vector by performing a bitwise-or operation on each of the elements in the given vectors. + /// + /// The first source vector. + /// The second source vector. + /// The resultant vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector BitwiseOr(Vector left, Vector right) where T : struct + { + return left | right; + } + + /// + /// Returns a new vector whose elements are obtained by taking the one's complement of the given vector's elements. + /// + /// The source vector. + /// The one's complement vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector OnesComplement(Vector value) where T : struct + { + return ~value; + } + + /// + /// Returns a new vector by performing a bitwise-exclusive-or operation on each of the elements in the given vectors. + /// + /// The first source vector. + /// The second source vector. + /// The resultant vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector Xor(Vector left, Vector right) where T : struct + { + return left ^ right; + } + + /// + /// Returns a new vector by performing a bitwise-and-not operation on each of the elements in the given vectors. + /// + /// The first source vector. + /// The second source vector. + /// The resultant vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector AndNot(Vector left, Vector right) where T : struct + { + return left & ~right; + } + #endregion Named Bitwise Operators + + #region Conversion Methods + /// + /// Reinterprets the bits of the given vector into those of a vector of unsigned bytes. + /// + /// The source vector + /// The reinterpreted vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector AsVectorByte(Vector value) where T : struct + { + return (Vector)value; + } + + /// + /// Reinterprets the bits of the given vector into those of a vector of signed bytes. + /// + /// The source vector + /// The reinterpreted vector. + [CLSCompliant(false)] + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector AsVectorSByte(Vector value) where T : struct + { + return (Vector)value; + } + + /// + /// Reinterprets the bits of the given vector into those of a vector of 16-bit integers. + /// + /// The source vector + /// The reinterpreted vector. + [CLSCompliant(false)] + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector AsVectorUInt16(Vector value) where T : struct + { + return (Vector)value; + } + + /// + /// Reinterprets the bits of the given vector into those of a vector of signed 16-bit integers. + /// + /// The source vector + /// The reinterpreted vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector AsVectorInt16(Vector value) where T : struct + { + return (Vector)value; + } + + /// + /// Reinterprets the bits of the given vector into those of a vector of unsigned 32-bit integers. + /// + /// The source vector + /// The reinterpreted vector. + [CLSCompliant(false)] + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector AsVectorUInt32(Vector value) where T : struct + { + return (Vector)value; + } + + /// + /// Reinterprets the bits of the given vector into those of a vector of signed 32-bit integers. + /// + /// The source vector + /// The reinterpreted vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector AsVectorInt32(Vector value) where T : struct + { + return (Vector)value; + } + + /// + /// Reinterprets the bits of the given vector into those of a vector of unsigned 64-bit integers. + /// + /// The source vector + /// The reinterpreted vector. + [CLSCompliant(false)] + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector AsVectorUInt64(Vector value) where T : struct + { + return (Vector)value; + } + + + /// + /// Reinterprets the bits of the given vector into those of a vector of signed 64-bit integers. + /// + /// The source vector + /// The reinterpreted vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector AsVectorInt64(Vector value) where T : struct + { + return (Vector)value; + } + + /// + /// Reinterprets the bits of the given vector into those of a vector of 32-bit floating point numbers. + /// + /// The source vector + /// The reinterpreted vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector AsVectorSingle(Vector value) where T : struct + { + return (Vector)value; + } + + /// + /// Reinterprets the bits of the given vector into those of a vector of 64-bit floating point numbers. + /// + /// The source vector + /// The reinterpreted vector. + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public static Vector AsVectorDouble(Vector value) where T : struct + { + return (Vector)value; + } + #endregion Conversion Methods + } +} diff --git a/external/corert/src/System.Private.CoreLib/shared/System/OverflowException.cs b/external/corert/src/System.Private.CoreLib/shared/System/OverflowException.cs index 963825b350..e28dcb87ed 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/OverflowException.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/OverflowException.cs @@ -6,7 +6,7 @@ ** ** ** -** Purpose: Exception class for Arthimatic Overflows. +** Purpose: Exception class for Arithmetic Overflows. ** ** =============================================================================*/ diff --git a/external/corert/src/System.Private.CoreLib/shared/System/ReadOnlyMemory.cs b/external/corert/src/System.Private.CoreLib/shared/System/ReadOnlyMemory.cs index 5d8f00f8ad..166a204edb 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/ReadOnlyMemory.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/ReadOnlyMemory.cs @@ -8,7 +8,9 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using EditorBrowsableAttribute = System.ComponentModel.EditorBrowsableAttribute; using EditorBrowsableState = System.ComponentModel.EditorBrowsableState; +#if !FEATURE_PORTABLE_SPAN using Internal.Runtime.CompilerServices; +#endif // FEATURE_PORTABLE_SPAN namespace System { @@ -36,14 +38,16 @@ namespace System /// Creates a new memory over the entirety of the target array. /// /// The target array. - /// Thrown when is a null - /// reference (Nothing in Visual Basic). + /// Returns default when is null. /// Thrown when is covariant and array's type is not exactly T[]. [MethodImpl(MethodImplOptions.AggressiveInlining)] public ReadOnlyMemory(T[] array) { if (array == null) - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); + { + this = default; + return; // returns default + } _object = array; _index = 0; @@ -57,8 +61,7 @@ namespace System /// The target array. /// The index at which to begin the memory. /// The number of items in the memory. - /// Thrown when is a null - /// reference (Nothing in Visual Basic). + /// Returns default when is null. /// Thrown when is covariant and array's type is not exactly T[]. /// /// Thrown when the specified or end index is not in the range (<0 or >=Length). @@ -67,7 +70,12 @@ namespace System public ReadOnlyMemory(T[] array, int start, int length) { if (array == null) - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); + { + if (start != 0 || length != 0) + ThrowHelper.ThrowArgumentOutOfRangeException(); + this = default; + return; // returns default + } if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start)) ThrowHelper.ThrowArgumentOutOfRangeException(); @@ -96,7 +104,7 @@ namespace System /// Defines an implicit conversion of an array to a /// public static implicit operator ReadOnlyMemory(T[] array) => new ReadOnlyMemory(array); - + /// /// Defines an implicit conversion of a to a /// @@ -168,7 +176,11 @@ namespace System } else if (typeof(T) == typeof(char) && _object is string s) { +#if FEATURE_PORTABLE_SPAN + return new ReadOnlySpan(Unsafe.As>(s), MemoryExtensions.StringAdjustment, s.Length).Slice(_index, _length); +#else return new ReadOnlySpan(ref Unsafe.As(ref s.GetRawStringData()), s.Length).Slice(_index, _length); +#endif // FEATURE_PORTABLE_SPAN } else if (_object != null) { @@ -216,19 +228,26 @@ namespace System { if (_index < 0) { - memoryHandle = ((OwnedMemory)_object).Pin(); - memoryHandle.AddOffset((_index & RemoveOwnedFlagBitMask) * Unsafe.SizeOf()); + memoryHandle = ((OwnedMemory)_object).Pin((_index & RemoveOwnedFlagBitMask) * Unsafe.SizeOf()); } else if (typeof(T) == typeof(char) && _object is string s) { GCHandle handle = GCHandle.Alloc(s, GCHandleType.Pinned); +#if FEATURE_PORTABLE_SPAN + void* pointer = Unsafe.Add((void*)handle.AddrOfPinnedObject(), _index); +#else void* pointer = Unsafe.Add(Unsafe.AsPointer(ref s.GetRawStringData()), _index); +#endif // FEATURE_PORTABLE_SPAN memoryHandle = new MemoryHandle(null, pointer, handle); } else if (_object is T[] array) { var handle = GCHandle.Alloc(array, GCHandleType.Pinned); +#if FEATURE_PORTABLE_SPAN + void* pointer = Unsafe.Add((void*)handle.AddrOfPinnedObject(), _index); +#else void* pointer = Unsafe.Add(Unsafe.AsPointer(ref array.GetRawSzArrayData()), _index); +#endif // FEATURE_PORTABLE_SPAN memoryHandle = new MemoryHandle(null, pointer, handle); } } @@ -286,7 +305,7 @@ namespace System { return _object != null ? CombineHashCodes(_object.GetHashCode(), _index.GetHashCode(), _length.GetHashCode()) : 0; } - + private static int CombineHashCodes(int left, int right) { return ((left << 5) + left) ^ right; diff --git a/external/corert/src/System.Private.CoreLib/shared/System/ReadOnlySpan.Fast.cs b/external/corert/src/System.Private.CoreLib/shared/System/ReadOnlySpan.Fast.cs new file mode 100644 index 0000000000..9bf3f211a8 --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/shared/System/ReadOnlySpan.Fast.cs @@ -0,0 +1,270 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.ComponentModel; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.Versioning; +using Internal.Runtime.CompilerServices; + +#pragma warning disable 0809 //warning CS0809: Obsolete member 'Span.Equals(object)' overrides non-obsolete member 'object.Equals(object)' + +#if BIT64 +using nuint = System.UInt64; +#else +using nuint = System.UInt32; +#endif + +namespace System +{ + /// + /// ReadOnlySpan represents a contiguous region of arbitrary memory. Unlike arrays, it can point to either managed + /// or native memory, or to memory allocated on the stack. It is type- and memory-safe. + /// + [DebuggerTypeProxy(typeof(SpanDebugView<>))] + [DebuggerDisplay("{ToString(),raw}")] + [NonVersionable] + public readonly ref partial struct ReadOnlySpan + { + /// A byref or a native ptr. + internal readonly ByReference _pointer; + /// The number of elements this ReadOnlySpan contains. +#if PROJECTN + [Bound] +#endif + private readonly int _length; + + /// + /// Creates a new read-only span over the entirety of the target array. + /// + /// The target array. + /// Returns default when is null. + /// reference (Nothing in Visual Basic). + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan(T[] array) + { + if (array == null) + { + this = default; + return; // returns default + } + + _pointer = new ByReference(ref Unsafe.As(ref array.GetRawSzArrayData())); + _length = array.Length; + } + + /// + /// Creates a new read-only span over the portion of the target array beginning + /// at 'start' index and ending at 'end' index (exclusive). + /// + /// The target array. + /// The index at which to begin the read-only span. + /// The number of items in the read-only span. + /// Returns default when is null. + /// reference (Nothing in Visual Basic). + /// + /// Thrown when the specified or end index is not in the range (<0 or >=Length). + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan(T[] array, int start, int length) + { + if (array == null) + { + if (start != 0 || length != 0) + ThrowHelper.ThrowArgumentOutOfRangeException(); + this = default; + return; // returns default + } + if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start)) + ThrowHelper.ThrowArgumentOutOfRangeException(); + + _pointer = new ByReference(ref Unsafe.Add(ref Unsafe.As(ref array.GetRawSzArrayData()), start)); + _length = length; + } + + /// + /// Creates a new read-only span over the target unmanaged buffer. Clearly this + /// is quite dangerous, because we are creating arbitrarily typed T's + /// out of a void*-typed block of memory. And the length is not checked. + /// But if this creation is correct, then all subsequent uses are correct. + /// + /// An unmanaged pointer to memory. + /// The number of elements the memory contains. + /// + /// Thrown when is reference type or contains pointers and hence cannot be stored in unmanaged memory. + /// + /// + /// Thrown when the specified is negative. + /// + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public unsafe ReadOnlySpan(void* pointer, int length) + { + if (RuntimeHelpers.IsReferenceOrContainsReferences()) + ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T)); + if (length < 0) + ThrowHelper.ThrowArgumentOutOfRangeException(); + + _pointer = new ByReference(ref Unsafe.As(ref *(byte*)pointer)); + _length = length; + } + + // Constructor for internal use only. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal ReadOnlySpan(ref T ptr, int length) + { + Debug.Assert(length >= 0); + + _pointer = new ByReference(ref ptr); + _length = length; + } + + /// + /// Returns the specified element of the read-only span. + /// + /// + /// + /// + /// Thrown when index less than 0 or index greater than or equal to Length + /// + public ref readonly T this[int index] + { +#if PROJECTN + [BoundsChecking] + get + { + return ref Unsafe.Add(ref _pointer.Value, index); + } +#else + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [NonVersionable] + get + { + if ((uint)index >= (uint)_length) + ThrowHelper.ThrowIndexOutOfRangeException(); + return ref Unsafe.Add(ref _pointer.Value, index); + } +#endif + } + + /// + /// Copies the contents of this read-only span into destination span. If the source + /// and destinations overlap, this method behaves as if the original values in + /// a temporary location before the destination is overwritten. + /// + /// The span to copy items into. + /// + /// Thrown when the destination Span is shorter than the source Span. + /// + /// + public void CopyTo(Span destination) + { + // Using "if (!TryCopyTo(...))" results in two branches: one for the length + // check, and one for the result of TryCopyTo. Since these checks are equivalent, + // we can optimize by performing the check once ourselves then calling Memmove directly. + + if ((uint)_length <= (uint)destination.Length) + { + Buffer.Memmove(ref destination._pointer.Value, ref _pointer.Value, (nuint)_length); + } + else + { + ThrowHelper.ThrowArgumentException_DestinationTooShort(); + } + } + + /// Copies the contents of this read-only span into destination span. If the source + /// and destinations overlap, this method behaves as if the original values in + /// a temporary location before the destination is overwritten. + /// + /// If the destination span is shorter than the source span, this method + /// return false and no data is written to the destination. + /// The span to copy items into. + public bool TryCopyTo(Span destination) + { + bool retVal = false; + if ((uint)_length <= (uint)destination.Length) + { + Buffer.Memmove(ref destination._pointer.Value, ref _pointer.Value, (nuint)_length); + retVal = true; + } + return retVal; + } + + /// + /// Returns true if left and right point at the same memory and have the same length. Note that + /// this does *not* check to see if the *contents* are equal. + /// + public static bool operator ==(ReadOnlySpan left, ReadOnlySpan right) + { + return left._length == right._length && Unsafe.AreSame(ref left._pointer.Value, ref right._pointer.Value); + } + + /// + /// For , returns a new instance of string that represents the characters pointed to by the span. + /// Otherwise, returns a with the name of the type and the number of elements. + /// + public override string ToString() + { + if (typeof(T) == typeof(char)) + { + unsafe + { + fixed (char* src = &Unsafe.As(ref _pointer.Value)) + return new string(src, 0, _length); + } + } + return string.Format("System.ReadOnlySpan<{0}>[{1}]", typeof(T).Name, _length); + } + + /// + /// Forms a slice out of the given read-only span, beginning at 'start'. + /// + /// The index at which to begin this slice. + /// + /// Thrown when the specified index is not in range (<0 or >=Length). + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan Slice(int start) + { + if ((uint)start > (uint)_length) + ThrowHelper.ThrowArgumentOutOfRangeException(); + + return new ReadOnlySpan(ref Unsafe.Add(ref _pointer.Value, start), _length - start); + } + + /// + /// Forms a slice out of the given read-only span, beginning at 'start', of given length + /// + /// The index at which to begin this slice. + /// The desired length for the slice (exclusive). + /// + /// Thrown when the specified or end index is not in range (<0 or >=Length). + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan Slice(int start, int length) + { + if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start)) + ThrowHelper.ThrowArgumentOutOfRangeException(); + + return new ReadOnlySpan(ref Unsafe.Add(ref _pointer.Value, start), length); + } + + /// + /// Copies the contents of this read-only span into a new array. This heap + /// allocates, so should generally be avoided, however it is sometimes + /// necessary to bridge the gap with APIs written in terms of arrays. + /// + public T[] ToArray() + { + if (_length == 0) + return Array.Empty(); + + var destination = new T[_length]; + Buffer.Memmove(ref Unsafe.As(ref destination.GetRawSzArrayData()), ref _pointer.Value, (nuint)_length); + return destination; + } + } +} diff --git a/external/corert/src/System.Private.CoreLib/shared/System/ReadOnlySpan.cs b/external/corert/src/System.Private.CoreLib/shared/System/ReadOnlySpan.cs index c49dddf986..906a3c4317 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/ReadOnlySpan.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/ReadOnlySpan.cs @@ -5,8 +5,9 @@ using System.ComponentModel; using System.Diagnostics; using System.Runtime.CompilerServices; +#if !FEATURE_PORTABLE_SPAN using System.Runtime.Versioning; -using Internal.Runtime.CompilerServices; +#endif // !FEATURE_PORTABLE_SPAN #pragma warning disable 0809 //warning CS0809: Obsolete member 'Span.Equals(object)' overrides non-obsolete member 'object.Equals(object)' @@ -17,128 +18,17 @@ namespace System /// or native memory, or to memory allocated on the stack. It is type- and memory-safe. /// [DebuggerTypeProxy(typeof(SpanDebugView<>))] - [DebuggerDisplay("{DebuggerDisplay,nq}")] - [NonVersionable] - public readonly ref struct ReadOnlySpan + [DebuggerDisplay("{ToString(),raw}")] + public readonly ref partial struct ReadOnlySpan { - /// A byref or a native ptr. - internal readonly ByReference _pointer; - /// The number of elements this ReadOnlySpan contains. -#if PROJECTN - [Bound] -#endif - private readonly int _length; - - /// - /// Creates a new read-only span over the entirety of the target array. - /// - /// The target array. - /// Thrown when is a null - /// reference (Nothing in Visual Basic). - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ReadOnlySpan(T[] array) - { - if (array == null) - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); - - _pointer = new ByReference(ref Unsafe.As(ref array.GetRawSzArrayData())); - _length = array.Length; - } - - /// - /// Creates a new read-only span over the portion of the target array beginning - /// at 'start' index and ending at 'end' index (exclusive). - /// - /// The target array. - /// The index at which to begin the read-only span. - /// The number of items in the read-only span. - /// Thrown when is a null - /// reference (Nothing in Visual Basic). - /// - /// Thrown when the specified or end index is not in the range (<0 or >=Length). - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ReadOnlySpan(T[] array, int start, int length) - { - if (array == null) - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); - if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start)) - ThrowHelper.ThrowArgumentOutOfRangeException(); - - _pointer = new ByReference(ref Unsafe.Add(ref Unsafe.As(ref array.GetRawSzArrayData()), start)); - _length = length; - } - - /// - /// Creates a new read-only span over the target unmanaged buffer. Clearly this - /// is quite dangerous, because we are creating arbitrarily typed T's - /// out of a void*-typed block of memory. And the length is not checked. - /// But if this creation is correct, then all subsequent uses are correct. - /// - /// An unmanaged pointer to memory. - /// The number of elements the memory contains. - /// - /// Thrown when is reference type or contains pointers and hence cannot be stored in unmanaged memory. - /// - /// - /// Thrown when the specified is negative. - /// - [CLSCompliant(false)] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public unsafe ReadOnlySpan(void* pointer, int length) - { - if (RuntimeHelpers.IsReferenceOrContainsReferences()) - ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T)); - if (length < 0) - ThrowHelper.ThrowArgumentOutOfRangeException(); - - _pointer = new ByReference(ref Unsafe.As(ref *(byte*)pointer)); - _length = length; - } - - /// - /// Create a new read-only span over a portion of a regular managed object. This can be useful - /// if part of a managed object represents a "fixed array." This is dangerous because neither the - /// is checked, nor being null, nor the fact that - /// "rawPointer" actually lies within . - /// - /// The managed object that contains the data to span over. - /// A reference to data within that object. - /// The number of elements the memory contains. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - [EditorBrowsable(EditorBrowsableState.Never)] - public static ReadOnlySpan DangerousCreate(object obj, ref T objectData, int length) => new ReadOnlySpan(ref objectData, length); - - // Constructor for internal use only. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal ReadOnlySpan(ref T ptr, int length) - { - Debug.Assert(length >= 0); - - _pointer = new ByReference(ref ptr); - _length = length; - } - - //Debugger Display = {T[length]} - private string DebuggerDisplay => string.Format("{{{0}[{1}]}}", typeof(T).Name, _length); - - /// - /// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to the location where the 0th element - /// would have been stored. Such a reference can be used for pinning but must never be dereferenced. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - [EditorBrowsable(EditorBrowsableState.Never)] - internal ref readonly T DangerousGetPinnableReference() - { - return ref _pointer.Value; - } - /// /// The number of items in the read-only span. /// public int Length { +#if !FEATURE_PORTABLE_SPAN [NonVersionable] +#endif // !FEATURE_PORTABLE_SPAN get { return _length; @@ -150,83 +40,14 @@ namespace System /// public bool IsEmpty { +#if !FEATURE_PORTABLE_SPAN [NonVersionable] +#endif // !FEATURE_PORTABLE_SPAN get { return _length == 0; } } - - /// - /// Returns the specified element of the read-only span. - /// - /// - /// - /// - /// Thrown when index less than 0 or index greater than or equal to Length - /// - public ref readonly T this[int index] - { -#if PROJECTN - [BoundsChecking] - get - { - return ref Unsafe.Add(ref _pointer.Value, index); - } -#else - [Intrinsic] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - [NonVersionable] - get - { - if ((uint)index >= (uint)_length) - ThrowHelper.ThrowIndexOutOfRangeException(); - return ref Unsafe.Add(ref _pointer.Value, index); - } -#endif - } - - /// - /// Copies the contents of this read-only span into destination span. If the source - /// and destinations overlap, this method behaves as if the original values in - /// a temporary location before the destination is overwritten. - /// - /// The span to copy items into. - /// - /// Thrown when the destination Span is shorter than the source Span. - /// - /// - public void CopyTo(Span destination) - { - if (!TryCopyTo(destination)) - ThrowHelper.ThrowArgumentException_DestinationTooShort(); - } - - /// Copies the contents of this read-only span into destination span. If the source - /// and destinations overlap, this method behaves as if the original values in - /// a temporary location before the destination is overwritten. - /// - /// If the destination span is shorter than the source span, this method - /// return false and no data is written to the destination. - /// The span to copy items into. - public bool TryCopyTo(Span destination) - { - if ((uint)_length > (uint)destination.Length) - return false; - - Span.CopyTo(ref destination.DangerousGetPinnableReference(), ref _pointer.Value, _length); - return true; - } - - /// - /// Returns true if left and right point at the same memory and have the same length. Note that - /// this does *not* check to see if the *contents* are equal. - /// - public static bool operator ==(ReadOnlySpan left, ReadOnlySpan right) - { - return left._length == right._length && Unsafe.AreSame(ref left._pointer.Value, ref right._pointer.Value); - } - /// /// Returns false if left and right point at the same memory and have the same length. Note that /// this does *not* check to see if the *contents* are equal. @@ -239,7 +60,7 @@ namespace System /// Always thrown by this method. /// /// - [Obsolete("Equals() on Span will always throw an exception. Use == instead.")] + [Obsolete("Equals() on ReadOnlySpan will always throw an exception. Use == instead.")] [EditorBrowsable(EditorBrowsableState.Never)] public override bool Equals(object obj) { @@ -252,7 +73,7 @@ namespace System /// Always thrown by this method. /// /// - [Obsolete("GetHashCode() on Span will always throw an exception.")] + [Obsolete("GetHashCode() on ReadOnlySpan will always throw an exception.")] [EditorBrowsable(EditorBrowsableState.Never)] public override int GetHashCode() { @@ -262,61 +83,13 @@ namespace System /// /// Defines an implicit conversion of an array to a /// - public static implicit operator ReadOnlySpan(T[] array) => array != null ? new ReadOnlySpan(array) : default; + public static implicit operator ReadOnlySpan(T[] array) => new ReadOnlySpan(array); /// /// Defines an implicit conversion of a to a /// public static implicit operator ReadOnlySpan(ArraySegment arraySegment) - => arraySegment.Array != null ? new ReadOnlySpan(arraySegment.Array, arraySegment.Offset, arraySegment.Count) : default; - - /// - /// Forms a slice out of the given read-only span, beginning at 'start'. - /// - /// The index at which to begin this slice. - /// - /// Thrown when the specified index is not in range (<0 or >=Length). - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ReadOnlySpan Slice(int start) - { - if ((uint)start > (uint)_length) - ThrowHelper.ThrowArgumentOutOfRangeException(); - - return new ReadOnlySpan(ref Unsafe.Add(ref _pointer.Value, start), _length - start); - } - - /// - /// Forms a slice out of the given read-only span, beginning at 'start', of given length - /// - /// The index at which to begin this slice. - /// The desired length for the slice (exclusive). - /// - /// Thrown when the specified or end index is not in range (<0 or >=Length). - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ReadOnlySpan Slice(int start, int length) - { - if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start)) - ThrowHelper.ThrowArgumentOutOfRangeException(); - - return new ReadOnlySpan(ref Unsafe.Add(ref _pointer.Value, start), length); - } - - /// - /// Copies the contents of this read-only span into a new array. This heap - /// allocates, so should generally be avoided, however it is sometimes - /// necessary to bridge the gap with APIs written in terms of arrays. - /// - public T[] ToArray() - { - if (_length == 0) - return Array.Empty(); - - var destination = new T[_length]; - Span.CopyTo(ref Unsafe.As(ref destination.GetRawSzArrayData()), ref _pointer.Value, _length); - return destination; - } + => new ReadOnlySpan(arraySegment.Array, arraySegment.Offset, arraySegment.Count); /// /// Returns a 0-length read-only span whose base is the null pointer. diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Reflection/AssemblyNameFormatter.cs b/external/corert/src/System.Private.CoreLib/shared/System/Reflection/AssemblyNameFormatter.cs index 7c4a980079..716afb045c 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Reflection/AssemblyNameFormatter.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Reflection/AssemblyNameFormatter.cs @@ -95,7 +95,7 @@ namespace System.Reflection //@todo: App-compat: You can use double or single quotes to quote a name, and Fusion (or rather the IdentityAuthority) picks one // by some algorithm. Rather than guess at it, I'll just use double-quote consistently. - if (s != s.Trim() || s.Contains("\"") || s.Contains("\'")) + if (s != s.Trim() || s.Contains('\"') || s.Contains('\'')) needsQuoting = true; if (needsQuoting) diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Reflection/ReflectionTypeLoadException.cs b/external/corert/src/System.Private.CoreLib/shared/System/Reflection/ReflectionTypeLoadException.cs index d78c068958..5011c50053 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Reflection/ReflectionTypeLoadException.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Reflection/ReflectionTypeLoadException.cs @@ -27,7 +27,7 @@ namespace System.Reflection HResult = HResults.COR_E_REFLECTIONTYPELOAD; } - private ReflectionTypeLoadException(SerializationInfo info, StreamingContext context) + private ReflectionTypeLoadException(SerializationInfo info, StreamingContext context) : base(info, context) { LoaderExceptions = (Exception[])(info.GetValue("Exceptions", typeof(Exception[]))); @@ -40,48 +40,34 @@ namespace System.Reflection info.AddValue("Exceptions", LoaderExceptions, typeof(Exception[])); } - public override string Message - { - get - { - if (LoaderExceptions == null || LoaderExceptions.Length == 0) - { - return base.Message; - } - - StringBuilder text = new StringBuilder(); - text.AppendLine(base.Message); - foreach (Exception e in LoaderExceptions) - { - if (e != null) - { - text.AppendLine(e.Message); - } - } - return text.ToString(); - } - } - - public override string ToString() - { - StringBuilder text = new StringBuilder(); - text.AppendLine(base.ToString()); - if (LoaderExceptions != null) - { - foreach (Exception e in LoaderExceptions) - { - if (e != null) - { - text.AppendLine(e.ToString()); - } - } - } - - return text.ToString(); - } - public Type[] Types { get; } public Exception[] LoaderExceptions { get; } + + public override string Message => CreateString(isMessage: true); + + public override string ToString() => CreateString(isMessage: false); + + private string CreateString(bool isMessage) + { + string baseValue = isMessage ? base.Message : base.ToString(); + + Exception[] exceptions = LoaderExceptions; + if (exceptions == null || exceptions.Length == 0) + { + return baseValue; + } + + var text = new StringBuilder(baseValue); + foreach (Exception e in exceptions) + { + if (e != null) + { + text.AppendLine(); + text.Append(isMessage ? e.Message : e.ToString()); + } + } + return text.ToString(); + } } } diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Reflection/SignatureTypeExtensions.cs b/external/corert/src/System.Private.CoreLib/shared/System/Reflection/SignatureTypeExtensions.cs index 5847944f14..9247132546 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Reflection/SignatureTypeExtensions.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Reflection/SignatureTypeExtensions.cs @@ -9,6 +9,7 @@ using System.Diagnostics; namespace System.Reflection { #if CORERT + [System.Runtime.CompilerServices.ReflectionBlocked] public // Needs to be public so that Reflection.Core can see it. #else internal diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilder.cs b/external/corert/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilder.cs index b5ecd7924c..0e1220d119 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilder.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilder.cs @@ -8,6 +8,108 @@ using System.Threading.Tasks; namespace System.Runtime.CompilerServices { + /// Represents a builder for asynchronous methods that return a . + [StructLayout(LayoutKind.Auto)] + public struct AsyncValueTaskMethodBuilder + { + /// The to which most operations are delegated. + private AsyncTaskMethodBuilder _methodBuilder; // mutable struct; do not make it readonly + /// true if completed synchronously and successfully; otherwise, false. + private bool _haveResult; + /// true if the builder should be used for setting/getting the result; otherwise, false. + private bool _useBuilder; + + /// Creates an instance of the struct. + /// The initialized instance. + public static AsyncValueTaskMethodBuilder Create() => +#if CORERT + // corert's AsyncTaskMethodBuilder.Create() currently does additional debugger-related + // work, so we need to delegate to it. + new AsyncValueTaskMethodBuilder() { _methodBuilder = AsyncTaskMethodBuilder.Create() }; +#else + // _methodBuilder should be initialized to AsyncTaskMethodBuilder.Create(), but on coreclr + // that Create() is a nop, so we can just return the default here. + default; +#endif + + /// Begins running the builder with the associated state machine. + /// The type of the state machine. + /// The state machine instance, passed by reference. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine => + // will provide the right ExecutionContext semantics +#if netstandard + _methodBuilder.Start(ref stateMachine); +#else + AsyncMethodBuilderCore.Start(ref stateMachine); +#endif + + /// Associates the builder with the specified state machine. + /// The state machine instance to associate with the builder. + public void SetStateMachine(IAsyncStateMachine stateMachine) => _methodBuilder.SetStateMachine(stateMachine); + + /// Marks the task as successfully completed. + public void SetResult() + { + if (_useBuilder) + { + _methodBuilder.SetResult(); + } + else + { + _haveResult = true; + } + } + + /// Marks the task as failed and binds the specified exception to the task. + /// The exception to bind to the task. + public void SetException(Exception exception) => _methodBuilder.SetException(exception); + + /// Gets the task for this builder. + public ValueTask Task + { + get + { + if (_haveResult) + { + return default; + } + else + { + _useBuilder = true; + return new ValueTask(_methodBuilder.Task); + } + } + } + + /// Schedules the state machine to proceed to the next action when the specified awaiter completes. + /// The type of the awaiter. + /// The type of the state machine. + /// The awaiter. + /// The state machine. + public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) + where TAwaiter : INotifyCompletion + where TStateMachine : IAsyncStateMachine + { + _useBuilder = true; + _methodBuilder.AwaitOnCompleted(ref awaiter, ref stateMachine); + } + + /// Schedules the state machine to proceed to the next action when the specified awaiter completes. + /// The type of the awaiter. + /// The type of the state machine. + /// The awaiter. + /// The state machine. + [SecuritySafeCritical] + public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) + where TAwaiter : ICriticalNotifyCompletion + where TStateMachine : IAsyncStateMachine + { + _useBuilder = true; + _methodBuilder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine); + } + } + /// Represents a builder for asynchronous methods that returns a . /// The type of the result. [StructLayout(LayoutKind.Auto)] @@ -32,14 +134,20 @@ namespace System.Runtime.CompilerServices #else // _methodBuilder should be initialized to AsyncTaskMethodBuilder.Create(), but on coreclr // that Create() is a nop, so we can just return the default here. - default(AsyncValueTaskMethodBuilder); + default; #endif /// Begins running the builder with the associated state machine. /// The type of the state machine. /// The state machine instance, passed by reference. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine => - _methodBuilder.Start(ref stateMachine); // will provide the right ExecutionContext semantics + // will provide the right ExecutionContext semantics +#if netstandard + _methodBuilder.Start(ref stateMachine); +#else + AsyncMethodBuilderCore.Start(ref stateMachine); +#endif /// Associates the builder with the specified state machine. /// The state machine instance to associate with the builder. diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs b/external/corert/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs index 4e8ce691be..b6f12299bf 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs @@ -5,9 +5,115 @@ using System.Diagnostics; using System.Runtime.InteropServices; using System.Threading.Tasks; +using System.Threading.Tasks.Sources; + +#if !netstandard +using Internal.Runtime.CompilerServices; +#endif namespace System.Runtime.CompilerServices { + /// Provides an awaitable type that enables configured awaits on a . + [StructLayout(LayoutKind.Auto)] + public readonly struct ConfiguredValueTaskAwaitable + { + /// The wrapped . + private readonly ValueTask _value; + + /// Initializes the awaitable. + /// The wrapped . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal ConfiguredValueTaskAwaitable(ValueTask value) => _value = value; + + /// Returns an awaiter for this instance. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ConfiguredValueTaskAwaiter GetAwaiter() => new ConfiguredValueTaskAwaiter(_value); + + /// Provides an awaiter for a . + [StructLayout(LayoutKind.Auto)] + public readonly struct ConfiguredValueTaskAwaiter : ICriticalNotifyCompletion +#if CORECLR + , IValueTaskAwaiter +#endif + { + /// The value being awaited. + private readonly ValueTask _value; + + /// Initializes the awaiter. + /// The value to be awaited. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal ConfiguredValueTaskAwaiter(ValueTask value) => _value = value; + + /// Gets whether the has completed. + public bool IsCompleted + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _value.IsCompleted; + } + + /// Gets the result of the ValueTask. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [StackTraceHidden] + public void GetResult() => _value.ThrowIfCompletedUnsuccessfully(); + + /// Schedules the continuation action for the . + public void OnCompleted(Action continuation) + { + if (_value.ObjectIsTask) + { + _value.UnsafeGetTask().ConfigureAwait(_value.ContinueOnCapturedContext).GetAwaiter().OnCompleted(continuation); + } + else if (_value._obj != null) + { + _value.UnsafeGetValueTaskSource().OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, + ValueTaskSourceOnCompletedFlags.FlowExecutionContext | + (_value.ContinueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None)); + } + else + { + ValueTask.CompletedTask.ConfigureAwait(_value.ContinueOnCapturedContext).GetAwaiter().OnCompleted(continuation); + } + } + + /// Schedules the continuation action for the . + public void UnsafeOnCompleted(Action continuation) + { + if (_value.ObjectIsTask) + { + _value.UnsafeGetTask().ConfigureAwait(_value.ContinueOnCapturedContext).GetAwaiter().UnsafeOnCompleted(continuation); + } + else if (_value._obj != null) + { + _value.UnsafeGetValueTaskSource().OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, + _value.ContinueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None); + } + else + { + ValueTask.CompletedTask.ConfigureAwait(_value.ContinueOnCapturedContext).GetAwaiter().UnsafeOnCompleted(continuation); + } + } + +#if CORECLR + void IValueTaskAwaiter.AwaitUnsafeOnCompleted(IAsyncStateMachineBox box) + { + if (_value.ObjectIsTask) + { + TaskAwaiter.UnsafeOnCompletedInternal(_value.UnsafeGetTask(), box, _value.ContinueOnCapturedContext); + } + else if (_value._obj != null) + { + _value.UnsafeGetValueTaskSource().OnCompleted(ValueTaskAwaiter.s_invokeAsyncStateMachineBox, box, _value._token, + _value.ContinueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None); + } + else + { + TaskAwaiter.UnsafeOnCompletedInternal(Task.CompletedTask, box, _value.ContinueOnCapturedContext); + } + } +#endif + } + } + /// Provides an awaitable type that enables configured awaits on a . /// The type of the result produced. [StructLayout(LayoutKind.Auto)] @@ -15,74 +121,98 @@ namespace System.Runtime.CompilerServices { /// The wrapped . private readonly ValueTask _value; - /// true to attempt to marshal the continuation back to the original context captured; otherwise, false. - private readonly bool _continueOnCapturedContext; /// Initializes the awaitable. /// The wrapped . - /// - /// true to attempt to marshal the continuation back to the original synchronization context captured; otherwise, false. - /// - internal ConfiguredValueTaskAwaitable(ValueTask value, bool continueOnCapturedContext) - { - _value = value; - _continueOnCapturedContext = continueOnCapturedContext; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal ConfiguredValueTaskAwaitable(ValueTask value) => _value = value; /// Returns an awaiter for this instance. - public ConfiguredValueTaskAwaiter GetAwaiter() => - new ConfiguredValueTaskAwaiter(_value, _continueOnCapturedContext); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ConfiguredValueTaskAwaiter GetAwaiter() => new ConfiguredValueTaskAwaiter(_value); /// Provides an awaiter for a . [StructLayout(LayoutKind.Auto)] - public struct ConfiguredValueTaskAwaiter : ICriticalNotifyCompletion, IConfiguredValueTaskAwaiter + public readonly struct ConfiguredValueTaskAwaiter : ICriticalNotifyCompletion +#if CORECLR + , IValueTaskAwaiter +#endif { /// The value being awaited. - private ValueTask _value; // Methods are called on this; avoid making it readonly so as to avoid unnecessary copies - /// The value to pass to ConfigureAwait. - internal readonly bool _continueOnCapturedContext; + private readonly ValueTask _value; /// Initializes the awaiter. /// The value to be awaited. - /// The value to pass to ConfigureAwait. - internal ConfiguredValueTaskAwaiter(ValueTask value, bool continueOnCapturedContext) - { - _value = value; - _continueOnCapturedContext = continueOnCapturedContext; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal ConfiguredValueTaskAwaiter(ValueTask value) => _value = value; /// Gets whether the has completed. - public bool IsCompleted => _value.IsCompleted; + public bool IsCompleted + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _value.IsCompleted; + } /// Gets the result of the ValueTask. + [MethodImpl(MethodImplOptions.AggressiveInlining)] [StackTraceHidden] - public TResult GetResult() => - _value._task == null ? - _value._result : - _value._task.GetAwaiter().GetResult(); + public TResult GetResult() => _value.Result; /// Schedules the continuation action for the . - public void OnCompleted(Action continuation) => - _value.AsTask().ConfigureAwait(_continueOnCapturedContext).GetAwaiter().OnCompleted(continuation); + public void OnCompleted(Action continuation) + { + if (_value.ObjectIsTask) + { + _value.UnsafeGetTask().ConfigureAwait(_value.ContinueOnCapturedContext).GetAwaiter().OnCompleted(continuation); + } + else if (_value._obj != null) + { + _value.UnsafeGetValueTaskSource().OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, + ValueTaskSourceOnCompletedFlags.FlowExecutionContext | + (_value.ContinueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None)); + } + else + { + ValueTask.CompletedTask.ConfigureAwait(_value.ContinueOnCapturedContext).GetAwaiter().OnCompleted(continuation); + } + } /// Schedules the continuation action for the . - public void UnsafeOnCompleted(Action continuation) => - _value.AsTask().ConfigureAwait(_continueOnCapturedContext).GetAwaiter().UnsafeOnCompleted(continuation); + public void UnsafeOnCompleted(Action continuation) + { + if (_value.ObjectIsTask) + { + _value.UnsafeGetTask().ConfigureAwait(_value.ContinueOnCapturedContext).GetAwaiter().UnsafeOnCompleted(continuation); + } + else if (_value._obj != null) + { + _value.UnsafeGetValueTaskSource().OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, + _value.ContinueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None); + } + else + { + ValueTask.CompletedTask.ConfigureAwait(_value.ContinueOnCapturedContext).GetAwaiter().UnsafeOnCompleted(continuation); + } + } - /// Gets the task underlying . - internal Task AsTask() => _value.AsTask(); - - /// Gets the task underlying the incomplete . - /// This method is used when awaiting and IsCompleted returned false; thus we expect the value task to be wrapping a non-null task. - (Task task, bool continueOnCapturedContext) IConfiguredValueTaskAwaiter.GetTask() => (_value.AsTaskExpectNonNull(), _continueOnCapturedContext); +#if CORECLR + void IValueTaskAwaiter.AwaitUnsafeOnCompleted(IAsyncStateMachineBox box) + { + if (_value.ObjectIsTask) + { + TaskAwaiter.UnsafeOnCompletedInternal(_value.UnsafeGetTask(), box, _value.ContinueOnCapturedContext); + } + else if (_value._obj != null) + { + _value.UnsafeGetValueTaskSource().OnCompleted(ValueTaskAwaiter.s_invokeAsyncStateMachineBox, box, _value._token, + _value.ContinueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None); + } + else + { + TaskAwaiter.UnsafeOnCompletedInternal(Task.CompletedTask, box, _value.ContinueOnCapturedContext); + } + } +#endif } } - - /// - /// Internal interface used to enable extract the Task from arbitrary configured ValueTask awaiters. - /// - internal interface IConfiguredValueTaskAwaiter - { - (Task task, bool continueOnCapturedContext) GetTask(); - } -} +} \ No newline at end of file diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/IntrinsicAttribute.cs b/external/corert/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/IntrinsicAttribute.cs index 381b4c63f7..6bdd91d844 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/IntrinsicAttribute.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/IntrinsicAttribute.cs @@ -6,8 +6,8 @@ namespace System.Runtime.CompilerServices { // Calls to methods or references to fields marked with this attribute may be replaced at // some call sites with jit intrinsic expansions. - // Types marked with this attribute may be specially treated by the rumtime/compiler. - [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Field, Inherited = false)] + // Types marked with this attribute may be specially treated by the runtime/compiler. + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Field, Inherited = false)] internal sealed class IntrinsicAttribute : Attribute { } diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/TypeForwardedFromAttribute.cs b/external/corert/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/TypeForwardedFromAttribute.cs index c4a8558243..27dd645755 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/TypeForwardedFromAttribute.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/TypeForwardedFromAttribute.cs @@ -9,6 +9,9 @@ namespace System.Runtime.CompilerServices { public TypeForwardedFromAttribute(string assemblyFullName) { + if (string.IsNullOrEmpty(assemblyFullName)) + throw new ArgumentNullException(nameof(assemblyFullName)); + AssemblyFullName = assemblyFullName; } diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ValueTaskAwaiter.cs b/external/corert/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ValueTaskAwaiter.cs index 7bc8b5cc7d..221a1a437d 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ValueTaskAwaiter.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ValueTaskAwaiter.cs @@ -4,50 +4,198 @@ using System.Diagnostics; using System.Threading.Tasks; +using System.Threading.Tasks.Sources; namespace System.Runtime.CompilerServices { - /// Provides an awaiter for a . - public struct ValueTaskAwaiter : ICriticalNotifyCompletion, IValueTaskAwaiter + /// Provides an awaiter for a . + public readonly struct ValueTaskAwaiter : ICriticalNotifyCompletion +#if CORECLR + , IValueTaskAwaiter +#endif { + /// Shim used to invoke an passed as the state argument to a . + internal static readonly Action s_invokeActionDelegate = state => + { + if (!(state is Action action)) + { + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.state); + return; + } + + action(); + }; /// The value being awaited. - private ValueTask _value; // Methods are called on this; avoid making it readonly so as to avoid unnecessary copies + private readonly ValueTask _value; /// Initializes the awaiter. /// The value to be awaited. - internal ValueTaskAwaiter(ValueTask value) => _value = value; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal ValueTaskAwaiter(ValueTask value) => _value = value; - /// Gets whether the has completed. - public bool IsCompleted => _value.IsCompleted; + /// Gets whether the has completed. + public bool IsCompleted + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _value.IsCompleted; + } /// Gets the result of the ValueTask. [StackTraceHidden] - public TResult GetResult() => - _value._task == null ? - _value._result : - _value._task.GetAwaiter().GetResult(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void GetResult() => _value.ThrowIfCompletedUnsuccessfully(); /// Schedules the continuation action for this ValueTask. - public void OnCompleted(Action continuation) => - _value.AsTask().ConfigureAwait(continueOnCapturedContext: true).GetAwaiter().OnCompleted(continuation); + public void OnCompleted(Action continuation) + { + if (_value.ObjectIsTask) + { + _value.UnsafeGetTask().GetAwaiter().OnCompleted(continuation); + } + else if (_value._obj != null) + { + _value.UnsafeGetValueTaskSource().OnCompleted(s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext | ValueTaskSourceOnCompletedFlags.FlowExecutionContext); + } + else + { + ValueTask.CompletedTask.GetAwaiter().OnCompleted(continuation); + } + } /// Schedules the continuation action for this ValueTask. - public void UnsafeOnCompleted(Action continuation) => - _value.AsTask().ConfigureAwait(continueOnCapturedContext: true).GetAwaiter().UnsafeOnCompleted(continuation); + public void UnsafeOnCompleted(Action continuation) + { + if (_value.ObjectIsTask) + { + _value.UnsafeGetTask().GetAwaiter().UnsafeOnCompleted(continuation); + } + else if (_value._obj != null) + { + _value.UnsafeGetValueTaskSource().OnCompleted(s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext); + } + else + { + ValueTask.CompletedTask.GetAwaiter().UnsafeOnCompleted(continuation); + } + } - /// Gets the task underlying . - internal Task AsTask() => _value.AsTask(); +#if CORECLR + void IValueTaskAwaiter.AwaitUnsafeOnCompleted(IAsyncStateMachineBox box) + { + if (_value.ObjectIsTask) + { + TaskAwaiter.UnsafeOnCompletedInternal(_value.UnsafeGetTask(), box, continueOnCapturedContext: true); + } + else if (_value._obj != null) + { + _value.UnsafeGetValueTaskSource().OnCompleted(s_invokeAsyncStateMachineBox, box, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext); + } + else + { + TaskAwaiter.UnsafeOnCompletedInternal(Task.CompletedTask, box, continueOnCapturedContext: true); + } + } - /// Gets the task underlying the incomplete . - /// This method is used when awaiting and IsCompleted returned false; thus we expect the value task to be wrapping a non-null task. - Task IValueTaskAwaiter.GetTask() => _value.AsTaskExpectNonNull(); + /// Shim used to invoke of the supplied . + internal static readonly Action s_invokeAsyncStateMachineBox = state => + { + if (!(state is IAsyncStateMachineBox box)) + { + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.state); + return; + } + + box.Invoke(null); + }; +#endif } - /// - /// Internal interface used to enable extract the Task from arbitrary ValueTask awaiters. - /// > + /// Provides an awaiter for a . + public readonly struct ValueTaskAwaiter : ICriticalNotifyCompletion +#if CORECLR + , IValueTaskAwaiter +#endif + { + /// The value being awaited. + private readonly ValueTask _value; + + /// Initializes the awaiter. + /// The value to be awaited. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal ValueTaskAwaiter(ValueTask value) => _value = value; + + /// Gets whether the has completed. + public bool IsCompleted + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _value.IsCompleted; + } + + /// Gets the result of the ValueTask. + [StackTraceHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public TResult GetResult() => _value.Result; + + /// Schedules the continuation action for this ValueTask. + public void OnCompleted(Action continuation) + { + if (_value.ObjectIsTask) + { + _value.UnsafeGetTask().GetAwaiter().OnCompleted(continuation); + } + else if (_value._obj != null) + { + _value.UnsafeGetValueTaskSource().OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext | ValueTaskSourceOnCompletedFlags.FlowExecutionContext); + } + else + { + ValueTask.CompletedTask.GetAwaiter().OnCompleted(continuation); + } + } + + /// Schedules the continuation action for this ValueTask. + public void UnsafeOnCompleted(Action continuation) + { + if (_value.ObjectIsTask) + { + _value.UnsafeGetTask().GetAwaiter().UnsafeOnCompleted(continuation); + } + else if (_value._obj != null) + { + _value.UnsafeGetValueTaskSource().OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext); + } + else + { + ValueTask.CompletedTask.GetAwaiter().UnsafeOnCompleted(continuation); + } + } + +#if CORECLR + void IValueTaskAwaiter.AwaitUnsafeOnCompleted(IAsyncStateMachineBox box) + { + if (_value.ObjectIsTask) + { + TaskAwaiter.UnsafeOnCompletedInternal(_value.UnsafeGetTask(), box, continueOnCapturedContext: true); + } + else if (_value._obj != null) + { + _value.UnsafeGetValueTaskSource().OnCompleted(ValueTaskAwaiter.s_invokeAsyncStateMachineBox, box, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext); + } + else + { + TaskAwaiter.UnsafeOnCompletedInternal(Task.CompletedTask, box, continueOnCapturedContext: true); + } + } +#endif + } + +#if CORECLR + /// Internal interface used to enable optimizations from on .> internal interface IValueTaskAwaiter { - Task GetTask(); + /// Invoked to set of the as the awaiter's continuation. + /// The box object. + void AwaitUnsafeOnCompleted(IAsyncStateMachineBox box); } -} +#endif +} \ No newline at end of file diff --git a/external/corert/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/YieldAwaitable.cs b/external/corert/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/YieldAwaitable.cs similarity index 69% rename from external/corert/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/YieldAwaitable.cs rename to external/corert/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/YieldAwaitable.cs index bcd1f616bb..c45ef2484c 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/YieldAwaitable.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/YieldAwaitable.cs @@ -5,7 +5,6 @@ // =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ // // - // // Compiler-targeted type for switching back into the current execution context, e.g. // @@ -25,6 +24,7 @@ using System; using System.Security; using System.Diagnostics; +using System.Diagnostics.Tracing; using System.Threading; using System.Threading.Tasks; @@ -46,7 +46,7 @@ namespace System.Runtime.CompilerServices /// Provides an awaiter that switches into a target environment. /// This type is intended for compiler use only. - public struct YieldAwaiter : ICriticalNotifyCompletion + public readonly struct YieldAwaiter : ICriticalNotifyCompletion { /// Gets whether a yield is not required. /// This property is intended for compiler user rather than use directly in code. @@ -57,7 +57,7 @@ namespace System.Runtime.CompilerServices /// The argument is null (Nothing in Visual Basic). public void OnCompleted(Action continuation) { - QueueContinuation(continuation); + QueueContinuation(continuation, flowContext: true); } /// Posts the back to the current context. @@ -65,17 +65,22 @@ namespace System.Runtime.CompilerServices /// The argument is null (Nothing in Visual Basic). public void UnsafeOnCompleted(Action continuation) { - QueueContinuation(continuation); + QueueContinuation(continuation, flowContext: false); } /// Posts the back to the current context. /// The action to invoke asynchronously. + /// true to flow ExecutionContext; false if flowing is not required. /// The argument is null (Nothing in Visual Basic). - private static void QueueContinuation(Action continuation) + private static void QueueContinuation(Action continuation, bool flowContext) { // Validate arguments if (continuation == null) throw new ArgumentNullException(nameof(continuation)); + if (TplEtwProvider.Log.IsEnabled()) + { + continuation = OutputCorrelationEtwEvent(continuation); + } // Get the current SynchronizationContext, and if there is one, // post the continuation to it. However, treat the base type // as if there wasn't a SynchronizationContext, since that's what it @@ -93,7 +98,14 @@ namespace System.Runtime.CompilerServices TaskScheduler scheduler = TaskScheduler.Current; if (scheduler == TaskScheduler.Default) { - ThreadPool.UnsafeQueueUserWorkItem(s_waitCallbackRunAction, continuation); + if (flowContext) + { + ThreadPool.QueueUserWorkItem(s_waitCallbackRunAction, continuation); + } + else + { + ThreadPool.UnsafeQueueUserWorkItem(s_waitCallbackRunAction, continuation); + } } // We're targeting a custom scheduler, so queue a task. else @@ -103,6 +115,40 @@ namespace System.Runtime.CompilerServices } } + private static Action OutputCorrelationEtwEvent(Action continuation) + { +#if CORERT + // TODO + return continuation; +#else + int continuationId = Task.NewId(); + Task currentTask = Task.InternalCurrent; + // fire the correlation ETW event + TplEtwProvider.Log.AwaitTaskContinuationScheduled(TaskScheduler.Current.Id, (currentTask != null) ? currentTask.Id : 0, continuationId); + + return AsyncMethodBuilderCore.CreateContinuationWrapper(continuation, (innerContinuation,continuationIdTask) => + { + var etwLog = TplEtwProvider.Log; + etwLog.TaskWaitContinuationStarted(((Task)continuationIdTask).Result); + + // ETW event for Task Wait End. + Guid prevActivityId = new Guid(); + // Ensure the continuation runs under the correlated activity ID generated above + if (etwLog.TasksSetActivityIds) + EventSource.SetCurrentThreadActivityId(TplEtwProvider.CreateGuidForTaskID(((Task)continuationIdTask).Result), out prevActivityId); + + // Invoke the original continuation provided to OnCompleted. + innerContinuation(); + // Restore activity ID + + if (etwLog.TasksSetActivityIds) + EventSource.SetCurrentThreadActivityId(prevActivityId); + + etwLog.TaskWaitContinuationComplete(((Task)continuationIdTask).Result); + }, Task.FromResult(continuationId)); // pass the ID in a task to avoid a closure\ +#endif + } + /// WaitCallback that invokes the Action supplied as object state. private static readonly WaitCallback s_waitCallbackRunAction = RunAction; /// SendOrPostCallback that invokes the Action supplied as object state. diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/MemoryMarshal.Fast.cs b/external/corert/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/MemoryMarshal.Fast.cs new file mode 100644 index 0000000000..8a5bb75394 --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/MemoryMarshal.Fast.cs @@ -0,0 +1,170 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Buffers; +using System.Runtime.CompilerServices; +using System.Collections.Generic; +using Internal.Runtime.CompilerServices; + +namespace System.Runtime.InteropServices +{ + /// + /// Provides a collection of methods for interoperating with , , + /// , and . + /// + public static partial class MemoryMarshal + { + /// Creates a from a . + /// The . + /// A representing the same memory as the , but writable. + /// + /// must be used with extreme caution. is used + /// to represent immutable data and other memory that is not meant to be written to; instances created + /// by should not be written to. The method exists to enable variables typed + /// as but only used for reading to store a . + /// + public static Memory AsMemory(ReadOnlyMemory readOnlyMemory) => + Unsafe.As, Memory>(ref readOnlyMemory); + + /// + /// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to the location where the 0th element + /// would have been stored. Such a reference can be used for pinning but must never be dereferenced. + /// + public static ref T GetReference(Span span) => ref span._pointer.Value; + + /// + /// Returns a reference to the 0th element of the ReadOnlySpan. If the Span is empty, returns a reference to the location where the 0th element + /// would have been stored. Such a reference can be used for pinning but must never be dereferenced. + /// + public static ref T GetReference(ReadOnlySpan span) => ref span._pointer.Value; + + /// + /// Casts a Span of one primitive type to another primitive type . + /// These types may not contain pointers or references. This is checked at runtime in order to preserve type safety. + /// + /// + /// Supported only for platforms that support misaligned memory access. + /// + /// The source slice, of type . + /// + /// Thrown when or contains pointers. + /// + public static Span Cast(Span source) + where TFrom : struct + where TTo : struct + { + if (RuntimeHelpers.IsReferenceOrContainsReferences()) + ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TFrom)); + if (RuntimeHelpers.IsReferenceOrContainsReferences()) + ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TTo)); + + // Use unsigned integers - unsigned division by constant (especially by power of 2) + // and checked casts are faster and smaller. + uint fromSize = (uint)Unsafe.SizeOf(); + uint toSize = (uint)Unsafe.SizeOf(); + uint fromLength = (uint)source.Length; + int toLength; + if (fromSize == toSize) + { + // Special case for same size types - `(ulong)fromLength * (ulong)fromSize / (ulong)toSize` + // should be optimized to just `length` but the JIT doesn't do that today. + toLength = (int)fromLength; + } + else if (fromSize == 1) + { + // Special case for byte sized TFrom - `(ulong)fromLength * (ulong)fromSize / (ulong)toSize` + // becomes `(ulong)fromLength / (ulong)toSize` but the JIT can't narrow it down to `int` + // and can't eliminate the checked cast. This also avoids a 32 bit specific issue, + // the JIT can't eliminate long multiply by 1. + toLength = (int)(fromLength / toSize); + } + else + { + // Ensure that casts are done in such a way that the JIT is able to "see" + // the uint->ulong casts and the multiply together so that on 32 bit targets + // 32x32to64 multiplication is used. + ulong toLengthUInt64 = (ulong)fromLength * (ulong)fromSize / (ulong)toSize; + toLength = checked((int)toLengthUInt64); + } + + return new Span( + ref Unsafe.As(ref source._pointer.Value), + toLength); + } + + /// + /// Casts a ReadOnlySpan of one primitive type to another primitive type . + /// These types may not contain pointers or references. This is checked at runtime in order to preserve type safety. + /// + /// + /// Supported only for platforms that support misaligned memory access. + /// + /// The source slice, of type . + /// + /// Thrown when or contains pointers. + /// + public static ReadOnlySpan Cast(ReadOnlySpan source) + where TFrom : struct + where TTo : struct + { + if (RuntimeHelpers.IsReferenceOrContainsReferences()) + ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TFrom)); + if (RuntimeHelpers.IsReferenceOrContainsReferences()) + ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TTo)); + + // Use unsigned integers - unsigned division by constant (especially by power of 2) + // and checked casts are faster and smaller. + uint fromSize = (uint)Unsafe.SizeOf(); + uint toSize = (uint)Unsafe.SizeOf(); + uint fromLength = (uint)source.Length; + int toLength; + if (fromSize == toSize) + { + // Special case for same size types - `(ulong)fromLength * (ulong)fromSize / (ulong)toSize` + // should be optimized to just `length` but the JIT doesn't do that today. + toLength = (int)fromLength; + } + else if (fromSize == 1) + { + // Special case for byte sized TFrom - `(ulong)fromLength * (ulong)fromSize / (ulong)toSize` + // becomes `(ulong)fromLength / (ulong)toSize` but the JIT can't narrow it down to `int` + // and can't eliminate the checked cast. This also avoids a 32 bit specific issue, + // the JIT can't eliminate long multiply by 1. + toLength = (int)(fromLength / toSize); + } + else + { + // Ensure that casts are done in such a way that the JIT is able to "see" + // the uint->ulong casts and the multiply together so that on 32 bit targets + // 32x32to64 multiplication is used. + ulong toLengthUInt64 = (ulong)fromLength * (ulong)fromSize / (ulong)toSize; + toLength = checked((int)toLengthUInt64); + } + + return new ReadOnlySpan( + ref Unsafe.As(ref MemoryMarshal.GetReference(source)), + toLength); + } + + /// + /// Create a new span over a portion of a regular managed object. This can be useful + /// if part of a managed object represents a "fixed array." This is dangerous because the + /// is not checked. + /// + /// A reference to data. + /// The number of elements the memory contains. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Span CreateSpan(ref T reference, int length) => new Span(ref reference, length); + + /// + /// Create a new read-only span over a portion of a regular managed object. This can be useful + /// if part of a managed object represents a "fixed array." This is dangerous because the + /// is not checked. + /// + /// A reference to data. + /// The number of elements the memory contains. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ReadOnlySpan CreateReadOnlySpan(ref T reference, int length) => new ReadOnlySpan(ref reference, length); + } +} diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/MemoryMarshal.cs b/external/corert/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/MemoryMarshal.cs index 2651df53a0..316ce12aab 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/MemoryMarshal.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/MemoryMarshal.cs @@ -4,7 +4,7 @@ using System.Buffers; using System.Runtime.CompilerServices; -using Internal.Runtime.CompilerServices; +using System.Collections.Generic; namespace System.Runtime.InteropServices { @@ -12,24 +12,12 @@ namespace System.Runtime.InteropServices /// Provides a collection of methods for interoperating with , , /// , and . /// - public static class MemoryMarshal + public static partial class MemoryMarshal { - /// Creates a from a . - /// The . - /// A representing the same memory as the , but writable. - /// - /// must be used with extreme caution. is used - /// to represent immutable data and other memory that is not meant to be written to; instances created - /// by should not be written to. The method exists to enable variables typed - /// as but only used for reading to store a . - /// - public static Memory AsMemory(ReadOnlyMemory readOnlyMemory) => - Unsafe.As, Memory>(ref readOnlyMemory); - - public static ref T GetReference(Span span) => ref span._pointer.Value; - - public static ref T GetReference(ReadOnlySpan span) => ref span._pointer.Value; - + /// + /// Get an array segment from the underlying memory. + /// If unable to get the array segment, return false with a default array segment. + /// public static bool TryGetArray(ReadOnlyMemory readOnlyMemory, out ArraySegment arraySegment) { object obj = readOnlyMemory.GetObjectStartLength(out int index, out int length); @@ -47,8 +35,92 @@ namespace System.Runtime.InteropServices return true; } + if (length == 0) + { +#if FEATURE_PORTABLE_SPAN + arraySegment = new ArraySegment(SpanHelpers.PerTypeValues.EmptyArray); +#else + arraySegment = ArraySegment.Empty; +#endif // FEATURE_PORTABLE_SPAN + return true; + } + arraySegment = default; return false; } + + /// + /// Gets an from the underlying readOnlyMemory. + /// If unable to get the type, returns false. + /// + /// The element type of the . + /// The type of to try and retrive. + /// The memory to get the owner for. + /// The returned owner of the . + /// A indicating if it was successful. + public static bool TryGetOwnedMemory(ReadOnlyMemory readOnlyMemory, out TOwner ownedMemory) + where TOwner : OwnedMemory + { + TOwner owner; // Use register for null comparison rather than byref + ownedMemory = owner = readOnlyMemory.GetObjectStartLength(out int index, out int length) as TOwner; + return !ReferenceEquals(owner, null); + } + + /// + /// Gets an and , from the underlying memory. + /// If unable to get the type, returns false. + /// + /// The element type of the . + /// The type of to try and retrive. + /// The memory to get the owner for. + /// The returned owner of the . + /// The offset from the start of the that the represents. + /// The length of the that the represents. + /// A indicating if it was successful. + public static bool TryGetOwnedMemory(ReadOnlyMemory readOnlyMemory, out TOwner ownedMemory, out int index, out int length) + where TOwner : OwnedMemory + { + TOwner owner; // Use register for null comparison rather than byref + ownedMemory = owner = readOnlyMemory.GetObjectStartLength(out index, out length) as TOwner; + index &= ReadOnlyMemory.RemoveOwnedFlagBitMask; + return !ReferenceEquals(owner, null); + } + + /// + /// Creates an view of the given to allow + /// the to be used in existing APIs that take an . + /// + /// The element type of the . + /// The ReadOnlyMemory to view as an + /// An view of the given + public static IEnumerable ToEnumerable(ReadOnlyMemory memory) + { + for (int i = 0; i < memory.Length; i++) + yield return memory.Span[i]; + } + + /// Attempts to get the underlying from a . + /// The memory that may be wrapping a object. + /// The string. + /// The starting location in . + /// The number of items in . + /// + public static bool TryGetString(ReadOnlyMemory readOnlyMemory, out string text, out int start, out int length) + { + if (readOnlyMemory.GetObjectStartLength(out int offset, out int count) is string s) + { + text = s; + start = offset; + length = count; + return true; + } + else + { + text = null; + start = 0; + length = 0; + return false; + } + } } } diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/StringBuffer.cs b/external/corert/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/StringBuffer.cs deleted file mode 100644 index fdd0b95590..0000000000 --- a/external/corert/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/StringBuffer.cs +++ /dev/null @@ -1,301 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Buffers; -using System.Runtime.CompilerServices; - -namespace System.Runtime.InteropServices -{ - /// - /// Buffer that deals in char size increments. Dispose to free memory. Always makes ordinal - /// comparisons. Not thread safe. - /// - /// A more performant replacement for StringBuilder when performing native interop. - /// - /// "No copy" valuetype. Has to be passed as "ref". - /// - /// - /// - /// Suggested use through P/Invoke: define DllImport arguments that take a character buffer as SafeHandle and pass StringBuffer.GetHandle(). - /// - internal struct StringBuffer - { - private char[] _buffer; - private int _length; - - /// - /// Instantiate the buffer with capacity for at least the specified number of characters. Capacity - /// includes the trailing null character. - /// - public StringBuffer(int initialCapacity) - { - _buffer = ArrayPool.Shared.Rent(initialCapacity); - _length = 0; - } - - /// - /// Get/set the character at the given index. - /// - /// Thrown if attempting to index outside of the buffer length. - public char this[int index] - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - if (index >= _length) throw new ArgumentOutOfRangeException(nameof(index)); - return _buffer[index]; - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - set - { - if (index >= _length) throw new ArgumentOutOfRangeException(nameof(index)); - _buffer[index] = value; - } - } - - /// - /// Underlying storage of the buffer. Used for interop. - /// - public char[] UnderlyingArray => _buffer; - - /// - /// Character capacity of the buffer. Includes the count for the trailing null character. - /// - public int Capacity => _buffer.Length; - - /// - /// Ensure capacity in characters is at least the given minimum. - /// - /// Thrown if unable to allocate memory when setting. - public void EnsureCapacity(int minCapacity) - { - if (minCapacity > Capacity) - { - char[] oldBuffer = _buffer; - _buffer = ArrayPool.Shared.Rent(minCapacity); - Array.Copy(oldBuffer, 0, _buffer, 0, oldBuffer.Length); - ArrayPool.Shared.Return(oldBuffer); - } - } - - /// - /// The logical length of the buffer in characters. (Does not include the final null.) Will automatically attempt to increase capacity. - /// This is where the usable data ends. - /// - /// Thrown if unable to allocate memory when setting. - /// Thrown if the set size in bytes is int.MaxValue (as space is implicitly reserved for the trailing null). - public int Length - { - get { return _length; } - set - { - // Null terminate - EnsureCapacity(checked(value + 1)); - _buffer[value] = '\0'; - - _length = value; - } - } - - /// - /// True if the buffer contains the given character. - /// - public unsafe bool Contains(char value) - { - fixed (char* start = _buffer) - { - int length = _length; - for (int i = 0; i < length; i++) - { - if (start[i] == value) return true; - } - } - - return false; - } - - /// - /// Returns true if the buffer starts with the given string. - /// - public bool StartsWith(string value) - { - if (value == null) throw new ArgumentNullException(nameof(value)); - if (_length < value.Length) return false; - return SubstringEquals(value, startIndex: 0, count: value.Length); - } - - /// - /// Returns true if the specified StringBuffer substring equals the given value. - /// - /// The value to compare against the specified substring. - /// Start index of the sub string. - /// Length of the substring, or -1 to check all remaining. - /// - /// Thrown if or are outside the range - /// of the buffer's length. - /// - public unsafe bool SubstringEquals(string value, int startIndex = 0, int count = -1) - { - if (value == null) return false; - if (count < -1) throw new ArgumentOutOfRangeException(nameof(count)); - if (startIndex > _length) throw new ArgumentOutOfRangeException(nameof(startIndex)); - - int realCount = count == -1 ? _length - startIndex : (int)count; - if (checked(startIndex + realCount) > _length) throw new ArgumentOutOfRangeException(nameof(count)); - - int length = value.Length; - - // Check the substring length against the input length - if (realCount != length) return false; - - fixed (char* valueStart = value) - fixed (char* bufferStart = _buffer) - { - char* subStringStart = bufferStart + startIndex; - - for (int i = 0; i < length; i++) - { - if (subStringStart[i] != valueStart[i]) return false; - } - } - - return true; - } - - /// - /// Append the given buffer. - /// - /// The buffer to append. - /// The index in the input buffer to start appending from. - /// The count of characters to copy from the buffer string. - /// Thrown if is null. - /// - /// Thrown if or are outside the range - /// of characters. - /// - public void Append(ref StringBuffer value, int startIndex = 0) - { - if (value.Length == 0) return; - - value.CopyTo( - bufferIndex: startIndex, - destination: ref this, - destinationIndex: _length, - count: value.Length); - } - - /// - /// Append the given buffer. - /// - /// The buffer to append. - /// The index in the input buffer to start appending from. - /// The count of characters to copy from the buffer string. - /// Thrown if is null. - /// - /// Thrown if or are outside the range - /// of characters. - /// - public void Append(ref StringBuffer value, int startIndex, int count) - { - if (count == 0) return; - - value.CopyTo( - bufferIndex: startIndex, - destination: ref this, - destinationIndex: _length, - count: count); - } - - /// - /// Copy contents to the specified buffer. Destination index must be within current destination length. - /// Will grow the destination buffer if needed. - /// - /// - /// Thrown if or or are outside the range - /// of characters. - /// - /// Thrown if is null. - public void CopyTo(int bufferIndex, ref StringBuffer destination, int destinationIndex, int count) - { - if (destinationIndex > destination._length) throw new ArgumentOutOfRangeException(nameof(destinationIndex)); - if (bufferIndex >= _length) throw new ArgumentOutOfRangeException(nameof(bufferIndex)); - if (_length < checked(bufferIndex + count)) throw new ArgumentOutOfRangeException(nameof(count)); - - if (count == 0) return; - int lastIndex = checked(destinationIndex + count); - if (destination.Length < lastIndex) destination.Length = lastIndex; - - Array.Copy(UnderlyingArray, bufferIndex, destination.UnderlyingArray, destinationIndex, count); - } - - /// - /// Copy contents from the specified string into the buffer at the given index. Start index must be within the current length of - /// the buffer, will grow as necessary. - /// - public void CopyFrom(int bufferIndex, string source, int sourceIndex = 0, int count = -1) - { - if (source == null) throw new ArgumentNullException(nameof(source)); - if (bufferIndex > _length) throw new ArgumentOutOfRangeException(nameof(bufferIndex)); - if (sourceIndex < 0 || sourceIndex > source.Length) throw new ArgumentOutOfRangeException(nameof(sourceIndex)); - if (count == -1) count = source.Length - sourceIndex; - if (count < 0 || source.Length - count < sourceIndex) throw new ArgumentOutOfRangeException(nameof(count)); - - if (count == 0) return; - int lastIndex = bufferIndex + (int)count; - if (_length < lastIndex) Length = lastIndex; - - source.CopyTo(sourceIndex, UnderlyingArray, bufferIndex, count); - } - - /// - /// Trim the specified values from the end of the buffer. If nothing is specified, nothing is trimmed. - /// - public void TrimEnd(char[] values) - { - if (values == null || values.Length == 0 || _length == 0) return; - - while (_length > 0 && Array.IndexOf(values, _buffer[_length - 1]) >= 0) - { - Length = _length - 1; - } - } - - /// - /// String representation of the entire buffer. If the buffer is larger than the maximum size string (int.MaxValue) this will throw. - /// - /// Thrown if the buffer is too big to fit into a string. - public override string ToString() - { - return new string(_buffer, startIndex: 0, length: _length); - } - - /// - /// Get the given substring in the buffer. - /// - /// Count of characters to take, or remaining characters from if -1. - /// - /// Thrown if or are outside the range of the buffer's length - /// or count is greater than the maximum string size (int.MaxValue). - /// - public string Substring(int startIndex, int count = -1) - { - if (startIndex > (_length == 0 ? 0 : _length - 1)) throw new ArgumentOutOfRangeException(nameof(startIndex)); - if (count < -1) throw new ArgumentOutOfRangeException(nameof(count)); - - int realCount = count == -1 ? _length - startIndex : (int)count; - if (realCount > int.MaxValue || checked(startIndex + realCount) > _length) throw new ArgumentOutOfRangeException(nameof(count)); - - // The buffer could be bigger than will fit into a string, but the substring might fit. As the starting - // index might be bigger than int we need to index ourselves. - return new string(_buffer, startIndex: startIndex, length: realCount); - } - - public void Free() - { - ArrayPool.Shared.Return(_buffer); - _buffer = null; - _length = 0; - } - } -} diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Security/SecureString.cs b/external/corert/src/System.Private.CoreLib/shared/System/Security/SecureString.cs index 9059f90e60..22f15accaa 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Security/SecureString.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Security/SecureString.cs @@ -2,9 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Diagnostics; using System.Runtime.InteropServices; +using System.Threading; namespace System.Security { @@ -43,11 +43,8 @@ namespace System.Security { get { - lock (_methodLock) - { - EnsureNotDisposed(); - return _decryptedLength; - } + EnsureNotDisposed(); + return Volatile.Read(ref _decryptedLength); } } @@ -108,20 +105,14 @@ namespace System.Security public bool IsReadOnly() { - lock (_methodLock) - { - EnsureNotDisposed(); - return _readOnly; - } + EnsureNotDisposed(); + return Volatile.Read(ref _readOnly); } public void MakeReadOnly() { - lock (_methodLock) - { - EnsureNotDisposed(); - _readOnly = true; - } + EnsureNotDisposed(); + Volatile.Write(ref _readOnly, true); } public void RemoveAt(int index) diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Single.cs b/external/corert/src/System.Private.CoreLib/shared/System/Single.cs index df97427d38..7bffa1ac77 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Single.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Single.cs @@ -16,6 +16,8 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; +using Internal.Runtime.CompilerServices; + namespace System { [Serializable] @@ -213,16 +215,18 @@ namespace System return IsNaN(obj) && IsNaN(m_value); } - public unsafe override int GetHashCode() + public override int GetHashCode() { - float f = m_value; - if (f == 0) + var bits = Unsafe.As(ref m_value); + + // Optimized check for IsNan() || IsZero() + if (((bits - 1) & 0x7FFFFFFF) >= 0x7F800000) { - // Ensure that 0 and -0 have the same hash code - return 0; + // Ensure that all NaNs and both zeros have the same hash code + bits &= 0x7F800000; } - int v = *(int*)(&f); - return v; + + return bits; } public override String ToString() diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Span.Fast.cs b/external/corert/src/System.Private.CoreLib/shared/System/Span.Fast.cs new file mode 100644 index 0000000000..0ae1922fd4 --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/shared/System/Span.Fast.cs @@ -0,0 +1,350 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.ComponentModel; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.Versioning; +using Internal.Runtime.CompilerServices; + +#pragma warning disable 0809 //warning CS0809: Obsolete member 'Span.Equals(object)' overrides non-obsolete member 'object.Equals(object)' + +#if BIT64 +using nuint = System.UInt64; +#else +using nuint = System.UInt32; +#endif + +namespace System +{ + /// + /// Span represents a contiguous region of arbitrary memory. Unlike arrays, it can point to either managed + /// or native memory, or to memory allocated on the stack. It is type- and memory-safe. + /// + [DebuggerTypeProxy(typeof(SpanDebugView<>))] + [DebuggerDisplay("{ToString(),raw}")] + [NonVersionable] + public readonly ref partial struct Span + { + /// A byref or a native ptr. + internal readonly ByReference _pointer; + /// The number of elements this Span contains. +#if PROJECTN + [Bound] +#endif + private readonly int _length; + + /// + /// Creates a new span over the entirety of the target array. + /// + /// The target array. + /// Returns default when is null. + /// reference (Nothing in Visual Basic). + /// Thrown when is covariant and array's type is not exactly T[]. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span(T[] array) + { + if (array == null) + { + this = default; + return; // returns default + } + if (default(T) == null && array.GetType() != typeof(T[])) + ThrowHelper.ThrowArrayTypeMismatchException(); + + _pointer = new ByReference(ref Unsafe.As(ref array.GetRawSzArrayData())); + _length = array.Length; + } + + /// + /// Creates a new span over the portion of the target array beginning + /// at 'start' index and ending at 'end' index (exclusive). + /// + /// The target array. + /// The index at which to begin the span. + /// The number of items in the span. + /// Returns default when is null. + /// reference (Nothing in Visual Basic). + /// Thrown when is covariant and array's type is not exactly T[]. + /// + /// Thrown when the specified or end index is not in the range (<0 or >=Length). + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span(T[] array, int start, int length) + { + if (array == null) + { + if (start != 0 || length != 0) + ThrowHelper.ThrowArgumentOutOfRangeException(); + this = default; + return; // returns default + } + if (default(T) == null && array.GetType() != typeof(T[])) + ThrowHelper.ThrowArrayTypeMismatchException(); + if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start)) + ThrowHelper.ThrowArgumentOutOfRangeException(); + + _pointer = new ByReference(ref Unsafe.Add(ref Unsafe.As(ref array.GetRawSzArrayData()), start)); + _length = length; + } + + /// + /// Creates a new span over the target unmanaged buffer. Clearly this + /// is quite dangerous, because we are creating arbitrarily typed T's + /// out of a void*-typed block of memory. And the length is not checked. + /// But if this creation is correct, then all subsequent uses are correct. + /// + /// An unmanaged pointer to memory. + /// The number of elements the memory contains. + /// + /// Thrown when is reference type or contains pointers and hence cannot be stored in unmanaged memory. + /// + /// + /// Thrown when the specified is negative. + /// + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public unsafe Span(void* pointer, int length) + { + if (RuntimeHelpers.IsReferenceOrContainsReferences()) + ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T)); + if (length < 0) + ThrowHelper.ThrowArgumentOutOfRangeException(); + + _pointer = new ByReference(ref Unsafe.As(ref *(byte*)pointer)); + _length = length; + } + + // Constructor for internal use only. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Span(ref T ptr, int length) + { + Debug.Assert(length >= 0); + + _pointer = new ByReference(ref ptr); + _length = length; + } + + /// Returns a reference to specified element of the Span. + /// + /// + /// + /// + /// Thrown when index less than 0 or index greater than or equal to Length + /// + public ref T this[int index] + { +#if PROJECTN + [BoundsChecking] + get + { + return ref Unsafe.Add(ref _pointer.Value, index); + } +#else + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [NonVersionable] + get + { + if ((uint)index >= (uint)_length) + ThrowHelper.ThrowIndexOutOfRangeException(); + return ref Unsafe.Add(ref _pointer.Value, index); + } +#endif + } + + /// + /// Clears the contents of this span. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() + { + if (RuntimeHelpers.IsReferenceOrContainsReferences()) + { + SpanHelpers.ClearWithReferences(ref Unsafe.As(ref _pointer.Value), (nuint)_length * (nuint)(Unsafe.SizeOf() / sizeof(nuint))); + } + else + { + SpanHelpers.ClearWithoutReferences(ref Unsafe.As(ref _pointer.Value), (nuint)_length * (nuint)Unsafe.SizeOf()); + } + } + + /// + /// Fills the contents of this span with the given value. + /// + public void Fill(T value) + { + if (Unsafe.SizeOf() == 1) + { + uint length = (uint)_length; + if (length == 0) + return; + + T tmp = value; // Avoid taking address of the "value" argument. It would regress performance of the loop below. + Unsafe.InitBlockUnaligned(ref Unsafe.As(ref _pointer.Value), Unsafe.As(ref tmp), length); + } + else + { + // Do all math as nuint to avoid unnecessary 64->32->64 bit integer truncations + nuint length = (uint)_length; + if (length == 0) + return; + + ref T r = ref _pointer.Value; + + // TODO: Create block fill for value types of power of two sizes e.g. 2,4,8,16 + + nuint elementSize = (uint)Unsafe.SizeOf(); + nuint i = 0; + for (; i < (length & ~(nuint)7); i += 8) + { + Unsafe.AddByteOffset(ref r, (i + 0) * elementSize) = value; + Unsafe.AddByteOffset(ref r, (i + 1) * elementSize) = value; + Unsafe.AddByteOffset(ref r, (i + 2) * elementSize) = value; + Unsafe.AddByteOffset(ref r, (i + 3) * elementSize) = value; + Unsafe.AddByteOffset(ref r, (i + 4) * elementSize) = value; + Unsafe.AddByteOffset(ref r, (i + 5) * elementSize) = value; + Unsafe.AddByteOffset(ref r, (i + 6) * elementSize) = value; + Unsafe.AddByteOffset(ref r, (i + 7) * elementSize) = value; + } + if (i < (length & ~(nuint)3)) + { + Unsafe.AddByteOffset(ref r, (i + 0) * elementSize) = value; + Unsafe.AddByteOffset(ref r, (i + 1) * elementSize) = value; + Unsafe.AddByteOffset(ref r, (i + 2) * elementSize) = value; + Unsafe.AddByteOffset(ref r, (i + 3) * elementSize) = value; + i += 4; + } + for (; i < length; i++) + { + Unsafe.AddByteOffset(ref r, i * elementSize) = value; + } + } + } + + /// + /// Copies the contents of this span into destination span. If the source + /// and destinations overlap, this method behaves as if the original values in + /// a temporary location before the destination is overwritten. + /// + /// The span to copy items into. + /// + /// Thrown when the destination Span is shorter than the source Span. + /// + public void CopyTo(Span destination) + { + // Using "if (!TryCopyTo(...))" results in two branches: one for the length + // check, and one for the result of TryCopyTo. Since these checks are equivalent, + // we can optimize by performing the check once ourselves then calling Memmove directly. + + if ((uint)_length <= (uint)destination.Length) + { + Buffer.Memmove(ref destination._pointer.Value, ref _pointer.Value, (nuint)_length); + } + else + { + ThrowHelper.ThrowArgumentException_DestinationTooShort(); + } + } + + /// + /// Copies the contents of this span into destination span. If the source + /// and destinations overlap, this method behaves as if the original values in + /// a temporary location before the destination is overwritten. + /// + /// The span to copy items into. + /// If the destination span is shorter than the source span, this method + /// return false and no data is written to the destination. + public bool TryCopyTo(Span destination) + { + bool retVal = false; + if ((uint)_length <= (uint)destination.Length) + { + Buffer.Memmove(ref destination._pointer.Value, ref _pointer.Value, (nuint)_length); + retVal = true; + } + return retVal; + } + + /// + /// Returns true if left and right point at the same memory and have the same length. Note that + /// this does *not* check to see if the *contents* are equal. + /// + public static bool operator ==(Span left, Span right) + { + return left._length == right._length && Unsafe.AreSame(ref left._pointer.Value, ref right._pointer.Value); + } + + /// + /// Defines an implicit conversion of a to a + /// + public static implicit operator ReadOnlySpan(Span span) => new ReadOnlySpan(ref span._pointer.Value, span._length); + + /// + /// For , returns a new instance of string that represents the characters pointed to by the span. + /// Otherwise, returns a with the name of the type and the number of elements. + /// + public override string ToString() + { + if (typeof(T) == typeof(char)) + { + unsafe + { + fixed (char* src = &Unsafe.As(ref _pointer.Value)) + return new string(src, 0, _length); + } + } + return string.Format("System.Span<{0}>[{1}]", typeof(T).Name, _length); + } + + /// + /// Forms a slice out of the given span, beginning at 'start'. + /// + /// The index at which to begin this slice. + /// + /// Thrown when the specified index is not in range (<0 or >=Length). + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span Slice(int start) + { + if ((uint)start > (uint)_length) + ThrowHelper.ThrowArgumentOutOfRangeException(); + + return new Span(ref Unsafe.Add(ref _pointer.Value, start), _length - start); + } + + /// + /// Forms a slice out of the given span, beginning at 'start', of given length + /// + /// The index at which to begin this slice. + /// The desired length for the slice (exclusive). + /// + /// Thrown when the specified or end index is not in range (<0 or >=Length). + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span Slice(int start, int length) + { + if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start)) + ThrowHelper.ThrowArgumentOutOfRangeException(); + + return new Span(ref Unsafe.Add(ref _pointer.Value, start), length); + } + + /// + /// Copies the contents of this span into a new array. This heap + /// allocates, so should generally be avoided, however it is sometimes + /// necessary to bridge the gap with APIs written in terms of arrays. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public T[] ToArray() + { + if (_length == 0) + return Array.Empty(); + + var destination = new T[_length]; + Buffer.Memmove(ref Unsafe.As(ref destination.GetRawSzArrayData()), ref _pointer.Value, (nuint)_length); + return destination; + } + } +} diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Span.cs b/external/corert/src/System.Private.CoreLib/shared/System/Span.cs index 5a813174d9..78733515cd 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Span.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Span.cs @@ -5,17 +5,12 @@ using System.ComponentModel; using System.Diagnostics; using System.Runtime.CompilerServices; +#if !FEATURE_PORTABLE_SPAN using System.Runtime.Versioning; -using Internal.Runtime.CompilerServices; +#endif // !FEATURE_PORTABLE_SPAN #pragma warning disable 0809 //warning CS0809: Obsolete member 'Span.Equals(object)' overrides non-obsolete member 'object.Equals(object)' -#if BIT64 -using nuint = System.UInt64; -#else -using nuint = System.UInt32; -#endif - namespace System { /// @@ -23,134 +18,17 @@ namespace System /// or native memory, or to memory allocated on the stack. It is type- and memory-safe. /// [DebuggerTypeProxy(typeof(SpanDebugView<>))] - [DebuggerDisplay("{DebuggerDisplay,nq}")] - [NonVersionable] - public readonly ref struct Span + [DebuggerDisplay("{ToString(),raw}")] + public readonly ref partial struct Span { - /// A byref or a native ptr. - internal readonly ByReference _pointer; - /// The number of elements this Span contains. -#if PROJECTN - [Bound] -#endif - private readonly int _length; - - /// - /// Creates a new span over the entirety of the target array. - /// - /// The target array. - /// Thrown when is a null - /// reference (Nothing in Visual Basic). - /// Thrown when is covariant and array's type is not exactly T[]. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span(T[] array) - { - if (array == null) - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); - if (default(T) == null && array.GetType() != typeof(T[])) - ThrowHelper.ThrowArrayTypeMismatchException(); - - _pointer = new ByReference(ref Unsafe.As(ref array.GetRawSzArrayData())); - _length = array.Length; - } - - /// - /// Creates a new span over the portion of the target array beginning - /// at 'start' index and ending at 'end' index (exclusive). - /// - /// The target array. - /// The index at which to begin the span. - /// The number of items in the span. - /// Thrown when is a null - /// reference (Nothing in Visual Basic). - /// Thrown when is covariant and array's type is not exactly T[]. - /// - /// Thrown when the specified or end index is not in the range (<0 or >=Length). - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span(T[] array, int start, int length) - { - if (array == null) - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); - if (default(T) == null && array.GetType() != typeof(T[])) - ThrowHelper.ThrowArrayTypeMismatchException(); - if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start)) - ThrowHelper.ThrowArgumentOutOfRangeException(); - - _pointer = new ByReference(ref Unsafe.Add(ref Unsafe.As(ref array.GetRawSzArrayData()), start)); - _length = length; - } - - /// - /// Creates a new span over the target unmanaged buffer. Clearly this - /// is quite dangerous, because we are creating arbitrarily typed T's - /// out of a void*-typed block of memory. And the length is not checked. - /// But if this creation is correct, then all subsequent uses are correct. - /// - /// An unmanaged pointer to memory. - /// The number of elements the memory contains. - /// - /// Thrown when is reference type or contains pointers and hence cannot be stored in unmanaged memory. - /// - /// - /// Thrown when the specified is negative. - /// - [CLSCompliant(false)] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public unsafe Span(void* pointer, int length) - { - if (RuntimeHelpers.IsReferenceOrContainsReferences()) - ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T)); - if (length < 0) - ThrowHelper.ThrowArgumentOutOfRangeException(); - - _pointer = new ByReference(ref Unsafe.As(ref *(byte*)pointer)); - _length = length; - } - - /// - /// Create a new span over a portion of a regular managed object. This can be useful - /// if part of a managed object represents a "fixed array." This is dangerous because neither the - /// is checked, nor being null, nor the fact that - /// "rawPointer" actually lies within . - /// - /// The managed object that contains the data to span over. - /// A reference to data within that object. - /// The number of elements the memory contains. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - [EditorBrowsable(EditorBrowsableState.Never)] - public static Span DangerousCreate(object obj, ref T objectData, int length) => new Span(ref objectData, length); - - // Constructor for internal use only. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal Span(ref T ptr, int length) - { - Debug.Assert(length >= 0); - - _pointer = new ByReference(ref ptr); - _length = length; - } - - //Debugger Display = {T[length]} - private string DebuggerDisplay => string.Format("{{{0}[{1}]}}", typeof(T).Name, _length); - - /// - /// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to the location where the 0th element - /// would have been stored. Such a reference can be used for pinning but must never be dereferenced. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - [EditorBrowsable(EditorBrowsableState.Never)] - internal ref T DangerousGetPinnableReference() - { - return ref _pointer.Value; - } - /// /// The number of items in the span. /// public int Length { +#if !FEATURE_PORTABLE_SPAN [NonVersionable] +#endif // !FEATURE_PORTABLE_SPAN get { return _length; @@ -162,152 +40,15 @@ namespace System /// public bool IsEmpty { +#if !FEATURE_PORTABLE_SPAN [NonVersionable] +#endif // !FEATURE_PORTABLE_SPAN get { return _length == 0; } } - /// - /// Returns a reference to specified element of the Span. - /// - /// - /// - /// - /// Thrown when index less than 0 or index greater than or equal to Length - /// - public ref T this[int index] - { -#if PROJECTN - [BoundsChecking] - get - { - return ref Unsafe.Add(ref _pointer.Value, index); - } -#else - [Intrinsic] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - [NonVersionable] - get - { - if ((uint)index >= (uint)_length) - ThrowHelper.ThrowIndexOutOfRangeException(); - return ref Unsafe.Add(ref _pointer.Value, index); - } -#endif - } - - /// - /// Clears the contents of this span. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Clear() - { - if (RuntimeHelpers.IsReferenceOrContainsReferences()) - { - Span.ClearWithReferences(ref Unsafe.As(ref _pointer.Value), (nuint)_length * (nuint)(Unsafe.SizeOf() / sizeof(nuint))); - } - else - { - Span.ClearWithoutReferences(ref Unsafe.As(ref _pointer.Value), (nuint)_length * (nuint)Unsafe.SizeOf()); - } - } - - /// - /// Fills the contents of this span with the given value. - /// - public void Fill(T value) - { - if (Unsafe.SizeOf() == 1) - { - uint length = (uint)_length; - if (length == 0) - return; - - T tmp = value; // Avoid taking address of the "value" argument. It would regress performance of the loop below. - Unsafe.InitBlockUnaligned(ref Unsafe.As(ref _pointer.Value), Unsafe.As(ref tmp), length); - } - else - { - // Do all math as nuint to avoid unnecessary 64->32->64 bit integer truncations - nuint length = (uint)_length; - if (length == 0) - return; - - ref T r = ref DangerousGetPinnableReference(); - - // TODO: Create block fill for value types of power of two sizes e.g. 2,4,8,16 - - nuint elementSize = (uint)Unsafe.SizeOf(); - nuint i = 0; - for (; i < (length & ~(nuint)7); i += 8) - { - Unsafe.AddByteOffset(ref r, (i + 0) * elementSize) = value; - Unsafe.AddByteOffset(ref r, (i + 1) * elementSize) = value; - Unsafe.AddByteOffset(ref r, (i + 2) * elementSize) = value; - Unsafe.AddByteOffset(ref r, (i + 3) * elementSize) = value; - Unsafe.AddByteOffset(ref r, (i + 4) * elementSize) = value; - Unsafe.AddByteOffset(ref r, (i + 5) * elementSize) = value; - Unsafe.AddByteOffset(ref r, (i + 6) * elementSize) = value; - Unsafe.AddByteOffset(ref r, (i + 7) * elementSize) = value; - } - if (i < (length & ~(nuint)3)) - { - Unsafe.AddByteOffset(ref r, (i + 0) * elementSize) = value; - Unsafe.AddByteOffset(ref r, (i + 1) * elementSize) = value; - Unsafe.AddByteOffset(ref r, (i + 2) * elementSize) = value; - Unsafe.AddByteOffset(ref r, (i + 3) * elementSize) = value; - i += 4; - } - for (; i < length; i++) - { - Unsafe.AddByteOffset(ref r, i * elementSize) = value; - } - } - } - - /// - /// Copies the contents of this span into destination span. If the source - /// and destinations overlap, this method behaves as if the original values in - /// a temporary location before the destination is overwritten. - /// - /// The span to copy items into. - /// - /// Thrown when the destination Span is shorter than the source Span. - /// - public void CopyTo(Span destination) - { - if (!TryCopyTo(destination)) - ThrowHelper.ThrowArgumentException_DestinationTooShort(); - } - - /// - /// Copies the contents of this span into destination span. If the source - /// and destinations overlap, this method behaves as if the original values in - /// a temporary location before the destination is overwritten. - /// - /// The span to copy items into. - /// If the destination span is shorter than the source span, this method - /// return false and no data is written to the destination. - public bool TryCopyTo(Span destination) - { - if ((uint)_length > (uint)destination.Length) - return false; - - Span.CopyTo(ref destination._pointer.Value, ref _pointer.Value, _length); - return true; - } - - /// - /// Returns true if left and right point at the same memory and have the same length. Note that - /// this does *not* check to see if the *contents* are equal. - /// - public static bool operator ==(Span left, Span right) - { - return left._length == right._length && Unsafe.AreSame(ref left._pointer.Value, ref right._pointer.Value); - } - /// /// Returns false if left and right point at the same memory and have the same length. Note that /// this does *not* check to see if the *contents* are equal. @@ -343,69 +84,15 @@ namespace System /// /// Defines an implicit conversion of an array to a /// - public static implicit operator Span(T[] array) => array != null ? new Span(array) : default; + public static implicit operator Span(T[] array) => new Span(array); /// /// Defines an implicit conversion of a to a /// public static implicit operator Span(ArraySegment arraySegment) - => arraySegment.Array != null ? new Span(arraySegment.Array, arraySegment.Offset, arraySegment.Count) : default; + => new Span(arraySegment.Array, arraySegment.Offset, arraySegment.Count); /// - /// Defines an implicit conversion of a to a - /// - public static implicit operator ReadOnlySpan(Span span) => new ReadOnlySpan(ref span._pointer.Value, span._length); - - /// - /// Forms a slice out of the given span, beginning at 'start'. - /// - /// The index at which to begin this slice. - /// - /// Thrown when the specified index is not in range (<0 or >=Length). - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span Slice(int start) - { - if ((uint)start > (uint)_length) - ThrowHelper.ThrowArgumentOutOfRangeException(); - - return new Span(ref Unsafe.Add(ref _pointer.Value, start), _length - start); - } - - /// - /// Forms a slice out of the given span, beginning at 'start', of given length - /// - /// The index at which to begin this slice. - /// The desired length for the slice (exclusive). - /// - /// Thrown when the specified or end index is not in range (<0 or >=Length). - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span Slice(int start, int length) - { - if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start)) - ThrowHelper.ThrowArgumentOutOfRangeException(); - - return new Span(ref Unsafe.Add(ref _pointer.Value, start), length); - } - - /// - /// Copies the contents of this span into a new array. This heap - /// allocates, so should generally be avoided, however it is sometimes - /// necessary to bridge the gap with APIs written in terms of arrays. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public T[] ToArray() - { - if (_length == 0) - return Array.Empty(); - - var destination = new T[_length]; - Span.CopyTo(ref Unsafe.As(ref destination.GetRawSzArrayData()), ref _pointer.Value, _length); - return destination; - } - - // /// Returns an empty /// public static Span Empty => default(Span); diff --git a/external/corert/src/System.Private.CoreLib/shared/System/SpanHelpers.BinarySearch.cs b/external/corert/src/System.Private.CoreLib/shared/System/SpanHelpers.BinarySearch.cs new file mode 100644 index 0000000000..656b864e22 --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/shared/System/SpanHelpers.BinarySearch.cs @@ -0,0 +1,83 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +#if !netstandard +using Internal.Runtime.CompilerServices; +#endif + +namespace System +{ + internal static partial class SpanHelpers + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int BinarySearch( + this ReadOnlySpan span, TComparable comparable) + where TComparable : IComparable + { + if (comparable == null) + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.comparable); + + return BinarySearch(ref MemoryMarshal.GetReference(span), span.Length, comparable); + } + + public static int BinarySearch( + ref T spanStart, int length, TComparable comparable) + where TComparable : IComparable + { + int lo = 0; + int hi = length - 1; + // If length == 0, hi == -1, and loop will not be entered + while (lo <= hi) + { + // PERF: `lo` or `hi` will never be negative inside the loop, + // so computing median using uints is safe since we know + // `length <= int.MaxValue`, and indices are >= 0 + // and thus cannot overflow an uint. + // Saves one subtraction per loop compared to + // `int i = lo + ((hi - lo) >> 1);` + int i = (int)(((uint)hi + (uint)lo) >> 1); + + int c = comparable.CompareTo(Unsafe.Add(ref spanStart, i)); + if (c == 0) + { + return i; + } + else if (c > 0) + { + lo = i + 1; + } + else + { + hi = i - 1; + } + } + // If none found, then a negative number that is the bitwise complement + // of the index of the next element that is larger than or, if there is + // no larger element, the bitwise complement of `length`, which + // is `lo` at this point. + return ~lo; + } + + // Helper to allow sharing all code via IComparable inlineable + internal struct ComparerComparable : IComparable + where TComparer : IComparer + { + readonly T _value; + readonly TComparer _comparer; + + public ComparerComparable(T value, TComparer comparer) + { + _value = value; + _comparer = comparer; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int CompareTo(T other) => _comparer.Compare(_value, other); + } + } +} diff --git a/external/corert/src/System.Private.CoreLib/shared/System/SpanHelpers.Byte.cs b/external/corert/src/System.Private.CoreLib/shared/System/SpanHelpers.Byte.cs new file mode 100644 index 0000000000..860b2efa0b --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/shared/System/SpanHelpers.Byte.cs @@ -0,0 +1,1104 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; +using System.Runtime.CompilerServices; + +#if !netstandard +using Internal.Runtime.CompilerServices; +#endif + +#if !netstandard11 +using System.Numerics; +#endif + +namespace System +{ + internal static partial class SpanHelpers + { + public static int IndexOf(ref byte searchSpace, int searchSpaceLength, ref byte value, int valueLength) + { + Debug.Assert(searchSpaceLength >= 0); + Debug.Assert(valueLength >= 0); + + if (valueLength == 0) + return 0; // A zero-length sequence is always treated as "found" at the start of the search space. + + byte valueHead = value; + ref byte valueTail = ref Unsafe.Add(ref value, 1); + int valueTailLength = valueLength - 1; + + int index = 0; + for (; ; ) + { + Debug.Assert(0 <= index && index <= searchSpaceLength); // Ensures no deceptive underflows in the computation of "remainingSearchSpaceLength". + int remainingSearchSpaceLength = searchSpaceLength - index - valueTailLength; + if (remainingSearchSpaceLength <= 0) + break; // The unsearched portion is now shorter than the sequence we're looking for. So it can't be there. + + // Do a quick search for the first element of "value". + int relativeIndex = IndexOf(ref Unsafe.Add(ref searchSpace, index), valueHead, remainingSearchSpaceLength); + if (relativeIndex == -1) + break; + index += relativeIndex; + + // Found the first element of "value". See if the tail matches. + if (SequenceEqual(ref Unsafe.Add(ref searchSpace, index + 1), ref valueTail, valueTailLength)) + return index; // The tail matched. Return a successful find. + + index++; + } + return -1; + } + + public static int IndexOfAny(ref byte searchSpace, int searchSpaceLength, ref byte value, int valueLength) + { + Debug.Assert(searchSpaceLength >= 0); + Debug.Assert(valueLength >= 0); + + if (valueLength == 0) + return 0; // A zero-length sequence is always treated as "found" at the start of the search space. + + int index = -1; + for (int i = 0; i < valueLength; i++) + { + var tempIndex = IndexOf(ref searchSpace, Unsafe.Add(ref value, i), searchSpaceLength); + if ((uint)tempIndex < (uint)index) + { + index = tempIndex; + // Reduce space for search, cause we don't care if we find the search value after the index of a previously found value + searchSpaceLength = tempIndex; + + if (index == 0) break; + } + } + return index; + } + + public static int LastIndexOfAny(ref byte searchSpace, int searchSpaceLength, ref byte value, int valueLength) + { + Debug.Assert(searchSpaceLength >= 0); + Debug.Assert(valueLength >= 0); + + if (valueLength == 0) + return 0; // A zero-length sequence is always treated as "found" at the start of the search space. + + int index = -1; + for (int i = 0; i < valueLength; i++) + { + var tempIndex = LastIndexOf(ref searchSpace, Unsafe.Add(ref value, i), searchSpaceLength); + if (tempIndex > index) index = tempIndex; + } + return index; + } + + public static unsafe int IndexOf(ref byte searchSpace, byte value, int length) + { + Debug.Assert(length >= 0); + + uint uValue = value; // Use uint for comparisons to avoid unnecessary 8->32 extensions + IntPtr index = (IntPtr)0; // Use UIntPtr for arithmetic to avoid unnecessary 64->32->64 truncations + IntPtr nLength = (IntPtr)(uint)length; +#if !netstandard11 + if (Vector.IsHardwareAccelerated && length >= Vector.Count * 2) + { + unchecked + { + int unaligned = (int)(byte*)Unsafe.AsPointer(ref searchSpace) & (Vector.Count - 1); + nLength = (IntPtr)(uint)((Vector.Count - unaligned) & (Vector.Count - 1)); + } + } + SequentialScan: +#endif + while ((byte*)nLength >= (byte*)8) + { + nLength -= 8; + + if (uValue == Unsafe.Add(ref searchSpace, index)) + goto Found; + if (uValue == Unsafe.Add(ref searchSpace, index + 1)) + goto Found1; + if (uValue == Unsafe.Add(ref searchSpace, index + 2)) + goto Found2; + if (uValue == Unsafe.Add(ref searchSpace, index + 3)) + goto Found3; + if (uValue == Unsafe.Add(ref searchSpace, index + 4)) + goto Found4; + if (uValue == Unsafe.Add(ref searchSpace, index + 5)) + goto Found5; + if (uValue == Unsafe.Add(ref searchSpace, index + 6)) + goto Found6; + if (uValue == Unsafe.Add(ref searchSpace, index + 7)) + goto Found7; + + index += 8; + } + + if ((byte*)nLength >= (byte*)4) + { + nLength -= 4; + + if (uValue == Unsafe.Add(ref searchSpace, index)) + goto Found; + if (uValue == Unsafe.Add(ref searchSpace, index + 1)) + goto Found1; + if (uValue == Unsafe.Add(ref searchSpace, index + 2)) + goto Found2; + if (uValue == Unsafe.Add(ref searchSpace, index + 3)) + goto Found3; + + index += 4; + } + + while ((byte*)nLength > (byte*)0) + { + nLength -= 1; + + if (uValue == Unsafe.Add(ref searchSpace, index)) + goto Found; + + index += 1; + } +#if !netstandard11 + if (Vector.IsHardwareAccelerated && ((int)(byte*)index < length)) + { + nLength = (IntPtr)(uint)((length - (uint)index) & ~(Vector.Count - 1)); + // Get comparison Vector + Vector vComparison = GetVector(value); + while ((byte*)nLength > (byte*)index) + { + var vMatches = Vector.Equals(vComparison, Unsafe.ReadUnaligned>(ref Unsafe.AddByteOffset(ref searchSpace, index))); + if (Vector.Zero.Equals(vMatches)) + { + index += Vector.Count; + continue; + } + // Find offset of first match + return (int)(byte*)index + LocateFirstFoundByte(vMatches); + } + + if ((int)(byte*)index < length) + { + unchecked + { + nLength = (IntPtr)(length - (int)(byte*)index); + } + goto SequentialScan; + } + } +#endif + return -1; + Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549 + return (int)(byte*)index; + Found1: + return (int)(byte*)(index + 1); + Found2: + return (int)(byte*)(index + 2); + Found3: + return (int)(byte*)(index + 3); + Found4: + return (int)(byte*)(index + 4); + Found5: + return (int)(byte*)(index + 5); + Found6: + return (int)(byte*)(index + 6); + Found7: + return (int)(byte*)(index + 7); + } + + public static int LastIndexOf(ref byte searchSpace, int searchSpaceLength, ref byte value, int valueLength) + { + Debug.Assert(searchSpaceLength >= 0); + Debug.Assert(valueLength >= 0); + + if (valueLength == 0) + return 0; // A zero-length sequence is always treated as "found" at the start of the search space. + + byte valueHead = value; + ref byte valueTail = ref Unsafe.Add(ref value, 1); + int valueTailLength = valueLength - 1; + + int index = 0; + for (; ; ) + { + Debug.Assert(0 <= index && index <= searchSpaceLength); // Ensures no deceptive underflows in the computation of "remainingSearchSpaceLength". + int remainingSearchSpaceLength = searchSpaceLength - index - valueTailLength; + if (remainingSearchSpaceLength <= 0) + break; // The unsearched portion is now shorter than the sequence we're looking for. So it can't be there. + + // Do a quick search for the first element of "value". + int relativeIndex = LastIndexOf(ref searchSpace, valueHead, remainingSearchSpaceLength); + if (relativeIndex == -1) + break; + + // Found the first element of "value". See if the tail matches. + if (SequenceEqual(ref Unsafe.Add(ref searchSpace, relativeIndex + 1), ref valueTail, valueTailLength)) + return relativeIndex; // The tail matched. Return a successful find. + + index += remainingSearchSpaceLength - relativeIndex; + } + return -1; + } + + public static unsafe int LastIndexOf(ref byte searchSpace, byte value, int length) + { + Debug.Assert(length >= 0); + + uint uValue = value; // Use uint for comparisons to avoid unnecessary 8->32 extensions + IntPtr index = (IntPtr)(uint)length; // Use UIntPtr for arithmetic to avoid unnecessary 64->32->64 truncations + IntPtr nLength = (IntPtr)(uint)length; +#if !netstandard11 + if (Vector.IsHardwareAccelerated && length >= Vector.Count * 2) + { + unchecked + { + int unaligned = (int)(byte*)Unsafe.AsPointer(ref searchSpace) & (Vector.Count - 1); + nLength = (IntPtr)(((length & (Vector.Count - 1)) + unaligned) & (Vector.Count - 1)); + } + } + SequentialScan: +#endif + while ((byte*)nLength >= (byte*)8) + { + nLength -= 8; + index -= 8; + + if (uValue == Unsafe.Add(ref searchSpace, index + 7)) + goto Found7; + if (uValue == Unsafe.Add(ref searchSpace, index + 6)) + goto Found6; + if (uValue == Unsafe.Add(ref searchSpace, index + 5)) + goto Found5; + if (uValue == Unsafe.Add(ref searchSpace, index + 4)) + goto Found4; + if (uValue == Unsafe.Add(ref searchSpace, index + 3)) + goto Found3; + if (uValue == Unsafe.Add(ref searchSpace, index + 2)) + goto Found2; + if (uValue == Unsafe.Add(ref searchSpace, index + 1)) + goto Found1; + if (uValue == Unsafe.Add(ref searchSpace, index)) + goto Found; + } + + if ((byte*)nLength >= (byte*)4) + { + nLength -= 4; + index -= 4; + + if (uValue == Unsafe.Add(ref searchSpace, index + 3)) + goto Found3; + if (uValue == Unsafe.Add(ref searchSpace, index + 2)) + goto Found2; + if (uValue == Unsafe.Add(ref searchSpace, index + 1)) + goto Found1; + if (uValue == Unsafe.Add(ref searchSpace, index)) + goto Found; + } + + while ((byte*)nLength > (byte*)0) + { + nLength -= 1; + index -= 1; + + if (uValue == Unsafe.Add(ref searchSpace, index)) + goto Found; + } +#if !netstandard11 + if (Vector.IsHardwareAccelerated && ((int)(byte*)index > 0)) + { + nLength = (IntPtr)(uint)((uint)index & ~(Vector.Count - 1)); + + // Get comparison Vector + Vector vComparison = GetVector(value); + while ((byte*)nLength > (byte*)(Vector.Count - 1)) + { + var vMatches = Vector.Equals(vComparison, Unsafe.ReadUnaligned>(ref Unsafe.AddByteOffset(ref searchSpace, index - Vector.Count))); + if (Vector.Zero.Equals(vMatches)) + { + index -= Vector.Count; + nLength -= Vector.Count; + continue; + } + // Find offset of first match + return (int)(byte*)(index) - Vector.Count + LocateLastFoundByte(vMatches); + } + if ((int)(byte*)index > 0) + { + nLength = index; + goto SequentialScan; + } + } +#endif + return -1; + Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549 + return (int)(byte*)index; + Found1: + return (int)(byte*)(index + 1); + Found2: + return (int)(byte*)(index + 2); + Found3: + return (int)(byte*)(index + 3); + Found4: + return (int)(byte*)(index + 4); + Found5: + return (int)(byte*)(index + 5); + Found6: + return (int)(byte*)(index + 6); + Found7: + return (int)(byte*)(index + 7); + } + + public static unsafe int IndexOfAny(ref byte searchSpace, byte value0, byte value1, int length) + { + Debug.Assert(length >= 0); + + uint uValue0 = value0; // Use uint for comparisons to avoid unnecessary 8->32 extensions + uint uValue1 = value1; // Use uint for comparisons to avoid unnecessary 8->32 extensions + IntPtr index = (IntPtr)0; // Use UIntPtr for arithmetic to avoid unnecessary 64->32->64 truncations + IntPtr nLength = (IntPtr)(uint)length; +#if !netstandard11 + if (Vector.IsHardwareAccelerated && length >= Vector.Count * 2) + { + unchecked + { + int unaligned = (int)(byte*)Unsafe.AsPointer(ref searchSpace) & (Vector.Count - 1); + nLength = (IntPtr)(uint)((Vector.Count - unaligned) & (Vector.Count - 1)); + } + } + SequentialScan: +#endif + uint lookUp; + while ((byte*)nLength >= (byte*)8) + { + nLength -= 8; + + lookUp = Unsafe.Add(ref searchSpace, index); + if (uValue0 == lookUp || uValue1 == lookUp) + goto Found; + lookUp = Unsafe.Add(ref searchSpace, index + 1); + if (uValue0 == lookUp || uValue1 == lookUp) + goto Found1; + lookUp = Unsafe.Add(ref searchSpace, index + 2); + if (uValue0 == lookUp || uValue1 == lookUp) + goto Found2; + lookUp = Unsafe.Add(ref searchSpace, index + 3); + if (uValue0 == lookUp || uValue1 == lookUp) + goto Found3; + lookUp = Unsafe.Add(ref searchSpace, index + 4); + if (uValue0 == lookUp || uValue1 == lookUp) + goto Found4; + lookUp = Unsafe.Add(ref searchSpace, index + 5); + if (uValue0 == lookUp || uValue1 == lookUp) + goto Found5; + lookUp = Unsafe.Add(ref searchSpace, index + 6); + if (uValue0 == lookUp || uValue1 == lookUp) + goto Found6; + lookUp = Unsafe.Add(ref searchSpace, index + 7); + if (uValue0 == lookUp || uValue1 == lookUp) + goto Found7; + + index += 8; + } + + if ((byte*)nLength >= (byte*)4) + { + nLength -= 4; + + lookUp = Unsafe.Add(ref searchSpace, index); + if (uValue0 == lookUp || uValue1 == lookUp) + goto Found; + lookUp = Unsafe.Add(ref searchSpace, index + 1); + if (uValue0 == lookUp || uValue1 == lookUp) + goto Found1; + lookUp = Unsafe.Add(ref searchSpace, index + 2); + if (uValue0 == lookUp || uValue1 == lookUp) + goto Found2; + lookUp = Unsafe.Add(ref searchSpace, index + 3); + if (uValue0 == lookUp || uValue1 == lookUp) + goto Found3; + + index += 4; + } + + while ((byte*)nLength > (byte*)0) + { + nLength -= 1; + + lookUp = Unsafe.Add(ref searchSpace, index); + if (uValue0 == lookUp || uValue1 == lookUp) + goto Found; + + index += 1; + } +#if !netstandard11 + if (Vector.IsHardwareAccelerated && ((int)(byte*)index < length)) + { + nLength = (IntPtr)(uint)((length - (uint)index) & ~(Vector.Count - 1)); + // Get comparison Vector + Vector values0 = GetVector(value0); + Vector values1 = GetVector(value1); + + while ((byte*)nLength > (byte*)index) + { + Vector vData = Unsafe.ReadUnaligned>(ref Unsafe.AddByteOffset(ref searchSpace, index)); + var vMatches = Vector.BitwiseOr( + Vector.Equals(vData, values0), + Vector.Equals(vData, values1)); + if (Vector.Zero.Equals(vMatches)) + { + index += Vector.Count; + continue; + } + // Find offset of first match + return (int)(byte*)index + LocateFirstFoundByte(vMatches); + } + + if ((int)(byte*)index < length) + { + unchecked + { + nLength = (IntPtr)(length - (int)(byte*)index); + } + goto SequentialScan; + } + } +#endif + return -1; + Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549 + return (int)(byte*)index; + Found1: + return (int)(byte*)(index + 1); + Found2: + return (int)(byte*)(index + 2); + Found3: + return (int)(byte*)(index + 3); + Found4: + return (int)(byte*)(index + 4); + Found5: + return (int)(byte*)(index + 5); + Found6: + return (int)(byte*)(index + 6); + Found7: + return (int)(byte*)(index + 7); + } + + public static unsafe int IndexOfAny(ref byte searchSpace, byte value0, byte value1, byte value2, int length) + { + Debug.Assert(length >= 0); + + uint uValue0 = value0; // Use uint for comparisons to avoid unnecessary 8->32 extensions + uint uValue1 = value1; // Use uint for comparisons to avoid unnecessary 8->32 extensions + uint uValue2 = value2; // Use uint for comparisons to avoid unnecessary 8->32 extensions + IntPtr index = (IntPtr)0; // Use UIntPtr for arithmetic to avoid unnecessary 64->32->64 truncations + IntPtr nLength = (IntPtr)(uint)length; +#if !netstandard11 + if (Vector.IsHardwareAccelerated && length >= Vector.Count * 2) + { + unchecked + { + int unaligned = (int)(byte*)Unsafe.AsPointer(ref searchSpace) & (Vector.Count - 1); + nLength = (IntPtr)(uint)((Vector.Count - unaligned) & (Vector.Count - 1)); + } + } + SequentialScan: +#endif + uint lookUp; + while ((byte*)nLength >= (byte*)8) + { + nLength -= 8; + + lookUp = Unsafe.Add(ref searchSpace, index); + if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp) + goto Found; + lookUp = Unsafe.Add(ref searchSpace, index + 1); + if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp) + goto Found1; + lookUp = Unsafe.Add(ref searchSpace, index + 2); + if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp) + goto Found2; + lookUp = Unsafe.Add(ref searchSpace, index + 3); + if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp) + goto Found3; + lookUp = Unsafe.Add(ref searchSpace, index + 4); + if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp) + goto Found4; + lookUp = Unsafe.Add(ref searchSpace, index + 5); + if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp) + goto Found5; + lookUp = Unsafe.Add(ref searchSpace, index + 6); + if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp) + goto Found6; + lookUp = Unsafe.Add(ref searchSpace, index + 7); + if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp) + goto Found7; + + index += 8; + } + + if ((byte*)nLength >= (byte*)4) + { + nLength -= 4; + + lookUp = Unsafe.Add(ref searchSpace, index); + if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp) + goto Found; + lookUp = Unsafe.Add(ref searchSpace, index + 1); + if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp) + goto Found1; + lookUp = Unsafe.Add(ref searchSpace, index + 2); + if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp) + goto Found2; + lookUp = Unsafe.Add(ref searchSpace, index + 3); + if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp) + goto Found3; + + index += 4; + } + + while ((byte*)nLength > (byte*)0) + { + nLength -= 1; + + lookUp = Unsafe.Add(ref searchSpace, index); + if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp) + goto Found; + + index += 1; + } +#if !netstandard11 + if (Vector.IsHardwareAccelerated && ((int)(byte*)index < length)) + { + nLength = (IntPtr)(uint)((length - (uint)index) & ~(Vector.Count - 1)); + // Get comparison Vector + Vector values0 = GetVector(value0); + Vector values1 = GetVector(value1); + Vector values2 = GetVector(value2); + while ((byte*)nLength > (byte*)index) + { + Vector vData = Unsafe.ReadUnaligned>(ref Unsafe.AddByteOffset(ref searchSpace, index)); + + var vMatches = Vector.BitwiseOr( + Vector.BitwiseOr( + Vector.Equals(vData, values0), + Vector.Equals(vData, values1)), + Vector.Equals(vData, values2)); + + if (Vector.Zero.Equals(vMatches)) + { + index += Vector.Count; + continue; + } + // Find offset of first match + return (int)(byte*)index + LocateFirstFoundByte(vMatches); + } + + if ((int)(byte*)index < length) + { + unchecked + { + nLength = (IntPtr)(length - (int)(byte*)index); + } + goto SequentialScan; + } + } +#endif + return -1; + Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549 + return (int)(byte*)index; + Found1: + return (int)(byte*)(index + 1); + Found2: + return (int)(byte*)(index + 2); + Found3: + return (int)(byte*)(index + 3); + Found4: + return (int)(byte*)(index + 4); + Found5: + return (int)(byte*)(index + 5); + Found6: + return (int)(byte*)(index + 6); + Found7: + return (int)(byte*)(index + 7); + } + + public static unsafe int LastIndexOfAny(ref byte searchSpace, byte value0, byte value1, int length) + { + Debug.Assert(length >= 0); + + uint uValue0 = value0; // Use uint for comparisons to avoid unnecessary 8->32 extensions + uint uValue1 = value1; // Use uint for comparisons to avoid unnecessary 8->32 extensions + IntPtr index = (IntPtr)(uint)length; // Use UIntPtr for arithmetic to avoid unnecessary 64->32->64 truncations + IntPtr nLength = (IntPtr)(uint)length; +#if !netstandard11 + if (Vector.IsHardwareAccelerated && length >= Vector.Count * 2) + { + unchecked + { + int unaligned = (int)(byte*)Unsafe.AsPointer(ref searchSpace) & (Vector.Count - 1); + nLength = (IntPtr)(((length & (Vector.Count - 1)) + unaligned) & (Vector.Count - 1)); + } + } + SequentialScan: +#endif + uint lookUp; + while ((byte*)nLength >= (byte*)8) + { + nLength -= 8; + index -= 8; + + lookUp = Unsafe.Add(ref searchSpace, index + 7); + if (uValue0 == lookUp || uValue1 == lookUp) + goto Found7; + lookUp = Unsafe.Add(ref searchSpace, index + 6); + if (uValue0 == lookUp || uValue1 == lookUp) + goto Found6; + lookUp = Unsafe.Add(ref searchSpace, index + 5); + if (uValue0 == lookUp || uValue1 == lookUp) + goto Found5; + lookUp = Unsafe.Add(ref searchSpace, index + 4); + if (uValue0 == lookUp || uValue1 == lookUp) + goto Found4; + lookUp = Unsafe.Add(ref searchSpace, index + 3); + if (uValue0 == lookUp || uValue1 == lookUp) + goto Found3; + lookUp = Unsafe.Add(ref searchSpace, index + 2); + if (uValue0 == lookUp || uValue1 == lookUp) + goto Found2; + lookUp = Unsafe.Add(ref searchSpace, index + 1); + if (uValue0 == lookUp || uValue1 == lookUp) + goto Found1; + lookUp = Unsafe.Add(ref searchSpace, index); + if (uValue0 == lookUp || uValue1 == lookUp) + goto Found; + } + + if ((byte*)nLength >= (byte*)4) + { + nLength -= 4; + index -= 4; + + lookUp = Unsafe.Add(ref searchSpace, index + 3); + if (uValue0 == lookUp || uValue1 == lookUp) + goto Found3; + lookUp = Unsafe.Add(ref searchSpace, index + 2); + if (uValue0 == lookUp || uValue1 == lookUp) + goto Found2; + lookUp = Unsafe.Add(ref searchSpace, index + 1); + if (uValue0 == lookUp || uValue1 == lookUp) + goto Found1; + lookUp = Unsafe.Add(ref searchSpace, index); + if (uValue0 == lookUp || uValue1 == lookUp) + goto Found; + } + + while ((byte*)nLength > (byte*)0) + { + nLength -= 1; + index -= 1; + + lookUp = Unsafe.Add(ref searchSpace, index); + if (uValue0 == lookUp || uValue1 == lookUp) + goto Found; + } +#if !netstandard11 + if (Vector.IsHardwareAccelerated && ((int)(byte*)index > 0)) + { + nLength = (IntPtr)(uint)((uint)index & ~(Vector.Count - 1)); + // Get comparison Vector + Vector values0 = GetVector(value0); + Vector values1 = GetVector(value1); + + while ((byte*)nLength > (byte*)(Vector.Count - 1)) + { + Vector vData = Unsafe.ReadUnaligned>(ref Unsafe.AddByteOffset(ref searchSpace, index - Vector.Count)); + var vMatches = Vector.BitwiseOr( + Vector.Equals(vData, values0), + Vector.Equals(vData, values1)); + if (Vector.Zero.Equals(vMatches)) + { + index -= Vector.Count; + nLength -= Vector.Count; + continue; + } + // Find offset of first match + return (int)(byte*)(index) - Vector.Count + LocateLastFoundByte(vMatches); + } + + if ((int)(byte*)index > 0) + { + nLength = index; + goto SequentialScan; + } + } +#endif + return -1; + Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549 + return (int)(byte*)index; + Found1: + return (int)(byte*)(index + 1); + Found2: + return (int)(byte*)(index + 2); + Found3: + return (int)(byte*)(index + 3); + Found4: + return (int)(byte*)(index + 4); + Found5: + return (int)(byte*)(index + 5); + Found6: + return (int)(byte*)(index + 6); + Found7: + return (int)(byte*)(index + 7); + } + + public static unsafe int LastIndexOfAny(ref byte searchSpace, byte value0, byte value1, byte value2, int length) + { + Debug.Assert(length >= 0); + + uint uValue0 = value0; // Use uint for comparisons to avoid unnecessary 8->32 extensions + uint uValue1 = value1; // Use uint for comparisons to avoid unnecessary 8->32 extensions + uint uValue2 = value2; // Use uint for comparisons to avoid unnecessary 8->32 extensions + IntPtr index = (IntPtr)(uint)length; // Use UIntPtr for arithmetic to avoid unnecessary 64->32->64 truncations + IntPtr nLength = (IntPtr)(uint)length; +#if !netstandard11 + if (Vector.IsHardwareAccelerated && length >= Vector.Count * 2) + { + unchecked + { + int unaligned = (int)(byte*)Unsafe.AsPointer(ref searchSpace) & (Vector.Count - 1); + nLength = (IntPtr)(((length & (Vector.Count - 1)) + unaligned) & (Vector.Count - 1)); + } + } + SequentialScan: +#endif + uint lookUp; + while ((byte*)nLength >= (byte*)8) + { + nLength -= 8; + index -= 8; + + lookUp = Unsafe.Add(ref searchSpace, index + 7); + if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp) + goto Found7; + lookUp = Unsafe.Add(ref searchSpace, index + 6); + if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp) + goto Found6; + lookUp = Unsafe.Add(ref searchSpace, index + 5); + if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp) + goto Found5; + lookUp = Unsafe.Add(ref searchSpace, index + 4); + if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp) + goto Found4; + lookUp = Unsafe.Add(ref searchSpace, index + 3); + if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp) + goto Found3; + lookUp = Unsafe.Add(ref searchSpace, index + 2); + if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp) + goto Found2; + lookUp = Unsafe.Add(ref searchSpace, index + 1); + if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp) + goto Found1; + lookUp = Unsafe.Add(ref searchSpace, index); + if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp) + goto Found; + } + + if ((byte*)nLength >= (byte*)4) + { + nLength -= 4; + index -= 4; + + lookUp = Unsafe.Add(ref searchSpace, index + 3); + if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp) + goto Found3; + lookUp = Unsafe.Add(ref searchSpace, index + 2); + if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp) + goto Found2; + lookUp = Unsafe.Add(ref searchSpace, index + 1); + if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp) + goto Found1; + lookUp = Unsafe.Add(ref searchSpace, index); + if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp) + goto Found; + } + + while ((byte*)nLength > (byte*)0) + { + nLength -= 1; + index -= 1; + + lookUp = Unsafe.Add(ref searchSpace, index); + if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp) + goto Found; + } +#if !netstandard11 + if (Vector.IsHardwareAccelerated && ((int)(byte*)index > 0)) + { + nLength = (IntPtr)(uint)((uint)index & ~(Vector.Count - 1)); + // Get comparison Vector + Vector values0 = GetVector(value0); + Vector values1 = GetVector(value1); + Vector values2 = GetVector(value2); + while ((byte*)nLength > (byte*)(Vector.Count - 1)) + { + Vector vData = Unsafe.ReadUnaligned>(ref Unsafe.AddByteOffset(ref searchSpace, index - Vector.Count)); + + var vMatches = Vector.BitwiseOr( + Vector.BitwiseOr( + Vector.Equals(vData, values0), + Vector.Equals(vData, values1)), + Vector.Equals(vData, values2)); + + if (Vector.Zero.Equals(vMatches)) + { + index -= Vector.Count; + nLength -= Vector.Count; + continue; + } + // Find offset of first match + return (int)(byte*)(index) - Vector.Count + LocateLastFoundByte(vMatches); + } + + if ((int)(byte*)index > 0) + { + nLength = index; + goto SequentialScan; + } + } +#endif + return -1; + Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549 + return (int)(byte*)index; + Found1: + return (int)(byte*)(index + 1); + Found2: + return (int)(byte*)(index + 2); + Found3: + return (int)(byte*)(index + 3); + Found4: + return (int)(byte*)(index + 4); + Found5: + return (int)(byte*)(index + 5); + Found6: + return (int)(byte*)(index + 6); + Found7: + return (int)(byte*)(index + 7); + } + + public static unsafe bool SequenceEqual(ref byte first, ref byte second, int length) + { + Debug.Assert(length >= 0); + + if (Unsafe.AreSame(ref first, ref second)) + goto Equal; + + IntPtr i = (IntPtr)0; // Use IntPtr and byte* for arithmetic to avoid unnecessary 64->32->64 truncations + IntPtr n = (IntPtr)length; + +#if !netstandard11 + if (Vector.IsHardwareAccelerated && (byte*)n >= (byte*)Vector.Count) + { + n -= Vector.Count; + while ((byte*)n > (byte*)i) + { + if (Unsafe.ReadUnaligned>(ref Unsafe.AddByteOffset(ref first, i)) != + Unsafe.ReadUnaligned>(ref Unsafe.AddByteOffset(ref second, i))) + { + goto NotEqual; + } + i += Vector.Count; + } + return Unsafe.ReadUnaligned>(ref Unsafe.AddByteOffset(ref first, n)) == + Unsafe.ReadUnaligned>(ref Unsafe.AddByteOffset(ref second, n)); + } +#endif + + if ((byte*)n >= (byte*)sizeof(UIntPtr)) + { + n -= sizeof(UIntPtr); + while ((byte*)n > (byte*)i) + { + if (Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref first, i)) != + Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref second, i))) + { + goto NotEqual; + } + i += sizeof(UIntPtr); + } + return Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref first, n)) == + Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref second, n)); + } + + while ((byte*)n > (byte*)i) + { + if (Unsafe.AddByteOffset(ref first, i) != Unsafe.AddByteOffset(ref second, i)) + goto NotEqual; + i += 1; + } + + Equal: + return true; + + NotEqual: // Workaround for https://github.com/dotnet/coreclr/issues/13549 + return false; + } + +#if !netstandard11 + // Vector sub-search adapted from https://github.com/aspnet/KestrelHttpServer/pull/1138 + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int LocateFirstFoundByte(Vector match) + { + var vector64 = Vector.AsVectorUInt64(match); + ulong candidate = 0; + int i = 0; + // Pattern unrolled by jit https://github.com/dotnet/coreclr/pull/8001 + for (; i < Vector.Count; i++) + { + candidate = vector64[i]; + if (candidate != 0) + { + break; + } + } + + // Single LEA instruction with jitted const (using function result) + return i * 8 + LocateFirstFoundByte(candidate); + } +#endif + + public static unsafe int SequenceCompareTo(ref byte first, int firstLength, ref byte second, int secondLength) + { + Debug.Assert(firstLength >= 0); + Debug.Assert(secondLength >= 0); + + if (Unsafe.AreSame(ref first, ref second)) + goto Equal; + + var minLength = firstLength; + if (minLength > secondLength) minLength = secondLength; + + IntPtr i = (IntPtr)0; // Use IntPtr and byte* for arithmetic to avoid unnecessary 64->32->64 truncations + IntPtr n = (IntPtr)minLength; + +#if !netstandard11 + if (Vector.IsHardwareAccelerated && (byte*)n > (byte*)Vector.Count) + { + n -= Vector.Count; + while ((byte*)n > (byte*)i) + { + if (Unsafe.ReadUnaligned>(ref Unsafe.AddByteOffset(ref first, i)) != + Unsafe.ReadUnaligned>(ref Unsafe.AddByteOffset(ref second, i))) + { + goto NotEqual; + } + i += Vector.Count; + } + goto NotEqual; + } +#endif + + if ((byte*)n > (byte*)sizeof(UIntPtr)) + { + n -= sizeof(UIntPtr); + while ((byte*)n > (byte*)i) + { + if (Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref first, i)) != + Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref second, i))) + { + goto NotEqual; + } + i += sizeof(UIntPtr); + } + } + + NotEqual: // Workaround for https://github.com/dotnet/coreclr/issues/13549 + while((byte*)minLength > (byte*)i) + { + int result = Unsafe.AddByteOffset(ref first, i).CompareTo(Unsafe.AddByteOffset(ref second, i)); + if (result != 0) return result; + i += 1; + } + + Equal: + return firstLength - secondLength; + } + +#if !netstandard11 + // Vector sub-search adapted from https://github.com/aspnet/KestrelHttpServer/pull/1138 + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int LocateLastFoundByte(Vector match) + { + var vector64 = Vector.AsVectorUInt64(match); + ulong candidate = 0; + int i = Vector.Count - 1; + // Pattern unrolled by jit https://github.com/dotnet/coreclr/pull/8001 + for (; i >= 0; i--) + { + candidate = vector64[i]; + if (candidate != 0) + { + break; + } + } + + // Single LEA instruction with jitted const (using function result) + return i * 8 + LocateLastFoundByte(candidate); + } +#endif + +#if !netstandard11 + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int LocateFirstFoundByte(ulong match) + { + unchecked + { + // Flag least significant power of two bit + var powerOfTwoFlag = match ^ (match - 1); + // Shift all powers of two into the high byte and extract + return (int)((powerOfTwoFlag * XorPowerOfTwoToHighByte) >> 57); + } + } +#endif + +#if !netstandard11 + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int LocateLastFoundByte(ulong match) + { + // Find the most significant byte that has its highest bit set + int index = 7; + while ((long)match > 0) + { + match = match << 8; + index--; + } + return index; + } +#endif + +#if !netstandard11 + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector GetVector(byte vectorByte) + { +#if !netcoreapp + // Vector .ctor doesn't become an intrinsic due to detection issue + // However this does cause it to become an intrinsic (with additional multiply and reg->reg copy) + // https://github.com/dotnet/coreclr/issues/7459#issuecomment-253965670 + return Vector.AsVectorByte(new Vector(vectorByte * 0x01010101u)); +#else + return new Vector(vectorByte); +#endif + } +#endif + +#if !netstandard11 + private const ulong XorPowerOfTwoToHighByte = (0x07ul | + 0x06ul << 8 | + 0x05ul << 16 | + 0x04ul << 24 | + 0x03ul << 32 | + 0x02ul << 40 | + 0x01ul << 48) + 1; +#endif + } +} diff --git a/external/corert/src/System.Private.CoreLib/shared/System/SpanHelpers.T.cs b/external/corert/src/System.Private.CoreLib/shared/System/SpanHelpers.T.cs new file mode 100644 index 0000000000..d1c62c8d51 --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/shared/System/SpanHelpers.T.cs @@ -0,0 +1,683 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; + +#if !netstandard +using Internal.Runtime.CompilerServices; +#else +using System.Runtime.CompilerServices; +#endif + +namespace System +{ + internal static partial class SpanHelpers + { + public static int IndexOf(ref T searchSpace, int searchSpaceLength, ref T value, int valueLength) + where T : IEquatable + { + Debug.Assert(searchSpaceLength >= 0); + Debug.Assert(valueLength >= 0); + + if (valueLength == 0) + return 0; // A zero-length sequence is always treated as "found" at the start of the search space. + + T valueHead = value; + ref T valueTail = ref Unsafe.Add(ref value, 1); + int valueTailLength = valueLength - 1; + + int index = 0; + for (; ; ) + { + Debug.Assert(0 <= index && index <= searchSpaceLength); // Ensures no deceptive underflows in the computation of "remainingSearchSpaceLength". + int remainingSearchSpaceLength = searchSpaceLength - index - valueTailLength; + if (remainingSearchSpaceLength <= 0) + break; // The unsearched portion is now shorter than the sequence we're looking for. So it can't be there. + + // Do a quick search for the first element of "value". + int relativeIndex = IndexOf(ref Unsafe.Add(ref searchSpace, index), valueHead, remainingSearchSpaceLength); + if (relativeIndex == -1) + break; + index += relativeIndex; + + // Found the first element of "value". See if the tail matches. + if (SequenceEqual(ref Unsafe.Add(ref searchSpace, index + 1), ref valueTail, valueTailLength)) + return index; // The tail matched. Return a successful find. + + index++; + } + return -1; + } + + public static unsafe int IndexOf(ref T searchSpace, T value, int length) + where T : IEquatable + { + Debug.Assert(length >= 0); + + IntPtr index = (IntPtr)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations + while (length >= 8) + { + length -= 8; + + if (value.Equals(Unsafe.Add(ref searchSpace, index))) + goto Found; + if (value.Equals(Unsafe.Add(ref searchSpace, index + 1))) + goto Found1; + if (value.Equals(Unsafe.Add(ref searchSpace, index + 2))) + goto Found2; + if (value.Equals(Unsafe.Add(ref searchSpace, index + 3))) + goto Found3; + if (value.Equals(Unsafe.Add(ref searchSpace, index + 4))) + goto Found4; + if (value.Equals(Unsafe.Add(ref searchSpace, index + 5))) + goto Found5; + if (value.Equals(Unsafe.Add(ref searchSpace, index + 6))) + goto Found6; + if (value.Equals(Unsafe.Add(ref searchSpace, index + 7))) + goto Found7; + + index += 8; + } + + if (length >= 4) + { + length -= 4; + + if (value.Equals(Unsafe.Add(ref searchSpace, index))) + goto Found; + if (value.Equals(Unsafe.Add(ref searchSpace, index + 1))) + goto Found1; + if (value.Equals(Unsafe.Add(ref searchSpace, index + 2))) + goto Found2; + if (value.Equals(Unsafe.Add(ref searchSpace, index + 3))) + goto Found3; + + index += 4; + } + + while (length > 0) + { + if (value.Equals(Unsafe.Add(ref searchSpace, index))) + goto Found; + + index += 1; + length--; + } + return -1; + + Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549 + return (int)(byte*)index; + Found1: + return (int)(byte*)(index + 1); + Found2: + return (int)(byte*)(index + 2); + Found3: + return (int)(byte*)(index + 3); + Found4: + return (int)(byte*)(index + 4); + Found5: + return (int)(byte*)(index + 5); + Found6: + return (int)(byte*)(index + 6); + Found7: + return (int)(byte*)(index + 7); + } + + public static int IndexOfAny(ref T searchSpace, T value0, T value1, int length) + where T : IEquatable + { + Debug.Assert(length >= 0); + + T lookUp; + int index = 0; + while ((length - index) >= 8) + { + lookUp = Unsafe.Add(ref searchSpace, index); + if (value0.Equals(lookUp) || value1.Equals(lookUp)) + goto Found; + lookUp = Unsafe.Add(ref searchSpace, index + 1); + if (value0.Equals(lookUp) || value1.Equals(lookUp)) + goto Found1; + lookUp = Unsafe.Add(ref searchSpace, index + 2); + if (value0.Equals(lookUp) || value1.Equals(lookUp)) + goto Found2; + lookUp = Unsafe.Add(ref searchSpace, index + 3); + if (value0.Equals(lookUp) || value1.Equals(lookUp)) + goto Found3; + lookUp = Unsafe.Add(ref searchSpace, index + 4); + if (value0.Equals(lookUp) || value1.Equals(lookUp)) + goto Found4; + lookUp = Unsafe.Add(ref searchSpace, index + 5); + if (value0.Equals(lookUp) || value1.Equals(lookUp)) + goto Found5; + lookUp = Unsafe.Add(ref searchSpace, index + 6); + if (value0.Equals(lookUp) || value1.Equals(lookUp)) + goto Found6; + lookUp = Unsafe.Add(ref searchSpace, index + 7); + if (value0.Equals(lookUp) || value1.Equals(lookUp)) + goto Found7; + + index += 8; + } + + if ((length - index) >= 4) + { + lookUp = Unsafe.Add(ref searchSpace, index); + if (value0.Equals(lookUp) || value1.Equals(lookUp)) + goto Found; + lookUp = Unsafe.Add(ref searchSpace, index + 1); + if (value0.Equals(lookUp) || value1.Equals(lookUp)) + goto Found1; + lookUp = Unsafe.Add(ref searchSpace, index + 2); + if (value0.Equals(lookUp) || value1.Equals(lookUp)) + goto Found2; + lookUp = Unsafe.Add(ref searchSpace, index + 3); + if (value0.Equals(lookUp) || value1.Equals(lookUp)) + goto Found3; + + index += 4; + } + + while (index < length) + { + lookUp = Unsafe.Add(ref searchSpace, index); + if (value0.Equals(lookUp) || value1.Equals(lookUp)) + goto Found; + + index++; + } + return -1; + + Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549 + return index; + Found1: + return index + 1; + Found2: + return index + 2; + Found3: + return index + 3; + Found4: + return index + 4; + Found5: + return index + 5; + Found6: + return index + 6; + Found7: + return index + 7; + } + + public static int IndexOfAny(ref T searchSpace, T value0, T value1, T value2, int length) + where T : IEquatable + { + Debug.Assert(length >= 0); + + T lookUp; + int index = 0; + while ((length - index) >= 8) + { + lookUp = Unsafe.Add(ref searchSpace, index); + if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp)) + goto Found; + lookUp = Unsafe.Add(ref searchSpace, index + 1); + if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp)) + goto Found1; + lookUp = Unsafe.Add(ref searchSpace, index + 2); + if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp)) + goto Found2; + lookUp = Unsafe.Add(ref searchSpace, index + 3); + if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp)) + goto Found3; + lookUp = Unsafe.Add(ref searchSpace, index + 4); + if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp)) + goto Found4; + lookUp = Unsafe.Add(ref searchSpace, index + 5); + if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp)) + goto Found5; + lookUp = Unsafe.Add(ref searchSpace, index + 6); + if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp)) + goto Found6; + lookUp = Unsafe.Add(ref searchSpace, index + 7); + if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp)) + goto Found7; + + index += 8; + } + + if ((length - index) >= 4) + { + lookUp = Unsafe.Add(ref searchSpace, index); + if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp)) + goto Found; + lookUp = Unsafe.Add(ref searchSpace, index + 1); + if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp)) + goto Found1; + lookUp = Unsafe.Add(ref searchSpace, index + 2); + if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp)) + goto Found2; + lookUp = Unsafe.Add(ref searchSpace, index + 3); + if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp)) + goto Found3; + + index += 4; + } + + while (index < length) + { + lookUp = Unsafe.Add(ref searchSpace, index); + if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp)) + goto Found; + + index++; + } + return -1; + + Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549 + return index; + Found1: + return index + 1; + Found2: + return index + 2; + Found3: + return index + 3; + Found4: + return index + 4; + Found5: + return index + 5; + Found6: + return index + 6; + Found7: + return index + 7; + } + + public static int IndexOfAny(ref T searchSpace, int searchSpaceLength, ref T value, int valueLength) + where T : IEquatable + { + Debug.Assert(searchSpaceLength >= 0); + Debug.Assert(valueLength >= 0); + + if (valueLength == 0) + return 0; // A zero-length sequence is always treated as "found" at the start of the search space. + + int index = -1; + for (int i = 0; i < valueLength; i++) + { + var tempIndex = IndexOf(ref searchSpace, Unsafe.Add(ref value, i), searchSpaceLength); + if ((uint)tempIndex < (uint)index) + { + index = tempIndex; + // Reduce space for search, cause we don't care if we find the search value after the index of a previously found value + searchSpaceLength = tempIndex; + + if (index == 0) break; + } + } + return index; + } + + public static int LastIndexOf(ref T searchSpace, int searchSpaceLength, ref T value, int valueLength) + where T : IEquatable + { + Debug.Assert(searchSpaceLength >= 0); + Debug.Assert(valueLength >= 0); + + if (valueLength == 0) + return 0; // A zero-length sequence is always treated as "found" at the start of the search space. + + T valueHead = value; + ref T valueTail = ref Unsafe.Add(ref value, 1); + int valueTailLength = valueLength - 1; + + int index = 0; + for (; ; ) + { + Debug.Assert(0 <= index && index <= searchSpaceLength); // Ensures no deceptive underflows in the computation of "remainingSearchSpaceLength". + int remainingSearchSpaceLength = searchSpaceLength - index - valueTailLength; + if (remainingSearchSpaceLength <= 0) + break; // The unsearched portion is now shorter than the sequence we're looking for. So it can't be there. + + // Do a quick search for the first element of "value". + int relativeIndex = LastIndexOf(ref searchSpace, valueHead, remainingSearchSpaceLength); + if (relativeIndex == -1) + break; + + // Found the first element of "value". See if the tail matches. + if (SequenceEqual(ref Unsafe.Add(ref searchSpace, relativeIndex + 1), ref valueTail, valueTailLength)) + return relativeIndex; // The tail matched. Return a successful find. + + index += remainingSearchSpaceLength - relativeIndex; + } + return -1; + } + + public static int LastIndexOf(ref T searchSpace, T value, int length) + where T : IEquatable + { + Debug.Assert(length >= 0); + + while (length >= 8) + { + length -= 8; + + if (value.Equals(Unsafe.Add(ref searchSpace, length + 7))) + goto Found7; + if (value.Equals(Unsafe.Add(ref searchSpace, length + 6))) + goto Found6; + if (value.Equals(Unsafe.Add(ref searchSpace, length + 5))) + goto Found5; + if (value.Equals(Unsafe.Add(ref searchSpace, length + 4))) + goto Found4; + if (value.Equals(Unsafe.Add(ref searchSpace, length + 3))) + goto Found3; + if (value.Equals(Unsafe.Add(ref searchSpace, length + 2))) + goto Found2; + if (value.Equals(Unsafe.Add(ref searchSpace, length + 1))) + goto Found1; + if (value.Equals(Unsafe.Add(ref searchSpace, length))) + goto Found; + } + + if (length >= 4) + { + length -= 4; + + if (value.Equals(Unsafe.Add(ref searchSpace, length + 3))) + goto Found3; + if (value.Equals(Unsafe.Add(ref searchSpace, length + 2))) + goto Found2; + if (value.Equals(Unsafe.Add(ref searchSpace, length + 1))) + goto Found1; + if (value.Equals(Unsafe.Add(ref searchSpace, length))) + goto Found; + } + + while (length > 0) + { + length--; + + if (value.Equals(Unsafe.Add(ref searchSpace, length))) + goto Found; + } + return -1; + + Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549 + return length; + Found1: + return length + 1; + Found2: + return length + 2; + Found3: + return length + 3; + Found4: + return length + 4; + Found5: + return length + 5; + Found6: + return length + 6; + Found7: + return length + 7; + } + + public static int LastIndexOfAny(ref T searchSpace, T value0, T value1, int length) + where T : IEquatable + { + Debug.Assert(length >= 0); + + T lookUp; + while (length >= 8) + { + length -= 8; + + lookUp = Unsafe.Add(ref searchSpace, length + 7); + if (value0.Equals(lookUp) || value1.Equals(lookUp)) + goto Found7; + lookUp = Unsafe.Add(ref searchSpace, length + 6); + if (value0.Equals(lookUp) || value1.Equals(lookUp)) + goto Found6; + lookUp = Unsafe.Add(ref searchSpace, length + 5); + if (value0.Equals(lookUp) || value1.Equals(lookUp)) + goto Found5; + lookUp = Unsafe.Add(ref searchSpace, length + 4); + if (value0.Equals(lookUp) || value1.Equals(lookUp)) + goto Found4; + lookUp = Unsafe.Add(ref searchSpace, length + 3); + if (value0.Equals(lookUp) || value1.Equals(lookUp)) + goto Found3; + lookUp = Unsafe.Add(ref searchSpace, length + 2); + if (value0.Equals(lookUp) || value1.Equals(lookUp)) + goto Found2; + lookUp = Unsafe.Add(ref searchSpace, length + 1); + if (value0.Equals(lookUp) || value1.Equals(lookUp)) + goto Found1; + lookUp = Unsafe.Add(ref searchSpace, length); + if (value0.Equals(lookUp) || value1.Equals(lookUp)) + goto Found; + } + + if (length >= 4) + { + length -= 4; + + lookUp = Unsafe.Add(ref searchSpace, length + 3); + if (value0.Equals(lookUp) || value1.Equals(lookUp)) + goto Found3; + lookUp = Unsafe.Add(ref searchSpace, length + 2); + if (value0.Equals(lookUp) || value1.Equals(lookUp)) + goto Found2; + lookUp = Unsafe.Add(ref searchSpace, length + 1); + if (value0.Equals(lookUp) || value1.Equals(lookUp)) + goto Found1; + lookUp = Unsafe.Add(ref searchSpace, length); + if (value0.Equals(lookUp) || value1.Equals(lookUp)) + goto Found; + } + + while (length > 0) + { + length--; + + lookUp = Unsafe.Add(ref searchSpace, length); + if (value0.Equals(lookUp) || value1.Equals(lookUp)) + goto Found; + } + return -1; + + Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549 + return length; + Found1: + return length + 1; + Found2: + return length + 2; + Found3: + return length + 3; + Found4: + return length + 4; + Found5: + return length + 5; + Found6: + return length + 6; + Found7: + return length + 7; + } + + public static int LastIndexOfAny(ref T searchSpace, T value0, T value1, T value2, int length) + where T : IEquatable + { + Debug.Assert(length >= 0); + + T lookUp; + while (length >= 8) + { + length -= 8; + + lookUp = Unsafe.Add(ref searchSpace, length + 7); + if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp)) + goto Found7; + lookUp = Unsafe.Add(ref searchSpace, length + 6); + if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp)) + goto Found6; + lookUp = Unsafe.Add(ref searchSpace, length + 5); + if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp)) + goto Found5; + lookUp = Unsafe.Add(ref searchSpace, length + 4); + if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp)) + goto Found4; + lookUp = Unsafe.Add(ref searchSpace, length + 3); + if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp)) + goto Found3; + lookUp = Unsafe.Add(ref searchSpace, length + 2); + if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp)) + goto Found2; + lookUp = Unsafe.Add(ref searchSpace, length + 1); + if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp)) + goto Found1; + lookUp = Unsafe.Add(ref searchSpace, length); + if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp)) + goto Found; + } + + if (length >= 4) + { + length -= 4; + + lookUp = Unsafe.Add(ref searchSpace, length + 3); + if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp)) + goto Found3; + lookUp = Unsafe.Add(ref searchSpace, length + 2); + if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp)) + goto Found2; + lookUp = Unsafe.Add(ref searchSpace, length + 1); + if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp)) + goto Found1; + lookUp = Unsafe.Add(ref searchSpace, length); + if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp)) + goto Found; + } + + while (length > 0) + { + length--; + + lookUp = Unsafe.Add(ref searchSpace, length); + if (value0.Equals(lookUp) || value1.Equals(lookUp) || value2.Equals(lookUp)) + goto Found; + } + return -1; + + Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549 + return length; + Found1: + return length + 1; + Found2: + return length + 2; + Found3: + return length + 3; + Found4: + return length + 4; + Found5: + return length + 5; + Found6: + return length + 6; + Found7: + return length + 7; + } + + public static int LastIndexOfAny(ref T searchSpace, int searchSpaceLength, ref T value, int valueLength) + where T : IEquatable + { + Debug.Assert(searchSpaceLength >= 0); + Debug.Assert(valueLength >= 0); + + if (valueLength == 0) + return 0; // A zero-length sequence is always treated as "found" at the start of the search space. + + int index = -1; + for (int i = 0; i < valueLength; i++) + { + var tempIndex = LastIndexOf(ref searchSpace, Unsafe.Add(ref value, i), searchSpaceLength); + if (tempIndex > index) index = tempIndex; + } + return index; + } + + public static bool SequenceEqual(ref T first, ref T second, int length) + where T : IEquatable + { + Debug.Assert(length >= 0); + + if (Unsafe.AreSame(ref first, ref second)) + goto Equal; + + IntPtr index = (IntPtr)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations + while (length >= 8) + { + length -= 8; + + if (!Unsafe.Add(ref first, index).Equals(Unsafe.Add(ref second, index))) + goto NotEqual; + if (!Unsafe.Add(ref first, index + 1).Equals(Unsafe.Add(ref second, index + 1))) + goto NotEqual; + if (!Unsafe.Add(ref first, index + 2).Equals(Unsafe.Add(ref second, index + 2))) + goto NotEqual; + if (!Unsafe.Add(ref first, index + 3).Equals(Unsafe.Add(ref second, index + 3))) + goto NotEqual; + if (!Unsafe.Add(ref first, index + 4).Equals(Unsafe.Add(ref second, index + 4))) + goto NotEqual; + if (!Unsafe.Add(ref first, index + 5).Equals(Unsafe.Add(ref second, index + 5))) + goto NotEqual; + if (!Unsafe.Add(ref first, index + 6).Equals(Unsafe.Add(ref second, index + 6))) + goto NotEqual; + if (!Unsafe.Add(ref first, index + 7).Equals(Unsafe.Add(ref second, index + 7))) + goto NotEqual; + + index += 8; + } + + if (length >= 4) + { + length -= 4; + + if (!Unsafe.Add(ref first, index).Equals(Unsafe.Add(ref second, index))) + goto NotEqual; + if (!Unsafe.Add(ref first, index + 1).Equals(Unsafe.Add(ref second, index + 1))) + goto NotEqual; + if (!Unsafe.Add(ref first, index + 2).Equals(Unsafe.Add(ref second, index + 2))) + goto NotEqual; + if (!Unsafe.Add(ref first, index + 3).Equals(Unsafe.Add(ref second, index + 3))) + goto NotEqual; + + index += 4; + } + + while (length > 0) + { + if (!Unsafe.Add(ref first, index).Equals(Unsafe.Add(ref second, index))) + goto NotEqual; + index += 1; + length--; + } + + Equal: + return true; + + NotEqual: // Workaround for https://github.com/dotnet/coreclr/issues/13549 + return false; + } + + public static int SequenceCompareTo(ref T first, int firstLength, ref T second, int secondLength) + where T : IComparable + { + Debug.Assert(firstLength >= 0); + Debug.Assert(secondLength >= 0); + + var minLength = firstLength; + if (minLength > secondLength) minLength = secondLength; + for (int i = 0; i < minLength; i++) + { + int result = Unsafe.Add(ref first, i).CompareTo(Unsafe.Add(ref second, i)); + if (result != 0) return result; + } + return firstLength.CompareTo(secondLength); + } + } +} diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Span.NonGeneric.cs b/external/corert/src/System.Private.CoreLib/shared/System/SpanHelpers.cs similarity index 65% rename from external/corert/src/System.Private.CoreLib/shared/System/Span.NonGeneric.cs rename to external/corert/src/System.Private.CoreLib/shared/System/SpanHelpers.cs index 775426f6b1..dad0f6294c 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Span.NonGeneric.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/SpanHelpers.cs @@ -3,8 +3,8 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Globalization; using System.Runtime; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Internal.Runtime.CompilerServices; @@ -17,196 +17,137 @@ using nuint = System.UInt32; namespace System { - /// - /// Extension methods and non-generic helpers for Span, ReadOnlySpan, Memory, and ReadOnlyMemory. - /// - public static class Span + internal static partial class SpanHelpers { - /// Creates a new over the portion of the target string. - /// The target string. - /// Thrown when is a null reference (Nothing in Visual Basic). - public static ReadOnlyMemory AsReadOnlyMemory(this string text) + public static int IndexOfCultureHelper(ReadOnlySpan span, ReadOnlySpan value, CompareInfo compareInfo) { - if (text == null) + Debug.Assert(span.Length != 0); + Debug.Assert(value.Length != 0); + + if (GlobalizationMode.Invariant) { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.text); + return CompareInfo.InvariantIndexOf(span, value, ignoreCase: false); } - return new ReadOnlyMemory(text, 0, text.Length); + return compareInfo.IndexOf(span, value, CompareOptions.None); } - /// Attempts to get the underlying from a . - /// The memory that may be wrapping a object. - /// The string. - /// The starting location in . - /// The number of items in . - /// - public static bool TryGetString(this ReadOnlyMemory readOnlyMemory, out string text, out int start, out int length) + public static int IndexOfCultureIgnoreCaseHelper(ReadOnlySpan span, ReadOnlySpan value, CompareInfo compareInfo) { - if (readOnlyMemory.GetObjectStartLength(out int offset, out int count) is string s) + Debug.Assert(span.Length != 0); + Debug.Assert(value.Length != 0); + + if (GlobalizationMode.Invariant) { - text = s; - start = offset; - length = count; - return true; + return CompareInfo.InvariantIndexOf(span, value, ignoreCase: true); } - else + + return compareInfo.IndexOf(span, value, CompareOptions.IgnoreCase); + } + + public static int IndexOfOrdinalHelper(ReadOnlySpan span, ReadOnlySpan value, bool ignoreCase) + { + Debug.Assert(span.Length != 0); + Debug.Assert(value.Length != 0); + + if (GlobalizationMode.Invariant) + { + return CompareInfo.InvariantIndexOf(span, value, ignoreCase); + } + + return CompareInfo.Invariant.IndexOfOrdinal(span, value, ignoreCase); + } + + public static bool StartsWithCultureHelper(ReadOnlySpan span, ReadOnlySpan value, CompareInfo compareInfo) + { + Debug.Assert(value.Length != 0); + + if (GlobalizationMode.Invariant) + { + return span.StartsWith(value); + } + if (span.Length == 0) { - text = null; - start = 0; - length = 0; return false; } + return compareInfo.IsPrefix(span, value, CompareOptions.None); } - /// - /// Casts a Span of one primitive type to Span of bytes. - /// That type may not contain pointers or references. This is checked at runtime in order to preserve type safety. - /// - /// The source slice, of type . - /// - /// Thrown when contains pointers. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Span AsBytes(this Span source) - where T : struct + public static bool StartsWithCultureIgnoreCaseHelper(ReadOnlySpan span, ReadOnlySpan value, CompareInfo compareInfo) { - if (RuntimeHelpers.IsReferenceOrContainsReferences()) - ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T)); + Debug.Assert(value.Length != 0); - return new Span( - ref Unsafe.As(ref MemoryMarshal.GetReference(source)), - checked(source.Length * Unsafe.SizeOf())); - } - - /// - /// Casts a ReadOnlySpan of one primitive type to ReadOnlySpan of bytes. - /// That type may not contain pointers or references. This is checked at runtime in order to preserve type safety. - /// - /// The source slice, of type . - /// - /// Thrown when contains pointers. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ReadOnlySpan AsBytes(this ReadOnlySpan source) - where T : struct - { - if (RuntimeHelpers.IsReferenceOrContainsReferences()) - ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T)); - - return new ReadOnlySpan( - ref Unsafe.As(ref MemoryMarshal.GetReference(source)), - checked(source.Length * Unsafe.SizeOf())); - } - - /// - /// Casts a Span of one primitive type to another primitive type . - /// These types may not contain pointers or references. This is checked at runtime in order to preserve type safety. - /// - /// - /// Supported only for platforms that support misaligned memory access. - /// - /// The source slice, of type . - /// - /// Thrown when or contains pointers. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Span NonPortableCast(this Span source) - where TFrom : struct - where TTo : struct - { - if (RuntimeHelpers.IsReferenceOrContainsReferences()) - ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TFrom)); - if (RuntimeHelpers.IsReferenceOrContainsReferences()) - ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TTo)); - - return new Span( - ref Unsafe.As(ref source.DangerousGetPinnableReference()), - checked((int)((long)source.Length * Unsafe.SizeOf() / Unsafe.SizeOf()))); - } - - /// - /// Casts a ReadOnlySpan of one primitive type to another primitive type . - /// These types may not contain pointers or references. This is checked at runtime in order to preserve type safety. - /// - /// - /// Supported only for platforms that support misaligned memory access. - /// - /// The source slice, of type . - /// - /// Thrown when or contains pointers. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ReadOnlySpan NonPortableCast(this ReadOnlySpan source) - where TFrom : struct - where TTo : struct - { - if (RuntimeHelpers.IsReferenceOrContainsReferences()) - ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TFrom)); - if (RuntimeHelpers.IsReferenceOrContainsReferences()) - ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TTo)); - - return new ReadOnlySpan( - ref Unsafe.As(ref MemoryMarshal.GetReference(source)), - checked((int)((long)source.Length * Unsafe.SizeOf() / Unsafe.SizeOf()))); - } - - /// - /// Creates a new readonly span over the portion of the target string. - /// - /// The target string. - /// Thrown when is a null - /// reference (Nothing in Visual Basic). - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ReadOnlySpan AsReadOnlySpan(this string text) - { - if (text == null) - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.text); - - return new ReadOnlySpan(ref text.GetRawStringData(), text.Length); - } - - internal static unsafe void CopyTo(ref T destination, ref T source, int elementsCount) - { - if (Unsafe.AreSame(ref destination, ref source)) - return; - - if (elementsCount <= 1) + if (GlobalizationMode.Invariant) { - if (elementsCount == 1) - { - destination = source; - } - return; + return StartsWithOrdinalIgnoreCaseHelper(span, value); } - - nuint byteCount = (nuint)elementsCount * (nuint)Unsafe.SizeOf(); - if (!RuntimeHelpers.IsReferenceOrContainsReferences()) + if (span.Length == 0) { - fixed (byte* pDestination = &Unsafe.As(ref destination)) - { - fixed (byte* pSource = &Unsafe.As(ref source)) - { - Buffer.Memmove(pDestination, pSource, byteCount); - } - } - } - else - { - RuntimeImports.RhBulkMoveWithWriteBarrier( - ref Unsafe.As(ref destination), - ref Unsafe.As(ref source), - byteCount); + return false; } + return compareInfo.IsPrefix(span, value, CompareOptions.IgnoreCase); } - internal static unsafe void ClearWithoutReferences(ref byte b, nuint byteLength) + public static bool StartsWithOrdinalIgnoreCaseHelper(ReadOnlySpan span, ReadOnlySpan value) + { + Debug.Assert(value.Length != 0); + + if (span.Length < value.Length) + { + return false; + } + return CompareInfo.CompareOrdinalIgnoreCase(span.Slice(0, value.Length), value) == 0; + } + + public static bool EndsWithCultureHelper(ReadOnlySpan span, ReadOnlySpan value, CompareInfo compareInfo) + { + Debug.Assert(value.Length != 0); + + if (GlobalizationMode.Invariant) + { + return span.EndsWith(value); + } + if (span.Length == 0) + { + return false; + } + return compareInfo.IsSuffix(span, value, CompareOptions.None); + } + + public static bool EndsWithCultureIgnoreCaseHelper(ReadOnlySpan span, ReadOnlySpan value, CompareInfo compareInfo) + { + Debug.Assert(value.Length != 0); + + if (GlobalizationMode.Invariant) + { + return EndsWithOrdinalIgnoreCaseHelper(span, value); + } + if (span.Length == 0) + { + return false; + } + return compareInfo.IsSuffix(span, value, CompareOptions.IgnoreCase); + } + + public static bool EndsWithOrdinalIgnoreCaseHelper(ReadOnlySpan span, ReadOnlySpan value) + { + Debug.Assert(value.Length != 0); + + if (span.Length < value.Length) + { + return false; + } + return (CompareInfo.CompareOrdinalIgnoreCase(span.Slice(span.Length - value.Length), value) == 0); + } + + public static unsafe void ClearWithoutReferences(ref byte b, nuint byteLength) { if (byteLength == 0) return; - + #if CORECLR && (AMD64 || ARM64) - if (byteLength > 4096) goto PInvoke; + if (byteLength > 4096) + goto PInvoke; Unsafe.InitBlockUnaligned(ref b, 0, (uint)byteLength); return; #else @@ -513,12 +454,12 @@ namespace System return; #endif - - PInvoke: + + PInvoke: RuntimeImports.RhZeroMemory(ref b, byteLength); } - internal static unsafe void ClearWithReferences(ref IntPtr ip, nuint pointerSizeLength) + public static unsafe void ClearWithReferences(ref IntPtr ip, nuint pointerSizeLength) { if (pointerSizeLength == 0) return; diff --git a/external/corert/src/System.Private.CoreLib/src/System/String.Manipulation.cs b/external/corert/src/System.Private.CoreLib/shared/System/String.Manipulation.cs similarity index 73% rename from external/corert/src/System.Private.CoreLib/src/System/String.Manipulation.cs rename to external/corert/src/System.Private.CoreLib/shared/System/String.Manipulation.cs index f069b39425..94f34b5829 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/String.Manipulation.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/String.Manipulation.cs @@ -2,20 +2,25 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Buffers; using System.Collections.Generic; -using System.Diagnostics; +using System.Diagnostics.Private; using System.Globalization; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Text; - using Internal.Runtime.CompilerServices; namespace System { public partial class String { - unsafe private static void FillStringChecked(String dest, int destPos, String src) + private const int StackallocIntBufferSizeLimit = 128; + + private static unsafe void FillStringChecked(string dest, int destPos, string src) { + Debug.Assert(dest != null); + Debug.Assert(src != null); if (src.Length > dest.Length - destPos) { throw new IndexOutOfRangeException(); @@ -28,44 +33,44 @@ namespace System } } - public static String Concat(Object arg0) + public static string Concat(object arg0) { if (arg0 == null) { - return String.Empty; + return string.Empty; } return arg0.ToString(); } - public static String Concat(Object arg0, Object arg1) + public static string Concat(object arg0, object arg1) { if (arg0 == null) { - arg0 = String.Empty; + arg0 = string.Empty; } if (arg1 == null) { - arg1 = String.Empty; + arg1 = string.Empty; } return Concat(arg0.ToString(), arg1.ToString()); } - public static String Concat(Object arg0, Object arg1, Object arg2) + public static string Concat(object arg0, object arg1, object arg2) { if (arg0 == null) { - arg0 = String.Empty; + arg0 = string.Empty; } if (arg1 == null) { - arg1 = String.Empty; + arg1 = string.Empty; } if (arg2 == null) { - arg2 = String.Empty; + arg2 = string.Empty; } return Concat(arg0.ToString(), arg1.ToString(), arg2.ToString()); @@ -250,13 +255,13 @@ namespace System } } - public static String Concat(String str0, String str1) + public static string Concat(string str0, string str1) { if (IsNullOrEmpty(str0)) { if (IsNullOrEmpty(str1)) { - return String.Empty; + return string.Empty; } return str1; } @@ -268,7 +273,7 @@ namespace System int str0Length = str0.Length; - String result = FastAllocateString(str0Length + str1.Length); + string result = FastAllocateString(str0Length + str1.Length); FillStringChecked(result, 0, str0); FillStringChecked(result, str0Length, str1); @@ -276,7 +281,7 @@ namespace System return result; } - public static String Concat(String str0, String str1, String str2) + public static string Concat(string str0, string str1, string str2) { if (IsNullOrEmpty(str0)) { @@ -295,7 +300,7 @@ namespace System int totalLength = str0.Length + str1.Length + str2.Length; - String result = FastAllocateString(totalLength); + string result = FastAllocateString(totalLength); FillStringChecked(result, 0, str0); FillStringChecked(result, str0.Length, str1); FillStringChecked(result, str0.Length + str1.Length, str2); @@ -303,7 +308,7 @@ namespace System return result; } - public static String Concat(String str0, String str1, String str2, String str3) + public static string Concat(string str0, string str1, string str2, string str3) { if (IsNullOrEmpty(str0)) { @@ -327,7 +332,7 @@ namespace System int totalLength = str0.Length + str1.Length + str2.Length + str3.Length; - String result = FastAllocateString(totalLength); + string result = FastAllocateString(totalLength); FillStringChecked(result, 0, str0); FillStringChecked(result, str0.Length, str1); FillStringChecked(result, str0.Length + str1.Length, str2); @@ -336,7 +341,7 @@ namespace System return result; } - public static String Concat(params String[] values) + public static string Concat(params string[] values) { if (values == null) throw new ArgumentNullException(nameof(values)); @@ -404,7 +409,22 @@ namespace System return copiedLength == totalLength ? result : Concat((string[])values.Clone()); } - public static String Format(String format, params Object[] args) + public static string Format(string format, object arg0) + { + return FormatHelper(null, format, new ParamsArray(arg0)); + } + + public static string Format(string format, object arg0, object arg1) + { + return FormatHelper(null, format, new ParamsArray(arg0, arg1)); + } + + public static string Format(string format, object arg0, object arg1, object arg2) + { + return FormatHelper(null, format, new ParamsArray(arg0, arg1, arg2)); + } + + public static string Format(string format, params object[] args) { if (args == null) { @@ -416,22 +436,22 @@ namespace System return FormatHelper(null, format, new ParamsArray(args)); } - public static String Format(String format, Object arg0) + public static string Format(IFormatProvider provider, string format, object arg0) { - return FormatHelper(null, format, new ParamsArray(arg0)); + return FormatHelper(provider, format, new ParamsArray(arg0)); } - public static String Format(String format, Object arg0, Object arg1) + public static string Format(IFormatProvider provider, string format, object arg0, object arg1) { - return FormatHelper(null, format, new ParamsArray(arg0, arg1)); + return FormatHelper(provider, format, new ParamsArray(arg0, arg1)); } - public static String Format(String format, Object arg0, Object arg1, Object arg2) + public static string Format(IFormatProvider provider, string format, object arg0, object arg1, object arg2) { - return FormatHelper(null, format, new ParamsArray(arg0, arg1, arg2)); + return FormatHelper(provider, format, new ParamsArray(arg0, arg1, arg2)); } - public static String Format(IFormatProvider provider, String format, params Object[] args) + public static string Format(IFormatProvider provider, string format, params object[] args) { if (args == null) { @@ -443,22 +463,7 @@ namespace System return FormatHelper(provider, format, new ParamsArray(args)); } - public static String Format(IFormatProvider provider, String format, Object arg0) - { - return FormatHelper(provider, format, new ParamsArray(arg0)); - } - - public static String Format(IFormatProvider provider, String format, Object arg0, Object arg1) - { - return FormatHelper(provider, format, new ParamsArray(arg0, arg1)); - } - - public static String Format(IFormatProvider provider, String format, Object arg0, Object arg1, Object arg2) - { - return FormatHelper(provider, format, new ParamsArray(arg0, arg1, arg2)); - } - - private static String FormatHelper(IFormatProvider provider, String format, ParamsArray args) + private static string FormatHelper(IFormatProvider provider, string format, ParamsArray args) { if (format == null) throw new ArgumentNullException(nameof(format)); @@ -469,7 +474,7 @@ namespace System .AppendFormatHelper(provider, format, args)); } - public String Insert(int startIndex, String value) + public string Insert(int startIndex, string value) { if (value == null) throw new ArgumentNullException(nameof(value)); @@ -484,10 +489,9 @@ namespace System if (insertLength == 0) return this; + // In case this computation overflows, newLength will be negative and FastAllocateString throws OutOfMemoryException int newLength = oldLength + insertLength; - if (newLength < 0) - throw new OutOfMemoryException(); - String result = FastAllocateString(newLength); + string result = FastAllocateString(newLength); unsafe { fixed (char* srcThis = &_firstChar) @@ -810,12 +814,9 @@ namespace System JoinCore(separator, separatorLength, (string[])value.Clone(), startIndex, count); } - public String PadLeft(int totalWidth) - { - return PadLeft(totalWidth, ' '); - } + public string PadLeft(int totalWidth) => PadLeft(totalWidth, ' '); - public String PadLeft(int totalWidth, char paddingChar) + public string PadLeft(int totalWidth, char paddingChar) { if (totalWidth < 0) throw new ArgumentOutOfRangeException(nameof(totalWidth), SR.ArgumentOutOfRange_NeedNonNegNum); @@ -823,7 +824,7 @@ namespace System int count = totalWidth - oldLength; if (count <= 0) return this; - String result = FastAllocateString(totalWidth); + string result = FastAllocateString(totalWidth); unsafe { fixed (char* dst = &result._firstChar) @@ -839,12 +840,9 @@ namespace System return result; } - public String PadRight(int totalWidth) - { - return PadRight(totalWidth, ' '); - } + public string PadRight(int totalWidth) => PadRight(totalWidth, ' '); - public String PadRight(int totalWidth, char paddingChar) + public string PadRight(int totalWidth, char paddingChar) { if (totalWidth < 0) throw new ArgumentOutOfRangeException(nameof(totalWidth), SR.ArgumentOutOfRange_NeedNonNegNum); @@ -852,7 +850,7 @@ namespace System int count = totalWidth - oldLength; if (count <= 0) return this; - String result = FastAllocateString(totalWidth); + string result = FastAllocateString(totalWidth); unsafe { fixed (char* dst = &result._firstChar) @@ -868,7 +866,7 @@ namespace System return result; } - public String Remove(int startIndex, int count) + public string Remove(int startIndex, int count) { if (startIndex < 0) throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_StartIndex); @@ -884,7 +882,7 @@ namespace System if (newLength == 0) return string.Empty; - String result = FastAllocateString(newLength); + string result = FastAllocateString(newLength); unsafe { fixed (char* src = &_firstChar) @@ -903,16 +901,10 @@ namespace System public string Remove(int startIndex) { if (startIndex < 0) - { - throw new ArgumentOutOfRangeException(nameof(startIndex), - SR.ArgumentOutOfRange_StartIndex); - } + throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_StartIndex); if (startIndex >= Length) - { - throw new ArgumentOutOfRangeException(nameof(startIndex), - SR.ArgumentOutOfRange_StartIndexLessThanLength); - } + throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_StartIndexLessThanLength); return Substring(0, startIndex); } @@ -939,7 +931,7 @@ namespace System return ReplaceCore(oldValue, newValue, CultureInfo.InvariantCulture, CompareOptions.IgnoreCase); case StringComparison.Ordinal: - return ReplaceCore(oldValue, newValue, CultureInfo.InvariantCulture, CompareOptions.Ordinal); + return Replace(oldValue, newValue); case StringComparison.OrdinalIgnoreCase: return ReplaceCore(oldValue, newValue, CultureInfo.InvariantCulture, CompareOptions.OrdinalIgnoreCase); @@ -949,7 +941,7 @@ namespace System } } - private unsafe String ReplaceCore(string oldValue, string newValue, CultureInfo culture, CompareOptions options) + private unsafe string ReplaceCore(string oldValue, string newValue, CultureInfo culture, CompareOptions options) { if (oldValue == null) throw new ArgumentNullException(nameof(oldValue)); @@ -974,7 +966,7 @@ namespace System do { - index = ci.IndexOf(this, oldValue, startIndex, _stringLength - startIndex, options, &matchLength); + index = ci.IndexOf(this, oldValue, startIndex, this.Length - startIndex, options, &matchLength); if (index >= 0) { // append the unmodified portion of string @@ -991,11 +983,12 @@ namespace System // small optimization, // if we have not done any replacements, // we will return the original string + StringBuilderCache.Release(result); return this; } else { - result.Append(this, startIndex, _stringLength - startIndex); + result.Append(this, startIndex, this.Length - startIndex); } } while (index >= 0); @@ -1004,7 +997,7 @@ namespace System // Replaces all instances of oldChar with newChar. // - public String Replace(char oldChar, char newChar) + public string Replace(char oldChar, char newChar) { if (oldChar == newChar) return this; @@ -1032,7 +1025,7 @@ namespace System if (remainingLength == 0) return this; - String result = FastAllocateString(Length); + string result = FastAllocateString(Length); fixed (char* pChars = &_firstChar) { @@ -1068,117 +1061,122 @@ namespace System } } - public String Replace(String oldValue, String newValue) + public string Replace(string oldValue, string newValue) { + if (oldValue == null) + throw new ArgumentNullException(nameof(oldValue)); + if (oldValue.Length == 0) + throw new ArgumentException(SR.Argument_StringZeroLength, nameof(oldValue)); + + // Api behavior: if newValue is null, instances of oldValue are to be removed. + if (newValue == null) + newValue = string.Empty; + + Span initialSpan = stackalloc int[StackallocIntBufferSizeLimit]; + var replacementIndices = new ValueListBuilder(initialSpan); + unsafe { - if (oldValue == null) - throw new ArgumentNullException(nameof(oldValue)); - if (oldValue.Length == 0) - throw new ArgumentException(SR.Format(SR.Argument_StringZeroLength, nameof(oldValue))); - // Api behavior: if newValue is null, instances of oldValue are to be removed. - if (newValue == null) - newValue = String.Empty; - - int numOccurrences = 0; - int[] replacementIndices = new int[this.Length]; fixed (char* pThis = &_firstChar) { - fixed (char* pOldValue = &oldValue._firstChar) + int matchIdx = 0; + int lastPossibleMatchIdx = this.Length - oldValue.Length; + while (matchIdx <= lastPossibleMatchIdx) { - int idx = 0; - int lastPossibleMatchIdx = this.Length - oldValue.Length; - while (idx <= lastPossibleMatchIdx) + char* pMatch = pThis + matchIdx; + for (int probeIdx = 0; probeIdx < oldValue.Length; probeIdx++) { - int probeIdx = idx; - int oldValueIdx = 0; - bool foundMismatch = false; - while (oldValueIdx < oldValue.Length) + if (pMatch[probeIdx] != oldValue[probeIdx]) { - Debug.Assert(probeIdx >= 0 && probeIdx < this.Length); - Debug.Assert(oldValueIdx >= 0 && oldValueIdx < oldValue.Length); - if (pThis[probeIdx] != pOldValue[oldValueIdx]) - { - foundMismatch = true; - break; - } - probeIdx++; - oldValueIdx++; - } - if (!foundMismatch) - { - // Found a match for the string. Record the location of the match and skip over the "oldValue." - replacementIndices[numOccurrences++] = idx; - Debug.Assert(probeIdx == idx + oldValue.Length); - idx = probeIdx; - } - else - { - idx++; + goto Next; } } + // Found a match for the string. Record the location of the match and skip over the "oldValue." + replacementIndices.Append(matchIdx); + matchIdx += oldValue.Length; + continue; + + Next: + matchIdx++; } } - - if (numOccurrences == 0) - return this; - - int dstLength = checked(this.Length + (newValue.Length - oldValue.Length) * numOccurrences); - String dst = FastAllocateString(dstLength); - fixed (char* pThis = &_firstChar) - { - fixed (char* pDst = &dst._firstChar) - { - fixed (char* pNewValue = &newValue._firstChar) - { - int dstIdx = 0; - int thisIdx = 0; - - for (int r = 0; r < numOccurrences; r++) - { - int replacementIdx = replacementIndices[r]; - - // Copy over the non-matching portion of the original that precedes this occurrence of oldValue. - int count = replacementIdx - thisIdx; - Debug.Assert(count >= 0); - Debug.Assert(thisIdx >= 0 && thisIdx <= this.Length - count); - Debug.Assert(dstIdx >= 0 && dstIdx <= dst.Length - count); - if (count != 0) - { - wstrcpy(&(pDst[dstIdx]), &(pThis[thisIdx]), count); - dstIdx += count; - } - thisIdx = replacementIdx + oldValue.Length; - - // Copy over newValue to replace the oldValue. - Debug.Assert(thisIdx >= 0 && thisIdx <= this.Length); - Debug.Assert(dstIdx >= 0 && dstIdx <= dst.Length - newValue.Length); - wstrcpy(&(pDst[dstIdx]), pNewValue, newValue.Length); - dstIdx += newValue.Length; - } - - // Copy over the final non-matching portion at the end of the string. - int tailLength = this.Length - thisIdx; - Debug.Assert(tailLength >= 0); - Debug.Assert(thisIdx == this.Length - tailLength); - Debug.Assert(dstIdx == dst.Length - tailLength); - wstrcpy(&(pDst[dstIdx]), &(pThis[thisIdx]), tailLength); - } - } - } - - return dst; } + + if (replacementIndices.Length == 0) + return this; + + // String allocation and copying is in separate method to make this method faster for the case where + // nothing needs replacing. + string dst = ReplaceHelper(oldValue.Length, newValue, replacementIndices.AsSpan()); + + replacementIndices.Dispose(); + + return dst; } - public unsafe String[] Split(char separator, StringSplitOptions options = StringSplitOptions.None) + private string ReplaceHelper(int oldValueLength, string newValue, ReadOnlySpan indices) { - return SplitInternal(&separator, 1, int.MaxValue, options); + Debug.Assert(indices.Length > 0); + + long dstLength = this.Length + ((long)(newValue.Length - oldValueLength)) * indices.Length; + if (dstLength > int.MaxValue) + throw new OutOfMemoryException(); + string dst = FastAllocateString((int)dstLength); + +#if FEATURE_PORTABLE_SPAN + Span dstSpan = new Span(Unsafe.As>(dst), MemoryExtensions.StringAdjustment, dst.Length); +#else + Span dstSpan = new Span(ref dst.GetRawStringData(), dst.Length); +#endif + + int thisIdx = 0; + int dstIdx = 0; + + for (int r = 0; r < indices.Length; r++) + { + int replacementIdx = indices[r]; + + // Copy over the non-matching portion of the original that precedes this occurrence of oldValue. + int count = replacementIdx - thisIdx; + if (count != 0) + { + this.AsSpan().Slice(thisIdx, count).CopyTo(dstSpan.Slice(dstIdx)); + dstIdx += count; + } + thisIdx = replacementIdx + oldValueLength; + + // Copy over newValue to replace the oldValue. + newValue.AsSpan().CopyTo(dstSpan.Slice(dstIdx)); + dstIdx += newValue.Length; + } + + // Copy over the final non-matching portion at the end of the string. + Debug.Assert(this.Length - thisIdx == dstSpan.Length - dstIdx); + this.AsSpan().Slice(thisIdx).CopyTo(dstSpan.Slice(dstIdx)); + + return dst; } - public unsafe String[] Split(char separator, int count, StringSplitOptions options = StringSplitOptions.None) + public string[] Split(char separator, StringSplitOptions options = StringSplitOptions.None) { - return SplitInternal(&separator, 1, count, options); +#if FEATURE_PORTABLE_SPAN + var srcSpan = new ReadOnlySpan(Unsafe.As>(separator), IntPtr.Zero, 1); +#else + var srcSpan = new ReadOnlySpan(ref separator, 1) +#endif + + return SplitInternal(srcSpan, int.MaxValue, options); + } + + public string[] Split(char separator, int count, StringSplitOptions options = StringSplitOptions.None) + { +#if FEATURE_PORTABLE_SPAN + var srcSpan = new ReadOnlySpan(Unsafe.As>(separator), IntPtr.Zero, 1); +#else + var srcSpan = new ReadOnlySpan(ref separator, 1) +#endif + + return SplitInternal(srcSpan, count, options); } // Creates an array of strings by splitting this string at each @@ -1190,9 +1188,9 @@ namespace System // If the separator is null // whitespace (i.e., Character.IsWhitespace) is used as the separator. // - public String[] Split(params char[] separator) + public string[] Split(params char[] separator) { - return SplitInternal(separator, Int32.MaxValue, StringSplitOptions.None); + return SplitInternal(separator, int.MaxValue, StringSplitOptions.None); } // Creates an array of strings by splitting this string at each @@ -1201,36 +1199,27 @@ namespace System // the array of strings. We then continue in this manner by searching // the substring that follows the occurrence. On the other hand, if the separator // is not found, the array of strings will contain this instance as its only element. - // If the separator is the empty string (i.e., String.Empty), then + // If the separator is the empty string (i.e., string.Empty), then // whitespace (i.e., Character.IsWhitespace) is used as the separator. // If there are more than count different strings, the last n-(count-1) - // elements are concatenated and added as the last String. + // elements are concatenated and added as the last string. // public string[] Split(char[] separator, int count) { return SplitInternal(separator, count, StringSplitOptions.None); } - public String[] Split(char[] separator, StringSplitOptions options) + public string[] Split(char[] separator, StringSplitOptions options) { - return SplitInternal(separator, Int32.MaxValue, options); + return SplitInternal(separator, int.MaxValue, options); } - public String[] Split(char[] separator, int count, StringSplitOptions options) + public string[] Split(char[] separator, int count, StringSplitOptions options) { return SplitInternal(separator, count, options); } - private unsafe String[] SplitInternal(char[] separator, int count, StringSplitOptions options) - { - fixed (char* pSeparators = separator) - { - int separatorsLength = separator == null ? 0 : separator.Length; - return SplitInternal(pSeparators, separatorsLength, count, options); - } - } - - private unsafe String[] SplitInternal(char* separators, int separatorsLength, int count, StringSplitOptions options) + private string[] SplitInternal(ReadOnlySpan separators, int count, StringSplitOptions options) { if (count < 0) throw new ArgumentOutOfRangeException(nameof(count), @@ -1241,56 +1230,58 @@ namespace System bool omitEmptyEntries = (options == StringSplitOptions.RemoveEmptyEntries); - if ((count == 0) || (omitEmptyEntries && this.Length == 0)) + if ((count == 0) || (omitEmptyEntries && Length == 0)) { - return Array.Empty(); + return Array.Empty(); } if (count == 1) { - return new String[] { this }; + return new string[] { this }; } - int[] sepList = new int[Length]; - int numReplaces = MakeSeparatorList(separators, separatorsLength, sepList); + Span initialSpan = stackalloc int[StackallocIntBufferSizeLimit]; + var sepListBuilder = new ValueListBuilder(initialSpan); + + MakeSeparatorList(separators, ref sepListBuilder); + ReadOnlySpan sepList = sepListBuilder.AsSpan(); // Handle the special case of no replaces. - if (0 == numReplaces) + if (sepList.Length == 0) { - return new String[] { this }; + return new string[] { this }; } - if (omitEmptyEntries) - { - return SplitOmitEmptyEntries(sepList, null, 1, numReplaces, count); - } - else - { - return SplitKeepEmptyEntries(sepList, null, 1, numReplaces, count); - } + string[] result = omitEmptyEntries + ? SplitOmitEmptyEntries(sepList, default, 1, count) + : SplitKeepEmptyEntries(sepList, default, 1, count); + + sepListBuilder.Dispose(); + + return result; } - public String[] Split(String separator, StringSplitOptions options = StringSplitOptions.None) + public string[] Split(string separator, StringSplitOptions options = StringSplitOptions.None) { - return SplitInternal(separator ?? String.Empty, null, Int32.MaxValue, options); + return SplitInternal(separator ?? string.Empty, null, int.MaxValue, options); } - public String[] Split(String separator, Int32 count, StringSplitOptions options = StringSplitOptions.None) + public string[] Split(string separator, Int32 count, StringSplitOptions options = StringSplitOptions.None) { - return SplitInternal(separator ?? String.Empty, null, count, options); + return SplitInternal(separator ?? string.Empty, null, count, options); } - public String[] Split(String[] separator, StringSplitOptions options) + public string[] Split(string[] separator, StringSplitOptions options) { - return SplitInternal(null, separator, Int32.MaxValue, options); + return SplitInternal(null, separator, int.MaxValue, options); } - public String[] Split(String[] separator, Int32 count, StringSplitOptions options) + public string[] Split(string[] separator, Int32 count, StringSplitOptions options) { return SplitInternal(null, separator, count, options); } - private String[] SplitInternal(String separator, String[] separators, Int32 count, StringSplitOptions options) + private string[] SplitInternal(string separator, string[] separators, int count, StringSplitOptions options) { if (count < 0) { @@ -1312,74 +1303,87 @@ namespace System return SplitInternal((char[])null, count, options); } - if ((count == 0) || (omitEmptyEntries && this.Length == 0)) + if ((count == 0) || (omitEmptyEntries && Length == 0)) { - return Array.Empty(); + return Array.Empty(); } if (count == 1 || (singleSeparator && separator.Length == 0)) { - return new String[] { this }; + return new string[] { this }; } - int[] sepList = new int[Length]; - int[] lengthList; - int defaultLength; - int numReplaces; - if (singleSeparator) { - lengthList = null; - defaultLength = separator.Length; - numReplaces = MakeSeparatorList(separator, sepList); - } - else - { - lengthList = new int[Length]; - defaultLength = 0; - numReplaces = MakeSeparatorList(separators, sepList, lengthList); + return SplitInternal(separator, count, options); } + + Span sepListInitialSpan = stackalloc int[StackallocIntBufferSizeLimit]; + var sepListBuilder = new ValueListBuilder(sepListInitialSpan); + Span lengthListInitialSpan = stackalloc int[StackallocIntBufferSizeLimit]; + var lengthListBuilder = new ValueListBuilder(lengthListInitialSpan); + + MakeSeparatorList(separators, ref sepListBuilder, ref lengthListBuilder); + ReadOnlySpan sepList = sepListBuilder.AsSpan(); + ReadOnlySpan lengthList = lengthListBuilder.AsSpan(); + // Handle the special case of no replaces. - if (0 == numReplaces) + if (sepList.Length == 0) { - return new String[] { this }; + return new string[] { this }; } - if (omitEmptyEntries) - { - return SplitOmitEmptyEntries(sepList, lengthList, defaultLength, numReplaces, count); - } - else - { - return SplitKeepEmptyEntries(sepList, lengthList, defaultLength, numReplaces, count); - } + string[] result = omitEmptyEntries + ? SplitOmitEmptyEntries(sepList, lengthList, 0, count) + : SplitKeepEmptyEntries(sepList, lengthList, 0, count); + + sepListBuilder.Dispose(); + lengthListBuilder.Dispose(); + + return result; } - // Note a special case in this function: - // If there is no separator in the string, a string array which only contains - // the original string will be returned regardless of the count. - // - - private String[] SplitKeepEmptyEntries(Int32[] sepList, Int32[] lengthList, Int32 defaultLength, Int32 numReplaces, int count) + private string[] SplitInternal(string separator, int count, StringSplitOptions options) + { + Span sepListInitialSpan = stackalloc int[StackallocIntBufferSizeLimit]; + var sepListBuilder = new ValueListBuilder(sepListInitialSpan); + + MakeSeparatorList(separator, ref sepListBuilder); + ReadOnlySpan sepList = sepListBuilder.AsSpan(); + if (sepList.Length == 0) + { + // there are no separators so sepListBuilder did not rent an array from pool and there is no need to dispose it + return new string[] { this }; + } + + string[] result = options == StringSplitOptions.RemoveEmptyEntries + ? SplitOmitEmptyEntries(sepList, default, separator.Length, count) + : SplitKeepEmptyEntries(sepList, default, separator.Length, count); + + sepListBuilder.Dispose(); + + return result; + } + + private string[] SplitKeepEmptyEntries(ReadOnlySpan sepList, ReadOnlySpan lengthList, int defaultLength, int count) { - Debug.Assert(numReplaces >= 0); Debug.Assert(count >= 2); int currIndex = 0; int arrIndex = 0; count--; - int numActualReplaces = (numReplaces < count) ? numReplaces : count; + int numActualReplaces = (sepList.Length < count) ? sepList.Length : count; //Allocate space for the new array. - //+1 for the string from the end of the last replace to the end of the String. - String[] splitStrings = new String[numActualReplaces + 1]; + //+1 for the string from the end of the last replace to the end of the string. + string[] splitStrings = new string[numActualReplaces + 1]; for (int i = 0; i < numActualReplaces && currIndex < Length; i++) { splitStrings[arrIndex++] = Substring(currIndex, sepList[i] - currIndex); - currIndex = sepList[i] + ((lengthList == null) ? defaultLength : lengthList[i]); + currIndex = sepList[i] + (lengthList.IsEmpty ? defaultLength : lengthList[i]); } //Handle the last string at the end of the array if there is one. @@ -1391,25 +1395,25 @@ namespace System { //We had a separator character at the end of a string. Rather than just allowing //a null character, we'll replace the last element in the array with an empty string. - splitStrings[arrIndex] = String.Empty; + splitStrings[arrIndex] = string.Empty; } return splitStrings; } - // This function will not keep the Empty String - private String[] SplitOmitEmptyEntries(Int32[] sepList, Int32[] lengthList, Int32 defaultLength, Int32 numReplaces, int count) + // This function will not keep the Empty string + private string[] SplitOmitEmptyEntries(ReadOnlySpan sepList, ReadOnlySpan lengthList, int defaultLength, int count) { - Debug.Assert(numReplaces >= 0); Debug.Assert(count >= 2); + int numReplaces = sepList.Length; + // Allocate array to hold items. This array may not be // filled completely in this function, we will create a // new array and copy string references to that new array. - int maxItems = (numReplaces < count) ? (numReplaces + 1) : count; - String[] splitStrings = new String[maxItems]; + string[] splitStrings = new string[maxItems]; int currIndex = 0; int arrIndex = 0; @@ -1420,13 +1424,13 @@ namespace System { splitStrings[arrIndex++] = Substring(currIndex, sepList[i] - currIndex); } - currIndex = sepList[i] + ((lengthList == null) ? defaultLength : lengthList[i]); + currIndex = sepList[i] + (lengthList.IsEmpty ? defaultLength : lengthList[i]); if (arrIndex == count - 1) { // If all the remaining entries at the end are empty, skip them while (i < numReplaces - 1 && currIndex == sepList[++i]) { - currIndex += ((lengthList == null) ? defaultLength : lengthList[i]); + currIndex += (lengthList.IsEmpty ? defaultLength : lengthList[i]); } break; } @@ -1441,10 +1445,10 @@ namespace System splitStrings[arrIndex++] = Substring(currIndex); } - String[] stringArray = splitStrings; + string[] stringArray = splitStrings; if (arrIndex != maxItems) { - stringArray = new String[arrIndex]; + stringArray = new string[arrIndex]; for (int j = 0; j < arrIndex; j++) { stringArray[j] = splitStrings[j]; @@ -1453,145 +1457,158 @@ namespace System return stringArray; } - //-------------------------------------------------------------------- - // This function returns the number of the places within this instance where - // characters in Separator occur. - // Args: separator -- A string containing all of the split characters. - // sepList -- an array of ints for split char indicies. - //-------------------------------------------------------------------- - private unsafe int MakeSeparatorList(char* separators, int separatorsLength, int[] sepList) + /// + /// Uses ValueListBuilder to create list that holds indexes of separators in string. + /// + /// of separator chars + /// to store indexes + /// + private void MakeSeparatorList(ReadOnlySpan separators, ref ValueListBuilder sepListBuilder) { - Debug.Assert(separatorsLength >= 0, "separatorsLength >= 0"); + char sep0, sep1, sep2; - int foundCount = 0; - - if (separators == null || separatorsLength == 0) + switch (separators.Length) { - fixed (char* pwzChars = &_firstChar) - { - //If they passed null or an empty string, look for whitespace. - for (int i = 0; i < Length && foundCount < sepList.Length; i++) + // Special-case no separators to mean any whitespace is a separator. + case 0: + for (int i = 0; i < Length; i++) { - if (Char.IsWhiteSpace(pwzChars[i])) + if (char.IsWhiteSpace(this[i])) { - sepList[foundCount++] = i; + sepListBuilder.Append(i); } } - } - } - else - { - int sepListCount = sepList.Length; - //If they passed in a string of chars, actually look for those chars. - fixed (char* pwzChars = &_firstChar) - { - for (int i = 0; i < Length && foundCount < sepListCount; i++) + break; + + // Special-case the common cases of 1, 2, and 3 separators, with manual comparisons against each separator. + case 1: + sep0 = separators[0]; + for (int i = 0; i < Length; i++) { - char* pSep = separators; - for (int j = 0; j < separatorsLength; j++, pSep++) + if (this[i] == sep0) { - if (pwzChars[i] == *pSep) + sepListBuilder.Append(i); + } + } + break; + case 2: + sep0 = separators[0]; + sep1 = separators[1]; + for (int i = 0; i < Length; i++) + { + char c = this[i]; + if (c == sep0 || c == sep1) + { + sepListBuilder.Append(i); + } + } + break; + case 3: + sep0 = separators[0]; + sep1 = separators[1]; + sep2 = separators[2]; + for (int i = 0; i < Length; i++) + { + char c = this[i]; + if (c == sep0 || c == sep1 || c == sep2) + { + sepListBuilder.Append(i); + } + } + break; + + // Handle > 3 separators with a probabilistic map, ala IndexOfAny. + // This optimizes for chars being unlikely to match a separator. + default: + unsafe + { + ProbabilisticMap map = default; + uint* charMap = (uint*)↦ + InitializeProbabilisticMap(charMap, separators); + + for (int i = 0; i < Length; i++) + { + char c = this[i]; + if (IsCharBitSet(charMap, (byte)c) && IsCharBitSet(charMap, (byte)(c >> 8)) && + separators.Contains(c)) { - sepList[foundCount++] = i; - break; + sepListBuilder.Append(i); } } } - } + break; } - return foundCount; } - //-------------------------------------------------------------------- - // This function returns number of the places within baseString where - // instances of the separator string occurs. - // Args: separator -- the separator - // sepList -- an array of ints for split string indicies. - //-------------------------------------------------------------------- - private unsafe int MakeSeparatorList(string separator, int[] sepList) + /// + /// Uses ValueListBuilder to create list that holds indexes of separators in string. + /// + /// separator string + /// to store indexes + /// + private void MakeSeparatorList(string separator, ref ValueListBuilder sepListBuilder) { - Debug.Assert(!string.IsNullOrEmpty(separator), "!string.IsNullOrEmpty(separator)"); + Debug.Assert(!IsNullOrEmpty(separator), "!string.IsNullOrEmpty(separator)"); - int foundCount = 0; - int sepListCount = sepList.Length; int currentSepLength = separator.Length; - fixed (char* pwzChars = &_firstChar) + for (int i = 0; i < Length; i++) { - for (int i = 0; i < Length && foundCount < sepListCount; i++) + if (this[i] == separator[0] && currentSepLength <= Length - i) { - if (pwzChars[i] == separator[0] && currentSepLength <= Length - i) + if (currentSepLength == 1 + || CompareOrdinal(this, i, separator, 0, currentSepLength) == 0) { - if (currentSepLength == 1 - || String.CompareOrdinal(this, i, separator, 0, currentSepLength) == 0) - { - sepList[foundCount] = i; - foundCount++; - i += currentSepLength - 1; - } + sepListBuilder.Append(i); + i += currentSepLength - 1; } } } - return foundCount; } - //-------------------------------------------------------------------- - // This function returns the number of the places within this instance where - // instances of separator strings occur. - // Args: separators -- An array containing all of the split strings. - // sepList -- an array of ints for split string indicies. - // lengthList -- an array of ints for split string lengths. - //-------------------------------------------------------------------- - private unsafe int MakeSeparatorList(String[] separators, int[] sepList, int[] lengthList) + /// + /// Uses ValueListBuilder to create list that holds indexes of separators in string and list that holds length of separator strings. + /// + /// separator strngs + /// for separator indexes + /// for separator length values + private void MakeSeparatorList(string[] separators, ref ValueListBuilder sepListBuilder, ref ValueListBuilder lengthListBuilder) { Debug.Assert(separators != null && separators.Length > 0, "separators != null && separators.Length > 0"); - int foundCount = 0; - int sepListCount = sepList.Length; int sepCount = separators.Length; - fixed (char* pwzChars = &_firstChar) + for (int i = 0; i < Length; i++) { - for (int i = 0; i < Length && foundCount < sepListCount; i++) + for (int j = 0; j < separators.Length; j++) { - for (int j = 0; j < separators.Length; j++) + string separator = separators[j]; + if (IsNullOrEmpty(separator)) { - String separator = separators[j]; - if (String.IsNullOrEmpty(separator)) + continue; + } + int currentSepLength = separator.Length; + if (this[i] == separator[0] && currentSepLength <= Length - i) + { + if (currentSepLength == 1 + || CompareOrdinal(this, i, separator, 0, currentSepLength) == 0) { - continue; - } - Int32 currentSepLength = separator.Length; - if (pwzChars[i] == separator[0] && currentSepLength <= Length - i) - { - if (currentSepLength == 1 - || String.CompareOrdinal(this, i, separator, 0, currentSepLength) == 0) - { - sepList[foundCount] = i; - lengthList[foundCount] = currentSepLength; - foundCount++; - i += currentSepLength - 1; - break; - } + sepListBuilder.Append(i); + lengthListBuilder.Append(currentSepLength); + i += currentSepLength - 1; + break; } } } } - return foundCount; } // Returns a substring of this string. // - public String Substring(int startIndex) - { - return this.Substring(startIndex, Length - startIndex); - } + public string Substring(int startIndex) => Substring(startIndex, Length - startIndex); - // Returns a substring of this string. - // - public String Substring(int startIndex, int length) + public string Substring(int startIndex, int length) { - //Bounds Checking. if (startIndex < 0) { throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_StartIndex); @@ -1614,7 +1631,7 @@ namespace System if (length == 0) { - return String.Empty; + return string.Empty; } if (startIndex == 0 && length == this.Length) @@ -1627,7 +1644,10 @@ namespace System private unsafe string InternalSubString(int startIndex, int length) { - String result = FastAllocateString(length); + Debug.Assert(startIndex >= 0 && startIndex <= this.Length, "StartIndex is out of range!"); + Debug.Assert(length >= 0 && startIndex <= this.Length - length, "length is out of range!"); + + string result = FastAllocateString(length); fixed (char* dest = &result._firstChar) fixed (char* src = &_firstChar) @@ -1639,13 +1659,13 @@ namespace System } // Creates a copy of this string in lower case. The culture is set by culture. - public String ToLower() + public string ToLower() { return CultureInfo.CurrentCulture.TextInfo.ToLower(this); } // Creates a copy of this string in lower case. The culture is set by culture. - public String ToLower(CultureInfo culture) + public string ToLower(CultureInfo culture) { if (culture == null) { @@ -1655,18 +1675,18 @@ namespace System } // Creates a copy of this string in lower case based on invariant culture. - public String ToLowerInvariant() + public string ToLowerInvariant() { return CultureInfo.InvariantCulture.TextInfo.ToLower(this); } - public String ToUpper() + public string ToUpper() { return CultureInfo.CurrentCulture.TextInfo.ToUpper(this); } // Creates a copy of this string in upper case. The culture is set by culture. - public String ToUpper(CultureInfo culture) + public string ToUpper(CultureInfo culture) { if (culture == null) { @@ -1676,7 +1696,7 @@ namespace System } //Creates a copy of this string in upper case based on invariant culture. - public String ToUpperInvariant() + public string ToUpperInvariant() { return CultureInfo.InvariantCulture.TextInfo.ToUpper(this); } diff --git a/external/corert/src/System.Private.CoreLib/shared/System/String.Searching.cs b/external/corert/src/System.Private.CoreLib/shared/System/String.Searching.cs index 5aa002b724..c86d135246 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/String.Searching.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/String.Searching.cs @@ -3,7 +3,10 @@ // See the LICENSE file in the project root for more information. using System.Globalization; +using System.Numerics; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using Internal.Runtime.CompilerServices; namespace System { @@ -53,34 +56,45 @@ namespace System return CultureInfo.CurrentCulture.CompareInfo.IndexOf(this, value, CompareOptions.IgnoreCase); case StringComparison.InvariantCulture: - return CultureInfo.InvariantCulture.CompareInfo.IndexOf(this, value, CompareOptions.None); + return CompareInfo.Invariant.IndexOf(this, value, CompareOptions.None); case StringComparison.InvariantCultureIgnoreCase: - return CultureInfo.InvariantCulture.CompareInfo.IndexOf(this, value, CompareOptions.IgnoreCase); + return CompareInfo.Invariant.IndexOf(this, value, CompareOptions.IgnoreCase); case StringComparison.Ordinal: - return CultureInfo.InvariantCulture.CompareInfo.IndexOf(this, value, CompareOptions.Ordinal); + return CompareInfo.Invariant.IndexOf(this, value, CompareOptions.Ordinal); case StringComparison.OrdinalIgnoreCase: - return CultureInfo.InvariantCulture.CompareInfo.IndexOf(this, value, CompareOptions.OrdinalIgnoreCase); - + return CompareInfo.Invariant.IndexOf(this, value, CompareOptions.OrdinalIgnoreCase); + default: throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType)); } } - + public unsafe int IndexOf(char value, int startIndex, int count) { - if (startIndex < 0 || startIndex > Length) + if ((uint)startIndex > (uint)Length) throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); - if (count < 0 || count > Length - startIndex) + if ((uint)count > (uint)(Length - startIndex)) throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count); fixed (char* pChars = &_firstChar) { char* pCh = pChars + startIndex; + char* pEndCh = pCh + count; + if (Vector.IsHardwareAccelerated && count >= Vector.Count * 2) + { + unchecked + { + const int elementsPerByte = sizeof(ushort) / sizeof(byte); + int unaligned = ((int)pCh & (Vector.Count - 1)) / elementsPerByte; + count = ((Vector.Count - unaligned) & (Vector.Count - 1)); + } + } + SequentialScan: while (count >= 4) { if (*pCh == value) goto ReturnIndex; @@ -101,6 +115,34 @@ namespace System pCh++; } + if (pCh < pEndCh) + { + count = (int)((pEndCh - pCh) & ~(Vector.Count - 1)); + // Get comparison Vector + Vector vComparison = new Vector(value); + while (count > 0) + { + var vMatches = Vector.Equals(vComparison, Unsafe.ReadUnaligned>(pCh)); + if (Vector.Zero.Equals(vMatches)) + { + pCh += Vector.Count; + count -= Vector.Count; + continue; + } + // Find offset of first match + return (int)(pCh - pChars) + LocateFirstFoundChar(vMatches); + } + + if (pCh < pEndCh) + { + unchecked + { + count = (int)(pEndCh - pCh); + } + goto SequentialScan; + } + } + return -1; ReturnIndex3: pCh++; @@ -111,6 +153,43 @@ namespace System } } + // Vector sub-search adapted from https://github.com/aspnet/KestrelHttpServer/pull/1138 + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int LocateFirstFoundChar(Vector match) + { + var vector64 = Vector.AsVectorUInt64(match); + ulong candidate = 0; + int i = 0; + // Pattern unrolled by jit https://github.com/dotnet/coreclr/pull/8001 + for (; i < Vector.Count; i++) + { + candidate = vector64[i]; + if (candidate != 0) + { + break; + } + } + + // Single LEA instruction with jitted const (using function result) + return i * 4 + LocateFirstFoundChar(candidate); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int LocateFirstFoundChar(ulong match) + { + unchecked + { + // Flag least significant power of two bit + var powerOfTwoFlag = match ^ (match - 1); + // Shift all powers of two into the high byte and extract + return (int)((powerOfTwoFlag * XorPowerOfTwoToHighChar) >> 49); + } + } + + private const ulong XorPowerOfTwoToHighChar = (0x03ul | + 0x02ul << 16 | + 0x01ul << 32) + 1; + // Returns the index of the first occurrence of any specified character in the current instance. // The search starts at startIndex and runs to startIndex + count - 1. // @@ -305,17 +384,17 @@ namespace System charMap[value & PROBABILISTICMAP_BLOCK_INDEX_MASK] |= 1u << (value >> PROBABILISTICMAP_BLOCK_INDEX_SHIFT); } - public int IndexOf(String value) + public int IndexOf(string value) { return IndexOf(value, StringComparison.CurrentCulture); } - public int IndexOf(String value, int startIndex) + public int IndexOf(string value, int startIndex) { return IndexOf(value, startIndex, StringComparison.CurrentCulture); } - public int IndexOf(String value, int startIndex, int count) + public int IndexOf(string value, int startIndex, int count) { if (startIndex < 0 || startIndex > this.Length) { @@ -330,17 +409,17 @@ namespace System return IndexOf(value, startIndex, count, StringComparison.CurrentCulture); } - public int IndexOf(String value, StringComparison comparisonType) + public int IndexOf(string value, StringComparison comparisonType) { return IndexOf(value, 0, this.Length, comparisonType); } - public int IndexOf(String value, int startIndex, StringComparison comparisonType) + public int IndexOf(string value, int startIndex, StringComparison comparisonType) { return IndexOf(value, startIndex, this.Length - startIndex, comparisonType); } - public int IndexOf(String value, int startIndex, int count, StringComparison comparisonType) + public int IndexOf(string value, int startIndex, int count, StringComparison comparisonType) { // Validate inputs if (value == null) @@ -361,16 +440,16 @@ namespace System return CultureInfo.CurrentCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase); case StringComparison.InvariantCulture: - return CultureInfo.InvariantCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.None); + return CompareInfo.Invariant.IndexOf(this, value, startIndex, count, CompareOptions.None); case StringComparison.InvariantCultureIgnoreCase: - return CultureInfo.InvariantCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase); + return CompareInfo.Invariant.IndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase); case StringComparison.Ordinal: - return CultureInfo.InvariantCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.Ordinal); + return CompareInfo.Invariant.IndexOfOrdinal(this, value, startIndex, count, ignoreCase: false); case StringComparison.OrdinalIgnoreCase: - return TextInfo.IndexOfStringOrdinalIgnoreCase(this, value, startIndex, count); + return CompareInfo.Invariant.IndexOfOrdinal(this, value, startIndex, count, ignoreCase: true); default: throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType)); @@ -397,17 +476,27 @@ namespace System if (Length == 0) return -1; - if (startIndex < 0 || startIndex >= Length) + if ((uint)startIndex >= (uint)Length) throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); - if (count < 0 || count - 1 > startIndex) + if ((uint)count > (uint)startIndex + 1) throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count); fixed (char* pChars = &_firstChar) { char* pCh = pChars + startIndex; + char* pEndCh = pCh - count; //We search [startIndex..EndIndex] + if (Vector.IsHardwareAccelerated && count >= Vector.Count * 2) + { + unchecked + { + const int elementsPerByte = sizeof(ushort) / sizeof(byte); + count = (((int)pCh & (Vector.Count - 1)) / elementsPerByte) + 1; + } + } + SequentialScan: while (count >= 4) { if (*pCh == value) goto ReturnIndex; @@ -428,6 +517,35 @@ namespace System pCh--; } + if (pCh > pEndCh) + { + count = (int)((pCh - pEndCh) & ~(Vector.Count - 1)); + + // Get comparison Vector + Vector vComparison = new Vector(value); + while (count > 0) + { + char* pStart = pCh - Vector.Count + 1; + var vMatches = Vector.Equals(vComparison, Unsafe.ReadUnaligned>(pStart)); + if (Vector.Zero.Equals(vMatches)) + { + pCh -= Vector.Count; + count -= Vector.Count; + continue; + } + // Find offset of last match + return (int)(pStart - pChars) + LocateLastFoundChar(vMatches); + } + + if (pCh > pEndCh) + { + unchecked + { + count = (int)(pCh - pEndCh); + } + goto SequentialScan; + } + } return -1; ReturnIndex3: pCh--; @@ -438,6 +556,40 @@ namespace System } } + // Vector sub-search adapted from https://github.com/aspnet/KestrelHttpServer/pull/1138 + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int LocateLastFoundChar(Vector match) + { + var vector64 = Vector.AsVectorUInt64(match); + ulong candidate = 0; + int i = Vector.Count - 1; + // Pattern unrolled by jit https://github.com/dotnet/coreclr/pull/8001 + for (; i >= 0; i--) + { + candidate = vector64[i]; + if (candidate != 0) + { + break; + } + } + + // Single LEA instruction with jitted const (using function result) + return i * 4 + LocateLastFoundChar(candidate); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int LocateLastFoundChar(ulong match) + { + // Find the most significant char that has its highest bit set + int index = 3; + while ((long)match > 0) + { + match = match << 16; + index--; + } + return index; + } + // Returns the index of the last occurrence of any specified character in the current instance. // The search starts at startIndex and runs backwards to startIndex - count + 1. // The character at position startIndex is included in the search. startIndex is the larger @@ -521,17 +673,17 @@ namespace System // The character at position startIndex is included in the search. startIndex is the larger // index within the string. // - public int LastIndexOf(String value) + public int LastIndexOf(string value) { return LastIndexOf(value, this.Length - 1, this.Length, StringComparison.CurrentCulture); } - public int LastIndexOf(String value, int startIndex) + public int LastIndexOf(string value, int startIndex) { return LastIndexOf(value, startIndex, startIndex + 1, StringComparison.CurrentCulture); } - public int LastIndexOf(String value, int startIndex, int count) + public int LastIndexOf(string value, int startIndex, int count) { if (count < 0) { @@ -541,17 +693,17 @@ namespace System return LastIndexOf(value, startIndex, count, StringComparison.CurrentCulture); } - public int LastIndexOf(String value, StringComparison comparisonType) + public int LastIndexOf(string value, StringComparison comparisonType) { return LastIndexOf(value, this.Length - 1, this.Length, comparisonType); } - public int LastIndexOf(String value, int startIndex, StringComparison comparisonType) + public int LastIndexOf(string value, int startIndex, StringComparison comparisonType) { return LastIndexOf(value, startIndex, startIndex + 1, comparisonType); } - public int LastIndexOf(String value, int startIndex, int count, StringComparison comparisonType) + public int LastIndexOf(string value, int startIndex, int count, StringComparison comparisonType) { if (value == null) throw new ArgumentNullException(nameof(value)); @@ -589,16 +741,16 @@ namespace System return CultureInfo.CurrentCulture.CompareInfo.LastIndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase); case StringComparison.InvariantCulture: - return CultureInfo.InvariantCulture.CompareInfo.LastIndexOf(this, value, startIndex, count, CompareOptions.None); + return CompareInfo.Invariant.LastIndexOf(this, value, startIndex, count, CompareOptions.None); case StringComparison.InvariantCultureIgnoreCase: - return CultureInfo.InvariantCulture.CompareInfo.LastIndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase); + return CompareInfo.Invariant.LastIndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase); case StringComparison.Ordinal: - return CultureInfo.InvariantCulture.CompareInfo.LastIndexOf(this, value, startIndex, count, CompareOptions.Ordinal); + return CompareInfo.Invariant.LastIndexOfOrdinal(this, value, startIndex, count, ignoreCase: false); case StringComparison.OrdinalIgnoreCase: - return TextInfo.LastIndexOfStringOrdinalIgnoreCase(this, value, startIndex, count); + return CompareInfo.Invariant.LastIndexOfOrdinal(this, value, startIndex, count, ignoreCase: true); default: throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType)); diff --git a/external/corert/src/System.Private.CoreLib/shared/System/StringComparer.cs b/external/corert/src/System.Private.CoreLib/shared/System/StringComparer.cs index 73c013599d..de311e91d1 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/StringComparer.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/StringComparer.cs @@ -13,8 +13,8 @@ namespace System [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] public abstract class StringComparer : IComparer, IEqualityComparer, IComparer, IEqualityComparer { - private static readonly CultureAwareComparer s_invariantCulture = new CultureAwareComparer(CultureInfo.InvariantCulture, false); - private static readonly CultureAwareComparer s_invariantCultureIgnoreCase = new CultureAwareComparer(CultureInfo.InvariantCulture, true); + private static readonly CultureAwareComparer s_invariantCulture = new CultureAwareComparer(CultureInfo.InvariantCulture, CompareOptions.None); + private static readonly CultureAwareComparer s_invariantCultureIgnoreCase = new CultureAwareComparer(CultureInfo.InvariantCulture, CompareOptions.IgnoreCase); private static readonly OrdinalCaseSensitiveComparer s_ordinal = new OrdinalCaseSensitiveComparer(); private static readonly OrdinalIgnoreCaseComparer s_ordinalIgnoreCase = new OrdinalIgnoreCaseComparer(); @@ -38,7 +38,7 @@ namespace System { get { - return new CultureAwareComparer(CultureInfo.CurrentCulture, false); + return new CultureAwareComparer(CultureInfo.CurrentCulture, CompareOptions.None); } } @@ -46,7 +46,7 @@ namespace System { get { - return new CultureAwareComparer(CultureInfo.CurrentCulture, true); + return new CultureAwareComparer(CultureInfo.CurrentCulture, CompareOptions.IgnoreCase); } } @@ -94,8 +94,18 @@ namespace System { throw new ArgumentNullException(nameof(culture)); } + + return new CultureAwareComparer(culture, ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None); + } - return new CultureAwareComparer(culture, ignoreCase); + public static StringComparer Create(CultureInfo culture, CompareOptions options) + { + if (culture == null) + { + throw new ArgumentException(nameof(culture)); + } + + return new CultureAwareComparer(culture, options); } public int Compare(object x, object y) @@ -123,7 +133,6 @@ namespace System throw new ArgumentException(SR.Argument_ImplementIComparable); } - public new bool Equals(Object x, Object y) { if (x == y) return true; @@ -163,32 +172,52 @@ namespace System [Serializable] [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] - public sealed class CultureAwareComparer : StringComparer + public sealed class CultureAwareComparer : StringComparer, ISerializable { - private readonly CompareInfo _compareInfo; // Do not rename (binary serialization) - private readonly bool _ignoreCase; // Do not rename (binary serialization) + private const CompareOptions ValidCompareMaskOffFlags = ~(CompareOptions.IgnoreCase | CompareOptions.IgnoreSymbols | CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreWidth | CompareOptions.IgnoreKanaType | CompareOptions.StringSort); - internal CultureAwareComparer(CultureInfo culture, bool ignoreCase) + private readonly CompareInfo _compareInfo; // Do not rename (binary serialization) + private CompareOptions _options; + + internal CultureAwareComparer(CultureInfo culture, CompareOptions options) : this(culture.CompareInfo, options) { } + + internal CultureAwareComparer(CompareInfo compareInfo, CompareOptions options) { - _compareInfo = culture.CompareInfo; - _ignoreCase = ignoreCase; + _compareInfo = compareInfo; + + if ((options & ValidCompareMaskOffFlags) != 0) + { + throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); + } + _options = options; } - private CompareOptions Options => _ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None; + private CultureAwareComparer(SerializationInfo info, StreamingContext context) + { + _compareInfo = (CompareInfo)info.GetValue("_compareInfo", typeof(CompareInfo)); + bool ignoreCase = info.GetBoolean("_ignoreCase"); + + var obj = info.GetValueNoThrow("_options", typeof(CompareOptions)); + if (obj != null) + _options = (CompareOptions)obj; + + // fix up the _options value in case we are getting old serialized object not having _options + _options |= ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None; + } public override int Compare(string x, string y) { if (object.ReferenceEquals(x, y)) return 0; if (x == null) return -1; if (y == null) return 1; - return _compareInfo.Compare(x, y, Options); + return _compareInfo.Compare(x, y, _options); } public override bool Equals(string x, string y) { if (object.ReferenceEquals(x, y)) return true; if (x == null || y == null) return false; - return _compareInfo.Compare(x, y, Options) == 0; + return _compareInfo.Compare(x, y, _options) == 0; } public override int GetHashCode(string obj) @@ -197,7 +226,7 @@ namespace System { throw new ArgumentNullException(nameof(obj)); } - return _compareInfo.GetHashCodeOfString(obj, Options); + return _compareInfo.GetHashCodeOfString(obj, _options); } // Equals method for the comparer itself. @@ -206,14 +235,20 @@ namespace System CultureAwareComparer comparer = obj as CultureAwareComparer; return comparer != null && - _ignoreCase == comparer._ignoreCase && + _options == comparer._options && _compareInfo.Equals(comparer._compareInfo); } public override int GetHashCode() { - int hashCode = _compareInfo.GetHashCode(); - return _ignoreCase ? ~hashCode : hashCode; + return _compareInfo.GetHashCode() ^ ((int)_options & 0x7FFFFFFF); + } + + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("_compareInfo", _compareInfo); + info.AddValue("_options", _options); + info.AddValue("_ignoreCase", (_options & CompareOptions.IgnoreCase) != 0); } } diff --git a/external/corert/src/System.Private.CoreLib/shared/System/StringSpanHelpers.cs b/external/corert/src/System.Private.CoreLib/shared/System/StringSpanHelpers.cs index 1c127b19d0..2d6152de56 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/StringSpanHelpers.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/StringSpanHelpers.cs @@ -17,7 +17,7 @@ namespace System throw new ArgumentOutOfRangeException(nameof(comparisonType)); public static bool Equals(this ReadOnlySpan left, string right) => - Equals(left, right.AsReadOnlySpan()); + Equals(left, right.AsSpan()); public static bool Equals(this ReadOnlySpan left, ReadOnlySpan right) { @@ -33,7 +33,7 @@ namespace System return false; } } - + return true; } @@ -57,23 +57,6 @@ namespace System return true; } - public static ReadOnlySpan Trim(this ReadOnlySpan source) - { - int startIndex = 0, endIndex = source.Length - 1; - - while (startIndex <= endIndex && char.IsWhiteSpace(source[startIndex])) - { - startIndex++; - } - - while (endIndex >= startIndex && char.IsWhiteSpace(source[endIndex])) - { - endIndex--; - } - - return source.Slice(startIndex, endIndex - startIndex + 1); - } - public static int IndexOf(this ReadOnlySpan source, char value) => IndexOf(source, value, 0); @@ -105,9 +88,12 @@ namespace System public static ReadOnlySpan Remove(this ReadOnlySpan source, int startIndex, int count) { - if (startIndex < 0) throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_StartIndex); - if (count < 0) throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NegativeCount); - if (count > source.Length - startIndex) throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_IndexCount); + if (startIndex < 0) + throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_StartIndex); + if (count < 0) + throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NegativeCount); + if (count > source.Length - startIndex) + throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_IndexCount); if (count == 0) { @@ -125,5 +111,29 @@ namespace System source.Slice(startIndex + count).CopyTo(result.Slice(startIndex)); return result; } + + // Returns the index of the last occurrence of a specified character in the current instance. + public static int LastIndexOf(this ReadOnlySpan source, char value) + { + if (source.Length == 0) + return -1; + + for (int i = source.Length - 1; i >= 0; i--) + { + if (source[i] == value) + return i; + } + + return -1; + } + + public static void CheckStringComparison(StringComparison comparisonType) + { + // Single comparison to check if comparisonType is within [CurrentCulture .. OrdinalIgnoreCase] + if ((uint)(comparisonType - StringComparison.CurrentCulture) > (StringComparison.OrdinalIgnoreCase - StringComparison.CurrentCulture)) + { + throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType)); + } + } } } diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Text/StringBuilder.cs b/external/corert/src/System.Private.CoreLib/shared/System/Text/StringBuilder.cs index d9da9377d0..a7804c3991 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Text/StringBuilder.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Text/StringBuilder.cs @@ -423,53 +423,12 @@ namespace System.Text } AssertInvariants(); - - StringBuilder chunk = this; - int sourceEndIndex = startIndex + length; - string result = string.FastAllocateString(length); - int curDestIndex = length; unsafe { fixed (char* destinationPtr = result) { - while (curDestIndex > 0) - { - int chunkEndIndex = sourceEndIndex - chunk.m_ChunkOffset; - if (chunkEndIndex >= 0) - { - chunkEndIndex = Math.Min(chunkEndIndex, chunk.m_ChunkLength); - - int countLeft = curDestIndex; - int chunkCount = countLeft; - int chunkStartIndex = chunkEndIndex - countLeft; - if (chunkStartIndex < 0) - { - chunkCount += chunkStartIndex; - chunkStartIndex = 0; - } - curDestIndex -= chunkCount; - - if (chunkCount > 0) - { - // Work off of local variables so that they are stable even in the presence of race conditions - char[] sourceArray = chunk.m_ChunkChars; - - // Check that we will not overrun our boundaries. - if ((uint)(chunkCount + curDestIndex) <= (uint)length && (uint)(chunkCount + chunkStartIndex) <= (uint)sourceArray.Length) - { - fixed (char* sourcePtr = &sourceArray[chunkStartIndex]) - string.wstrcpy(destinationPtr + curDestIndex, sourcePtr, chunkCount); - } - else - { - throw new ArgumentOutOfRangeException(nameof(chunkCount), SR.ArgumentOutOfRange_Index); - } - } - } - chunk = chunk.m_ChunkPrevious; - } - + this.CopyTo(startIndex, new Span(destinationPtr, length), length); return result; } } @@ -790,6 +749,79 @@ namespace System.Text } } + public StringBuilder Append(StringBuilder value) + { + if (value != null && value.Length != 0) + { + return AppendCore(value, 0, value.Length); + } + return this; + } + + public StringBuilder Append(StringBuilder value, int startIndex, int count) + { + if (startIndex < 0) + { + throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); + } + + if (count < 0) + { + throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_GenericPositive); + } + + if (value == null) + { + if (startIndex == 0 && count == 0) + { + return this; + } + throw new ArgumentNullException(nameof(value)); + } + + if (count == 0) + { + return this; + } + + if (count > value.Length - startIndex) + { + throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); + } + + return AppendCore(value, startIndex, count); + } + + private StringBuilder AppendCore(StringBuilder value, int startIndex, int count) + { + if (value == this) + return Append(value.ToString(startIndex, count)); + + int newLength = Length + count; + + if ((uint)newLength > (uint)m_MaxCapacity) + { + throw new ArgumentOutOfRangeException(nameof(Capacity), SR.ArgumentOutOfRange_Capacity); + } + + while (count > 0) + { + int length = Math.Min(m_ChunkChars.Length - m_ChunkLength, count); + if (length == 0) + { + ExpandByABlock(count); + length = Math.Min(m_ChunkChars.Length - m_ChunkLength, count); + } + value.CopyTo(startIndex, new Span(m_ChunkChars, m_ChunkLength, length), length); + + m_ChunkLength += length; + startIndex += length; + count -= length; + } + + return this; + } + public StringBuilder AppendLine() => Append(Environment.NewLine); public StringBuilder AppendLine(string value) @@ -1520,7 +1552,7 @@ namespace System.Text if (startPos != pos) { // There was no brace escaping, extract the item format as a single string - itemFormatSpan = format.AsReadOnlySpan().Slice(startPos, pos - startPos); + itemFormatSpan = format.AsSpan().Slice(startPos, pos - startPos); } } else @@ -1645,6 +1677,35 @@ namespace System.Text } } + /// + /// Determines if the contents of this builder are equal to the contents of ReadOnlySpan. + /// + /// The ReadOnlySpan{char}. + public bool Equals(ReadOnlySpan value) + { + if (value.Length != Length) + return false; + + StringBuilder sbChunk = this; + int offset = 0; + + do + { + int chunk_length = sbChunk.m_ChunkLength; + offset += chunk_length; + + ReadOnlySpan chunk = new ReadOnlySpan(sbChunk.m_ChunkChars, 0, chunk_length); + + if (!chunk.Equals(value.Slice(value.Length - offset, chunk_length))) + return false; + + sbChunk = sbChunk.m_ChunkPrevious; + } while (sbChunk != null); + + Debug.Assert(offset == Length); + return true; + } + /// /// Replaces all instances of one string with another in part of this builder. /// diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Text/UTF8Encoding.cs.REMOVED.git-id b/external/corert/src/System.Private.CoreLib/shared/System/Text/UTF8Encoding.cs.REMOVED.git-id index 6176a63d8f..add73271c0 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Text/UTF8Encoding.cs.REMOVED.git-id +++ b/external/corert/src/System.Private.CoreLib/shared/System/Text/UTF8Encoding.cs.REMOVED.git-id @@ -1 +1 @@ -a89af8edb0b2b357812747b41f60144b3881dee9 \ No newline at end of file +67f87c9b09cea24711f13de237cd53a00386c382 \ No newline at end of file diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Text/ValueStringBuilder.cs b/external/corert/src/System.Private.CoreLib/shared/System/Text/ValueStringBuilder.cs index 0a91eb0f63..18d5648672 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Text/ValueStringBuilder.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Text/ValueStringBuilder.cs @@ -5,6 +5,7 @@ using System.Buffers; using System.Diagnostics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace System.Text { @@ -21,27 +22,56 @@ namespace System.Text _pos = 0; } - public int Length => _pos; + public int Length + { + get => _pos; + set + { + Debug.Assert(value <= _chars.Length); + _pos = value; + } + } + + public int Capacity => _chars.Length; + + public void EnsureCapacity(int capacity) + { + if (capacity > _chars.Length) + Grow(capacity - _chars.Length); + } + + public ref char GetPinnableReference() => ref MemoryMarshal.GetReference(_chars); + + public ref char this[int index] + { + get + { + Debug.Assert(index < _pos); + return ref _chars[index]; + } + } public override string ToString() { var s = new string(_chars.Slice(0, _pos)); - Clear(); + Dispose(); return s; } + public ReadOnlySpan AsSpan() => _chars.Slice(0, _pos); + public bool TryCopyTo(Span destination, out int charsWritten) { if (_chars.Slice(0, _pos).TryCopyTo(destination)) { charsWritten = _pos; - Clear(); + Dispose(); return true; } else { charsWritten = 0; - Clear(); + Dispose(); return false; } } @@ -97,8 +127,7 @@ namespace System.Text Grow(s.Length); } - bool copied = s.AsReadOnlySpan().TryCopyTo(_chars.Slice(pos)); - Debug.Assert(copied, "Grow should have made enough room to successfully copy"); + s.AsSpan().CopyTo(_chars.Slice(pos)); _pos += s.Length; } @@ -133,6 +162,18 @@ namespace System.Text _pos += length; } + public unsafe void Append(ReadOnlySpan value) + { + int pos = _pos; + if (pos > _chars.Length - value.Length) + { + Grow(value.Length); + } + + value.CopyTo(_chars.Slice(_pos)); + _pos += value.Length; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Span AppendSpan(int length) { @@ -156,12 +197,11 @@ namespace System.Text [MethodImpl(MethodImplOptions.NoInlining)] private void Grow(int requiredAdditionalCapacity) { - Debug.Assert(requiredAdditionalCapacity > _chars.Length - _pos); + Debug.Assert(requiredAdditionalCapacity > 0); char[] poolArray = ArrayPool.Shared.Rent(Math.Max(_pos + requiredAdditionalCapacity, _chars.Length * 2)); - bool success = _chars.TryCopyTo(poolArray); - Debug.Assert(success); + _chars.CopyTo(poolArray); char[] toReturn = _arrayToReturnToPool; _chars = _arrayToReturnToPool = poolArray; @@ -172,7 +212,7 @@ namespace System.Text } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void Clear() + public void Dispose() { char[] toReturn = _arrayToReturnToPool; this = default; // for safety, to avoid using pooled array if this instance is erroneously appended to again diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Threading/AsyncLocal.cs b/external/corert/src/System.Private.CoreLib/shared/System/Threading/AsyncLocal.cs index 59c8fb3c88..3531265bec 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Threading/AsyncLocal.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Threading/AsyncLocal.cs @@ -125,7 +125,7 @@ namespace System.Threading public static IAsyncLocalValueMap Empty { get; } = new EmptyAsyncLocalValueMap(); // Instance without any key/value pairs. Used as a singleton/ - private sealed class EmptyAsyncLocalValueMap : IAsyncLocalValueMap + internal sealed class EmptyAsyncLocalValueMap : IAsyncLocalValueMap { public IAsyncLocalValueMap Set(IAsyncLocal key, object value) { @@ -144,7 +144,7 @@ namespace System.Threading } // Instance with one key/value pair. - private sealed class OneElementAsyncLocalValueMap : IAsyncLocalValueMap + internal sealed class OneElementAsyncLocalValueMap : IAsyncLocalValueMap { private readonly IAsyncLocal _key1; private readonly object _value1; diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Threading/ExecutionContext.cs b/external/corert/src/System.Private.CoreLib/shared/System/Threading/ExecutionContext.cs index 2d5f5be190..9f27c6dcb4 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Threading/ExecutionContext.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Threading/ExecutionContext.cs @@ -21,40 +21,18 @@ namespace System.Threading { public delegate void ContextCallback(Object state); - internal struct ExecutionContextSwitcher - { - internal ExecutionContext m_ec; - internal SynchronizationContext m_sc; - - internal void Undo(Thread currentThread) - { - Debug.Assert(currentThread == Thread.CurrentThread); - - // The common case is that these have not changed, so avoid the cost of a write if not needed. - if (currentThread.SynchronizationContext != m_sc) - { - currentThread.SynchronizationContext = m_sc; - } - - if (currentThread.ExecutionContext != m_ec) - { - ExecutionContext.Restore(currentThread, m_ec); - } - } - } - public sealed class ExecutionContext : IDisposable, ISerializable { - internal static readonly ExecutionContext Default = new ExecutionContext(); + internal static readonly ExecutionContext Default = new ExecutionContext(isDefault: true); private readonly IAsyncLocalValueMap m_localValues; private readonly IAsyncLocal[] m_localChangeNotifications; private readonly bool m_isFlowSuppressed; + private readonly bool m_isDefault; - private ExecutionContext() + private ExecutionContext(bool isDefault) { - m_localValues = AsyncLocalValueMap.Empty; - m_localChangeNotifications = Array.Empty(); + m_isDefault = isDefault; } private ExecutionContext( @@ -86,12 +64,14 @@ namespace System.Threading Debug.Assert(isFlowSuppressed != m_isFlowSuppressed); if (!isFlowSuppressed && - m_localValues == Default.m_localValues && - m_localChangeNotifications == Default.m_localChangeNotifications) + (m_localValues == null || + m_localValues.GetType() == typeof(AsyncLocalValueMap.EmptyAsyncLocalValueMap)) + ) { return null; // implies the default context } - return new ExecutionContext(m_localValues, m_localChangeNotifications, isFlowSuppressed); + // Flow suppressing a Default context will have null values, set them to Empty + return new ExecutionContext(m_localValues ?? AsyncLocalValueMap.Empty, m_localChangeNotifications ?? Array.Empty(), isFlowSuppressed); } public static AsyncFlowControl SuppressFlow() @@ -128,134 +108,248 @@ namespace System.Threading return executionContext != null && executionContext.m_isFlowSuppressed; } + internal bool HasChangeNotifications => m_localChangeNotifications != null; + + internal bool IsDefault => m_isDefault; + public static void Run(ExecutionContext executionContext, ContextCallback callback, Object state) { + // Note: ExecutionContext.Run is an extremely hot function and used by every await, ThreadPool execution, etc. if (executionContext == null) - throw new InvalidOperationException(SR.InvalidOperation_NullContext); + { + ThrowNullContext(); + } - Thread currentThread = Thread.CurrentThread; - ExecutionContextSwitcher ecsw = default(ExecutionContextSwitcher); + RunInternal(executionContext, callback, state); + } + + internal static void RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) + { + // Note: ExecutionContext.RunInternal is an extremely hot function and used by every await, ThreadPool execution, etc. + // Note: Manual enregistering may be addressed by "Exception Handling Write Through Optimization" + // https://github.com/dotnet/coreclr/blob/master/Documentation/design-docs/eh-writethru.md + + // Enregister variables with 0 post-fix so they can be used in registers without EH forcing them to stack + // Capture references to Thread Contexts + Thread currentThread0 = Thread.CurrentThread; + Thread currentThread = currentThread0; + ExecutionContext previousExecutionCtx0 = currentThread0.ExecutionContext; + + // Store current ExecutionContext and SynchronizationContext as "previousXxx". + // This allows us to restore them and undo any Context changes made in callback.Invoke + // so that they won't "leak" back into caller. + // These variables will cross EH so be forced to stack + ExecutionContext previousExecutionCtx = previousExecutionCtx0; + SynchronizationContext previousSyncCtx = currentThread0.SynchronizationContext; + + if (executionContext != null && executionContext.m_isDefault) + { + // Default is a null ExecutionContext internally + executionContext = null; + } + + if (previousExecutionCtx0 != executionContext) + { + // Restore changed ExecutionContext + currentThread0.ExecutionContext = executionContext; + if ((executionContext != null && executionContext.HasChangeNotifications) || + (previousExecutionCtx0 != null && previousExecutionCtx0.HasChangeNotifications)) + { + // There are change notifications; trigger any affected + OnValuesChanged(previousExecutionCtx0, executionContext); + } + } + + ExceptionDispatchInfo edi = null; try { - EstablishCopyOnWriteScope(currentThread, ref ecsw); - ExecutionContext.Restore(currentThread, executionContext); - callback(state); + callback.Invoke(state); } - catch + catch (Exception ex) { // Note: we have a "catch" rather than a "finally" because we want // to stop the first pass of EH here. That way we can restore the previous - // context before any of our callers' EH filters run. That means we need to - // end the scope separately in the non-exceptional case below. - ecsw.Undo(currentThread); - throw; - } - ecsw.Undo(currentThread); - } - - internal static void Restore(Thread currentThread, ExecutionContext executionContext) - { - Debug.Assert(currentThread == Thread.CurrentThread); - - ExecutionContext previous = currentThread.ExecutionContext ?? Default; - currentThread.ExecutionContext = executionContext; - - // New EC could be null if that's what ECS.Undo saved off. - // For the purposes of dealing with context change, treat this as the default EC - executionContext = executionContext ?? Default; - - if (previous != executionContext) - { - OnContextChanged(previous, executionContext); - } - } - - internal static void EstablishCopyOnWriteScope(Thread currentThread, ref ExecutionContextSwitcher ecsw) - { - Debug.Assert(currentThread == Thread.CurrentThread); - - ecsw.m_ec = currentThread.ExecutionContext; - ecsw.m_sc = currentThread.SynchronizationContext; - } - - private static void OnContextChanged(ExecutionContext previous, ExecutionContext current) - { - Debug.Assert(previous != null); - Debug.Assert(current != null); - Debug.Assert(previous != current); - - foreach (IAsyncLocal local in previous.m_localChangeNotifications) - { - object previousValue; - object currentValue; - previous.m_localValues.TryGetValue(local, out previousValue); - current.m_localValues.TryGetValue(local, out currentValue); - - if (previousValue != currentValue) - local.OnValueChanged(previousValue, currentValue, true); + // context before any of our callers' EH filters run. + edi = ExceptionDispatchInfo.Capture(ex); } - if (current.m_localChangeNotifications != previous.m_localChangeNotifications) + // Re-enregistrer variables post EH with 1 post-fix so they can be used in registers rather than from stack + SynchronizationContext previousSyncCtx1 = previousSyncCtx; + Thread currentThread1 = currentThread; + // The common case is that these have not changed, so avoid the cost of a write barrier if not needed. + if (currentThread1.SynchronizationContext != previousSyncCtx1) { - try + // Restore changed SynchronizationContext back to previous + currentThread1.SynchronizationContext = previousSyncCtx1; + } + + ExecutionContext previousExecutionCtx1 = previousExecutionCtx; + ExecutionContext currentExecutionCtx1 = currentThread1.ExecutionContext; + if (currentExecutionCtx1 != previousExecutionCtx1) + { + // Restore changed ExecutionContext back to previous + currentThread1.ExecutionContext = previousExecutionCtx1; + if ((currentExecutionCtx1 != null && currentExecutionCtx1.HasChangeNotifications) || + (previousExecutionCtx1 != null && previousExecutionCtx1.HasChangeNotifications)) { - foreach (IAsyncLocal local in current.m_localChangeNotifications) - { - // If the local has a value in the previous context, we already fired the event for that local - // in the code above. - object previousValue; - if (!previous.m_localValues.TryGetValue(local, out previousValue)) - { - object currentValue; - current.m_localValues.TryGetValue(local, out currentValue); + // There are change notifications; trigger any affected + OnValuesChanged(currentExecutionCtx1, previousExecutionCtx1); + } + } - if (previousValue != currentValue) - local.OnValueChanged(previousValue, currentValue, true); + // If exception was thrown by callback, rethrow it now original contexts are restored + edi?.Throw(); + } + + internal static void OnValuesChanged(ExecutionContext previousExecutionCtx, ExecutionContext nextExecutionCtx) + { + Debug.Assert(previousExecutionCtx != nextExecutionCtx); + + // Collect Change Notifications + IAsyncLocal[] previousChangeNotifications = previousExecutionCtx?.m_localChangeNotifications; + IAsyncLocal[] nextChangeNotifications = nextExecutionCtx?.m_localChangeNotifications; + + // At least one side must have notifications + Debug.Assert(previousChangeNotifications != null || nextChangeNotifications != null); + + // Fire Change Notifications + try + { + if (previousChangeNotifications != null && nextChangeNotifications != null) + { + // Notifications can't exist without values + Debug.Assert(previousExecutionCtx.m_localValues != null); + Debug.Assert(nextExecutionCtx.m_localValues != null); + // Both contexts have change notifications, check previousExecutionCtx first + foreach (IAsyncLocal local in previousChangeNotifications) + { + previousExecutionCtx.m_localValues.TryGetValue(local, out object previousValue); + nextExecutionCtx.m_localValues.TryGetValue(local, out object currentValue); + + if (previousValue != currentValue) + { + local.OnValueChanged(previousValue, currentValue, contextChanged: true); + } + } + + if (nextChangeNotifications != previousChangeNotifications) + { + // Check for additional notifications in nextExecutionCtx + foreach (IAsyncLocal local in nextChangeNotifications) + { + // If the local has a value in the previous context, we already fired the event + // for that local in the code above. + if (!previousExecutionCtx.m_localValues.TryGetValue(local, out object previousValue)) + { + nextExecutionCtx.m_localValues.TryGetValue(local, out object currentValue); + if (previousValue != currentValue) + { + local.OnValueChanged(previousValue, currentValue, contextChanged: true); + } + } } } } - catch (Exception ex) + else if (previousChangeNotifications != null) { - Environment.FailFast( - SR.ExecutionContext_ExceptionInAsyncLocalNotification, - ex); + // Notifications can't exist without values + Debug.Assert(previousExecutionCtx.m_localValues != null); + // No current values, so just check previous against null + foreach (IAsyncLocal local in previousChangeNotifications) + { + previousExecutionCtx.m_localValues.TryGetValue(local, out object previousValue); + if (previousValue != null) + { + local.OnValueChanged(previousValue, null, contextChanged: true); + } + } + } + else // Implied: nextChangeNotifications != null + { + // Notifications can't exist without values + Debug.Assert(nextExecutionCtx.m_localValues != null); + // No previous values, so just check current against null + foreach (IAsyncLocal local in nextChangeNotifications) + { + nextExecutionCtx.m_localValues.TryGetValue(local, out object currentValue); + if (currentValue != null) + { + local.OnValueChanged(null, currentValue, contextChanged: true); + } + } } } + catch (Exception ex) + { + Environment.FailFast( + SR.ExecutionContext_ExceptionInAsyncLocalNotification, + ex); + } + } + + [StackTraceHidden] + private static void ThrowNullContext() + { + throw new InvalidOperationException(SR.InvalidOperation_NullContext); } internal static object GetLocalValue(IAsyncLocal local) { ExecutionContext current = Thread.CurrentThread.ExecutionContext; if (current == null) + { return null; + } - object value; - current.m_localValues.TryGetValue(local, out value); + current.m_localValues.TryGetValue(local, out object value); return value; } internal static void SetLocalValue(IAsyncLocal local, object newValue, bool needChangeNotifications) { - ExecutionContext current = Thread.CurrentThread.ExecutionContext ?? ExecutionContext.Default; + ExecutionContext current = Thread.CurrentThread.ExecutionContext; - object previousValue; - bool hadPreviousValue = current.m_localValues.TryGetValue(local, out previousValue); + object previousValue = null; + bool hadPreviousValue = false; + if (current != null) + { + hadPreviousValue = current.m_localValues.TryGetValue(local, out previousValue); + } if (previousValue == newValue) + { return; + } - IAsyncLocalValueMap newValues = current.m_localValues.Set(local, newValue); + IAsyncLocal[] newChangeNotifications = null; + IAsyncLocalValueMap newValues; + bool isFlowSuppressed = false; + if (current != null) + { + isFlowSuppressed = current.m_isFlowSuppressed; + newValues = current.m_localValues.Set(local, newValue); + newChangeNotifications = current.m_localChangeNotifications; + } + else + { + // First AsyncLocal + newValues = new AsyncLocalValueMap.OneElementAsyncLocalValueMap(local, newValue); + } // // Either copy the change notification array, or create a new one, depending on whether we need to add a new item. // - IAsyncLocal[] newChangeNotifications = current.m_localChangeNotifications; if (needChangeNotifications) { if (hadPreviousValue) { + Debug.Assert(newChangeNotifications != null); Debug.Assert(Array.IndexOf(newChangeNotifications, local) >= 0); } + else if (newChangeNotifications == null) + { + newChangeNotifications = new IAsyncLocal[1] { local }; + } else { int newNotificationIndex = newChangeNotifications.Length; @@ -264,12 +358,14 @@ namespace System.Threading } } - Thread.CurrentThread.ExecutionContext = - new ExecutionContext(newValues, newChangeNotifications, current.m_isFlowSuppressed); + Thread.CurrentThread.ExecutionContext = + (!isFlowSuppressed && newValues.GetType() == typeof(AsyncLocalValueMap.EmptyAsyncLocalValueMap)) ? + null : // No values, return to Default context + new ExecutionContext(newValues, newChangeNotifications, isFlowSuppressed); if (needChangeNotifications) { - local.OnValueChanged(previousValue, newValue, false); + local.OnValueChanged(previousValue, newValue, contextChanged: false); } } diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Threading/ReaderWriterLockSlim.cs b/external/corert/src/System.Private.CoreLib/shared/System/Threading/ReaderWriterLockSlim.cs index 3c4aad603a..45175488e7 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Threading/ReaderWriterLockSlim.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Threading/ReaderWriterLockSlim.cs @@ -1249,7 +1249,7 @@ namespace System.Threading } // Don't want to Sleep(1) in this spin wait: - // - Don't want to spin for that long, since a proper wait will follow when the spin wait fails. The artifical + // - Don't want to spin for that long, since a proper wait will follow when the spin wait fails. The artificial // delay introduced by Sleep(1) will in some cases be much longer than desired. // - Sleep(1) would put the thread into a wait state, and a proper wait will follow when the spin wait fails // anyway, so it's preferable to put the thread into the proper wait state diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Threading/Tasks/Sources/IValueTaskSource.cs b/external/corert/src/System.Private.CoreLib/shared/System/Threading/Tasks/Sources/IValueTaskSource.cs new file mode 100644 index 0000000000..e411146a1d --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/shared/System/Threading/Tasks/Sources/IValueTaskSource.cs @@ -0,0 +1,82 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Threading.Tasks.Sources +{ + /// + /// Flags passed from and to + /// and + /// to control behavior. + /// + [Flags] + public enum ValueTaskSourceOnCompletedFlags + { + /// + /// No requirements are placed on how the continuation is invoked. + /// + None, + /// + /// Set if OnCompleted should capture the current scheduling context (e.g. SynchronizationContext) + /// and use it when queueing the continuation for execution. If this is not set, the implementation + /// may choose to execute the continuation in an arbitrary location. + /// + UseSchedulingContext = 0x1, + /// + /// Set if OnCompleted should capture the current ExecutionContext and use it to run the continuation. + /// + FlowExecutionContext = 0x2, + } + + /// Indicates the status of an or . + public enum ValueTaskSourceStatus + { + /// The operation has not yet completed. + Pending = 0, + /// The operation completed successfully. + Succeeded = 1, + /// The operation completed with an error. + Faulted = 2, + /// The operation completed due to cancellation. + Canceled = 3 + } + + /// Represents an object that can be wrapped by a . + public interface IValueTaskSource + { + /// Gets the status of the current operation. + /// Opaque value that was provided to the 's constructor. + ValueTaskSourceStatus GetStatus(short token); + + /// Schedules the continuation action for this . + /// The continuation to invoke when the operation has completed. + /// The state object to pass to when it's invoked. + /// Opaque value that was provided to the 's constructor. + /// The flags describing the behavior of the continuation. + void OnCompleted(Action continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags); + + /// Gets the result of the . + /// Opaque value that was provided to the 's constructor. + void GetResult(short token); + } + + /// Represents an object that can be wrapped by a . + /// Specifies the type of data returned from the object. + public interface IValueTaskSource + { + /// Gets the status of the current operation. + /// Opaque value that was provided to the 's constructor. + ValueTaskSourceStatus GetStatus(short token); + + /// Schedules the continuation action for this . + /// The continuation to invoke when the operation has completed. + /// The state object to pass to when it's invoked. + /// Opaque value that was provided to the 's constructor. + /// The flags describing the behavior of the continuation. + void OnCompleted(Action continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags); + + /// Gets the result of the . + /// Opaque value that was provided to the 's constructor. + TResult GetResult(short token); + } +} diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Threading/Tasks/ValueTask.cs b/external/corert/src/System.Private.CoreLib/shared/System/Threading/Tasks/ValueTask.cs index de9b016328..18e4a27a49 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Threading/Tasks/ValueTask.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Threading/Tasks/ValueTask.cs @@ -3,72 +3,401 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.ComponentModel; +using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Threading.Tasks.Sources; + +#if !netstandard +using Internal.Runtime.CompilerServices; +#endif namespace System.Threading.Tasks { - /// - /// Provides a value type that wraps a and a , - /// only one of which is used. - /// - /// The type of the result. + /// Provides an awaitable result of an asynchronous operation. /// - /// - /// Methods may return an instance of this value type when it's likely that the result of their - /// operations will be available synchronously and when the method is expected to be invoked so - /// frequently that the cost of allocating a new for each call will - /// be prohibitive. - /// - /// - /// There are tradeoffs to using a instead of a . - /// For example, while a can help avoid an allocation in the case where the - /// successful result is available synchronously, it also contains two fields whereas a - /// as a reference type is a single field. This means that a method call ends up returning two fields worth of - /// data instead of one, which is more data to copy. It also means that if a method that returns one of these - /// is awaited within an async method, the state machine for that async method will be larger due to needing - /// to store the struct that's two fields instead of a single reference. - /// - /// - /// Further, for uses other than consuming the result of an asynchronous operation via await, - /// can lead to a more convoluted programming model, which can in turn actually - /// lead to more allocations. For example, consider a method that could return either a - /// with a cached task as a common result or a . If the consumer of the result - /// wants to use it as a , such as to use with in methods like Task.WhenAll and Task.WhenAny, - /// the would first need to be converted into a using - /// , which leads to an allocation that would have been avoided if a cached - /// had been used in the first place. - /// - /// - /// As such, the default choice for any asynchronous method should be to return a or - /// . Only if performance analysis proves it worthwhile should a - /// be used instead of . There is no non-generic version of - /// as the Task.CompletedTask property may be used to hand back a successfully completed singleton in the case where - /// a -returning method completes synchronously and successfully. - /// + /// s are meant to be directly awaited. To do more complicated operations with them, a + /// should be extracted using . Such operations might include caching an instance to be awaited later, + /// registering multiple continuations with a single operation, awaiting the same task multiple times, and using combinators over + /// multiple operations. + /// + [AsyncMethodBuilder(typeof(AsyncValueTaskMethodBuilder))] + [StructLayout(LayoutKind.Auto)] + public readonly struct ValueTask : IEquatable + { + internal static Task CompletedTask +#if netstandard + { get; } = Task.Delay(0); +#else + => Task.CompletedTask; +#endif + + /// null if representing a successful synchronous completion, otherwise a or a . + internal readonly object _obj; + /// Flags providing additional details about the ValueTask's contents and behavior. + internal readonly ValueTaskFlags _flags; + /// Opaque value passed through to the . + internal readonly short _token; + + // An instance created with the default ctor (a zero init'd struct) represents a synchronously, successfully completed operation. + + /// Initialize the with a that represents the operation. + /// The task. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ValueTask(Task task) + { + if (task == null) + { + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.task); + } + + _obj = task; + + _flags = ValueTaskFlags.ObjectIsTask; + _token = 0; + } + + /// Initialize the with a object that represents the operation. + /// The source. + /// Opaque value passed through to the . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ValueTask(IValueTaskSource source, short token) + { + if (source == null) + { + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); + } + + _obj = source; + _token = token; + + _flags = 0; + } + + /// Non-verified initialization of the struct to the specified values. + /// The object. + /// The token. + /// The flags. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private ValueTask(object obj, short token, ValueTaskFlags flags) + { + _obj = obj; + _token = token; + _flags = flags; + } + + /// Gets whether the contination should be scheduled to the current context. + internal bool ContinueOnCapturedContext + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => (_flags & ValueTaskFlags.AvoidCapturedContext) == 0; + } + + /// Gets whether the object in the field is a . + internal bool ObjectIsTask + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => (_flags & ValueTaskFlags.ObjectIsTask) != 0; + } + + /// Returns the stored in . This uses . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Task UnsafeGetTask() + { + Debug.Assert(ObjectIsTask); + Debug.Assert(_obj is Task); + return Unsafe.As(_obj); + } + + /// Returns the stored in . This uses . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal IValueTaskSource UnsafeGetValueTaskSource() + { + Debug.Assert(!ObjectIsTask); + Debug.Assert(_obj is IValueTaskSource); + return Unsafe.As(_obj); + } + + /// Returns the hash code for this instance. + public override int GetHashCode() => _obj?.GetHashCode() ?? 0; + + /// Returns a value indicating whether this value is equal to a specified . + public override bool Equals(object obj) => + obj is ValueTask && + Equals((ValueTask)obj); + + /// Returns a value indicating whether this value is equal to a specified value. + public bool Equals(ValueTask other) => _obj == other._obj && _token == other._token; + + /// Returns a value indicating whether two values are equal. + public static bool operator ==(ValueTask left, ValueTask right) => + left.Equals(right); + + /// Returns a value indicating whether two values are not equal. + public static bool operator !=(ValueTask left, ValueTask right) => + !left.Equals(right); + + /// + /// Gets a object to represent this ValueTask. + /// + /// + /// It will either return the wrapped task object if one exists, or it'll + /// manufacture a new task object to represent the result. + /// + public Task AsTask() => + _obj == null ? ValueTask.CompletedTask : + ObjectIsTask ? UnsafeGetTask() : + GetTaskForValueTaskSource(); + + /// Gets a that may be used at any point in the future. + public ValueTask Preserve() => _obj == null ? this : new ValueTask(AsTask()); + + /// Creates a to represent the . + private Task GetTaskForValueTaskSource() + { + IValueTaskSource t = UnsafeGetValueTaskSource(); + ValueTaskSourceStatus status = t.GetStatus(_token); + if (status != ValueTaskSourceStatus.Pending) + { + try + { + // Propagate any exceptions that may have occurred, then return + // an already successfully completed task. + t.GetResult(_token); + return ValueTask.CompletedTask; + + // If status is Faulted or Canceled, GetResult should throw. But + // we can't guarantee every implementation will do the "right thing". + // If it doesn't throw, we just treat that as success and ignore + // the status. + } + catch (Exception exc) + { + if (status == ValueTaskSourceStatus.Canceled) + { +#if netstandard + var tcs = new TaskCompletionSource(); + tcs.TrySetCanceled(); + return tcs.Task; +#else + if (exc is OperationCanceledException oce) + { + var task = new Task(); + task.TrySetCanceled(oce.CancellationToken, oce); + return task; + } + else + { + return Task.FromCanceled(new CancellationToken(true)); + } +#endif + } + else + { +#if netstandard + var tcs = new TaskCompletionSource(); + tcs.TrySetException(exc); + return tcs.Task; +#else + return Task.FromException(exc); +#endif + } + } + } + + var m = new ValueTaskSourceTask(t, _token); + return +#if netstandard + m.Task; +#else + m; +#endif + } + + /// Type used to create a to represent a . + private sealed class ValueTaskSourceTask : +#if netstandard + TaskCompletionSource +#else + Task +#endif + { + private static readonly Action s_completionAction = state => + { + if (!(state is ValueTaskSourceTask vtst) || + !(vtst._source is IValueTaskSource source)) + { + // This could only happen if the IValueTaskSource passed the wrong state + // or if this callback were invoked multiple times such that the state + // was previously nulled out. + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.state); + return; + } + + vtst._source = null; + ValueTaskSourceStatus status = source.GetStatus(vtst._token); + try + { + source.GetResult(vtst._token); + vtst.TrySetResult(default); + } + catch (Exception exc) + { + if (status == ValueTaskSourceStatus.Canceled) + { +#if netstandard + vtst.TrySetCanceled(); +#else + if (exc is OperationCanceledException oce) + { + vtst.TrySetCanceled(oce.CancellationToken, oce); + } + else + { + vtst.TrySetCanceled(new CancellationToken(true)); + } +#endif + } + else + { + vtst.TrySetException(exc); + } + } + }; + + /// The associated . + private IValueTaskSource _source; + /// The token to pass through to operations on + private readonly short _token; + + public ValueTaskSourceTask(IValueTaskSource source, short token) + { + _token = token; + _source = source; + source.OnCompleted(s_completionAction, this, token, ValueTaskSourceOnCompletedFlags.None); + } + } + + /// Gets whether the represents a completed operation. + public bool IsCompleted + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _obj == null || (ObjectIsTask ? UnsafeGetTask().IsCompleted : UnsafeGetValueTaskSource().GetStatus(_token) != ValueTaskSourceStatus.Pending); + } + + /// Gets whether the represents a successfully completed operation. + public bool IsCompletedSuccessfully + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => + _obj == null || + (ObjectIsTask ? +#if netstandard + UnsafeTask.Status == TaskStatus.RanToCompletion : +#else + UnsafeGetTask().IsCompletedSuccessfully : +#endif + UnsafeGetValueTaskSource().GetStatus(_token) == ValueTaskSourceStatus.Succeeded); + } + + /// Gets whether the represents a failed operation. + public bool IsFaulted + { + get => + _obj != null && + (ObjectIsTask ? UnsafeGetTask().IsFaulted : UnsafeGetValueTaskSource().GetStatus(_token) == ValueTaskSourceStatus.Faulted); + } + + /// Gets whether the represents a canceled operation. + /// + /// If the is backed by a result or by a , + /// this will always return false. If it's backed by a , it'll return the + /// value of the task's property. + /// + public bool IsCanceled + { + get => + _obj != null && + (ObjectIsTask ? UnsafeGetTask().IsCanceled : UnsafeGetValueTaskSource().GetStatus(_token) == ValueTaskSourceStatus.Canceled); + } + + /// Throws the exception that caused the to fail. If it completed successfully, nothing is thrown. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [StackTraceHidden] + internal void ThrowIfCompletedUnsuccessfully() + { + if (_obj != null) + { + if (ObjectIsTask) + { +#if netstandard + UnsafeTask.GetAwaiter().GetResult(); +#else + TaskAwaiter.ValidateEnd(UnsafeGetTask()); +#endif + } + else + { + UnsafeGetValueTaskSource().GetResult(_token); + } + } + } + + /// Gets an awaiter for this . + public ValueTaskAwaiter GetAwaiter() => new ValueTaskAwaiter(this); + + /// Configures an awaiter for this . + /// + /// true to attempt to marshal the continuation back to the captured context; otherwise, false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ConfiguredValueTaskAwaitable ConfigureAwait(bool continueOnCapturedContext) + { + // TODO: Simplify once https://github.com/dotnet/coreclr/pull/16138 is fixed. + bool avoidCapture = !continueOnCapturedContext; + return new ConfiguredValueTaskAwaitable(new ValueTask(_obj, _token, _flags | Unsafe.As(ref avoidCapture))); + } + } + + /// Provides a value type that can represent a synchronously available value or a task object. + /// Specifies the type of the result. + /// + /// s are meant to be directly awaited. To do more complicated operations with them, a + /// should be extracted using or . Such operations might include caching an instance to + /// be awaited later, registering multiple continuations with a single operation, awaiting the same task multiple times, and using + /// combinators over multiple operations. /// [AsyncMethodBuilder(typeof(AsyncValueTaskMethodBuilder<>))] [StructLayout(LayoutKind.Auto)] public readonly struct ValueTask : IEquatable> { - /// The task to be used if the operation completed asynchronously or if it completed synchronously but non-successfully. - internal readonly Task _task; + /// null if has the result, otherwise a or a . + internal readonly object _obj; /// The result to be used if the operation completed successfully synchronously. internal readonly TResult _result; + /// Flags providing additional details about the ValueTask's contents and behavior. + internal readonly ValueTaskFlags _flags; + /// Opaque value passed through to the . + internal readonly short _token; - /// Initialize the with the result of the successful operation. + // An instance created with the default ctor (a zero init'd struct) represents a synchronously, successfully completed operation + // with a result of default(TResult). + + /// Initialize the with a result value. /// The result. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public ValueTask(TResult result) { - _task = null; _result = result; + + _obj = null; + _flags = 0; + _token = 0; } - /// - /// Initialize the with a that represents the operation. - /// + /// Initialize the with a that represents the operation. /// The task. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public ValueTask(Task task) { if (task == null) @@ -76,103 +405,371 @@ namespace System.Threading.Tasks ThrowHelper.ThrowArgumentNullException(ExceptionArgument.task); } - _task = task; - _result = default(TResult); + _obj = task; + + _result = default; + _flags = ValueTaskFlags.ObjectIsTask; + _token = 0; + } + + /// Initialize the with a object that represents the operation. + /// The source. + /// Opaque value passed through to the . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ValueTask(IValueTaskSource source, short token) + { + if (source == null) + { + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); + } + + _obj = source; + _token = token; + + _result = default; + _flags = 0; + } + + /// Non-verified initialization of the struct to the specified values. + /// The object. + /// The result. + /// The token. + /// The flags. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private ValueTask(object obj, TResult result, short token, ValueTaskFlags flags) + { + _obj = obj; + _result = result; + _token = token; + _flags = flags; + } + + /// Gets whether the contination should be scheduled to the current context. + internal bool ContinueOnCapturedContext + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => (_flags & ValueTaskFlags.AvoidCapturedContext) == 0; + } + + /// Gets whether the object in the field is a . + internal bool ObjectIsTask + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => (_flags & ValueTaskFlags.ObjectIsTask) != 0; + } + + /// Returns the stored in . This uses . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Task UnsafeGetTask() + { + Debug.Assert(ObjectIsTask); + Debug.Assert(_obj is Task); + return Unsafe.As>(_obj); + } + + /// Returns the stored in . This uses . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal IValueTaskSource UnsafeGetValueTaskSource() + { + Debug.Assert(!ObjectIsTask); + Debug.Assert(_obj is IValueTaskSource); + return Unsafe.As>(_obj); } /// Returns the hash code for this instance. public override int GetHashCode() => - _task != null ? _task.GetHashCode() : + _obj != null ? _obj.GetHashCode() : _result != null ? _result.GetHashCode() : 0; /// Returns a value indicating whether this value is equal to a specified . public override bool Equals(object obj) => - obj is ValueTask && + obj is ValueTask && Equals((ValueTask)obj); /// Returns a value indicating whether this value is equal to a specified value. public bool Equals(ValueTask other) => - _task != null || other._task != null ? - _task == other._task : + _obj != null || other._obj != null ? + _obj == other._obj && _token == other._token : EqualityComparer.Default.Equals(_result, other._result); /// Returns a value indicating whether two values are equal. - public static bool operator==(ValueTask left, ValueTask right) => + public static bool operator ==(ValueTask left, ValueTask right) => left.Equals(right); /// Returns a value indicating whether two values are not equal. - public static bool operator!=(ValueTask left, ValueTask right) => + public static bool operator !=(ValueTask left, ValueTask right) => !left.Equals(right); /// - /// Gets a object to represent this ValueTask. It will - /// either return the wrapped task object if one exists, or it'll manufacture a new - /// task object to represent the result. + /// Gets a object to represent this ValueTask. /// + /// + /// It will either return the wrapped task object if one exists, or it'll + /// manufacture a new task object to represent the result. + /// public Task AsTask() => - // Return the task if we were constructed from one, otherwise manufacture one. We don't - // cache the generated task into _task as it would end up changing both equality comparison - // and the hash code we generate in GetHashCode. - _task ?? AsyncTaskMethodBuilder.GetTaskForResult(_result); + _obj == null ? +#if netstandard + Task.FromResult(_result) : +#else + AsyncTaskMethodBuilder.GetTaskForResult(_result) : +#endif + ObjectIsTask ? UnsafeGetTask() : + GetTaskForValueTaskSource(); - internal Task AsTaskExpectNonNull() => - // Return the task if we were constructed from one, otherwise manufacture one. - // Unlike AsTask(), this method is called only when we expect _task to be non-null, - // and thus we don't want GetTaskForResult inlined. - _task ?? GetTaskForResultNoInlining(); + /// Gets a that may be used at any point in the future. + public ValueTask Preserve() => _obj == null ? this : new ValueTask(AsTask()); - [MethodImpl(MethodImplOptions.NoInlining)] - private Task GetTaskForResultNoInlining() => AsyncTaskMethodBuilder.GetTaskForResult(_result); + /// Creates a to represent the . + private Task GetTaskForValueTaskSource() + { + IValueTaskSource t = UnsafeGetValueTaskSource(); + ValueTaskSourceStatus status = t.GetStatus(_token); + if (status != ValueTaskSourceStatus.Pending) + { + try + { + // Get the result of the operation and return a task for it. + // If any exception occurred, propagate it + return +#if netstandard + Task.FromResult(t.GetResult(_token)); +#else + AsyncTaskMethodBuilder.GetTaskForResult(t.GetResult(_token)); +#endif + + // If status is Faulted or Canceled, GetResult should throw. But + // we can't guarantee every implementation will do the "right thing". + // If it doesn't throw, we just treat that as success and ignore + // the status. + } + catch (Exception exc) + { + if (status == ValueTaskSourceStatus.Canceled) + { +#if netstandard + var tcs = new TaskCompletionSource(); + tcs.TrySetCanceled(); + return tcs.Task; +#else + if (exc is OperationCanceledException oce) + { + var task = new Task(); + task.TrySetCanceled(oce.CancellationToken, oce); + return task; + } + else + { + return Task.FromCanceled(new CancellationToken(true)); + } +#endif + } + else + { +#if netstandard + var tcs = new TaskCompletionSource(); + tcs.TrySetException(exc); + return tcs.Task; +#else + return Task.FromException(exc); +#endif + } + } + } + + var m = new ValueTaskSourceTask(t, _token); + return +#if netstandard + m.Task; +#else + m; +#endif + } + + /// Type used to create a to represent a . + private sealed class ValueTaskSourceTask : +#if netstandard + TaskCompletionSource +#else + Task +#endif + { + private static readonly Action s_completionAction = state => + { + if (!(state is ValueTaskSourceTask vtst) || + !(vtst._source is IValueTaskSource source)) + { + // This could only happen if the IValueTaskSource passed the wrong state + // or if this callback were invoked multiple times such that the state + // was previously nulled out. + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.state); + return; + } + + vtst._source = null; + ValueTaskSourceStatus status = source.GetStatus(vtst._token); + try + { + vtst.TrySetResult(source.GetResult(vtst._token)); + } + catch (Exception exc) + { + if (status == ValueTaskSourceStatus.Canceled) + { +#if netstandard + vtst.TrySetCanceled(); +#else + if (exc is OperationCanceledException oce) + { + vtst.TrySetCanceled(oce.CancellationToken, oce); + } + else + { + vtst.TrySetCanceled(new CancellationToken(true)); + } +#endif + } + else + { + vtst.TrySetException(exc); + } + } + }; + + /// The associated . + private IValueTaskSource _source; + /// The token to pass through to operations on + private readonly short _token; + + public ValueTaskSourceTask(IValueTaskSource source, short token) + { + _source = source; + _token = token; + source.OnCompleted(s_completionAction, this, token, ValueTaskSourceOnCompletedFlags.None); + } + } /// Gets whether the represents a completed operation. - public bool IsCompleted => _task == null || _task.IsCompleted; + public bool IsCompleted + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _obj == null || (ObjectIsTask ? UnsafeGetTask().IsCompleted : UnsafeGetValueTaskSource().GetStatus(_token) != ValueTaskSourceStatus.Pending); + } /// Gets whether the represents a successfully completed operation. - public bool IsCompletedSuccessfully => _task == null || _task.IsCompletedSuccessfully; + public bool IsCompletedSuccessfully + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => + _obj == null || + (ObjectIsTask ? +#if netstandard + UnsafeTask.Status == TaskStatus.RanToCompletion : +#else + UnsafeGetTask().IsCompletedSuccessfully : +#endif + UnsafeGetValueTaskSource().GetStatus(_token) == ValueTaskSourceStatus.Succeeded); + } /// Gets whether the represents a failed operation. - public bool IsFaulted => _task != null && _task.IsFaulted; + public bool IsFaulted + { + get => + _obj != null && + (ObjectIsTask ? UnsafeGetTask().IsFaulted : UnsafeGetValueTaskSource().GetStatus(_token) == ValueTaskSourceStatus.Faulted); + } /// Gets whether the represents a canceled operation. - public bool IsCanceled => _task != null && _task.IsCanceled; + /// + /// If the is backed by a result or by a , + /// this will always return false. If it's backed by a , it'll return the + /// value of the task's property. + /// + public bool IsCanceled + { + get => + _obj != null && + (ObjectIsTask ? UnsafeGetTask().IsCanceled : UnsafeGetValueTaskSource().GetStatus(_token) == ValueTaskSourceStatus.Canceled); + } /// Gets the result. - public TResult Result => _task == null ? _result : _task.GetAwaiter().GetResult(); + public TResult Result + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + if (_obj == null) + { + return _result; + } - /// Gets an awaiter for this value. + if (ObjectIsTask) + { +#if netstandard + return UnsafeTask.GetAwaiter().GetResult(); +#else + Task t = UnsafeGetTask(); + TaskAwaiter.ValidateEnd(t); + return t.ResultOnSuccess; +#endif + } + + return UnsafeGetValueTaskSource().GetResult(_token); + } + } + + /// Gets an awaiter for this . + [MethodImpl(MethodImplOptions.AggressiveInlining)] public ValueTaskAwaiter GetAwaiter() => new ValueTaskAwaiter(this); - /// Configures an awaiter for this value. + /// Configures an awaiter for this . /// /// true to attempt to marshal the continuation back to the captured context; otherwise, false. /// - public ConfiguredValueTaskAwaitable ConfigureAwait(bool continueOnCapturedContext) => - new ConfiguredValueTaskAwaitable(this, continueOnCapturedContext); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ConfiguredValueTaskAwaitable ConfigureAwait(bool continueOnCapturedContext) + { + // TODO: Simplify once https://github.com/dotnet/coreclr/pull/16138 is fixed. + bool avoidCapture = !continueOnCapturedContext; + return new ConfiguredValueTaskAwaitable(new ValueTask(_obj, _result, _token, _flags | Unsafe.As(ref avoidCapture))); + } /// Gets a string-representation of this . public override string ToString() { - if (_task != null) + if (IsCompletedSuccessfully) { - return _task.IsCompletedSuccessfully && _task.Result != null ? - _task.Result.ToString() : - string.Empty; - } - else - { - return _result != null ? - _result.ToString() : - string.Empty; + TResult result = Result; + if (result != null) + { + return result.ToString(); + } } + + return string.Empty; } - - // TODO https://github.com/dotnet/corefx/issues/22171: - // Remove CreateAsyncMethodBuilder once the C# compiler relies on the AsyncBuilder attribute. - - /// Creates a method builder for use with an async method. - /// The created builder. - [EditorBrowsable(EditorBrowsableState.Never)] // intended only for compiler consumption - public static AsyncValueTaskMethodBuilder CreateAsyncMethodBuilder() => AsyncValueTaskMethodBuilder.Create(); } -} + + /// Internal flags used in the implementation of and . + [Flags] + internal enum ValueTaskFlags : byte + { + /// + /// Indicates that context (e.g. SynchronizationContext) should not be captured when adding + /// a continuation. + /// + /// + /// The value here must be 0x1, to match the value of a true Boolean reinterpreted as a byte. + /// This only has meaning when awaiting a ValueTask, with ConfigureAwait creating a new + /// ValueTask setting or not setting this flag appropriately. + /// + AvoidCapturedContext = 0x1, + + /// + /// Indicates that the ValueTask's object field stores a Task. This is used to avoid + /// a type check on whatever is stored in the object field. + /// + ObjectIsTask = 0x2 + } +} \ No newline at end of file diff --git a/external/corert/src/System.Private.CoreLib/shared/System/TimeZoneInfo.AdjustmentRule.cs b/external/corert/src/System.Private.CoreLib/shared/System/TimeZoneInfo.AdjustmentRule.cs new file mode 100644 index 0000000000..0e949a30ec --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/shared/System/TimeZoneInfo.AdjustmentRule.cs @@ -0,0 +1,248 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.Serialization; + +namespace System +{ + public sealed partial class TimeZoneInfo + { + [Serializable] + public sealed class AdjustmentRule : IEquatable, ISerializable, IDeserializationCallback + { + private readonly DateTime _dateStart; + private readonly DateTime _dateEnd; + private readonly TimeSpan _daylightDelta; + private readonly TransitionTime _daylightTransitionStart; + private readonly TransitionTime _daylightTransitionEnd; + private readonly TimeSpan _baseUtcOffsetDelta; // delta from the default Utc offset (utcOffset = defaultUtcOffset + _baseUtcOffsetDelta) + private readonly bool _noDaylightTransitions; + + public DateTime DateStart => _dateStart; + + public DateTime DateEnd => _dateEnd; + + public TimeSpan DaylightDelta => _daylightDelta; + + public TransitionTime DaylightTransitionStart => _daylightTransitionStart; + + public TransitionTime DaylightTransitionEnd => _daylightTransitionEnd; + + internal TimeSpan BaseUtcOffsetDelta => _baseUtcOffsetDelta; + + /// + /// Gets a value indicating that this AdjustmentRule fixes the time zone offset + /// from DateStart to DateEnd without any daylight transitions in between. + /// + internal bool NoDaylightTransitions => _noDaylightTransitions; + + internal bool HasDaylightSaving => + DaylightDelta != TimeSpan.Zero || + (DaylightTransitionStart != default(TransitionTime) && DaylightTransitionStart.TimeOfDay != DateTime.MinValue) || + (DaylightTransitionEnd != default(TransitionTime) && DaylightTransitionEnd.TimeOfDay != DateTime.MinValue.AddMilliseconds(1)); + + public bool Equals(AdjustmentRule other) => + other != null && + _dateStart == other._dateStart && + _dateEnd == other._dateEnd && + _daylightDelta == other._daylightDelta && + _baseUtcOffsetDelta == other._baseUtcOffsetDelta && + _daylightTransitionEnd.Equals(other._daylightTransitionEnd) && + _daylightTransitionStart.Equals(other._daylightTransitionStart); + + public override int GetHashCode() => _dateStart.GetHashCode(); + + private AdjustmentRule( + DateTime dateStart, + DateTime dateEnd, + TimeSpan daylightDelta, + TransitionTime daylightTransitionStart, + TransitionTime daylightTransitionEnd, + TimeSpan baseUtcOffsetDelta, + bool noDaylightTransitions) + { + ValidateAdjustmentRule(dateStart, dateEnd, daylightDelta, + daylightTransitionStart, daylightTransitionEnd, noDaylightTransitions); + + _dateStart = dateStart; + _dateEnd = dateEnd; + _daylightDelta = daylightDelta; + _daylightTransitionStart = daylightTransitionStart; + _daylightTransitionEnd = daylightTransitionEnd; + _baseUtcOffsetDelta = baseUtcOffsetDelta; + _noDaylightTransitions = noDaylightTransitions; + } + + public static AdjustmentRule CreateAdjustmentRule( + DateTime dateStart, + DateTime dateEnd, + TimeSpan daylightDelta, + TransitionTime daylightTransitionStart, + TransitionTime daylightTransitionEnd) + { + return new AdjustmentRule( + dateStart, + dateEnd, + daylightDelta, + daylightTransitionStart, + daylightTransitionEnd, + baseUtcOffsetDelta: TimeSpan.Zero, + noDaylightTransitions: false); + } + + internal static AdjustmentRule CreateAdjustmentRule( + DateTime dateStart, + DateTime dateEnd, + TimeSpan daylightDelta, + TransitionTime daylightTransitionStart, + TransitionTime daylightTransitionEnd, + TimeSpan baseUtcOffsetDelta, + bool noDaylightTransitions) + { + return new AdjustmentRule( + dateStart, + dateEnd, + daylightDelta, + daylightTransitionStart, + daylightTransitionEnd, + baseUtcOffsetDelta, + noDaylightTransitions); + } + + // + // When Windows sets the daylight transition start Jan 1st at 12:00 AM, it means the year starts with the daylight saving on. + // We have to special case this value and not adjust it when checking if any date is in the daylight saving period. + // + internal bool IsStartDateMarkerForBeginningOfYear() => + !NoDaylightTransitions && + DaylightTransitionStart.Month == 1 && DaylightTransitionStart.Day == 1 && DaylightTransitionStart.TimeOfDay.Hour == 0 && + DaylightTransitionStart.TimeOfDay.Minute == 0 && DaylightTransitionStart.TimeOfDay.Second == 0 && + _dateStart.Year == _dateEnd.Year; + + // + // When Windows sets the daylight transition end Jan 1st at 12:00 AM, it means the year ends with the daylight saving on. + // We have to special case this value and not adjust it when checking if any date is in the daylight saving period. + // + internal bool IsEndDateMarkerForEndOfYear() => + !NoDaylightTransitions && + DaylightTransitionEnd.Month == 1 && DaylightTransitionEnd.Day == 1 && DaylightTransitionEnd.TimeOfDay.Hour == 0 && + DaylightTransitionEnd.TimeOfDay.Minute == 0 && DaylightTransitionEnd.TimeOfDay.Second == 0 && + _dateStart.Year == _dateEnd.Year; + + /// + /// Helper function that performs all of the validation checks for the factory methods and deserialization callback. + /// + private static void ValidateAdjustmentRule( + DateTime dateStart, + DateTime dateEnd, + TimeSpan daylightDelta, + TransitionTime daylightTransitionStart, + TransitionTime daylightTransitionEnd, + bool noDaylightTransitions) + { + if (dateStart.Kind != DateTimeKind.Unspecified && dateStart.Kind != DateTimeKind.Utc) + { + throw new ArgumentException(SR.Argument_DateTimeKindMustBeUnspecifiedOrUtc, nameof(dateStart)); + } + + if (dateEnd.Kind != DateTimeKind.Unspecified && dateEnd.Kind != DateTimeKind.Utc) + { + throw new ArgumentException(SR.Argument_DateTimeKindMustBeUnspecifiedOrUtc, nameof(dateEnd)); + } + + if (daylightTransitionStart.Equals(daylightTransitionEnd) && !noDaylightTransitions) + { + throw new ArgumentException(SR.Argument_TransitionTimesAreIdentical, nameof(daylightTransitionEnd)); + } + + if (dateStart > dateEnd) + { + throw new ArgumentException(SR.Argument_OutOfOrderDateTimes, nameof(dateStart)); + } + + // This cannot use UtcOffsetOutOfRange to account for the scenario where Samoa moved across the International Date Line, + // which caused their current BaseUtcOffset to be +13. But on the other side of the line it was UTC-11 (+1 for daylight). + // So when trying to describe DaylightDeltas for those times, the DaylightDelta needs + // to be -23 (what it takes to go from UTC+13 to UTC-10) + if (daylightDelta.TotalHours < -23.0 || daylightDelta.TotalHours > 14.0) + { + throw new ArgumentOutOfRangeException(nameof(daylightDelta), daylightDelta, SR.ArgumentOutOfRange_UtcOffset); + } + + if (daylightDelta.Ticks % TimeSpan.TicksPerMinute != 0) + { + throw new ArgumentException(SR.Argument_TimeSpanHasSeconds, nameof(daylightDelta)); + } + + if (dateStart != DateTime.MinValue && dateStart.Kind == DateTimeKind.Unspecified && dateStart.TimeOfDay != TimeSpan.Zero) + { + throw new ArgumentException(SR.Argument_DateTimeHasTimeOfDay, nameof(dateStart)); + } + + if (dateEnd != DateTime.MaxValue && dateEnd.Kind == DateTimeKind.Unspecified && dateEnd.TimeOfDay != TimeSpan.Zero) + { + throw new ArgumentException(SR.Argument_DateTimeHasTimeOfDay, nameof(dateEnd)); + } + } + + void IDeserializationCallback.OnDeserialization(object sender) + { + // OnDeserialization is called after each instance of this class is deserialized. + // This callback method performs AdjustmentRule validation after being deserialized. + + try + { + ValidateAdjustmentRule(_dateStart, _dateEnd, _daylightDelta, + _daylightTransitionStart, _daylightTransitionEnd, _noDaylightTransitions); + } + catch (ArgumentException e) + { + throw new SerializationException(SR.Serialization_InvalidData, e); + } + } + + void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) + { + if (info == null) + { + throw new ArgumentNullException(nameof(info)); + } + + info.AddValue("DateStart", _dateStart); // Do not rename (binary serialization) + info.AddValue("DateEnd", _dateEnd); // Do not rename (binary serialization) + info.AddValue("DaylightDelta", _daylightDelta); // Do not rename (binary serialization) + info.AddValue("DaylightTransitionStart", _daylightTransitionStart); // Do not rename (binary serialization) + info.AddValue("DaylightTransitionEnd", _daylightTransitionEnd); // Do not rename (binary serialization) + info.AddValue("BaseUtcOffsetDelta", _baseUtcOffsetDelta); // Do not rename (binary serialization) + info.AddValue("NoDaylightTransitions", _noDaylightTransitions); // Do not rename (binary serialization) + } + + private AdjustmentRule(SerializationInfo info, StreamingContext context) + { + if (info == null) + { + throw new ArgumentNullException(nameof(info)); + } + + _dateStart = (DateTime)info.GetValue("DateStart", typeof(DateTime)); // Do not rename (binary serialization) + _dateEnd = (DateTime)info.GetValue("DateEnd", typeof(DateTime)); // Do not rename (binary serialization) + _daylightDelta = (TimeSpan)info.GetValue("DaylightDelta", typeof(TimeSpan)); // Do not rename (binary serialization) + _daylightTransitionStart = (TransitionTime)info.GetValue("DaylightTransitionStart", typeof(TransitionTime)); // Do not rename (binary serialization) + _daylightTransitionEnd = (TransitionTime)info.GetValue("DaylightTransitionEnd", typeof(TransitionTime)); // Do not rename (binary serialization) + + object o = info.GetValueNoThrow("BaseUtcOffsetDelta", typeof(TimeSpan)); // Do not rename (binary serialization) + if (o != null) + { + _baseUtcOffsetDelta = (TimeSpan)o; + } + + o = info.GetValueNoThrow("NoDaylightTransitions", typeof(bool)); // Do not rename (binary serialization) + if (o != null) + { + _noDaylightTransitions = (bool)o; + } + } + } + } +} diff --git a/external/corert/src/System.Private.CoreLib/shared/System/TimeZoneInfo.StringSerializer.cs b/external/corert/src/System.Private.CoreLib/shared/System/TimeZoneInfo.StringSerializer.cs new file mode 100644 index 0000000000..e3e9ddbf58 --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/shared/System/TimeZoneInfo.StringSerializer.cs @@ -0,0 +1,625 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Globalization; +using System.Runtime.Serialization; +using System.Text; + +namespace System +{ + public sealed partial class TimeZoneInfo + { + /// + /// Used to serialize and deserialize TimeZoneInfo objects based on the custom string serialization format. + /// + private struct StringSerializer + { + private enum State + { + Escaped = 0, + NotEscaped = 1, + StartOfToken = 2, + EndOfLine = 3 + } + + private readonly string _serializedText; + private int _currentTokenStartIndex; + private State _state; + + // the majority of the strings contained in the OS time zones fit in 64 chars + private const int InitialCapacityForString = 64; + private const char Esc = '\\'; + private const char Sep = ';'; + private const char Lhs = '['; + private const char Rhs = ']'; + private const string DateTimeFormat = "MM:dd:yyyy"; + private const string TimeOfDayFormat = "HH:mm:ss.FFF"; + + /// + /// Creates the custom serialized string representation of a TimeZoneInfo instance. + /// + public static string GetSerializedString(TimeZoneInfo zone) + { + StringBuilder serializedText = StringBuilderCache.Acquire(); + + // + // <_id>;<_baseUtcOffset>;<_displayName>;<_standardDisplayName>;<_daylightDispayName> + // + SerializeSubstitute(zone.Id, serializedText); + serializedText.Append(Sep); + serializedText.Append(zone.BaseUtcOffset.TotalMinutes.ToString(CultureInfo.InvariantCulture)); + serializedText.Append(Sep); + SerializeSubstitute(zone.DisplayName, serializedText); + serializedText.Append(Sep); + SerializeSubstitute(zone.StandardName, serializedText); + serializedText.Append(Sep); + SerializeSubstitute(zone.DaylightName, serializedText); + serializedText.Append(Sep); + + AdjustmentRule[] rules = zone.GetAdjustmentRules(); + foreach (AdjustmentRule rule in rules) + { + serializedText.Append(Lhs); + serializedText.Append(rule.DateStart.ToString(DateTimeFormat, DateTimeFormatInfo.InvariantInfo)); + serializedText.Append(Sep); + serializedText.Append(rule.DateEnd.ToString(DateTimeFormat, DateTimeFormatInfo.InvariantInfo)); + serializedText.Append(Sep); + serializedText.Append(rule.DaylightDelta.TotalMinutes.ToString(CultureInfo.InvariantCulture)); + serializedText.Append(Sep); + // serialize the TransitionTime's + SerializeTransitionTime(rule.DaylightTransitionStart, serializedText); + serializedText.Append(Sep); + SerializeTransitionTime(rule.DaylightTransitionEnd, serializedText); + serializedText.Append(Sep); + if (rule.BaseUtcOffsetDelta != TimeSpan.Zero) + { + // Serialize it only when BaseUtcOffsetDelta has a value to reduce the impact of adding rule.BaseUtcOffsetDelta + serializedText.Append(rule.BaseUtcOffsetDelta.TotalMinutes.ToString(CultureInfo.InvariantCulture)); + serializedText.Append(Sep); + } + if (rule.NoDaylightTransitions) + { + // Serialize it only when NoDaylightTransitions is true to reduce the impact of adding rule.NoDaylightTransitions + serializedText.Append('1'); + serializedText.Append(Sep); + } + serializedText.Append(Rhs); + } + serializedText.Append(Sep); + + return StringBuilderCache.GetStringAndRelease(serializedText); + } + + /// + /// Instantiates a TimeZoneInfo from a custom serialized string. + /// + public static TimeZoneInfo GetDeserializedTimeZoneInfo(string source) + { + StringSerializer s = new StringSerializer(source); + + string id = s.GetNextStringValue(); + TimeSpan baseUtcOffset = s.GetNextTimeSpanValue(); + string displayName = s.GetNextStringValue(); + string standardName = s.GetNextStringValue(); + string daylightName = s.GetNextStringValue(); + AdjustmentRule[] rules = s.GetNextAdjustmentRuleArrayValue(); + + try + { + return new TimeZoneInfo(id, baseUtcOffset, displayName, standardName, daylightName, rules, disableDaylightSavingTime: false); + } + catch (ArgumentException ex) + { + throw new SerializationException(SR.Serialization_InvalidData, ex); + } + catch (InvalidTimeZoneException ex) + { + throw new SerializationException(SR.Serialization_InvalidData, ex); + } + } + + private StringSerializer(string str) + { + _serializedText = str; + _currentTokenStartIndex = 0; + _state = State.StartOfToken; + } + + /// + /// Appends the String to the StringBuilder with all of the reserved chars escaped. + /// + /// ";" -> "\;" + /// "[" -> "\[" + /// "]" -> "\]" + /// "\" -> "\\" + /// + private static void SerializeSubstitute(string text, StringBuilder serializedText) + { + foreach (char c in text) + { + if (c == Esc || c == Lhs || c == Rhs || c == Sep) + { + serializedText.Append('\\'); + } + serializedText.Append(c); + } + } + + /// + /// Helper method to serialize a TimeZoneInfo.TransitionTime object. + /// + private static void SerializeTransitionTime(TransitionTime time, StringBuilder serializedText) + { + serializedText.Append(Lhs); + serializedText.Append(time.IsFixedDateRule ? '1' : '0'); + serializedText.Append(Sep); + serializedText.Append(time.TimeOfDay.ToString(TimeOfDayFormat, DateTimeFormatInfo.InvariantInfo)); + serializedText.Append(Sep); + serializedText.Append(time.Month.ToString(CultureInfo.InvariantCulture)); + serializedText.Append(Sep); + if (time.IsFixedDateRule) + { + serializedText.Append(time.Day.ToString(CultureInfo.InvariantCulture)); + serializedText.Append(Sep); + } + else + { + serializedText.Append(time.Week.ToString(CultureInfo.InvariantCulture)); + serializedText.Append(Sep); + serializedText.Append(((int)time.DayOfWeek).ToString(CultureInfo.InvariantCulture)); + serializedText.Append(Sep); + } + serializedText.Append(Rhs); + } + + /// + /// Helper function to determine if the passed in string token is allowed to be preceded by an escape sequence token. + /// + private static void VerifyIsEscapableCharacter(char c) + { + if (c != Esc && c != Sep && c != Lhs && c != Rhs) + { + throw new SerializationException(SR.Format(SR.Serialization_InvalidEscapeSequence, c)); + } + } + + /// + /// Helper function that reads past "v.Next" data fields. Receives a "depth" parameter indicating the + /// current relative nested bracket depth that _currentTokenStartIndex is at. The function ends + /// successfully when "depth" returns to zero (0). + /// + private void SkipVersionNextDataFields(int depth /* starting depth in the nested brackets ('[', ']')*/) + { + if (_currentTokenStartIndex < 0 || _currentTokenStartIndex >= _serializedText.Length) + { + throw new SerializationException(SR.Serialization_InvalidData); + } + State tokenState = State.NotEscaped; + + // walk the serialized text, building up the token as we go... + for (int i = _currentTokenStartIndex; i < _serializedText.Length; i++) + { + if (tokenState == State.Escaped) + { + VerifyIsEscapableCharacter(_serializedText[i]); + tokenState = State.NotEscaped; + } + else if (tokenState == State.NotEscaped) + { + switch (_serializedText[i]) + { + case Esc: + tokenState = State.Escaped; + break; + + case Lhs: + depth++; + break; + case Rhs: + depth--; + if (depth == 0) + { + _currentTokenStartIndex = i + 1; + if (_currentTokenStartIndex >= _serializedText.Length) + { + _state = State.EndOfLine; + } + else + { + _state = State.StartOfToken; + } + return; + } + break; + + case '\0': + // invalid character + throw new SerializationException(SR.Serialization_InvalidData); + + default: + break; + } + } + } + + throw new SerializationException(SR.Serialization_InvalidData); + } + + /// + /// Helper function that reads a string token from the serialized text. The function + /// updates to point to the next token on exit. + /// Also is set to either or + /// on exit. + /// + private string GetNextStringValue() + { + // first verify the internal state of the object + if (_state == State.EndOfLine) + { + throw new SerializationException(SR.Serialization_InvalidData); + } + if (_currentTokenStartIndex < 0 || _currentTokenStartIndex >= _serializedText.Length) + { + throw new SerializationException(SR.Serialization_InvalidData); + } + State tokenState = State.NotEscaped; + StringBuilder token = StringBuilderCache.Acquire(InitialCapacityForString); + + // walk the serialized text, building up the token as we go... + for (int i = _currentTokenStartIndex; i < _serializedText.Length; i++) + { + if (tokenState == State.Escaped) + { + VerifyIsEscapableCharacter(_serializedText[i]); + token.Append(_serializedText[i]); + tokenState = State.NotEscaped; + } + else if (tokenState == State.NotEscaped) + { + switch (_serializedText[i]) + { + case Esc: + tokenState = State.Escaped; + break; + + case Lhs: + // '[' is an unexpected character + throw new SerializationException(SR.Serialization_InvalidData); + + case Rhs: + // ']' is an unexpected character + throw new SerializationException(SR.Serialization_InvalidData); + + case Sep: + _currentTokenStartIndex = i + 1; + if (_currentTokenStartIndex >= _serializedText.Length) + { + _state = State.EndOfLine; + } + else + { + _state = State.StartOfToken; + } + return StringBuilderCache.GetStringAndRelease(token); + + case '\0': + // invalid character + throw new SerializationException(SR.Serialization_InvalidData); + + default: + token.Append(_serializedText[i]); + break; + } + } + } + // + // we are at the end of the line + // + if (tokenState == State.Escaped) + { + // we are at the end of the serialized text but we are in an escaped state + throw new SerializationException(SR.Format(SR.Serialization_InvalidEscapeSequence, string.Empty)); + } + + throw new SerializationException(SR.Serialization_InvalidData); + } + + /// + /// Helper function to read a DateTime token. + /// + private DateTime GetNextDateTimeValue(string format) + { + string token = GetNextStringValue(); + DateTime time; + if (!DateTime.TryParseExact(token, format, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.None, out time)) + { + throw new SerializationException(SR.Serialization_InvalidData); + } + return time; + } + + /// + /// Helper function to read a TimeSpan token. + /// + private TimeSpan GetNextTimeSpanValue() + { + int token = GetNextInt32Value(); + try + { + return new TimeSpan(hours: 0, minutes: token, seconds: 0); + } + catch (ArgumentOutOfRangeException e) + { + throw new SerializationException(SR.Serialization_InvalidData, e); + } + } + + /// + /// Helper function to read an Int32 token. + /// + private int GetNextInt32Value() + { + string token = GetNextStringValue(); + int value; + if (!int.TryParse(token, NumberStyles.AllowLeadingSign /* "[sign]digits" */, CultureInfo.InvariantCulture, out value)) + { + throw new SerializationException(SR.Serialization_InvalidData); + } + return value; + } + + /// + /// Helper function to read an AdjustmentRule[] token. + /// + private AdjustmentRule[] GetNextAdjustmentRuleArrayValue() + { + List rules = new List(1); + int count = 0; + + // individual AdjustmentRule array elements do not require semicolons + AdjustmentRule rule = GetNextAdjustmentRuleValue(); + while (rule != null) + { + rules.Add(rule); + count++; + + rule = GetNextAdjustmentRuleValue(); + } + + // the AdjustmentRule array must end with a separator + if (_state == State.EndOfLine) + { + throw new SerializationException(SR.Serialization_InvalidData); + } + if (_currentTokenStartIndex < 0 || _currentTokenStartIndex >= _serializedText.Length) + { + throw new SerializationException(SR.Serialization_InvalidData); + } + + return count != 0 ? rules.ToArray() : null; + } + + /// + /// Helper function to read an AdjustmentRule token. + /// + private AdjustmentRule GetNextAdjustmentRuleValue() + { + // first verify the internal state of the object + if (_state == State.EndOfLine) + { + return null; + } + + if (_currentTokenStartIndex < 0 || _currentTokenStartIndex >= _serializedText.Length) + { + throw new SerializationException(SR.Serialization_InvalidData); + } + + // check to see if the very first token we see is the separator + if (_serializedText[_currentTokenStartIndex] == Sep) + { + return null; + } + + // verify the current token is a left-hand-side marker ("[") + if (_serializedText[_currentTokenStartIndex] != Lhs) + { + throw new SerializationException(SR.Serialization_InvalidData); + } + _currentTokenStartIndex++; + + DateTime dateStart = GetNextDateTimeValue(DateTimeFormat); + DateTime dateEnd = GetNextDateTimeValue(DateTimeFormat); + TimeSpan daylightDelta = GetNextTimeSpanValue(); + TransitionTime daylightStart = GetNextTransitionTimeValue(); + TransitionTime daylightEnd = GetNextTransitionTimeValue(); + TimeSpan baseUtcOffsetDelta = TimeSpan.Zero; + int noDaylightTransitions = 0; + + // verify that the string is now at the right-hand-side marker ("]") ... + + if (_state == State.EndOfLine || _currentTokenStartIndex >= _serializedText.Length) + { + throw new SerializationException(SR.Serialization_InvalidData); + } + + // Check if we have baseUtcOffsetDelta in the serialized string and then deserialize it + if ((_serializedText[_currentTokenStartIndex] >= '0' && _serializedText[_currentTokenStartIndex] <= '9') || + _serializedText[_currentTokenStartIndex] == '-' || _serializedText[_currentTokenStartIndex] == '+') + { + baseUtcOffsetDelta = GetNextTimeSpanValue(); + } + + // Check if we have NoDaylightTransitions in the serialized string and then deserialize it + if ((_serializedText[_currentTokenStartIndex] >= '0' && _serializedText[_currentTokenStartIndex] <= '1')) + { + noDaylightTransitions = GetNextInt32Value(); + } + + if (_state == State.EndOfLine || _currentTokenStartIndex >= _serializedText.Length) + { + throw new SerializationException(SR.Serialization_InvalidData); + } + + if (_serializedText[_currentTokenStartIndex] != Rhs) + { + // skip ahead of any "v.Next" data at the end of the AdjustmentRule + // + // FUTURE: if the serialization format is extended in the future then this + // code section will need to be changed to read the new fields rather + // than just skipping the data at the end of the [AdjustmentRule]. + SkipVersionNextDataFields(1); + } + else + { + _currentTokenStartIndex++; + } + + // create the AdjustmentRule from the deserialized fields ... + + AdjustmentRule rule; + try + { + rule = AdjustmentRule.CreateAdjustmentRule(dateStart, dateEnd, daylightDelta, daylightStart, daylightEnd, baseUtcOffsetDelta, noDaylightTransitions > 0); + } + catch (ArgumentException e) + { + throw new SerializationException(SR.Serialization_InvalidData, e); + } + + // finally set the state to either EndOfLine or StartOfToken for the next caller + if (_currentTokenStartIndex >= _serializedText.Length) + { + _state = State.EndOfLine; + } + else + { + _state = State.StartOfToken; + } + return rule; + } + + /// + /// Helper function to read a TransitionTime token. + /// + private TransitionTime GetNextTransitionTimeValue() + { + // first verify the internal state of the object + + if (_state == State.EndOfLine || + (_currentTokenStartIndex < _serializedText.Length && _serializedText[_currentTokenStartIndex] == Rhs)) + { + // + // we are at the end of the line or we are starting at a "]" character + // + throw new SerializationException(SR.Serialization_InvalidData); + } + + if (_currentTokenStartIndex < 0 || _currentTokenStartIndex >= _serializedText.Length) + { + throw new SerializationException(SR.Serialization_InvalidData); + } + + // verify the current token is a left-hand-side marker ("[") + + if (_serializedText[_currentTokenStartIndex] != Lhs) + { + throw new SerializationException(SR.Serialization_InvalidData); + } + _currentTokenStartIndex++; + + int isFixedDate = GetNextInt32Value(); + + if (isFixedDate != 0 && isFixedDate != 1) + { + throw new SerializationException(SR.Serialization_InvalidData); + } + + TransitionTime transition; + + DateTime timeOfDay = GetNextDateTimeValue(TimeOfDayFormat); + timeOfDay = new DateTime(1, 1, 1, timeOfDay.Hour, timeOfDay.Minute, timeOfDay.Second, timeOfDay.Millisecond); + + int month = GetNextInt32Value(); + + if (isFixedDate == 1) + { + int day = GetNextInt32Value(); + + try + { + transition = TransitionTime.CreateFixedDateRule(timeOfDay, month, day); + } + catch (ArgumentException e) + { + throw new SerializationException(SR.Serialization_InvalidData, e); + } + } + else + { + int week = GetNextInt32Value(); + int dayOfWeek = GetNextInt32Value(); + + try + { + transition = TransitionTime.CreateFloatingDateRule(timeOfDay, month, week, (DayOfWeek)dayOfWeek); + } + catch (ArgumentException e) + { + throw new SerializationException(SR.Serialization_InvalidData, e); + } + } + + // verify that the string is now at the right-hand-side marker ("]") ... + + if (_state == State.EndOfLine || _currentTokenStartIndex >= _serializedText.Length) + { + throw new SerializationException(SR.Serialization_InvalidData); + } + + if (_serializedText[_currentTokenStartIndex] != Rhs) + { + // skip ahead of any "v.Next" data at the end of the AdjustmentRule + // + // FUTURE: if the serialization format is extended in the future then this + // code section will need to be changed to read the new fields rather + // than just skipping the data at the end of the [TransitionTime]. + SkipVersionNextDataFields(1); + } + else + { + _currentTokenStartIndex++; + } + + // check to see if the string is now at the separator (";") ... + bool sepFound = false; + if (_currentTokenStartIndex < _serializedText.Length && + _serializedText[_currentTokenStartIndex] == Sep) + { + // handle the case where we ended on a ";" + _currentTokenStartIndex++; + sepFound = true; + } + + if (!sepFound) + { + // we MUST end on a separator + throw new SerializationException(SR.Serialization_InvalidData); + } + + // finally set the state to either EndOfLine or StartOfToken for the next caller + if (_currentTokenStartIndex >= _serializedText.Length) + { + _state = State.EndOfLine; + } + else + { + _state = State.StartOfToken; + } + return transition; + } + } + } +} diff --git a/external/corert/src/System.Private.CoreLib/shared/System/TimeZoneInfo.TransitionTime.cs b/external/corert/src/System.Private.CoreLib/shared/System/TimeZoneInfo.TransitionTime.cs new file mode 100644 index 0000000000..b93794262c --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/shared/System/TimeZoneInfo.TransitionTime.cs @@ -0,0 +1,155 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.Serialization; + +namespace System +{ + public sealed partial class TimeZoneInfo + { + [Serializable] + public readonly struct TransitionTime : IEquatable, ISerializable, IDeserializationCallback + { + private readonly DateTime _timeOfDay; + private readonly byte _month; + private readonly byte _week; + private readonly byte _day; + private readonly DayOfWeek _dayOfWeek; + private readonly bool _isFixedDateRule; + + public DateTime TimeOfDay => _timeOfDay; + + public int Month => _month; + + public int Week => _week; + + public int Day => _day; + + public DayOfWeek DayOfWeek => _dayOfWeek; + + public bool IsFixedDateRule => _isFixedDateRule; + + public override bool Equals(object obj) => + obj is TransitionTime && Equals((TransitionTime)obj); + + public static bool operator ==(TransitionTime t1, TransitionTime t2) => t1.Equals(t2); + + public static bool operator !=(TransitionTime t1, TransitionTime t2) => !t1.Equals(t2); + + public bool Equals(TransitionTime other) => + _isFixedDateRule == other._isFixedDateRule && + _timeOfDay == other._timeOfDay && + _month == other._month && + (other._isFixedDateRule ? + _day == other._day : + _week == other._week && _dayOfWeek == other._dayOfWeek); + + public override int GetHashCode() => (int)_month ^ (int)_week << 8; + + private TransitionTime(DateTime timeOfDay, int month, int week, int day, DayOfWeek dayOfWeek, bool isFixedDateRule) + { + ValidateTransitionTime(timeOfDay, month, week, day, dayOfWeek); + + _timeOfDay = timeOfDay; + _month = (byte)month; + _week = (byte)week; + _day = (byte)day; + _dayOfWeek = dayOfWeek; + _isFixedDateRule = isFixedDateRule; + } + + public static TransitionTime CreateFixedDateRule(DateTime timeOfDay, int month, int day) => + new TransitionTime(timeOfDay, month, 1, day, DayOfWeek.Sunday, isFixedDateRule: true); + + public static TransitionTime CreateFloatingDateRule(DateTime timeOfDay, int month, int week, DayOfWeek dayOfWeek) => + new TransitionTime(timeOfDay, month, week, 1, dayOfWeek, isFixedDateRule: false); + + /// + /// Helper function that validates a TransitionTime instance. + /// + private static void ValidateTransitionTime(DateTime timeOfDay, int month, int week, int day, DayOfWeek dayOfWeek) + { + if (timeOfDay.Kind != DateTimeKind.Unspecified) + { + throw new ArgumentException(SR.Argument_DateTimeKindMustBeUnspecified, nameof(timeOfDay)); + } + + // Month range 1-12 + if (month < 1 || month > 12) + { + throw new ArgumentOutOfRangeException(nameof(month), SR.ArgumentOutOfRange_MonthParam); + } + + // Day range 1-31 + if (day < 1 || day > 31) + { + throw new ArgumentOutOfRangeException(nameof(day), SR.ArgumentOutOfRange_DayParam); + } + + // Week range 1-5 + if (week < 1 || week > 5) + { + throw new ArgumentOutOfRangeException(nameof(week), SR.ArgumentOutOfRange_Week); + } + + // DayOfWeek range 0-6 + if ((int)dayOfWeek < 0 || (int)dayOfWeek > 6) + { + throw new ArgumentOutOfRangeException(nameof(dayOfWeek), SR.ArgumentOutOfRange_DayOfWeek); + } + + timeOfDay.GetDatePart(out int timeOfDayYear, out int timeOfDayMonth, out int timeOfDayDay); + if (timeOfDayYear != 1 || timeOfDayMonth != 1 || timeOfDayDay != 1 || (timeOfDay.Ticks % TimeSpan.TicksPerMillisecond != 0)) + { + throw new ArgumentException(SR.Argument_DateTimeHasTicks, nameof(timeOfDay)); + } + } + + void IDeserializationCallback.OnDeserialization(object sender) + { + // OnDeserialization is called after each instance of this class is deserialized. + // This callback method performs TransitionTime validation after being deserialized. + + try + { + ValidateTransitionTime(_timeOfDay, _month, _week, _day, _dayOfWeek); + } + catch (ArgumentException e) + { + throw new SerializationException(SR.Serialization_InvalidData, e); + } + } + + void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) + { + if (info == null) + { + throw new ArgumentNullException(nameof(info)); + } + + info.AddValue("TimeOfDay", _timeOfDay); // Do not rename (binary serialization) + info.AddValue("Month", _month); // Do not rename (binary serialization) + info.AddValue("Week", _week); // Do not rename (binary serialization) + info.AddValue("Day", _day); // Do not rename (binary serialization) + info.AddValue("DayOfWeek", _dayOfWeek); // Do not rename (binary serialization) + info.AddValue("IsFixedDateRule", _isFixedDateRule); // Do not rename (binary serialization) + } + + private TransitionTime(SerializationInfo info, StreamingContext context) + { + if (info == null) + { + throw new ArgumentNullException(nameof(info)); + } + + _timeOfDay = (DateTime)info.GetValue("TimeOfDay", typeof(DateTime)); // Do not rename (binary serialization) + _month = (byte)info.GetValue("Month", typeof(byte)); // Do not rename (binary serialization) + _week = (byte)info.GetValue("Week", typeof(byte)); // Do not rename (binary serialization) + _day = (byte)info.GetValue("Day", typeof(byte)); // Do not rename (binary serialization) + _dayOfWeek = (DayOfWeek)info.GetValue("DayOfWeek", typeof(DayOfWeek)); // Do not rename (binary serialization) + _isFixedDateRule = (bool)info.GetValue("IsFixedDateRule", typeof(bool)); // Do not rename (binary serialization) + } + } + } +} diff --git a/external/corert/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Unix.cs b/external/corert/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Unix.cs new file mode 100644 index 0000000000..410eaf3ff1 --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Unix.cs @@ -0,0 +1,1560 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Text; +using System.Threading; +using System.Security; + +using Internal.IO; + +namespace System +{ + public sealed partial class TimeZoneInfo + { + private const string DefaultTimeZoneDirectory = "/usr/share/zoneinfo/"; + private const string ZoneTabFileName = "zone.tab"; + private const string TimeZoneEnvironmentVariable = "TZ"; + private const string TimeZoneDirectoryEnvironmentVariable = "TZDIR"; + + private TimeZoneInfo(byte[] data, string id, bool dstDisabled) + { + TZifHead t; + DateTime[] dts; + byte[] typeOfLocalTime; + TZifType[] transitionType; + string zoneAbbreviations; + bool[] StandardTime; + bool[] GmtTime; + string futureTransitionsPosixFormat; + + // parse the raw TZif bytes; this method can throw ArgumentException when the data is malformed. + TZif_ParseRaw(data, out t, out dts, out typeOfLocalTime, out transitionType, out zoneAbbreviations, out StandardTime, out GmtTime, out futureTransitionsPosixFormat); + + _id = id; + _displayName = LocalId; + _baseUtcOffset = TimeSpan.Zero; + + // find the best matching baseUtcOffset and display strings based on the current utcNow value. + // NOTE: read the display strings from the tzfile now in case they can't be loaded later + // from the globalization data. + DateTime utcNow = DateTime.UtcNow; + for (int i = 0; i < dts.Length && dts[i] <= utcNow; i++) + { + int type = typeOfLocalTime[i]; + if (!transitionType[type].IsDst) + { + _baseUtcOffset = transitionType[type].UtcOffset; + _standardDisplayName = TZif_GetZoneAbbreviation(zoneAbbreviations, transitionType[type].AbbreviationIndex); + } + else + { + _daylightDisplayName = TZif_GetZoneAbbreviation(zoneAbbreviations, transitionType[type].AbbreviationIndex); + } + } + + if (dts.Length == 0) + { + // time zones like Africa/Bujumbura and Etc/GMT* have no transition times but still contain + // TZifType entries that may contain a baseUtcOffset and display strings + for (int i = 0; i < transitionType.Length; i++) + { + if (!transitionType[i].IsDst) + { + _baseUtcOffset = transitionType[i].UtcOffset; + _standardDisplayName = TZif_GetZoneAbbreviation(zoneAbbreviations, transitionType[i].AbbreviationIndex); + } + else + { + _daylightDisplayName = TZif_GetZoneAbbreviation(zoneAbbreviations, transitionType[i].AbbreviationIndex); + } + } + } + _displayName = _standardDisplayName; + + GetDisplayName(Interop.Globalization.TimeZoneDisplayNameType.Generic, ref _displayName); + GetDisplayName(Interop.Globalization.TimeZoneDisplayNameType.Standard, ref _standardDisplayName); + GetDisplayName(Interop.Globalization.TimeZoneDisplayNameType.DaylightSavings, ref _daylightDisplayName); + + // TZif supports seconds-level granularity with offsets but TimeZoneInfo only supports minutes since it aligns + // with DateTimeOffset, SQL Server, and the W3C XML Specification + if (_baseUtcOffset.Ticks % TimeSpan.TicksPerMinute != 0) + { + _baseUtcOffset = new TimeSpan(_baseUtcOffset.Hours, _baseUtcOffset.Minutes, 0); + } + + if (!dstDisabled) + { + // only create the adjustment rule if DST is enabled + TZif_GenerateAdjustmentRules(out _adjustmentRules, _baseUtcOffset, dts, typeOfLocalTime, transitionType, StandardTime, GmtTime, futureTransitionsPosixFormat); + } + + ValidateTimeZoneInfo(_id, _baseUtcOffset, _adjustmentRules, out _supportsDaylightSavingTime); + } + + private void GetDisplayName(Interop.Globalization.TimeZoneDisplayNameType nameType, ref string displayName) + { + if (GlobalizationMode.Invariant) + { + displayName = _standardDisplayName; + return; + } + + string timeZoneDisplayName; + bool result = Interop.CallStringMethod( + (locale, id, type, stringBuilder) => Interop.Globalization.GetTimeZoneDisplayName( + locale, + id, + type, + stringBuilder, + stringBuilder.Capacity), + CultureInfo.CurrentUICulture.Name, + _id, + nameType, + out timeZoneDisplayName); + + // If there is an unknown error, don't set the displayName field. + // It will be set to the abbreviation that was read out of the tzfile. + if (result) + { + displayName = timeZoneDisplayName; + } + } + + /// + /// Returns a cloned array of AdjustmentRule objects + /// + public AdjustmentRule[] GetAdjustmentRules() + { + if (_adjustmentRules == null) + { + return Array.Empty(); + } + + // The rules we use in Unix care mostly about the start and end dates but don't fill the transition start and end info. + // as the rules now is public, we should fill it properly so the caller doesn't have to know how we use it internally + // and can use it as it is used in Windows + + AdjustmentRule[] rules = new AdjustmentRule[_adjustmentRules.Length]; + + for (int i = 0; i < _adjustmentRules.Length; i++) + { + var rule = _adjustmentRules[i]; + var start = rule.DateStart.Kind == DateTimeKind.Utc ? + // At the daylight start we didn't start the daylight saving yet then we convert to Local time + // by adding the _baseUtcOffset to the UTC time + new DateTime(rule.DateStart.Ticks + _baseUtcOffset.Ticks, DateTimeKind.Unspecified) : + rule.DateStart; + var end = rule.DateEnd.Kind == DateTimeKind.Utc ? + // At the daylight saving end, the UTC time is mapped to local time which is already shifted by the daylight delta + // we calculate the local time by adding _baseUtcOffset + DaylightDelta to the UTC time + new DateTime(rule.DateEnd.Ticks + _baseUtcOffset.Ticks + rule.DaylightDelta.Ticks, DateTimeKind.Unspecified) : + rule.DateEnd; + + var startTransition = TimeZoneInfo.TransitionTime.CreateFixedDateRule(new DateTime(1, 1, 1, start.Hour, start.Minute, start.Second), start.Month, start.Day); + var endTransition = TimeZoneInfo.TransitionTime.CreateFixedDateRule(new DateTime(1, 1, 1, end.Hour, end.Minute, end.Second), end.Month, end.Day); + + rules[i] = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(start.Date, end.Date, rule.DaylightDelta, startTransition, endTransition); + } + + return rules; + } + + private static void PopulateAllSystemTimeZones(CachedData cachedData) + { + Debug.Assert(Monitor.IsEntered(cachedData)); + + string timeZoneDirectory = GetTimeZoneDirectory(); + foreach (string timeZoneId in GetTimeZoneIds(timeZoneDirectory)) + { + TimeZoneInfo value; + Exception ex; + TryGetTimeZone(timeZoneId, false, out value, out ex, cachedData, alwaysFallbackToLocalMachine: true); // populate the cache + } + } + + /// + /// Helper function for retrieving the local system time zone. + /// May throw COMException, TimeZoneNotFoundException, InvalidTimeZoneException. + /// Assumes cachedData lock is taken. + /// + /// A new TimeZoneInfo instance. + private static TimeZoneInfo GetLocalTimeZone(CachedData cachedData) + { + Debug.Assert(Monitor.IsEntered(cachedData)); + + // Without Registry support, create the TimeZoneInfo from a TZ file + return GetLocalTimeZoneFromTzFile(); + } + + private static TimeZoneInfoResult TryGetTimeZoneFromLocalMachine(string id, out TimeZoneInfo value, out Exception e) + { + value = null; + e = null; + + string timeZoneDirectory = GetTimeZoneDirectory(); + string timeZoneFilePath = Path.Combine(timeZoneDirectory, id); + byte[] rawData; + try + { + rawData = File.ReadAllBytes(timeZoneFilePath); + } + catch (UnauthorizedAccessException ex) + { + e = ex; + return TimeZoneInfoResult.SecurityException; + } + catch (FileNotFoundException ex) + { + e = ex; + return TimeZoneInfoResult.TimeZoneNotFoundException; + } + catch (DirectoryNotFoundException ex) + { + e = ex; + return TimeZoneInfoResult.TimeZoneNotFoundException; + } + catch (IOException ex) + { + e = new InvalidTimeZoneException(SR.Format(SR.InvalidTimeZone_InvalidFileData, id, timeZoneFilePath), ex); + return TimeZoneInfoResult.InvalidTimeZoneException; + } + + value = GetTimeZoneFromTzData(rawData, id); + + if (value == null) + { + e = new InvalidTimeZoneException(SR.Format(SR.InvalidTimeZone_InvalidFileData, id, timeZoneFilePath)); + return TimeZoneInfoResult.InvalidTimeZoneException; + } + + return TimeZoneInfoResult.Success; + } + + /// + /// Returns a collection of TimeZone Id values from the zone.tab file in the timeZoneDirectory. + /// + /// + /// Lines that start with # are comments and are skipped. + /// + private static List GetTimeZoneIds(string timeZoneDirectory) + { + List timeZoneIds = new List(); + + try + { + using (StreamReader sr = new StreamReader(Path.Combine(timeZoneDirectory, ZoneTabFileName), Encoding.UTF8)) + { + string zoneTabFileLine; + while ((zoneTabFileLine = sr.ReadLine()) != null) + { + if (!string.IsNullOrEmpty(zoneTabFileLine) && zoneTabFileLine[0] != '#') + { + // the format of the line is "country-code \t coordinates \t TimeZone Id \t comments" + + int firstTabIndex = zoneTabFileLine.IndexOf('\t'); + if (firstTabIndex != -1) + { + int secondTabIndex = zoneTabFileLine.IndexOf('\t', firstTabIndex + 1); + if (secondTabIndex != -1) + { + string timeZoneId; + int startIndex = secondTabIndex + 1; + int thirdTabIndex = zoneTabFileLine.IndexOf('\t', startIndex); + if (thirdTabIndex != -1) + { + int length = thirdTabIndex - startIndex; + timeZoneId = zoneTabFileLine.Substring(startIndex, length); + } + else + { + timeZoneId = zoneTabFileLine.Substring(startIndex); + } + + if (!string.IsNullOrEmpty(timeZoneId)) + { + timeZoneIds.Add(timeZoneId); + } + } + } + } + } + } + } + catch (IOException) { } + catch (UnauthorizedAccessException) { } + + return timeZoneIds; + } + + /// + /// Gets the tzfile raw data for the current 'local' time zone using the following rules. + /// 1. Read the TZ environment variable. If it is set, use it. + /// 2. Look for the data in /etc/localtime. + /// 3. Look for the data in GetTimeZoneDirectory()/localtime. + /// 4. Use UTC if all else fails. + /// + private static bool TryGetLocalTzFile(out byte[] rawData, out string id) + { + rawData = null; + id = null; + string tzVariable = GetTzEnvironmentVariable(); + + // If the env var is null, use the localtime file + if (tzVariable == null) + { + return + TryLoadTzFile("/etc/localtime", ref rawData, ref id) || + TryLoadTzFile(Path.Combine(GetTimeZoneDirectory(), "localtime"), ref rawData, ref id); + } + + // If it's empty, use UTC (TryGetLocalTzFile() should return false). + if (tzVariable.Length == 0) + { + return false; + } + + // Otherwise, use the path from the env var. If it's not absolute, make it relative + // to the system timezone directory + string tzFilePath; + if (tzVariable[0] != '/') + { + id = tzVariable; + tzFilePath = Path.Combine(GetTimeZoneDirectory(), tzVariable); + } + else + { + tzFilePath = tzVariable; + } + return TryLoadTzFile(tzFilePath, ref rawData, ref id); + } + + private static string GetTzEnvironmentVariable() + { + string result = Environment.GetEnvironmentVariable(TimeZoneEnvironmentVariable); + if (!string.IsNullOrEmpty(result)) + { + if (result[0] == ':') + { + // strip off the ':' prefix + result = result.Substring(1); + } + } + + return result; + } + + private static bool TryLoadTzFile(string tzFilePath, ref byte[] rawData, ref string id) + { + if (File.Exists(tzFilePath)) + { + try + { + rawData = File.ReadAllBytes(tzFilePath); + if (string.IsNullOrEmpty(id)) + { + id = FindTimeZoneIdUsingReadLink(tzFilePath); + + if (string.IsNullOrEmpty(id)) + { + id = FindTimeZoneId(rawData); + } + } + return true; + } + catch (IOException) { } + catch (SecurityException) { } + catch (UnauthorizedAccessException) { } + } + return false; + } + + /// + /// Finds the time zone id by using 'readlink' on the path to see if tzFilePath is + /// a symlink to a file. + /// + private static string FindTimeZoneIdUsingReadLink(string tzFilePath) + { + string id = null; + + string symlinkPath = Interop.Sys.ReadLink(tzFilePath); + if (symlinkPath != null) + { + // Use Path.Combine to resolve links that contain a relative path (e.g. /etc/localtime). + symlinkPath = Path.Combine(tzFilePath, symlinkPath); + + string timeZoneDirectory = GetTimeZoneDirectory(); + if (symlinkPath.StartsWith(timeZoneDirectory, StringComparison.Ordinal)) + { + id = symlinkPath.Substring(timeZoneDirectory.Length); + } + } + + return id; + } + + /// + /// Enumerate files + /// + private static IEnumerable EnumerateFilesRecursively(string path) + { + List toExplore = null; // List used as a stack + + string currentPath = path; + for(;;) + { + using (Microsoft.Win32.SafeHandles.SafeDirectoryHandle dirHandle = Interop.Sys.OpenDir(currentPath)) + { + if (dirHandle.IsInvalid) + { + throw Interop.GetExceptionForIoErrno(Interop.Sys.GetLastErrorInfo(), currentPath, isDirectory: true); + } + + // Read each entry from the enumerator + Interop.Sys.DirectoryEntry dirent; + while (Interop.Sys.ReadDir(dirHandle, out dirent) == 0) + { + if (dirent.InodeName == "." || dirent.InodeName == "..") + continue; + + string fullPath = Path.Combine(currentPath, dirent.InodeName); + + // Get from the dir entry whether the entry is a file or directory. + // We classify everything as a file unless we know it to be a directory. + bool isDir; + if (dirent.InodeType == Interop.Sys.NodeType.DT_DIR) + { + // We know it's a directory. + isDir = true; + } + else if (dirent.InodeType == Interop.Sys.NodeType.DT_LNK || dirent.InodeType == Interop.Sys.NodeType.DT_UNKNOWN) + { + // It's a symlink or unknown: stat to it to see if we can resolve it to a directory. + // If we can't (e.g. symlink to a file, broken symlink, etc.), we'll just treat it as a file. + + Interop.Sys.FileStatus fileinfo; + if (Interop.Sys.Stat(fullPath, out fileinfo) >= 0) + { + isDir = (fileinfo.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFDIR; + } + else + { + isDir = false; + } + } + else + { + // Otherwise, treat it as a file. This includes regular files, FIFOs, etc. + isDir = false; + } + + // Yield the result if the user has asked for it. In the case of directories, + // always explore it by pushing it onto the stack, regardless of whether + // we're returning directories. + if (isDir) + { + if (toExplore == null) + { + toExplore = new List(); + } + toExplore.Add(fullPath); + } + else + { + yield return fullPath; + } + } + } + + if (toExplore == null || toExplore.Count == 0) + break; + + currentPath = toExplore[toExplore.Count - 1]; + toExplore.RemoveAt(toExplore.Count - 1); + } + } + + /// + /// Find the time zone id by searching all the tzfiles for the one that matches rawData + /// and return its file name. + /// + private static string FindTimeZoneId(byte[] rawData) + { + // default to "Local" if we can't find the right tzfile + string id = LocalId; + string timeZoneDirectory = GetTimeZoneDirectory(); + string localtimeFilePath = Path.Combine(timeZoneDirectory, "localtime"); + string posixrulesFilePath = Path.Combine(timeZoneDirectory, "posixrules"); + byte[] buffer = new byte[rawData.Length]; + + try + { + foreach (string filePath in EnumerateFilesRecursively(timeZoneDirectory)) + { + // skip the localtime and posixrules file, since they won't give us the correct id + if (!string.Equals(filePath, localtimeFilePath, StringComparison.OrdinalIgnoreCase) + && !string.Equals(filePath, posixrulesFilePath, StringComparison.OrdinalIgnoreCase)) + { + if (CompareTimeZoneFile(filePath, buffer, rawData)) + { + // if all bytes are the same, this must be the right tz file + id = filePath; + + // strip off the root time zone directory + if (id.StartsWith(timeZoneDirectory, StringComparison.Ordinal)) + { + id = id.Substring(timeZoneDirectory.Length); + } + break; + } + } + } + } + catch (IOException) { } + catch (SecurityException) { } + catch (UnauthorizedAccessException) { } + + return id; + } + + private static bool CompareTimeZoneFile(string filePath, byte[] buffer, byte[] rawData) + { + try + { + // bufferSize == 1 used to avoid unnecessary buffer in FileStream + using (FileStream stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 1)) + { + if (stream.Length == rawData.Length) + { + int index = 0; + int count = rawData.Length; + + while (count > 0) + { + int n = stream.Read(buffer, index, count); + if (n == 0) + throw Error.GetEndOfFile(); + + int end = index + n; + for (; index < end; index++) + { + if (buffer[index] != rawData[index]) + { + return false; + } + } + + count -= n; + } + + return true; + } + } + } + catch (IOException) { } + catch (SecurityException) { } + catch (UnauthorizedAccessException) { } + + return false; + } + + /// + /// Helper function used by 'GetLocalTimeZone()' - this function wraps the call + /// for loading time zone data from computers without Registry support. + /// + /// The TryGetLocalTzFile() call returns a Byte[] containing the compiled tzfile. + /// + private static TimeZoneInfo GetLocalTimeZoneFromTzFile() + { + byte[] rawData; + string id; + if (TryGetLocalTzFile(out rawData, out id)) + { + TimeZoneInfo result = GetTimeZoneFromTzData(rawData, id); + if (result != null) + { + return result; + } + } + + // if we can't find a local time zone, return UTC + return Utc; + } + + private static TimeZoneInfo GetTimeZoneFromTzData(byte[] rawData, string id) + { + if (rawData != null) + { + try + { + return new TimeZoneInfo(rawData, id, dstDisabled: false); // create a TimeZoneInfo instance from the TZif data w/ DST support + } + catch (ArgumentException) { } + catch (InvalidTimeZoneException) { } + try + { + return new TimeZoneInfo(rawData, id, dstDisabled: true); // create a TimeZoneInfo instance from the TZif data w/o DST support + } + catch (ArgumentException) { } + catch (InvalidTimeZoneException) { } + } + + return null; + } + + private static string GetTimeZoneDirectory() + { + string tzDirectory = Environment.GetEnvironmentVariable(TimeZoneDirectoryEnvironmentVariable); + + if (tzDirectory == null) + { + tzDirectory = DefaultTimeZoneDirectory; + } + else if (!tzDirectory.EndsWith(Path.DirectorySeparatorChar)) + { + tzDirectory += Path.DirectorySeparatorChar; + } + + return tzDirectory; + } + + /// + /// Helper function for retrieving a TimeZoneInfo object by . + /// This function wraps the logic necessary to keep the private + /// SystemTimeZones cache in working order + /// + /// This function will either return a valid TimeZoneInfo instance or + /// it will throw 'InvalidTimeZoneException' / 'TimeZoneNotFoundException'. + /// + public static TimeZoneInfo FindSystemTimeZoneById(string id) + { + // Special case for Utc as it will not exist in the dictionary with the rest + // of the system time zones. There is no need to do this check for Local.Id + // since Local is a real time zone that exists in the dictionary cache + if (string.Equals(id, UtcId, StringComparison.OrdinalIgnoreCase)) + { + return Utc; + } + + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + else if (id.Length == 0 || id.Contains('\0')) + { + throw new TimeZoneNotFoundException(SR.Format(SR.TimeZoneNotFound_MissingData, id)); + } + + TimeZoneInfo value; + Exception e; + + TimeZoneInfoResult result; + + CachedData cachedData = s_cachedData; + + lock (cachedData) + { + result = TryGetTimeZone(id, false, out value, out e, cachedData, alwaysFallbackToLocalMachine: true); + } + + if (result == TimeZoneInfoResult.Success) + { + return value; + } + else if (result == TimeZoneInfoResult.InvalidTimeZoneException) + { + Debug.Assert(e is InvalidTimeZoneException, + "TryGetTimeZone must create an InvalidTimeZoneException when it returns TimeZoneInfoResult.InvalidTimeZoneException"); + throw e; + } + else if (result == TimeZoneInfoResult.SecurityException) + { + throw new SecurityException(SR.Format(SR.Security_CannotReadFileData, id), e); + } + else + { + throw new TimeZoneNotFoundException(SR.Format(SR.TimeZoneNotFound_MissingData, id), e); + } + } + + // DateTime.Now fast path that avoids allocating an historically accurate TimeZoneInfo.Local and just creates a 1-year (current year) accurate time zone + internal static TimeSpan GetDateTimeNowUtcOffsetFromUtc(DateTime time, out bool isAmbiguousLocalDst) + { + bool isDaylightSavings; + // Use the standard code path for Unix since there isn't a faster way of handling current-year-only time zones + return GetUtcOffsetFromUtc(time, Local, out isDaylightSavings, out isAmbiguousLocalDst); + } + + // TZFILE(5) BSD File Formats Manual TZFILE(5) + // + // NAME + // tzfile -- timezone information + // + // SYNOPSIS + // #include "/usr/src/lib/libc/stdtime/tzfile.h" + // + // DESCRIPTION + // The time zone information files used by tzset(3) begin with the magic + // characters ``TZif'' to identify them as time zone information files, fol- + // lowed by sixteen bytes reserved for future use, followed by four four- + // byte values written in a ``standard'' byte order (the high-order byte of + // the value is written first). These values are, in order: + // + // tzh_ttisgmtcnt The number of UTC/local indicators stored in the file. + // tzh_ttisstdcnt The number of standard/wall indicators stored in the + // file. + // tzh_leapcnt The number of leap seconds for which data is stored in + // the file. + // tzh_timecnt The number of ``transition times'' for which data is + // stored in the file. + // tzh_typecnt The number of ``local time types'' for which data is + // stored in the file (must not be zero). + // tzh_charcnt The number of characters of ``time zone abbreviation + // strings'' stored in the file. + // + // The above header is followed by tzh_timecnt four-byte values of type + // long, sorted in ascending order. These values are written in ``stan- + // dard'' byte order. Each is used as a transition time (as returned by + // time(3)) at which the rules for computing local time change. Next come + // tzh_timecnt one-byte values of type unsigned char; each one tells which + // of the different types of ``local time'' types described in the file is + // associated with the same-indexed transition time. These values serve as + // indices into an array of ttinfo structures that appears next in the file; + // these structures are defined as follows: + // + // struct ttinfo { + // long tt_gmtoff; + // int tt_isdst; + // unsigned int tt_abbrind; + // }; + // + // Each structure is written as a four-byte value for tt_gmtoff of type + // long, in a standard byte order, followed by a one-byte value for tt_isdst + // and a one-byte value for tt_abbrind. In each structure, tt_gmtoff gives + // the number of seconds to be added to UTC, tt_isdst tells whether tm_isdst + // should be set by localtime(3) and tt_abbrind serves as an index into the + // array of time zone abbreviation characters that follow the ttinfo struc- + // ture(s) in the file. + // + // Then there are tzh_leapcnt pairs of four-byte values, written in standard + // byte order; the first value of each pair gives the time (as returned by + // time(3)) at which a leap second occurs; the second gives the total number + // of leap seconds to be applied after the given time. The pairs of values + // are sorted in ascending order by time.b + // + // Then there are tzh_ttisstdcnt standard/wall indicators, each stored as a + // one-byte value; they tell whether the transition times associated with + // local time types were specified as standard time or wall clock time, and + // are used when a time zone file is used in handling POSIX-style time zone + // environment variables. + // + // Finally there are tzh_ttisgmtcnt UTC/local indicators, each stored as a + // one-byte value; they tell whether the transition times associated with + // local time types were specified as UTC or local time, and are used when a + // time zone file is used in handling POSIX-style time zone environment + // variables. + // + // localtime uses the first standard-time ttinfo structure in the file (or + // simply the first ttinfo structure in the absence of a standard-time + // structure) if either tzh_timecnt is zero or the time argument is less + // than the first transition time recorded in the file. + // + // SEE ALSO + // ctime(3), time2posix(3), zic(8) + // + // BSD September 13, 1994 BSD + // + // + // + // TIME(3) BSD Library Functions Manual TIME(3) + // + // NAME + // time -- get time of day + // + // LIBRARY + // Standard C Library (libc, -lc) + // + // SYNOPSIS + // #include + // + // time_t + // time(time_t *tloc); + // + // DESCRIPTION + // The time() function returns the value of time in seconds since 0 hours, 0 + // minutes, 0 seconds, January 1, 1970, Coordinated Universal Time, without + // including leap seconds. If an error occurs, time() returns the value + // (time_t)-1. + // + // The return value is also stored in *tloc, provided that tloc is non-null. + // + // ERRORS + // The time() function may fail for any of the reasons described in + // gettimeofday(2). + // + // SEE ALSO + // gettimeofday(2), ctime(3) + // + // STANDARDS + // The time function conforms to IEEE Std 1003.1-2001 (``POSIX.1''). + // + // BUGS + // Neither ISO/IEC 9899:1999 (``ISO C99'') nor IEEE Std 1003.1-2001 + // (``POSIX.1'') requires time() to set errno on failure; thus, it is impos- + // sible for an application to distinguish the valid time value -1 (repre- + // senting the last UTC second of 1969) from the error return value. + // + // Systems conforming to earlier versions of the C and POSIX standards + // (including older versions of FreeBSD) did not set *tloc in the error + // case. + // + // HISTORY + // A time() function appeared in Version 6 AT&T UNIX. + // + // BSD July 18, 2003 BSD + // + // + private static void TZif_GenerateAdjustmentRules(out AdjustmentRule[] rules, TimeSpan baseUtcOffset, DateTime[] dts, byte[] typeOfLocalTime, + TZifType[] transitionType, bool[] StandardTime, bool[] GmtTime, string futureTransitionsPosixFormat) + { + rules = null; + + if (dts.Length > 0) + { + int index = 0; + List rulesList = new List(); + + while (index <= dts.Length) + { + TZif_GenerateAdjustmentRule(ref index, baseUtcOffset, rulesList, dts, typeOfLocalTime, transitionType, StandardTime, GmtTime, futureTransitionsPosixFormat); + } + + rules = rulesList.ToArray(); + if (rules != null && rules.Length == 0) + { + rules = null; + } + } + } + + private static void TZif_GenerateAdjustmentRule(ref int index, TimeSpan timeZoneBaseUtcOffset, List rulesList, DateTime[] dts, + byte[] typeOfLocalTime, TZifType[] transitionTypes, bool[] StandardTime, bool[] GmtTime, string futureTransitionsPosixFormat) + { + // To generate AdjustmentRules, use the following approach: + // The first AdjustmentRule will go from DateTime.MinValue to the first transition time greater than DateTime.MinValue. + // Each middle AdjustmentRule wil go from dts[index-1] to dts[index]. + // The last AdjustmentRule will go from dts[dts.Length-1] to Datetime.MaxValue. + + // 0. Skip any DateTime.MinValue transition times. In newer versions of the tzfile, there + // is a "big bang" transition time, which is before the year 0001. Since any times before year 0001 + // cannot be represented by DateTime, there is no reason to make AdjustmentRules for these unrepresentable time periods. + // 1. If there are no DateTime.MinValue times, the first AdjustmentRule goes from DateTime.MinValue + // to the first transition and uses the first standard transitionType (or the first transitionType if none of them are standard) + // 2. Create an AdjustmentRule for each transition, i.e. from dts[index - 1] to dts[index]. + // This rule uses the transitionType[index - 1] and the whole AdjustmentRule only describes a single offset - either + // all daylight savings, or all stanard time. + // 3. After all the transitions are filled out, the last AdjustmentRule is created from either: + // a. a POSIX-style timezone description ("futureTransitionsPosixFormat"), if there is one or + // b. continue the last transition offset until DateTime.Max + + while (index < dts.Length && dts[index] == DateTime.MinValue) + { + index++; + } + + if (index == 0) + { + TZifType transitionType = TZif_GetEarlyDateTransitionType(transitionTypes); + DateTime endTransitionDate = dts[index]; + + TimeSpan transitionOffset = TZif_CalculateTransitionOffsetFromBase(transitionType.UtcOffset, timeZoneBaseUtcOffset); + TimeSpan daylightDelta = transitionType.IsDst ? transitionOffset : TimeSpan.Zero; + TimeSpan baseUtcDelta = transitionType.IsDst ? TimeSpan.Zero : transitionOffset; + + AdjustmentRule r = AdjustmentRule.CreateAdjustmentRule( + DateTime.MinValue, + endTransitionDate.AddTicks(-1), + daylightDelta, + default(TransitionTime), + default(TransitionTime), + baseUtcDelta, + noDaylightTransitions: true); + rulesList.Add(r); + } + else if (index < dts.Length) + { + DateTime startTransitionDate = dts[index - 1]; + TZifType startTransitionType = transitionTypes[typeOfLocalTime[index - 1]]; + + DateTime endTransitionDate = dts[index]; + + TimeSpan transitionOffset = TZif_CalculateTransitionOffsetFromBase(startTransitionType.UtcOffset, timeZoneBaseUtcOffset); + TimeSpan daylightDelta = startTransitionType.IsDst ? transitionOffset : TimeSpan.Zero; + TimeSpan baseUtcDelta = startTransitionType.IsDst ? TimeSpan.Zero : transitionOffset; + + TransitionTime dstStart; + if (startTransitionType.IsDst) + { + // the TransitionTime fields are not used when AdjustmentRule.NoDaylightTransitions == true. + // However, there are some cases in the past where DST = true, and the daylight savings offset + // now equals what the current BaseUtcOffset is. In that case, the AdjustmentRule.DaylightOffset + // is going to be TimeSpan.Zero. But we still need to return 'true' from AdjustmentRule.HasDaylightSaving. + // To ensure we always return true from HasDaylightSaving, make a "special" dstStart that will make the logic + // in HasDaylightSaving return true. + dstStart = TransitionTime.CreateFixedDateRule(DateTime.MinValue.AddMilliseconds(2), 1, 1); + } + else + { + dstStart = default(TransitionTime); + } + + AdjustmentRule r = AdjustmentRule.CreateAdjustmentRule( + startTransitionDate, + endTransitionDate.AddTicks(-1), + daylightDelta, + dstStart, + default(TransitionTime), + baseUtcDelta, + noDaylightTransitions: true); + rulesList.Add(r); + } + else + { + // create the AdjustmentRule that will be used for all DateTimes after the last transition + + // NOTE: index == dts.Length + DateTime startTransitionDate = dts[index - 1]; + + if (!string.IsNullOrEmpty(futureTransitionsPosixFormat)) + { + AdjustmentRule r = TZif_CreateAdjustmentRuleForPosixFormat(futureTransitionsPosixFormat, startTransitionDate, timeZoneBaseUtcOffset); + if (r != null) + { + rulesList.Add(r); + } + } + else + { + // just use the last transition as the rule which will be used until the end of time + + TZifType transitionType = transitionTypes[typeOfLocalTime[index - 1]]; + TimeSpan transitionOffset = TZif_CalculateTransitionOffsetFromBase(transitionType.UtcOffset, timeZoneBaseUtcOffset); + TimeSpan daylightDelta = transitionType.IsDst ? transitionOffset : TimeSpan.Zero; + TimeSpan baseUtcDelta = transitionType.IsDst ? TimeSpan.Zero : transitionOffset; + + AdjustmentRule r = AdjustmentRule.CreateAdjustmentRule( + startTransitionDate, + DateTime.MaxValue, + daylightDelta, + default(TransitionTime), + default(TransitionTime), + baseUtcDelta, + noDaylightTransitions: true); + rulesList.Add(r); + } + } + + index++; + } + + private static TimeSpan TZif_CalculateTransitionOffsetFromBase(TimeSpan transitionOffset, TimeSpan timeZoneBaseUtcOffset) + { + TimeSpan result = transitionOffset - timeZoneBaseUtcOffset; + + // TZif supports seconds-level granularity with offsets but TimeZoneInfo only supports minutes since it aligns + // with DateTimeOffset, SQL Server, and the W3C XML Specification + if (result.Ticks % TimeSpan.TicksPerMinute != 0) + { + result = new TimeSpan(result.Hours, result.Minutes, 0); + } + + return result; + } + + /// + /// Gets the first standard-time transition type, or simply the first transition type + /// if there are no standard transition types. + /// > + /// + /// from 'man tzfile': + /// localtime(3) uses the first standard-time ttinfo structure in the file + /// (or simply the first ttinfo structure in the absence of a standard-time + /// structure) if either tzh_timecnt is zero or the time argument is less + /// than the first transition time recorded in the file. + /// + private static TZifType TZif_GetEarlyDateTransitionType(TZifType[] transitionTypes) + { + foreach (TZifType transitionType in transitionTypes) + { + if (!transitionType.IsDst) + { + return transitionType; + } + } + + if (transitionTypes.Length > 0) + { + return transitionTypes[0]; + } + + throw new InvalidTimeZoneException(SR.InvalidTimeZone_NoTTInfoStructures); + } + + /// + /// Creates an AdjustmentRule given the POSIX TZ environment variable string. + /// + /// + /// See http://man7.org/linux/man-pages/man3/tzset.3.html for the format and semantics of this POSX string. + /// + private static AdjustmentRule TZif_CreateAdjustmentRuleForPosixFormat(string posixFormat, DateTime startTransitionDate, TimeSpan timeZoneBaseUtcOffset) + { + string standardName; + string standardOffset; + string daylightSavingsName; + string daylightSavingsOffset; + string start; + string startTime; + string end; + string endTime; + + if (TZif_ParsePosixFormat(posixFormat, out standardName, out standardOffset, out daylightSavingsName, + out daylightSavingsOffset, out start, out startTime, out end, out endTime)) + { + // a valid posixFormat has at least standardName and standardOffset + + TimeSpan? parsedBaseOffset = TZif_ParseOffsetString(standardOffset); + if (parsedBaseOffset.HasValue) + { + TimeSpan baseOffset = parsedBaseOffset.Value.Negate(); // offsets are backwards in POSIX notation + baseOffset = TZif_CalculateTransitionOffsetFromBase(baseOffset, timeZoneBaseUtcOffset); + + // having a daylightSavingsName means there is a DST rule + if (!string.IsNullOrEmpty(daylightSavingsName)) + { + TimeSpan? parsedDaylightSavings = TZif_ParseOffsetString(daylightSavingsOffset); + TimeSpan daylightSavingsTimeSpan; + if (!parsedDaylightSavings.HasValue) + { + // default DST to 1 hour if it isn't specified + daylightSavingsTimeSpan = new TimeSpan(1, 0, 0); + } + else + { + daylightSavingsTimeSpan = parsedDaylightSavings.Value.Negate(); // offsets are backwards in POSIX notation + daylightSavingsTimeSpan = TZif_CalculateTransitionOffsetFromBase(daylightSavingsTimeSpan, timeZoneBaseUtcOffset); + daylightSavingsTimeSpan = TZif_CalculateTransitionOffsetFromBase(daylightSavingsTimeSpan, baseOffset); + } + + TransitionTime dstStart = TZif_CreateTransitionTimeFromPosixRule(start, startTime); + TransitionTime dstEnd = TZif_CreateTransitionTimeFromPosixRule(end, endTime); + + return AdjustmentRule.CreateAdjustmentRule( + startTransitionDate, + DateTime.MaxValue, + daylightSavingsTimeSpan, + dstStart, + dstEnd, + baseOffset, + noDaylightTransitions: false); + } + else + { + // if there is no daylightSavingsName, the whole AdjustmentRule should be with no transitions - just the baseOffset + return AdjustmentRule.CreateAdjustmentRule( + startTransitionDate, + DateTime.MaxValue, + TimeSpan.Zero, + default(TransitionTime), + default(TransitionTime), + baseOffset, + noDaylightTransitions: true); + } + } + } + + return null; + } + + private static TimeSpan? TZif_ParseOffsetString(string offset) + { + TimeSpan? result = null; + + if (!string.IsNullOrEmpty(offset)) + { + bool negative = offset[0] == '-'; + if (negative || offset[0] == '+') + { + offset = offset.Substring(1); + } + + // Try parsing just hours first. + // Note, TimeSpan.TryParseExact "%h" can't be used here because some time zones using values + // like "26" or "144" and TimeSpan parsing would turn that into 26 or 144 *days* instead of hours. + int hours; + if (int.TryParse(offset, out hours)) + { + result = new TimeSpan(hours, 0, 0); + } + else + { + TimeSpan parsedTimeSpan; + if (TimeSpan.TryParseExact(offset, "g", CultureInfo.InvariantCulture, out parsedTimeSpan)) + { + result = parsedTimeSpan; + } + } + + if (result.HasValue && negative) + { + result = result.Value.Negate(); + } + } + + return result; + } + + private static TransitionTime TZif_CreateTransitionTimeFromPosixRule(string date, string time) + { + if (string.IsNullOrEmpty(date)) + { + return default(TransitionTime); + } + + if (date[0] == 'M') + { + // Mm.w.d + // This specifies day d of week w of month m. The day d must be between 0(Sunday) and 6.The week w must be between 1 and 5; + // week 1 is the first week in which day d occurs, and week 5 specifies the last d day in the month. The month m should be between 1 and 12. + + int month; + int week; + DayOfWeek day; + if (!TZif_ParseMDateRule(date, out month, out week, out day)) + { + throw new InvalidTimeZoneException(SR.Format(SR.InvalidTimeZone_UnparseablePosixMDateString, date)); + } + + DateTime timeOfDay; + TimeSpan? timeOffset = TZif_ParseOffsetString(time); + if (timeOffset.HasValue) + { + // This logic isn't correct and can't be corrected until https://github.com/dotnet/corefx/issues/2618 is fixed. + // Some time zones use time values like, "26", "144", or "-2". + // This allows the week to sometimes be week 4 and sometimes week 5 in the month. + // For now, strip off any 'days' in the offset, and just get the time of day correct + timeOffset = new TimeSpan(timeOffset.Value.Hours, timeOffset.Value.Minutes, timeOffset.Value.Seconds); + if (timeOffset.Value < TimeSpan.Zero) + { + timeOfDay = new DateTime(1, 1, 2, 0, 0, 0); + } + else + { + timeOfDay = new DateTime(1, 1, 1, 0, 0, 0); + } + + timeOfDay += timeOffset.Value; + } + else + { + // default to 2AM. + timeOfDay = new DateTime(1, 1, 1, 2, 0, 0); + } + + return TransitionTime.CreateFloatingDateRule(timeOfDay, month, week, day); + } + else + { + // Jn + // This specifies the Julian day, with n between 1 and 365.February 29 is never counted, even in leap years. + + // n + // This specifies the Julian day, with n between 0 and 365.February 29 is counted in leap years. + + // These two rules cannot be expressed with the current AdjustmentRules + // One of them *could* be supported if we relaxed the TransitionTime validation rules, and allowed + // "IsFixedDateRule = true, Month = 0, Day = n" to mean the nth day of the year, picking one of the rules above + + throw new InvalidTimeZoneException(SR.InvalidTimeZone_JulianDayNotSupported); + } + } + + /// + /// Parses a string like Mm.w.d into month, week and DayOfWeek values. + /// + /// + /// true if the parsing succeeded; otherwise, false. + /// + private static bool TZif_ParseMDateRule(string dateRule, out int month, out int week, out DayOfWeek dayOfWeek) + { + if (dateRule[0] == 'M') + { + int firstDotIndex = dateRule.IndexOf('.'); + if (firstDotIndex > 0) + { + int secondDotIndex = dateRule.IndexOf('.', firstDotIndex + 1); + if (secondDotIndex > 0) + { + if (int.TryParse(dateRule.AsSpan().Slice(1, firstDotIndex - 1), out month) && + int.TryParse(dateRule.AsSpan().Slice(firstDotIndex + 1, secondDotIndex - firstDotIndex - 1), out week) && + int.TryParse(dateRule.AsSpan().Slice(secondDotIndex + 1), out int day)) + { + dayOfWeek = (DayOfWeek)day; + return true; + } + } + } + } + + month = 0; + week = 0; + dayOfWeek = default(DayOfWeek); + return false; + } + + private static bool TZif_ParsePosixFormat( + string posixFormat, + out string standardName, + out string standardOffset, + out string daylightSavingsName, + out string daylightSavingsOffset, + out string start, + out string startTime, + out string end, + out string endTime) + { + standardName = null; + standardOffset = null; + daylightSavingsName = null; + daylightSavingsOffset = null; + start = null; + startTime = null; + end = null; + endTime = null; + + int index = 0; + standardName = TZif_ParsePosixName(posixFormat, ref index); + standardOffset = TZif_ParsePosixOffset(posixFormat, ref index); + + daylightSavingsName = TZif_ParsePosixName(posixFormat, ref index); + if (!string.IsNullOrEmpty(daylightSavingsName)) + { + daylightSavingsOffset = TZif_ParsePosixOffset(posixFormat, ref index); + + if (index < posixFormat.Length && posixFormat[index] == ',') + { + index++; + TZif_ParsePosixDateTime(posixFormat, ref index, out start, out startTime); + + if (index < posixFormat.Length && posixFormat[index] == ',') + { + index++; + TZif_ParsePosixDateTime(posixFormat, ref index, out end, out endTime); + } + } + } + + return !string.IsNullOrEmpty(standardName) && !string.IsNullOrEmpty(standardOffset); + } + + private static string TZif_ParsePosixName(string posixFormat, ref int index) + { + bool isBracketEnclosed = index < posixFormat.Length && posixFormat[index] == '<'; + if (isBracketEnclosed) + { + // move past the opening bracket + index++; + + string result = TZif_ParsePosixString(posixFormat, ref index, c => c == '>'); + + // move past the closing bracket + if (index < posixFormat.Length && posixFormat[index] == '>') + { + index++; + } + + return result; + } + else + { + return TZif_ParsePosixString( + posixFormat, + ref index, + c => char.IsDigit(c) || c == '+' || c == '-' || c == ','); + } + } + + private static string TZif_ParsePosixOffset(string posixFormat, ref int index) => + TZif_ParsePosixString(posixFormat, ref index, c => !char.IsDigit(c) && c != '+' && c != '-' && c != ':'); + + private static void TZif_ParsePosixDateTime(string posixFormat, ref int index, out string date, out string time) + { + time = null; + + date = TZif_ParsePosixDate(posixFormat, ref index); + if (index < posixFormat.Length && posixFormat[index] == '/') + { + index++; + time = TZif_ParsePosixTime(posixFormat, ref index); + } + } + + private static string TZif_ParsePosixDate(string posixFormat, ref int index) => + TZif_ParsePosixString(posixFormat, ref index, c => c == '/' || c == ','); + + private static string TZif_ParsePosixTime(string posixFormat, ref int index) => + TZif_ParsePosixString(posixFormat, ref index, c => c == ','); + + private static string TZif_ParsePosixString(string posixFormat, ref int index, Func breakCondition) + { + int startIndex = index; + for (; index < posixFormat.Length; index++) + { + char current = posixFormat[index]; + if (breakCondition(current)) + { + break; + } + } + + return posixFormat.Substring(startIndex, index - startIndex); + } + + // Returns the Substring from zoneAbbreviations starting at index and ending at '\0' + // zoneAbbreviations is expected to be in the form: "PST\0PDT\0PWT\0\PPT" + private static string TZif_GetZoneAbbreviation(string zoneAbbreviations, int index) + { + int lastIndex = zoneAbbreviations.IndexOf('\0', index); + return lastIndex > 0 ? + zoneAbbreviations.Substring(index, lastIndex - index) : + zoneAbbreviations.Substring(index); + } + + // Converts an array of bytes into an int - always using standard byte order (Big Endian) + // per TZif file standard + private static unsafe int TZif_ToInt32(byte[] value, int startIndex) + { + fixed (byte* pbyte = &value[startIndex]) + { + return (*pbyte << 24) | (*(pbyte + 1) << 16) | (*(pbyte + 2) << 8) | (*(pbyte + 3)); + } + } + + // Converts an array of bytes into a long - always using standard byte order (Big Endian) + // per TZif file standard + private static unsafe long TZif_ToInt64(byte[] value, int startIndex) + { + fixed (byte* pbyte = &value[startIndex]) + { + int i1 = (*pbyte << 24) | (*(pbyte + 1) << 16) | (*(pbyte + 2) << 8) | (*(pbyte + 3)); + int i2 = (*(pbyte + 4) << 24) | (*(pbyte + 5) << 16) | (*(pbyte + 6) << 8) | (*(pbyte + 7)); + return (uint)i2 | ((long)i1 << 32); + } + } + + private static long TZif_ToUnixTime(byte[] value, int startIndex, TZVersion version) => + version != TZVersion.V1 ? + TZif_ToInt64(value, startIndex) : + TZif_ToInt32(value, startIndex); + + private static DateTime TZif_UnixTimeToDateTime(long unixTime) => + unixTime < DateTimeOffset.UnixMinSeconds ? DateTime.MinValue : + unixTime > DateTimeOffset.UnixMaxSeconds ? DateTime.MaxValue : + DateTimeOffset.FromUnixTimeSeconds(unixTime).UtcDateTime; + + private static void TZif_ParseRaw(byte[] data, out TZifHead t, out DateTime[] dts, out byte[] typeOfLocalTime, out TZifType[] transitionType, + out string zoneAbbreviations, out bool[] StandardTime, out bool[] GmtTime, out string futureTransitionsPosixFormat) + { + // initialize the out parameters in case the TZifHead ctor throws + dts = null; + typeOfLocalTime = null; + transitionType = null; + zoneAbbreviations = string.Empty; + StandardTime = null; + GmtTime = null; + futureTransitionsPosixFormat = null; + + // read in the 44-byte TZ header containing the count/length fields + // + int index = 0; + t = new TZifHead(data, index); + index += TZifHead.Length; + + int timeValuesLength = 4; // the first version uses 4-bytes to specify times + if (t.Version != TZVersion.V1) + { + // move index past the V1 information to read the V2 information + index += (int)((timeValuesLength * t.TimeCount) + t.TimeCount + (6 * t.TypeCount) + ((timeValuesLength + 4) * t.LeapCount) + t.IsStdCount + t.IsGmtCount + t.CharCount); + + // read the V2 header + t = new TZifHead(data, index); + index += TZifHead.Length; + timeValuesLength = 8; // the second version uses 8-bytes + } + + // initialize the containers for the rest of the TZ data + dts = new DateTime[t.TimeCount]; + typeOfLocalTime = new byte[t.TimeCount]; + transitionType = new TZifType[t.TypeCount]; + zoneAbbreviations = string.Empty; + StandardTime = new bool[t.TypeCount]; + GmtTime = new bool[t.TypeCount]; + + // read in the UTC transition points and convert them to Windows + // + for (int i = 0; i < t.TimeCount; i++) + { + long unixTime = TZif_ToUnixTime(data, index, t.Version); + dts[i] = TZif_UnixTimeToDateTime(unixTime); + index += timeValuesLength; + } + + // read in the Type Indices; there is a 1:1 mapping of UTC transition points to Type Indices + // these indices directly map to the array index in the transitionType array below + // + for (int i = 0; i < t.TimeCount; i++) + { + typeOfLocalTime[i] = data[index]; + index += 1; + } + + // read in the Type table. Each 6-byte entry represents + // {UtcOffset, IsDst, AbbreviationIndex} + // + // each AbbreviationIndex is a character index into the zoneAbbreviations string below + // + for (int i = 0; i < t.TypeCount; i++) + { + transitionType[i] = new TZifType(data, index); + index += 6; + } + + // read in the Abbreviation ASCII string. This string will be in the form: + // "PST\0PDT\0PWT\0\PPT" + // + Encoding enc = Encoding.UTF8; + zoneAbbreviations = enc.GetString(data, index, (int)t.CharCount); + index += (int)t.CharCount; + + // skip ahead of the Leap-Seconds Adjustment data. In a future release, consider adding + // support for Leap-Seconds + // + index += (int)(t.LeapCount * (timeValuesLength + 4)); // skip the leap second transition times + + // read in the Standard Time table. There should be a 1:1 mapping between Type-Index and Standard + // Time table entries. + // + // TRUE = transition time is standard time + // FALSE = transition time is wall clock time + // ABSENT = transition time is wall clock time + // + for (int i = 0; i < t.IsStdCount && i < t.TypeCount && index < data.Length; i++) + { + StandardTime[i] = (data[index++] != 0); + } + + // read in the GMT Time table. There should be a 1:1 mapping between Type-Index and GMT Time table + // entries. + // + // TRUE = transition time is UTC + // FALSE = transition time is local time + // ABSENT = transition time is local time + // + for (int i = 0; i < t.IsGmtCount && i < t.TypeCount && index < data.Length; i++) + { + GmtTime[i] = (data[index++] != 0); + } + + if (t.Version != TZVersion.V1) + { + // read the POSIX-style format, which should be wrapped in newlines with the last newline at the end of the file + if (data[index++] == '\n' && data[data.Length - 1] == '\n') + { + futureTransitionsPosixFormat = enc.GetString(data, index, data.Length - index - 1); + } + } + } + + private struct TZifType + { + public const int Length = 6; + + public readonly TimeSpan UtcOffset; + public readonly bool IsDst; + public readonly byte AbbreviationIndex; + + public TZifType(byte[] data, int index) + { + if (data == null || data.Length < index + Length) + { + throw new ArgumentException(SR.Argument_TimeZoneInfoInvalidTZif, nameof(data)); + } + UtcOffset = new TimeSpan(0, 0, TZif_ToInt32(data, index + 00)); + IsDst = (data[index + 4] != 0); + AbbreviationIndex = data[index + 5]; + } + } + + private struct TZifHead + { + public const int Length = 44; + + public readonly uint Magic; // TZ_MAGIC "TZif" + public readonly TZVersion Version; // 1 byte for a \0 or 2 or 3 + // public byte[15] Reserved; // reserved for future use + public readonly uint IsGmtCount; // number of transition time flags + public readonly uint IsStdCount; // number of transition time flags + public readonly uint LeapCount; // number of leap seconds + public readonly uint TimeCount; // number of transition times + public readonly uint TypeCount; // number of local time types + public readonly uint CharCount; // number of abbreviated characters + + public TZifHead(byte[] data, int index) + { + if (data == null || data.Length < Length) + { + throw new ArgumentException("bad data", nameof(data)); + } + + Magic = (uint)TZif_ToInt32(data, index + 00); + + if (Magic != 0x545A6966) + { + // 0x545A6966 = {0x54, 0x5A, 0x69, 0x66} = "TZif" + throw new ArgumentException(SR.Argument_TimeZoneInfoBadTZif, nameof(data)); + } + + byte version = data[index + 04]; + Version = + version == '2' ? TZVersion.V2 : + version == '3' ? TZVersion.V3 : + TZVersion.V1; // default/fallback to V1 to guard against future, unsupported version numbers + + // skip the 15 byte reserved field + + // don't use the BitConverter class which parses data + // based on the Endianess of the machine architecture. + // this data is expected to always be in "standard byte order", + // regardless of the machine it is being processed on. + + IsGmtCount = (uint)TZif_ToInt32(data, index + 20); + IsStdCount = (uint)TZif_ToInt32(data, index + 24); + LeapCount = (uint)TZif_ToInt32(data, index + 28); + TimeCount = (uint)TZif_ToInt32(data, index + 32); + TypeCount = (uint)TZif_ToInt32(data, index + 36); + CharCount = (uint)TZif_ToInt32(data, index + 40); + } + } + + private enum TZVersion : byte + { + V1 = 0, + V2, + V3, + // when adding more versions, ensure all the logic using TZVersion is still correct + } + } +} diff --git a/external/corert/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Win32.cs b/external/corert/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Win32.cs new file mode 100644 index 0000000000..5950c9565a --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Win32.cs @@ -0,0 +1,999 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Security; +using System.Text; +using System.Threading; + +using Microsoft.Win32; +using Microsoft.Win32.SafeHandles; + +using Internal.Runtime.CompilerServices; + +using REG_TZI_FORMAT = Interop.Kernel32.REG_TZI_FORMAT; +using TIME_ZONE_INFORMATION = Interop.Kernel32.TIME_ZONE_INFORMATION; +using TIME_DYNAMIC_ZONE_INFORMATION = Interop.Kernel32.TIME_DYNAMIC_ZONE_INFORMATION; + +namespace System +{ + public sealed partial class TimeZoneInfo + { + // registry constants for the 'Time Zones' hive + // + private const string TimeZonesRegistryHive = @"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones"; + private const string DisplayValue = "Display"; + private const string DaylightValue = "Dlt"; + private const string StandardValue = "Std"; + private const string MuiDisplayValue = "MUI_Display"; + private const string MuiDaylightValue = "MUI_Dlt"; + private const string MuiStandardValue = "MUI_Std"; + private const string TimeZoneInfoValue = "TZI"; + private const string FirstEntryValue = "FirstEntry"; + private const string LastEntryValue = "LastEntry"; + + private const int MaxKeyLength = 255; + +#pragma warning disable 0420 + private sealed partial class CachedData + { + private static TimeZoneInfo GetCurrentOneYearLocal() + { + // load the data from the OS + TIME_ZONE_INFORMATION timeZoneInformation; + uint result = Interop.Kernel32.GetTimeZoneInformation(out timeZoneInformation); + return result == Interop.Kernel32.TIME_ZONE_ID_INVALID ? + CreateCustomTimeZone(LocalId, TimeSpan.Zero, LocalId, LocalId) : + GetLocalTimeZoneFromWin32Data(timeZoneInformation, dstDisabled: false); + } + + private volatile OffsetAndRule _oneYearLocalFromUtc; + + public OffsetAndRule GetOneYearLocalFromUtc(int year) + { + OffsetAndRule oneYearLocFromUtc = _oneYearLocalFromUtc; + if (oneYearLocFromUtc == null || oneYearLocFromUtc.Year != year) + { + TimeZoneInfo currentYear = GetCurrentOneYearLocal(); + AdjustmentRule rule = currentYear._adjustmentRules == null ? null : currentYear._adjustmentRules[0]; + oneYearLocFromUtc = new OffsetAndRule(year, currentYear.BaseUtcOffset, rule); + _oneYearLocalFromUtc = oneYearLocFromUtc; + } + return oneYearLocFromUtc; + } + } +#pragma warning restore 0420 + + private sealed class OffsetAndRule + { + public readonly int Year; + public readonly TimeSpan Offset; + public readonly AdjustmentRule Rule; + + public OffsetAndRule(int year, TimeSpan offset, AdjustmentRule rule) + { + Year = year; + Offset = offset; + Rule = rule; + } + } + + /// + /// Returns a cloned array of AdjustmentRule objects + /// + public AdjustmentRule[] GetAdjustmentRules() + { + if (_adjustmentRules == null) + { + return Array.Empty(); + } + + return (AdjustmentRule[])_adjustmentRules.Clone(); + } + + private static void PopulateAllSystemTimeZones(CachedData cachedData) + { + Debug.Assert(Monitor.IsEntered(cachedData)); + + using (RegistryKey reg = Registry.LocalMachine.OpenSubKey(TimeZonesRegistryHive, writable: false)) + { + if (reg != null) + { + foreach (string keyName in reg.GetSubKeyNames()) + { + TimeZoneInfo value; + Exception ex; + TryGetTimeZone(keyName, false, out value, out ex, cachedData); // populate the cache + } + } + } + } + + private TimeZoneInfo(in TIME_ZONE_INFORMATION zone, bool dstDisabled) + { + string standardName = zone.GetStandardName(); + if (standardName.Length == 0) + { + _id = LocalId; // the ID must contain at least 1 character - initialize _id to "Local" + } + else + { + _id = standardName; + } + _baseUtcOffset = new TimeSpan(0, -(zone.Bias), 0); + + if (!dstDisabled) + { + // only create the adjustment rule if DST is enabled + REG_TZI_FORMAT regZone = new REG_TZI_FORMAT(zone); + AdjustmentRule rule = CreateAdjustmentRuleFromTimeZoneInformation(regZone, DateTime.MinValue.Date, DateTime.MaxValue.Date, zone.Bias); + if (rule != null) + { + _adjustmentRules = new[] { rule }; + } + } + + ValidateTimeZoneInfo(_id, _baseUtcOffset, _adjustmentRules, out _supportsDaylightSavingTime); + _displayName = standardName; + _standardDisplayName = standardName; + _daylightDisplayName = zone.GetDaylightName(); + } + + /// + /// Helper function to check if the current TimeZoneInformation struct does not support DST. + /// This check returns true when the DaylightDate == StandardDate. + /// This check is only meant to be used for "Local". + /// + private static bool CheckDaylightSavingTimeNotSupported(in TIME_ZONE_INFORMATION timeZone) => + timeZone.DaylightDate.Equals(timeZone.StandardDate); + + /// + /// Converts a REG_TZI_FORMAT struct to an AdjustmentRule. + /// + private static AdjustmentRule CreateAdjustmentRuleFromTimeZoneInformation(in REG_TZI_FORMAT timeZoneInformation, DateTime startDate, DateTime endDate, int defaultBaseUtcOffset) + { + bool supportsDst = timeZoneInformation.StandardDate.Month != 0; + + if (!supportsDst) + { + if (timeZoneInformation.Bias == defaultBaseUtcOffset) + { + // this rule will not contain any information to be used to adjust dates. just ignore it + return null; + } + + return AdjustmentRule.CreateAdjustmentRule( + startDate, + endDate, + TimeSpan.Zero, // no daylight saving transition + TransitionTime.CreateFixedDateRule(DateTime.MinValue, 1, 1), + TransitionTime.CreateFixedDateRule(DateTime.MinValue.AddMilliseconds(1), 1, 1), + new TimeSpan(0, defaultBaseUtcOffset - timeZoneInformation.Bias, 0), // Bias delta is all what we need from this rule + noDaylightTransitions: false); + } + + // + // Create an AdjustmentRule with TransitionTime objects + // + TransitionTime daylightTransitionStart; + if (!TransitionTimeFromTimeZoneInformation(timeZoneInformation, out daylightTransitionStart, readStartDate: true)) + { + return null; + } + + TransitionTime daylightTransitionEnd; + if (!TransitionTimeFromTimeZoneInformation(timeZoneInformation, out daylightTransitionEnd, readStartDate: false)) + { + return null; + } + + if (daylightTransitionStart.Equals(daylightTransitionEnd)) + { + // this happens when the time zone does support DST but the OS has DST disabled + return null; + } + + return AdjustmentRule.CreateAdjustmentRule( + startDate, + endDate, + new TimeSpan(0, -timeZoneInformation.DaylightBias, 0), + daylightTransitionStart, + daylightTransitionEnd, + new TimeSpan(0, defaultBaseUtcOffset - timeZoneInformation.Bias, 0), + noDaylightTransitions: false); + } + + /// + /// Helper function that searches the registry for a time zone entry + /// that matches the TimeZoneInformation struct. + /// + private static string FindIdFromTimeZoneInformation(in TIME_ZONE_INFORMATION timeZone, out bool dstDisabled) + { + dstDisabled = false; + + using (RegistryKey key = Registry.LocalMachine.OpenSubKey(TimeZonesRegistryHive, writable: false)) + { + if (key == null) + { + return null; + } + + foreach (string keyName in key.GetSubKeyNames()) + { + if (TryCompareTimeZoneInformationToRegistry(timeZone, keyName, out dstDisabled)) + { + return keyName; + } + } + } + + return null; + } + + /// + /// Helper function for retrieving the local system time zone. + /// May throw COMException, TimeZoneNotFoundException, InvalidTimeZoneException. + /// Assumes cachedData lock is taken. + /// + /// A new TimeZoneInfo instance. + private static TimeZoneInfo GetLocalTimeZone(CachedData cachedData) + { + Debug.Assert(Monitor.IsEntered(cachedData)); + + // + // Try using the "kernel32!GetDynamicTimeZoneInformation" API to get the "id" + // + var dynamicTimeZoneInformation = new TIME_DYNAMIC_ZONE_INFORMATION(); + + // call kernel32!GetDynamicTimeZoneInformation... + uint result = Interop.Kernel32.GetDynamicTimeZoneInformation(out dynamicTimeZoneInformation); + if (result == Interop.Kernel32.TIME_ZONE_ID_INVALID) + { + // return a dummy entry + return CreateCustomTimeZone(LocalId, TimeSpan.Zero, LocalId, LocalId); + } + + // check to see if we can use the key name returned from the API call + string dynamicTimeZoneKeyName = dynamicTimeZoneInformation.GetTimeZoneKeyName(); + if (dynamicTimeZoneKeyName.Length != 0) + { + TimeZoneInfo zone; + Exception ex; + + if (TryGetTimeZone(dynamicTimeZoneKeyName, dynamicTimeZoneInformation.DynamicDaylightTimeDisabled != 0, out zone, out ex, cachedData) == TimeZoneInfoResult.Success) + { + // successfully loaded the time zone from the registry + return zone; + } + } + + var timeZoneInformation = new TIME_ZONE_INFORMATION(dynamicTimeZoneInformation); + + // the key name was not returned or it pointed to a bogus entry - search for the entry ourselves + string id = FindIdFromTimeZoneInformation(timeZoneInformation, out bool dstDisabled); + + if (id != null) + { + TimeZoneInfo zone; + Exception ex; + if (TryGetTimeZone(id, dstDisabled, out zone, out ex, cachedData) == TimeZoneInfoResult.Success) + { + // successfully loaded the time zone from the registry + return zone; + } + } + + // We could not find the data in the registry. Fall back to using + // the data from the Win32 API + return GetLocalTimeZoneFromWin32Data(timeZoneInformation, dstDisabled); + } + + /// + /// Helper function used by 'GetLocalTimeZone()' - this function wraps a bunch of + /// try/catch logic for handling the TimeZoneInfo private constructor that takes + /// a TIME_ZONE_INFORMATION structure. + /// + private static TimeZoneInfo GetLocalTimeZoneFromWin32Data(in TIME_ZONE_INFORMATION timeZoneInformation, bool dstDisabled) + { + // first try to create the TimeZoneInfo with the original 'dstDisabled' flag + try + { + return new TimeZoneInfo(timeZoneInformation, dstDisabled); + } + catch (ArgumentException) { } + catch (InvalidTimeZoneException) { } + + // if 'dstDisabled' was false then try passing in 'true' as a last ditch effort + if (!dstDisabled) + { + try + { + return new TimeZoneInfo(timeZoneInformation, dstDisabled: true); + } + catch (ArgumentException) { } + catch (InvalidTimeZoneException) { } + } + + // the data returned from Windows is completely bogus; return a dummy entry + return CreateCustomTimeZone(LocalId, TimeSpan.Zero, LocalId, LocalId); + } + + /// + /// Helper function for retrieving a TimeZoneInfo object by . + /// This function wraps the logic necessary to keep the private + /// SystemTimeZones cache in working order + /// + /// This function will either return a valid TimeZoneInfo instance or + /// it will throw 'InvalidTimeZoneException' / 'TimeZoneNotFoundException'. + /// + public static TimeZoneInfo FindSystemTimeZoneById(string id) + { + // Special case for Utc as it will not exist in the dictionary with the rest + // of the system time zones. There is no need to do this check for Local.Id + // since Local is a real time zone that exists in the dictionary cache + if (string.Equals(id, UtcId, StringComparison.OrdinalIgnoreCase)) + { + return Utc; + } + + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + if (id.Length == 0 || id.Length > MaxKeyLength || id.Contains('\0')) + { + throw new TimeZoneNotFoundException(SR.Format(SR.TimeZoneNotFound_MissingData, id)); + } + + TimeZoneInfo value; + Exception e; + + TimeZoneInfoResult result; + + CachedData cachedData = s_cachedData; + + lock (cachedData) + { + result = TryGetTimeZone(id, false, out value, out e, cachedData); + } + + if (result == TimeZoneInfoResult.Success) + { + return value; + } + else if (result == TimeZoneInfoResult.InvalidTimeZoneException) + { + throw new InvalidTimeZoneException(SR.Format(SR.InvalidTimeZone_InvalidRegistryData, id), e); + } + else if (result == TimeZoneInfoResult.SecurityException) + { + throw new SecurityException(SR.Format(SR.Security_CannotReadRegistryData, id), e); + } + else + { + throw new TimeZoneNotFoundException(SR.Format(SR.TimeZoneNotFound_MissingData, id), e); + } + } + + // DateTime.Now fast path that avoids allocating an historically accurate TimeZoneInfo.Local and just creates a 1-year (current year) accurate time zone + internal static TimeSpan GetDateTimeNowUtcOffsetFromUtc(DateTime time, out bool isAmbiguousLocalDst) + { + bool isDaylightSavings = false; + isAmbiguousLocalDst = false; + TimeSpan baseOffset; + int timeYear = time.Year; + + OffsetAndRule match = s_cachedData.GetOneYearLocalFromUtc(timeYear); + baseOffset = match.Offset; + + if (match.Rule != null) + { + baseOffset = baseOffset + match.Rule.BaseUtcOffsetDelta; + if (match.Rule.HasDaylightSaving) + { + isDaylightSavings = GetIsDaylightSavingsFromUtc(time, timeYear, match.Offset, match.Rule, null, out isAmbiguousLocalDst, Local); + baseOffset += (isDaylightSavings ? match.Rule.DaylightDelta : TimeSpan.Zero /* FUTURE: rule.StandardDelta */); + } + } + return baseOffset; + } + + /// + /// Converts a REG_TZI_FORMAT struct to a TransitionTime + /// - When the argument 'readStart' is true the corresponding daylightTransitionTimeStart field is read + /// - When the argument 'readStart' is false the corresponding dayightTransitionTimeEnd field is read + /// + private static bool TransitionTimeFromTimeZoneInformation(in REG_TZI_FORMAT timeZoneInformation, out TransitionTime transitionTime, bool readStartDate) + { + // + // SYSTEMTIME - + // + // If the time zone does not support daylight saving time or if the caller needs + // to disable daylight saving time, the wMonth member in the SYSTEMTIME structure + // must be zero. If this date is specified, the DaylightDate value in the + // TIME_ZONE_INFORMATION structure must also be specified. Otherwise, the system + // assumes the time zone data is invalid and no changes will be applied. + // + bool supportsDst = (timeZoneInformation.StandardDate.Month != 0); + + if (!supportsDst) + { + transitionTime = default(TransitionTime); + return false; + } + + // + // SYSTEMTIME - + // + // * FixedDateRule - + // If the Year member is not zero, the transition date is absolute; it will only occur one time + // + // * FloatingDateRule - + // To select the correct day in the month, set the Year member to zero, the Hour and Minute + // members to the transition time, the DayOfWeek member to the appropriate weekday, and the + // Day member to indicate the occurence of the day of the week within the month (first through fifth). + // + // Using this notation, specify the 2:00a.m. on the first Sunday in April as follows: + // Hour = 2, + // Month = 4, + // DayOfWeek = 0, + // Day = 1. + // + // Specify 2:00a.m. on the last Thursday in October as follows: + // Hour = 2, + // Month = 10, + // DayOfWeek = 4, + // Day = 5. + // + if (readStartDate) + { + // + // read the "daylightTransitionStart" + // + if (timeZoneInformation.DaylightDate.Year == 0) + { + transitionTime = TransitionTime.CreateFloatingDateRule( + new DateTime(1, /* year */ + 1, /* month */ + 1, /* day */ + timeZoneInformation.DaylightDate.Hour, + timeZoneInformation.DaylightDate.Minute, + timeZoneInformation.DaylightDate.Second, + timeZoneInformation.DaylightDate.Milliseconds), + timeZoneInformation.DaylightDate.Month, + timeZoneInformation.DaylightDate.Day, /* Week 1-5 */ + (DayOfWeek)timeZoneInformation.DaylightDate.DayOfWeek); + } + else + { + transitionTime = TransitionTime.CreateFixedDateRule( + new DateTime(1, /* year */ + 1, /* month */ + 1, /* day */ + timeZoneInformation.DaylightDate.Hour, + timeZoneInformation.DaylightDate.Minute, + timeZoneInformation.DaylightDate.Second, + timeZoneInformation.DaylightDate.Milliseconds), + timeZoneInformation.DaylightDate.Month, + timeZoneInformation.DaylightDate.Day); + } + } + else + { + // + // read the "daylightTransitionEnd" + // + if (timeZoneInformation.StandardDate.Year == 0) + { + transitionTime = TransitionTime.CreateFloatingDateRule( + new DateTime(1, /* year */ + 1, /* month */ + 1, /* day */ + timeZoneInformation.StandardDate.Hour, + timeZoneInformation.StandardDate.Minute, + timeZoneInformation.StandardDate.Second, + timeZoneInformation.StandardDate.Milliseconds), + timeZoneInformation.StandardDate.Month, + timeZoneInformation.StandardDate.Day, /* Week 1-5 */ + (DayOfWeek)timeZoneInformation.StandardDate.DayOfWeek); + } + else + { + transitionTime = TransitionTime.CreateFixedDateRule( + new DateTime(1, /* year */ + 1, /* month */ + 1, /* day */ + timeZoneInformation.StandardDate.Hour, + timeZoneInformation.StandardDate.Minute, + timeZoneInformation.StandardDate.Second, + timeZoneInformation.StandardDate.Milliseconds), + timeZoneInformation.StandardDate.Month, + timeZoneInformation.StandardDate.Day); + } + } + + return true; + } + + /// + /// Helper function that takes: + /// 1. A string representing a registry key name. + /// 2. A REG_TZI_FORMAT struct containing the default rule. + /// 3. An AdjustmentRule[] out-parameter. + /// + private static bool TryCreateAdjustmentRules(string id, in REG_TZI_FORMAT defaultTimeZoneInformation, out AdjustmentRule[] rules, out Exception e, int defaultBaseUtcOffset) + { + rules = null; + e = null; + + try + { + // Optional, Dynamic Time Zone Registry Data + // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + // + // HKLM + // Software + // Microsoft + // Windows NT + // CurrentVersion + // Time Zones + // + // Dynamic DST + // * "FirstEntry" REG_DWORD "1980" + // First year in the table. If the current year is less than this value, + // this entry will be used for DST boundaries + // * "LastEntry" REG_DWORD "2038" + // Last year in the table. If the current year is greater than this value, + // this entry will be used for DST boundaries" + // * "" REG_BINARY REG_TZI_FORMAT + // * "" REG_BINARY REG_TZI_FORMAT + // * "" REG_BINARY REG_TZI_FORMAT + // + using (RegistryKey dynamicKey = Registry.LocalMachine.OpenSubKey(TimeZonesRegistryHive + "\\" + id + "\\Dynamic DST", writable: false)) + { + if (dynamicKey == null) + { + AdjustmentRule rule = CreateAdjustmentRuleFromTimeZoneInformation( + defaultTimeZoneInformation, DateTime.MinValue.Date, DateTime.MaxValue.Date, defaultBaseUtcOffset); + if (rule != null) + { + rules = new[] { rule }; + } + return true; + } + + // + // loop over all of the "\Dynamic DST" hive entries + // + // read FirstEntry {MinValue - (year1, 12, 31)} + // read MiddleEntry {(yearN, 1, 1) - (yearN, 12, 31)} + // read LastEntry {(yearN, 1, 1) - MaxValue } + + // read the FirstEntry and LastEntry key values (ex: "1980", "2038") + int first = (int)dynamicKey.GetValue(FirstEntryValue, -1, RegistryValueOptions.None); + int last = (int)dynamicKey.GetValue(LastEntryValue, -1, RegistryValueOptions.None); + + if (first == -1 || last == -1 || first > last) + { + return false; + } + + // read the first year entry + REG_TZI_FORMAT dtzi; + + if (!TryGetTimeZoneEntryFromRegistry(dynamicKey, first.ToString(CultureInfo.InvariantCulture), out dtzi)) + { + return false; + } + + if (first == last) + { + // there is just 1 dynamic rule for this time zone. + AdjustmentRule rule = CreateAdjustmentRuleFromTimeZoneInformation(dtzi, DateTime.MinValue.Date, DateTime.MaxValue.Date, defaultBaseUtcOffset); + if (rule != null) + { + rules = new[] { rule }; + } + return true; + } + + List rulesList = new List(1); + + // there are more than 1 dynamic rules for this time zone. + AdjustmentRule firstRule = CreateAdjustmentRuleFromTimeZoneInformation( + dtzi, + DateTime.MinValue.Date, // MinValue + new DateTime(first, 12, 31), // December 31, + defaultBaseUtcOffset); + + if (firstRule != null) + { + rulesList.Add(firstRule); + } + + // read the middle year entries + for (int i = first + 1; i < last; i++) + { + if (!TryGetTimeZoneEntryFromRegistry(dynamicKey, i.ToString(CultureInfo.InvariantCulture), out dtzi)) + { + return false; + } + AdjustmentRule middleRule = CreateAdjustmentRuleFromTimeZoneInformation( + dtzi, + new DateTime(i, 1, 1), // January 01, + new DateTime(i, 12, 31), // December 31, + defaultBaseUtcOffset); + + if (middleRule != null) + { + rulesList.Add(middleRule); + } + } + + // read the last year entry + if (!TryGetTimeZoneEntryFromRegistry(dynamicKey, last.ToString(CultureInfo.InvariantCulture), out dtzi)) + { + return false; + } + AdjustmentRule lastRule = CreateAdjustmentRuleFromTimeZoneInformation( + dtzi, + new DateTime(last, 1, 1), // January 01, + DateTime.MaxValue.Date, // MaxValue + defaultBaseUtcOffset); + + if (lastRule != null) + { + rulesList.Add(lastRule); + } + + // convert the List to an AdjustmentRule array + if (rulesList.Count != 0) + { + rules = rulesList.ToArray(); + } + } // end of: using (RegistryKey dynamicKey... + } + catch (InvalidCastException ex) + { + // one of the RegistryKey.GetValue calls could not be cast to an expected value type + e = ex; + return false; + } + catch (ArgumentOutOfRangeException ex) + { + e = ex; + return false; + } + catch (ArgumentException ex) + { + e = ex; + return false; + } + return true; + } + + private unsafe static bool TryGetTimeZoneEntryFromRegistry(RegistryKey key, string name, out REG_TZI_FORMAT dtzi) + { + byte[] regValue = key.GetValue(name, null, RegistryValueOptions.None) as byte[]; + if (regValue == null || regValue.Length != sizeof(REG_TZI_FORMAT)) + { + dtzi = default; + return false; + } + fixed (byte * pBytes = ®Value[0]) + dtzi = *(REG_TZI_FORMAT *)pBytes; + return true; + } + + /// + /// Helper function that compares the StandardBias and StandardDate portion a + /// TimeZoneInformation struct to a time zone registry entry. + /// + private static bool TryCompareStandardDate(in TIME_ZONE_INFORMATION timeZone, in REG_TZI_FORMAT registryTimeZoneInfo) => + timeZone.Bias == registryTimeZoneInfo.Bias && + timeZone.StandardBias == registryTimeZoneInfo.StandardBias && + timeZone.StandardDate.Equals(registryTimeZoneInfo.StandardDate); + + /// + /// Helper function that compares a TimeZoneInformation struct to a time zone registry entry. + /// + private static bool TryCompareTimeZoneInformationToRegistry(in TIME_ZONE_INFORMATION timeZone, string id, out bool dstDisabled) + { + dstDisabled = false; + + using (RegistryKey key = Registry.LocalMachine.OpenSubKey(TimeZonesRegistryHive + "\\" + id, writable: false)) + { + if (key == null) + { + return false; + } + + REG_TZI_FORMAT registryTimeZoneInfo; + if (!TryGetTimeZoneEntryFromRegistry(key, TimeZoneInfoValue, out registryTimeZoneInfo)) + { + return false; + } + + // + // first compare the bias and standard date information between the data from the Win32 API + // and the data from the registry... + // + bool result = TryCompareStandardDate(timeZone, registryTimeZoneInfo); + + if (!result) + { + return false; + } + + result = dstDisabled || CheckDaylightSavingTimeNotSupported(timeZone) || + // + // since Daylight Saving Time is not "disabled", do a straight comparision between + // the Win32 API data and the registry data ... + // + (timeZone.DaylightBias == registryTimeZoneInfo.DaylightBias && + timeZone.DaylightDate.Equals(registryTimeZoneInfo.DaylightDate)); + + // Finally compare the "StandardName" string value... + // + // we do not compare "DaylightName" as this TimeZoneInformation field may contain + // either "StandardName" or "DaylightName" depending on the time of year and current machine settings + // + if (result) + { + string registryStandardName = key.GetValue(StandardValue, string.Empty, RegistryValueOptions.None) as string; + result = string.Equals(registryStandardName, timeZone.GetStandardName(), StringComparison.Ordinal); + } + return result; + } + } + + /// + /// Helper function for retrieving a localized string resource via MUI. + /// The function expects a string in the form: "@resource.dll, -123" + /// + /// "resource.dll" is a language-neutral portable executable (LNPE) file in + /// the %windir%\system32 directory. The OS is queried to find the best-fit + /// localized resource file for this LNPE (ex: %windir%\system32\en-us\resource.dll.mui). + /// If a localized resource file exists, we LoadString resource ID "123" and + /// return it to our caller. + /// + private static string TryGetLocalizedNameByMuiNativeResource(string resource) + { + if (string.IsNullOrEmpty(resource)) + { + return string.Empty; + } + + // parse "@tzres.dll, -100" + // + // filePath = "C:\Windows\System32\tzres.dll" + // resourceId = -100 + // + string[] resources = resource.Split(','); + if (resources.Length != 2) + { + return string.Empty; + } + + string filePath; + int resourceId; + + // get the path to Windows\System32 + string system32 = Environment.SystemDirectory; + + // trim the string "@tzres.dll" => "tzres.dll" + string tzresDll = resources[0].TrimStart('@'); + + try + { + filePath = Path.Combine(system32, tzresDll); + } + catch (ArgumentException) + { + // there were probably illegal characters in the path + return string.Empty; + } + + if (!int.TryParse(resources[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out resourceId)) + { + return string.Empty; + } + resourceId = -resourceId; + + try + { + StringBuilder fileMuiPath = StringBuilderCache.Acquire(Interop.Kernel32.MAX_PATH); + fileMuiPath.Length = Interop.Kernel32.MAX_PATH; + int fileMuiPathLength = Interop.Kernel32.MAX_PATH; + int languageLength = 0; + long enumerator = 0; + + bool succeeded = Interop.Kernel32.GetFileMUIPath( + Interop.Kernel32.MUI_PREFERRED_UI_LANGUAGES, + filePath, null /* language */, ref languageLength, + fileMuiPath, ref fileMuiPathLength, ref enumerator); + if (!succeeded) + { + StringBuilderCache.Release(fileMuiPath); + return string.Empty; + } + return TryGetLocalizedNameByNativeResource(StringBuilderCache.GetStringAndRelease(fileMuiPath), resourceId); + } + catch (EntryPointNotFoundException) + { + return string.Empty; + } + } + + /// + /// Helper function for retrieving a localized string resource via a native resource DLL. + /// The function expects a string in the form: "C:\Windows\System32\en-us\resource.dll" + /// + /// "resource.dll" is a language-specific resource DLL. + /// If the localized resource DLL exists, LoadString(resource) is returned. + /// + private static string TryGetLocalizedNameByNativeResource(string filePath, int resource) + { + using (SafeLibraryHandle handle = + Interop.Kernel32.LoadLibraryEx(filePath, IntPtr.Zero, Interop.Kernel32.LOAD_LIBRARY_AS_DATAFILE)) + { + if (!handle.IsInvalid) + { + const int LoadStringMaxLength = 500; + + StringBuilder localizedResource = StringBuilderCache.Acquire(LoadStringMaxLength); + + int result = Interop.User32.LoadString(handle, resource, + localizedResource, LoadStringMaxLength); + + if (result != 0) + { + return StringBuilderCache.GetStringAndRelease(localizedResource); + } + } + } + return string.Empty; + } + + /// + /// Helper function for retrieving the DisplayName, StandardName, and DaylightName from the registry + /// + /// The function first checks the MUI_ key-values, and if they exist, it loads the strings from the MUI + /// resource dll(s). When the keys do not exist, the function falls back to reading from the standard + /// key-values + /// + private static void GetLocalizedNamesByRegistryKey(RegistryKey key, out string displayName, out string standardName, out string daylightName) + { + displayName = string.Empty; + standardName = string.Empty; + daylightName = string.Empty; + + // read the MUI_ registry keys + string displayNameMuiResource = key.GetValue(MuiDisplayValue, string.Empty, RegistryValueOptions.None) as string; + string standardNameMuiResource = key.GetValue(MuiStandardValue, string.Empty, RegistryValueOptions.None) as string; + string daylightNameMuiResource = key.GetValue(MuiDaylightValue, string.Empty, RegistryValueOptions.None) as string; + + // try to load the strings from the native resource DLL(s) + if (!string.IsNullOrEmpty(displayNameMuiResource)) + { + displayName = TryGetLocalizedNameByMuiNativeResource(displayNameMuiResource); + } + + if (!string.IsNullOrEmpty(standardNameMuiResource)) + { + standardName = TryGetLocalizedNameByMuiNativeResource(standardNameMuiResource); + } + + if (!string.IsNullOrEmpty(daylightNameMuiResource)) + { + daylightName = TryGetLocalizedNameByMuiNativeResource(daylightNameMuiResource); + } + + // fallback to using the standard registry keys + if (string.IsNullOrEmpty(displayName)) + { + displayName = key.GetValue(DisplayValue, string.Empty, RegistryValueOptions.None) as string; + } + if (string.IsNullOrEmpty(standardName)) + { + standardName = key.GetValue(StandardValue, string.Empty, RegistryValueOptions.None) as string; + } + if (string.IsNullOrEmpty(daylightName)) + { + daylightName = key.GetValue(DaylightValue, string.Empty, RegistryValueOptions.None) as string; + } + } + + /// + /// Helper function that takes a string representing a registry key name + /// and returns a TimeZoneInfo instance. + /// + private static TimeZoneInfoResult TryGetTimeZoneFromLocalMachine(string id, out TimeZoneInfo value, out Exception e) + { + e = null; + + // Standard Time Zone Registry Data + // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + // HKLM + // Software + // Microsoft + // Windows NT + // CurrentVersion + // Time Zones + // + // * STD, REG_SZ "Standard Time Name" + // (For OS installed zones, this will always be English) + // * MUI_STD, REG_SZ "@tzres.dll,-1234" + // Indirect string to localized resource for Standard Time, + // add "%windir%\system32\" after "@" + // * DLT, REG_SZ "Daylight Time Name" + // (For OS installed zones, this will always be English) + // * MUI_DLT, REG_SZ "@tzres.dll,-1234" + // Indirect string to localized resource for Daylight Time, + // add "%windir%\system32\" after "@" + // * Display, REG_SZ "Display Name like (GMT-8:00) Pacific Time..." + // * MUI_Display, REG_SZ "@tzres.dll,-1234" + // Indirect string to localized resource for the Display, + // add "%windir%\system32\" after "@" + // * TZI, REG_BINARY REG_TZI_FORMAT + // + using (RegistryKey key = Registry.LocalMachine.OpenSubKey(TimeZonesRegistryHive + "\\" + id, writable: false)) + { + if (key == null) + { + value = null; + return TimeZoneInfoResult.TimeZoneNotFoundException; + } + + REG_TZI_FORMAT defaultTimeZoneInformation; + if (!TryGetTimeZoneEntryFromRegistry(key, TimeZoneInfoValue, out defaultTimeZoneInformation)) + { + // the registry value could not be cast to a byte array + value = null; + return TimeZoneInfoResult.InvalidTimeZoneException; + } + + AdjustmentRule[] adjustmentRules; + if (!TryCreateAdjustmentRules(id, defaultTimeZoneInformation, out adjustmentRules, out e, defaultTimeZoneInformation.Bias)) + { + value = null; + return TimeZoneInfoResult.InvalidTimeZoneException; + } + + GetLocalizedNamesByRegistryKey(key, out string displayName, out string standardName, out string daylightName); + + try + { + value = new TimeZoneInfo( + id, + new TimeSpan(0, -(defaultTimeZoneInformation.Bias), 0), + displayName, + standardName, + daylightName, + adjustmentRules, + disableDaylightSavingTime: false); + + return TimeZoneInfoResult.Success; + } + catch (ArgumentException ex) + { + // TimeZoneInfo constructor can throw ArgumentException and InvalidTimeZoneException + value = null; + e = ex; + return TimeZoneInfoResult.InvalidTimeZoneException; + } + catch (InvalidTimeZoneException ex) + { + // TimeZoneInfo constructor can throw ArgumentException and InvalidTimeZoneException + value = null; + e = ex; + return TimeZoneInfoResult.InvalidTimeZoneException; + } + } + } + } +} diff --git a/external/corert/src/System.Private.CoreLib/shared/System/TimeZoneInfo.cs b/external/corert/src/System.Private.CoreLib/shared/System/TimeZoneInfo.cs new file mode 100644 index 0000000000..6e27376b68 --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/shared/System/TimeZoneInfo.cs @@ -0,0 +1,1993 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Globalization; +using System.Runtime.Serialization; +using System.Threading; + +namespace System +{ + // + // DateTime uses TimeZoneInfo under the hood for IsDaylightSavingTime, IsAmbiguousTime, and GetUtcOffset. + // These TimeZoneInfo APIs can throw ArgumentException when an Invalid-Time is passed in. To avoid this + // unwanted behavior in DateTime public APIs, DateTime internally passes the + // TimeZoneInfoOptions.NoThrowOnInvalidTime flag to internal TimeZoneInfo APIs. + // + // In the future we can consider exposing similar options on the public TimeZoneInfo APIs if there is enough + // demand for this alternate behavior. + // + [Flags] + internal enum TimeZoneInfoOptions + { + None = 1, + NoThrowOnInvalidTime = 2 + }; + + [Serializable] + [System.Runtime.CompilerServices.TypeForwardedFrom("System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] + public sealed partial class TimeZoneInfo : IEquatable, ISerializable, IDeserializationCallback + { + private enum TimeZoneInfoResult + { + Success = 0, + TimeZoneNotFoundException = 1, + InvalidTimeZoneException = 2, + SecurityException = 3 + }; + + private readonly string _id; + private readonly string _displayName; + private readonly string _standardDisplayName; + private readonly string _daylightDisplayName; + private readonly TimeSpan _baseUtcOffset; + private readonly bool _supportsDaylightSavingTime; + private readonly AdjustmentRule[] _adjustmentRules; + + // constants for TimeZoneInfo.Local and TimeZoneInfo.Utc + private const string UtcId = "UTC"; + private const string LocalId = "Local"; + + private static readonly TimeZoneInfo s_utcTimeZone = CreateCustomTimeZone(UtcId, TimeSpan.Zero, UtcId, UtcId); + + private static CachedData s_cachedData = new CachedData(); + + // + // All cached data are encapsulated in a helper class to allow consistent view even when the data are refreshed using ClearCachedData() + // + // For example, TimeZoneInfo.Local can be cleared by another thread calling TimeZoneInfo.ClearCachedData. Without the consistent snapshot, + // there is a chance that the internal ConvertTime calls will throw since 'source' won't be reference equal to the new TimeZoneInfo.Local. + // +#pragma warning disable 0420 + private sealed partial class CachedData + { + private volatile TimeZoneInfo _localTimeZone; + + private TimeZoneInfo CreateLocal() + { + lock (this) + { + TimeZoneInfo timeZone = _localTimeZone; + if (timeZone == null) + { + timeZone = GetLocalTimeZone(this); + + // this step is to break the reference equality + // between TimeZoneInfo.Local and a second time zone + // such as "Pacific Standard Time" + timeZone = new TimeZoneInfo( + timeZone._id, + timeZone._baseUtcOffset, + timeZone._displayName, + timeZone._standardDisplayName, + timeZone._daylightDisplayName, + timeZone._adjustmentRules, + disableDaylightSavingTime: false); + + _localTimeZone = timeZone; + } + return timeZone; + } + } + + public TimeZoneInfo Local + { + get + { + TimeZoneInfo timeZone = _localTimeZone; + if (timeZone == null) + { + timeZone = CreateLocal(); + } + return timeZone; + } + } + + /// + /// Helper function that returns the corresponding DateTimeKind for this TimeZoneInfo. + /// + public DateTimeKind GetCorrespondingKind(TimeZoneInfo timeZone) + { + // We check reference equality to see if 'this' is the same as + // TimeZoneInfo.Local or TimeZoneInfo.Utc. This check is needed to + // support setting the DateTime Kind property to 'Local' or + // 'Utc' on the ConverTime(...) return value. + // + // Using reference equality instead of value equality was a + // performance based design compromise. The reference equality + // has much greater performance, but it reduces the number of + // returned DateTime's that can be properly set as 'Local' or 'Utc'. + // + // For example, the user could be converting to the TimeZoneInfo returned + // by FindSystemTimeZoneById("Pacific Standard Time") and their local + // machine may be in Pacific time. If we used value equality to determine + // the corresponding Kind then this conversion would be tagged as 'Local'; + // where as we are currently tagging the returned DateTime as 'Unspecified' + // in this example. Only when the user passes in TimeZoneInfo.Local or + // TimeZoneInfo.Utc to the ConvertTime(...) methods will this check succeed. + // + return + ReferenceEquals(timeZone, s_utcTimeZone) ? DateTimeKind.Utc : + ReferenceEquals(timeZone, _localTimeZone) ? DateTimeKind.Local : + DateTimeKind.Unspecified; + } + + public Dictionary _systemTimeZones; + public ReadOnlyCollection _readOnlySystemTimeZones; + public bool _allSystemTimeZonesRead; + }; +#pragma warning restore 0420 + + // used by GetUtcOffsetFromUtc (DateTime.Now, DateTime.ToLocalTime) for max/min whole-day range checks + private static readonly DateTime s_maxDateOnly = new DateTime(9999, 12, 31); + private static readonly DateTime s_minDateOnly = new DateTime(1, 1, 2); + + public string Id => _id; + + public string DisplayName => _displayName ?? string.Empty; + + public string StandardName => _standardDisplayName ?? string.Empty; + + public string DaylightName => _daylightDisplayName ?? string.Empty; + + public TimeSpan BaseUtcOffset => _baseUtcOffset; + + public bool SupportsDaylightSavingTime => _supportsDaylightSavingTime; + + /// + /// Returns an array of TimeSpan objects representing all of + /// possible UTC offset values for this ambiguous time. + /// + public TimeSpan[] GetAmbiguousTimeOffsets(DateTimeOffset dateTimeOffset) + { + if (!SupportsDaylightSavingTime) + { + throw new ArgumentException(SR.Argument_DateTimeOffsetIsNotAmbiguous, nameof(dateTimeOffset)); + } + + DateTime adjustedTime = ConvertTime(dateTimeOffset, this).DateTime; + + bool isAmbiguous = false; + int? ruleIndex; + AdjustmentRule rule = GetAdjustmentRuleForAmbiguousOffsets(adjustedTime, out ruleIndex); + if (rule != null && rule.HasDaylightSaving) + { + DaylightTimeStruct daylightTime = GetDaylightTime(adjustedTime.Year, rule, ruleIndex); + isAmbiguous = GetIsAmbiguousTime(adjustedTime, rule, daylightTime); + } + + if (!isAmbiguous) + { + throw new ArgumentException(SR.Argument_DateTimeOffsetIsNotAmbiguous, nameof(dateTimeOffset)); + } + + // the passed in dateTime is ambiguous in this TimeZoneInfo instance + TimeSpan[] timeSpans = new TimeSpan[2]; + + TimeSpan actualUtcOffset = _baseUtcOffset + rule.BaseUtcOffsetDelta; + + // the TimeSpan array must be sorted from least to greatest + if (rule.DaylightDelta > TimeSpan.Zero) + { + timeSpans[0] = actualUtcOffset; // FUTURE: + rule.StandardDelta; + timeSpans[1] = actualUtcOffset + rule.DaylightDelta; + } + else + { + timeSpans[0] = actualUtcOffset + rule.DaylightDelta; + timeSpans[1] = actualUtcOffset; // FUTURE: + rule.StandardDelta; + } + return timeSpans; + } + + /// + /// Returns an array of TimeSpan objects representing all of + /// possible UTC offset values for this ambiguous time. + /// + public TimeSpan[] GetAmbiguousTimeOffsets(DateTime dateTime) + { + if (!SupportsDaylightSavingTime) + { + throw new ArgumentException(SR.Argument_DateTimeIsNotAmbiguous, nameof(dateTime)); + } + + DateTime adjustedTime; + if (dateTime.Kind == DateTimeKind.Local) + { + CachedData cachedData = s_cachedData; + adjustedTime = ConvertTime(dateTime, cachedData.Local, this, TimeZoneInfoOptions.None, cachedData); + } + else if (dateTime.Kind == DateTimeKind.Utc) + { + CachedData cachedData = s_cachedData; + adjustedTime = ConvertTime(dateTime, s_utcTimeZone, this, TimeZoneInfoOptions.None, cachedData); + } + else + { + adjustedTime = dateTime; + } + + bool isAmbiguous = false; + int? ruleIndex; + AdjustmentRule rule = GetAdjustmentRuleForAmbiguousOffsets(adjustedTime, out ruleIndex); + if (rule != null && rule.HasDaylightSaving) + { + DaylightTimeStruct daylightTime = GetDaylightTime(adjustedTime.Year, rule, ruleIndex); + isAmbiguous = GetIsAmbiguousTime(adjustedTime, rule, daylightTime); + } + + if (!isAmbiguous) + { + throw new ArgumentException(SR.Argument_DateTimeIsNotAmbiguous, nameof(dateTime)); + } + + // the passed in dateTime is ambiguous in this TimeZoneInfo instance + TimeSpan[] timeSpans = new TimeSpan[2]; + TimeSpan actualUtcOffset = _baseUtcOffset + rule.BaseUtcOffsetDelta; + + // the TimeSpan array must be sorted from least to greatest + if (rule.DaylightDelta > TimeSpan.Zero) + { + timeSpans[0] = actualUtcOffset; // FUTURE: + rule.StandardDelta; + timeSpans[1] = actualUtcOffset + rule.DaylightDelta; + } + else + { + timeSpans[0] = actualUtcOffset + rule.DaylightDelta; + timeSpans[1] = actualUtcOffset; // FUTURE: + rule.StandardDelta; + } + return timeSpans; + } + + // note the time is already adjusted + private AdjustmentRule GetAdjustmentRuleForAmbiguousOffsets(DateTime adjustedTime, out int? ruleIndex) + { + AdjustmentRule rule = GetAdjustmentRuleForTime(adjustedTime, out ruleIndex); + if (rule != null && rule.NoDaylightTransitions && !rule.HasDaylightSaving) + { + // When using NoDaylightTransitions rules, each rule is only for one offset. + // When looking for the Daylight savings rules, and we found the non-DST rule, + // then we get the rule right before this rule. + return GetPreviousAdjustmentRule(rule, ruleIndex); + } + + return rule; + } + + /// + /// Gets the AdjustmentRule that is immediately preceding the specified rule. + /// If the specified rule is the first AdjustmentRule, or it isn't in _adjustmentRules, + /// then the specified rule is returned. + /// + private AdjustmentRule GetPreviousAdjustmentRule(AdjustmentRule rule, int? ruleIndex) + { + Debug.Assert(rule.NoDaylightTransitions, "GetPreviousAdjustmentRule should only be used with NoDaylightTransitions rules."); + + if (ruleIndex.HasValue && 0 < ruleIndex.Value && ruleIndex.Value < _adjustmentRules.Length) + { + return _adjustmentRules[ruleIndex.Value - 1]; + } + + AdjustmentRule result = rule; + for (int i = 1; i < _adjustmentRules.Length; i++) + { + // use ReferenceEquals here instead of AdjustmentRule.Equals because + // ReferenceEquals is much faster. This is safe because all the callers + // of GetPreviousAdjustmentRule pass in a rule that was retrieved from + // _adjustmentRules. A different approach will be needed if this ever changes. + if (ReferenceEquals(rule, _adjustmentRules[i])) + { + result = _adjustmentRules[i - 1]; + break; + } + } + return result; + } + + /// + /// Returns the Universal Coordinated Time (UTC) Offset for the current TimeZoneInfo instance. + /// + public TimeSpan GetUtcOffset(DateTimeOffset dateTimeOffset) => + GetUtcOffsetFromUtc(dateTimeOffset.UtcDateTime, this); + + /// + /// Returns the Universal Coordinated Time (UTC) Offset for the current TimeZoneInfo instance. + /// + public TimeSpan GetUtcOffset(DateTime dateTime) => + GetUtcOffset(dateTime, TimeZoneInfoOptions.NoThrowOnInvalidTime, s_cachedData); + + // Shortcut for TimeZoneInfo.Local.GetUtcOffset + internal static TimeSpan GetLocalUtcOffset(DateTime dateTime, TimeZoneInfoOptions flags) + { + CachedData cachedData = s_cachedData; + return cachedData.Local.GetUtcOffset(dateTime, flags, cachedData); + } + + /// + /// Returns the Universal Coordinated Time (UTC) Offset for the current TimeZoneInfo instance. + /// + internal TimeSpan GetUtcOffset(DateTime dateTime, TimeZoneInfoOptions flags) => + GetUtcOffset(dateTime, flags, s_cachedData); + + private TimeSpan GetUtcOffset(DateTime dateTime, TimeZoneInfoOptions flags, CachedData cachedData) + { + if (dateTime.Kind == DateTimeKind.Local) + { + if (cachedData.GetCorrespondingKind(this) != DateTimeKind.Local) + { + // + // normal case of converting from Local to Utc and then getting the offset from the UTC DateTime + // + DateTime adjustedTime = ConvertTime(dateTime, cachedData.Local, s_utcTimeZone, flags); + return GetUtcOffsetFromUtc(adjustedTime, this); + } + + // + // Fall through for TimeZoneInfo.Local.GetUtcOffset(date) + // to handle an edge case with Invalid-Times for DateTime formatting: + // + // Consider the invalid PST time "2007-03-11T02:00:00.0000000-08:00" + // + // By directly calling GetUtcOffset instead of converting to UTC and then calling GetUtcOffsetFromUtc + // the correct invalid offset of "-08:00" is returned. In the normal case of converting to UTC as an + // interim-step, the invalid time is adjusted into a *valid* UTC time which causes a change in output: + // + // 1) invalid PST time "2007-03-11T02:00:00.0000000-08:00" + // 2) converted to UTC "2007-03-11T10:00:00.0000000Z" + // 3) offset returned "2007-03-11T03:00:00.0000000-07:00" + // + } + else if (dateTime.Kind == DateTimeKind.Utc) + { + if (cachedData.GetCorrespondingKind(this) == DateTimeKind.Utc) + { + return _baseUtcOffset; + } + else + { + // + // passing in a UTC dateTime to a non-UTC TimeZoneInfo instance is a + // special Loss-Less case. + // + return GetUtcOffsetFromUtc(dateTime, this); + } + } + + return GetUtcOffset(dateTime, this, flags); + } + + /// + /// Returns true if the time is during the ambiguous time period + /// for the current TimeZoneInfo instance. + /// + public bool IsAmbiguousTime(DateTimeOffset dateTimeOffset) + { + if (!_supportsDaylightSavingTime) + { + return false; + } + + DateTimeOffset adjustedTime = ConvertTime(dateTimeOffset, this); + return IsAmbiguousTime(adjustedTime.DateTime); + } + + /// + /// Returns true if the time is during the ambiguous time period + /// for the current TimeZoneInfo instance. + /// + public bool IsAmbiguousTime(DateTime dateTime) => + IsAmbiguousTime(dateTime, TimeZoneInfoOptions.NoThrowOnInvalidTime); + + /// + /// Returns true if the time is during the ambiguous time period + /// for the current TimeZoneInfo instance. + /// + internal bool IsAmbiguousTime(DateTime dateTime, TimeZoneInfoOptions flags) + { + if (!_supportsDaylightSavingTime) + { + return false; + } + + CachedData cachedData = s_cachedData; + DateTime adjustedTime = + dateTime.Kind == DateTimeKind.Local ? ConvertTime(dateTime, cachedData.Local, this, flags, cachedData) : + dateTime.Kind == DateTimeKind.Utc ? ConvertTime(dateTime, s_utcTimeZone, this, flags, cachedData) : + dateTime; + + int? ruleIndex; + AdjustmentRule rule = GetAdjustmentRuleForTime(adjustedTime, out ruleIndex); + if (rule != null && rule.HasDaylightSaving) + { + DaylightTimeStruct daylightTime = GetDaylightTime(adjustedTime.Year, rule, ruleIndex); + return GetIsAmbiguousTime(adjustedTime, rule, daylightTime); + } + return false; + } + + /// + /// Returns true if the time is during Daylight Saving time for the current TimeZoneInfo instance. + /// + public bool IsDaylightSavingTime(DateTimeOffset dateTimeOffset) + { + bool isDaylightSavingTime; + GetUtcOffsetFromUtc(dateTimeOffset.UtcDateTime, this, out isDaylightSavingTime); + return isDaylightSavingTime; + } + + /// + /// Returns true if the time is during Daylight Saving time for the current TimeZoneInfo instance. + /// + public bool IsDaylightSavingTime(DateTime dateTime) => + IsDaylightSavingTime(dateTime, TimeZoneInfoOptions.NoThrowOnInvalidTime, s_cachedData); + + /// + /// Returns true if the time is during Daylight Saving time for the current TimeZoneInfo instance. + /// + internal bool IsDaylightSavingTime(DateTime dateTime, TimeZoneInfoOptions flags) => + IsDaylightSavingTime(dateTime, flags, s_cachedData); + + private bool IsDaylightSavingTime(DateTime dateTime, TimeZoneInfoOptions flags, CachedData cachedData) + { + // + // dateTime.Kind is UTC, then time will be converted from UTC + // into current instance's timezone + // dateTime.Kind is Local, then time will be converted from Local + // into current instance's timezone + // dateTime.Kind is UnSpecified, then time is already in + // current instance's timezone + // + // Our DateTime handles ambiguous times, (one is in the daylight and + // one is in standard.) If a new DateTime is constructed during ambiguous + // time, it is defaulted to "Standard" (i.e. this will return false). + // For Invalid times, we will return false + + if (!_supportsDaylightSavingTime || _adjustmentRules == null) + { + return false; + } + + DateTime adjustedTime; + // + // handle any Local/Utc special cases... + // + if (dateTime.Kind == DateTimeKind.Local) + { + adjustedTime = ConvertTime(dateTime, cachedData.Local, this, flags, cachedData); + } + else if (dateTime.Kind == DateTimeKind.Utc) + { + if (cachedData.GetCorrespondingKind(this) == DateTimeKind.Utc) + { + // simple always false case: TimeZoneInfo.Utc.IsDaylightSavingTime(dateTime, flags); + return false; + } + else + { + // + // passing in a UTC dateTime to a non-UTC TimeZoneInfo instance is a + // special Loss-Less case. + // + bool isDaylightSavings; + GetUtcOffsetFromUtc(dateTime, this, out isDaylightSavings); + return isDaylightSavings; + } + } + else + { + adjustedTime = dateTime; + } + + // + // handle the normal cases... + // + int? ruleIndex; + AdjustmentRule rule = GetAdjustmentRuleForTime(adjustedTime, out ruleIndex); + if (rule != null && rule.HasDaylightSaving) + { + DaylightTimeStruct daylightTime = GetDaylightTime(adjustedTime.Year, rule, ruleIndex); + return GetIsDaylightSavings(adjustedTime, rule, daylightTime, flags); + } + else + { + return false; + } + } + + /// + /// Returns true when dateTime falls into a "hole in time". + /// + public bool IsInvalidTime(DateTime dateTime) + { + bool isInvalid = false; + + if ((dateTime.Kind == DateTimeKind.Unspecified) || + (dateTime.Kind == DateTimeKind.Local && s_cachedData.GetCorrespondingKind(this) == DateTimeKind.Local)) + { + // only check Unspecified and (Local when this TimeZoneInfo instance is Local) + int? ruleIndex; + AdjustmentRule rule = GetAdjustmentRuleForTime(dateTime, out ruleIndex); + + if (rule != null && rule.HasDaylightSaving) + { + DaylightTimeStruct daylightTime = GetDaylightTime(dateTime.Year, rule, ruleIndex); + isInvalid = GetIsInvalidTime(dateTime, rule, daylightTime); + } + else + { + isInvalid = false; + } + } + + return isInvalid; + } + + /// + /// Clears data from static members. + /// + public static void ClearCachedData() + { + // Clear a fresh instance of cached data + s_cachedData = new CachedData(); + } + + /// + /// Converts the value of a DateTime object from sourceTimeZone to destinationTimeZone. + /// + public static DateTimeOffset ConvertTimeBySystemTimeZoneId(DateTimeOffset dateTimeOffset, string destinationTimeZoneId) => + ConvertTime(dateTimeOffset, FindSystemTimeZoneById(destinationTimeZoneId)); + + /// + /// Converts the value of a DateTime object from sourceTimeZone to destinationTimeZone. + /// + public static DateTime ConvertTimeBySystemTimeZoneId(DateTime dateTime, string destinationTimeZoneId) => + ConvertTime(dateTime, FindSystemTimeZoneById(destinationTimeZoneId)); + + /// + /// Converts the value of a DateTime object from sourceTimeZone to destinationTimeZone. + /// + public static DateTime ConvertTimeBySystemTimeZoneId(DateTime dateTime, string sourceTimeZoneId, string destinationTimeZoneId) + { + if (dateTime.Kind == DateTimeKind.Local && string.Equals(sourceTimeZoneId, Local.Id, StringComparison.OrdinalIgnoreCase)) + { + // TimeZoneInfo.Local can be cleared by another thread calling TimeZoneInfo.ClearCachedData. + // Take snapshot of cached data to guarantee this method will not be impacted by the ClearCachedData call. + // Without the snapshot, there is a chance that ConvertTime will throw since 'source' won't + // be reference equal to the new TimeZoneInfo.Local + // + CachedData cachedData = s_cachedData; + return ConvertTime(dateTime, cachedData.Local, FindSystemTimeZoneById(destinationTimeZoneId), TimeZoneInfoOptions.None, cachedData); + } + else if (dateTime.Kind == DateTimeKind.Utc && string.Equals(sourceTimeZoneId, Utc.Id, StringComparison.OrdinalIgnoreCase)) + { + return ConvertTime(dateTime, s_utcTimeZone, FindSystemTimeZoneById(destinationTimeZoneId), TimeZoneInfoOptions.None, s_cachedData); + } + else + { + return ConvertTime(dateTime, FindSystemTimeZoneById(sourceTimeZoneId), FindSystemTimeZoneById(destinationTimeZoneId)); + } + } + + /// + /// Converts the value of the dateTime object from sourceTimeZone to destinationTimeZone + /// + public static DateTimeOffset ConvertTime(DateTimeOffset dateTimeOffset, TimeZoneInfo destinationTimeZone) + { + if (destinationTimeZone == null) + { + throw new ArgumentNullException(nameof(destinationTimeZone)); + } + + // calculate the destination time zone offset + DateTime utcDateTime = dateTimeOffset.UtcDateTime; + TimeSpan destinationOffset = GetUtcOffsetFromUtc(utcDateTime, destinationTimeZone); + + // check for overflow + long ticks = utcDateTime.Ticks + destinationOffset.Ticks; + + return + ticks > DateTimeOffset.MaxValue.Ticks ? DateTimeOffset.MaxValue : + ticks < DateTimeOffset.MinValue.Ticks ? DateTimeOffset.MinValue : + new DateTimeOffset(ticks, destinationOffset); + } + + /// + /// Converts the value of the dateTime object from sourceTimeZone to destinationTimeZone + /// + public static DateTime ConvertTime(DateTime dateTime, TimeZoneInfo destinationTimeZone) + { + if (destinationTimeZone == null) + { + throw new ArgumentNullException(nameof(destinationTimeZone)); + } + + // Special case to give a way clearing the cache without exposing ClearCachedData() + if (dateTime.Ticks == 0) + { + ClearCachedData(); + } + CachedData cachedData = s_cachedData; + TimeZoneInfo sourceTimeZone = dateTime.Kind == DateTimeKind.Utc ? s_utcTimeZone : cachedData.Local; + return ConvertTime(dateTime, sourceTimeZone, destinationTimeZone, TimeZoneInfoOptions.None, cachedData); + } + + /// + /// Converts the value of the dateTime object from sourceTimeZone to destinationTimeZone + /// + public static DateTime ConvertTime(DateTime dateTime, TimeZoneInfo sourceTimeZone, TimeZoneInfo destinationTimeZone) => + ConvertTime(dateTime, sourceTimeZone, destinationTimeZone, TimeZoneInfoOptions.None, s_cachedData); + + /// + /// Converts the value of the dateTime object from sourceTimeZone to destinationTimeZone + /// + internal static DateTime ConvertTime(DateTime dateTime, TimeZoneInfo sourceTimeZone, TimeZoneInfo destinationTimeZone, TimeZoneInfoOptions flags) => + ConvertTime(dateTime, sourceTimeZone, destinationTimeZone, flags, s_cachedData); + + private static DateTime ConvertTime(DateTime dateTime, TimeZoneInfo sourceTimeZone, TimeZoneInfo destinationTimeZone, TimeZoneInfoOptions flags, CachedData cachedData) + { + if (sourceTimeZone == null) + { + throw new ArgumentNullException(nameof(sourceTimeZone)); + } + + if (destinationTimeZone == null) + { + throw new ArgumentNullException(nameof(destinationTimeZone)); + } + + DateTimeKind sourceKind = cachedData.GetCorrespondingKind(sourceTimeZone); + if (((flags & TimeZoneInfoOptions.NoThrowOnInvalidTime) == 0) && (dateTime.Kind != DateTimeKind.Unspecified) && (dateTime.Kind != sourceKind)) + { + throw new ArgumentException(SR.Argument_ConvertMismatch, nameof(sourceTimeZone)); + } + + // + // check to see if the DateTime is in an invalid time range. This check + // requires the current AdjustmentRule and DaylightTime - which are also + // needed to calculate 'sourceOffset' in the normal conversion case. + // By calculating the 'sourceOffset' here we improve the + // performance for the normal case at the expense of the 'ArgumentException' + // case and Loss-less Local special cases. + // + int? sourceRuleIndex; + AdjustmentRule sourceRule = sourceTimeZone.GetAdjustmentRuleForTime(dateTime, out sourceRuleIndex); + TimeSpan sourceOffset = sourceTimeZone.BaseUtcOffset; + + if (sourceRule != null) + { + sourceOffset = sourceOffset + sourceRule.BaseUtcOffsetDelta; + if (sourceRule.HasDaylightSaving) + { + bool sourceIsDaylightSavings = false; + DaylightTimeStruct sourceDaylightTime = sourceTimeZone.GetDaylightTime(dateTime.Year, sourceRule, sourceRuleIndex); + + // 'dateTime' might be in an invalid time range since it is in an AdjustmentRule + // period that supports DST + if (((flags & TimeZoneInfoOptions.NoThrowOnInvalidTime) == 0) && GetIsInvalidTime(dateTime, sourceRule, sourceDaylightTime)) + { + throw new ArgumentException(SR.Argument_DateTimeIsInvalid, nameof(dateTime)); + } + sourceIsDaylightSavings = GetIsDaylightSavings(dateTime, sourceRule, sourceDaylightTime, flags); + + // adjust the sourceOffset according to the Adjustment Rule / Daylight Saving Rule + sourceOffset += (sourceIsDaylightSavings ? sourceRule.DaylightDelta : TimeSpan.Zero /*FUTURE: sourceRule.StandardDelta*/); + } + } + + DateTimeKind targetKind = cachedData.GetCorrespondingKind(destinationTimeZone); + + // handle the special case of Loss-less Local->Local and UTC->UTC) + if (dateTime.Kind != DateTimeKind.Unspecified && sourceKind != DateTimeKind.Unspecified && sourceKind == targetKind) + { + return dateTime; + } + + long utcTicks = dateTime.Ticks - sourceOffset.Ticks; + + // handle the normal case by converting from 'source' to UTC and then to 'target' + bool isAmbiguousLocalDst; + DateTime targetConverted = ConvertUtcToTimeZone(utcTicks, destinationTimeZone, out isAmbiguousLocalDst); + + if (targetKind == DateTimeKind.Local) + { + // Because the ticks conversion between UTC and local is lossy, we need to capture whether the + // time is in a repeated hour so that it can be passed to the DateTime constructor. + return new DateTime(targetConverted.Ticks, DateTimeKind.Local, isAmbiguousLocalDst); + } + else + { + return new DateTime(targetConverted.Ticks, targetKind); + } + } + + /// + /// Converts the value of a DateTime object from Coordinated Universal Time (UTC) to the destinationTimeZone. + /// + public static DateTime ConvertTimeFromUtc(DateTime dateTime, TimeZoneInfo destinationTimeZone) => + ConvertTime(dateTime, s_utcTimeZone, destinationTimeZone, TimeZoneInfoOptions.None, s_cachedData); + + /// + /// Converts the value of a DateTime object to Coordinated Universal Time (UTC). + /// + public static DateTime ConvertTimeToUtc(DateTime dateTime) + { + if (dateTime.Kind == DateTimeKind.Utc) + { + return dateTime; + } + CachedData cachedData = s_cachedData; + return ConvertTime(dateTime, cachedData.Local, s_utcTimeZone, TimeZoneInfoOptions.None, cachedData); + } + + /// + /// Converts the value of a DateTime object to Coordinated Universal Time (UTC). + /// + internal static DateTime ConvertTimeToUtc(DateTime dateTime, TimeZoneInfoOptions flags) + { + if (dateTime.Kind == DateTimeKind.Utc) + { + return dateTime; + } + CachedData cachedData = s_cachedData; + return ConvertTime(dateTime, cachedData.Local, s_utcTimeZone, flags, cachedData); + } + + /// + /// Converts the value of a DateTime object to Coordinated Universal Time (UTC). + /// + public static DateTime ConvertTimeToUtc(DateTime dateTime, TimeZoneInfo sourceTimeZone) => + ConvertTime(dateTime, sourceTimeZone, s_utcTimeZone, TimeZoneInfoOptions.None, s_cachedData); + + /// + /// Returns value equality. Equals does not compare any localizable + /// String objects (DisplayName, StandardName, DaylightName). + /// + public bool Equals(TimeZoneInfo other) => + other != null && + string.Equals(_id, other._id, StringComparison.OrdinalIgnoreCase) && + HasSameRules(other); + + public override bool Equals(object obj) => Equals(obj as TimeZoneInfo); + + public static TimeZoneInfo FromSerializedString(string source) + { + if (source == null) + { + throw new ArgumentNullException(nameof(source)); + } + if (source.Length == 0) + { + throw new ArgumentException(SR.Format(SR.Argument_InvalidSerializedString, source), nameof(source)); + } + + return StringSerializer.GetDeserializedTimeZoneInfo(source); + } + + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(_id); + + /// + /// Returns a ReadOnlyCollection containing all valid TimeZone's + /// from the local machine. The entries in the collection are sorted by + /// . + /// This method does *not* throw TimeZoneNotFoundException or InvalidTimeZoneException. + /// + public static ReadOnlyCollection GetSystemTimeZones() + { + CachedData cachedData = s_cachedData; + + lock (cachedData) + { + if (cachedData._readOnlySystemTimeZones == null) + { + PopulateAllSystemTimeZones(cachedData); + cachedData._allSystemTimeZonesRead = true; + + List list; + if (cachedData._systemTimeZones != null) + { + // return a collection of the cached system time zones + list = new List(cachedData._systemTimeZones.Values); + } + else + { + // return an empty collection + list = new List(); + } + + // sort and copy the TimeZoneInfo's into a ReadOnlyCollection for the user + list.Sort((x, y) => + { + // sort by BaseUtcOffset first and by DisplayName second - this is similar to the Windows Date/Time control panel + int comparison = x.BaseUtcOffset.CompareTo(y.BaseUtcOffset); + return comparison == 0 ? string.CompareOrdinal(x.DisplayName, y.DisplayName) : comparison; + }); + + cachedData._readOnlySystemTimeZones = new ReadOnlyCollection(list); + } + } + return cachedData._readOnlySystemTimeZones; + } + + /// + /// Value equality on the "adjustmentRules" array + /// + public bool HasSameRules(TimeZoneInfo other) + { + if (other == null) + { + throw new ArgumentNullException(nameof(other)); + } + + // check the utcOffset and supportsDaylightSavingTime members + if (_baseUtcOffset != other._baseUtcOffset || + _supportsDaylightSavingTime != other._supportsDaylightSavingTime) + { + return false; + } + + bool sameRules; + AdjustmentRule[] currentRules = _adjustmentRules; + AdjustmentRule[] otherRules = other._adjustmentRules; + + sameRules = + (currentRules == null && otherRules == null) || + (currentRules != null && otherRules != null); + + if (!sameRules) + { + // AdjustmentRule array mismatch + return false; + } + + if (currentRules != null) + { + if (currentRules.Length != otherRules.Length) + { + // AdjustmentRule array length mismatch + return false; + } + + for (int i = 0; i < currentRules.Length; i++) + { + if (!(currentRules[i]).Equals(otherRules[i])) + { + // AdjustmentRule value-equality mismatch + return false; + } + } + } + return sameRules; + } + + /// + /// Returns a TimeZoneInfo instance that represents the local time on the machine. + /// Accessing this property may throw InvalidTimeZoneException or COMException + /// if the machine is in an unstable or corrupt state. + /// + public static TimeZoneInfo Local => s_cachedData.Local; + + // + // ToSerializedString - + // + // "TimeZoneInfo" := TimeZoneInfo Data;[AdjustmentRule Data 1];...;[AdjustmentRule Data N] + // + // "TimeZoneInfo Data" := <_id>;<_baseUtcOffset>;<_displayName>; + // <_standardDisplayName>;<_daylightDispayName>; + // + // "AdjustmentRule Data" := ;;; + // [TransitionTime Data DST Start] + // [TransitionTime Data DST End] + // + // "TransitionTime Data" += ;;;; + // + public string ToSerializedString() => StringSerializer.GetSerializedString(this); + + /// + /// Returns the : "(GMT-08:00) Pacific Time (US & Canada); Tijuana" + /// + public override string ToString() => DisplayName; + + /// + /// Returns a TimeZoneInfo instance that represents Universal Coordinated Time (UTC) + /// + public static TimeZoneInfo Utc => s_utcTimeZone; + + private TimeZoneInfo( + string id, + TimeSpan baseUtcOffset, + string displayName, + string standardDisplayName, + string daylightDisplayName, + AdjustmentRule[] adjustmentRules, + bool disableDaylightSavingTime) + { + bool adjustmentRulesSupportDst; + ValidateTimeZoneInfo(id, baseUtcOffset, adjustmentRules, out adjustmentRulesSupportDst); + + _id = id; + _baseUtcOffset = baseUtcOffset; + _displayName = displayName; + _standardDisplayName = standardDisplayName; + _daylightDisplayName = disableDaylightSavingTime ? null : daylightDisplayName; + _supportsDaylightSavingTime = adjustmentRulesSupportDst && !disableDaylightSavingTime; + _adjustmentRules = adjustmentRules; + } + + /// + /// Returns a simple TimeZoneInfo instance that does not support Daylight Saving Time. + /// + public static TimeZoneInfo CreateCustomTimeZone( + string id, + TimeSpan baseUtcOffset, + string displayName, + string standardDisplayName) + { + return new TimeZoneInfo( + id, + baseUtcOffset, + displayName, + standardDisplayName, + standardDisplayName, + adjustmentRules: null, + disableDaylightSavingTime: false); + } + + /// + /// Returns a TimeZoneInfo instance that may support Daylight Saving Time. + /// + public static TimeZoneInfo CreateCustomTimeZone( + string id, + TimeSpan baseUtcOffset, + string displayName, + string standardDisplayName, + string daylightDisplayName, + AdjustmentRule[] adjustmentRules) + { + return CreateCustomTimeZone( + id, + baseUtcOffset, + displayName, + standardDisplayName, + daylightDisplayName, + adjustmentRules, + disableDaylightSavingTime: false); + } + + /// + /// Returns a TimeZoneInfo instance that may support Daylight Saving Time. + /// + public static TimeZoneInfo CreateCustomTimeZone( + string id, + TimeSpan baseUtcOffset, + string displayName, + string standardDisplayName, + string daylightDisplayName, + AdjustmentRule[] adjustmentRules, + bool disableDaylightSavingTime) + { + if (!disableDaylightSavingTime && adjustmentRules?.Length > 0) + { + adjustmentRules = (AdjustmentRule[])adjustmentRules.Clone(); + } + + return new TimeZoneInfo( + id, + baseUtcOffset, + displayName, + standardDisplayName, + daylightDisplayName, + adjustmentRules, + disableDaylightSavingTime); + } + + void IDeserializationCallback.OnDeserialization(object sender) + { + try + { + bool adjustmentRulesSupportDst; + ValidateTimeZoneInfo(_id, _baseUtcOffset, _adjustmentRules, out adjustmentRulesSupportDst); + + if (adjustmentRulesSupportDst != _supportsDaylightSavingTime) + { + throw new SerializationException(SR.Format(SR.Serialization_CorruptField, "SupportsDaylightSavingTime")); + } + } + catch (ArgumentException e) + { + throw new SerializationException(SR.Serialization_InvalidData, e); + } + catch (InvalidTimeZoneException e) + { + throw new SerializationException(SR.Serialization_InvalidData, e); + } + } + + void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) + { + if (info == null) + { + throw new ArgumentNullException(nameof(info)); + } + + info.AddValue("Id", _id); // Do not rename (binary serialization) + info.AddValue("DisplayName", _displayName); // Do not rename (binary serialization) + info.AddValue("StandardName", _standardDisplayName); // Do not rename (binary serialization) + info.AddValue("DaylightName", _daylightDisplayName); // Do not rename (binary serialization) + info.AddValue("BaseUtcOffset", _baseUtcOffset); // Do not rename (binary serialization) + info.AddValue("AdjustmentRules", _adjustmentRules); // Do not rename (binary serialization) + info.AddValue("SupportsDaylightSavingTime", _supportsDaylightSavingTime); // Do not rename (binary serialization) + } + + private TimeZoneInfo(SerializationInfo info, StreamingContext context) + { + if (info == null) + { + throw new ArgumentNullException(nameof(info)); + } + + _id = (string)info.GetValue("Id", typeof(string)); // Do not rename (binary serialization) + _displayName = (string)info.GetValue("DisplayName", typeof(string)); // Do not rename (binary serialization) + _standardDisplayName = (string)info.GetValue("StandardName", typeof(string)); // Do not rename (binary serialization) + _daylightDisplayName = (string)info.GetValue("DaylightName", typeof(string)); // Do not rename (binary serialization) + _baseUtcOffset = (TimeSpan)info.GetValue("BaseUtcOffset", typeof(TimeSpan)); // Do not rename (binary serialization) + _adjustmentRules = (AdjustmentRule[])info.GetValue("AdjustmentRules", typeof(AdjustmentRule[])); // Do not rename (binary serialization) + _supportsDaylightSavingTime = (bool)info.GetValue("SupportsDaylightSavingTime", typeof(bool)); // Do not rename (binary serialization) + } + + private AdjustmentRule GetAdjustmentRuleForTime(DateTime dateTime, out int? ruleIndex) + { + AdjustmentRule result = GetAdjustmentRuleForTime(dateTime, dateTimeisUtc: false, ruleIndex: out ruleIndex); + Debug.Assert(result == null || ruleIndex.HasValue, "If an AdjustmentRule was found, ruleIndex should also be set."); + + return result; + } + + private AdjustmentRule GetAdjustmentRuleForTime(DateTime dateTime, bool dateTimeisUtc, out int? ruleIndex) + { + if (_adjustmentRules == null || _adjustmentRules.Length == 0) + { + ruleIndex = null; + return null; + } + + // Only check the whole-date portion of the dateTime for DateTimeKind.Unspecified rules - + // This is because the AdjustmentRule DateStart & DateEnd are stored as + // Date-only values {4/2/2006 - 10/28/2006} but actually represent the + // time span {4/2/2006@00:00:00.00000 - 10/28/2006@23:59:59.99999} + DateTime date = dateTimeisUtc ? + (dateTime + BaseUtcOffset).Date : + dateTime.Date; + + int low = 0; + int high = _adjustmentRules.Length - 1; + + while (low <= high) + { + int median = low + ((high - low) >> 1); + + AdjustmentRule rule = _adjustmentRules[median]; + AdjustmentRule previousRule = median > 0 ? _adjustmentRules[median - 1] : rule; + + int compareResult = CompareAdjustmentRuleToDateTime(rule, previousRule, dateTime, date, dateTimeisUtc); + if (compareResult == 0) + { + ruleIndex = median; + return rule; + } + else if (compareResult < 0) + { + low = median + 1; + } + else + { + high = median - 1; + } + } + + ruleIndex = null; + return null; + } + + /// + /// Determines if 'rule' is the correct AdjustmentRule for the given dateTime. + /// + /// + /// A value less than zero if rule is for times before dateTime. + /// Zero if rule is correct for dateTime. + /// A value greater than zero if rule is for times after dateTime. + /// + private int CompareAdjustmentRuleToDateTime(AdjustmentRule rule, AdjustmentRule previousRule, + DateTime dateTime, DateTime dateOnly, bool dateTimeisUtc) + { + bool isAfterStart; + if (rule.DateStart.Kind == DateTimeKind.Utc) + { + DateTime dateTimeToCompare = dateTimeisUtc ? + dateTime : + // use the previous rule to compute the dateTimeToCompare, since the time daylight savings "switches" + // is based on the previous rule's offset + ConvertToUtc(dateTime, previousRule.DaylightDelta, previousRule.BaseUtcOffsetDelta); + + isAfterStart = dateTimeToCompare >= rule.DateStart; + } + else + { + // if the rule's DateStart is Unspecified, then use the whole-date portion + isAfterStart = dateOnly >= rule.DateStart; + } + + if (!isAfterStart) + { + return 1; + } + + bool isBeforeEnd; + if (rule.DateEnd.Kind == DateTimeKind.Utc) + { + DateTime dateTimeToCompare = dateTimeisUtc ? + dateTime : + ConvertToUtc(dateTime, rule.DaylightDelta, rule.BaseUtcOffsetDelta); + + isBeforeEnd = dateTimeToCompare <= rule.DateEnd; + } + else + { + // if the rule's DateEnd is Unspecified, then use the whole-date portion + isBeforeEnd = dateOnly <= rule.DateEnd; + } + + return isBeforeEnd ? 0 : -1; + } + + /// + /// Converts the dateTime to UTC using the specified deltas. + /// + private DateTime ConvertToUtc(DateTime dateTime, TimeSpan daylightDelta, TimeSpan baseUtcOffsetDelta) => + ConvertToFromUtc(dateTime, daylightDelta, baseUtcOffsetDelta, convertToUtc: true); + + /// + /// Converts the dateTime from UTC using the specified deltas. + /// + private DateTime ConvertFromUtc(DateTime dateTime, TimeSpan daylightDelta, TimeSpan baseUtcOffsetDelta) => + ConvertToFromUtc(dateTime, daylightDelta, baseUtcOffsetDelta, convertToUtc: false); + + /// + /// Converts the dateTime to or from UTC using the specified deltas. + /// + private DateTime ConvertToFromUtc(DateTime dateTime, TimeSpan daylightDelta, TimeSpan baseUtcOffsetDelta, bool convertToUtc) + { + TimeSpan offset = BaseUtcOffset + daylightDelta + baseUtcOffsetDelta; + if (convertToUtc) + { + offset = offset.Negate(); + } + + long ticks = dateTime.Ticks + offset.Ticks; + + return + ticks > DateTime.MaxValue.Ticks ? DateTime.MaxValue : + ticks < DateTime.MinValue.Ticks ? DateTime.MinValue : + new DateTime(ticks); + } + + /// + /// Helper function that converts a dateTime from UTC into the destinationTimeZone + /// - Returns DateTime.MaxValue when the converted value is too large. + /// - Returns DateTime.MinValue when the converted value is too small. + /// + private static DateTime ConvertUtcToTimeZone(long ticks, TimeZoneInfo destinationTimeZone, out bool isAmbiguousLocalDst) + { + // used to calculate the UTC offset in the destinationTimeZone + DateTime utcConverted = + ticks > DateTime.MaxValue.Ticks ? DateTime.MaxValue : + ticks < DateTime.MinValue.Ticks ? DateTime.MinValue : + new DateTime(ticks); + + // verify the time is between MinValue and MaxValue in the new time zone + TimeSpan offset = GetUtcOffsetFromUtc(utcConverted, destinationTimeZone, out isAmbiguousLocalDst); + ticks += offset.Ticks; + + return + ticks > DateTime.MaxValue.Ticks ? DateTime.MaxValue : + ticks < DateTime.MinValue.Ticks ? DateTime.MinValue : + new DateTime(ticks); + } + + /// + /// Helper function that returns a DaylightTime from a year and AdjustmentRule. + /// + private DaylightTimeStruct GetDaylightTime(int year, AdjustmentRule rule, int? ruleIndex) + { + TimeSpan delta = rule.DaylightDelta; + DateTime startTime; + DateTime endTime; + if (rule.NoDaylightTransitions) + { + // NoDaylightTransitions rules don't use DaylightTransition Start and End, instead + // the DateStart and DateEnd are UTC times that represent when daylight savings time changes. + // Convert the UTC times into adjusted time zone times. + + // use the previous rule to calculate the startTime, since the DST change happens w.r.t. the previous rule + AdjustmentRule previousRule = GetPreviousAdjustmentRule(rule, ruleIndex); + startTime = ConvertFromUtc(rule.DateStart, previousRule.DaylightDelta, previousRule.BaseUtcOffsetDelta); + + endTime = ConvertFromUtc(rule.DateEnd, rule.DaylightDelta, rule.BaseUtcOffsetDelta); + } + else + { + startTime = TransitionTimeToDateTime(year, rule.DaylightTransitionStart); + endTime = TransitionTimeToDateTime(year, rule.DaylightTransitionEnd); + } + return new DaylightTimeStruct(startTime, endTime, delta); + } + + /// + /// Helper function that checks if a given dateTime is in Daylight Saving Time (DST). + /// This function assumes the dateTime and AdjustmentRule are both in the same time zone. + /// + private static bool GetIsDaylightSavings(DateTime time, AdjustmentRule rule, DaylightTimeStruct daylightTime, TimeZoneInfoOptions flags) + { + if (rule == null) + { + return false; + } + + DateTime startTime; + DateTime endTime; + + if (time.Kind == DateTimeKind.Local) + { + // startTime and endTime represent the period from either the start of + // DST to the end and ***includes*** the potentially overlapped times + startTime = rule.IsStartDateMarkerForBeginningOfYear() ? + new DateTime(daylightTime.Start.Year, 1, 1, 0, 0, 0) : + daylightTime.Start + daylightTime.Delta; + + endTime = rule.IsEndDateMarkerForEndOfYear() ? + new DateTime(daylightTime.End.Year + 1, 1, 1, 0, 0, 0).AddTicks(-1) : + daylightTime.End; + } + else + { + // startTime and endTime represent the period from either the start of DST to the end and + // ***does not include*** the potentially overlapped times + // + // -=-=-=-=-=- Pacific Standard Time -=-=-=-=-=-=- + // April 2, 2006 October 29, 2006 + // 2AM 3AM 1AM 2AM + // | +1 hr | | -1 hr | + // | | | | + // [========== DST ========>) + // + // -=-=-=-=-=- Some Weird Time Zone -=-=-=-=-=-=- + // April 2, 2006 October 29, 2006 + // 1AM 2AM 2AM 3AM + // | -1 hr | | +1 hr | + // | | | | + // [======== DST ========>) + // + bool invalidAtStart = rule.DaylightDelta > TimeSpan.Zero; + + startTime = rule.IsStartDateMarkerForBeginningOfYear() ? + new DateTime(daylightTime.Start.Year, 1, 1, 0, 0, 0) : + daylightTime.Start + (invalidAtStart ? rule.DaylightDelta : TimeSpan.Zero); /* FUTURE: - rule.StandardDelta; */ + + endTime = rule.IsEndDateMarkerForEndOfYear() ? + new DateTime(daylightTime.End.Year + 1, 1, 1, 0, 0, 0).AddTicks(-1) : + daylightTime.End + (invalidAtStart ? -rule.DaylightDelta : TimeSpan.Zero); + } + + bool isDst = CheckIsDst(startTime, time, endTime, false, rule); + + // If this date was previously converted from a UTC date and we were able to detect that the local + // DateTime would be ambiguous, this data is stored in the DateTime to resolve this ambiguity. + if (isDst && time.Kind == DateTimeKind.Local) + { + // For normal time zones, the ambiguous hour is the last hour of daylight saving when you wind the + // clock back. It is theoretically possible to have a positive delta, (which would really be daylight + // reduction time), where you would have to wind the clock back in the begnning. + if (GetIsAmbiguousTime(time, rule, daylightTime)) + { + isDst = time.IsAmbiguousDaylightSavingTime(); + } + } + + return isDst; + } + + /// + /// Gets the offset that should be used to calculate DST start times from a UTC time. + /// + private TimeSpan GetDaylightSavingsStartOffsetFromUtc(TimeSpan baseUtcOffset, AdjustmentRule rule, int? ruleIndex) + { + if (rule.NoDaylightTransitions) + { + // use the previous rule to calculate the startTime, since the DST change happens w.r.t. the previous rule + AdjustmentRule previousRule = GetPreviousAdjustmentRule(rule, ruleIndex); + return baseUtcOffset + previousRule.BaseUtcOffsetDelta + previousRule.DaylightDelta; + } + else + { + return baseUtcOffset + rule.BaseUtcOffsetDelta; /* FUTURE: + rule.StandardDelta; */ + } + } + + /// + /// Gets the offset that should be used to calculate DST end times from a UTC time. + /// + private TimeSpan GetDaylightSavingsEndOffsetFromUtc(TimeSpan baseUtcOffset, AdjustmentRule rule) + { + // NOTE: even NoDaylightTransitions rules use this logic since DST ends w.r.t. the current rule + return baseUtcOffset + rule.BaseUtcOffsetDelta + rule.DaylightDelta; /* FUTURE: + rule.StandardDelta; */ + } + + /// + /// Helper function that checks if a given dateTime is in Daylight Saving Time (DST). + /// This function assumes the dateTime is in UTC and AdjustmentRule is in a different time zone. + /// + private static bool GetIsDaylightSavingsFromUtc(DateTime time, int year, TimeSpan utc, AdjustmentRule rule, int? ruleIndex, out bool isAmbiguousLocalDst, TimeZoneInfo zone) + { + isAmbiguousLocalDst = false; + + if (rule == null) + { + return false; + } + + // Get the daylight changes for the year of the specified time. + DaylightTimeStruct daylightTime = zone.GetDaylightTime(year, rule, ruleIndex); + + // The start and end times represent the range of universal times that are in DST for that year. + // Within that there is an ambiguous hour, usually right at the end, but at the beginning in + // the unusual case of a negative daylight savings delta. + // We need to handle the case if the current rule has daylight saving end by the end of year. If so, we need to check if next year starts with daylight saving on + // and get the actual daylight saving end time. Here is example for such case: + // Converting the UTC datetime "12/31/2011 8:00:00 PM" to "(UTC+03:00) Moscow, St. Petersburg, Volgograd (RTZ 2)" zone. + // In 2011 the daylight saving will go through the end of the year. If we use the end of 2011 as the daylight saving end, + // that will fail the conversion because the UTC time +4 hours (3 hours for the zone UTC offset and 1 hour for daylight saving) will move us to the next year "1/1/2012 12:00 AM", + // checking against the end of 2011 will tell we are not in daylight saving which is wrong and the conversion will be off by one hour. + // Note we handle the similar case when rule year start with daylight saving and previous year end with daylight saving. + + bool ignoreYearAdjustment = false; + TimeSpan dstStartOffset = zone.GetDaylightSavingsStartOffsetFromUtc(utc, rule, ruleIndex); + DateTime startTime; + if (rule.IsStartDateMarkerForBeginningOfYear() && daylightTime.Start.Year > DateTime.MinValue.Year) + { + int? previousYearRuleIndex; + AdjustmentRule previousYearRule = zone.GetAdjustmentRuleForTime( + new DateTime(daylightTime.Start.Year - 1, 12, 31), + out previousYearRuleIndex); + if (previousYearRule != null && previousYearRule.IsEndDateMarkerForEndOfYear()) + { + DaylightTimeStruct previousDaylightTime = zone.GetDaylightTime( + daylightTime.Start.Year - 1, + previousYearRule, + previousYearRuleIndex); + startTime = previousDaylightTime.Start - utc - previousYearRule.BaseUtcOffsetDelta; + ignoreYearAdjustment = true; + } + else + { + startTime = new DateTime(daylightTime.Start.Year, 1, 1, 0, 0, 0) - dstStartOffset; + } + } + else + { + startTime = daylightTime.Start - dstStartOffset; + } + + TimeSpan dstEndOffset = zone.GetDaylightSavingsEndOffsetFromUtc(utc, rule); + DateTime endTime; + if (rule.IsEndDateMarkerForEndOfYear() && daylightTime.End.Year < DateTime.MaxValue.Year) + { + int? nextYearRuleIndex; + AdjustmentRule nextYearRule = zone.GetAdjustmentRuleForTime( + new DateTime(daylightTime.End.Year + 1, 1, 1), + out nextYearRuleIndex); + if (nextYearRule != null && nextYearRule.IsStartDateMarkerForBeginningOfYear()) + { + if (nextYearRule.IsEndDateMarkerForEndOfYear()) + { + // next year end with daylight saving on too + endTime = new DateTime(daylightTime.End.Year + 1, 12, 31) - utc - nextYearRule.BaseUtcOffsetDelta - nextYearRule.DaylightDelta; + } + else + { + DaylightTimeStruct nextdaylightTime = zone.GetDaylightTime( + daylightTime.End.Year + 1, + nextYearRule, + nextYearRuleIndex); + endTime = nextdaylightTime.End - utc - nextYearRule.BaseUtcOffsetDelta - nextYearRule.DaylightDelta; + } + ignoreYearAdjustment = true; + } + else + { + endTime = new DateTime(daylightTime.End.Year + 1, 1, 1, 0, 0, 0).AddTicks(-1) - dstEndOffset; + } + } + else + { + endTime = daylightTime.End - dstEndOffset; + } + + DateTime ambiguousStart; + DateTime ambiguousEnd; + if (daylightTime.Delta.Ticks > 0) + { + ambiguousStart = endTime - daylightTime.Delta; + ambiguousEnd = endTime; + } + else + { + ambiguousStart = startTime; + ambiguousEnd = startTime - daylightTime.Delta; + } + + bool isDst = CheckIsDst(startTime, time, endTime, ignoreYearAdjustment, rule); + + // See if the resulting local time becomes ambiguous. This must be captured here or the + // DateTime will not be able to round-trip back to UTC accurately. + if (isDst) + { + isAmbiguousLocalDst = (time >= ambiguousStart && time < ambiguousEnd); + + if (!isAmbiguousLocalDst && ambiguousStart.Year != ambiguousEnd.Year) + { + // there exists an extreme corner case where the start or end period is on a year boundary and + // because of this the comparison above might have been performed for a year-early or a year-later + // than it should have been. + DateTime ambiguousStartModified; + DateTime ambiguousEndModified; + try + { + ambiguousStartModified = ambiguousStart.AddYears(1); + ambiguousEndModified = ambiguousEnd.AddYears(1); + isAmbiguousLocalDst = (time >= ambiguousStart && time < ambiguousEnd); + } + catch (ArgumentOutOfRangeException) { } + + if (!isAmbiguousLocalDst) + { + try + { + ambiguousStartModified = ambiguousStart.AddYears(-1); + ambiguousEndModified = ambiguousEnd.AddYears(-1); + isAmbiguousLocalDst = (time >= ambiguousStart && time < ambiguousEnd); + } + catch (ArgumentOutOfRangeException) { } + } + } + } + + return isDst; + } + + private static bool CheckIsDst(DateTime startTime, DateTime time, DateTime endTime, bool ignoreYearAdjustment, AdjustmentRule rule) + { + // NoDaylightTransitions AdjustmentRules should never get their year adjusted since they adjust the offset for the + // entire time period - which may be for multiple years + if (!ignoreYearAdjustment && !rule.NoDaylightTransitions) + { + int startTimeYear = startTime.Year; + int endTimeYear = endTime.Year; + + if (startTimeYear != endTimeYear) + { + endTime = endTime.AddYears(startTimeYear - endTimeYear); + } + + int timeYear = time.Year; + + if (startTimeYear != timeYear) + { + time = time.AddYears(startTimeYear - timeYear); + } + } + + if (startTime > endTime) + { + // In southern hemisphere, the daylight saving time starts later in the year, and ends in the beginning of next year. + // Note, the summer in the southern hemisphere begins late in the year. + return (time < endTime || time >= startTime); + } + else if (rule.NoDaylightTransitions) + { + // In NoDaylightTransitions AdjustmentRules, the startTime is always before the endTime, + // and both the start and end times are inclusive + return time >= startTime && time <= endTime; + } + else + { + // In northern hemisphere, the daylight saving time starts in the middle of the year. + return time >= startTime && time < endTime; + } + } + + /// + /// Returns true when the dateTime falls into an ambiguous time range. + /// + /// For example, in Pacific Standard Time on Sunday, October 29, 2006 time jumps from + /// 2AM to 1AM. This means the timeline on Sunday proceeds as follows: + /// 12AM ... [1AM ... 1:59:59AM -> 1AM ... 1:59:59AM] 2AM ... 3AM ... + /// + /// In this example, any DateTime values that fall into the [1AM - 1:59:59AM] range + /// are ambiguous; as it is unclear if these times are in Daylight Saving Time. + /// + private static bool GetIsAmbiguousTime(DateTime time, AdjustmentRule rule, DaylightTimeStruct daylightTime) + { + bool isAmbiguous = false; + if (rule == null || rule.DaylightDelta == TimeSpan.Zero) + { + return isAmbiguous; + } + + DateTime startAmbiguousTime; + DateTime endAmbiguousTime; + + // if at DST start we transition forward in time then there is an ambiguous time range at the DST end + if (rule.DaylightDelta > TimeSpan.Zero) + { + if (rule.IsEndDateMarkerForEndOfYear()) + { // year end with daylight on so there is no ambiguous time + return false; + } + startAmbiguousTime = daylightTime.End; + endAmbiguousTime = daylightTime.End - rule.DaylightDelta; /* FUTURE: + rule.StandardDelta; */ + } + else + { + if (rule.IsStartDateMarkerForBeginningOfYear()) + { // year start with daylight on so there is no ambiguous time + return false; + } + startAmbiguousTime = daylightTime.Start; + endAmbiguousTime = daylightTime.Start + rule.DaylightDelta; /* FUTURE: - rule.StandardDelta; */ + } + + isAmbiguous = (time >= endAmbiguousTime && time < startAmbiguousTime); + + if (!isAmbiguous && startAmbiguousTime.Year != endAmbiguousTime.Year) + { + // there exists an extreme corner case where the start or end period is on a year boundary and + // because of this the comparison above might have been performed for a year-early or a year-later + // than it should have been. + DateTime startModifiedAmbiguousTime; + DateTime endModifiedAmbiguousTime; + try + { + startModifiedAmbiguousTime = startAmbiguousTime.AddYears(1); + endModifiedAmbiguousTime = endAmbiguousTime.AddYears(1); + isAmbiguous = (time >= endModifiedAmbiguousTime && time < startModifiedAmbiguousTime); + } + catch (ArgumentOutOfRangeException) { } + + if (!isAmbiguous) + { + try + { + startModifiedAmbiguousTime = startAmbiguousTime.AddYears(-1); + endModifiedAmbiguousTime = endAmbiguousTime.AddYears(-1); + isAmbiguous = (time >= endModifiedAmbiguousTime && time < startModifiedAmbiguousTime); + } + catch (ArgumentOutOfRangeException) { } + } + } + return isAmbiguous; + } + + /// + /// Helper function that checks if a given DateTime is in an invalid time ("time hole") + /// A "time hole" occurs at a DST transition point when time jumps forward; + /// For example, in Pacific Standard Time on Sunday, April 2, 2006 time jumps from + /// 1:59:59.9999999 to 3AM. The time range 2AM to 2:59:59.9999999AM is the "time hole". + /// A "time hole" is not limited to only occurring at the start of DST, and may occur at + /// the end of DST as well. + /// + private static bool GetIsInvalidTime(DateTime time, AdjustmentRule rule, DaylightTimeStruct daylightTime) + { + bool isInvalid = false; + if (rule == null || rule.DaylightDelta == TimeSpan.Zero) + { + return isInvalid; + } + + DateTime startInvalidTime; + DateTime endInvalidTime; + + // if at DST start we transition forward in time then there is an ambiguous time range at the DST end + if (rule.DaylightDelta < TimeSpan.Zero) + { + // if the year ends with daylight saving on then there cannot be any time-hole's in that year. + if (rule.IsEndDateMarkerForEndOfYear()) + return false; + + startInvalidTime = daylightTime.End; + endInvalidTime = daylightTime.End - rule.DaylightDelta; /* FUTURE: + rule.StandardDelta; */ + } + else + { + // if the year starts with daylight saving on then there cannot be any time-hole's in that year. + if (rule.IsStartDateMarkerForBeginningOfYear()) + return false; + + startInvalidTime = daylightTime.Start; + endInvalidTime = daylightTime.Start + rule.DaylightDelta; /* FUTURE: - rule.StandardDelta; */ + } + + isInvalid = (time >= startInvalidTime && time < endInvalidTime); + + if (!isInvalid && startInvalidTime.Year != endInvalidTime.Year) + { + // there exists an extreme corner case where the start or end period is on a year boundary and + // because of this the comparison above might have been performed for a year-early or a year-later + // than it should have been. + DateTime startModifiedInvalidTime; + DateTime endModifiedInvalidTime; + try + { + startModifiedInvalidTime = startInvalidTime.AddYears(1); + endModifiedInvalidTime = endInvalidTime.AddYears(1); + isInvalid = (time >= startModifiedInvalidTime && time < endModifiedInvalidTime); + } + catch (ArgumentOutOfRangeException) { } + + if (!isInvalid) + { + try + { + startModifiedInvalidTime = startInvalidTime.AddYears(-1); + endModifiedInvalidTime = endInvalidTime.AddYears(-1); + isInvalid = (time >= startModifiedInvalidTime && time < endModifiedInvalidTime); + } + catch (ArgumentOutOfRangeException) { } + } + } + return isInvalid; + } + + /// + /// Helper function that calculates the UTC offset for a dateTime in a timeZone. + /// This function assumes that the dateTime is already converted into the timeZone. + /// + private static TimeSpan GetUtcOffset(DateTime time, TimeZoneInfo zone, TimeZoneInfoOptions flags) + { + TimeSpan baseOffset = zone.BaseUtcOffset; + int? ruleIndex; + AdjustmentRule rule = zone.GetAdjustmentRuleForTime(time, out ruleIndex); + + if (rule != null) + { + baseOffset = baseOffset + rule.BaseUtcOffsetDelta; + if (rule.HasDaylightSaving) + { + DaylightTimeStruct daylightTime = zone.GetDaylightTime(time.Year, rule, ruleIndex); + bool isDaylightSavings = GetIsDaylightSavings(time, rule, daylightTime, flags); + baseOffset += (isDaylightSavings ? rule.DaylightDelta : TimeSpan.Zero /* FUTURE: rule.StandardDelta */); + } + } + + return baseOffset; + } + + /// + /// Helper function that calculates the UTC offset for a UTC-dateTime in a timeZone. + /// This function assumes that the dateTime is represented in UTC and has *not* already been converted into the timeZone. + /// + private static TimeSpan GetUtcOffsetFromUtc(DateTime time, TimeZoneInfo zone) + { + bool isDaylightSavings; + return GetUtcOffsetFromUtc(time, zone, out isDaylightSavings); + } + + /// + /// Helper function that calculates the UTC offset for a UTC-dateTime in a timeZone. + /// This function assumes that the dateTime is represented in UTC and has *not* already been converted into the timeZone. + /// + private static TimeSpan GetUtcOffsetFromUtc(DateTime time, TimeZoneInfo zone, out bool isDaylightSavings) + { + bool isAmbiguousLocalDst; + return GetUtcOffsetFromUtc(time, zone, out isDaylightSavings, out isAmbiguousLocalDst); + } + + /// + /// Helper function that calculates the UTC offset for a UTC-dateTime in a timeZone. + /// This function assumes that the dateTime is represented in UTC and has *not* already been converted into the timeZone. + /// + internal static TimeSpan GetUtcOffsetFromUtc(DateTime time, TimeZoneInfo zone, out bool isDaylightSavings, out bool isAmbiguousLocalDst) + { + isDaylightSavings = false; + isAmbiguousLocalDst = false; + TimeSpan baseOffset = zone.BaseUtcOffset; + int year; + int? ruleIndex; + AdjustmentRule rule; + + if (time > s_maxDateOnly) + { + rule = zone.GetAdjustmentRuleForTime(DateTime.MaxValue, out ruleIndex); + year = 9999; + } + else if (time < s_minDateOnly) + { + rule = zone.GetAdjustmentRuleForTime(DateTime.MinValue, out ruleIndex); + year = 1; + } + else + { + rule = zone.GetAdjustmentRuleForTime(time, dateTimeisUtc: true, ruleIndex: out ruleIndex); + Debug.Assert(rule == null || ruleIndex.HasValue, + "If GetAdjustmentRuleForTime returned an AdjustmentRule, ruleIndex should also be set."); + + // As we get the associated rule using the adjusted targetTime, we should use the adjusted year (targetTime.Year) too as after adding the baseOffset, + // sometimes the year value can change if the input datetime was very close to the beginning or the end of the year. Examples of such cases: + // Libya Standard Time when used with the date 2011-12-31T23:59:59.9999999Z + // "W. Australia Standard Time" used with date 2005-12-31T23:59:00.0000000Z + DateTime targetTime = time + baseOffset; + year = targetTime.Year; + } + + if (rule != null) + { + baseOffset = baseOffset + rule.BaseUtcOffsetDelta; + if (rule.HasDaylightSaving) + { + isDaylightSavings = GetIsDaylightSavingsFromUtc(time, year, zone._baseUtcOffset, rule, ruleIndex, out isAmbiguousLocalDst, zone); + baseOffset += (isDaylightSavings ? rule.DaylightDelta : TimeSpan.Zero /* FUTURE: rule.StandardDelta */); + } + } + + return baseOffset; + } + + /// + /// Helper function that converts a year and TransitionTime into a DateTime. + /// + internal static DateTime TransitionTimeToDateTime(int year, TransitionTime transitionTime) + { + DateTime value; + DateTime timeOfDay = transitionTime.TimeOfDay; + + if (transitionTime.IsFixedDateRule) + { + // create a DateTime from the passed in year and the properties on the transitionTime + + // if the day is out of range for the month then use the last day of the month + int day = DateTime.DaysInMonth(year, transitionTime.Month); + + value = new DateTime(year, transitionTime.Month, (day < transitionTime.Day) ? day : transitionTime.Day, + timeOfDay.Hour, timeOfDay.Minute, timeOfDay.Second, timeOfDay.Millisecond); + } + else + { + if (transitionTime.Week <= 4) + { + // + // Get the (transitionTime.Week)th Sunday. + // + value = new DateTime(year, transitionTime.Month, 1, + timeOfDay.Hour, timeOfDay.Minute, timeOfDay.Second, timeOfDay.Millisecond); + + int dayOfWeek = (int)value.DayOfWeek; + int delta = (int)transitionTime.DayOfWeek - dayOfWeek; + if (delta < 0) + { + delta += 7; + } + delta += 7 * (transitionTime.Week - 1); + + if (delta > 0) + { + value = value.AddDays(delta); + } + } + else + { + // + // If TransitionWeek is greater than 4, we will get the last week. + // + int daysInMonth = DateTime.DaysInMonth(year, transitionTime.Month); + value = new DateTime(year, transitionTime.Month, daysInMonth, + timeOfDay.Hour, timeOfDay.Minute, timeOfDay.Second, timeOfDay.Millisecond); + + // This is the day of week for the last day of the month. + int dayOfWeek = (int)value.DayOfWeek; + int delta = dayOfWeek - (int)transitionTime.DayOfWeek; + if (delta < 0) + { + delta += 7; + } + + if (delta > 0) + { + value = value.AddDays(-delta); + } + } + } + return value; + } + + /// + /// Helper function for retrieving a TimeZoneInfo object by . + /// + /// This function may return null. + /// + /// assumes cachedData lock is taken + /// + private static TimeZoneInfoResult TryGetTimeZone(string id, bool dstDisabled, out TimeZoneInfo value, out Exception e, CachedData cachedData, bool alwaysFallbackToLocalMachine = false) + { + Debug.Assert(Monitor.IsEntered(cachedData)); + + TimeZoneInfoResult result = TimeZoneInfoResult.Success; + e = null; + TimeZoneInfo match = null; + + // check the cache + if (cachedData._systemTimeZones != null) + { + if (cachedData._systemTimeZones.TryGetValue(id, out match)) + { + if (dstDisabled && match._supportsDaylightSavingTime) + { + // we found a cache hit but we want a time zone without DST and this one has DST data + value = CreateCustomTimeZone(match._id, match._baseUtcOffset, match._displayName, match._standardDisplayName); + } + else + { + value = new TimeZoneInfo(match._id, match._baseUtcOffset, match._displayName, match._standardDisplayName, + match._daylightDisplayName, match._adjustmentRules, disableDaylightSavingTime: false); + } + return result; + } + } + + // Fall back to reading from the local machine when the cache is not fully populated. + // On UNIX, there may be some tzfiles that aren't in the zones.tab file, and thus aren't returned from GetSystemTimeZones(). + // If a caller asks for one of these zones before calling GetSystemTimeZones(), the time zone is returned successfully. But if + // GetSystemTimeZones() is called first, FindSystemTimeZoneById will throw TimeZoneNotFoundException, which is inconsistent. + // To fix this, when 'alwaysFallbackToLocalMachine' is true, even if _allSystemTimeZonesRead is true, try reading the tzfile + // from disk, but don't add the time zone to the list returned from GetSystemTimeZones(). These time zones will only be + // available if asked for directly. + if (!cachedData._allSystemTimeZonesRead || alwaysFallbackToLocalMachine) + { + result = TryGetTimeZoneFromLocalMachine(id, dstDisabled, out value, out e, cachedData); + } + else + { + result = TimeZoneInfoResult.TimeZoneNotFoundException; + value = null; + } + + return result; + } + + private static TimeZoneInfoResult TryGetTimeZoneFromLocalMachine(string id, bool dstDisabled, out TimeZoneInfo value, out Exception e, CachedData cachedData) + { + TimeZoneInfoResult result; + TimeZoneInfo match; + + result = TryGetTimeZoneFromLocalMachine(id, out match, out e); + + if (result == TimeZoneInfoResult.Success) + { + if (cachedData._systemTimeZones == null) + cachedData._systemTimeZones = new Dictionary(StringComparer.OrdinalIgnoreCase); + + cachedData._systemTimeZones.Add(id, match); + + if (dstDisabled && match._supportsDaylightSavingTime) + { + // we found a cache hit but we want a time zone without DST and this one has DST data + value = CreateCustomTimeZone(match._id, match._baseUtcOffset, match._displayName, match._standardDisplayName); + } + else + { + value = new TimeZoneInfo(match._id, match._baseUtcOffset, match._displayName, match._standardDisplayName, + match._daylightDisplayName, match._adjustmentRules, disableDaylightSavingTime: false); + } + } + else + { + value = null; + } + + return result; + } + + /// + /// Helper function that validates the TimeSpan is within +/- 14.0 hours + /// + internal static bool UtcOffsetOutOfRange(TimeSpan offset) => + offset.TotalHours < -14.0 || offset.TotalHours > 14.0; + + /// + /// Helper function that performs all of the validation checks for the + /// factory methods and deserialization callback. + /// + private static void ValidateTimeZoneInfo(string id, TimeSpan baseUtcOffset, AdjustmentRule[] adjustmentRules, out bool adjustmentRulesSupportDst) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + + if (id.Length == 0) + { + throw new ArgumentException(SR.Format(SR.Argument_InvalidId, id), nameof(id)); + } + + if (UtcOffsetOutOfRange(baseUtcOffset)) + { + throw new ArgumentOutOfRangeException(nameof(baseUtcOffset), SR.ArgumentOutOfRange_UtcOffset); + } + + if (baseUtcOffset.Ticks % TimeSpan.TicksPerMinute != 0) + { + throw new ArgumentException(SR.Argument_TimeSpanHasSeconds, nameof(baseUtcOffset)); + } + + adjustmentRulesSupportDst = false; + + // + // "adjustmentRules" can either be null or a valid array of AdjustmentRule objects. + // A valid array is one that does not contain any null elements and all elements + // are sorted in chronological order + // + + if (adjustmentRules != null && adjustmentRules.Length != 0) + { + adjustmentRulesSupportDst = true; + AdjustmentRule prev = null; + AdjustmentRule current = null; + for (int i = 0; i < adjustmentRules.Length; i++) + { + prev = current; + current = adjustmentRules[i]; + + if (current == null) + { + throw new InvalidTimeZoneException(SR.Argument_AdjustmentRulesNoNulls); + } + + // FUTURE: check to see if this rule supports Daylight Saving Time + // adjustmentRulesSupportDst = adjustmentRulesSupportDst || current.SupportsDaylightSavingTime; + // FUTURE: test baseUtcOffset + current.StandardDelta + + if (UtcOffsetOutOfRange(baseUtcOffset + current.DaylightDelta)) + { + throw new InvalidTimeZoneException(SR.ArgumentOutOfRange_UtcOffsetAndDaylightDelta); + } + + if (prev != null && current.DateStart <= prev.DateEnd) + { + // verify the rules are in chronological order and the DateStart/DateEnd do not overlap + throw new InvalidTimeZoneException(SR.Argument_AdjustmentRulesOutOfOrder); + } + } + } + } + } +} diff --git a/external/corert/src/System.Private.CoreLib/shared/System/Version.cs b/external/corert/src/System.Private.CoreLib/shared/System/Version.cs index df16be2cd2..9e4cefcd6f 100644 --- a/external/corert/src/System.Private.CoreLib/shared/System/Version.cs +++ b/external/corert/src/System.Private.CoreLib/shared/System/Version.cs @@ -300,7 +300,7 @@ namespace System throw new ArgumentNullException(nameof(input)); } - return ParseVersion(input.AsReadOnlySpan(), throwOnFailure: true); + return ParseVersion(input.AsSpan(), throwOnFailure: true); } public static Version Parse(ReadOnlySpan input) => @@ -314,7 +314,7 @@ namespace System return false; } - return (result = ParseVersion(input.AsReadOnlySpan(), throwOnFailure: false)) != null; + return (result = ParseVersion(input.AsSpan(), throwOnFailure: false)) != null; } public static bool TryParse(ReadOnlySpan input, out Version result) => diff --git a/external/corert/src/System.Private.CoreLib/src/Internal/DeveloperExperience/DeveloperExperience.cs b/external/corert/src/System.Private.CoreLib/src/Internal/DeveloperExperience/DeveloperExperience.cs index 0c5c05d9e2..791f0ed353 100644 --- a/external/corert/src/System.Private.CoreLib/src/Internal/DeveloperExperience/DeveloperExperience.cs +++ b/external/corert/src/System.Private.CoreLib/src/Internal/DeveloperExperience/DeveloperExperience.cs @@ -13,6 +13,7 @@ using Internal.Runtime.Augments; namespace Internal.DeveloperExperience { + [System.Runtime.CompilerServices.ReflectionBlocked] public class DeveloperExperience { public virtual void WriteLine(String s) diff --git a/external/corert/src/System.Private.CoreLib/src/Internal/Reflection/Augments/ReflectionAugments.cs b/external/corert/src/System.Private.CoreLib/src/Internal/Reflection/Augments/ReflectionAugments.cs index ebf0d31fb3..6eb006f35f 100644 --- a/external/corert/src/System.Private.CoreLib/src/Internal/Reflection/Augments/ReflectionAugments.cs +++ b/external/corert/src/System.Private.CoreLib/src/Internal/Reflection/Augments/ReflectionAugments.cs @@ -28,6 +28,7 @@ using EnumInfo = Internal.Runtime.Augments.EnumInfo; namespace Internal.Reflection.Augments { + [System.Runtime.CompilerServices.ReflectionBlocked] public static class ReflectionAugments { // @@ -123,6 +124,7 @@ namespace Internal.Reflection.Augments // This class is implemented by Internal.Reflection.Core.dll and provides the actual implementation // of Type.GetTypeInfo() and (on Project N) (Assembly.Load()). // + [System.Runtime.CompilerServices.ReflectionBlocked] public abstract class ReflectionCoreCallbacks { public abstract Assembly Load(AssemblyName refName, bool throwOnFileNotFound); diff --git a/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/AsyncCausalityTracer.cs b/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/AsyncCausalityTracer.cs index bcd9583b06..5be109184b 100644 --- a/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/AsyncCausalityTracer.cs +++ b/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/AsyncCausalityTracer.cs @@ -6,7 +6,10 @@ using System; namespace Internal.Runtime.Augments { - public enum CausalityRelation +#if !MONO + public +#endif + enum CausalityRelation { AssignDelegate = 0, Join = 1, @@ -15,21 +18,30 @@ namespace Internal.Runtime.Augments Error = 4, } - public enum CausalitySource +#if !MONO + public +#endif + enum CausalitySource { Application = 0, Library = 1, System = 2, } - public enum CausalityTraceLevel +#if !MONO + public +#endif + enum CausalityTraceLevel { Required = 0, Important = 1, Verbose = 2, } - public enum AsyncStatus +#if !MONO + public +#endif + enum AsyncStatus { Started = 0, Completed = 1, @@ -37,7 +49,10 @@ namespace Internal.Runtime.Augments Error = 3, } - public enum CausalitySynchronousWork +#if !MONO + public +#endif + enum CausalitySynchronousWork { CompletionNotification = 0, ProgressNotification = 1, diff --git a/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/EnumInfo.cs b/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/EnumInfo.cs index ff1d196359..7363a9b09b 100644 --- a/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/EnumInfo.cs +++ b/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/EnumInfo.cs @@ -11,6 +11,7 @@ using System.Runtime.CompilerServices; namespace Internal.Runtime.Augments { + [ReflectionBlocked] public sealed class EnumInfo { public EnumInfo(Type enumType) diff --git a/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/EnvironmentAugments.Windows.cs b/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/EnvironmentAugments.Windows.cs index 71b5063fee..adfe174599 100644 --- a/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/EnvironmentAugments.Windows.cs +++ b/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/EnvironmentAugments.Windows.cs @@ -60,6 +60,9 @@ namespace Internal.Runtime.Augments // The error message from Win32 is "The filename or extension is too long", // which is not accurate. throw new ArgumentException(SR.Argument_LongEnvVarValue); + case Interop.Errors.ERROR_NOT_ENOUGH_MEMORY: + case Interop.Errors.ERROR_NO_SYSTEM_RESOURCES: + throw new OutOfMemoryException(Interop.Kernel32.GetMessage(errorCode)); default: throw new ArgumentException(Interop.Kernel32.GetMessage(errorCode)); } diff --git a/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/EnvironmentAugments.cs b/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/EnvironmentAugments.cs index 02c6717a15..eff2b98929 100644 --- a/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/EnvironmentAugments.cs +++ b/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/EnvironmentAugments.cs @@ -55,8 +55,6 @@ namespace Internal.Runtime.Augments private static void ValidateVariableAndValue(string variable, ref string value) { - const int MaxEnvVariableValueLength = 32767; - if (variable == null) throw new ArgumentNullException(nameof(variable)); @@ -66,9 +64,6 @@ namespace Internal.Runtime.Augments if (variable[0] == '\0') throw new ArgumentException(SR.Argument_StringFirstCharIsZero, nameof(variable)); - if (variable.Length >= MaxEnvVariableValueLength) - throw new ArgumentException(SR.Argument_LongEnvVarValue, nameof(variable)); - if (variable.IndexOf('=') != -1) throw new ArgumentException(SR.Argument_IllegalEnvVarName, nameof(variable)); @@ -77,10 +72,6 @@ namespace Internal.Runtime.Augments // Explicitly null out value if it's empty value = null; } - else if (value.Length >= MaxEnvVariableValueLength) - { - throw new ArgumentException(SR.Argument_LongEnvVarValue, nameof(value)); - } } public static IEnumerable> EnumerateEnvironmentVariables(EnvironmentVariableTarget target) diff --git a/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/InteropCallbacks.cs b/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/InteropCallbacks.cs index 7424ebcc5c..fb982fec84 100644 --- a/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/InteropCallbacks.cs +++ b/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/InteropCallbacks.cs @@ -9,9 +9,12 @@ using System.Runtime.InteropServices; namespace Internal.Runtime.Augments { [CLSCompliant(false)] + [System.Runtime.CompilerServices.ReflectionBlocked] public abstract class InteropCallbacks { - public abstract bool TryGetMarshallerDataForDelegate(RuntimeTypeHandle delegateTypeHandle, out McgPInvokeDelegateData delegateData); + public abstract IntPtr GetForwardDelegateCreationStub(RuntimeTypeHandle delegateTypeHandle); + + public abstract IntPtr GetDelegateMarshallingStub(RuntimeTypeHandle delegateTypeHandle, bool openStaticDelegate); public abstract bool TryGetStructUnmarshalStub(RuntimeTypeHandle structureTypeHandle, out IntPtr unmarshalStub); diff --git a/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/ReflectionExecutionDomainCallbacks.cs b/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/ReflectionExecutionDomainCallbacks.cs index cf6b61bfe7..c37c0d064d 100644 --- a/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/ReflectionExecutionDomainCallbacks.cs +++ b/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/ReflectionExecutionDomainCallbacks.cs @@ -23,6 +23,7 @@ using System.Reflection; namespace Internal.Runtime.Augments { [CLSCompliant(false)] + [System.Runtime.CompilerServices.ReflectionBlocked] public abstract class ReflectionExecutionDomainCallbacks { // Api's that are exposed in System.Runtime but are really reflection apis. diff --git a/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs b/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs index c8b3b83a15..0213e88210 100644 --- a/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs +++ b/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs @@ -35,6 +35,7 @@ using Volatile = System.Threading.Volatile; namespace Internal.Runtime.Augments { + [ReflectionBlocked] public static class RuntimeAugments { /// @@ -1074,7 +1075,7 @@ namespace Internal.Runtime.Augments public static bool FileExists(string path) { - return InternalFile.Exists(path); + return Internal.IO.File.Exists(path); } public static string GetLastResortString(RuntimeTypeHandle typeHandle) @@ -1082,16 +1083,6 @@ namespace Internal.Runtime.Augments return typeHandle.LastResortToString; } - public static void RhpSetHighLevelDebugFuncEvalHelper(IntPtr highLevelDebugFuncEvalHelper) - { - RuntimeImports.RhpSetHighLevelDebugFuncEvalHelper(highLevelDebugFuncEvalHelper); - } - - public static void RhpSetHighLevelDebugFuncEvalAbortHelper(IntPtr highLevelDebugFuncEvalAbortHelper) - { - RuntimeImports.RhpSetHighLevelDebugFuncEvalAbortHelper(highLevelDebugFuncEvalAbortHelper); - } - public static void RhpSendCustomEventToDebugger(IntPtr payload, int length) { RuntimeImports.RhpSendCustomEventToDebugger(payload, length); diff --git a/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/StackTraceMetadataCallbacks.cs b/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/StackTraceMetadataCallbacks.cs index 000b207ce0..ca813e6cd2 100644 --- a/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/StackTraceMetadataCallbacks.cs +++ b/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/StackTraceMetadataCallbacks.cs @@ -15,6 +15,7 @@ namespace Internal.Runtime.Augments /// Internal.Runtime.Augments.RuntimeAugments.InitializeStackTraceMetadataSupport(StackTraceMetadataCallbacks callbacks); /// /// + [System.Runtime.CompilerServices.ReflectionBlocked] [CLSCompliant(false)] public abstract class StackTraceMetadataCallbacks { diff --git a/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/TaskTraceCallbacks.cs b/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/TaskTraceCallbacks.cs index 6705cf9b01..17804306e6 100644 --- a/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/TaskTraceCallbacks.cs +++ b/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/TaskTraceCallbacks.cs @@ -12,7 +12,10 @@ namespace Internal.Runtime.Augments /// assembly. /// Implemented in System.Private.Threading. /// - public abstract class TaskTraceCallbacks +#if !MONO + public +#endif + abstract class TaskTraceCallbacks { public abstract bool Enabled { get; } diff --git a/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/TypeLoaderCallbacks.cs b/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/TypeLoaderCallbacks.cs index b1b216906e..241dae8545 100644 --- a/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/TypeLoaderCallbacks.cs +++ b/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/TypeLoaderCallbacks.cs @@ -11,6 +11,7 @@ using Internal.Runtime.CompilerServices; namespace Internal.Runtime.Augments { [CLSCompliant(false)] + [System.Runtime.CompilerServices.ReflectionBlocked] public abstract class TypeLoaderCallbacks { public abstract bool TryGetConstructedGenericTypeForComponents(RuntimeTypeHandle genericTypeDefinitionHandle, RuntimeTypeHandle[] genericTypeArgumentHandles, out RuntimeTypeHandle runtimeTypeHandle); diff --git a/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/WinRTInterop.cs b/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/WinRTInterop.cs index 6d999fb6f0..7d3da97a2c 100644 --- a/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/WinRTInterop.cs +++ b/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/WinRTInterop.cs @@ -3,7 +3,7 @@ // See the LICENSE file in the project root for more information. // -// System.Private.CoreLib cannot directly interop with WinRT because the interop DLL depends on System.Private.CoreLib which causes circular dependancy. +// System.Private.CoreLib cannot directly interop with WinRT because the interop DLL depends on System.Private.CoreLib which causes circular dependency. // To enable System.Private.CoreLib to call WinRT, we do have another assembly System.Private.WinRTInterop.CoreLib.dll which does the interop with WinRT // and to allow System.Private.CoreLib to call System.Private.WinRTInterop.CoreLib we do the following trick // o RmtGen tool will inject code WinRT.Initialize() to the app before the app Main method while building it diff --git a/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/InteropHelpers.cs b/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/InteropHelpers.cs index 90a4c51569..ad79c2510b 100644 --- a/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/InteropHelpers.cs +++ b/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/InteropHelpers.cs @@ -339,20 +339,15 @@ namespace Internal.Runtime.CompilerHelpers { PInvokeMarshal.CoTaskMemFree((IntPtr)p); } - /// - /// Returns the stub to the pinvoke marshalling stub - /// - public static IntPtr GetStubForPInvokeDelegate(Delegate del) + + public static IntPtr GetFunctionPointerForDelegate(Delegate del) { - return PInvokeMarshal.GetStubForPInvokeDelegate(del); + return PInvokeMarshal.GetFunctionPointerForDelegate(del); } - /// - /// Retrieve the corresponding P/invoke instance from the stub - /// - public static Delegate GetPInvokeDelegateForStub(IntPtr pStub, RuntimeTypeHandle delegateType) + public static Delegate GetDelegateForFunctionPointer(IntPtr ptr, RuntimeTypeHandle delegateType) { - return PInvokeMarshal.GetPInvokeDelegateForStub(pStub, delegateType); + return PInvokeMarshal.GetDelegateForFunctionPointer(ptr, delegateType); } /// diff --git a/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/FunctionPointerOps.cs b/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/FunctionPointerOps.cs index 8a1bd9426d..81d8a5b4c5 100644 --- a/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/FunctionPointerOps.cs +++ b/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/FunctionPointerOps.cs @@ -9,6 +9,7 @@ using Internal.Runtime.Augments; namespace Internal.Runtime.CompilerServices { + [System.Runtime.CompilerServices.ReflectionBlocked] public static class FunctionPointerOps { private struct GenericMethodDescriptorInfo : IEquatable diff --git a/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/GenericMethodDescriptor.cs b/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/GenericMethodDescriptor.cs index d0daffe268..b9bcd26d4a 100644 --- a/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/GenericMethodDescriptor.cs +++ b/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/GenericMethodDescriptor.cs @@ -6,6 +6,7 @@ using System; namespace Internal.Runtime.CompilerServices { + [System.Runtime.CompilerServices.ReflectionBlocked] public unsafe struct GenericMethodDescriptor { internal IntPtr _MethodFunctionPointer; diff --git a/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/OpenMethodResolver.cs b/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/OpenMethodResolver.cs index 917702235f..d207d7ea2c 100644 --- a/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/OpenMethodResolver.cs +++ b/external/corert/src/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/OpenMethodResolver.cs @@ -20,6 +20,7 @@ namespace Internal.Runtime.CompilerServices // so that repeated allocation of the same resolver will not leak. // 3) Use the ResolveMethod function to do the virtual lookup. This function takes advantage of // a lockless cache so the resolution is very fast for repeated lookups. + [ReflectionBlocked] public struct OpenMethodResolver : IEquatable { public const short DispatchResolve = 0; @@ -199,7 +200,7 @@ namespace Internal.Runtime.CompilerServices public override int GetHashCode() { - return CalcHashCode(_resolveType, _handle, _methodHandleOrSlotOrCodePointer.GetHashCode(), _declaringType.GetHashCode()); + return CalcHashCode(_resolveType, _handle, _methodHandleOrSlotOrCodePointer.GetHashCode(), _declaringType.IsNull ? 0 : _declaringType.GetHashCode()); } public bool Equals(OpenMethodResolver other) diff --git a/external/corert/src/System.Private.CoreLib/src/Internal/Threading/Tasks/Tracing/TaskTrace.cs b/external/corert/src/System.Private.CoreLib/src/Internal/Threading/Tasks/Tracing/TaskTrace.cs index 45c0de76e5..842b77d119 100644 --- a/external/corert/src/System.Private.CoreLib/src/Internal/Threading/Tasks/Tracing/TaskTrace.cs +++ b/external/corert/src/System.Private.CoreLib/src/Internal/Threading/Tasks/Tracing/TaskTrace.cs @@ -11,7 +11,10 @@ namespace Internal.Threading.Tasks.Tracing /// Calls are forwarded to an instance of , if one has been /// provided. /// - public static class TaskTrace +#if !MONO + public +#endif + static class TaskTrace { private static TaskTraceCallbacks s_callbacks; diff --git a/external/corert/src/System.Private.CoreLib/src/Interop/Interop.manual.cs b/external/corert/src/System.Private.CoreLib/src/Interop/Interop.manual.cs index a6c2be7be7..c1785e5d3b 100644 --- a/external/corert/src/System.Private.CoreLib/src/Interop/Interop.manual.cs +++ b/external/corert/src/System.Private.CoreLib/src/Interop/Interop.manual.cs @@ -24,7 +24,6 @@ internal partial class Interop CreateSuspended = 0x4u, WaitAbandoned0 = 0x80u, WaitTimeout = 0x102u, - MaxPath = 0x104u, StackSizeParamIsAReservation = 0x10000u, Synchronize = 0x100000u, MaximumAllowed = 0x02000000u, diff --git a/external/corert/src/System.Private.CoreLib/src/MembersMustExist.AnalyzerData b/external/corert/src/System.Private.CoreLib/src/MembersMustExist.AnalyzerData index 1ac5206dd0..840e4bba11 100644 --- a/external/corert/src/System.Private.CoreLib/src/MembersMustExist.AnalyzerData +++ b/external/corert/src/System.Private.CoreLib/src/MembersMustExist.AnalyzerData @@ -72,7 +72,7 @@ internal static extern bool System.Runtime.RuntimeImports.AreTypesAssignable(Sys internal static extern bool System.Runtime.RuntimeImports.AreTypesEquivalent(System.EETypePtr pType1, System.EETypePtr pType2) internal static extern double System.Runtime.RuntimeImports.asin(double x) internal static extern double System.Runtime.RuntimeImports.atan(double x) -internal static extern double System.Runtime.RuntimeImports.atan2(double x, double y) +internal static extern double System.Runtime.RuntimeImports.atan2(double y, double x) internal static extern double System.Runtime.RuntimeImports.ceil(double x) internal static extern double System.Runtime.RuntimeImports.cos(double x) internal static extern double System.Runtime.RuntimeImports.cosh(double x) @@ -219,7 +219,7 @@ private void* System.IntPtr._value private static volatile System.Collections.Generic.ArraySortHelper System.Collections.Generic.ArraySortHelper.s_defaultArraySortHelper private static volatile System.Globalization.CultureInfo System.Globalization.CultureInfo.s_DefaultThreadCurrentCulture private static volatile System.Globalization.CultureInfo System.Globalization.CultureInfo.s_DefaultThreadCurrentUICulture -private static volatile System.Globalization.CultureInfo System.Globalization.CultureInfo.s_InvariantCultureInfo +private static readonly System.Globalization.CultureInfo System.Globalization.CultureInfo.s_InvariantCultureInfo private System.Threading.Tasks.Task System.Runtime.CompilerServices.AsyncVoidMethodBuilder.m_task private System.Threading.Tasks.Task System.Runtime.CompilerServices.AsyncTaskMethodBuilder.m_task private System.Threading.Tasks.Task System.Runtime.CompilerServices.AsyncTaskMethodBuilder.m_task diff --git a/external/corert/src/System.Private.CoreLib/src/Resources/Strings.resx.REMOVED.git-id b/external/corert/src/System.Private.CoreLib/src/Resources/Strings.resx.REMOVED.git-id index 4b508a3bdf..0fb663f8d8 100644 --- a/external/corert/src/System.Private.CoreLib/src/Resources/Strings.resx.REMOVED.git-id +++ b/external/corert/src/System.Private.CoreLib/src/Resources/Strings.resx.REMOVED.git-id @@ -1 +1 @@ -24977e34b093bb0384adecc5b062042d2bf831ea \ No newline at end of file +2eedd405ce53c21b93239ee9ad64d45bc60796c6 \ No newline at end of file diff --git a/external/corert/src/System.Private.CoreLib/src/System.Private.CoreLib.csproj b/external/corert/src/System.Private.CoreLib/src/System.Private.CoreLib.csproj index 847dd80f1b..9f041c4627 100644 --- a/external/corert/src/System.Private.CoreLib/src/System.Private.CoreLib.csproj +++ b/external/corert/src/System.Private.CoreLib/src/System.Private.CoreLib.csproj @@ -191,7 +191,6 @@ - @@ -203,9 +202,6 @@ - - - @@ -214,6 +210,7 @@ + @@ -225,7 +222,6 @@ - @@ -257,7 +253,6 @@ - @@ -268,6 +263,7 @@ + @@ -277,8 +273,8 @@ + - @@ -347,7 +343,6 @@ - @@ -421,10 +416,8 @@ - - @@ -469,9 +462,6 @@ Interop\Windows\kernel32\Interop.VirtualAlloc.cs - - Interop\Windows\mincore\Interop.MUI.cs - Interop\Windows\mincore\Interop.DateTime.cs @@ -489,6 +479,7 @@ Interop\Windows\mincore\Interop.CommandLine.cs + Interop\Windows\mincore\Interop.GetTickCount64.cs @@ -527,11 +518,28 @@ Interop\Windows\mincore\Interop.ThreadPoolIO.cs + + Interop\Windows\mincore\Interop.TimeZone.cs + + + Interop\Windows\Interop.Libraries.cs + + + Interop\Windows\mincore\Interop.GetLastError.cs + + + Interop\Windows\mincore\Interop.GetSystemDirectory.cs + + + Interop\Windows\mincore\Interop.CoCreateGuid.cs + + + Interop\Windows\mincore\Interop.QueryUnbiasedInterruptTime.cs + - @@ -546,30 +554,6 @@ - - - - Interop\Windows\Interop.Libraries.cs - - - Interop\Windows\mincore\Interop.GetLastError.cs - - - Interop\Windows\mincore\Interop.GetSystemDirectory.cs - - - Interop\Windows\mincore\Interop.TimeZone.cs - - - Interop\Windows\mincore\Interop.TimeZone.Win32.cs - - - Interop\Windows\mincore\Interop.CoCreateGuid.cs - - - Interop\Windows\mincore\Interop.QueryUnbiasedInterruptTime.cs - - @@ -589,7 +573,6 @@ - @@ -695,9 +678,6 @@ System\Runtime\InteropServices\McgGeneratedNativeCallCodeAttribute.cs - - System\Runtime\InteropServices\McgPInvokeData.cs - System\NotImplemented.cs @@ -784,7 +764,7 @@ - + diff --git a/external/corert/src/System.Private.CoreLib/src/System/AppContext.Windows.cs b/external/corert/src/System.Private.CoreLib/src/System/AppContext.Windows.cs index 7d535c5de7..a53e848138 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/AppContext.Windows.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/AppContext.Windows.cs @@ -19,7 +19,7 @@ namespace System /// private static string GetBaseDirectoryCore() { - StringBuilder buffer = new StringBuilder(Interop.mincore.MAX_PATH); + StringBuilder buffer = new StringBuilder(Interop.Kernel32.MAX_PATH); while (true) { int size = Interop.mincore.GetModuleFileName(IntPtr.Zero, buffer, buffer.Capacity); diff --git a/external/corert/src/System.Private.CoreLib/src/System/Array.CoreRT.cs b/external/corert/src/System.Private.CoreLib/src/System/Array.CoreRT.cs index 9ae235f14b..80c4d2bbf0 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Array.CoreRT.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Array.CoreRT.cs @@ -942,7 +942,7 @@ namespace System { public ComparerAsComparerT(IComparer comparer) { - _comparer = (comparer == null) ? LowLevelComparer.Default : comparer; + _comparer = (comparer == null) ? Comparer.Default : comparer; } public int Compare(Object x, Object y) diff --git a/external/corert/src/System.Private.CoreLib/src/System/Array.cs b/external/corert/src/System.Private.CoreLib/src/System/Array.cs index 184964df19..2822401ff6 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Array.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Array.cs @@ -466,7 +466,7 @@ namespace System if (array.Rank != 1) throw new RankException(SR.Rank_MultiDimNotSupported); - if (comparer == null) comparer = LowLevelComparer.Default; + if (comparer == null) comparer = Comparer.Default; int lo = index; int hi = index + length - 1; diff --git a/external/corert/src/System.Private.CoreLib/src/System/Buffer.cs b/external/corert/src/System.Private.CoreLib/src/System/Buffer.cs index 5e31e69fdd..b8c840e421 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Buffer.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Buffer.cs @@ -15,8 +15,10 @@ using System.Runtime.CompilerServices; using Internal.Runtime.CompilerServices; #if BIT64 +using nint = System.Int64; using nuint = System.UInt64; #else +using nint = System.Int32; using nuint = System.UInt32; #endif @@ -434,6 +436,248 @@ namespace System _Memmove(dest, src, len); } + // This method has different signature for x64 and other platforms and is done for performance reasons. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void Memmove(ref T destination, ref T source, nuint elementCount) + { + if (!RuntimeHelpers.IsReferenceOrContainsReferences()) + { + // Blittable memmove +#if PROJECTN + unsafe + { + fixed (byte* pDestination = &Unsafe.As(ref destination), pSource = &Unsafe.As(ref source)) + Memmove(pDestination, pSource, elementCount * (nuint)Unsafe.SizeOf()); + } +#else + Memmove( + new ByReference(ref Unsafe.As(ref destination)), + new ByReference(ref Unsafe.As(ref source)), + elementCount * (nuint)Unsafe.SizeOf()); +#endif + } + else + { + // Non-blittable memmove + + // Try to avoid calling RhBulkMoveWithWriteBarrier if we can get away + // with a no-op. + if (!Unsafe.AreSame(ref destination, ref source) && elementCount != 0) + { + RuntimeImports.RhBulkMoveWithWriteBarrier( + ref Unsafe.As(ref destination), + ref Unsafe.As(ref source), + elementCount * (nuint)Unsafe.SizeOf()); + } + } + } + +#if !PROJECTN + // This method has different signature for x64 and other platforms and is done for performance reasons. + private static void Memmove(ByReference dest, ByReference src, nuint len) + { +#if AMD64 || (BIT32 && !ARM) + const nuint CopyThreshold = 2048; +#elif ARM64 +#if PLATFORM_WINDOWS + // Determined optimal value for Windows. + // https://github.com/dotnet/coreclr/issues/13843 + const nuint CopyThreshold = UInt64.MaxValue; +#else // PLATFORM_WINDOWS + // Managed code is currently faster than glibc unoptimized memmove + // TODO-ARM64-UNIX-OPT revisit when glibc optimized memmove is in Linux distros + // https://github.com/dotnet/coreclr/issues/13844 + const nuint CopyThreshold = UInt64.MaxValue; +#endif // PLATFORM_WINDOWS +#else + const nuint CopyThreshold = 512; +#endif // AMD64 || (BIT32 && !ARM) + + // P/Invoke into the native version when the buffers are overlapping. + + if (((nuint)Unsafe.ByteOffset(ref src.Value, ref dest.Value) < len) || ((nuint)Unsafe.ByteOffset(ref dest.Value, ref src.Value) < len)) + { + goto BuffersOverlap; + } + + // Use "(IntPtr)(nint)len" to avoid overflow checking on the explicit cast to IntPtr + + ref byte srcEnd = ref Unsafe.Add(ref src.Value, (IntPtr)(nint)len); + ref byte destEnd = ref Unsafe.Add(ref dest.Value, (IntPtr)(nint)len); + + if (len <= 16) + goto MCPY02; + if (len > 64) + goto MCPY05; + +MCPY00: +// Copy bytes which are multiples of 16 and leave the remainder for MCPY01 to handle. + Debug.Assert(len > 16 && len <= 64); +#if HAS_CUSTOM_BLOCKS + Unsafe.As(ref dest.Value) = Unsafe.As(ref src.Value); // [0,16] +#elif BIT64 + Unsafe.As(ref dest.Value) = Unsafe.As(ref src.Value); + Unsafe.As(ref Unsafe.Add(ref dest.Value, 8)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 8)); // [0,16] +#else + Unsafe.As(ref dest.Value) = Unsafe.As(ref src.Value); + Unsafe.As(ref Unsafe.Add(ref dest.Value, 4)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 4)); + Unsafe.As(ref Unsafe.Add(ref dest.Value, 8)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 8)); + Unsafe.As(ref Unsafe.Add(ref dest.Value, 12)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 12)); // [0,16] +#endif + if (len <= 32) + goto MCPY01; +#if HAS_CUSTOM_BLOCKS + Unsafe.As(ref Unsafe.Add(ref dest.Value, 16)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 16)); // [0,32] +#elif BIT64 + Unsafe.As(ref Unsafe.Add(ref dest.Value, 16)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 16)); + Unsafe.As(ref Unsafe.Add(ref dest.Value, 24)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 24)); // [0,32] +#else + Unsafe.As(ref Unsafe.Add(ref dest.Value, 16)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 16)); + Unsafe.As(ref Unsafe.Add(ref dest.Value, 20)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 20)); + Unsafe.As(ref Unsafe.Add(ref dest.Value, 24)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 24)); + Unsafe.As(ref Unsafe.Add(ref dest.Value, 28)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 28)); // [0,32] +#endif + if (len <= 48) + goto MCPY01; +#if HAS_CUSTOM_BLOCKS + Unsafe.As(ref Unsafe.Add(ref dest.Value, 32)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 32)); // [0,48] +#elif BIT64 + Unsafe.As(ref Unsafe.Add(ref dest.Value, 32)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 32)); + Unsafe.As(ref Unsafe.Add(ref dest.Value, 40)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 40)); // [0,48] +#else + Unsafe.As(ref Unsafe.Add(ref dest.Value, 32)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 32)); + Unsafe.As(ref Unsafe.Add(ref dest.Value, 36)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 36)); + Unsafe.As(ref Unsafe.Add(ref dest.Value, 40)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 40)); + Unsafe.As(ref Unsafe.Add(ref dest.Value, 44)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 44)); // [0,48] +#endif + +MCPY01: +// Unconditionally copy the last 16 bytes using destEnd and srcEnd and return. + Debug.Assert(len > 16 && len <= 64); +#if HAS_CUSTOM_BLOCKS + Unsafe.As(ref Unsafe.Add(ref destEnd, -16)) = Unsafe.As(ref Unsafe.Add(ref srcEnd, -16)); +#elif BIT64 + Unsafe.As(ref Unsafe.Add(ref destEnd, -16)) = Unsafe.As(ref Unsafe.Add(ref srcEnd, -16)); + Unsafe.As(ref Unsafe.Add(ref destEnd, -8)) = Unsafe.As(ref Unsafe.Add(ref srcEnd, -8)); +#else + Unsafe.As(ref Unsafe.Add(ref destEnd, -16)) = Unsafe.As(ref Unsafe.Add(ref srcEnd, -16)); + Unsafe.As(ref Unsafe.Add(ref destEnd, -12)) = Unsafe.As(ref Unsafe.Add(ref srcEnd, -12)); + Unsafe.As(ref Unsafe.Add(ref destEnd, -8)) = Unsafe.As(ref Unsafe.Add(ref srcEnd, -8)); + Unsafe.As(ref Unsafe.Add(ref destEnd, -4)) = Unsafe.As(ref Unsafe.Add(ref srcEnd, -4)); +#endif + return; + +MCPY02: +// Copy the first 8 bytes and then unconditionally copy the last 8 bytes and return. + if ((len & 24) == 0) + goto MCPY03; + Debug.Assert(len >= 8 && len <= 16); +#if BIT64 + Unsafe.As(ref dest.Value) = Unsafe.As(ref src.Value); + Unsafe.As(ref Unsafe.Add(ref destEnd, -8)) = Unsafe.As(ref Unsafe.Add(ref srcEnd, -8)); +#else + Unsafe.As(ref dest.Value) = Unsafe.As(ref src.Value); + Unsafe.As(ref Unsafe.Add(ref dest.Value, 4)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 4)); + Unsafe.As(ref Unsafe.Add(ref destEnd, -8)) = Unsafe.As(ref Unsafe.Add(ref srcEnd, -8)); + Unsafe.As(ref Unsafe.Add(ref destEnd, -4)) = Unsafe.As(ref Unsafe.Add(ref srcEnd, -4)); +#endif + return; + +MCPY03: +// Copy the first 4 bytes and then unconditionally copy the last 4 bytes and return. + if ((len & 4) == 0) + goto MCPY04; + Debug.Assert(len >= 4 && len < 8); + Unsafe.As(ref dest.Value) = Unsafe.As(ref src.Value); + Unsafe.As(ref Unsafe.Add(ref destEnd, -4)) = Unsafe.As(ref Unsafe.Add(ref srcEnd, -4)); + return; + +MCPY04: +// Copy the first byte. For pending bytes, do an unconditionally copy of the last 2 bytes and return. + Debug.Assert(len < 4); + if (len == 0) + return; + dest.Value = src.Value; + if ((len & 2) == 0) + return; + Unsafe.As(ref Unsafe.Add(ref destEnd, -2)) = Unsafe.As(ref Unsafe.Add(ref srcEnd, -2)); + return; + +MCPY05: +// PInvoke to the native version when the copy length exceeds the threshold. + if (len > CopyThreshold) + { + goto PInvoke; + } + // Copy 64-bytes at a time until the remainder is less than 64. + // If remainder is greater than 16 bytes, then jump to MCPY00. Otherwise, unconditionally copy the last 16 bytes and return. + Debug.Assert(len > 64 && len <= CopyThreshold); + nuint n = len >> 6; + +MCPY06: +#if HAS_CUSTOM_BLOCKS + Unsafe.As(ref dest.Value) = Unsafe.As(ref src.Value); +#elif BIT64 + Unsafe.As(ref dest.Value) = Unsafe.As(ref src.Value); + Unsafe.As(ref Unsafe.Add(ref dest.Value, 8)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 8)); + Unsafe.As(ref Unsafe.Add(ref dest.Value, 16)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 16)); + Unsafe.As(ref Unsafe.Add(ref dest.Value, 24)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 24)); + Unsafe.As(ref Unsafe.Add(ref dest.Value, 32)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 32)); + Unsafe.As(ref Unsafe.Add(ref dest.Value, 40)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 40)); + Unsafe.As(ref Unsafe.Add(ref dest.Value, 48)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 48)); + Unsafe.As(ref Unsafe.Add(ref dest.Value, 56)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 56)); +#else + Unsafe.As(ref dest.Value) = Unsafe.As(ref src.Value); + Unsafe.As(ref Unsafe.Add(ref dest.Value, 4)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 4)); + Unsafe.As(ref Unsafe.Add(ref dest.Value, 8)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 8)); + Unsafe.As(ref Unsafe.Add(ref dest.Value, 12)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 12)); + Unsafe.As(ref Unsafe.Add(ref dest.Value, 16)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 16)); + Unsafe.As(ref Unsafe.Add(ref dest.Value, 20)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 20)); + Unsafe.As(ref Unsafe.Add(ref dest.Value, 24)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 24)); + Unsafe.As(ref Unsafe.Add(ref dest.Value, 28)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 28)); + Unsafe.As(ref Unsafe.Add(ref dest.Value, 32)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 32)); + Unsafe.As(ref Unsafe.Add(ref dest.Value, 36)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 36)); + Unsafe.As(ref Unsafe.Add(ref dest.Value, 40)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 40)); + Unsafe.As(ref Unsafe.Add(ref dest.Value, 44)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 44)); + Unsafe.As(ref Unsafe.Add(ref dest.Value, 48)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 48)); + Unsafe.As(ref Unsafe.Add(ref dest.Value, 52)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 52)); + Unsafe.As(ref Unsafe.Add(ref dest.Value, 56)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 56)); + Unsafe.As(ref Unsafe.Add(ref dest.Value, 60)) = Unsafe.As(ref Unsafe.Add(ref src.Value, 60)); +#endif + dest = new ByReference(ref Unsafe.Add(ref dest.Value, 64)); + src = new ByReference(ref Unsafe.Add(ref src.Value, 64)); + n--; + if (n != 0) + goto MCPY06; + + len %= 64; + if (len > 16) + goto MCPY00; +#if HAS_CUSTOM_BLOCKS + Unsafe.As(ref Unsafe.Add(ref destEnd, -16)) = Unsafe.As(ref Unsafe.Add(ref srcEnd, -16)); +#elif BIT64 + Unsafe.As(ref Unsafe.Add(ref destEnd, -16)) = Unsafe.As(ref Unsafe.Add(ref srcEnd, -16)); + Unsafe.As(ref Unsafe.Add(ref destEnd, -8)) = Unsafe.As(ref Unsafe.Add(ref srcEnd, -8)); +#else + Unsafe.As(ref Unsafe.Add(ref destEnd, -16)) = Unsafe.As(ref Unsafe.Add(ref srcEnd, -16)); + Unsafe.As(ref Unsafe.Add(ref destEnd, -12)) = Unsafe.As(ref Unsafe.Add(ref srcEnd, -12)); + Unsafe.As(ref Unsafe.Add(ref destEnd, -8)) = Unsafe.As(ref Unsafe.Add(ref srcEnd, -8)); + Unsafe.As(ref Unsafe.Add(ref destEnd, -4)) = Unsafe.As(ref Unsafe.Add(ref srcEnd, -4)); +#endif + return; + +BuffersOverlap: + // If the buffers overlap perfectly, there's no point to copying the data. + if (Unsafe.AreSame(ref dest.Value, ref src.Value)) + { + return; + } + +PInvoke: + _Memmove(ref dest.Value, ref src.Value, len); + } +#endif // !PROJECTN + // Non-inlinable wrapper around the QCall that avoids poluting the fast path // with P/Invoke prolog/epilog. [MethodImplAttribute(MethodImplOptions.NoInlining)] @@ -442,6 +686,16 @@ namespace System RuntimeImports.memmove(dest, src, len); } + // Non-inlinable wrapper around the QCall that avoids polluting the fast path + // with P/Invoke prolog/epilog. + [MethodImplAttribute(MethodImplOptions.NoInlining)] + private unsafe static void _Memmove(ref byte dest, ref byte src, nuint len) + { + fixed (byte* pDest = &dest) + fixed (byte* pSrc = &src) + RuntimeImports.memmove(pDest, pSrc, len); + } + #if HAS_CUSTOM_BLOCKS [StructLayout(LayoutKind.Explicit, Size = 16)] private struct Block16 { } diff --git a/external/corert/src/System.Private.CoreLib/src/System/Collections/LowLevelComparer.cs b/external/corert/src/System.Private.CoreLib/src/System/Collections/LowLevelComparer.cs deleted file mode 100644 index c6da9b58ff..0000000000 --- a/external/corert/src/System.Private.CoreLib/src/System/Collections/LowLevelComparer.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -// -// LowLevelComparer emulates the desktop type System.Collections.Comparer. -// - -using System; -using System.Globalization; -using System.Diagnostics; - -namespace System.Collections -{ - internal sealed class LowLevelComparer : IComparer - { - internal static readonly LowLevelComparer Default = new LowLevelComparer(); - - private LowLevelComparer() - { - } - - public int Compare(Object a, Object b) - { - if (a == b) return 0; - if (a == null) return -1; - if (b == null) return 1; - - IComparable ia = a as IComparable; - if (ia != null) - return ia.CompareTo(b); - - IComparable ib = b as IComparable; - if (ib != null) - return -ib.CompareTo(a); - - throw new ArgumentException(SR.Argument_ImplementIComparable); - } - } -} diff --git a/external/corert/src/System.Private.CoreLib/src/System/Decimal.DecCalc.cs.REMOVED.git-id b/external/corert/src/System.Private.CoreLib/src/System/Decimal.DecCalc.cs.REMOVED.git-id index ca121adcd2..5de76f9948 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Decimal.DecCalc.cs.REMOVED.git-id +++ b/external/corert/src/System.Private.CoreLib/src/System/Decimal.DecCalc.cs.REMOVED.git-id @@ -1 +1 @@ -5e67f3f61baf3054844a4218cb88abb58f3a4f20 \ No newline at end of file +05afe6b7e296d261b03eff87b6fb61e1db537d32 \ No newline at end of file diff --git a/external/corert/src/System.Private.CoreLib/src/System/Decimal.cs b/external/corert/src/System.Private.CoreLib/src/System/Decimal.cs index e9498a5294..244ef6223d 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Decimal.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Decimal.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Globalization; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; @@ -247,9 +248,7 @@ namespace System public static long ToOACurrency(Decimal value) { - long cy; - DecCalc.VarCyFromDec(ref value, out cy); - return cy; + return DecCalc.VarCyFromDec(ref value); } private static bool IsValid(uint flags) => (flags & ~(SignMask | ScaleMask)) == 0 && ((flags & ScaleMask) <= (28 << 16)); @@ -274,11 +273,6 @@ namespace System // equally valid, and all are numerically equivalent. // public Decimal(int[] bits) - { - SetBits(bits); - } - - private void SetBits(int[] bits) { if (bits == null) throw new ArgumentNullException(nameof(bits)); @@ -315,37 +309,25 @@ namespace System { // OnDeserialization is called after each instance of this class is deserialized. // This callback method performs decimal validation after being deserialized. - try - { - SetBits(GetBits(this)); - } - catch (ArgumentException e) - { - throw new SerializationException(SR.Overflow_Decimal, e); - } + if (!IsValid(uflags)) + throw new SerializationException(SR.Overflow_Decimal); } // Constructs a Decimal from its constituent parts. - private Decimal(int lo, int mid, int hi, int flags) + private Decimal(ulong ulomidLE, uint hi, uint flags) { - if ((flags & ~(SignMask | ScaleMask)) == 0 && (flags & ScaleMask) <= (28 << 16)) - { - this.lo = lo; - this.mid = mid; - this.hi = hi; - this.flags = flags; - return; - } - throw new ArgumentException(SR.Arg_DecBitCtor); + this.ulomidLE = ulomidLE; + this.uhi = hi; + this.uflags = flags; } // Returns the absolute value of the given Decimal. If d is // positive, the result is d. If d is negative, the result // is -d. // - internal static Decimal Abs(Decimal d) + internal static Decimal Abs(ref Decimal d) { - return new Decimal(d.lo, d.mid, d.hi, (int)(d.uflags & ~SignMask)); + return new Decimal(d.ulomidLE, d.uhi, d.uflags & ~SignMask); } @@ -362,7 +344,10 @@ namespace System // towards positive infinity. public static Decimal Ceiling(Decimal d) { - return (-(Decimal.Floor(-d))); + uint flags = d.uflags; + if ((flags & ScaleMask) != 0) + DecCalc.InternalRound(ref d, (byte)(flags >> ScaleShift), DecCalc.RoundingMode.Ceiling); + return d; } // Compares two Decimal values, returning an integer that indicates their @@ -457,7 +442,9 @@ namespace System // public static Decimal Floor(Decimal d) { - DecCalc.VarDecInt(ref d); + uint flags = d.uflags; + if ((flags & ScaleMask) != 0) + DecCalc.InternalRound(ref d, (byte)(flags >> ScaleShift), DecCalc.RoundingMode.Floor); return d; } @@ -544,7 +531,7 @@ namespace System return Number.ParseDecimal(s, style, NumberFormatInfo.GetInstance(provider)); } - public static Decimal Parse(ReadOnlySpan s, NumberStyles style, IFormatProvider provider) + public static Decimal Parse(ReadOnlySpan s, NumberStyles style = NumberStyles.Integer, IFormatProvider provider = null) { ValidateParseStyleFloatingPoint(style); return Number.ParseDecimal(s, style, NumberFormatInfo.GetInstance(provider)); @@ -624,16 +611,16 @@ namespace System // Returns the larger of two Decimal values. // - internal static Decimal Max(Decimal d1, Decimal d2) + internal static ref Decimal Max(ref Decimal d1, ref Decimal d2) { - return Compare(d1, d2) >= 0 ? d1 : d2; + return ref DecCalc.VarDecCmp(ref d1, ref d2) >= 0 ? ref d1 : ref d2; } // Returns the smaller of two Decimal values. // - internal static Decimal Min(Decimal d1, Decimal d2) + internal static ref Decimal Min(ref Decimal d1, ref Decimal d2) { - return Compare(d1, d2) < 0 ? d1 : d2; + return ref DecCalc.VarDecCmp(ref d1, ref d2) < 0 ? ref d1 : ref d2; } @@ -655,7 +642,7 @@ namespace System // public static Decimal Negate(Decimal d) { - return new Decimal(d.lo, d.mid, d.hi, (int)(d.uflags ^ SignMask)); + return new Decimal(d.ulomidLE, d.uhi, d.uflags ^ SignMask); } // Rounds a Decimal value to a given number of decimal places. The value @@ -666,46 +653,21 @@ namespace System // By default a mid-point value is rounded to the nearest even number. If the mode is // passed in, it can also round away from zero. - public static Decimal Round(Decimal d) - { - return Round(d, 0); - } + public static Decimal Round(Decimal d) => Round(ref d, 0, MidpointRounding.ToEven); + public static Decimal Round(Decimal d, int decimals) => Round(ref d, decimals, MidpointRounding.ToEven); + public static Decimal Round(Decimal d, MidpointRounding mode) => Round(ref d, 0, mode); + public static Decimal Round(Decimal d, int decimals, MidpointRounding mode) => Round(ref d, decimals, mode); - public static Decimal Round(Decimal d, int decimals) + private static Decimal Round(ref Decimal d, int decimals, MidpointRounding mode) { - Decimal result = new Decimal(); - - if (decimals < 0 || decimals > 28) + if ((uint)decimals > 28) throw new ArgumentOutOfRangeException(nameof(decimals), SR.ArgumentOutOfRange_DecimalRound); + if ((uint)mode > (uint)MidpointRounding.AwayFromZero) + throw new ArgumentException(SR.Format(SR.Argument_InvalidEnumValue, mode, nameof(MidpointRounding)), nameof(mode)); - DecCalc.VarDecRound(ref d, decimals, ref result); - - d = result; - return d; - } - - public static Decimal Round(Decimal d, MidpointRounding mode) - { - return Round(d, 0, mode); - } - - public static Decimal Round(Decimal d, int decimals, MidpointRounding mode) - { - if (decimals < 0 || decimals > 28) - throw new ArgumentOutOfRangeException(nameof(decimals), SR.ArgumentOutOfRange_DecimalRound); - if (mode < MidpointRounding.ToEven || mode > MidpointRounding.AwayFromZero) - throw new ArgumentException(SR.Format(SR.Argument_InvalidEnumValue, mode, "MidpointRounding"), nameof(mode)); - - if (mode == MidpointRounding.ToEven) - { - Decimal result = new Decimal(); - DecCalc.VarDecRound(ref d, decimals, ref result); - d = result; - } - else - { - DecCalc.InternalRoundFromZero(ref d, decimals); - } + int scale = d.Scale - decimals; + if (scale > 0) + DecCalc.InternalRound(ref d, (uint)scale, (DecCalc.RoundingMode)mode); return d; } @@ -791,8 +753,8 @@ namespace System // public static int ToInt32(Decimal d) { - if (d.Scale != 0) DecCalc.VarDecFix(ref d); - if (d.hi == 0 && d.mid == 0) + Truncate(ref d); + if ((d.hi | d.mid) == 0) { int i = d.lo; if (!d.IsNegative) @@ -814,10 +776,10 @@ namespace System // public static long ToInt64(Decimal d) { - if (d.Scale != 0) DecCalc.VarDecFix(ref d); + Truncate(ref d); if (d.uhi == 0) { - long l = d.ulo | (long)(int)d.umid << 32; + long l = (long)d.Low64; if (!d.IsNegative) { if (l >= 0) return l; @@ -858,11 +820,12 @@ namespace System [CLSCompliant(false)] public static uint ToUInt32(Decimal d) { - if (d.Scale != 0) DecCalc.VarDecFix(ref d); - if (d.uhi == 0 && d.umid == 0) + Truncate(ref d); + if ((d.uhi | d.umid) == 0) { - if (!d.IsNegative || d.ulo == 0) - return d.ulo; + uint i = d.ulo; + if (!d.IsNegative || i == 0) + return i; } throw new OverflowException(SR.Overflow_UInt32); } @@ -874,10 +837,10 @@ namespace System [CLSCompliant(false)] public static ulong ToUInt64(Decimal d) { - if (d.Scale != 0) DecCalc.VarDecFix(ref d); + Truncate(ref d); if (d.uhi == 0) { - ulong l = (ulong)d.ulo | ((ulong)d.umid << 32); + ulong l = d.Low64; if (!d.IsNegative || l == 0) return l; } @@ -898,10 +861,18 @@ namespace System // public static Decimal Truncate(Decimal d) { - DecCalc.VarDecFix(ref d); + Truncate(ref d); return d; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void Truncate(ref Decimal d) + { + uint flags = d.uflags; + if ((flags & ScaleMask) != 0) + DecCalc.InternalRound(ref d, (byte)(flags >> ScaleShift), DecCalc.RoundingMode.Truncate); + } + public static implicit operator Decimal(byte value) { return new Decimal(value); diff --git a/external/corert/src/System.Private.CoreLib/src/System/Delegate.cs b/external/corert/src/System.Private.CoreLib/src/System/Delegate.cs index 0ec444eaa5..e4746b1abd 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Delegate.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Delegate.cs @@ -493,21 +493,21 @@ namespace System // This method will combine this delegate with the passed delegate // to form a new delegate. - protected virtual Delegate CombineImpl(Delegate follow) + protected virtual Delegate CombineImpl(Delegate d) { - if ((Object)follow == null) // cast to object for a more efficient test + if ((Object)d == null) // cast to object for a more efficient test return this; // Verify that the types are the same... - if (!InternalEqualTypes(this, follow)) + if (!InternalEqualTypes(this, d)) throw new ArgumentException(); - if (IsDynamicDelegate() && follow.IsDynamicDelegate()) + if (IsDynamicDelegate() && d.IsDynamicDelegate()) { throw new InvalidOperationException(); } - MulticastDelegate dFollow = (MulticastDelegate)follow; + MulticastDelegate dFollow = (MulticastDelegate)d; Delegate[] resultList; int followCount = 1; Delegate[] followList = dFollow.m_helperObject as Delegate[]; @@ -616,12 +616,12 @@ namespace System // look at the invocation list.) If this is found we remove it from // this list and return a new delegate. If its not found a copy of the // current list is returned. - protected virtual Delegate RemoveImpl(Delegate value) + protected virtual Delegate RemoveImpl(Delegate d) { // There is a special case were we are removing using a delegate as // the value we need to check for this case // - MulticastDelegate v = value as MulticastDelegate; + MulticastDelegate v = d as MulticastDelegate; if (v == null) return this; @@ -631,7 +631,7 @@ namespace System if (invocationList == null) { // they are both not real Multicast - if (this.Equals(value)) + if (this.Equals(d)) return null; } else @@ -639,7 +639,7 @@ namespace System int invocationCount = (int)m_extraFunctionPointerOrData; for (int i = invocationCount; --i >= 0;) { - if (value.Equals(invocationList[i])) + if (d.Equals(invocationList[i])) { if (invocationCount == 2) { diff --git a/external/corert/src/System.Private.CoreLib/src/System/Diagnostics/Debug.Windows.cs b/external/corert/src/System.Private.CoreLib/src/System/Diagnostics/Debug.Windows.cs index aae5c6c37d..9493cadef8 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Diagnostics/Debug.Windows.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Diagnostics/Debug.Windows.cs @@ -11,8 +11,9 @@ namespace System.Diagnostics { public static partial class Debug { - private static void ShowAssertDialog(string stackTrace, string message, string detailMessage) + private static void ShowDialog(string stackTrace, string message, string detailMessage, string errorSource) { + // We can safely ignore errorSource since it's a CoreCLR specific argument for distinguishing calls from Debug.Assert and Environment.FailFast string fullMessage = message + Environment.NewLine + detailMessage; bool result = DeveloperExperience.Default.OnContractFailure(stackTrace, ContractFailureKind.Assert, fullMessage, null, null, null); if (!result) diff --git a/external/corert/src/System.Private.CoreLib/src/System/Diagnostics/DebugAnnotations.cs b/external/corert/src/System.Private.CoreLib/src/System/Diagnostics/DebugAnnotations.cs index 7c4d877541..4130003275 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Diagnostics/DebugAnnotations.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Diagnostics/DebugAnnotations.cs @@ -7,6 +7,7 @@ namespace System.Diagnostics /// /// Annotations used by debugger /// + [System.Runtime.CompilerServices.ReflectionBlocked] public static class DebugAnnotations { /// diff --git a/external/corert/src/System.Private.CoreLib/src/System/Diagnostics/DebuggerGuidedStepThroughAttribute.cs b/external/corert/src/System.Private.CoreLib/src/System/Diagnostics/DebuggerGuidedStepThroughAttribute.cs index ff6219b79e..68bf185778 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Diagnostics/DebuggerGuidedStepThroughAttribute.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Diagnostics/DebuggerGuidedStepThroughAttribute.cs @@ -4,6 +4,7 @@ namespace System.Diagnostics { + [System.Runtime.CompilerServices.ReflectionBlocked] [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Constructor, Inherited = false)] public sealed class DebuggerGuidedStepThroughAttribute : Attribute { diff --git a/external/corert/src/System.Private.CoreLib/src/System/Diagnostics/LowLevelDebugFuncEval.cs b/external/corert/src/System.Private.CoreLib/src/System/Diagnostics/LowLevelDebugFuncEval.cs new file mode 100644 index 0000000000..f1d140429a --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/src/System/Diagnostics/LowLevelDebugFuncEval.cs @@ -0,0 +1,39 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime; +using System.Runtime.InteropServices; + +namespace System.Diagnostics +{ + public static class LowLevelDebugFuncEval + { + private static Action s_highLevelDebugFuncEvalHelper; + private static Action s_highLevelDebugFuncEvalAbortHelper; + + [RuntimeExport("DebugFuncEvalHelper")] + public static void DebugFuncEvalHelper() + { + Debug.Assert(s_highLevelDebugFuncEvalHelper != null); + s_highLevelDebugFuncEvalHelper(); + } + + [NativeCallable(EntryPoint="DebugFuncEvalAbortHelper")] + public static void DebugFuncEvalAbortHelper(long pointerFromDebugger) + { + Debug.Assert(s_highLevelDebugFuncEvalHelper != null); + s_highLevelDebugFuncEvalAbortHelper(pointerFromDebugger); + } + + public static void SetHighLevelDebugFuncEvalHelper(Action highLevelDebugFuncEvalHelper) + { + s_highLevelDebugFuncEvalHelper = highLevelDebugFuncEvalHelper; + } + + public static void SetHighLevelDebugFuncEvalAbortHelper(Action highLevelDebugFuncEvalAbortHelper) + { + s_highLevelDebugFuncEvalAbortHelper = highLevelDebugFuncEvalAbortHelper; + } + } +} \ No newline at end of file diff --git a/external/corert/src/System.Private.CoreLib/src/System/Diagnostics/StackTrace.cs b/external/corert/src/System.Private.CoreLib/src/System/Diagnostics/StackTrace.cs index 7dc82a5908..4d5a2155ca 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Diagnostics/StackTrace.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Diagnostics/StackTrace.cs @@ -5,6 +5,7 @@ using System; using System.Runtime; using System.Text; +using System.Reflection; using Internal.Diagnostics; @@ -201,6 +202,19 @@ namespace System.Diagnostics /// Builds a readable representation of the stack trace /// public override String ToString() + { + return ToString(TraceFormat.Normal); // default behavior in RT did not have trailing newline + } + + // TraceFormat is Used to specify options for how the + // string-representation of a StackTrace should be generated. + internal enum TraceFormat + { + Normal, + TrailingNewLine, // include a trailing new line character + } + + internal String ToString(TraceFormat traceFormat) { if (_stackFrames == null) { @@ -212,7 +226,14 @@ namespace System.Diagnostics { frame.AppendToStackTrace(builder); } + + if (traceFormat == TraceFormat.TrailingNewLine) + { + builder.Append(Environment.NewLine); + } + return builder.ToString(); } + } } diff --git a/external/corert/src/System.Private.CoreLib/src/System/Enum.cs b/external/corert/src/System.Private.CoreLib/src/System/Enum.cs index e863605c97..06da1b1174 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Enum.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Enum.cs @@ -833,6 +833,7 @@ namespace System return Format(enumInfo, this, format); } + [Obsolete("The provider argument is not used. Please use ToString().")] public String ToString(String format, IFormatProvider provider) { return ToString(format); diff --git a/external/corert/src/System.Private.CoreLib/src/System/Environment.Win32.cs b/external/corert/src/System.Private.CoreLib/src/System/Environment.Win32.cs new file mode 100644 index 0000000000..4d6dd60db9 --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/src/System/Environment.Win32.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text; + +namespace System +{ + internal static partial class Environment + { + internal static string SystemDirectory + { + get + { + StringBuilder sb = new StringBuilder(Interop.Kernel32.MAX_PATH); + int r = Interop.mincore.GetSystemDirectory(sb, Interop.Kernel32.MAX_PATH); + return sb.ToString(); + } + } + } +} diff --git a/external/corert/src/System.Private.CoreLib/src/System/Environment.cs b/external/corert/src/System.Private.CoreLib/src/System/Environment.cs index 9835a2592e..c1d4ac171b 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Environment.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Environment.cs @@ -13,10 +13,12 @@ ============================================================*/ using System.Diagnostics; +using System.Diagnostics.Contracts; using System.Runtime.CompilerServices; using System.Threading; using Internal.Runtime.Augments; +using Internal.DeveloperExperience; namespace System { @@ -58,6 +60,17 @@ namespace System RuntimeExceptionHelpers.FailFast(message, exception); } + internal static void FailFast(String message, Exception exception, String errorSource) + { + // TODO: errorSource originates from CoreCLR (See: https://github.com/dotnet/coreclr/pull/15895) + // For now, we ignore errorSource on CoreRT but we should distinguish the way FailFast prints exception message using errorSource + bool result = DeveloperExperience.Default.OnContractFailure(exception.StackTrace, ContractFailureKind.Assert, message, null, null, null); + if (!result) + { + RuntimeExceptionHelpers.FailFast(message, exception); + } + } + // Still needed by shared\System\Diagnostics\Debug.Unix.cs public static string GetEnvironmentVariable(string variable) => EnvironmentAugments.GetEnvironmentVariable(variable); diff --git a/external/corert/src/System.Private.CoreLib/src/System/GC.cs b/external/corert/src/System.Private.CoreLib/src/System/GC.cs index 053785d750..68d1bc9a34 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/GC.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/GC.cs @@ -75,23 +75,23 @@ namespace System /// Returns the current generation number of the target /// of a specified . /// - /// The WeakReference whose target is the object + /// The WeakReference whose target is the object /// whose generation will be returned /// The generation of the target of the WeakReference /// The target of the weak reference /// has already been garbage collected. - public static int GetGeneration(WeakReference wr) + public static int GetGeneration(WeakReference wo) { // note - this throws an NRE if given a null weak reference. This isn't // documented, but it's the behavior of Desktop and CoreCLR. - Object handleRef = RuntimeImports.RhHandleGet(wr.m_handle); + Object handleRef = RuntimeImports.RhHandleGet(wo.m_handle); if (handleRef == null) { - throw new ArgumentNullException(nameof(wr)); + throw new ArgumentNullException(nameof(wo)); } int result = RuntimeImports.RhGetGeneration(handleRef); - KeepAlive(wr); + KeepAlive(wo); return result; } diff --git a/external/corert/src/System.Private.CoreLib/src/System/Globalization/CompareInfo.Unix.cs b/external/corert/src/System.Private.CoreLib/src/System/Globalization/CompareInfo.Unix.cs index cbf3fb555c..40f0ab0081 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Globalization/CompareInfo.Unix.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Globalization/CompareInfo.Unix.cs @@ -12,7 +12,7 @@ namespace System.Globalization public partial class CompareInfo { [NonSerialized] - private Interop.GlobalizationInterop.SafeSortHandle _sortHandle; + private Interop.Globalization.SafeSortHandle _sortHandle; [NonSerialized] private bool _isAsciiEqualityOrdinal; @@ -27,12 +27,12 @@ namespace System.Globalization } else { - Interop.GlobalizationInterop.ResultCode resultCode = Interop.GlobalizationInterop.GetSortHandle(GetNullTerminatedUtf8String(_sortName), out _sortHandle); - if (resultCode != Interop.GlobalizationInterop.ResultCode.Success) + Interop.Globalization.ResultCode resultCode = Interop.Globalization.GetSortHandle(GetNullTerminatedUtf8String(_sortName), out _sortHandle); + if (resultCode != Interop.Globalization.ResultCode.Success) { _sortHandle.Dispose(); - if (resultCode == Interop.GlobalizationInterop.ResultCode.OutOfMemory) + if (resultCode == Interop.Globalization.ResultCode.OutOfMemory) throw new OutOfMemoryException(); throw new ExternalException(SR.Arg_ExternalException); @@ -62,7 +62,7 @@ namespace System.Globalization { fixed (char* pSource = source) { - int index = Interop.GlobalizationInterop.IndexOfOrdinalIgnoreCase(value, value.Length, pSource + startIndex, count, findLast: false); + int index = Interop.Globalization.IndexOfOrdinalIgnoreCase(value, value.Length, pSource + startIndex, count, findLast: false); return index != -1 ? startIndex + index : -1; @@ -87,6 +87,47 @@ namespace System.Globalization return -1; } + internal static unsafe int IndexOfOrdinalCore(ReadOnlySpan source, ReadOnlySpan value, bool ignoreCase) + { + Debug.Assert(!GlobalizationMode.Invariant); + + Debug.Assert(source.Length != 0); + Debug.Assert(value.Length != 0); + + if (source.Length < value.Length) + { + return -1; + } + + if (ignoreCase) + { + fixed (char* pSource = &MemoryMarshal.GetReference(source)) + fixed (char* pValue = &MemoryMarshal.GetReference(value)) + { + int index = Interop.Globalization.IndexOfOrdinalIgnoreCase(pValue, value.Length, pSource, source.Length, findLast: false); + return index; + } + } + + int endIndex = source.Length - value.Length; + for (int i = 0; i <= endIndex; i++) + { + int valueIndex, sourceIndex; + + for (valueIndex = 0, sourceIndex = i; + valueIndex < value.Length && source[sourceIndex] == value[valueIndex]; + valueIndex++, sourceIndex++) + ; + + if (valueIndex == value.Length) + { + return i; + } + } + + return -1; + } + internal static unsafe int LastIndexOfOrdinalCore(string source, string value, int startIndex, int count, bool ignoreCase) { Debug.Assert(!GlobalizationMode.Invariant); @@ -113,7 +154,7 @@ namespace System.Globalization { fixed (char* pSource = source) { - int lastIndex = Interop.GlobalizationInterop.IndexOfOrdinalIgnoreCase(value, value.Length, pSource + leftStartIndex, count, findLast: true); + int lastIndex = Interop.Globalization.IndexOfOrdinalIgnoreCase(value, value.Length, pSource + leftStartIndex, count, findLast: true); return lastIndex != -1 ? leftStartIndex + lastIndex : -1; @@ -140,7 +181,7 @@ namespace System.Globalization { Debug.Assert(!GlobalizationMode.Invariant); - return Interop.GlobalizationInterop.CompareStringOrdinalIgnoreCase(string1, count1, string2, count2); + return Interop.Globalization.CompareStringOrdinalIgnoreCase(string1, count1, string2, count2); } // TODO https://github.com/dotnet/coreclr/issues/13827: @@ -155,7 +196,7 @@ namespace System.Globalization fixed (char* pString1 = &MemoryMarshal.GetReference(string1)) fixed (char* pString2 = &string2.GetRawStringData()) { - return Interop.GlobalizationInterop.CompareString(_sortHandle, pString1, string1.Length, pString2, string2.Length, options); + return Interop.Globalization.CompareString(_sortHandle, pString1, string1.Length, pString2, string2.Length, options); } } @@ -167,7 +208,7 @@ namespace System.Globalization fixed (char* pString1 = &MemoryMarshal.GetReference(string1)) fixed (char* pString2 = &MemoryMarshal.GetReference(string2)) { - return Interop.GlobalizationInterop.CompareString(_sortHandle, pString1, string1.Length, pString2, string2.Length, options); + return Interop.Globalization.CompareString(_sortHandle, pString1, string1.Length, pString2, string2.Length, options); } } @@ -212,12 +253,165 @@ namespace System.Globalization #endif fixed (char* pSource = source) { - index = Interop.GlobalizationInterop.IndexOf(_sortHandle, target, target.Length, pSource + startIndex, count, options, matchLengthPtr); + index = Interop.Globalization.IndexOf(_sortHandle, target, target.Length, pSource + startIndex, count, options, matchLengthPtr); return index != -1 ? index + startIndex : -1; } } + // For now, this method is only called from Span APIs with either options == CompareOptions.None or CompareOptions.IgnoreCase + internal unsafe int IndexOfCore(ReadOnlySpan source, ReadOnlySpan target, CompareOptions options, int* matchLengthPtr) + { + Debug.Assert(!_invariantMode); + Debug.Assert(source.Length != 0); + Debug.Assert(target.Length != 0); + + if (_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions(options)) + { + if ((options & CompareOptions.IgnoreCase) == CompareOptions.IgnoreCase) + { + return IndexOfOrdinalIgnoreCaseHelper(source, target, options, matchLengthPtr); + } + else + { + return IndexOfOrdinalHelper(source, target, options, matchLengthPtr); + } + } + else + { + fixed (char* pSource = &MemoryMarshal.GetReference(source)) + fixed (char* pTarget = &MemoryMarshal.GetReference(target)) + { + return Interop.Globalization.IndexOf(_sortHandle, pTarget, target.Length, pSource, source.Length, options, matchLengthPtr); + } + } + } + + private unsafe int IndexOfOrdinalIgnoreCaseHelper(ReadOnlySpan source, ReadOnlySpan target, CompareOptions options, int* matchLengthPtr) + { + Debug.Assert(!_invariantMode); + + Debug.Assert(!source.IsEmpty); + Debug.Assert(!target.IsEmpty); + Debug.Assert(_isAsciiEqualityOrdinal); + + fixed (char* ap = &MemoryMarshal.GetReference(source)) + fixed (char* bp = &MemoryMarshal.GetReference(target)) + { + char* a = ap; + char* b = bp; + int endIndex = source.Length - target.Length; + + if (endIndex < 0) + goto InteropCall; + + for (int j = 0; j < target.Length; j++) + { + char targetChar = *(b + j); + if (targetChar >= 0x80 || s_highCharTable[targetChar]) + goto InteropCall; + } + + int i = 0; + for (; i <= endIndex; i++) + { + int targetIndex = 0; + int sourceIndex = i; + + for (; targetIndex < target.Length; targetIndex++) + { + char valueChar = *(a + sourceIndex); + char targetChar = *(b + targetIndex); + + if (valueChar == targetChar && valueChar < 0x80 && !s_highCharTable[valueChar]) + { + sourceIndex++; + continue; + } + + // uppercase both chars - notice that we need just one compare per char + if ((uint)(valueChar - 'a') <= ('z' - 'a')) + valueChar = (char)(valueChar - 0x20); + if ((uint)(targetChar - 'a') <= ('z' - 'a')) + targetChar = (char)(targetChar - 0x20); + + if (valueChar >= 0x80 || s_highCharTable[valueChar]) + goto InteropCall; + else if (valueChar != targetChar) + break; + sourceIndex++; + } + + if (targetIndex == target.Length) + { + if (matchLengthPtr != null) + *matchLengthPtr = target.Length; + return i; + } + } + if (i > endIndex) + return -1; + InteropCall: + return Interop.Globalization.IndexOf(_sortHandle, b, target.Length, a, source.Length, options, matchLengthPtr); + } + } + + private unsafe int IndexOfOrdinalHelper(ReadOnlySpan source, ReadOnlySpan target, CompareOptions options, int* matchLengthPtr) + { + Debug.Assert(!_invariantMode); + + Debug.Assert(!source.IsEmpty); + Debug.Assert(!target.IsEmpty); + Debug.Assert(_isAsciiEqualityOrdinal); + + fixed (char* ap = &MemoryMarshal.GetReference(source)) + fixed (char* bp = &MemoryMarshal.GetReference(target)) + { + char* a = ap; + char* b = bp; + int endIndex = source.Length - target.Length; + + if (endIndex < 0) + goto InteropCall; + + for (int j = 0; j < target.Length; j++) + { + char targetChar = *(b + j); + if (targetChar >= 0x80 || s_highCharTable[targetChar]) + goto InteropCall; + } + + int i = 0; + for (; i <= endIndex; i++) + { + int targetIndex = 0; + int sourceIndex = i; + + for (; targetIndex < target.Length; targetIndex++) + { + char valueChar = *(a + sourceIndex); + char targetChar = *(b + targetIndex); + if (valueChar >= 0x80 || s_highCharTable[valueChar]) + goto InteropCall; + else if (valueChar != targetChar) + break; + sourceIndex++; + } + + if (targetIndex == target.Length) + { + if (matchLengthPtr != null) + *matchLengthPtr = target.Length; + return i; + } + } + if (i > endIndex) + return -1; + InteropCall: + return Interop.Globalization.IndexOf(_sortHandle, b, target.Length, a, source.Length, options, matchLengthPtr); + } + } + private unsafe int LastIndexOfCore(string source, string target, int startIndex, int count, CompareOptions options) { Debug.Assert(!_invariantMode); @@ -249,7 +443,7 @@ namespace System.Globalization fixed (char* pSource = source) { - int lastIndex = Interop.GlobalizationInterop.LastIndexOf(_sortHandle, target, target.Length, pSource + (startIndex - count + 1), count, options); + int lastIndex = Interop.Globalization.LastIndexOf(_sortHandle, target, target.Length, pSource + (startIndex - count + 1), count, options); return lastIndex != -1 ? lastIndex + leftStartIndex : -1; } @@ -270,7 +464,122 @@ namespace System.Globalization } #endif - return Interop.GlobalizationInterop.StartsWith(_sortHandle, prefix, prefix.Length, source, source.Length, options); + return Interop.Globalization.StartsWith(_sortHandle, prefix, prefix.Length, source, source.Length, options); + } + + private unsafe bool StartsWith(ReadOnlySpan source, ReadOnlySpan prefix, CompareOptions options) + { + Debug.Assert(!_invariantMode); + + Debug.Assert(!source.IsEmpty); + Debug.Assert(!prefix.IsEmpty); + Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); + + if (_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions(options)) + { + if (source.Length < prefix.Length) + { + return false; + } + + if ((options & CompareOptions.IgnoreCase) == CompareOptions.IgnoreCase) + { + return StartsWithOrdinalIgnoreCaseHelper(source, prefix, options); + } + else + { + return StartsWithOrdinalHelper(source, prefix, options); + } + } + else + { + fixed (char* pSource = &MemoryMarshal.GetReference(source)) + fixed (char* pPrefix = &MemoryMarshal.GetReference(prefix)) + { + return Interop.Globalization.StartsWith(_sortHandle, pPrefix, prefix.Length, pSource, source.Length, options); + } + } + } + + private unsafe bool StartsWithOrdinalIgnoreCaseHelper(ReadOnlySpan source, ReadOnlySpan prefix, CompareOptions options) + { + Debug.Assert(!_invariantMode); + + Debug.Assert(!source.IsEmpty); + Debug.Assert(!prefix.IsEmpty); + Debug.Assert(_isAsciiEqualityOrdinal); + Debug.Assert(source.Length >= prefix.Length); + + int length = prefix.Length; + + fixed (char* ap = &MemoryMarshal.GetReference(source)) + fixed (char* bp = &MemoryMarshal.GetReference(prefix)) + { + char* a = ap; + char* b = bp; + + while (length != 0 && (*a < 0x80) && (*b < 0x80) && (!s_highCharTable[*a]) && (!s_highCharTable[*b])) + { + int charA = *a; + int charB = *b; + + if (charA == charB) + { + a++; b++; + length--; + continue; + } + + // uppercase both chars - notice that we need just one compare per char + if ((uint)(charA - 'a') <= (uint)('z' - 'a')) charA -= 0x20; + if ((uint)(charB - 'a') <= (uint)('z' - 'a')) charB -= 0x20; + + if (charA != charB) + return false; + + // Next char + a++; b++; + length--; + } + + if (length == 0) return true; + return Interop.Globalization.StartsWith(_sortHandle, b, length, a, length, options); + } + } + + private unsafe bool StartsWithOrdinalHelper(ReadOnlySpan source, ReadOnlySpan prefix, CompareOptions options) + { + Debug.Assert(!_invariantMode); + + Debug.Assert(!source.IsEmpty); + Debug.Assert(!prefix.IsEmpty); + Debug.Assert(_isAsciiEqualityOrdinal); + Debug.Assert(source.Length >= prefix.Length); + + int length = prefix.Length; + + fixed (char* ap = &MemoryMarshal.GetReference(source)) + fixed (char* bp = &MemoryMarshal.GetReference(prefix)) + { + char* a = ap; + char* b = bp; + + while (length != 0 && (*a < 0x80) && (*b < 0x80) && (!s_highCharTable[*a]) && (!s_highCharTable[*b])) + { + int charA = *a; + int charB = *b; + + if (charA != charB) + return false; + + // Next char + a++; b++; + length--; + } + + if (length == 0) return true; + return Interop.Globalization.StartsWith(_sortHandle, b, length, a, length, options); + } } private bool EndsWith(string source, string suffix, CompareOptions options) @@ -288,9 +597,124 @@ namespace System.Globalization } #endif - return Interop.GlobalizationInterop.EndsWith(_sortHandle, suffix, suffix.Length, source, source.Length, options); + return Interop.Globalization.EndsWith(_sortHandle, suffix, suffix.Length, source, source.Length, options); } + private unsafe bool EndsWith(ReadOnlySpan source, ReadOnlySpan suffix, CompareOptions options) + { + Debug.Assert(!_invariantMode); + + Debug.Assert(!source.IsEmpty); + Debug.Assert(!suffix.IsEmpty); + Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); + + if (_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions(options)) + { + if (source.Length < suffix.Length) + { + return false; + } + + if ((options & CompareOptions.IgnoreCase) == CompareOptions.IgnoreCase) + { + return EndsWithOrdinalIgnoreCaseHelper(source, suffix, options); + } + else + { + return EndsWithOrdinalHelper(source, suffix, options); + } + } + else + { + fixed (char* pSource = &MemoryMarshal.GetReference(source)) + fixed (char* pSuffix = &MemoryMarshal.GetReference(suffix)) + { + return Interop.Globalization.EndsWith(_sortHandle, pSuffix, suffix.Length, pSource, source.Length, options); + } + } + } + + private unsafe bool EndsWithOrdinalIgnoreCaseHelper(ReadOnlySpan source, ReadOnlySpan suffix, CompareOptions options) + { + Debug.Assert(!_invariantMode); + + Debug.Assert(!source.IsEmpty); + Debug.Assert(!suffix.IsEmpty); + Debug.Assert(_isAsciiEqualityOrdinal); + Debug.Assert(source.Length >= suffix.Length); + + int length = suffix.Length; + + fixed (char* ap = &MemoryMarshal.GetReference(source)) + fixed (char* bp = &MemoryMarshal.GetReference(suffix)) + { + char* a = ap + source.Length - 1; + char* b = bp + suffix.Length - 1; + + while (length != 0 && (*a < 0x80) && (*b < 0x80) && (!s_highCharTable[*a]) && (!s_highCharTable[*b])) + { + int charA = *a; + int charB = *b; + + if (charA == charB) + { + a--; b--; + length--; + continue; + } + + // uppercase both chars - notice that we need just one compare per char + if ((uint)(charA - 'a') <= (uint)('z' - 'a')) charA -= 0x20; + if ((uint)(charB - 'a') <= (uint)('z' - 'a')) charB -= 0x20; + + if (charA != charB) + return false; + + // Next char + a--; b--; + length--; + } + + if (length == 0) return true; + return Interop.Globalization.EndsWith(_sortHandle, b - length + 1, length, a - length + 1, length, options); + } + } + + private unsafe bool EndsWithOrdinalHelper(ReadOnlySpan source, ReadOnlySpan suffix, CompareOptions options) + { + Debug.Assert(!_invariantMode); + + Debug.Assert(!source.IsEmpty); + Debug.Assert(!suffix.IsEmpty); + Debug.Assert(_isAsciiEqualityOrdinal); + Debug.Assert(source.Length >= suffix.Length); + + int length = suffix.Length; + + fixed (char* ap = &MemoryMarshal.GetReference(source)) + fixed (char* bp = &MemoryMarshal.GetReference(suffix)) + { + char* a = ap + source.Length - 1; + char* b = bp + suffix.Length - 1; + + while (length != 0 && (*a < 0x80) && (*b < 0x80) && (!s_highCharTable[*a]) && (!s_highCharTable[*b])) + { + int charA = *a; + int charB = *b; + + if (charA != charB) + return false; + + // Next char + a--; b--; + length--; + } + + if (length == 0) return true; + return Interop.Globalization.EndsWith(_sortHandle, b - length + 1, length, a - length + 1, length, options); + } + } + private unsafe SortKey CreateSortKey(String source, CompareOptions options) { Debug.Assert(!_invariantMode); @@ -309,12 +733,12 @@ namespace System.Globalization } else { - int sortKeyLength = Interop.GlobalizationInterop.GetSortKey(_sortHandle, source, source.Length, null, 0, options); + int sortKeyLength = Interop.Globalization.GetSortKey(_sortHandle, source, source.Length, null, 0, options); keyData = new byte[sortKeyLength]; fixed (byte* pSortKey = keyData) { - Interop.GlobalizationInterop.GetSortKey(_sortHandle, source, source.Length, pSortKey, sortKeyLength, options); + Interop.Globalization.GetSortKey(_sortHandle, source, source.Length, pSortKey, sortKeyLength, options); } } @@ -335,7 +759,7 @@ namespace System.Globalization if (index == length - 1 || !Char.IsLowSurrogate(text[index+1])) return false; // unpaired surrogate - uc = CharUnicodeInfo.InternalGetUnicodeCategory(Char.ConvertToUtf32(text[index], text[index+1])); + uc = CharUnicodeInfo.GetUnicodeCategory(Char.ConvertToUtf32(text[index], text[index+1])); if (uc == UnicodeCategory.PrivateUse || uc == UnicodeCategory.OtherNotAssigned) return false; @@ -376,13 +800,13 @@ namespace System.Globalization return 0; } - int sortKeyLength = Interop.GlobalizationInterop.GetSortKey(_sortHandle, source, source.Length, null, 0, options); + int sortKeyLength = Interop.Globalization.GetSortKey(_sortHandle, source, source.Length, null, 0, options); // As an optimization, for small sort keys we allocate the buffer on the stack. if (sortKeyLength <= 256) { byte* pSortKey = stackalloc byte[sortKeyLength]; - Interop.GlobalizationInterop.GetSortKey(_sortHandle, source, source.Length, pSortKey, sortKeyLength, options); + Interop.Globalization.GetSortKey(_sortHandle, source, source.Length, pSortKey, sortKeyLength, options); return InternalHashSortKey(pSortKey, sortKeyLength); } @@ -390,7 +814,7 @@ namespace System.Globalization fixed (byte* pSortKey = &sortKey[0]) { - Interop.GlobalizationInterop.GetSortKey(_sortHandle, source, source.Length, pSortKey, sortKeyLength, options); + Interop.Globalization.GetSortKey(_sortHandle, source, source.Length, pSortKey, sortKeyLength, options); return InternalHashSortKey(pSortKey, sortKeyLength); } } @@ -455,12 +879,145 @@ namespace System.Globalization { Debug.Assert(!_invariantMode); - int sortVersion = Interop.GlobalizationInterop.GetSortVersion(_sortHandle); + int sortVersion = Interop.Globalization.GetSortVersion(_sortHandle); return new SortVersion(sortVersion, LCID, new Guid(sortVersion, 0, 0, 0, 0, 0, 0, (byte) (LCID >> 24), (byte) ((LCID & 0x00FF0000) >> 16), (byte) ((LCID & 0x0000FF00) >> 8), (byte) (LCID & 0xFF))); } + + // See https://github.com/dotnet/coreclr/blob/master/src/utilcode/util_nodependencies.cpp#L970 + private static readonly bool[] s_highCharTable = new bool[0x80] + { + true, /* 0x0, 0x0 */ + true, /* 0x1, .*/ + true, /* 0x2, .*/ + true, /* 0x3, .*/ + true, /* 0x4, .*/ + true, /* 0x5, .*/ + true, /* 0x6, .*/ + true, /* 0x7, .*/ + true, /* 0x8, .*/ + false, /* 0x9, */ + true, /* 0xA, */ + false, /* 0xB, .*/ + false, /* 0xC, .*/ + true, /* 0xD, */ + true, /* 0xE, .*/ + true, /* 0xF, .*/ + true, /* 0x10, .*/ + true, /* 0x11, .*/ + true, /* 0x12, .*/ + true, /* 0x13, .*/ + true, /* 0x14, .*/ + true, /* 0x15, .*/ + true, /* 0x16, .*/ + true, /* 0x17, .*/ + true, /* 0x18, .*/ + true, /* 0x19, .*/ + true, /* 0x1A, */ + true, /* 0x1B, .*/ + true, /* 0x1C, .*/ + true, /* 0x1D, .*/ + true, /* 0x1E, .*/ + true, /* 0x1F, .*/ + false, /*0x20, */ + false, /*0x21, !*/ + false, /*0x22, "*/ + false, /*0x23, #*/ + false, /*0x24, $*/ + false, /*0x25, %*/ + false, /*0x26, &*/ + true, /*0x27, '*/ + false, /*0x28, (*/ + false, /*0x29, )*/ + false, /*0x2A **/ + false, /*0x2B, +*/ + false, /*0x2C, ,*/ + true, /*0x2D, -*/ + false, /*0x2E, .*/ + false, /*0x2F, /*/ + false, /*0x30, 0*/ + false, /*0x31, 1*/ + false, /*0x32, 2*/ + false, /*0x33, 3*/ + false, /*0x34, 4*/ + false, /*0x35, 5*/ + false, /*0x36, 6*/ + false, /*0x37, 7*/ + false, /*0x38, 8*/ + false, /*0x39, 9*/ + false, /*0x3A, :*/ + false, /*0x3B, ;*/ + false, /*0x3C, <*/ + false, /*0x3D, =*/ + false, /*0x3E, >*/ + false, /*0x3F, ?*/ + false, /*0x40, @*/ + false, /*0x41, A*/ + false, /*0x42, B*/ + false, /*0x43, C*/ + false, /*0x44, D*/ + false, /*0x45, E*/ + false, /*0x46, F*/ + false, /*0x47, G*/ + false, /*0x48, H*/ + false, /*0x49, I*/ + false, /*0x4A, J*/ + false, /*0x4B, K*/ + false, /*0x4C, L*/ + false, /*0x4D, M*/ + false, /*0x4E, N*/ + false, /*0x4F, O*/ + false, /*0x50, P*/ + false, /*0x51, Q*/ + false, /*0x52, R*/ + false, /*0x53, S*/ + false, /*0x54, T*/ + false, /*0x55, U*/ + false, /*0x56, V*/ + false, /*0x57, W*/ + false, /*0x58, X*/ + false, /*0x59, Y*/ + false, /*0x5A, Z*/ + false, /*0x5B, [*/ + false, /*0x5C, \*/ + false, /*0x5D, ]*/ + false, /*0x5E, ^*/ + false, /*0x5F, _*/ + false, /*0x60, `*/ + false, /*0x61, a*/ + false, /*0x62, b*/ + false, /*0x63, c*/ + false, /*0x64, d*/ + false, /*0x65, e*/ + false, /*0x66, f*/ + false, /*0x67, g*/ + false, /*0x68, h*/ + false, /*0x69, i*/ + false, /*0x6A, j*/ + false, /*0x6B, k*/ + false, /*0x6C, l*/ + false, /*0x6D, m*/ + false, /*0x6E, n*/ + false, /*0x6F, o*/ + false, /*0x70, p*/ + false, /*0x71, q*/ + false, /*0x72, r*/ + false, /*0x73, s*/ + false, /*0x74, t*/ + false, /*0x75, u*/ + false, /*0x76, v*/ + false, /*0x77, w*/ + false, /*0x78, x*/ + false, /*0x79, y*/ + false, /*0x7A, z*/ + false, /*0x7B, {*/ + false, /*0x7C, |*/ + false, /*0x7D, }*/ + false, /*0x7E, ~*/ + true, /*0x7F, */ + }; } } diff --git a/external/corert/src/System.Private.CoreLib/src/System/Globalization/CompareInfo.Windows.cs b/external/corert/src/System.Private.CoreLib/src/System/Globalization/CompareInfo.Windows.cs index 958dc727c3..c0befb2633 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Globalization/CompareInfo.Windows.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Globalization/CompareInfo.Windows.cs @@ -51,6 +51,28 @@ namespace System.Globalization return ret < 0 ? ret : ret + offset; } } + + private static unsafe int FindStringOrdinal( + uint dwFindStringOrdinalFlags, + ReadOnlySpan source, + ReadOnlySpan value, + bool bIgnoreCase) + { + Debug.Assert(!GlobalizationMode.Invariant); + + fixed (char* pSource = &MemoryMarshal.GetReference(source)) + fixed (char* pValue = &MemoryMarshal.GetReference(value)) + { + int ret = Interop.Kernel32.FindStringOrdinal( + dwFindStringOrdinalFlags, + pSource, + source.Length, + pValue, + value.Length, + bIgnoreCase ? 1 : 0); + return ret; + } + } internal static int IndexOfOrdinalCore(string source, string value, int startIndex, int count, bool ignoreCase) { @@ -62,6 +84,16 @@ namespace System.Globalization return FindStringOrdinal(FIND_FROMSTART, source, startIndex, count, value, value.Length, ignoreCase); } + internal static int IndexOfOrdinalCore(ReadOnlySpan source, ReadOnlySpan value, bool ignoreCase) + { + Debug.Assert(!GlobalizationMode.Invariant); + + Debug.Assert(source.Length != 0); + Debug.Assert(value.Length != 0); + + return FindStringOrdinal(FIND_FROMSTART, source, value, ignoreCase); + } + internal static int LastIndexOfOrdinalCore(string source, string value, int startIndex, int count, bool ignoreCase) { Debug.Assert(!GlobalizationMode.Invariant); @@ -177,6 +209,34 @@ namespace System.Globalization } } + private unsafe int FindString( + uint dwFindNLSStringFlags, + ReadOnlySpan lpStringSource, + ReadOnlySpan lpStringValue, + int* pcchFound) + { + Debug.Assert(!_invariantMode); + + string localeName = _sortHandle != IntPtr.Zero ? null : _sortName; + + fixed (char* pLocaleName = localeName) + fixed (char* pSource = &MemoryMarshal.GetReference(lpStringSource)) + fixed (char* pValue = &MemoryMarshal.GetReference(lpStringValue)) + { + return Interop.Kernel32.FindNLSStringEx( + pLocaleName, + dwFindNLSStringFlags, + pSource, + lpStringSource.Length, + pValue, + lpStringValue.Length, + pcchFound, + null, + null, + _sortHandle); + } + } + private unsafe int FindString( uint dwFindNLSStringFlags, string lpStringSource, @@ -256,6 +316,18 @@ namespace System.Globalization return -1; } + internal unsafe int IndexOfCore(ReadOnlySpan source, ReadOnlySpan target, CompareOptions options, int* matchLengthPtr) + { + Debug.Assert(!_invariantMode); + + Debug.Assert(source.Length != 0); + Debug.Assert(target.Length != 0); + Debug.Assert((options == CompareOptions.None || options == CompareOptions.IgnoreCase)); + + int retValue = FindString(FIND_FROMSTART | (uint)GetNativeCompareFlags(options), source, target, matchLengthPtr); + return retValue; + } + private unsafe int LastIndexOfCore(string source, string target, int startIndex, int count, CompareOptions options) { Debug.Assert(!_invariantMode); @@ -311,6 +383,17 @@ namespace System.Globalization null) >= 0; } + private unsafe bool StartsWith(ReadOnlySpan source, ReadOnlySpan prefix, CompareOptions options) + { + Debug.Assert(!_invariantMode); + + Debug.Assert(!source.IsEmpty); + Debug.Assert(!prefix.IsEmpty); + Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); + + return FindString(FIND_STARTSWITH | (uint)GetNativeCompareFlags(options), source, prefix, null) >= 0; + } + private unsafe bool EndsWith(string source, string suffix, CompareOptions options) { Debug.Assert(!_invariantMode); @@ -329,6 +412,17 @@ namespace System.Globalization null) >= 0; } + private unsafe bool EndsWith(ReadOnlySpan source, ReadOnlySpan suffix, CompareOptions options) + { + Debug.Assert(!_invariantMode); + + Debug.Assert(!source.IsEmpty); + Debug.Assert(!suffix.IsEmpty); + Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); + + return FindString(FIND_ENDSWITH | (uint)GetNativeCompareFlags(options), source, suffix, null) >= 0; + } + // PAL ends here [NonSerialized] private IntPtr _sortHandle; diff --git a/external/corert/src/System.Private.CoreLib/src/System/Globalization/CultureData.cs b/external/corert/src/System.Private.CoreLib/src/System/Globalization/CultureData.cs deleted file mode 100644 index e17d4b0cae..0000000000 --- a/external/corert/src/System.Private.CoreLib/src/System/Globalization/CultureData.cs +++ /dev/null @@ -1,2458 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; -using System.Threading; - -namespace System.Globalization -{ - // - // List of culture data - // Note the we cache overrides. - // Note that localized names (resource names) aren't available from here. - // - - // - // Our names are a tad confusing. - // - // sWindowsName -- The name that windows thinks this culture is, ie: - // en-US if you pass in en-US - // de-DE_phoneb if you pass in de-DE_phoneb - // fj-FJ if you pass in fj (neutral, on a pre-Windows 7 machine) - // fj if you pass in fj (neutral, post-Windows 7 machine) - // - // sRealName -- The name you used to construct the culture, in pretty form - // en-US if you pass in EN-us - // en if you pass in en - // de-DE_phoneb if you pass in de-DE_phoneb - // - // sSpecificCulture -- The specific culture for this culture - // en-US for en-US - // en-US for en - // de-DE_phoneb for alt sort - // fj-FJ for fj (neutral) - // - // sName -- The IETF name of this culture (ie: no sort info, could be neutral) - // en-US if you pass in en-US - // en if you pass in en - // de-DE if you pass in de-DE_phoneb - // - internal partial class CultureData - { - private const int undef = -1; - - // Override flag - private String _sRealName; // Name you passed in (ie: en-US, en, or de-DE_phoneb) - private String _sWindowsName; // Name OS thinks the object is (ie: de-DE_phoneb, or en-US (even if en was passed in)) - - // Identity - private String _sName; // locale name (ie: en-us, NO sort info, but could be neutral) - private String _sParent; // Parent name (which may be a custom locale/culture) - private String _sLocalizedDisplayName; // Localized pretty name for this locale - private String _sEnglishDisplayName; // English pretty name for this locale - private String _sNativeDisplayName; // Native pretty name for this locale - private String _sSpecificCulture; // The culture name to be used in CultureInfo.CreateSpecificCulture(), en-US form if neutral, sort name if sort - - // Language - private String _sISO639Language; // ISO 639 Language Name - private String _sISO639Language2; // ISO 639 Language Name - private String _sLocalizedLanguage; // Localized name for this language - private String _sEnglishLanguage; // English name for this language - private String _sNativeLanguage; // Native name of this language - private String _sAbbrevLang; // abbreviated language name (Windows Language Name) ex: ENU - private string _sConsoleFallbackName; // The culture name for the console fallback UI culture - private int _iInputLanguageHandle = undef;// input language handle - - // Region - private String _sRegionName; // (RegionInfo) - private String _sLocalizedCountry; // localized country name - private String _sEnglishCountry; // english country name (RegionInfo) - private String _sNativeCountry; // native country name - private String _sISO3166CountryName; // ISO 3166 (RegionInfo), ie: US - private String _sISO3166CountryName2; // 3 char ISO 3166 country name 2 2(RegionInfo) ex: USA (ISO) - private int _iGeoId = undef; // GeoId - - // Numbers - private String _sPositiveSign; // (user can override) positive sign - private String _sNegativeSign; // (user can override) negative sign - // (nfi populates these 5, don't have to be = undef) - private int _iDigits; // (user can override) number of fractional digits - private int _iNegativeNumber; // (user can override) negative number format - private int[] _waGrouping; // (user can override) grouping of digits - private String _sDecimalSeparator; // (user can override) decimal separator - private String _sThousandSeparator; // (user can override) thousands separator - private String _sNaN; // Not a Number - private String _sPositiveInfinity; // + Infinity - private String _sNegativeInfinity; // - Infinity - - // Percent - private int _iNegativePercent = undef; // Negative Percent (0-3) - private int _iPositivePercent = undef; // Positive Percent (0-11) - private String _sPercent; // Percent (%) symbol - private String _sPerMille; // PerMille symbol - - // Currency - private String _sCurrency; // (user can override) local monetary symbol - private String _sIntlMonetarySymbol; // international monetary symbol (RegionInfo) - private String _sEnglishCurrency; // English name for this currency - private String _sNativeCurrency; // Native name for this currency - // (nfi populates these 4, don't have to be = undef) - private int _iCurrencyDigits; // (user can override) # local monetary fractional digits - private int _iCurrency; // (user can override) positive currency format - private int _iNegativeCurrency; // (user can override) negative currency format - private int[] _waMonetaryGrouping; // (user can override) monetary grouping of digits - private String _sMonetaryDecimal; // (user can override) monetary decimal separator - private String _sMonetaryThousand; // (user can override) monetary thousands separator - - // Misc - private int _iMeasure = undef; // (user can override) system of measurement 0=metric, 1=US (RegionInfo) - private String _sListSeparator; // (user can override) list separator - - // Time - private String _sAM1159; // (user can override) AM designator - private String _sPM2359; // (user can override) PM designator - private String _sTimeSeparator; - private volatile String[] _saLongTimes; // (user can override) time format - private volatile String[] _saShortTimes; // short time format - private volatile String[] _saDurationFormats; // time duration format - - // Calendar specific data - private int _iFirstDayOfWeek = undef; // (user can override) first day of week (gregorian really) - private int _iFirstWeekOfYear = undef; // (user can override) first week of year (gregorian really) - private volatile CalendarId[] _waCalendars; // all available calendar type(s). The first one is the default calendar - - // Store for specific data about each calendar - private CalendarData[] _calendars; // Store for specific calendar data - - // Text information - private int _iReadingLayout = undef; // Reading layout data - // 0 - Left to right (eg en-US) - // 1 - Right to left (eg arabic locales) - // 2 - Vertical top to bottom with columns to the left and also left to right (ja-JP locales) - // 3 - Vertical top to bottom with columns proceeding to the right - - // CoreCLR depends on this even though its not exposed publicly. - - private int _iDefaultAnsiCodePage = undef; // default ansi code page ID (ACP) - private int _iDefaultOemCodePage = undef; // default oem code page ID (OCP or OEM) - private int _iDefaultMacCodePage = undef; // default macintosh code page - private int _iDefaultEbcdicCodePage = undef; // default EBCDIC code page - - private int _iLanguage; // locale ID (0409) - NO sort information - private bool _bUseOverrides; // use user overrides? - private bool _bNeutral; // Flags for the culture (ie: neutral or not right now) - - - // Region Name to Culture Name mapping table - // (In future would be nice to be in registry or something) - - //Using a property so we avoid creating the dictionary untill we need it - private static LowLevelDictionary RegionNames - { - get - { - if (s_RegionNames == null) - { - LowLevelDictionary regionNames = new LowLevelDictionary(211 /* prime */); - - regionNames.Add("029", "en-029"); - regionNames.Add("AE", "ar-AE"); - regionNames.Add("AF", "prs-AF"); - regionNames.Add("AL", "sq-AL"); - regionNames.Add("AM", "hy-AM"); - regionNames.Add("AR", "es-AR"); - regionNames.Add("AT", "de-AT"); - regionNames.Add("AU", "en-AU"); - regionNames.Add("AZ", "az-Cyrl-AZ"); - regionNames.Add("BA", "bs-Latn-BA"); - regionNames.Add("BD", "bn-BD"); - regionNames.Add("BE", "nl-BE"); - regionNames.Add("BG", "bg-BG"); - regionNames.Add("BH", "ar-BH"); - regionNames.Add("BN", "ms-BN"); - regionNames.Add("BO", "es-BO"); - regionNames.Add("BR", "pt-BR"); - regionNames.Add("BY", "be-BY"); - regionNames.Add("BZ", "en-BZ"); - regionNames.Add("CA", "en-CA"); - regionNames.Add("CH", "it-CH"); - regionNames.Add("CL", "es-CL"); - regionNames.Add("CN", "zh-CN"); - regionNames.Add("CO", "es-CO"); - regionNames.Add("CR", "es-CR"); - regionNames.Add("CS", "sr-Cyrl-CS"); - regionNames.Add("CZ", "cs-CZ"); - regionNames.Add("DE", "de-DE"); - regionNames.Add("DK", "da-DK"); - regionNames.Add("DO", "es-DO"); - regionNames.Add("DZ", "ar-DZ"); - regionNames.Add("EC", "es-EC"); - regionNames.Add("EE", "et-EE"); - regionNames.Add("EG", "ar-EG"); - regionNames.Add("ES", "es-ES"); - regionNames.Add("ET", "am-ET"); - regionNames.Add("FI", "fi-FI"); - regionNames.Add("FO", "fo-FO"); - regionNames.Add("FR", "fr-FR"); - regionNames.Add("GB", "en-GB"); - regionNames.Add("GE", "ka-GE"); - regionNames.Add("GL", "kl-GL"); - regionNames.Add("GR", "el-GR"); - regionNames.Add("GT", "es-GT"); - regionNames.Add("HK", "zh-HK"); - regionNames.Add("HN", "es-HN"); - regionNames.Add("HR", "hr-HR"); - regionNames.Add("HU", "hu-HU"); - regionNames.Add("ID", "id-ID"); - regionNames.Add("IE", "en-IE"); - regionNames.Add("IL", "he-IL"); - regionNames.Add("IN", "hi-IN"); - regionNames.Add("IQ", "ar-IQ"); - regionNames.Add("IR", "fa-IR"); - regionNames.Add("IS", "is-IS"); - regionNames.Add("IT", "it-IT"); - regionNames.Add("IV", ""); - regionNames.Add("JM", "en-JM"); - regionNames.Add("JO", "ar-JO"); - regionNames.Add("JP", "ja-JP"); - regionNames.Add("KE", "sw-KE"); - regionNames.Add("KG", "ky-KG"); - regionNames.Add("KH", "km-KH"); - regionNames.Add("KR", "ko-KR"); - regionNames.Add("KW", "ar-KW"); - regionNames.Add("KZ", "kk-KZ"); - regionNames.Add("LA", "lo-LA"); - regionNames.Add("LB", "ar-LB"); - regionNames.Add("LI", "de-LI"); - regionNames.Add("LK", "si-LK"); - regionNames.Add("LT", "lt-LT"); - regionNames.Add("LU", "lb-LU"); - regionNames.Add("LV", "lv-LV"); - regionNames.Add("LY", "ar-LY"); - regionNames.Add("MA", "ar-MA"); - regionNames.Add("MC", "fr-MC"); - regionNames.Add("ME", "sr-Latn-ME"); - regionNames.Add("MK", "mk-MK"); - regionNames.Add("MN", "mn-MN"); - regionNames.Add("MO", "zh-MO"); - regionNames.Add("MT", "mt-MT"); - regionNames.Add("MV", "dv-MV"); - regionNames.Add("MX", "es-MX"); - regionNames.Add("MY", "ms-MY"); - regionNames.Add("NG", "ig-NG"); - regionNames.Add("NI", "es-NI"); - regionNames.Add("NL", "nl-NL"); - regionNames.Add("NO", "nn-NO"); - regionNames.Add("NP", "ne-NP"); - regionNames.Add("NZ", "en-NZ"); - regionNames.Add("OM", "ar-OM"); - regionNames.Add("PA", "es-PA"); - regionNames.Add("PE", "es-PE"); - regionNames.Add("PH", "en-PH"); - regionNames.Add("PK", "ur-PK"); - regionNames.Add("PL", "pl-PL"); - regionNames.Add("PR", "es-PR"); - regionNames.Add("PT", "pt-PT"); - regionNames.Add("PY", "es-PY"); - regionNames.Add("QA", "ar-QA"); - regionNames.Add("RO", "ro-RO"); - regionNames.Add("RS", "sr-Latn-RS"); - regionNames.Add("RU", "ru-RU"); - regionNames.Add("RW", "rw-RW"); - regionNames.Add("SA", "ar-SA"); - regionNames.Add("SE", "sv-SE"); - regionNames.Add("SG", "zh-SG"); - regionNames.Add("SI", "sl-SI"); - regionNames.Add("SK", "sk-SK"); - regionNames.Add("SN", "wo-SN"); - regionNames.Add("SV", "es-SV"); - regionNames.Add("SY", "ar-SY"); - regionNames.Add("TH", "th-TH"); - regionNames.Add("TJ", "tg-Cyrl-TJ"); - regionNames.Add("TM", "tk-TM"); - regionNames.Add("TN", "ar-TN"); - regionNames.Add("TR", "tr-TR"); - regionNames.Add("TT", "en-TT"); - regionNames.Add("TW", "zh-TW"); - regionNames.Add("UA", "uk-UA"); - regionNames.Add("US", "en-US"); - regionNames.Add("UY", "es-UY"); - regionNames.Add("UZ", "uz-Cyrl-UZ"); - regionNames.Add("VE", "es-VE"); - regionNames.Add("VN", "vi-VN"); - regionNames.Add("YE", "ar-YE"); - regionNames.Add("ZA", "af-ZA"); - regionNames.Add("ZW", "en-ZW"); - - s_RegionNames = regionNames; - } - - return s_RegionNames; - } - } - - // Cache of regions we've already looked up - private static volatile LowLevelDictionary s_cachedRegions; - private static volatile LowLevelDictionary s_RegionNames; - - internal static CultureData GetCultureDataForRegion(String cultureName, bool useUserOverride) - { - // First do a shortcut for Invariant - if (String.IsNullOrEmpty(cultureName)) - { - return CultureData.Invariant; - } - - // - // First check if GetCultureData() can find it (ie: its a real culture) - // - CultureData retVal = GetCultureData(cultureName, useUserOverride); - if (retVal != null && (retVal.IsNeutralCulture == false)) return retVal; - - // - // Not a specific culture, perhaps it's region-only name - // (Remember this isn't a core clr path where that's not supported) - // - - // If it was neutral remember that so that RegionInfo() can throw the right exception - CultureData neutral = retVal; - - // Try the hash table next - String hashName = AnsiToLower(useUserOverride ? cultureName : cultureName + '*'); - LowLevelDictionary tempHashTable = s_cachedRegions; - if (tempHashTable == null) - { - // No table yet, make a new one - tempHashTable = new LowLevelDictionary(); - } - else - { - // Check the hash table - using (LockHolder.Hold(s_lock)) - { - tempHashTable.TryGetValue(hashName, out retVal); - } - if (retVal != null) - { - return retVal; - } - } - - // - // Not found in the hash table, look it up the hard way - // - - // If not a valid mapping from the registry we'll have to try the hard coded table - if (retVal == null || (retVal.IsNeutralCulture == true)) - { - // Not a valid mapping, try the hard coded table - string name; - if (RegionNames.TryGetValue(cultureName, out name)) - { - // Make sure we can get culture data for it - retVal = GetCultureData(name, useUserOverride); - } - } - - // If not found in the hard coded table we'll have to find a culture that works for us - if (retVal == null || (retVal.IsNeutralCulture == true)) - { - retVal = GetCultureDataFromRegionName(cultureName); - } - - // If we found one we can use, then cache it for next time - if (retVal != null && (retVal.IsNeutralCulture == false)) - { - // first add it to the cache - using (LockHolder.Hold(s_lock)) - { - tempHashTable[hashName] = retVal; - } - - // Copy the hashtable to the corresponding member variables. This will potentially overwrite - // new tables simultaneously created by a new thread, but maximizes thread safety. - s_cachedRegions = tempHashTable; - } - else - { - // Unable to find a matching culture/region, return null or neutral - // (regionInfo throws a more specific exception on neutrals) - retVal = neutral; - } - - // Return the found culture to use, null, or the neutral culture. - return retVal; - } - - // Clear our internal caches - internal static void ClearCachedData() - { - s_cachedCultures = null; - s_cachedRegions = null; - } - - internal static CultureInfo[] GetCultures(CultureTypes types) - { - // Disable warning 618: System.Globalization.CultureTypes.FrameworkCultures' is obsolete -#pragma warning disable 618 - // Validate flags - if ((int)types <= 0 || ((int)types & (int)~(CultureTypes.NeutralCultures | CultureTypes.SpecificCultures | - CultureTypes.InstalledWin32Cultures | CultureTypes.UserCustomCulture | - CultureTypes.ReplacementCultures | CultureTypes.WindowsOnlyCultures | - CultureTypes.FrameworkCultures)) != 0) - { - throw new ArgumentOutOfRangeException(nameof(types), - SR.Format(SR.ArgumentOutOfRange_Range, CultureTypes.NeutralCultures, CultureTypes.FrameworkCultures)); - } - - // We have deprecated CultureTypes.FrameworkCultures. - // When this enum is used, we will enumerate Whidbey framework cultures (for compatibility). - // - - // We have deprecated CultureTypes.WindowsOnlyCultures. - // When this enum is used, we will return an empty array for this enum. - if ((types & CultureTypes.WindowsOnlyCultures) != 0) - { - // Remove the enum as it is an no-op. - types &= (~CultureTypes.WindowsOnlyCultures); - } - -#pragma warning restore 618 - return EnumCultures(types); - } - - ///////////////////////////////////////////////////////////////////////// - // Build our invariant information - // - // We need an invariant instance, which we build hard-coded - ///////////////////////////////////////////////////////////////////////// - internal static CultureData Invariant - { - get - { - if (s_Invariant == null) - { - // Make a new culturedata - CultureData invariant = new CultureData(); - - // Basics - // Note that we override the resources since this IS NOT supposed to change (by definition) - invariant._bUseOverrides = false; - invariant._sRealName = ""; // Name you passed in (ie: en-US, en, or de-DE_phoneb) - invariant._sWindowsName = ""; // Name OS thinks the object is (ie: de-DE_phoneb, or en-US (even if en was passed in)) - - // Identity - invariant._sName = ""; // locale name (ie: en-us) - invariant._sParent = ""; // Parent name (which may be a custom locale/culture) - invariant._bNeutral = false; // Flags for the culture (ie: neutral or not right now) - invariant._sEnglishDisplayName = "Invariant Language (Invariant Country)"; // English pretty name for this locale - invariant._sNativeDisplayName = "Invariant Language (Invariant Country)"; // Native pretty name for this locale - invariant._sSpecificCulture = ""; // The culture name to be used in CultureInfo.CreateSpecificCulture() - - // Language - invariant._sISO639Language = "iv"; // ISO 639 Language Name - invariant._sISO639Language2 = "ivl"; // 3 char ISO 639 lang name 2 - invariant._sLocalizedLanguage = "Invariant Language"; // Display name for this Language - invariant._sEnglishLanguage = "Invariant Language"; // English name for this language - invariant._sNativeLanguage = "Invariant Language"; // Native name of this language - invariant._sAbbrevLang = "IVL"; // abbreviated language name (Windows Language Name) - invariant._sConsoleFallbackName = ""; // The culture name for the console fallback UI culture - invariant._iInputLanguageHandle = 0x07F; // input language handle - - // Region - invariant._sRegionName = "IV"; // (RegionInfo) - invariant._sEnglishCountry = "Invariant Country"; // english country name (RegionInfo) - invariant._sNativeCountry = "Invariant Country"; // native country name (Windows Only) - invariant._sISO3166CountryName = "IV"; // (RegionInfo), ie: US - invariant._sISO3166CountryName2 = "ivc"; // 3 char ISO 3166 country name 2 2(RegionInfo) - invariant._iGeoId = 244; // GeoId (Windows Only) - - // Numbers - invariant._sPositiveSign = "+"; // positive sign - invariant._sNegativeSign = "-"; // negative sign - invariant._iDigits = 2; // number of fractional digits - invariant._iNegativeNumber = 1; // negative number format - invariant._waGrouping = new int[] { 3 }; // grouping of digits - invariant._sDecimalSeparator = "."; // decimal separator - invariant._sThousandSeparator = ","; // thousands separator - invariant._sNaN = "NaN"; // Not a Number - invariant._sPositiveInfinity = "Infinity"; // + Infinity - invariant._sNegativeInfinity = "-Infinity"; // - Infinity - - // Percent - invariant._iNegativePercent = 0; // Negative Percent (0-3) - invariant._iPositivePercent = 0; // Positive Percent (0-11) - invariant._sPercent = "%"; // Percent (%) symbol - invariant._sPerMille = "\x2030"; // PerMille symbol - - // Currency - invariant._sCurrency = "\x00a4"; // local monetary symbol: for international monetary symbol - invariant._sIntlMonetarySymbol = "XDR"; // international monetary symbol (RegionInfo) - invariant._sEnglishCurrency = "International Monetary Fund"; // English name for this currency (Windows Only) - invariant._sNativeCurrency = "International Monetary Fund"; // Native name for this currency (Windows Only) - invariant._iCurrencyDigits = 2; // # local monetary fractional digits - invariant._iCurrency = 0; // positive currency format - invariant._iNegativeCurrency = 0; // negative currency format - invariant._waMonetaryGrouping = new int[] { 3 }; // monetary grouping of digits - invariant._sMonetaryDecimal = "."; // monetary decimal separator - invariant._sMonetaryThousand = ","; // monetary thousands separator - - // Misc - invariant._iMeasure = 0; // system of measurement 0=metric, 1=US (RegionInfo) - invariant._sListSeparator = ","; // list separator - - // Time - invariant._sAM1159 = "AM"; // AM designator - invariant._sPM2359 = "PM"; // PM designator - invariant._saLongTimes = new String[] { "HH:mm:ss" }; // time format - invariant._saShortTimes = new String[] { "HH:mm", "hh:mm tt", "H:mm", "h:mm tt" }; // short time format - invariant._saDurationFormats = new String[] { "HH:mm:ss" }; // time duration format - - - // Calendar specific data - invariant._iFirstDayOfWeek = 0; // first day of week - invariant._iFirstWeekOfYear = 0; // first week of year - invariant._waCalendars = new CalendarId[] { CalendarId.GREGORIAN }; // all available calendar type(s). The first one is the default calendar - - // Store for specific data about each calendar - invariant._calendars = new CalendarData[CalendarData.MAX_CALENDARS]; - invariant._calendars[0] = CalendarData.Invariant; - - // Text information - invariant._iReadingLayout = 0; - - // These are desktop only, not coreclr - - invariant._iLanguage = CultureInfo.LOCALE_INVARIANT; // locale ID (0409) - NO sort information - invariant._iDefaultAnsiCodePage = 1252; // default ansi code page ID (ACP) - invariant._iDefaultOemCodePage = 437; // default oem code page ID (OCP or OEM) - invariant._iDefaultMacCodePage = 10000; // default macintosh code page - invariant._iDefaultEbcdicCodePage = 037; // default EBCDIC code page - // Remember it - s_Invariant = invariant; - } - return s_Invariant; - } - } - private volatile static CultureData s_Invariant; - - /////////////// - // Constructors // - /////////////// - // Cache of cultures we've already looked up - private static volatile LowLevelDictionary s_cachedCultures; - private static readonly Lock s_lock = new Lock(); - - internal static CultureData GetCultureData(String cultureName, bool useUserOverride) - { - // First do a shortcut for Invariant - if (String.IsNullOrEmpty(cultureName)) - { - return CultureData.Invariant; - } - - // Try the hash table first - String hashName = AnsiToLower(useUserOverride ? cultureName : cultureName + '*'); - LowLevelDictionary tempHashTable = s_cachedCultures; - if (tempHashTable == null) - { - // No table yet, make a new one - tempHashTable = new LowLevelDictionary(); - } - else - { - // Check the hash table - bool ret; - CultureData retVal; - using (LockHolder.Hold(s_lock)) - { - ret = tempHashTable.TryGetValue(hashName, out retVal); - } - if (ret && retVal != null) - { - return retVal; - } - } - - // Not found in the hash table, need to see if we can build one that works for us - CultureData culture = CreateCultureData(cultureName, useUserOverride); - if (culture == null) - { - return null; - } - - // Found one, add it to the cache - using (LockHolder.Hold(s_lock)) - { - tempHashTable[hashName] = culture; - } - - // Copy the hashtable to the corresponding member variables. This will potentially overwrite - // new tables simultaneously created by a new thread, but maximizes thread safety. - s_cachedCultures = tempHashTable; - - return culture; - } - - private static CultureData CreateCultureData(string cultureName, bool useUserOverride) - { - CultureData culture = new CultureData(); - culture._bUseOverrides = useUserOverride; - culture._sRealName = cultureName; - - // Ask native code if that one's real - if (culture.InitCultureData() == false) - { - if (culture.InitCompatibilityCultureData() == false) - { - return null; - } - } - - return culture; - } - - private bool InitCompatibilityCultureData() - { - // for compatibility handle the deprecated ids: zh-chs, zh-cht - string cultureName = _sRealName; - - string fallbackCultureName; - string realCultureName; - switch (AnsiToLower(cultureName)) - { - case "zh-chs": - fallbackCultureName = "zh-Hans"; - realCultureName = "zh-CHS"; - break; - case "zh-cht": - fallbackCultureName = "zh-Hant"; - realCultureName = "zh-CHT"; - break; - default: - return false; - } - - _sRealName = fallbackCultureName; - if (InitCultureData() == false) - { - return false; - } - // fixup our data - _sName = realCultureName; // the name that goes back to the user - _sParent = fallbackCultureName; - - return true; - } - - // We'd rather people use the named version since this doesn't allow custom locales - internal static CultureData GetCultureData(int culture, bool bUseUserOverride) - { - string localeName = null; - CultureData retVal = null; - - if (culture == CultureInfo.LOCALE_INVARIANT) - return Invariant; - - // Convert the lcid to a name, then use that - // Note that this'll return neutral names (unlike Vista native API) - localeName = LCIDToLocaleName(culture); - - if (!String.IsNullOrEmpty(localeName)) - { - // Valid name, use it - retVal = GetCultureData(localeName, bUseUserOverride); - } - - // If not successful, throw - if (retVal == null) - throw new CultureNotFoundException(nameof(culture), culture, SR.Argument_CultureNotSupported); - - // Return the one we found - return retVal; - } - - //////////////////////////////////////////////////////////////////////// - // - // All the accessors - // - // Accessors for our data object items - // - //////////////////////////////////////////////////////////////////////// - - /////////// - // Identity // - /////////// - - // The real name used to construct the locale (ie: de-DE_phoneb) - internal String CultureName - { - get - { - Debug.Assert(_sRealName != null, "[CultureData.CultureName] Expected _sRealName to be populated by already"); - // since windows doesn't know about zh-CHS and zh-CHT, - // we leave sRealName == zh-Hanx but we still need to - // pretend that it was zh-CHX. - switch (_sName) - { - case "zh-CHS": - case "zh-CHT": - return _sName; - } - return _sRealName; - } - } - - // Are overrides enabled? - internal bool UseUserOverride - { - get - { - return _bUseOverrides; - } - } - - // locale name (ie: de-DE, NO sort information) - internal String SNAME - { - get - { - if (_sName == null) - { - _sName = String.Empty; - } - return _sName; - } - } - - // Parent name (which may be a custom locale/culture) - internal String SPARENT - { - get - { - if (_sParent == null) - { - // Ask using the real name, so that we get parents of neutrals - _sParent = GetLocaleInfo(_sRealName, LocaleStringData.ParentName); - } - return _sParent; - } - } - - // Localized pretty name for this locale (ie: Inglis (estados Unitos)) - internal String SLOCALIZEDDISPLAYNAME - { - get - { - if (_sLocalizedDisplayName == null) - { - if (this.IsSupplementalCustomCulture) - { - if (this.IsNeutralCulture) - { - _sLocalizedDisplayName = this.SNATIVELANGUAGE; - } - else - { - _sLocalizedDisplayName = this.SNATIVEDISPLAYNAME; - } - } - else - { - try - { - const string ZH_CHT = "zh-CHT"; - const string ZH_CHS = "zh-CHS"; - - if (SNAME.Equals(ZH_CHT, StringComparison.OrdinalIgnoreCase)) - { - _sLocalizedDisplayName = GetLanguageDisplayName("zh-Hant"); - } - else if (SNAME.Equals(ZH_CHS, StringComparison.OrdinalIgnoreCase)) - { - _sLocalizedDisplayName = GetLanguageDisplayName("zh-Hans"); - } - else - { - _sLocalizedDisplayName = GetLanguageDisplayName(SNAME); - } - } - catch (Exception) - { - // do nothing - } - } - // If it hasn't been found (Windows 8 and up), fallback to the system - if (String.IsNullOrEmpty(_sLocalizedDisplayName)) - { - // If its neutral use the language name - if (this.IsNeutralCulture) - { - _sLocalizedDisplayName = this.SLOCALIZEDLANGUAGE; - } - else - { - // Usually the UI culture shouldn't be different than what we got from WinRT except - // if DefaultThreadCurrentUICulture was set - CultureInfo ci; - - if (CultureInfo.DefaultThreadCurrentUICulture != null && - ((ci = GetUserDefaultCulture()) != null) && - !CultureInfo.DefaultThreadCurrentUICulture.Name.Equals(ci.Name)) - { - _sLocalizedDisplayName = this.SNATIVEDISPLAYNAME; - } - else - { - _sLocalizedDisplayName = GetLocaleInfo(LocaleStringData.LocalizedDisplayName); - } - } - } - } - - return _sLocalizedDisplayName; - } - } - - // English pretty name for this locale (ie: English (United States)) - internal String SENGDISPLAYNAME - { - get - { - if (_sEnglishDisplayName == null) - { - // If its neutral use the language name - if (this.IsNeutralCulture) - { - _sEnglishDisplayName = this.SENGLISHLANGUAGE; - // differentiate the legacy display names - switch (_sName) - { - case "zh-CHS": - case "zh-CHT": - _sEnglishDisplayName += " Legacy"; - break; - } - } - else - { - _sEnglishDisplayName = GetLocaleInfo(LocaleStringData.EnglishDisplayName); - - // if it isn't found build one: - if (String.IsNullOrEmpty(_sEnglishDisplayName)) - { - // Our existing names mostly look like: - // "English" + "United States" -> "English (United States)" - // "Azeri (Latin)" + "Azerbaijan" -> "Azeri (Latin, Azerbaijan)" - if (this.SENGLISHLANGUAGE[this.SENGLISHLANGUAGE.Length - 1] == ')') - { - // "Azeri (Latin)" + "Azerbaijan" -> "Azeri (Latin, Azerbaijan)" - _sEnglishDisplayName = - this.SENGLISHLANGUAGE.Substring(0, _sEnglishLanguage.Length - 1) + - ", " + this.SENGCOUNTRY + ")"; - } - else - { - // "English" + "United States" -> "English (United States)" - _sEnglishDisplayName = this.SENGLISHLANGUAGE + " (" + this.SENGCOUNTRY + ")"; - } - } - } - } - return _sEnglishDisplayName; - } - } - - // Native pretty name for this locale (ie: Deutsch (Deutschland)) - internal String SNATIVEDISPLAYNAME - { - get - { - if (_sNativeDisplayName == null) - { - // If its neutral use the language name - if (this.IsNeutralCulture) - { - _sNativeDisplayName = this.SNATIVELANGUAGE; - // differentiate the legacy display names - switch (_sName) - { - case "zh-CHS": - _sNativeDisplayName += " \u65E7\u7248"; - break; - case "zh-CHT": - _sNativeDisplayName += " \u820A\u7248"; - break; - } - } - else - { - _sNativeDisplayName = GetLocaleInfo(LocaleStringData.NativeDisplayName); - - // if it isn't found build one: - if (String.IsNullOrEmpty(_sNativeDisplayName)) - { - // These should primarily be "Deutsch (Deutschland)" type names - _sNativeDisplayName = this.SNATIVELANGUAGE + " (" + this.SNATIVECOUNTRY + ")"; - } - } - } - return _sNativeDisplayName; - } - } - - // The culture name to be used in CultureInfo.CreateSpecificCulture() - internal string SSPECIFICCULTURE - { - get - { - // This got populated during the culture initialization - Debug.Assert(_sSpecificCulture != null, "[CultureData.SSPECIFICCULTURE] Expected this.sSpecificCulture to be populated by culture data initialization already"); - return _sSpecificCulture; - } - } - - ///////////// - // Language // - ///////////// - - // iso 639 language name, ie: en - internal String SISO639LANGNAME - { - get - { - if (_sISO639Language == null) - { - _sISO639Language = GetLocaleInfo(LocaleStringData.Iso639LanguageTwoLetterName); - } - return _sISO639Language; - } - } - - // iso 639 language name, ie: eng - internal string SISO639LANGNAME2 - { - get - { - if (_sISO639Language2 == null) - { - _sISO639Language2 = GetLocaleInfo(LocaleStringData.Iso639LanguageThreeLetterName); - } - return _sISO639Language2; - } - } - - // abbreviated windows language name (ie: enu) (non-standard, avoid this) - internal string SABBREVLANGNAME - { - get - { - if (_sAbbrevLang == null) - { - _sAbbrevLang = GetThreeLetterWindowsLanguageName(_sRealName); - } - return _sAbbrevLang; - } - } - - // Localized name for this language (Windows Only) ie: Inglis - // This is only valid for Windows 8 and higher neutrals: - internal String SLOCALIZEDLANGUAGE - { - get - { - if (_sLocalizedLanguage == null) - { - // Usually the UI culture shouldn't be different than what we got from WinRT except - // if DefaultThreadCurrentUICulture was set - CultureInfo ci; - - if (CultureInfo.DefaultThreadCurrentUICulture != null && - ((ci = GetUserDefaultCulture()) != null) && - !CultureInfo.DefaultThreadCurrentUICulture.Name.Equals(ci.Name)) - { - _sLocalizedLanguage = SNATIVELANGUAGE; - } - else - { - _sLocalizedLanguage = GetLocaleInfo(LocaleStringData.LocalizedLanguageName); - } - } - - return _sLocalizedLanguage; - } - } - - // English name for this language (Windows Only) ie: German - internal String SENGLISHLANGUAGE - { - get - { - if (_sEnglishLanguage == null) - { - _sEnglishLanguage = GetLocaleInfo(LocaleStringData.EnglishLanguageName); - } - return _sEnglishLanguage; - } - } - - // Native name of this language (Windows Only) ie: Deutsch - internal String SNATIVELANGUAGE - { - get - { - if (_sNativeLanguage == null) - { - _sNativeLanguage = GetLocaleInfo(LocaleStringData.NativeLanguageName); - } - return _sNativeLanguage; - } - } - - /////////// - // Region // - /////////// - - // region name (eg US) - internal String SREGIONNAME - { - get - { - if (_sRegionName == null) - { - _sRegionName = GetLocaleInfo(LocaleStringData.Iso3166CountryName); - } - return _sRegionName; - } - } - - internal int IGEOID - { - get - { - if (_iGeoId == undef) - { - _iGeoId = GetGeoId(_sRealName); - } - return _iGeoId; - } - } - - // localized name for the country - internal string SLOCALIZEDCOUNTRY - { - get - { - if (_sLocalizedCountry == null) - { - try - { - _sLocalizedCountry = GetRegionDisplayName(SISO3166CTRYNAME); - } - catch (Exception) - { - // do nothing. we'll fallback - } - - if (_sLocalizedCountry == null) - { - _sLocalizedCountry = SNATIVECOUNTRY; - } - } - return _sLocalizedCountry; - } - } - - // english country name (RegionInfo) ie: Germany - internal String SENGCOUNTRY - { - get - { - if (_sEnglishCountry == null) - { - _sEnglishCountry = GetLocaleInfo(LocaleStringData.EnglishCountryName); - } - return _sEnglishCountry; - } - } - - // native country name (RegionInfo) ie: Deutschland - internal String SNATIVECOUNTRY - { - get - { - if (_sNativeCountry == null) - { - _sNativeCountry = GetLocaleInfo(LocaleStringData.NativeCountryName); - } - return _sNativeCountry; - } - } - - // ISO 3166 Country Name - internal String SISO3166CTRYNAME - { - get - { - if (_sISO3166CountryName == null) - { - _sISO3166CountryName = GetLocaleInfo(LocaleStringData.Iso3166CountryName); - } - return _sISO3166CountryName; - } - } - - // 3 letter ISO 3166 country code - internal String SISO3166CTRYNAME2 - { - get - { - if (_sISO3166CountryName2 == null) - { - _sISO3166CountryName2 = GetLocaleInfo(LocaleStringData.Iso3166CountryName2); - } - return _sISO3166CountryName2; - } - } - - internal int IINPUTLANGUAGEHANDLE - { - get - { - if (_iInputLanguageHandle == undef) - { - if (IsSupplementalCustomCulture) - { - _iInputLanguageHandle = 0x0409; - } - else - { - // Input Language is same as LCID for built-in cultures - _iInputLanguageHandle = this.ILANGUAGE; - } - } - return _iInputLanguageHandle; - } - } - - // Console fallback name (ie: locale to use for console apps for unicode-only locales) - internal string SCONSOLEFALLBACKNAME - { - get - { - if (_sConsoleFallbackName == null) - { - _sConsoleFallbackName = GetConsoleFallbackName(_sRealName); - } - return _sConsoleFallbackName; - } - } - - // (user can override) grouping of digits - internal int[] WAGROUPING - { - get - { - if (_waGrouping == null) - { - _waGrouping = GetLocaleInfo(LocaleGroupingData.Digit); - } - return _waGrouping; - } - } - - - // internal String sDecimalSeparator ; // (user can override) decimal separator - // internal String sThousandSeparator ; // (user can override) thousands separator - - // Not a Number - internal String SNAN - { - get - { - if (_sNaN == null) - { - _sNaN = GetLocaleInfo(LocaleStringData.NaNSymbol); - } - return _sNaN; - } - } - - // + Infinity - internal String SPOSINFINITY - { - get - { - if (_sPositiveInfinity == null) - { - _sPositiveInfinity = GetLocaleInfo(LocaleStringData.PositiveInfinitySymbol); - } - return _sPositiveInfinity; - } - } - - // - Infinity - internal String SNEGINFINITY - { - get - { - if (_sNegativeInfinity == null) - { - _sNegativeInfinity = GetLocaleInfo(LocaleStringData.NegativeInfinitySymbol); - } - return _sNegativeInfinity; - } - } - - - //////////// - // Percent // - /////////// - - // Negative Percent (0-3) - internal int INEGATIVEPERCENT - { - get - { - if (_iNegativePercent == undef) - { - // Note that <= Windows Vista this is synthesized by native code - _iNegativePercent = GetLocaleInfo(LocaleNumberData.NegativePercentFormat); - } - return _iNegativePercent; - } - } - - // Positive Percent (0-11) - internal int IPOSITIVEPERCENT - { - get - { - if (_iPositivePercent == undef) - { - // Note that <= Windows Vista this is synthesized by native code - _iPositivePercent = GetLocaleInfo(LocaleNumberData.PositivePercentFormat); - } - return _iPositivePercent; - } - } - - // Percent (%) symbol - internal String SPERCENT - { - get - { - if (_sPercent == null) - { - _sPercent = GetLocaleInfo(LocaleStringData.PercentSymbol); - } - return _sPercent; - } - } - - // PerMille symbol - internal String SPERMILLE - { - get - { - if (_sPerMille == null) - { - _sPerMille = GetLocaleInfo(LocaleStringData.PerMilleSymbol); - } - return _sPerMille; - } - } - - ///////////// - // Currency // - ///////////// - - // (user can override) local monetary symbol, eg: $ - internal String SCURRENCY - { - get - { - if (_sCurrency == null) - { - _sCurrency = GetLocaleInfo(LocaleStringData.MonetarySymbol); - } - return _sCurrency; - } - } - - // international monetary symbol (RegionInfo), eg: USD - internal String SINTLSYMBOL - { - get - { - if (_sIntlMonetarySymbol == null) - { - _sIntlMonetarySymbol = GetLocaleInfo(LocaleStringData.Iso4217MonetarySymbol); - } - return _sIntlMonetarySymbol; - } - } - - // English name for this currency (RegionInfo), eg: US Dollar - internal String SENGLISHCURRENCY - { - get - { - if (_sEnglishCurrency == null) - { - _sEnglishCurrency = GetLocaleInfo(LocaleStringData.CurrencyEnglishName); - } - return _sEnglishCurrency; - } - } - - // Native name for this currency (RegionInfo), eg: Schweiz Frank - internal String SNATIVECURRENCY - { - get - { - if (_sNativeCurrency == null) - { - _sNativeCurrency = GetLocaleInfo(LocaleStringData.CurrencyNativeName); - } - return _sNativeCurrency; - } - } - - // internal int iCurrencyDigits ; // (user can override) # local monetary fractional digits - // internal int iCurrency ; // (user can override) positive currency format - // internal int iNegativeCurrency ; // (user can override) negative currency format - - // (user can override) monetary grouping of digits - internal int[] WAMONGROUPING - { - get - { - if (_waMonetaryGrouping == null) - { - _waMonetaryGrouping = GetLocaleInfo(LocaleGroupingData.Monetary); - } - return _waMonetaryGrouping; - } - } - - // (user can override) system of measurement 0=metric, 1=US (RegionInfo) - internal int IMEASURE - { - get - { - if (_iMeasure == undef) - { - _iMeasure = GetLocaleInfo(LocaleNumberData.MeasurementSystem); - } - return _iMeasure; - } - } - - // (user can override) list Separator - internal String SLIST - { - get - { - if (_sListSeparator == null) - { - _sListSeparator = GetLocaleInfo(LocaleStringData.ListSeparator); - } - return _sListSeparator; - } - } - - - //////////////////////////// - // Calendar/Time (Gregorian) // - //////////////////////////// - - // (user can override) AM designator - internal String SAM1159 - { - get - { - if (_sAM1159 == null) - { - _sAM1159 = GetLocaleInfo(LocaleStringData.AMDesignator); - } - return _sAM1159; - } - } - - // (user can override) PM designator - internal String SPM2359 - { - get - { - if (_sPM2359 == null) - { - _sPM2359 = GetLocaleInfo(LocaleStringData.PMDesignator); - } - return _sPM2359; - } - } - - // (user can override) time format - internal String[] LongTimes - { - get - { - if (_saLongTimes == null) - { - String[] longTimes = GetTimeFormats(); - if (longTimes == null || longTimes.Length == 0) - { - _saLongTimes = Invariant._saLongTimes; - } - else - { - _saLongTimes = longTimes; - } - } - return _saLongTimes; - } - } - - // short time format - // Short times (derived from long times format) - // TODO: NLS Arrowhead - On Windows 7 we should have short times so this isn't necessary - internal String[] ShortTimes - { - get - { - if (_saShortTimes == null) - { - // Try to get the short times from the OS/culture.dll - String[] shortTimes = null; - shortTimes = GetShortTimeFormats(); - - if (shortTimes == null || shortTimes.Length == 0) - { - // - // If we couldn't find short times, then compute them from long times - // (eg: CORECLR on < Win7 OS & fallback for missing culture.dll) - // - shortTimes = DeriveShortTimesFromLong(); - } - - /* The above logic doesn't make sense on Mac, since the OS can provide us a "short time pattern". - * currently this is the 4th element in the array returned by LongTimes. We'll add this to our array - * if it doesn't exist. - */ - shortTimes = AdjustShortTimesForMac(shortTimes); - - // Found short times, use them - _saShortTimes = shortTimes; - } - return _saShortTimes; - } - } - - private string[] AdjustShortTimesForMac(string[] shortTimes) - { - return shortTimes; - } - - private string[] DeriveShortTimesFromLong() - { - // Our logic is to look for h,H,m,s,t. If we find an s, then we check the string - // between it and the previous marker, if any. If its a short, unescaped separator, - // then we don't retain that part. - // We then check after the ss and remove anything before the next h,H,m,t... - string[] shortTimes = new string[LongTimes.Length]; - - for (int i = 0; i < LongTimes.Length; i++) - { - shortTimes[i] = StripSecondsFromPattern(LongTimes[i]); - } - return shortTimes; - } - - private static string StripSecondsFromPattern(string time) - { - bool bEscape = false; - int iLastToken = -1; - - // Find the seconds - for (int j = 0; j < time.Length; j++) - { - // Change escape mode? - if (time[j] == '\'') - { - // Continue - bEscape = !bEscape; - continue; - } - - // See if there was a single \ - if (time[j] == '\\') - { - // Skip next char - j++; - continue; - } - - if (bEscape) - { - continue; - } - - switch (time[j]) - { - // Check for seconds - case 's': - // Found seconds, see if there was something unescaped and short between - // the last marker and the seconds. Windows says separator can be a - // maximum of three characters (without null) - // If 1st or last characters were ', then ignore it - if ((j - iLastToken) <= 4 && (j - iLastToken) > 1 && - (time[iLastToken + 1] != '\'') && - (time[j - 1] != '\'')) - { - // There was something there we want to remember - if (iLastToken >= 0) - { - j = iLastToken + 1; - } - } - - bool containsSpace; - int endIndex = GetIndexOfNextTokenAfterSeconds(time, j, out containsSpace); - - string sep; - - if (containsSpace) - { - sep = " "; - } - else - { - sep = ""; - } - - time = time.Substring(0, j) + sep + time.Substring(endIndex); - break; - case 'm': - case 'H': - case 'h': - iLastToken = j; - break; - } - } - return time; - } - - private static int GetIndexOfNextTokenAfterSeconds(string time, int index, out bool containsSpace) - { - bool bEscape = false; - containsSpace = false; - for (; index < time.Length; index++) - { - switch (time[index]) - { - case '\'': - bEscape = !bEscape; - continue; - case '\\': - index++; - if (time[index] == ' ') - { - containsSpace = true; - } - continue; - case ' ': - containsSpace = true; - break; - case 't': - case 'm': - case 'H': - case 'h': - if (bEscape) - { - continue; - } - return index; - } - } - containsSpace = false; - return index; - } - - // (user can override) first day of week - internal int IFIRSTDAYOFWEEK - { - get - { - if (_iFirstDayOfWeek == undef) - { - _iFirstDayOfWeek = GetFirstDayOfWeek(); - } - return _iFirstDayOfWeek; - } - } - - // (user can override) first week of year - internal int IFIRSTWEEKOFYEAR - { - get - { - if (_iFirstWeekOfYear == undef) - { - _iFirstWeekOfYear = GetLocaleInfo(LocaleNumberData.FirstWeekOfYear); - } - return _iFirstWeekOfYear; - } - } - - // (user can override default only) short date format - internal String[] ShortDates(CalendarId calendarId) - { - return GetCalendar(calendarId).saShortDates; - } - - // (user can override default only) long date format - internal String[] LongDates(CalendarId calendarId) - { - return GetCalendar(calendarId).saLongDates; - } - - // (user can override) date year/month format. - internal String[] YearMonths(CalendarId calendarId) - { - return GetCalendar(calendarId).saYearMonths; - } - - // day names - internal string[] DayNames(CalendarId calendarId) - { - return GetCalendar(calendarId).saDayNames; - } - - // abbreviated day names - internal string[] AbbreviatedDayNames(CalendarId calendarId) - { - // Get abbreviated day names for this calendar from the OS if necessary - return GetCalendar(calendarId).saAbbrevDayNames; - } - - // The super short day names - internal string[] SuperShortDayNames(CalendarId calendarId) - { - return GetCalendar(calendarId).saSuperShortDayNames; - } - - // month names - internal string[] MonthNames(CalendarId calendarId) - { - return GetCalendar(calendarId).saMonthNames; - } - - // Genitive month names - internal string[] GenitiveMonthNames(CalendarId calendarId) - { - return GetCalendar(calendarId).saMonthGenitiveNames; - } - - // month names - internal string[] AbbreviatedMonthNames(CalendarId calendarId) - { - return GetCalendar(calendarId).saAbbrevMonthNames; - } - - // Genitive month names - internal string[] AbbreviatedGenitiveMonthNames(CalendarId calendarId) - { - return GetCalendar(calendarId).saAbbrevMonthGenitiveNames; - } - - // Leap year month names - // Note: This only applies to Hebrew, and it basically adds a "1" to the 6th month name - // the non-leap names skip the 7th name in the normal month name array - internal string[] LeapYearMonthNames(CalendarId calendarId) - { - return GetCalendar(calendarId).saLeapYearMonthNames; - } - - // month/day format (single string, no override) - internal String MonthDay(CalendarId calendarId) - { - return GetCalendar(calendarId).sMonthDay; - } - - - - ///////////// - // Calendars // - ///////////// - - // all available calendar type(s), The first one is the default calendar. - internal CalendarId[] CalendarIds - { - get - { - if (_waCalendars == null) - { - // We pass in an array of ints, and native side fills it up with count calendars. - // We then have to copy that list to a new array of the right size. - // Default calendar should be first - CalendarId[] calendars = new CalendarId[23]; - Debug.Assert(_sWindowsName != null, "[CultureData.CalendarIds] Expected _sWindowsName to be populated by already"); - int count = CalendarData.GetCalendars(_sWindowsName, _bUseOverrides, calendars); - - // See if we had a calendar to add. - if (count == 0) - { - // Failed for some reason, just grab Gregorian from Invariant - _waCalendars = Invariant._waCalendars; - } - else - { - // The OS may not return calendar 4 for zh-TW, but we've always allowed it. - // TODO: Is this hack necessary long-term? - if (_sWindowsName == "zh-TW") - { - bool found = false; - - // Do we need to insert calendar 4? - for (int i = 0; i < count; i++) - { - // Stop if we found calendar four - if (calendars[i] == CalendarId.TAIWAN) - { - found = true; - break; - } - } - - // If not found then insert it - if (!found) - { - // Insert it as the 2nd calendar - count++; - // Copy them from the 2nd position to the end, -1 for skipping 1st, -1 for one being added. - Array.Copy(calendars, 1, calendars, 2, 23 - 1 - 1); - calendars[1] = CalendarId.TAIWAN; - } - } - - // It worked, remember the list - CalendarId[] temp = new CalendarId[count]; - Array.Copy(calendars, temp, count); - - // Want 1st calendar to be default - // Prior to Vista the enumeration didn't have default calendar first - if (temp.Length > 1) - { - CalendarId i = (CalendarId)GetLocaleInfo(LocaleNumberData.CalendarType); - if (temp[1] == i) - { - temp[1] = temp[0]; - temp[0] = i; - } - } - - _waCalendars = temp; - } - } - - return _waCalendars; - } - } - - // Native calendar names. index of optional calendar - 1, empty if no optional calendar at that number - internal string CalendarName(CalendarId calendarId) - { - // Get the calendar - return GetCalendar(calendarId).sNativeName; - } - - internal CalendarData GetCalendar(CalendarId calendarId) - { - Debug.Assert(calendarId > 0 && calendarId <= CalendarId.LAST_CALENDAR, - "[CultureData.GetCalendar] Expect calendarId to be in a valid range"); - - // arrays are 0 based, calendarIds are 1 based - int calendarIndex = (int)calendarId - 1; - - // Have to have calendars - if (_calendars == null) - { - _calendars = new CalendarData[CalendarData.MAX_CALENDARS]; - } - - // we need the following local variable to avoid returning null - // when another thread creates a new array of CalendarData (above) - // right after we insert the newly created CalendarData (below) - CalendarData calendarData = _calendars[calendarIndex]; - // Make sure that calendar has data - if (calendarData == null) - { - Debug.Assert(_sWindowsName != null, "[CultureData.GetCalendar] Expected _sWindowsName to be populated by already"); - calendarData = new CalendarData(_sWindowsName, calendarId, this.UseUserOverride); - _calendars[calendarIndex] = calendarData; - } - - return calendarData; - } - - /////////////////// - // Text Information // - /////////////////// - - // IsRightToLeft - internal bool IsRightToLeft - { - get - { - // Returns one of the following 4 reading layout values: - // 0 - Left to right (eg en-US) - // 1 - Right to left (eg arabic locales) - // 2 - Vertical top to bottom with columns to the left and also left to right (ja-JP locales) - // 3 - Vertical top to bottom with columns proceeding to the right - return (this.IREADINGLAYOUT == 1); - } - } - - // IREADINGLAYOUT - // Returns one of the following 4 reading layout values: - // 0 - Left to right (eg en-US) - // 1 - Right to left (eg arabic locales) - // 2 - Vertical top to bottom with columns to the left and also left to right (ja-JP locales) - // 3 - Vertical top to bottom with columns proceeding to the right - // - // If exposed as a public API, we'd have an enum with those 4 values - private int IREADINGLAYOUT - { - get - { - if (_iReadingLayout == undef) - { - Debug.Assert(_sRealName != null, "[CultureData.IsRightToLeft] Expected _sRealName to be populated by already"); - _iReadingLayout = GetLocaleInfo(LocaleNumberData.ReadingLayout); - } - - return (_iReadingLayout); - } - } - - // The TextInfo name never includes that alternate sort and is always specific - // For customs, it uses the SortLocale (since the textinfo is not exposed in Win7) - // en -> en-US - // en-US -> en-US - // fj (custom neutral) -> en-US (assuming that en-US is the sort locale for fj) - // fj_FJ (custom specific) -> en-US (assuming that en-US is the sort locale for fj-FJ) - // es-ES_tradnl -> es-ES - internal String STEXTINFO // Text info name to use for text information - { - get - { - // Note: Custom cultures might point at another culture's textinfo, however windows knows how - // to redirect it to the desired textinfo culture, so this is OK. - Debug.Assert(_sRealName != null, "[CultureData.STEXTINFO] Expected _sRealName to be populated by already"); - return (_sRealName); - } - } - - // Compare info name (including sorting key) to use if custom - internal String SCOMPAREINFO - { - get - { - Debug.Assert(_sRealName != null, "[CultureData.SCOMPAREINFO] Expected _sRealName to be populated by already"); - return (_sRealName); - } - } - - internal bool IsSupplementalCustomCulture - { - get - { - return IsCustomCultureId(this.ILANGUAGE); - } - } - - internal int IDEFAULTANSICODEPAGE // default ansi code page ID (ACP) - { - get - { - if (_iDefaultAnsiCodePage == undef) - { - _iDefaultAnsiCodePage = GetAnsiCodePage(_sRealName); - } - return _iDefaultAnsiCodePage; - } - } - - internal int IDEFAULTOEMCODEPAGE // default oem code page ID (OCP or OEM) - { - get - { - if (_iDefaultOemCodePage == undef) - { - _iDefaultOemCodePage = GetOemCodePage(_sRealName); - } - return _iDefaultOemCodePage; - } - } - - internal int IDEFAULTMACCODEPAGE // default macintosh code page - { - get - { - if (_iDefaultMacCodePage == undef) - { - _iDefaultMacCodePage = GetMacCodePage(_sRealName); - } - return _iDefaultMacCodePage; - } - } - - internal int IDEFAULTEBCDICCODEPAGE // default EBCDIC code page - { - get - { - if (_iDefaultEbcdicCodePage == undef) - { - _iDefaultEbcdicCodePage = GetEbcdicCodePage(_sRealName); - } - return _iDefaultEbcdicCodePage; - } - } - - internal int ILANGUAGE - { - get - { - if (_iLanguage == 0) - { - Debug.Assert(_sRealName != null, "[CultureData.ILANGUAGE] Expected this.sRealName to be populated by COMNlsInfo::nativeInitCultureData already"); - _iLanguage = LocaleNameToLCID(_sRealName); - } - return _iLanguage; - } - } - - internal bool IsNeutralCulture - { - get - { - // InitCultureData told us if we're neutral or not - return _bNeutral; - } - } - - internal bool IsInvariantCulture - { - get - { - return String.IsNullOrEmpty(this.SNAME); - } - } - - // Get an instance of our default calendar - internal Calendar DefaultCalendar - { - get - { - CalendarId defaultCalId = (CalendarId)GetLocaleInfo(LocaleNumberData.CalendarType); - - if (defaultCalId == 0) - { - defaultCalId = this.CalendarIds[0]; - } - - return CultureInfo.GetCalendarInstance(defaultCalId); - } - } - - // All of our era names - internal String[] EraNames(CalendarId calendarId) - { - Debug.Assert(calendarId > 0, "[CultureData.saEraNames] Expected Calendar.ID > 0"); - - return this.GetCalendar(calendarId).saEraNames; - } - - internal String[] AbbrevEraNames(CalendarId calendarId) - { - Debug.Assert(calendarId > 0, "[CultureData.saAbbrevEraNames] Expected Calendar.ID > 0"); - - return this.GetCalendar(calendarId).saAbbrevEraNames; - } - - internal String[] AbbreviatedEnglishEraNames(CalendarId calendarId) - { - Debug.Assert(calendarId > 0, "[CultureData.saAbbrevEraNames] Expected Calendar.ID > 0"); - - return this.GetCalendar(calendarId).saAbbrevEnglishEraNames; - } - - //// String array DEFAULTS - //// Note: GetDTFIOverrideValues does the user overrides for these, so we don't have to. - - - // Time separator (derived from time format) - internal String TimeSeparator - { - get - { - if (_sTimeSeparator == null) - { - string longTimeFormat = GetTimeFormatString(); - if (String.IsNullOrEmpty(longTimeFormat)) - { - longTimeFormat = LongTimes[0]; - } - - // Compute STIME from time format - _sTimeSeparator = GetTimeSeparator(longTimeFormat); - } - return _sTimeSeparator; - } - } - - // Date separator (derived from short date format) - internal String DateSeparator(CalendarId calendarId) - { - return GetDateSeparator(ShortDates(calendarId)[0]); - } - - ////////////////////////////////////// - // Helper Functions to get derived properties // - ////////////////////////////////////// - - //////////////////////////////////////////////////////////////////////////// - // - // Unescape a NLS style quote string - // - // This removes single quotes: - // 'fred' -> fred - // 'fred -> fred - // fred' -> fred - // fred's -> freds - // - // This removes the first \ of escaped characters: - // fred\'s -> fred's - // a\\b -> a\b - // a\b -> ab - // - // We don't build the stringbuilder unless we find a ' or a \. If we find a ' or a \, we - // always build a stringbuilder because we need to remove the ' or \. - // - //////////////////////////////////////////////////////////////////////////// - private static String UnescapeNlsString(String str, int start, int end) - { - Debug.Assert(str != null); - Debug.Assert(start >= 0); - Debug.Assert(end >= 0); - StringBuilder result = null; - - for (int i = start; i < str.Length && i <= end; i++) - { - switch (str[i]) - { - case '\'': - if (result == null) - { - result = new StringBuilder(str, start, i - start, str.Length); - } - break; - case '\\': - if (result == null) - { - result = new StringBuilder(str, start, i - start, str.Length); - } - ++i; - if (i < str.Length) - { - result.Append(str[i]); - } - break; - default: - if (result != null) - { - result.Append(str[i]); - } - break; - } - } - - if (result == null) - return (str.Substring(start, end - start + 1)); - - return (result.ToString()); - } - - private static String GetTimeSeparator(String format) - { - // Time format separator (ie: : in 12:39:00) - // - // We calculate this from the provided time format - // - - // - // Find the time separator so that we can pretend we know STIME. - // - return GetSeparator(format, "Hhms"); - } - - private static String GetDateSeparator(String format) - { - // Date format separator (ie: / in 9/1/03) - // - // We calculate this from the provided short date - // - - // - // Find the date separator so that we can pretend we know SDATE. - // - return GetSeparator(format, "dyM"); - } - - private static string GetSeparator(string format, string timeParts) - { - int index = IndexOfTimePart(format, 0, timeParts); - - if (index != -1) - { - // Found a time part, find out when it changes - char cTimePart = format[index]; - - do - { - index++; - } while (index < format.Length && format[index] == cTimePart); - - int separatorStart = index; - - // Now we need to find the end of the separator - if (separatorStart < format.Length) - { - int separatorEnd = IndexOfTimePart(format, separatorStart, timeParts); - if (separatorEnd != -1) - { - // From [separatorStart, count) is our string, except we need to unescape - return UnescapeNlsString(format, separatorStart, separatorEnd - 1); - } - } - } - - return String.Empty; - } - - private static int IndexOfTimePart(string format, int startIndex, string timeParts) - { - Debug.Assert(startIndex >= 0, "startIndex cannot be negative"); - Debug.Assert(timeParts.IndexOfAny(new char[] { '\'', '\\' }) == -1, "timeParts cannot include quote characters"); - bool inQuote = false; - for (int i = startIndex; i < format.Length; ++i) - { - // See if we have a time Part - if (!inQuote && timeParts.IndexOf(format[i]) != -1) - { - return i; - } - switch (format[i]) - { - case '\\': - if (i + 1 < format.Length) - { - ++i; - switch (format[i]) - { - case '\'': - case '\\': - break; - default: - --i; //backup since we will move over this next - break; - } - } - break; - case '\'': - inQuote = !inQuote; - break; - } - } - - return -1; - } - - internal static bool IsCustomCultureId(int cultureId) - { - return (cultureId == CultureInfo.LOCALE_CUSTOM_DEFAULT || cultureId == CultureInfo.LOCALE_CUSTOM_UNSPECIFIED); - } - - internal void GetNFIValues(NumberFormatInfo nfi) - { - if (this.IsInvariantCulture) - { - // FUTURE: NumberFormatInfo already has default values for many of these fields. Can we not do this? - nfi.positiveSign = _sPositiveSign; - nfi.negativeSign = _sNegativeSign; - - nfi.numberGroupSeparator = _sThousandSeparator; - nfi.numberDecimalSeparator = _sDecimalSeparator; - nfi.numberDecimalDigits = _iDigits; - nfi.numberNegativePattern = _iNegativeNumber; - - nfi.currencySymbol = _sCurrency; - nfi.currencyGroupSeparator = _sMonetaryThousand; - nfi.currencyDecimalSeparator = _sMonetaryDecimal; - nfi.currencyDecimalDigits = _iCurrencyDigits; - nfi.currencyNegativePattern = _iNegativeCurrency; - nfi.currencyPositivePattern = _iCurrency; - } - else - { - Debug.Assert(_sWindowsName != null, "[CultureData.GetNFIValues] Expected _sWindowsName to be populated by already"); - // String values - nfi.positiveSign = GetLocaleInfo(LocaleStringData.PositiveSign); - nfi.negativeSign = GetLocaleInfo(LocaleStringData.NegativeSign); - - nfi.numberDecimalSeparator = GetLocaleInfo(LocaleStringData.DecimalSeparator); - nfi.numberGroupSeparator = GetLocaleInfo(LocaleStringData.ThousandSeparator); - nfi.currencyGroupSeparator = GetLocaleInfo(LocaleStringData.MonetaryThousandSeparator); - nfi.currencyDecimalSeparator = GetLocaleInfo(LocaleStringData.MonetaryDecimalSeparator); - nfi.currencySymbol = GetLocaleInfo(LocaleStringData.MonetarySymbol); - - // Numeric values - nfi.numberDecimalDigits = GetLocaleInfo(LocaleNumberData.FractionalDigitsCount); - nfi.currencyDecimalDigits = GetLocaleInfo(LocaleNumberData.MonetaryFractionalDigitsCount); - nfi.currencyPositivePattern = GetLocaleInfo(LocaleNumberData.PositiveMonetaryNumberFormat); - nfi.currencyNegativePattern = GetLocaleInfo(LocaleNumberData.NegativeMonetaryNumberFormat); - nfi.numberNegativePattern = GetLocaleInfo(LocaleNumberData.NegativeNumberFormat); - - // LOCALE_SNATIVEDIGITS (array of 10 single character strings). - string digits = GetLocaleInfo(LocaleStringData.Digits); - nfi.nativeDigits = new string[10]; - for (int i = 0; i < nfi.nativeDigits.Length; i++) - { - nfi.nativeDigits[i] = new string(digits[i], 1); - } - - nfi.digitSubstitution = GetDigitSubstitution(_sRealName); - } - - // - // Gather additional data - // - nfi.numberGroupSizes = this.WAGROUPING; - nfi.currencyGroupSizes = this.WAMONGROUPING; - - // prefer the cached value since these do not have user overrides - nfi.percentNegativePattern = this.INEGATIVEPERCENT; - nfi.percentPositivePattern = this.IPOSITIVEPERCENT; - nfi.percentSymbol = this.SPERCENT; - nfi.perMilleSymbol = this.SPERMILLE; - - nfi.negativeInfinitySymbol = this.SNEGINFINITY; - nfi.positiveInfinitySymbol = this.SPOSINFINITY; - nfi.nanSymbol = this.SNAN; - - // - // We don't have percent values, so use the number values - // - nfi.percentDecimalDigits = nfi.numberDecimalDigits; - nfi.percentDecimalSeparator = nfi.numberDecimalSeparator; - nfi.percentGroupSizes = nfi.numberGroupSizes; - nfi.percentGroupSeparator = nfi.numberGroupSeparator; - - // - // Clean up a few odd values - // - - // Windows usually returns an empty positive sign, but we like it to be "+" - if (nfi.positiveSign == null || nfi.positiveSign.Length == 0) nfi.positiveSign = "+"; - - //Special case for Italian. The currency decimal separator in the control panel is the empty string. When the user - //specifies C4 as the currency format, this results in the number apparently getting multiplied by 10000 because the - //decimal point doesn't show up. We'll just hack this here because our default currency format will never use nfi. - if (nfi.currencyDecimalSeparator == null || nfi.currencyDecimalSeparator.Length == 0) - { - nfi.currencyDecimalSeparator = nfi.numberDecimalSeparator; - } - } - - // Helper - // This is ONLY used for caching names and shouldn't be used for anything else - internal static string AnsiToLower(string testString) - { - int index = 0; - - while (index < testString.Length && (testString[index] < 'A' || testString[index] > 'Z')) - { - index++; - } - if (index >= testString.Length) - { - return testString; // we didn't really change the string - } - - StringBuilder sb = new StringBuilder(testString.Length); - for (int i = 0; i < index; i++) - { - sb.Append(testString[i]); - } - - sb.Append((char)(testString[index] - 'A' + 'a')); - - for (int ich = index + 1; ich < testString.Length; ich++) - { - char ch = testString[ich]; - sb.Append(ch <= 'Z' && ch >= 'A' ? (char)(ch - 'A' + 'a') : ch); - } - - return (sb.ToString()); - } - - /// - /// The numeric values of the enum members match their Win32 counterparts. The CultureData Win32 PAL implementation - /// takes a dependency on this fact, in order to prevent having to construct a mapping from internal values to LCTypes. - /// - private enum LocaleStringData : uint - { - /// localized name of locale, eg "German (Germany)" in UI language (coresponds to LOCALE_SLOCALIZEDDISPLAYNAME) - LocalizedDisplayName = 0x00000002, - /// Display name (language + country usually) in English, eg "German (Germany)" (coresponds to LOCALE_SENGLISHDISPLAYNAME) - EnglishDisplayName = 0x00000072, - /// Display name in native locale language, eg "Deutsch (Deutschland) (coresponds to LOCALE_SNATIVEDISPLAYNAME) - NativeDisplayName = 0x00000073, - /// Language Display Name for a language, eg "German" in UI language (coresponds to LOCALE_SLOCALIZEDLANGUAGENAME) - LocalizedLanguageName = 0x0000006f, - /// English name of language, eg "German" (coresponds to LOCALE_SENGLISHLANGUAGENAME) - EnglishLanguageName = 0x00001001, - /// native name of language, eg "Deutsch" (coresponds to LOCALE_SNATIVELANGUAGENAME) - NativeLanguageName = 0x00000004, - /// localized name of country, eg "Germany" in UI language (coresponds to LOCALE_SLOCALIZEDCOUNTRYNAME) - LocalizedCountryName = 0x00000006, - /// English name of country, eg "Germany" (coresponds to LOCALE_SENGLISHCOUNTRYNAME) - EnglishCountryName = 0x00001002, - /// native name of country, eg "Deutschland" (coresponds to LOCALE_SNATIVECOUNTRYNAME) - NativeCountryName = 0x00000008, - /// abbreviated language name (coresponds to LOCALE_SABBREVLANGNAME) - AbbreviatedWindowsLanguageName = 0x00000003, - /// list item separator (coresponds to LOCALE_SLIST) - ListSeparator = 0x0000000C, - /// decimal separator (coresponds to LOCALE_SDECIMAL) - DecimalSeparator = 0x0000000E, - /// thousand separator (coresponds to LOCALE_STHOUSAND) - ThousandSeparator = 0x0000000F, - /// digit grouping (coresponds to LOCALE_SGROUPING) - Digits = 0x00000013, - /// local monetary symbol (coresponds to LOCALE_SCURRENCY) - MonetarySymbol = 0x00000014, - /// English currency name (coresponds to LOCALE_SENGCURRNAME) - CurrencyEnglishName = 0x00001007, - /// Native currency name (coresponds to LOCALE_SNATIVECURRNAME) - CurrencyNativeName = 0x00001008, - /// uintl monetary symbol (coresponds to LOCALE_SINTLSYMBOL) - Iso4217MonetarySymbol = 0x00000015, - /// monetary decimal separator (coresponds to LOCALE_SMONDECIMALSEP) - MonetaryDecimalSeparator = 0x00000016, - /// monetary thousand separator (coresponds to LOCALE_SMONTHOUSANDSEP) - MonetaryThousandSeparator = 0x00000017, - /// AM designator (coresponds to LOCALE_S1159) - AMDesignator = 0x00000028, - /// PM designator (coresponds to LOCALE_S2359) - PMDesignator = 0x00000029, - /// positive sign (coresponds to LOCALE_SPOSITIVESIGN) - PositiveSign = 0x00000050, - /// negative sign (coresponds to LOCALE_SNEGATIVESIGN) - NegativeSign = 0x00000051, - /// ISO abbreviated language name (coresponds to LOCALE_SISO639LANGNAME) - Iso639LanguageTwoLetterName = 0x00000059, - /// ISO abbreviated country name (coresponds to LOCALE_SISO639LANGNAME2) - Iso639LanguageThreeLetterName = 0x00000067, - /// ISO abbreviated language name (coresponds to LOCALE_SISO639LANGNAME) - Iso639LanguageName = 0x00000059, - /// ISO abbreviated country name (coresponds to LOCALE_SISO3166CTRYNAME) - Iso3166CountryName = 0x0000005A, - /// 3 letter ISO country code (coresponds to LOCALE_SISO3166CTRYNAME2) - Iso3166CountryName2 = 0x00000068, // 3 character ISO country name - /// Not a Number (coresponds to LOCALE_SNAN) - NaNSymbol = 0x00000069, - /// + Infinity (coresponds to LOCALE_SPOSINFINITY) - PositiveInfinitySymbol = 0x0000006a, - /// - Infinity (coresponds to LOCALE_SNEGINFINITY) - NegativeInfinitySymbol = 0x0000006b, - /// Fallback name for resources (coresponds to LOCALE_SPARENT) - ParentName = 0x0000006d, - /// Fallback name for within the console (coresponds to LOCALE_SCONSOLEFALLBACKNAME) - ConsoleFallbackName = 0x0000006e, - /// Returns the percent symbol (coresponds to LOCALE_SPERCENT) - PercentSymbol = 0x00000076, - /// Returns the permille (U+2030) symbol (coresponds to LOCALE_SPERMILLE) - PerMilleSymbol = 0x00000077 - } - - /// - /// The numeric values of the enum members match their Win32 counterparts. The CultureData Win32 PAL implementation - /// takes a dependency on this fact, in order to prevent having to construct a mapping from internal values to LCTypes. - /// - private enum LocaleGroupingData : uint - { - /// digit grouping (coresponds to LOCALE_SGROUPING) - Digit = 0x00000010, - /// monetary grouping (coresponds to LOCALE_SMONGROUPING) - Monetary = 0x00000018, - } - - /// - /// The numeric values of the enum members match their Win32 counterparts. The CultureData Win32 PAL implementation - /// takes a dependency on this fact, in order to prevent having to construct a mapping from internal values to LCTypes. - /// - private enum LocaleNumberData : uint - { - /// language id (coresponds to LOCALE_ILANGUAGE) - LanguageId = 0x00000001, - /// geographical location id, (coresponds to LOCALE_IGEOID) - GeoId = 0x0000005B, - /// 0 = context, 1 = none, 2 = national (coresponds to LOCALE_IDIGITSUBSTITUTION) - DigitSubstitution = 0x00001014, - /// 0 = metric, 1 = US (coresponds to LOCALE_IMEASURE) - MeasurementSystem = 0x0000000D, - /// number of fractional digits (coresponds to LOCALE_IDIGITS) - FractionalDigitsCount = 0x00000011, - /// negative number mode (coresponds to LOCALE_INEGNUMBER) - NegativeNumberFormat = 0x00001010, - /// # local monetary digits (coresponds to LOCALE_ICURRDIGITS) - MonetaryFractionalDigitsCount = 0x00000019, - /// positive currency mode (coresponds to LOCALE_ICURRENCY) - PositiveMonetaryNumberFormat = 0x0000001B, - /// negative currency mode (coresponds to LOCALE_INEGCURR) - NegativeMonetaryNumberFormat = 0x0000001C, - /// type of calendar specifier (coresponds to LOCALE_ICALENDARTYPE) - CalendarType = 0x00001009, - /// first day of week specifier (coresponds to LOCALE_IFIRSTDAYOFWEEK) - FirstDayOfWeek = 0x0000100C, - /// first week of year specifier (coresponds to LOCALE_IFIRSTWEEKOFYEAR) - FirstWeekOfYear = 0x0000100D, - /// - /// Returns one of the following 4 reading layout values: - /// 0 - Left to right (eg en-US) - /// 1 - Right to left (eg arabic locales) - /// 2 - Vertical top to bottom with columns to the left and also left to right (ja-JP locales) - /// 3 - Vertical top to bottom with columns proceeding to the right - /// (coresponds to LOCALE_IREADINGLAYOUT) - /// - ReadingLayout = 0x00000070, - /// Returns 0-11 for the negative percent format (coresponds to LOCALE_INEGATIVEPERCENT) - NegativePercentFormat = 0x00000074, - /// Returns 0-3 for the positive percent format (coresponds to LOCALE_IPOSITIVEPERCENT) - PositivePercentFormat = 0x00000075, - /// default ansi code page (coresponds to LOCALE_IDEFAULTCODEPAGE) - OemCodePage = 0x0000000B, - /// default ansi code page (coresponds to LOCALE_IDEFAULTANSICODEPAGE) - AnsiCodePage = 0x00001004, - /// default mac code page (coresponds to LOCALE_IDEFAULTMACCODEPAGE) - MacCodePage = 0x00001011, - /// default ebcdic code page (coresponds to LOCALE_IDEFAULTEBCDICCODEPAGE) - EbcdicCodePage = 0x00001012, - } - } -} diff --git a/external/corert/src/System.Private.CoreLib/src/System/Globalization/CultureInfo.Unix.cs b/external/corert/src/System.Private.CoreLib/src/System/Globalization/CultureInfo.Unix.cs index 5a06bccd48..c50831b09a 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Globalization/CultureInfo.Unix.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Globalization/CultureInfo.Unix.cs @@ -30,5 +30,10 @@ namespace System.Globalization return cultureInfo; } + + private static CultureInfo GetUserDefaultUICulture() + { + return s_userDefaultCulture ?? InitializeUserDefaultCulture(); + } } } diff --git a/external/corert/src/System.Private.CoreLib/src/System/Globalization/CultureInfo.Windows.cs b/external/corert/src/System.Private.CoreLib/src/System/Globalization/CultureInfo.Windows.cs index f5a6992e66..df13759f74 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Globalization/CultureInfo.Windows.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Globalization/CultureInfo.Windows.cs @@ -56,5 +56,36 @@ namespace System.Globalization return temp; } + + private static CultureInfo GetUserDefaultUICulture() + { +#if !ENABLE_WINRT + if (GlobalizationMode.Invariant) + return CultureInfo.InvariantCulture; + + const uint MUI_LANGUAGE_NAME = 0x8; // Use ISO language (culture) name convention + uint langCount = 0; + uint bufLen = 0; + + if (Interop.Kernel32.GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, out langCount, null, ref bufLen)) + { + char[] languages = new char[bufLen]; + if (Interop.Kernel32.GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, out langCount, languages, ref bufLen)) + { + int index = 0; + while (languages[index] != (char)0 && index < languages.Length) + { + index++; + } + + CultureInfo temp = GetCultureByName(new String(languages, 0, index), true); + temp._isReadOnly = true; + return temp; + } + } +#endif + + return s_userDefaultCulture ?? InitializeUserDefaultCulture(); + } } } diff --git a/external/corert/src/System.Private.CoreLib/src/System/Globalization/CultureInfo.cs b/external/corert/src/System.Private.CoreLib/src/System/Globalization/CultureInfo.cs index bc4411ab78..08be455f97 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Globalization/CultureInfo.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Globalization/CultureInfo.cs @@ -80,7 +80,7 @@ namespace System.Globalization // textinfo and compareinfo names are the same as the name // Note that the name used to be serialized for Everett; it is now serialized - // because alernate sorts can have alternate names. + // because alternate sorts can have alternate names. // This has a de-DE, de-DE_phoneb or fj-FJ style name internal string _name; @@ -100,12 +100,8 @@ namespace System.Globalization // //--------------------------------------------------------------------// - //Get the current user default culture. This one is almost always used, so we create it by default. private static volatile CultureInfo s_userDefaultCulture; - - // - // All of the following will be created on demand. - // + private static volatile CultureInfo s_userDefaultUICulture; // WARNING: We allow diagnostic tools to directly inspect these three members (s_InvariantCultureInfo, s_DefaultThreadCurrentUICulture and s_DefaultThreadCurrentCulture) // See https://github.com/dotnet/corert/blob/master/Documentation/design-docs/diagnostics/diagnostics-tools-contract.md for more details. @@ -113,7 +109,7 @@ namespace System.Globalization // Get in touch with the diagnostics team if you have questions. //The Invariant culture; - private static volatile CultureInfo s_InvariantCultureInfo; + private static readonly CultureInfo s_InvariantCultureInfo = new CultureInfo(CultureData.Invariant, isReadOnly: true); //These are defaults that we use if a thread has not opted into having an explicit culture private static volatile CultureInfo s_DefaultThreadCurrentUICulture; @@ -140,23 +136,16 @@ namespace System.Globalization internal const int LOCALE_CUSTOM_DEFAULT = 0x0c00; internal const int LOCALE_INVARIANT = 0x007F; - // - // The CultureData instance that reads the data provided by our CultureData class. - // - // Using a field initializer rather than a static constructor so that the whole class can be lazy - // init. - private static readonly bool s_init = Init(); - private static bool Init() + private static CultureInfo InitializeUserDefaultCulture() { - if (s_InvariantCultureInfo == null) - { - CultureInfo temp = new CultureInfo("", false); - temp._isReadOnly = true; - s_InvariantCultureInfo = temp; - } + Interlocked.CompareExchange(ref s_userDefaultCulture, GetUserDefaultCulture(), null); + return s_userDefaultCulture; + } - s_userDefaultCulture = GetUserDefaultCulture(); - return true; + private static CultureInfo InitializeUserDefaultUICulture() + { + Interlocked.CompareExchange(ref s_userDefaultUICulture, GetUserDefaultUICulture(), null); + return s_userDefaultUICulture; } //////////////////////////////////////////////////////////////////////// @@ -180,22 +169,23 @@ namespace System.Globalization } // Get our data providing record - this._cultureData = CultureData.GetCultureData(name, useUserOverride); + _cultureData = CultureData.GetCultureData(name, useUserOverride); - if (this._cultureData == null) + if (_cultureData == null) throw new CultureNotFoundException( nameof(name), name, SR.Argument_CultureNotSupported); - this._name = this._cultureData.CultureName; - this._isInherited = !this.EETypePtr.FastEquals(EETypePtr.EETypePtrOf()); + _name = _cultureData.CultureName; + _isInherited = !this.EETypePtr.FastEquals(EETypePtr.EETypePtrOf()); } - private CultureInfo(CultureData cultureData) + private CultureInfo(CultureData cultureData, bool isReadOnly = false) { Debug.Assert(cultureData != null); _cultureData = cultureData; _name = cultureData.CultureName; _isInherited = false; + _isReadOnly = isReadOnly; } private static CultureInfo CreateCultureInfoNoThrow(string name, bool useUserOverride) @@ -222,11 +212,6 @@ namespace System.Globalization throw new ArgumentOutOfRangeException(nameof(culture), SR.ArgumentOutOfRange_NeedPosNum); } - InitializeFromCultureId(culture, useUserOverride); - } - - private void InitializeFromCultureId(int culture, bool useUserOverride) - { switch (culture) { case LOCALE_CUSTOM_DEFAULT: @@ -354,15 +339,6 @@ namespace System.Globalization return (new CultureInfo(culture._cultureData.SSPECIFICCULTURE)); } - // // - // // Return a specific culture. A tad irrelevent now since we always return valid data - // // for neutral locales. - // // - // // Note that there's interesting behavior that tries to find a smaller name, ala RFC4647, - // // if we can't find a bigger name. That doesn't help with things like "zh" though, so - // // the approach is of questionable value - // // - internal static bool VerifyCultureName(String cultureName, bool throwException) { // This function is used by ResourceManager.GetResourceFileName(). @@ -439,15 +415,7 @@ namespace System.Globalization return ci; } - // if s_userDefaultCulture == null means CultureInfo statics didn't get initialized yet. this can happen if there early static - // method get executed which eventually hit the cultureInfo code while CultureInfo statics didn't get chance to initialize - if (s_userDefaultCulture == null) - { - Init(); - } - - Debug.Assert(s_userDefaultCulture != null); - return s_userDefaultCulture; + return s_userDefaultCulture ?? InitializeUserDefaultCulture(); } set @@ -491,15 +459,7 @@ namespace System.Globalization return ci; } - // if s_userDefaultCulture == null means CultureInfo statics didn't get initialized yet. this can happen if there early static - // method get executed which eventually hit the cultureInfo code while CultureInfo statics didn't get chance to initialize - if (s_userDefaultCulture == null) - { - Init(); - } - - Debug.Assert(s_userDefaultCulture != null); - return s_userDefaultCulture; + return s_userDefaultUICulture ?? InitializeUserDefaultUICulture(); } set @@ -530,18 +490,9 @@ namespace System.Globalization s_currentThreadUICulture = null; } - public static CultureInfo InstalledUICulture - { - get - { - if (s_userDefaultCulture == null) - { - Init(); - } - Debug.Assert(s_userDefaultCulture != null, "[CultureInfo.InstalledUICulture] s_userDefaultCulture != null"); - return s_userDefaultCulture; - } - } + internal static CultureInfo UserDefaultUICulture => s_userDefaultUICulture ?? InitializeUserDefaultUICulture(); + + public static CultureInfo InstalledUICulture => s_userDefaultCulture ?? InitializeUserDefaultCulture(); public static CultureInfo DefaultThreadCurrentCulture { @@ -593,6 +544,7 @@ namespace System.Globalization { get { + Debug.Assert(s_InvariantCultureInfo != null); return (s_InvariantCultureInfo); } } @@ -823,7 +775,7 @@ namespace System.Globalization // Since CompareInfo's don't have any overrideable properties, get the CompareInfo from // the Non-Overridden CultureInfo so that we only create one CompareInfo per culture CompareInfo temp = UseUserOverride - ? GetCultureInfo(this._name).CompareInfo + ? GetCultureInfo(_name).CompareInfo : new CompareInfo(this); if (OkayToCacheClassWithCompatibilityBehavior) { @@ -860,7 +812,7 @@ namespace System.Globalization if (_textInfo == null) { // Make a new textInfo - TextInfo tempTextInfo = new TextInfo(this._cultureData); + TextInfo tempTextInfo = new TextInfo(_cultureData); tempTextInfo.SetReadOnlyState(_isReadOnly); if (OkayToCacheClassWithCompatibilityBehavior) @@ -950,7 +902,7 @@ namespace System.Globalization { get { - return this._cultureData.IsNeutralCulture; + return _cultureData.IsNeutralCulture; } } @@ -985,7 +937,7 @@ namespace System.Globalization { if (numInfo == null) { - NumberFormatInfo temp = new NumberFormatInfo(this._cultureData); + NumberFormatInfo temp = new NumberFormatInfo(_cultureData); temp.isReadOnly = _isReadOnly; Interlocked.CompareExchange(ref numInfo, temp, null); } @@ -1017,7 +969,7 @@ namespace System.Globalization if (dateTimeInfo == null) { // Change the calendar of DTFI to the specified calendar of this CultureInfo. - DateTimeFormatInfo temp = new DateTimeFormatInfo(this._cultureData, this.Calendar); + DateTimeFormatInfo temp = new DateTimeFormatInfo(_cultureData, this.Calendar); temp._isReadOnly = _isReadOnly; Interlocked.CompareExchange(ref dateTimeInfo, temp, null); } @@ -1037,7 +989,9 @@ namespace System.Globalization public void ClearCachedData() { - s_userDefaultCulture = null; + // reset the default culture values + s_userDefaultCulture = GetUserDefaultCulture(); + s_userDefaultUICulture = GetUserDefaultUICulture(); RegionInfo.s_currentRegionInfo = null; #pragma warning disable 0618 // disable the obsolete warning @@ -1115,10 +1069,10 @@ namespace System.Globalization { if (_calendar == null) { - Debug.Assert(this._cultureData.CalendarIds.Length > 0, "this._cultureData.CalendarIds.Length > 0"); + Debug.Assert(_cultureData.CalendarIds.Length > 0, "_cultureData.CalendarIds.Length > 0"); // Get the default calendar for this culture. Note that the value can be // from registry if this is a user default culture. - Calendar newObj = this._cultureData.DefaultCalendar; + Calendar newObj = _cultureData.DefaultCalendar; System.Threading.Interlocked.MemoryBarrier(); newObj.SetReadOnlyState(_isReadOnly); @@ -1143,7 +1097,7 @@ namespace System.Globalization // // This property always returns a new copy of the calendar array. // - CalendarId[] calID = this._cultureData.CalendarIds; + CalendarId[] calID = _cultureData.CalendarIds; Calendar[] cals = new Calendar[calID.Length]; for (int i = 0; i < cals.Length; i++) { diff --git a/external/corert/src/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.Unix.cs b/external/corert/src/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.Unix.cs index e4ab832d5e..f292d54dce 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.Unix.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.Unix.cs @@ -13,7 +13,7 @@ namespace System.Globalization bool invariantEnabled = false; if (!invariantEnabled) { - if (Interop.GlobalizationInterop.LoadICU() == 0) + if (Interop.Globalization.LoadICU() == 0) { string message = "Couldn't find a valid ICU package installed on the system. " + "Set the configuration flag System.Globalization.Invariant to true if you want to run with no globalization support."; diff --git a/external/corert/src/System.Private.CoreLib/src/System/IO/InternalFile.Windows.cs b/external/corert/src/System.Private.CoreLib/src/System/IO/InternalFile.Windows.cs deleted file mode 100644 index 59dffd7d9e..0000000000 --- a/external/corert/src/System.Private.CoreLib/src/System/IO/InternalFile.Windows.cs +++ /dev/null @@ -1,136 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.Win32; -using Microsoft.Win32.SafeHandles; -using System.Runtime.InteropServices; - -namespace System.IO -{ - internal static partial class InternalFile - { - internal static bool InternalExists(String path) - { - Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA data = new Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA(); - int errorCode = FillAttributeInfo(path, ref data, false, true); - - return (errorCode == 0) && (data.fileAttributes != -1) - && ((data.fileAttributes & Interop.Kernel32.FileAttributes.FILE_ATTRIBUTE_DIRECTORY) == 0); - } - - // Returns 0 on success, otherwise a Win32 error code. Note that - // classes should use -1 as the uninitialized state for dataInitialized. - internal static int FillAttributeInfo(String path, ref Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA data, bool tryagain, bool returnErrorOnNotFound) - { - int errorCode = 0; - if (tryagain) // someone has a handle to the file open, or other error - { - Interop.Kernel32.WIN32_FIND_DATA findData; - findData = new Interop.Kernel32.WIN32_FIND_DATA(); - - // Remove trailing slash since this can cause grief to FindFirstFile. You will get an invalid argument error - String tempPath = path.TrimEnd(new char[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }); - - // For floppy drives, normally the OS will pop up a dialog saying - // there is no disk in drive A:, please insert one. We don't want that. - // SetThreadErrorMode will let us disable this, but we should set the error - // mode back, since this may have wide-ranging effects. - uint oldMode; - bool setThreadErrorModeSuccess = Interop.Kernel32.SetThreadErrorMode(Interop.Kernel32.SEM_FAILCRITICALERRORS, out oldMode); - try - { - bool error = false; - SafeFindHandle handle = Interop.Kernel32.FindFirstFile(tempPath, ref findData); - try - { - if (handle.IsInvalid) - { - error = true; - errorCode = Marshal.GetLastWin32Error(); - - if (errorCode == Interop.Errors.ERROR_FILE_NOT_FOUND || - errorCode == Interop.Errors.ERROR_PATH_NOT_FOUND || - errorCode == Interop.Errors.ERROR_NOT_READY) // floppy device not ready - { - if (!returnErrorOnNotFound) - { - // Return default value for backward compatibility - errorCode = 0; - data.fileAttributes = -1; - } - } - return errorCode; - } - } - finally - { - // Close the Win32 handle - try - { - handle.Dispose(); - } - catch - { - // if we're already returning an error, don't throw another one. - if (!error) - { - throw Win32Marshal.GetExceptionForLastWin32Error(); - } - } - } - } - finally - { - if (setThreadErrorModeSuccess) - Interop.Kernel32.SetThreadErrorMode(oldMode, out oldMode); - } - - // Copy the information to data - data.PopulateFrom(ref findData); - } - else - { - // For floppy drives, normally the OS will pop up a dialog saying - // there is no disk in drive A:, please insert one. We don't want that. - // SetThreadErrorMode will let us disable this, but we should set the error - // mode back, since this may have wide-ranging effects. - bool success = false; - uint oldMode; - bool setThreadErrorModeSuccess = Interop.Kernel32.SetThreadErrorMode(Interop.Kernel32.SEM_FAILCRITICALERRORS, out oldMode); - try - { - success = Interop.Kernel32.GetFileAttributesEx(path, Interop.Kernel32.GET_FILEEX_INFO_LEVELS.GetFileExInfoStandard, ref data); - } - finally - { - if (setThreadErrorModeSuccess) - Interop.Kernel32.SetThreadErrorMode(oldMode, out oldMode); - } - - if (!success) - { - errorCode = Marshal.GetLastWin32Error(); - if (errorCode != Interop.Errors.ERROR_FILE_NOT_FOUND && - errorCode != Interop.Errors.ERROR_PATH_NOT_FOUND && - errorCode != Interop.Errors.ERROR_NOT_READY) // floppy device not ready - { - // In case someone latched onto the file. Take the perf hit only for failure - return FillAttributeInfo(path, ref data, true, returnErrorOnNotFound); - } - else - { - if (!returnErrorOnNotFound) - { - // Return default value for backward compatibility - errorCode = 0; - data.fileAttributes = -1; - } - } - } - } - - return errorCode; - } - } -} diff --git a/external/corert/src/System.Private.CoreLib/src/System/IO/Stream.cs b/external/corert/src/System.Private.CoreLib/src/System/IO/Stream.cs index b4f8ab30de..c307ec91e1 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/IO/Stream.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/IO/Stream.cs @@ -242,7 +242,7 @@ namespace System.IO public virtual ValueTask ReadAsync(Memory destination, CancellationToken cancellationToken = default(CancellationToken)) { - if (destination.TryGetArray(out ArraySegment array)) + if (MemoryMarshal.TryGetArray(destination, out ArraySegment array)) { return new ValueTask(ReadAsync(array.Array, array.Offset, array.Count, cancellationToken)); } @@ -316,17 +316,17 @@ namespace System.IO buffer, offset, count, this); } - public virtual Task WriteAsync(ReadOnlyMemory source, CancellationToken cancellationToken = default(CancellationToken)) + public virtual ValueTask WriteAsync(ReadOnlyMemory source, CancellationToken cancellationToken = default(CancellationToken)) { if (MemoryMarshal.TryGetArray(source, out ArraySegment array)) { - return WriteAsync(array.Array, array.Offset, array.Count, cancellationToken); + return new ValueTask(WriteAsync(array.Array, array.Offset, array.Count, cancellationToken)); } else { byte[] buffer = ArrayPool.Shared.Rent(source.Length); source.Span.CopyTo(buffer); - return FinishWriteAsync(WriteAsync(buffer, 0, source.Length, cancellationToken), buffer); + return new ValueTask(FinishWriteAsync(WriteAsync(buffer, 0, source.Length, cancellationToken), buffer)); async Task FinishWriteAsync(Task writeTask, byte[] localBuffer) { @@ -559,7 +559,7 @@ namespace System.IO cancellationToken.ThrowIfCancellationRequested(); } - public override async Task WriteAsync(ReadOnlyMemory source, CancellationToken cancellationToken) + public override async ValueTask WriteAsync(ReadOnlyMemory source, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); } diff --git a/external/corert/src/System.Private.CoreLib/src/System/InvokeUtils.cs b/external/corert/src/System.Private.CoreLib/src/System/InvokeUtils.cs index 8b92cfef31..69435aee9a 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/InvokeUtils.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/InvokeUtils.cs @@ -14,6 +14,7 @@ using Internal.Runtime.CompilerServices; namespace System { + [System.Runtime.CompilerServices.ReflectionBlocked] [System.Runtime.CompilerServices.DependencyReductionRoot] public static class InvokeUtils { @@ -32,7 +33,7 @@ namespace System // // null converted to default(T) (this is important when T is a valuetype.) // - // There is also another transform of T -> Nullable. This method acknowleges that rule but does not actually transform the T. + // There is also another transform of T -> Nullable. This method acknowledges that rule but does not actually transform the T. // Rather, the transformation happens naturally when the caller unboxes the value to its final destination. // // This method is targeted by the Delegate ILTransformer. diff --git a/external/corert/src/System.Private.CoreLib/src/System/Marvin.cs b/external/corert/src/System.Private.CoreLib/src/System/Marvin.cs index 32ae26eb13..f703423e67 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Marvin.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Marvin.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Diagnostics; +using System.Diagnostics.Private; using System.Runtime.CompilerServices; using Internal.Runtime.CompilerServices; @@ -131,12 +131,16 @@ namespace System private static ulong GenerateSeed() { +#if MONO + return 839433921; +#else ulong seed; unsafe { Interop.GetRandomBytes((byte*)&seed, sizeof(ulong)); } return seed; +#endif } } } diff --git a/external/corert/src/System.Private.CoreLib/src/System/Math.CoreRT.cs b/external/corert/src/System.Private.CoreLib/src/System/Math.CoreRT.cs index dc4e40a175..1f5edbb98e 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Math.CoreRT.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Math.CoreRT.cs @@ -20,7 +20,7 @@ namespace System [Intrinsic] public static float Abs(float value) { - return (float)RuntimeImports.fabs(value); + return RuntimeImports.fabsf(value); } [Intrinsic] @@ -35,12 +35,24 @@ namespace System return RuntimeImports.acos(d); } + [Intrinsic] + public static double Acosh(double d) + { + return RuntimeImports.acosh(d); + } + [Intrinsic] public static double Asin(double d) { return RuntimeImports.asin(d); } + [Intrinsic] + public static double Asinh(double d) + { + return RuntimeImports.asinh(d); + } + [Intrinsic] public static double Atan(double d) { @@ -49,10 +61,22 @@ namespace System [Intrinsic] public static double Atan2(double y, double x) - { + { return RuntimeImports.atan2(y, x); } + [Intrinsic] + public static double Atanh(double d) + { + return RuntimeImports.atanh(d); + } + + [Intrinsic] + public static double Cbrt(double d) + { + return RuntimeImports.cbrt(d); + } + [Intrinsic] public static double Ceiling(double a) { @@ -73,7 +97,7 @@ namespace System [Intrinsic] public static double Exp(double d) - { + { return RuntimeImports.exp(d); } diff --git a/external/corert/src/System.Private.CoreLib/src/System/MathF.CoreRT.cs b/external/corert/src/System.Private.CoreLib/src/System/MathF.CoreRT.cs index b67b8bbd40..be61cf73c5 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/MathF.CoreRT.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/MathF.CoreRT.cs @@ -17,123 +17,142 @@ namespace System { public static partial class MathF { - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static float Acos(float x) { - return (float)Math.Acos(x); + return RuntimeImports.acosf(x); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] + public static float Acosh(float x) + { + return RuntimeImports.acoshf(x); + } + + [Intrinsic] public static float Asin(float x) { - return (float)Math.Asin(x); + return RuntimeImports.asinf(x); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] + public static float Asinh(float x) + { + return RuntimeImports.asinhf(x); + } + + [Intrinsic] public static float Atan(float x) { - return (float)Math.Atan(x); + return RuntimeImports.atanf(x); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static float Atan2(float y, float x) { - return (float)Math.Atan2(y, x); + return RuntimeImports.atan2f(y, x); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] + public static float Atanh(float x) + { + return RuntimeImports.atanhf(x); + } + + [Intrinsic] + public static float Cbrt(float x) + { + return RuntimeImports.cbrtf(x); + } + + [Intrinsic] public static float Ceiling(float x) { - return (float)Math.Ceiling(x); + return RuntimeImports.ceilf(x); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static float Cos(float x) { - return (float)Math.Cos(x); + return RuntimeImports.cosf(x); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static float Cosh(float x) { - return (float)Math.Cosh(x); + return RuntimeImports.coshf(x); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static float Exp(float x) { - return (float)Math.Exp(x); + return RuntimeImports.expf(x); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static float Floor(float x) { - return (float)Math.Floor(x); + return RuntimeImports.floorf(x); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static float Log(float x) { - return (float)Math.Log(x); + return RuntimeImports.logf(x); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static float Log10(float x) { - return (float)Math.Log10(x); + return RuntimeImports.log10f(x); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static float Pow(float x, float y) { - return (float)Math.Pow(x, y); + return RuntimeImports.powf(x, y); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static float Sin(float x) { - return (float)Math.Sin(x); + return RuntimeImports.sinf(x); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static float Sinh(float x) { - return (float)Math.Sinh(x); + return RuntimeImports.sinhf(x); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static float Sqrt(float x) { - return (float)Math.Sqrt(x); + return RuntimeImports.sqrtf(x); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static float Tan(float x) { - return (float)Math.Tan(x); + return RuntimeImports.tanf(x); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static float Tanh(float x) { - return (float)Math.Tanh(x); + return RuntimeImports.tanhf(x); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] private static float FMod(float x, float y) { - return (float)RuntimeImports.fmod(x, y); + return RuntimeImports.fmodf(x, y); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] private static unsafe float ModF(float x, float* intptr) { - //todo : https://github.com/dotnet/corert/issues/3167 - double d = x; - double r = RuntimeImports.modf(d, &d); - - *intptr = (float)d; - return (float)r; + return RuntimeImports.modff(x, intptr); } } } diff --git a/external/corert/src/System.Private.CoreLib/src/System/MissingFieldException.cs b/external/corert/src/System.Private.CoreLib/src/System/MissingFieldException.cs index 95d517ccad..88cd41c6ad 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/MissingFieldException.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/MissingFieldException.cs @@ -35,10 +35,10 @@ namespace System HResult = HResults.COR_E_MISSINGFIELD; } - public MissingFieldException(string className, string methodName) + public MissingFieldException(string className, string fieldName) { ClassName = className; - MemberName = methodName; + MemberName = fieldName; } protected MissingFieldException(SerializationInfo info, StreamingContext context) diff --git a/external/corert/src/System.Private.CoreLib/src/System/MulticastDelegate.cs b/external/corert/src/System.Private.CoreLib/src/System/MulticastDelegate.cs index 7368f2a156..a3a23e67a0 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/MulticastDelegate.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/MulticastDelegate.cs @@ -118,18 +118,22 @@ namespace System public static bool operator ==(MulticastDelegate d1, MulticastDelegate d2) { - if ((Object)d1 == null) - return (Object)d2 == null; + if (ReferenceEquals(d1, d2)) + { + return true; + } - return d1.Equals(d2); + return d1 is null ? false : d1.Equals(d2); } public static bool operator !=(MulticastDelegate d1, MulticastDelegate d2) { - if ((Object)d1 == null) - return (Object)d2 != null; + if (ReferenceEquals(d1, d2)) + { + return false; + } - return !d1.Equals(d2); + return d1 is null ? true : !d1.Equals(d2); } public override sealed Delegate[] GetInvocationList() diff --git a/external/corert/src/System.Private.CoreLib/src/System/Reflection/AssemblyNameHelpers.cs b/external/corert/src/System.Private.CoreLib/src/System/Reflection/AssemblyNameHelpers.cs index 3aa1541a8a..dab7c131a6 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Reflection/AssemblyNameHelpers.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Reflection/AssemblyNameHelpers.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; namespace System.Reflection { + [System.Runtime.CompilerServices.ReflectionBlocked] public static partial class AssemblyNameHelpers { // diff --git a/external/corert/src/System.Private.CoreLib/src/System/Reflection/AssemblyNameParser.cs b/external/corert/src/System.Private.CoreLib/src/System/Reflection/AssemblyNameParser.cs index a29919faa0..f963e0323c 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Reflection/AssemblyNameParser.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Reflection/AssemblyNameParser.cs @@ -15,6 +15,7 @@ namespace System.Reflection // // Parses an assembly name. // + [System.Runtime.CompilerServices.ReflectionBlocked] public static class AssemblyNameParser { public static void Parse(AssemblyName blank, String s) diff --git a/external/corert/src/System.Private.CoreLib/src/System/Reflection/BinderBundle.cs b/external/corert/src/System.Private.CoreLib/src/System/Reflection/BinderBundle.cs index 76dea8d989..4399ee5595 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Reflection/BinderBundle.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Reflection/BinderBundle.cs @@ -12,6 +12,7 @@ namespace System.Reflection // to manage.) // // This is not an api type but needs to be public as both Reflection.Core and System.Private.Corelib accesses it. + [System.Runtime.CompilerServices.ReflectionBlocked] public sealed class BinderBundle { public BinderBundle(Binder binder, CultureInfo culture) diff --git a/external/corert/src/System.Private.CoreLib/src/System/Reflection/CustomAttributeExtensions.cs b/external/corert/src/System.Private.CoreLib/src/System/Reflection/CustomAttributeExtensions.cs index 55a306fa6c..f2143f8e0b 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Reflection/CustomAttributeExtensions.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Reflection/CustomAttributeExtensions.cs @@ -345,7 +345,18 @@ namespace System.Reflection } int count = attributes.Count; Attribute[] result; - result = (Attribute[])Array.CreateInstance(actualElementType, count); + try + { + result = (Attribute[])Array.CreateInstance(actualElementType, count); + } + catch (NotSupportedException) when (actualElementType.ContainsGenericParameters) + { + // This is here for desktop compatibility (using try-catch as control flow to avoid slowing down the mainline case.) + // CustomAttributeExtensions.GetCustomAttributes() normally returns an array of the exact attribute type requested except when + // the reqested type is an open type. Its ICustomAttributeProvider counterpart would return an Object[] array but that's + // not possible with this api's return type so it returns null instead. + return null; + } attributes.CopyTo(result, 0); return result; } diff --git a/external/corert/src/System.Private.CoreLib/src/System/Reflection/Runtime/CustomAttributes/RuntimeImplementedCustomAttributeData.cs b/external/corert/src/System.Private.CoreLib/src/System/Reflection/Runtime/CustomAttributes/RuntimeImplementedCustomAttributeData.cs index 5e75540e7d..f21515b1e1 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Reflection/Runtime/CustomAttributes/RuntimeImplementedCustomAttributeData.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Reflection/Runtime/CustomAttributes/RuntimeImplementedCustomAttributeData.cs @@ -12,6 +12,7 @@ namespace System.Reflection.Runtime.CustomAttributes // If a CustomAttributeData implementation derives from this, it is a hint that it has a AttributeType implementation // that's more efficient than building a ConstructorInfo and gettings its DeclaredType. // + [System.Runtime.CompilerServices.ReflectionBlocked] public abstract class RuntimeImplementedCustomAttributeData : CustomAttributeData { public new abstract Type AttributeType { get; } diff --git a/external/corert/src/System.Private.CoreLib/src/System/Resources/FileBasedResourceGroveler.cs b/external/corert/src/System.Private.CoreLib/src/System/Resources/FileBasedResourceGroveler.cs index 54240cb5f0..174a41975f 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Resources/FileBasedResourceGroveler.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Resources/FileBasedResourceGroveler.cs @@ -4,9 +4,6 @@ /*============================================================ ** -** -** -** ** ** Purpose: Searches for resources on disk, used for file- ** based resource lookup. @@ -14,19 +11,16 @@ ** ===========================================================*/ +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Threading; + +using Internal.IO; + namespace System.Resources { - using System; - using System.Collections; - using System.Collections.Generic; - using System.IO; - using System.Globalization; - using System.Runtime.CompilerServices; - using System.Runtime.Versioning; - using System.Text; - using System.Threading; - using System.Diagnostics; - internal class FileBasedResourceGroveler : IResourceGroveler { private ResourceManager.ResourceManagerMediator _mediator; @@ -89,14 +83,14 @@ namespace System.Resources if (_mediator.ModuleDir != null) { String path = Path.Combine(_mediator.ModuleDir, fileName); - if (InternalFile.Exists(path)) + if (File.Exists(path)) { return path; } } // look in . - if (InternalFile.Exists(fileName)) + if (File.Exists(fileName)) return fileName; return null; // give up. diff --git a/external/corert/src/System.Private.CoreLib/src/System/Resources/ManifestBasedResourceGroveler.cs b/external/corert/src/System.Private.CoreLib/src/System/Resources/ManifestBasedResourceGroveler.cs index 4fdec754f8..fc22413519 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Resources/ManifestBasedResourceGroveler.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Resources/ManifestBasedResourceGroveler.cs @@ -357,11 +357,10 @@ namespace System.Resources sb.Append(name); String givenName = sb.ToString(); - CompareInfo comparer = CultureInfo.InvariantCulture.CompareInfo; String canonicalName = null; foreach (String existingName in satellite.GetManifestResourceNames()) { - if (comparer.Compare(existingName, givenName, CompareOptions.IgnoreCase) == 0) + if (String.Equals(existingName, givenName, StringComparison.InvariantCultureIgnoreCase)) { if (canonicalName == null) { diff --git a/external/corert/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs b/external/corert/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs index 3cabd25e67..5601bae5a9 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs @@ -71,9 +71,7 @@ namespace System.Runtime.CompilerServices [DebuggerStepThrough] [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine - { - AsyncMethodBuilderCore.Start(ref stateMachine); - } + => AsyncMethodBuilderCore.Start(ref stateMachine); /// Associates the builder with the state machine it represents. /// The heap-allocated state machine object. @@ -238,9 +236,7 @@ namespace System.Runtime.CompilerServices [DebuggerStepThrough] [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine - { - AsyncMethodBuilderCore.Start(ref stateMachine); - } + => AsyncMethodBuilderCore.Start(ref stateMachine); /// Associates the builder with the state machine it represents. /// The heap-allocated state machine object. @@ -437,9 +433,7 @@ namespace System.Runtime.CompilerServices [DebuggerStepThrough] [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine - { - AsyncMethodBuilderCore.Start(ref stateMachine); // argument validation handled by AsyncMethodBuilderCore - } + => AsyncMethodBuilderCore.Start(ref stateMachine); /// Associates the builder with the state machine it represents. /// The heap-allocated state machine object. @@ -617,7 +611,6 @@ namespace System.Runtime.CompilerServices // - Boolean // - Byte, SByte // - Char - // - Decimal // - Int32, UInt32 // - Int64, UInt64 // - Int16, UInt16 @@ -652,7 +645,6 @@ namespace System.Runtime.CompilerServices (typeof(TResult) == typeof(Byte) && default(Byte) == (Byte)(object)result) || (typeof(TResult) == typeof(SByte) && default(SByte) == (SByte)(object)result) || (typeof(TResult) == typeof(Char) && default(Char) == (Char)(object)result) || - (typeof(TResult) == typeof(Decimal) && default(Decimal) == (Decimal)(object)result) || (typeof(TResult) == typeof(Int64) && default(Int64) == (Int64)(object)result) || (typeof(TResult) == typeof(UInt64) && default(UInt64) == (UInt64)(object)result) || (typeof(TResult) == typeof(Int16) && default(Int16) == (Int16)(object)result) || @@ -724,12 +716,32 @@ namespace System.Runtime.CompilerServices internal static void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine { - // Async state machines are required not to throw, so no need for try/finally here. Thread currentThread = Thread.CurrentThread; - ExecutionContextSwitcher ecs = default(ExecutionContextSwitcher); - ExecutionContext.EstablishCopyOnWriteScope(currentThread, ref ecs); + ExecutionContext previousExecutionCtx = currentThread.ExecutionContext; + SynchronizationContext previousSyncCtx = currentThread.SynchronizationContext; + + // Async state machines are required not to throw, so no need for try/finally here. stateMachine.MoveNext(); - ecs.Undo(currentThread); + + // The common case is that these have not changed, so avoid the cost of a write barrier if not needed. + if (previousSyncCtx != currentThread.SynchronizationContext) + { + // Restore changed SynchronizationContext back to previous + currentThread.SynchronizationContext = previousSyncCtx; + } + + ExecutionContext currentExecutionCtx = currentThread.ExecutionContext; + if (previousExecutionCtx != currentExecutionCtx) + { + // Restore changed ExecutionContext back to previous + currentThread.ExecutionContext = previousExecutionCtx; + if ((currentExecutionCtx != null && currentExecutionCtx.HasChangeNotifications) || + (previousExecutionCtx != null && previousExecutionCtx.HasChangeNotifications)) + { + // There are change notifications; trigger any affected + ExecutionContext.OnValuesChanged(currentExecutionCtx, previousExecutionCtx); + } + } } // diff --git a/external/corert/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/ReflectionBlockedAttribute.cs b/external/corert/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/ReflectionBlockedAttribute.cs index f80f7093e5..5e01e09cad 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/ReflectionBlockedAttribute.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/ReflectionBlockedAttribute.cs @@ -7,7 +7,10 @@ namespace System.Runtime.CompilerServices // When applied to a type this custom attribute cause the type to be treated as reflection blocked. [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Delegate | AttributeTargets.Enum | AttributeTargets.Interface, Inherited = false, AllowMultiple = false)] [DependencyReductionRoot] - public class ReflectionBlockedAttribute : Attribute +#if !MONO + public +#endif + class ReflectionBlockedAttribute : Attribute { } } diff --git a/external/corert/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs b/external/corert/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs index d5c425a3ba..f126f4f812 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs @@ -65,23 +65,23 @@ namespace System.Runtime.CompilerServices return RuntimeImports.RhMemberwiseClone(obj); } - public new static bool Equals(Object obj1, Object obj2) + public new static bool Equals(Object o1, Object o2) { - if (obj1 == obj2) + if (o1 == o2) return true; - if ((obj1 == null) || (obj2 == null)) + if ((o1 == null) || (o2 == null)) return false; // If it's not a value class, don't compare by value - if (!obj1.EETypePtr.IsValueType) + if (!o1.EETypePtr.IsValueType) return false; // Make sure they are the same type. - if (obj1.EETypePtr != obj2.EETypePtr) + if (o1.EETypePtr != o2.EETypePtr) return false; - return RuntimeImports.RhCompareObjectContentsAndPadding(obj1, obj2); + return RuntimeImports.RhCompareObjectContentsAndPadding(o1, o2); } #if !FEATURE_SYNCTABLE @@ -157,9 +157,6 @@ namespace System.Runtime.CompilerServices public static int OffsetToStringData { - // Workaround to allow WebAssembly to define a size here without a special CoreLib build - // https://github.com/dotnet/corert/issues/4506 includes removing this. - [Intrinsic] get { // Number of bytes from the address pointed to by a reference to diff --git a/external/corert/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/TaskAwaiter.cs b/external/corert/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/TaskAwaiter.cs index 33b5b0b26b..12bd0de71c 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/TaskAwaiter.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/TaskAwaiter.cs @@ -39,6 +39,7 @@ // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- using System.Diagnostics; +using System.Diagnostics.Private; using System.Threading; using System.Threading.Tasks; diff --git a/external/corert/src/System.Private.CoreLib/src/System/Runtime/InteropServices/InteropExtensions.cs b/external/corert/src/System.Private.CoreLib/src/System/Runtime/InteropServices/InteropExtensions.cs index 7bdb228f02..b296c66fdd 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Runtime/InteropServices/InteropExtensions.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Runtime/InteropServices/InteropExtensions.cs @@ -19,6 +19,7 @@ namespace System.Runtime.InteropServices /// in order to be accessible from System.Private.Interop.dll. /// [CLSCompliant(false)] + [ReflectionBlocked] public static class InteropExtensions { // Converts a managed DateTime to native OLE datetime @@ -183,8 +184,7 @@ namespace System.Runtime.InteropServices public static bool IsDelegate(this RuntimeTypeHandle handle) { - return InteropExtensions.AreTypesAssignable(handle, typeof(MulticastDelegate).TypeHandle) || - InteropExtensions.AreTypesAssignable(handle, typeof(Delegate).TypeHandle); + return InteropExtensions.AreTypesAssignable(handle, typeof(Delegate).TypeHandle); } public static bool AreTypesAssignable(RuntimeTypeHandle sourceType, RuntimeTypeHandle targetType) diff --git a/external/corert/src/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs b/external/corert/src/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs index aaac87eb2d..5af9ce674d 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using Internal.Runtime.Augments; namespace System.Runtime.InteropServices { @@ -26,6 +27,11 @@ namespace System.Runtime.InteropServices return PInvokeMarshal.GetLastWin32Error(); } + public static int GetHRForLastWin32Error() + { + return PInvokeMarshal.GetHRForLastWin32Error(); + } + public static unsafe IntPtr AllocHGlobal(IntPtr cb) { return PInvokeMarshal.AllocHGlobal(cb); @@ -61,6 +67,17 @@ namespace System.Runtime.InteropServices { return PInvokeMarshal.PtrToStringAnsi(ptr); } + + public static unsafe String PtrToStringAnsi(IntPtr ptr, int len) + { + return PInvokeMarshal.PtrToStringAnsi(ptr, len); + } #endif + + public static void ThrowExceptionForHR(int errorCode) + { + if (errorCode < 0) + throw RuntimeAugments.Callbacks.GetExceptionForHR(errorCode); + } } } diff --git a/external/corert/src/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeFunctionPointerWrapper.cs b/external/corert/src/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeFunctionPointerWrapper.cs new file mode 100644 index 0000000000..d259223fff --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeFunctionPointerWrapper.cs @@ -0,0 +1,26 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Runtime.InteropServices +{ + /// + /// Base class for all 'wrapper' classes that wraps a native function pointer + /// The forward delegates (that wraps native function pointers) points to derived Invoke method of this + /// class, and the Invoke method would implement the marshalling and making the call + /// + public abstract class NativeFunctionPointerWrapper + { + public NativeFunctionPointerWrapper(IntPtr nativeFunctionPointer) + { + m_nativeFunctionPointer = nativeFunctionPointer; + } + + IntPtr m_nativeFunctionPointer; + + public IntPtr NativeFunctionPointer + { + get { return m_nativeFunctionPointer; } + } + } +} diff --git a/external/corert/src/System.Private.CoreLib/src/System/Runtime/InteropServices/PInvokeMarshal.Unix.cs b/external/corert/src/System.Private.CoreLib/src/System/Runtime/InteropServices/PInvokeMarshal.Unix.cs index 8a97ce15ac..aeac95a074 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Runtime/InteropServices/PInvokeMarshal.Unix.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Runtime/InteropServices/PInvokeMarshal.Unix.cs @@ -44,6 +44,16 @@ namespace System.Runtime.InteropServices return System.Text.Encoding.UTF8.GetString((byte*)ptr, len); } + public static unsafe String PtrToStringAnsi(IntPtr ptr, int len) + { + if (ptr == IntPtr.Zero) + throw new ArgumentNullException(nameof(ptr)); + if (len < 0) + throw new ArgumentException(nameof(len)); + + return System.Text.Encoding.UTF8.GetString((byte*)ptr, len); + } + public static unsafe IntPtr MemAlloc(IntPtr cb) { return Interop.MemAlloc((UIntPtr)(void*)cb); diff --git a/external/corert/src/System.Private.CoreLib/src/System/Runtime/InteropServices/PInvokeMarshal.cs b/external/corert/src/System.Private.CoreLib/src/System/Runtime/InteropServices/PInvokeMarshal.cs index 79c3ed85a5..bca69bce3e 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Runtime/InteropServices/PInvokeMarshal.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Runtime/InteropServices/PInvokeMarshal.cs @@ -40,6 +40,15 @@ namespace System.Runtime.InteropServices s_lastWin32Error = errorCode; } + public static int GetHRForLastWin32Error() + { + int dwLastError = GetLastWin32Error(); + if ((dwLastError & 0x80000000) == 0x80000000) + return dwLastError; + else + return (dwLastError & 0x0000FFFF) | unchecked((int)0x80070000); + } + public static unsafe IntPtr AllocHGlobal(IntPtr cb) { return MemAlloc(cb); @@ -177,7 +186,7 @@ namespace System.Runtime.InteropServices /// Return the stub to the pinvoke marshalling stub /// /// The delegate - public static IntPtr GetStubForPInvokeDelegate(Delegate del) + public static IntPtr GetFunctionPointerForDelegate(Delegate del) { if (del == null) return IntPtr.Zero; @@ -305,16 +314,13 @@ namespace System.Runtime.InteropServices var delegateThunk = new PInvokeDelegateThunk(del); - McgPInvokeDelegateData pinvokeDelegateData; - if (!RuntimeAugments.InteropCallbacks.TryGetMarshallerDataForDelegate(del.GetTypeHandle(), out pinvokeDelegateData)) - { - Environment.FailFast("Couldn't find marshalling stubs for delegate."); - } - // // For open static delegates set target to ReverseOpenStaticDelegateStub which calls the static function pointer directly // - IntPtr pTarget = del.GetRawFunctionPointerForOpenStaticDelegate() == IntPtr.Zero ? pinvokeDelegateData.ReverseStub : pinvokeDelegateData.ReverseOpenStaticDelegateStub; + bool openStaticDelegate = del.GetRawFunctionPointerForOpenStaticDelegate() != IntPtr.Zero; + + IntPtr pTarget = RuntimeAugments.InteropCallbacks.GetDelegateMarshallingStub(del.GetTypeHandle(), openStaticDelegate); + Debug.Assert(pTarget != IntPtr.Zero); RuntimeAugments.SetThunkData(s_thunkPoolHeap, delegateThunk.Thunk, delegateThunk.ContextData, pTarget); @@ -324,9 +330,9 @@ namespace System.Runtime.InteropServices /// /// Retrieve the corresponding P/invoke instance from the stub /// - public static Delegate GetPInvokeDelegateForStub(IntPtr pStub, RuntimeTypeHandle delegateType) + public static Delegate GetDelegateForFunctionPointer(IntPtr ptr, RuntimeTypeHandle delegateType) { - if (pStub == IntPtr.Zero) + if (ptr == IntPtr.Zero) return null; // // First try to see if this is one of the thunks we've allocated when we marshal a managed @@ -335,7 +341,7 @@ namespace System.Runtime.InteropServices // IntPtr pContext; IntPtr pTarget; - if (s_thunkPoolHeap != null && RuntimeAugments.TryGetThunkData(s_thunkPoolHeap, pStub, out pContext, out pTarget)) + if (s_thunkPoolHeap != null && RuntimeAugments.TryGetThunkData(s_thunkPoolHeap, ptr, out pContext, out pTarget)) { GCHandle handle; unsafe @@ -343,7 +349,7 @@ namespace System.Runtime.InteropServices // Pull out Handle from context handle = ((ThunkContextData*)pContext)->Handle; } - Delegate target = InteropExtensions.UncheckedCast(handle.Target); + Delegate target = Unsafe.As(handle.Target); // // The delegate might already been garbage collected @@ -363,15 +369,10 @@ namespace System.Runtime.InteropServices // We need to create the delegate that points to the invoke method of a // NativeFunctionPointerWrapper derived class // - McgPInvokeDelegateData pInvokeDelegateData; - if (!RuntimeAugments.InteropCallbacks.TryGetMarshallerDataForDelegate(delegateType, out pInvokeDelegateData)) - { - return null; - } - return CalliIntrinsics.Call( - pInvokeDelegateData.ForwardDelegateCreationStub, - pStub - ); + IntPtr pDelegateCreationStub = RuntimeAugments.InteropCallbacks.GetForwardDelegateCreationStub(delegateType); + Debug.Assert(pDelegateCreationStub != IntPtr.Zero); + + return CalliIntrinsics.Call(pDelegateCreationStub, ptr); } /// @@ -420,7 +421,7 @@ namespace System.Runtime.InteropServices } - T target = InteropExtensions.UncheckedCast(handle.Target); + T target = Unsafe.As(handle.Target); // // The delegate might already been garbage collected diff --git a/external/corert/src/System.Private.CoreLib/src/System/Runtime/InteropServices/SafeHandle.cs b/external/corert/src/System.Private.CoreLib/src/System/Runtime/InteropServices/SafeHandle.cs index 668064865e..79f5c2e83c 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Runtime/InteropServices/SafeHandle.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Runtime/InteropServices/SafeHandle.cs @@ -429,7 +429,7 @@ namespace System.Runtime.InteropServices (fDispose ? StateBits.Disposed : 0); } while (Interlocked.CompareExchange(ref _state, newState, oldState) != oldState); - // If we get here we successfully decremented the ref count. Additonally we + // If we get here we successfully decremented the ref count. Additionally we // may have decremented it to zero and set the handle state as closed. In // this case (providng we own the handle) we will call the ReleaseHandle // method on the SafeHandle subclass. diff --git a/external/corert/src/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs b/external/corert/src/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs index 65473f205d..f8ebc13ee8 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs @@ -26,18 +26,11 @@ namespace System.Runtime // E.g., the class and methods are marked internal assuming that only the base class library needs them // but if a class library wants to factor differently (such as putting the GCHandle methods in an // optional library, those methods can be moved to a different file/namespace/dll - + [ReflectionBlocked] public static class RuntimeImports { private const string RuntimeLibrary = "[MRT]"; - [MethodImpl(MethodImplOptions.InternalCall)] - [RuntimeImport(RuntimeLibrary, "RhpSetHighLevelDebugFuncEvalHelper")] - internal static extern void RhpSetHighLevelDebugFuncEvalHelper(IntPtr highLevelDebugFuncEvalHelper); - - [DllImport(RuntimeLibrary, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] - internal static extern void RhpSetHighLevelDebugFuncEvalAbortHelper(IntPtr highLevelDebugFuncEvalAbortHelper); - [MethodImpl(MethodImplOptions.InternalCall)] [RuntimeImport(RuntimeLibrary, "RhpSendCustomEventToDebugger")] internal static extern void RhpSendCustomEventToDebugger(IntPtr payload, int length); @@ -339,6 +332,10 @@ namespace System.Runtime [RuntimeImport(RuntimeLibrary, "RhBoxAny")] internal static extern unsafe object RhBoxAny(void* pData, EETypePtr pEEType); + [MethodImpl(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "RhBoxAny")] + internal static extern unsafe object RhBoxAny(ref byte pData, EETypePtr pEEType); + [MethodImpl(MethodImplOptions.InternalCall)] [RuntimeImport(RuntimeLibrary, "RhNewObject")] internal static extern object RhNewObject(EETypePtr pEEType); @@ -766,101 +763,250 @@ namespace System.Runtime [RuntimeImport(RuntimeLibrary, "fabs")] internal static extern double fabs(double x); +#if PROJECTN [Intrinsic] [MethodImplAttribute(MethodImplOptions.InternalCall)] - [RuntimeImport(RuntimeLibrary, "floor")] - internal static extern double floor(double x); - + [RuntimeImport(RuntimeLibrary, "fabsf")] + internal static extern float fabsf(float x); +#else [Intrinsic] - [MethodImplAttribute(MethodImplOptions.InternalCall)] - [RuntimeImport(RuntimeLibrary, "fmod")] - internal static extern double fmod(double x, double y); - - [Intrinsic] - [MethodImplAttribute(MethodImplOptions.InternalCall)] - [RuntimeImport(RuntimeLibrary, "pow")] - internal static extern double pow(double x, double y); - - [Intrinsic] - [MethodImplAttribute(MethodImplOptions.InternalCall)] - [RuntimeImport(RuntimeLibrary, "sqrt")] - internal static extern double sqrt(double x); - - [Intrinsic] - [MethodImplAttribute(MethodImplOptions.InternalCall)] - [RuntimeImport(RuntimeLibrary, "ceil")] - internal static extern double ceil(double x); - - [Intrinsic] - [MethodImplAttribute(MethodImplOptions.InternalCall)] - [RuntimeImport(RuntimeLibrary, "cos")] - internal static extern double cos(double x); - - [Intrinsic] - [MethodImplAttribute(MethodImplOptions.InternalCall)] - [RuntimeImport(RuntimeLibrary, "sin")] - internal static extern double sin(double x); - - [Intrinsic] - [MethodImplAttribute(MethodImplOptions.InternalCall)] - [RuntimeImport(RuntimeLibrary, "tan")] - internal static extern double tan(double x); - - [Intrinsic] - [MethodImplAttribute(MethodImplOptions.InternalCall)] - [RuntimeImport(RuntimeLibrary, "cosh")] - internal static extern double cosh(double x); - - [Intrinsic] - [MethodImplAttribute(MethodImplOptions.InternalCall)] - [RuntimeImport(RuntimeLibrary, "sinh")] - internal static extern double sinh(double x); - - [Intrinsic] - [MethodImplAttribute(MethodImplOptions.InternalCall)] - [RuntimeImport(RuntimeLibrary, "tanh")] - internal static extern double tanh(double x); + internal static float fabsf(float x) + { + // fabsf is not a real export for some architectures + return (float)fabs(x); + } +#endif [Intrinsic] [MethodImplAttribute(MethodImplOptions.InternalCall)] [RuntimeImport(RuntimeLibrary, "acos")] internal static extern double acos(double x); + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "acosf")] + internal static extern float acosf(float x); + + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "acosh")] + internal static extern double acosh(double x); + + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "acoshf")] + internal static extern float acoshf(float x); + [Intrinsic] [MethodImplAttribute(MethodImplOptions.InternalCall)] [RuntimeImport(RuntimeLibrary, "asin")] internal static extern double asin(double x); + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "asinf")] + internal static extern float asinf(float x); + + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "asinh")] + internal static extern double asinh(double x); + + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "asinhf")] + internal static extern float asinhf(float x); + [Intrinsic] [MethodImplAttribute(MethodImplOptions.InternalCall)] [RuntimeImport(RuntimeLibrary, "atan")] internal static extern double atan(double x); + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "atanf")] + internal static extern float atanf(float x); + [Intrinsic] [MethodImplAttribute(MethodImplOptions.InternalCall)] [RuntimeImport(RuntimeLibrary, "atan2")] - internal static extern double atan2(double x, double y); + internal static extern double atan2(double y, double x); [Intrinsic] [MethodImplAttribute(MethodImplOptions.InternalCall)] - [RuntimeImport(RuntimeLibrary, "log")] - internal static extern double log(double x); + [RuntimeImport(RuntimeLibrary, "atan2f")] + internal static extern float atan2f(float y, float x); [Intrinsic] [MethodImplAttribute(MethodImplOptions.InternalCall)] - [RuntimeImport(RuntimeLibrary, "log10")] - internal static extern double log10(double x); + [RuntimeImport(RuntimeLibrary, "atanh")] + internal static extern double atanh(double x); + + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "atanhf")] + internal static extern float atanhf(float x); + + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "cbrt")] + internal static extern double cbrt(double x); + + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "cbrtf")] + internal static extern float cbrtf(float x); + + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "ceil")] + internal static extern double ceil(double x); + + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "ceilf")] + internal static extern float ceilf(float x); + + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "cos")] + internal static extern double cos(double x); + + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "cosf")] + internal static extern float cosf(float x); + + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "cosh")] + internal static extern double cosh(double x); + + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "coshf")] + internal static extern float coshf(float x); [Intrinsic] [MethodImplAttribute(MethodImplOptions.InternalCall)] [RuntimeImport(RuntimeLibrary, "exp")] internal static extern double exp(double x); + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "expf")] + internal static extern float expf(float x); + + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "floor")] + internal static extern double floor(double x); + + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "floorf")] + internal static extern float floorf(float x); + + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "log")] + internal static extern double log(double x); + + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "logf")] + internal static extern float logf(float x); + + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "log10")] + internal static extern double log10(double x); + + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "log10f")] + internal static extern float log10f(float x); + + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "pow")] + internal static extern double pow(double x, double y); + + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "powf")] + internal static extern float powf(float x, float y); + + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "sin")] + internal static extern double sin(double x); + + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "sinf")] + internal static extern float sinf(float x); + + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "sinh")] + internal static extern double sinh(double x); + + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "sinhf")] + internal static extern float sinhf(float x); + + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "sqrt")] + internal static extern double sqrt(double x); + + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "sqrtf")] + internal static extern float sqrtf(float x); + + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "tan")] + internal static extern double tan(double x); + + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "tanf")] + internal static extern float tanf(float x); + + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "tanh")] + internal static extern double tanh(double x); + + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "tanhf")] + internal static extern float tanhf(float x); + + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "fmod")] + internal static extern double fmod(double x, double y); + + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "fmodf")] + internal static extern float fmodf(float x, float y); + [Intrinsic] [MethodImplAttribute(MethodImplOptions.InternalCall)] [RuntimeImport(RuntimeLibrary, "modf")] internal static extern unsafe double modf(double x, double* intptr); + [Intrinsic] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [RuntimeImport(RuntimeLibrary, "modff")] + internal static extern unsafe float modff(float x, float* intptr); + #if !PLATFORM_UNIX // ExactSpelling = 'true' to force MCG to resolve it to default [DllImport(RuntimeImports.RuntimeLibrary, ExactSpelling = true)] diff --git a/external/corert/src/System.Private.CoreLib/src/System/Runtime/TypeLoaderExports.cs b/external/corert/src/System.Private.CoreLib/src/System/Runtime/TypeLoaderExports.cs index c42a690f56..fe283e992d 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Runtime/TypeLoaderExports.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Runtime/TypeLoaderExports.cs @@ -11,6 +11,7 @@ using System.Runtime.InteropServices; namespace System.Runtime { + [ReflectionBlocked] public static class TypeLoaderExports { #if PROJECTN @@ -419,6 +420,7 @@ namespace System.Runtime } } + [ReflectionBlocked] public delegate IntPtr RuntimeObjectFactory(IntPtr context, IntPtr signature, object contextObject, ref IntPtr auxResult); [System.Runtime.InteropServices.McgIntrinsicsAttribute] diff --git a/external/corert/src/System.Private.CoreLib/src/System/RuntimeArgumentHandle.cs b/external/corert/src/System.Private.CoreLib/src/System/RuntimeArgumentHandle.cs index 917ef82d91..2a95e2d254 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/RuntimeArgumentHandle.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/RuntimeArgumentHandle.cs @@ -7,7 +7,7 @@ using System.Runtime.InteropServices; namespace System { [StructLayout(LayoutKind.Sequential)] - public struct RuntimeArgumentHandle + public ref struct RuntimeArgumentHandle { } } diff --git a/external/corert/src/System.Private.CoreLib/src/System/RuntimeExceptionHelpers.cs b/external/corert/src/System.Private.CoreLib/src/System/RuntimeExceptionHelpers.cs index bc12ca38b5..ec40c126dc 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/RuntimeExceptionHelpers.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/RuntimeExceptionHelpers.cs @@ -24,6 +24,7 @@ namespace System } } + [ReflectionBlocked] public class RuntimeExceptionHelpers { //------------------------------------------------------------------------------------------------------------ @@ -200,7 +201,7 @@ namespace System internal static void FailFast(string message, Exception exception, RhFailFastReason reason, IntPtr pExAddress, IntPtr pExContext) { - // If this a recursive call to FailFast, avoid all unnecessary and complex actitivy the second time around to avoid the recursion + // If this a recursive call to FailFast, avoid all unnecessary and complex activity the second time around to avoid the recursion // that got us here the first time (Some judgement is required as to what activity is "unnecessary and complex".) bool minimalFailFast = InFailFast.Value || (exception is OutOfMemoryException); InFailFast.Value = true; @@ -248,9 +249,9 @@ namespace System #pragma warning disable 414 // field is assigned, but never used -- This is because C# doesn't realize that we // copy the field into a buffer. /// - /// This is the header that describes our 'error report' buffer to the minidump auxillary provider. + /// This is the header that describes our 'error report' buffer to the minidump auxiliary provider. /// Its format is know to that system-wide DLL, so do not change it. The remainder of the buffer is - /// opaque to the minidump auxillary provider, so it'll have its own format that is more easily + /// opaque to the minidump auxiliary provider, so it'll have its own format that is more easily /// changed. /// [StructLayout(LayoutKind.Sequential)] @@ -361,7 +362,7 @@ namespace System /// /// This method will call the runtime to gather the Exception objects from every exception dispatch in /// progress on the current thread. It will then serialize them into a new buffer and pass that - /// buffer back to the runtime, which will publish it to a place where a global "minidump auxillary + /// buffer back to the runtime, which will publish it to a place where a global "minidump auxiliary /// provider" will be able to save the buffer's contents into triage dumps. /// /// Thread safety information: The guarantee of this method is that the buffer it produces will have diff --git a/external/corert/src/System.Private.CoreLib/src/System/RuntimeFieldHandle.cs b/external/corert/src/System.Private.CoreLib/src/System/RuntimeFieldHandle.cs index 844447a934..dac2f2958a 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/RuntimeFieldHandle.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/RuntimeFieldHandle.cs @@ -31,6 +31,9 @@ namespace System if (_value == handle._value) return true; + if (_value == IntPtr.Zero || handle._value == IntPtr.Zero) + return false; + string fieldName1, fieldName2; RuntimeTypeHandle declaringType1, declaringType2; @@ -48,6 +51,9 @@ namespace System public override int GetHashCode() { + if (_value == IntPtr.Zero) + return 0; + string fieldName; RuntimeTypeHandle declaringType; RuntimeAugments.TypeLoaderCallbacks.GetRuntimeFieldHandleComponents(this, out declaringType, out fieldName); diff --git a/external/corert/src/System.Private.CoreLib/src/System/RuntimeMethodHandle.cs b/external/corert/src/System.Private.CoreLib/src/System/RuntimeMethodHandle.cs index ba276010e3..c079f4756d 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/RuntimeMethodHandle.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/RuntimeMethodHandle.cs @@ -33,6 +33,9 @@ namespace System if (_value == handle._value) return true; + if (_value == IntPtr.Zero || handle._value == IntPtr.Zero) + return false; + RuntimeTypeHandle declaringType1, declaringType2; MethodNameAndSignature nameAndSignature1, nameAndSignature2; RuntimeTypeHandle[] genericArgs1, genericArgs2; @@ -68,6 +71,9 @@ namespace System public override int GetHashCode() { + if (_value == IntPtr.Zero) + return 0; + RuntimeTypeHandle declaringType; MethodNameAndSignature nameAndSignature; RuntimeTypeHandle[] genericArgs; diff --git a/external/corert/src/System.Private.CoreLib/src/System/String.Comparison.cs b/external/corert/src/System.Private.CoreLib/src/System/String.Comparison.cs index b5d3c1787a..5086ea0ae1 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/String.Comparison.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/String.Comparison.cs @@ -2,12 +2,19 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Diagnostics; +using System.Diagnostics.Private; using System.Globalization; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using Internal.Runtime.CompilerServices; +#if BIT64 +using nuint = System.UInt64; +#else +using nuint = System.UInt32; +#endif + namespace System { public partial class String @@ -15,7 +22,7 @@ namespace System // //Native Static Methods // - +#if !MONO private static unsafe int FastCompareStringHelper(uint* strAChars, int countA, uint* strBChars, int countB) { int count = (countA < countB) ? countA : countB; @@ -145,7 +152,7 @@ namespace System return countA - countB; } - +#endif // // // NATIVE INSTANCE METHODS @@ -427,23 +434,21 @@ namespace System // for meaning of different comparisonType. public static int Compare(String strA, String strB, StringComparison comparisonType) { - if (comparisonType < StringComparison.CurrentCulture || comparisonType > StringComparison.OrdinalIgnoreCase) - { - throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType)); - } - if (object.ReferenceEquals(strA, strB)) { + StringSpanHelpers.CheckStringComparison(comparisonType); return 0; } // They can't both be null at this point. if (strA == null) { + StringSpanHelpers.CheckStringComparison(comparisonType); return -1; } if (strB == null) { + StringSpanHelpers.CheckStringComparison(comparisonType); return 1; } @@ -470,13 +475,13 @@ namespace System return CompareInfo.CompareOrdinalIgnoreCase(strA, 0, strA.Length, strB, 0, strB.Length); case StringComparison.InvariantCulture: - return CultureInfo.InvariantCulture.CompareInfo.Compare(strA, strB, CompareOptions.None); + return CompareInfo.Invariant.Compare(strA, strB, CompareOptions.None); case StringComparison.InvariantCultureIgnoreCase: - return CultureInfo.InvariantCulture.CompareInfo.Compare(strA, strB, CompareOptions.IgnoreCase); + return CompareInfo.Invariant.Compare(strA, strB, CompareOptions.IgnoreCase); default: - throw new NotSupportedException(SR.NotSupported_StringComparison); + throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType)); } } @@ -596,10 +601,7 @@ namespace System public static int Compare(String strA, int indexA, String strB, int indexB, int length, StringComparison comparisonType) { - if (comparisonType < StringComparison.CurrentCulture || comparisonType > StringComparison.OrdinalIgnoreCase) - { - throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType)); - } + StringSpanHelpers.CheckStringComparison(comparisonType); if (strA == null || strB == null) { @@ -653,13 +655,13 @@ namespace System return CompareInfo.CompareOrdinalIgnoreCase(strA, indexA, lengthA, strB, indexB, lengthB); case StringComparison.InvariantCulture: - return CultureInfo.InvariantCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.None); + return CompareInfo.Invariant.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.None); case StringComparison.InvariantCultureIgnoreCase: - return CultureInfo.InvariantCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.IgnoreCase); + return CompareInfo.Invariant.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.IgnoreCase); default: - throw new ArgumentException(SR.NotSupported_StringComparison); + throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType)); } } @@ -696,19 +698,36 @@ namespace System // TODO https://github.com/dotnet/corefx/issues/21395: Expose this publicly? internal static int CompareOrdinal(ReadOnlySpan strA, ReadOnlySpan strB) { - // TODO: This needs to be optimized / unrolled. It can't just use CompareOrdinalHelper(str, str) - // (changed to accept spans) because its implementation is based on a string layout, - // in a way that doesn't work when there isn't guaranteed to be a null terminator. + // TODO: Add a vectorized code path, similar to SequenceEqual + // https://github.com/dotnet/corefx/blob/master/src/System.Memory/src/System/SpanHelpers.byte.cs#L900 int minLength = Math.Min(strA.Length, strB.Length); - for (int i = 0; i < minLength; i++) + ref char first = ref MemoryMarshal.GetReference(strA); + ref char second = ref MemoryMarshal.GetReference(strB); + + int i = 0; + if (minLength >= sizeof(nuint) / sizeof(char)) { - if (strA[i] != strB[i]) + while (i < minLength - sizeof(nuint) / sizeof(char)) { - return strA[i] - strB[i]; + if (Unsafe.ReadUnaligned(ref Unsafe.As(ref Unsafe.Add(ref first, i))) != + Unsafe.ReadUnaligned(ref Unsafe.As(ref Unsafe.Add(ref second, i)))) + { + break; + } + i += sizeof(nuint) / sizeof(char); } } - + while (i < minLength) + { + char a = Unsafe.Add(ref first, i); + char b = Unsafe.Add(ref second, i); + if (a != b) + { + return a - b; + } + i++; + } return strA.Length - strB.Length; } @@ -804,18 +823,15 @@ namespace System throw new ArgumentNullException(nameof(value)); } - if (comparisonType < StringComparison.CurrentCulture || comparisonType > StringComparison.OrdinalIgnoreCase) - { - throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType)); - } - if ((Object)this == (Object)value) { + StringSpanHelpers.CheckStringComparison(comparisonType); return true; } if (value.Length == 0) { + StringSpanHelpers.CheckStringComparison(comparisonType); return true; } @@ -834,10 +850,10 @@ namespace System return this.Length < value.Length ? false : (CompareInfo.CompareOrdinalIgnoreCase(this, this.Length - value.Length, value.Length, value, 0, value.Length) == 0); case StringComparison.InvariantCulture: - return CultureInfo.InvariantCulture.CompareInfo.IsSuffix(this, value, CompareOptions.None); + return CompareInfo.Invariant.IsSuffix(this, value, CompareOptions.None); case StringComparison.InvariantCultureIgnoreCase: - return CultureInfo.InvariantCulture.CompareInfo.IsSuffix(this, value, CompareOptions.IgnoreCase); + return CompareInfo.Invariant.IsSuffix(this, value, CompareOptions.IgnoreCase); default: throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType)); @@ -912,16 +928,15 @@ namespace System public bool Equals(String value, StringComparison comparisonType) { - if (comparisonType < StringComparison.CurrentCulture || comparisonType > StringComparison.OrdinalIgnoreCase) - throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType)); - if ((Object)this == (Object)value) { + StringSpanHelpers.CheckStringComparison(comparisonType); return true; } if ((Object)value == null) { + StringSpanHelpers.CheckStringComparison(comparisonType); return false; } @@ -947,10 +962,10 @@ namespace System } case StringComparison.InvariantCulture: - return (CultureInfo.InvariantCulture.CompareInfo.Compare(this, value, CompareOptions.None) == 0); + return (CompareInfo.Invariant.Compare(this, value, CompareOptions.None) == 0); case StringComparison.InvariantCultureIgnoreCase: - return (CultureInfo.InvariantCulture.CompareInfo.Compare(this, value, CompareOptions.IgnoreCase) == 0); + return (CompareInfo.Invariant.Compare(this, value, CompareOptions.IgnoreCase) == 0); default: throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType)); @@ -976,16 +991,15 @@ namespace System public static bool Equals(String a, String b, StringComparison comparisonType) { - if (comparisonType < StringComparison.CurrentCulture || comparisonType > StringComparison.OrdinalIgnoreCase) - throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType)); - if ((Object)a == (Object)b) { + StringSpanHelpers.CheckStringComparison(comparisonType); return true; } if ((Object)a == null || (Object)b == null) { + StringSpanHelpers.CheckStringComparison(comparisonType); return false; } @@ -1011,10 +1025,10 @@ namespace System } case StringComparison.InvariantCulture: - return (CultureInfo.InvariantCulture.CompareInfo.Compare(a, b, CompareOptions.None) == 0); + return (CompareInfo.Invariant.Compare(a, b, CompareOptions.None) == 0); case StringComparison.InvariantCultureIgnoreCase: - return (CultureInfo.InvariantCulture.CompareInfo.Compare(a, b, CompareOptions.IgnoreCase) == 0); + return (CompareInfo.Invariant.Compare(a, b, CompareOptions.IgnoreCase) == 0); default: throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType)); @@ -1043,7 +1057,11 @@ namespace System // they will return the same hash code. public override int GetHashCode() { +#if MONO + return LegacyStringGetHashCode(); +#else return Marvin.ComputeHash32(ref Unsafe.As(ref _firstChar), _stringLength * 2, Marvin.DefaultSeed); +#endif } // Gets a hash code for this string and this comparison. If strings A and B and comparison C are such @@ -1119,18 +1137,15 @@ namespace System throw new ArgumentNullException(nameof(value)); } - if (comparisonType < StringComparison.CurrentCulture || comparisonType > StringComparison.OrdinalIgnoreCase) - { - throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType)); - } - if ((Object)this == (Object)value) { + StringSpanHelpers.CheckStringComparison(comparisonType); return true; } if (value.Length == 0) { + StringSpanHelpers.CheckStringComparison(comparisonType); return true; } @@ -1159,10 +1174,10 @@ namespace System return CompareInfo.CompareOrdinalIgnoreCase(this, 0, value.Length, value, 0, value.Length) == 0; case StringComparison.InvariantCulture: - return CultureInfo.InvariantCulture.CompareInfo.IsPrefix(this, value, CompareOptions.None); + return CompareInfo.Invariant.IsPrefix(this, value, CompareOptions.None); case StringComparison.InvariantCultureIgnoreCase: - return CultureInfo.InvariantCulture.CompareInfo.IsPrefix(this, value, CompareOptions.IgnoreCase); + return CompareInfo.Invariant.IsPrefix(this, value, CompareOptions.IgnoreCase); default: throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType)); diff --git a/external/corert/src/System.Private.CoreLib/src/System/String.CoreRT.cs b/external/corert/src/System.Private.CoreLib/src/System/String.CoreRT.cs new file mode 100644 index 0000000000..a892006d9c --- /dev/null +++ b/external/corert/src/System.Private.CoreLib/src/System/String.CoreRT.cs @@ -0,0 +1,85 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.Runtime; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Versioning; +using System.Text; + +using Internal.Runtime.CompilerServices; + +namespace System +{ + [StructLayout(LayoutKind.Sequential)] + [System.Runtime.CompilerServices.EagerStaticClassConstructionAttribute] + [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] + public partial class String + { +#if BIT64 + private const int POINTER_SIZE = 8; +#else + private const int POINTER_SIZE = 4; +#endif + // m_pEEType + _stringLength + internal const int FIRST_CHAR_OFFSET = POINTER_SIZE + sizeof(int); + + // CS0169: The private field '{blah}' is never used + // CS0649: Field '{blah}' is never assigned to, and will always have its default value +#pragma warning disable 169, 649 + +#if PROJECTN + [Bound] +#endif + // WARNING: We allow diagnostic tools to directly inspect these two members (_stringLength, _firstChar) + // See https://github.com/dotnet/corert/blob/master/Documentation/design-docs/diagnostics/diagnostics-tools-contract.md for more details. + // Please do not change the type, the name, or the semantic usage of this member without understanding the implication for tools. + // Get in touch with the diagnostics team if you have questions. + [NonSerialized] + private int _stringLength; + [NonSerialized] + private char _firstChar; + +#pragma warning restore + + public static readonly String Empty = ""; + + // Gets the character at a specified position. + // + // Spec#: Apply the precondition here using a contract assembly. Potential perf issue. + [System.Runtime.CompilerServices.IndexerName("Chars")] + public unsafe char this[int index] + { +#if PROJECTN + [BoundsChecking] + get + { + return Unsafe.Add(ref _firstChar, index); + } +#else + [Intrinsic] + get + { + if ((uint)index >= _stringLength) + ThrowHelper.ThrowIndexOutOfRangeException(); + return Unsafe.Add(ref _firstChar, index); + } +#endif + } + + internal static String FastAllocateString(int length) + { + // We allocate one extra char as an interop convenience so that our strings are null- + // terminated, however, we don't pass the extra +1 to the string allocation because the base + // size of this object includes the _firstChar field. + string newStr = RuntimeImports.RhNewString(EETypePtr.EETypePtrOf(), length); + Debug.Assert(newStr._stringLength == length); + return newStr; + } + } +} diff --git a/external/corert/src/System.Private.CoreLib/src/System/String.cs b/external/corert/src/System.Private.CoreLib/src/System/String.cs index 076bd02a8c..a10d212c00 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/String.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/String.cs @@ -12,7 +12,7 @@ using System.Buffers; using System.Collections; using System.Collections.Generic; -using System.Diagnostics; +using System.Diagnostics.Private; using System.Globalization; using System.Runtime; using System.Runtime.CompilerServices; @@ -74,38 +74,9 @@ namespace System // constructed itself depends on this class also being eagerly constructed. Plus, it's nice to have this // eagerly constructed to avoid the cost of defered ctors. I can't imagine any app that doesn't use string // - [StructLayout(LayoutKind.Sequential)] - [System.Runtime.CompilerServices.EagerStaticClassConstructionAttribute] [Serializable] - [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] public sealed partial class String : IComparable, IEnumerable, IEnumerable, IComparable, IEquatable, IConvertible, ICloneable { -#if BIT64 - private const int POINTER_SIZE = 8; -#else - private const int POINTER_SIZE = 4; -#endif - // m_pEEType + _stringLength - internal const int FIRST_CHAR_OFFSET = POINTER_SIZE + sizeof(int); - - // CS0169: The private field '{blah}' is never used - // CS0649: Field '{blah}' is never assigned to, and will always have its default value -#pragma warning disable 169, 649 - -#if PROJECTN - [Bound] -#endif - // WARNING: We allow diagnostic tools to directly inspect these two members (_stringLength, _firstChar) - // See https://github.com/dotnet/corert/blob/master/Documentation/design-docs/diagnostics/diagnostics-tools-contract.md for more details. - // Please do not change the type, the name, or the semantic usage of this member without understanding the implication for tools. - // Get in touch with the diagnostics team if you have questions. - [NonSerialized] - private int _stringLength; - [NonSerialized] - private char _firstChar; - -#pragma warning restore - // String constructors // These are special. the implementation methods for these have a different signature from the // declared constructors. @@ -293,7 +264,7 @@ namespace System if (numBytes == 0) return string.Empty; -#if PLATFORM_UNIX +#if PLATFORM_UNIX || MONO return Encoding.UTF8.GetString(pb, numBytes); #else int numCharsRequired = Interop.Kernel32.MultiByteToWideChar(Interop.Kernel32.CP_ACP, Interop.Kernel32.MB_PRECOMPOSED, pb, numBytes, (char*)null, 0); @@ -326,6 +297,14 @@ namespace System if (startIndex < 0) throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_StartIndex); + if (value == null) + { + if (length == 0) + return Empty; + + throw new ArgumentNullException(nameof(value)); + } + byte* pStart = (byte*)(value + startIndex); if (pStart < value) { @@ -415,6 +394,7 @@ namespace System return result; } +#if !MONO // TODO: Undo public static string Create(int length, TState state, SpanAction action) { if (action == null) @@ -439,6 +419,7 @@ namespace System public static implicit operator ReadOnlySpan(string value) => value != null ? new ReadOnlySpan(ref value.GetRawStringData(), value.Length) : default; +#endif public object Clone() { @@ -464,31 +445,6 @@ namespace System return result; } - public static readonly String Empty = ""; - - // Gets the character at a specified position. - // - // Spec#: Apply the precondition here using a contract assembly. Potential perf issue. - [System.Runtime.CompilerServices.IndexerName("Chars")] - public unsafe char this[int index] - { -#if PROJECTN - [BoundsChecking] - get - { - return Unsafe.Add(ref _firstChar, index); - } -#else - [Intrinsic] - get - { - if ((uint)index >= _stringLength) - ThrowHelper.ThrowIndexOutOfRangeException(); - return Unsafe.Add(ref _firstChar, index); - } -#endif - } - // Converts a substring of this string to an array of characters. Copies the // characters of this string beginning at position sourceIndex and ending at // sourceIndex + count - 1 to the character array buffer, beginning @@ -630,16 +586,6 @@ namespace System return result; } - internal static String FastAllocateString(int length) - { - // We allocate one extra char as an interop convenience so that our strings are null- - // terminated, however, we don't pass the extra +1 to the string allocation because the base - // size of this object includes the _firstChar field. - string newStr = RuntimeImports.RhNewString(EETypePtr.EETypePtrOf(), length); - Debug.Assert(newStr._stringLength == length); - return newStr; - } - internal static unsafe void wstrcpy(char* dmem, char* smem, int charCount) { Buffer.Memmove((byte*)dmem, (byte*)smem, ((uint)charCount) * 2); diff --git a/external/corert/src/System.Private.CoreLib/src/System/Threading/Condition.cs b/external/corert/src/System.Private.CoreLib/src/System/Threading/Condition.cs index b854aa9467..7dffcb4187 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Threading/Condition.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Threading/Condition.cs @@ -9,6 +9,7 @@ using System.Diagnostics; namespace System.Threading { + [System.Runtime.CompilerServices.ReflectionBlocked] public sealed class Condition { internal class Waiter diff --git a/external/corert/src/System.Private.CoreLib/src/System/Threading/EventWaitHandle.Windows.cs b/external/corert/src/System.Private.CoreLib/src/System/Threading/EventWaitHandle.Windows.cs index 28b938ab29..2800fc9518 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Threading/EventWaitHandle.Windows.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Threading/EventWaitHandle.Windows.cs @@ -19,16 +19,16 @@ namespace System.Threading private static void VerifyNameForCreate(string name) { - if (null != name && ((int)Interop.Constants.MaxPath) < name.Length) + if (null != name && Interop.Kernel32.MAX_PATH < name.Length) { - throw new ArgumentException(SR.Format(SR.Argument_WaitHandleNameTooLong, Interop.Constants.MaxPath), nameof(name)); + throw new ArgumentException(SR.Format(SR.Argument_WaitHandleNameTooLong, Interop.Kernel32.MAX_PATH), nameof(name)); } } private void CreateEventCore(bool initialState, EventResetMode mode, string name, out bool createdNew) { Debug.Assert((mode == EventResetMode.AutoReset) || (mode == EventResetMode.ManualReset)); - Debug.Assert(name == null || name.Length <= (int)Interop.Constants.MaxPath); + Debug.Assert(name == null || name.Length <= Interop.Kernel32.MAX_PATH); uint eventFlags = initialState ? (uint)Interop.Constants.CreateEventInitialSet : 0; if (mode == EventResetMode.ManualReset) @@ -71,9 +71,9 @@ namespace System.Threading throw new ArgumentException(SR.Argument_EmptyName, nameof(name)); } - if (null != name && ((int)Interop.Constants.MaxPath) < name.Length) + if (null != name && Interop.Kernel32.MAX_PATH < name.Length) { - throw new ArgumentException(SR.Format(SR.Argument_WaitHandleNameTooLong, Interop.Constants.MaxPath), nameof(name)); + throw new ArgumentException(SR.Format(SR.Argument_WaitHandleNameTooLong, Interop.Kernel32.MAX_PATH), nameof(name)); } result = null; diff --git a/external/corert/src/System.Private.CoreLib/src/System/Threading/Lock.cs b/external/corert/src/System.Private.CoreLib/src/System/Threading/Lock.cs index 9669b21ebc..2150a69338 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Threading/Lock.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Threading/Lock.cs @@ -9,6 +9,7 @@ using Internal.Runtime.Augments; namespace System.Threading { + [ReflectionBlocked] public sealed class Lock { // The following constants define characteristics of spinning logic in the Lock class diff --git a/external/corert/src/System.Private.CoreLib/src/System/Threading/LockHolder.cs b/external/corert/src/System.Private.CoreLib/src/System/Threading/LockHolder.cs index 8c2b167a99..eea076390d 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Threading/LockHolder.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Threading/LockHolder.cs @@ -6,6 +6,7 @@ using System.Runtime.CompilerServices; namespace System.Threading { + [ReflectionBlocked] public struct LockHolder : IDisposable { private Lock _lock; diff --git a/external/corert/src/System.Private.CoreLib/src/System/Threading/Mutex.Windows.cs b/external/corert/src/System.Private.CoreLib/src/System/Threading/Mutex.Windows.cs index 2b3c25061a..ba5e863043 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Threading/Mutex.Windows.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Threading/Mutex.Windows.cs @@ -14,15 +14,15 @@ namespace System.Threading private static void VerifyNameForCreate(string name) { - if (null != name && ((int)Interop.Constants.MaxPath) < name.Length) + if (null != name && Interop.Kernel32.MAX_PATH < name.Length) { - throw new ArgumentException(SR.Format(SR.Argument_WaitHandleNameTooLong, Interop.Constants.MaxPath), nameof(name)); + throw new ArgumentException(SR.Format(SR.Argument_WaitHandleNameTooLong, Interop.Kernel32.MAX_PATH), nameof(name)); } } private void CreateMutexCore(bool initiallyOwned, string name, out bool createdNew) { - Debug.Assert(name == null || name.Length <= (int)Interop.Constants.MaxPath); + Debug.Assert(name == null || name.Length <= Interop.Kernel32.MAX_PATH); uint mutexFlags = initiallyOwned ? (uint)Interop.Constants.CreateMutexInitialOwner : 0; @@ -52,9 +52,9 @@ namespace System.Threading { throw new ArgumentException(SR.Argument_EmptyName, nameof(name)); } - if (((int)Interop.Constants.MaxPath) < (uint)name.Length) + if (Interop.Kernel32.MAX_PATH < (uint)name.Length) { - throw new ArgumentException(SR.Format(SR.Argument_WaitHandleNameTooLong, Interop.Constants.MaxPath), nameof(name)); + throw new ArgumentException(SR.Format(SR.Argument_WaitHandleNameTooLong, Interop.Kernel32.MAX_PATH), nameof(name)); } result = null; diff --git a/external/corert/src/System.Private.CoreLib/src/System/Threading/PinnableBufferCache.cs b/external/corert/src/System.Private.CoreLib/src/System/Threading/PinnableBufferCache.cs index c85d532d00..5ebeb44412 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Threading/PinnableBufferCache.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Threading/PinnableBufferCache.cs @@ -401,9 +401,9 @@ namespace System.Threading else if (m_restockSize < 256) m_restockSize = m_restockSize * 2; // Grow quickly at small sizes else if (m_restockSize < 4096) - m_restockSize = m_restockSize * 3 / 2; // Less agressively at large ones + m_restockSize = m_restockSize * 3 / 2; // Less aggressively at large ones else - m_restockSize = 4096; // Cap how agressive we are + m_restockSize = 4096; // Cap how aggressive we are // Ensure we hit our minimums if (m_minBufferCount > m_buffersUnderManagement) diff --git a/external/corert/src/System.Private.CoreLib/src/System/Threading/Semaphore.Windows.cs b/external/corert/src/System.Private.CoreLib/src/System/Threading/Semaphore.Windows.cs index 67eec809a5..3eab7f5d25 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Threading/Semaphore.Windows.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Threading/Semaphore.Windows.cs @@ -19,9 +19,9 @@ namespace System.Threading private static void VerifyNameForCreate(string name) { - if (null != name && MAX_PATH < name.Length) + if (null != name && Interop.Kernel32.MAX_PATH < name.Length) { - throw new ArgumentException(SR.Format(SR.Argument_WaitHandleNameTooLong, Interop.Constants.MaxPath), nameof(name)); + throw new ArgumentException(SR.Format(SR.Argument_WaitHandleNameTooLong, Interop.Kernel32.MAX_PATH), nameof(name)); } } @@ -30,7 +30,7 @@ namespace System.Threading Debug.Assert(initialCount >= 0); Debug.Assert(maximumCount >= 1); Debug.Assert(initialCount <= maximumCount); - Debug.Assert(name == null || name.Length <= MAX_PATH); + Debug.Assert(name == null || name.Length <= Interop.Kernel32.MAX_PATH); SafeWaitHandle myHandle = Interop.mincore.CreateSemaphoreEx(IntPtr.Zero, initialCount, maximumCount, name, 0, AccessRights); @@ -64,9 +64,9 @@ namespace System.Threading { throw new ArgumentException(SR.Argument_EmptyName, nameof(name)); } - if (null != name && MAX_PATH < name.Length) + if (null != name && Interop.Kernel32.MAX_PATH < name.Length) { - throw new ArgumentException(SR.Format(SR.Argument_WaitHandleNameTooLong, MAX_PATH), nameof(name)); + throw new ArgumentException(SR.Format(SR.Argument_WaitHandleNameTooLong, Interop.Kernel32.MAX_PATH), nameof(name)); } result = null; diff --git a/external/corert/src/System.Private.CoreLib/src/System/Threading/Semaphore.cs b/external/corert/src/System.Private.CoreLib/src/System/Threading/Semaphore.cs index ddc3c54f1f..9e7a7796a4 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Threading/Semaphore.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Threading/Semaphore.cs @@ -13,8 +13,6 @@ namespace System.Threading { public sealed partial class Semaphore : WaitHandle { - private const int MAX_PATH = (int)Interop.Constants.MaxPath; - // creates a nameless semaphore object // Win32 only takes maximum count of Int32.MaxValue public Semaphore(int initialCount, int maximumCount) diff --git a/external/corert/src/System.Private.CoreLib/src/System/Threading/SpinLock.cs b/external/corert/src/System.Private.CoreLib/src/System/Threading/SpinLock.cs index f0305ad043..f949896e2c 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Threading/SpinLock.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Threading/SpinLock.cs @@ -321,7 +321,7 @@ namespace System.Threading // In this case there are three ways to acquire the lock // 1- the first way the thread either tries to get the lock if it's free or updates the waiters, if the turn >= the processors count then go to 3 else go to 2 // 2- In this step the waiter threads spins and tries to acquire the lock, the number of spin iterations and spin count is dependent on the thread turn - // the late the thread arrives the more it spins and less frequent it check the lock avilability + // the late the thread arrives the more it spins and less frequent it check the lock availability // Also the spins count is increases each iteration // If the spins iterations finished and failed to acquire the lock, go to step 3 // 3- This is the yielding step, there are two ways of yielding Thread.Yield and Sleep(1) @@ -337,19 +337,19 @@ namespace System.Threading { if (CompareExchange(ref m_owner, observedOwner | 1, observedOwner, ref lockTaken) == observedOwner) { - // Aquired lock + // Acquired lock return; } if (millisecondsTimeout == 0) { - // Did not aquire lock in CompareExchange and timeout is 0 so fail fast + // Did not acquire lock in CompareExchange and timeout is 0 so fail fast return; } } else if (millisecondsTimeout == 0) { - // Did not aquire lock as owned and timeout is 0 so fail fast + // Did not acquire lock as owned and timeout is 0 so fail fast return; } else //failed to acquire the lock,then try to update the waiters. If the waiters count reached the maximum, jsut break the loop to avoid overflow diff --git a/external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/Future.cs b/external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/Future.cs index ed2c06d745..249214c4c4 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/Future.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/Future.cs @@ -13,6 +13,7 @@ using System.Runtime.CompilerServices; using System.Diagnostics; +using System.Diagnostics.Private; // Disable the "reference to volatile field not treated as volatile" error. diff --git a/external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/FutureFactory.cs.REMOVED.git-id b/external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/FutureFactory.cs.REMOVED.git-id index 2a6ed083c9..c8c82ed1fb 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/FutureFactory.cs.REMOVED.git-id +++ b/external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/FutureFactory.cs.REMOVED.git-id @@ -1 +1 @@ -b27b1858fea5bbb83b6ef0a139929bdcebcba74d \ No newline at end of file +a536d51d1c315ded8a565fd23c7697bb35dc6f1c \ No newline at end of file diff --git a/external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs.REMOVED.git-id b/external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs.REMOVED.git-id index 8a18e60b59..6856f6ffee 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs.REMOVED.git-id +++ b/external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs.REMOVED.git-id @@ -1 +1 @@ -04a0c1a960a88fa95d87deb30f8e57e685b66894 \ No newline at end of file +48443f12612316da12c20882839cea4e7be89e74 \ No newline at end of file diff --git a/external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/TaskContinuation.cs b/external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/TaskContinuation.cs index 5c59699f96..063fcda864 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/TaskContinuation.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/TaskContinuation.cs @@ -11,7 +11,7 @@ // // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -using System.Diagnostics; +using System.Diagnostics.Private; using System.Runtime.CompilerServices; using Internal.Runtime.Augments; @@ -225,7 +225,7 @@ namespace System.Threading.Tasks // - SynchronizationContextAwaitTaskContinuation: awaiting with a "current" sync ctx /// Represents a continuation. - internal abstract class TaskContinuation + internal abstract partial class TaskContinuation { /// Inlines or schedules the continuation. /// The antecedent task that has completed. @@ -501,7 +501,7 @@ namespace System.Threading.Tasks } /// Base task continuation class used for await continuations. - internal class AwaitTaskContinuation : TaskContinuation, IThreadPoolWorkItem + internal partial class AwaitTaskContinuation : TaskContinuation, IThreadPoolWorkItem { /// The ExecutionContext with which to run the continuation. private readonly ExecutionContext m_capturedContext; diff --git a/external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/TaskFactory.cs.REMOVED.git-id b/external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/TaskFactory.cs.REMOVED.git-id index c9d581633a..9cfd557a87 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/TaskFactory.cs.REMOVED.git-id +++ b/external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/TaskFactory.cs.REMOVED.git-id @@ -1 +1 @@ -627a760c70dad24b763acc3e566b6cf1c18ae6e7 \ No newline at end of file +c80953c82c13044ea68c339395b3895f2eabc64c \ No newline at end of file diff --git a/external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/TaskScheduler.cs b/external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/TaskScheduler.cs index 653345cef6..245ba6116b 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/TaskScheduler.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/TaskScheduler.cs @@ -12,6 +12,7 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.Private; using System.Runtime.CompilerServices; namespace System.Threading.Tasks diff --git a/external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/ThreadPoolTaskScheduler.cs b/external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/ThreadPoolTaskScheduler.cs index 7ac733a291..02c6e0ac3e 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/ThreadPoolTaskScheduler.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/ThreadPoolTaskScheduler.cs @@ -48,7 +48,7 @@ namespace System.Threading.Tasks task.Id, creatingTask == null ? 0 : creatingTask.Id, (int)task.Options); } - +#if !WASM if ((task.Options & TaskCreationOptions.LongRunning) != 0) { // Run LongRunning tasks on their own dedicated thread. @@ -57,6 +57,8 @@ namespace System.Threading.Tasks thread.Start(task); } else +#endif + { // Normal handling for non-LongRunning tasks. bool forceToGlobalQueue = ((task.Options & TaskCreationOptions.PreferFairness) != 0); diff --git a/external/corert/src/System.Private.CoreLib/src/System/Threading/ThreadPool.cs b/external/corert/src/System.Private.CoreLib/src/System/Threading/ThreadPool.cs index e83cdce77d..c41b377533 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Threading/ThreadPool.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Threading/ThreadPool.cs @@ -691,24 +691,20 @@ namespace System.Threading void ExecuteWorkItem(); } - internal sealed class QueueUserWorkItemCallback : IThreadPoolWorkItem + internal abstract class QueueUserWorkItemCallbackBase : IThreadPoolWorkItem { - private WaitCallback callback; - private readonly ExecutionContext context; - private readonly Object state; - #if DEBUG private volatile int executed; [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1821:RemoveEmptyFinalizers")] - ~QueueUserWorkItemCallback() + ~QueueUserWorkItemCallbackBase() { Debug.Assert( executed != 0 || Environment.HasShutdownStarted /*|| AppDomain.CurrentDomain.IsFinalizingForUnload()*/, "A QueueUserWorkItemCallback was never called!"); } - private void MarkExecuted() + protected void MarkExecuted() { GC.SuppressFinalize(this); Debug.Assert( @@ -717,86 +713,51 @@ namespace System.Threading } #endif - internal QueueUserWorkItemCallback(WaitCallback waitCallback, Object stateObj, ExecutionContext ec) - { - callback = waitCallback; - state = stateObj; - context = ec; - } - - void IThreadPoolWorkItem.ExecuteWorkItem() + public virtual void ExecuteWorkItem() { #if DEBUG MarkExecuted(); #endif - try - { - if (context == null) - { - WaitCallback cb = callback; - callback = null; - cb(state); - } - else - ExecutionContext.Run(context, ccb, this); - } - catch (Exception e) - { - RuntimeAugments.ReportUnhandledException(e); - throw; //unreachable - } - } - - internal static readonly ContextCallback ccb = new ContextCallback(WaitCallback_Context); - - private static void WaitCallback_Context(Object state) - { - QueueUserWorkItemCallback obj = (QueueUserWorkItemCallback)state; - WaitCallback wc = obj.callback; - Debug.Assert(null != wc); - wc(obj.state); } } - internal sealed class QueueUserWorkItemCallbackDefaultContext : IThreadPoolWorkItem + internal sealed class QueueUserWorkItemCallback : QueueUserWorkItemCallbackBase { - private WaitCallback callback; - private readonly Object state; + private WaitCallback _callback; + private readonly object _state; + private readonly ExecutionContext _context; -#if DEBUG - private volatile int executed; - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1821:RemoveEmptyFinalizers")] - ~QueueUserWorkItemCallbackDefaultContext() + internal static readonly ContextCallback s_executionContextShim = state => { - Debug.Assert( - executed != 0 || Environment.HasShutdownStarted /*|| AppDomain.CurrentDomain.IsFinalizingForUnload()*/, - "A QueueUserWorkItemCallbackDefaultContext was never called!"); + var obj = (QueueUserWorkItemCallback)state; + WaitCallback c = obj._callback; + Debug.Assert(c != null); + obj._callback = null; + c(obj._state); + }; + + internal QueueUserWorkItemCallback(WaitCallback callback, object state, ExecutionContext context) + { + _callback = callback; + _state = state; + _context = context; } - private void MarkExecuted() + public override void ExecuteWorkItem() { - GC.SuppressFinalize(this); - Debug.Assert( - 0 == Interlocked.Exchange(ref executed, 1), - "A QueueUserWorkItemCallbackDefaultContext was called twice!"); - } -#endif - - internal QueueUserWorkItemCallbackDefaultContext(WaitCallback waitCallback, Object stateObj) - { - callback = waitCallback; - state = stateObj; - } - - void IThreadPoolWorkItem.ExecuteWorkItem() - { -#if DEBUG - MarkExecuted(); -#endif + base.ExecuteWorkItem(); try { - ExecutionContext.Run(ExecutionContext.Default, ccb, this); + if (_context == null) + { + WaitCallback c = _callback; + _callback = null; + c(_state); + } + else + { + ExecutionContext.Run(_context, s_executionContextShim, this); + } } catch (Exception e) { @@ -804,16 +765,121 @@ namespace System.Threading throw; //unreachable } } + } - internal static readonly ContextCallback ccb = new ContextCallback(WaitCallback_Context); + internal sealed class QueueUserWorkItemCallback : QueueUserWorkItemCallbackBase + { + private Action _callback; + private readonly TState _state; + private readonly ExecutionContext _context; - private static void WaitCallback_Context(Object state) + internal static readonly ContextCallback s_executionContextShim = state => { - QueueUserWorkItemCallbackDefaultContext obj = (QueueUserWorkItemCallbackDefaultContext)state; - WaitCallback wc = obj.callback; - Debug.Assert(null != wc); - obj.callback = null; - wc(obj.state); + var obj = (QueueUserWorkItemCallback)state; + Action c = obj._callback; + Debug.Assert(c != null); + obj._callback = null; + c(obj._state); + }; + + internal QueueUserWorkItemCallback(Action callback, TState state, ExecutionContext context) + { + _callback = callback; + _state = state; + _context = context; + } + + public override void ExecuteWorkItem() + { + base.ExecuteWorkItem(); + try + { + if (_context == null) + { + Action c = _callback; + _callback = null; + c(_state); + } + else + { + ExecutionContext.RunInternal(_context, s_executionContextShim, this); + } + } + catch (Exception e) + { + RuntimeAugments.ReportUnhandledException(e); + throw; //unreachable + } + } + } + + internal sealed class QueueUserWorkItemCallbackDefaultContext : QueueUserWorkItemCallbackBase + { + private WaitCallback _callback; + private readonly object _state; + + internal static readonly ContextCallback s_executionContextShim = state => + { + var obj = (QueueUserWorkItemCallbackDefaultContext)state; + WaitCallback c = obj._callback; + Debug.Assert(c != null); + obj._callback = null; + c(obj._state); + }; + + internal QueueUserWorkItemCallbackDefaultContext(WaitCallback callback, object state) + { + _callback = callback; + _state = state; + } + + public override void ExecuteWorkItem() + { + base.ExecuteWorkItem(); + try + { + ExecutionContext.Run(ExecutionContext.Default, s_executionContextShim, this); + } + catch (Exception e) + { + RuntimeAugments.ReportUnhandledException(e); + throw; //unreachable + } + } + } + + internal sealed class QueueUserWorkItemCallbackDefaultContext : QueueUserWorkItemCallbackBase + { + private Action _callback; + private readonly TState _state; + + internal static readonly ContextCallback s_executionContextShim = state => + { + var obj = (QueueUserWorkItemCallbackDefaultContext)state; + Action c = obj._callback; + Debug.Assert(c != null); + obj._callback = null; + c(obj._state); + }; + + internal QueueUserWorkItemCallbackDefaultContext(Action callback, TState state) + { + _callback = callback; + _state = state; + } + + public override void ExecuteWorkItem() + { + base.ExecuteWorkItem(); + try + { + ExecutionContext.Run(ExecutionContext.Default, s_executionContextShim, this); + } + catch (Exception e) + { + RuntimeAugments.ReportUnhandledException(e); + throw; //unreachable + } } } @@ -965,12 +1031,9 @@ namespace System.Threading } public static bool QueueUserWorkItem(WaitCallback callBack) => - QueueUserWorkItem(callBack, null, preferLocal: false); + QueueUserWorkItem(callBack, null); - public static bool QueueUserWorkItem(WaitCallback callBack, object state) => - QueueUserWorkItem(callBack, state, preferLocal: false); - - public static bool QueueUserWorkItem(WaitCallback callBack, object state, bool preferLocal) + public static bool QueueUserWorkItem(WaitCallback callBack, object state) { if (callBack == null) { @@ -983,6 +1046,24 @@ namespace System.Threading new QueueUserWorkItemCallbackDefaultContext(callBack, state) : (IThreadPoolWorkItem)new QueueUserWorkItemCallback(callBack, state, context); + ThreadPoolGlobals.workQueue.Enqueue(tpcallBack, forceGlobal: true); + + return true; + } + + public static bool QueueUserWorkItem(Action callBack, TState state, bool preferLocal) + { + if (callBack == null) + { + throw new ArgumentNullException(nameof(callBack)); + } + + ExecutionContext context = ExecutionContext.Capture(); + + IThreadPoolWorkItem tpcallBack = context == ExecutionContext.Default ? + new QueueUserWorkItemCallbackDefaultContext(callBack, state) : + (IThreadPoolWorkItem)new QueueUserWorkItemCallback(callBack, state, context); + ThreadPoolGlobals.workQueue.Enqueue(tpcallBack, forceGlobal: !preferLocal); return true; diff --git a/external/corert/src/System.Private.CoreLib/src/System/Threading/WaitSubsystem.Unix.cs b/external/corert/src/System.Private.CoreLib/src/System/Threading/WaitSubsystem.Unix.cs index f082a5d1d4..1d7367d93c 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Threading/WaitSubsystem.Unix.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Threading/WaitSubsystem.Unix.cs @@ -65,7 +65,7 @@ namespace System.Threading /// - A signaler iterates over waiters and tries to release waiters based on the signal count /// - For each waiter, the signaler checks if the waiter's wait can be terminated /// - When a waiter's wait can be terminated, the signaler does everything necesary before waking the waiter, such that - /// the waiter can simply continue after awakening, including unregistering the wait and assigining ownership if + /// the waiter can simply continue after awakening, including unregistering the wait and assigning ownership if /// applicable /// - Interrupting /// - Interrupting is just another way of signaling a waiting thread. The interrupter unregisters the wait and wakes the diff --git a/external/corert/src/System.Private.CoreLib/src/System/ThrowHelper.cs b/external/corert/src/System.Private.CoreLib/src/System/ThrowHelper.cs index ff7bb2b4b2..a3e3a0602b 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/ThrowHelper.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/ThrowHelper.cs @@ -93,6 +93,10 @@ namespace System { throw new ArgumentException(SR.Argument_DestinationTooShort); } + internal static void ThrowArgumentException_OverlapAlignmentMismatch() + { + throw new ArgumentException(SR.Argument_OverlapAlignmentMismatch); + } internal static void ThrowArgumentOutOfRange_IndexException() { throw GetArgumentOutOfRangeException(ExceptionArgument.index, @@ -164,16 +168,16 @@ namespace System throw new ArgumentNullException(GetArgumentName(argument)); } - internal static void ThrowObjectDisposedException(string objectName, ExceptionResource resource) - { - throw new ObjectDisposedException(objectName, GetResourceString(resource)); - } - internal static void ThrowInvalidOperationException(ExceptionResource resource) { throw new InvalidOperationException(GetResourceString(resource)); } + internal static void ThrowInvalidOperationException_OutstandingReferences() + { + throw new InvalidOperationException(SR.Memory_OutstandingReferences); + } + internal static void ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion() { throw new InvalidOperationException(SR.InvalidOperation_EnumFailedVersion); @@ -204,6 +208,11 @@ namespace System throw new SerializationException(GetResourceString(resource)); } + internal static void ThrowObjectDisposedException_MemoryDisposed() + { + throw new ObjectDisposedException("OwnedMemory", SR.MemoryDisposed); + } + internal static void ThrowNotSupportedException() { throw new NotSupportedException(); @@ -302,6 +311,16 @@ namespace System return "start"; case ExceptionArgument.format: return "format"; + case ExceptionArgument.culture: + return "culture"; + case ExceptionArgument.comparer: + return "comparer"; + case ExceptionArgument.comparable: + return "comparable"; + case ExceptionArgument.source: + return "source"; + case ExceptionArgument.state: + return "state"; default: Debug.Fail("The enum value is not defined, please check the ExceptionArgument Enum."); return ""; @@ -350,10 +369,6 @@ namespace System return SR.TaskCompletionSourceT_TrySetException_NullException; case ExceptionResource.TaskCompletionSourceT_TrySetException_NoExceptions: return SR.TaskCompletionSourceT_TrySetException_NoExceptions; - case ExceptionResource.Memory_ThrowIfDisposed: - return SR.Memory_ThrowIfDisposed; - case ExceptionResource.Memory_OutstandingReferences: - return SR.Memory_OutstandingReferences; default: Debug.Assert(false, "The enum value is not defined, please check the ExceptionResource Enum."); @@ -394,7 +409,12 @@ namespace System exception, pointer, start, - format + format, + culture, + comparer, + comparable, + source, + state } // @@ -421,7 +441,5 @@ namespace System TaskT_TransitionToFinal_AlreadyCompleted, TaskCompletionSourceT_TrySetException_NullException, TaskCompletionSourceT_TrySetException_NoExceptions, - Memory_ThrowIfDisposed, - Memory_OutstandingReferences, } } diff --git a/external/corert/src/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.cs b/external/corert/src/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.cs deleted file mode 100644 index 8e85f21ede..0000000000 --- a/external/corert/src/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.cs +++ /dev/null @@ -1,933 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/*============================================================ -** -** -** -** Purpose: -** This class is used to represent a Dynamic TimeZone. It -** has methods for converting a DateTime between TimeZones -** -** -============================================================*/ - -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Diagnostics; -using System.Globalization; -using System.Runtime.CompilerServices; -using System.Threading; - -namespace System -{ - sealed public partial class TimeZoneInfo - { - // use for generating multi-year DST periods - private static readonly TransitionTime s_transition5_15 = TransitionTime.CreateFixedDateRule(new DateTime(1, 1, 1), 05, 15); - private static readonly TransitionTime s_transition7_15 = TransitionTime.CreateFixedDateRule(new DateTime(1, 1, 1), 07, 15); - private static readonly TransitionTime s_transition10_15 = TransitionTime.CreateFixedDateRule(new DateTime(1, 1, 1), 10, 15); - private static readonly TransitionTime s_transition12_15 = TransitionTime.CreateFixedDateRule(new DateTime(1, 1, 1), 12, 15); - - private TimeZoneInfo(Byte[] data, Boolean dstDisabled) - { - TZifHead t; - DateTime[] dts; - Byte[] typeOfLocalTime; - TZifType[] transitionType; - String zoneAbbreviations; - Boolean[] StandardTime; - Boolean[] GmtTime; - - // parse the raw TZif bytes; this method can throw ArgumentException when the data is malformed. - TZif_ParseRaw(data, out t, out dts, out typeOfLocalTime, out transitionType, out zoneAbbreviations, out StandardTime, out GmtTime); - - _id = c_localId; - _displayName = c_localId; - _baseUtcOffset = TimeSpan.Zero; - - // find the best matching baseUtcOffset and display strings based on the current utcNow value - DateTime utcNow = DateTime.UtcNow; - for (int i = 0; i < dts.Length && dts[i] <= utcNow; i++) - { - int type = typeOfLocalTime[i]; - if (!transitionType[type].IsDst) - { - _baseUtcOffset = transitionType[type].UtcOffset; - _standardDisplayName = TZif_GetZoneAbbreviation(zoneAbbreviations, transitionType[type].AbbreviationIndex); - } - else - { - _daylightDisplayName = TZif_GetZoneAbbreviation(zoneAbbreviations, transitionType[type].AbbreviationIndex); - } - } - - if (dts.Length == 0) - { - // time zones like Africa/Bujumbura and Etc/GMT* have no transition times but still contain - // TZifType entries that may contain a baseUtcOffset and display strings - for (int i = 0; i < transitionType.Length; i++) - { - if (!transitionType[i].IsDst) - { - _baseUtcOffset = transitionType[i].UtcOffset; - _standardDisplayName = TZif_GetZoneAbbreviation(zoneAbbreviations, transitionType[i].AbbreviationIndex); - } - else - { - _daylightDisplayName = TZif_GetZoneAbbreviation(zoneAbbreviations, transitionType[i].AbbreviationIndex); - } - } - } - _id = _standardDisplayName; - _displayName = _standardDisplayName; - - // TZif supports seconds-level granularity with offsets but TimeZoneInfo only supports minutes since it aligns - // with DateTimeOffset, SQL Server, and the W3C XML Specification - if (_baseUtcOffset.Ticks % TimeSpan.TicksPerMinute != 0) - { - _baseUtcOffset = new TimeSpan(_baseUtcOffset.Hours, _baseUtcOffset.Minutes, 0); - } - - if (!dstDisabled) - { - // only create the adjustment rule if DST is enabled - TZif_GenerateAdjustmentRules(out _adjustmentRules, dts, typeOfLocalTime, transitionType, StandardTime, GmtTime); - } - - ValidateTimeZoneInfo(_id, _baseUtcOffset, _adjustmentRules, out _supportsDaylightSavingTime); - } - - // ---- SECTION: public methods --------------* - // - // GetAdjustmentRules - - // - // returns a cloned array of AdjustmentRule objects - // - public AdjustmentRule[] GetAdjustmentRules() - { - if (_adjustmentRules == null) - { - return Array.Empty(); - } - - // The rules we use in Unix cares mostly about the start and end dates but doesn't fill the transition start and end info. - // as the rules now is public, we should fill it properly so the caller doesn't have to know how we use it internally - // and can use it as it is used in Windows - - AdjustmentRule[] rules = new AdjustmentRule[_adjustmentRules.Length]; - - for (int i = 0; i < _adjustmentRules.Length; i++) - { - var rule = _adjustmentRules[i]; - var start = rule.DateStart.Kind == DateTimeKind.Utc ? - new DateTime(TimeZoneInfo.ConvertTime(rule.DateStart, this).Ticks, DateTimeKind.Unspecified) : - rule.DateStart; - var end = rule.DateEnd.Kind == DateTimeKind.Utc ? - new DateTime(TimeZoneInfo.ConvertTime(rule.DateEnd, this).Ticks - 1, DateTimeKind.Unspecified) : - rule.DateEnd; - - var startTransition = TimeZoneInfo.TransitionTime.CreateFixedDateRule(new DateTime(1, 1, 1, start.Hour, start.Minute, start.Second), start.Month, start.Day); - var endTransition = TimeZoneInfo.TransitionTime.CreateFixedDateRule(new DateTime(1, 1, 1, end.Hour, end.Minute, end.Second), end.Month, end.Day); - - rules[i] = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(start.Date, end.Date, rule.DaylightDelta, startTransition, endTransition); - } - - return rules; - } - - public static TimeZoneInfo FindSystemTimeZoneById(string id) - { - // UNIXTODO - throw new NotImplementedException(); - } - - private static void PopulateAllSystemTimeZones(CachedData cachedData) - { - Debug.Assert(Monitor.IsEntered(cachedData)); - // UNIXTODO - throw new NotImplementedException(); - } - - internal static Byte[] GetLocalTzFile() - { - // UNIXTODO - throw new NotImplementedException(); - } - - private static TimeZoneInfo GetLocalTimeZone(CachedData cachedData) - { - Byte[] rawData = GetLocalTzFile(); - - if (rawData != null) - { - try - { - return new TimeZoneInfo(rawData, false); // create a TimeZoneInfo instance from the TZif data w/ DST support - } - catch (ArgumentException) { } - catch (InvalidTimeZoneException) { } - try - { - return new TimeZoneInfo(rawData, true); // create a TimeZoneInfo instance from the TZif data w/o DST support - } - catch (ArgumentException) { } - catch (InvalidTimeZoneException) { } - } - // the data returned from the PAL is completely bogus; return a dummy entry - return CreateCustomTimeZone(c_localId, TimeSpan.Zero, c_localId, c_localId); - } - - // TZFILE(5) BSD File Formats Manual TZFILE(5) - // - // NAME - // tzfile -- timezone information - // - // SYNOPSIS - // #include "/usr/src/lib/libc/stdtime/tzfile.h" - // - // DESCRIPTION - // The time zone information files used by tzset(3) begin with the magic - // characters ``TZif'' to identify them as time zone information files, fol- - // lowed by sixteen bytes reserved for future use, followed by four four- - // byte values written in a ``standard'' byte order (the high-order byte of - // the value is written first). These values are, in order: - // - // tzh_ttisgmtcnt The number of UTC/local indicators stored in the file. - // tzh_ttisstdcnt The number of standard/wall indicators stored in the - // file. - // tzh_leapcnt The number of leap seconds for which data is stored in - // the file. - // tzh_timecnt The number of ``transition times'' for which data is - // stored in the file. - // tzh_typecnt The number of ``local time types'' for which data is - // stored in the file (must not be zero). - // tzh_charcnt The number of characters of ``time zone abbreviation - // strings'' stored in the file. - // - // The above header is followed by tzh_timecnt four-byte values of type - // long, sorted in ascending order. These values are written in ``stan- - // dard'' byte order. Each is used as a transition time (as returned by - // time(3)) at which the rules for computing local time change. Next come - // tzh_timecnt one-byte values of type unsigned char; each one tells which - // of the different types of ``local time'' types described in the file is - // associated with the same-indexed transition time. These values serve as - // indices into an array of ttinfo structures that appears next in the file; - // these structures are defined as follows: - // - // struct ttinfo { - // long tt_gmtoff; - // int tt_isdst; - // unsigned int tt_abbrind; - // }; - // - // Each structure is written as a four-byte value for tt_gmtoff of type - // long, in a standard byte order, followed by a one-byte value for tt_isdst - // and a one-byte value for tt_abbrind. In each structure, tt_gmtoff gives - // the number of seconds to be added to UTC, tt_isdst tells whether t_isdst - // should be set by localtime(3) and tt_abbrind serves as an index into the - // array of time zone abbreviation characters that follow the ttinfo struc- - // ture(s) in the file. - // - // Then there are tzh_leapcnt pairs of four-byte values, written in standard - // byte order; the first value of each pair gives the time (as returned by - // time(3)) at which a leap second occurs; the second gives the total number - // of leap seconds to be applied after the given time. The pairs of values - // are sorted in ascending order by time.b - // - // Then there are tzh_ttisstdcnt standard/wall indicators, each stored as a - // one-byte value; they tell whether the transition times associated with - // local time types were specified as standard time or wall clock time, and - // are used when a time zone file is used in handling POSIX-style time zone - // environment variables. - // - // Finally there are tzh_ttisgmtcnt UTC/local indicators, each stored as a - // one-byte value; they tell whether the transition times associated with - // local time types were specified as UTC or local time, and are used when a - // time zone file is used in handling POSIX-style time zone environment - // variables. - // - // localtime uses the first standard-time ttinfo structure in the file (or - // simply the first ttinfo structure in the absence of a standard-time - // structure) if either tzh_timecnt is zero or the time argument is less - // than the first transition time recorded in the file. - // - // SEE ALSO - // ctime(3), time2posix(3), zic(8) - // - // BSD September 13, 1994 BSD - // - // - // - // TIME(3) BSD Library Functions Manual TIME(3) - // - // NAME - // time -- get time of day - // - // LIBRARY - // Standard C Library (libc, -lc) - // - // SYNOPSIS - // #include - // - // time_t - // time(time_t *tloc); - // - // DESCRIPTION - // The time() function returns the value of time in seconds since 0 hours, 0 - // minutes, 0 seconds, January 1, 1970, Coordinated Universal Time, without - // including leap seconds. If an error occurs, time() returns the value - // (time_t)-1. - // - // The return value is also stored in *tloc, provided that tloc is non-null. - // - // ERRORS - // The time() function may fail for any of the reasons described in - // gettimeofday(2). - // - // SEE ALSO - // gettimeofday(2), ctime(3) - // - // STANDARDS - // The time function conforms to IEEE Std 1003.1-2001 (``POSIX.1''). - // - // BUGS - // Neither ISO/IEC 9899:1999 (``ISO C99'') nor IEEE Std 1003.1-2001 - // (``POSIX.1'') requires time() to set errno on failure; thus, it is impos- - // sible for an application to distinguish the valid time value -1 (repre- - // senting the last UTC second of 1969) from the error return value. - // - // Systems conforming to earlier versions of the C and POSIX standards - // (including older versions of FreeBSD) did not set *tloc in the error - // case. - // - // HISTORY - // A time() function appeared in Version 6 AT&T UNIX. - // - // BSD July 18, 2003 BSD - // - // - - // - // TZif_CalculateTransitionTime - - // - // Example inputs: - // ----------------- - // utc = 1918-03-31T10:00:00.0000000Z - // transitionType = {-08:00:00 DST=False, Index 4} - // standardTime = False - // gmtTime = False - // - private static TransitionTime TZif_CalculateTransitionTime(DateTime utc, TimeSpan offset, - TZifType transitionType, Boolean standardTime, - Boolean gmtTime, out DateTime ruleDate) - { - // convert from UTC to local clock time - Int64 ticks = utc.Ticks + offset.Ticks; - if (ticks > DateTime.MaxValue.Ticks) - { - utc = DateTime.MaxValue; - } - else if (ticks < DateTime.MinValue.Ticks) - { - utc = DateTime.MinValue; - } - else - { - utc = new DateTime(ticks); - } - - DateTime timeOfDay = new DateTime(1, 1, 1, utc.Hour, utc.Minute, utc.Second, utc.Millisecond); - int month = utc.Month; - int day = utc.Day; - - ruleDate = new DateTime(utc.Year, month, day); - // FUTURE: take standardTime/gmtTime into account - return TransitionTime.CreateFixedDateRule(timeOfDay, month, day); - } - - private static void TZif_GenerateAdjustmentRules(out AdjustmentRule[] rules, DateTime[] dts, Byte[] typeOfLocalTime, - TZifType[] transitionType, Boolean[] StandardTime, Boolean[] GmtTime) - { - rules = null; - - int index = 0; - List rulesList = new List(1); - bool succeeded = true; - - while (succeeded && index < dts.Length) - { - succeeded = TZif_GenerateAdjustmentRule(ref index, ref rulesList, dts, typeOfLocalTime, transitionType, StandardTime, GmtTime); - } - - rules = rulesList.ToArray(); - if (rules != null && rules.Length == 0) - { - rules = null; - } - } - - - private static bool TZif_GenerateAdjustmentRule(ref int startIndex, ref List rulesList, DateTime[] dts, Byte[] typeOfLocalTime, - TZifType[] transitionType, Boolean[] StandardTime, Boolean[] GmtTime) - { - int index = startIndex; - bool Dst = false; - int DstStartIndex = -1; - int DstEndIndex = -1; - DateTime startDate = DateTime.MinValue.Date; - DateTime endDate = DateTime.MaxValue.Date; - - - // find the next DST transition start time index - while (!Dst && index < typeOfLocalTime.Length) - { - int typeIndex = typeOfLocalTime[index]; - if (typeIndex < transitionType.Length && transitionType[typeIndex].IsDst) - { - // found the next DST transition start time - Dst = true; - DstStartIndex = index; - } - else - { - index++; - } - } - - // find the next DST transition end time index - while (Dst && index < typeOfLocalTime.Length) - { - int typeIndex = typeOfLocalTime[index]; - if (typeIndex < transitionType.Length && !transitionType[typeIndex].IsDst) - { - // found the next DST transition end time - Dst = false; - DstEndIndex = index; - } - else - { - index++; - } - } - - - // - // construct the adjustment rule from the two indices - // - if (DstStartIndex >= 0) - { - DateTime startTransitionDate = dts[DstStartIndex]; - DateTime endTransitionDate; - - - if (DstEndIndex == -1) - { - // we found a DST start but no DST end; in this case use the - // prior non-DST entry if it exists, else use the current entry for both start and end (e.g., zero daylightDelta) - if (DstStartIndex > 0) - { - DstEndIndex = DstStartIndex - 1; - } - else - { - DstEndIndex = DstStartIndex; - } - endTransitionDate = DateTime.MaxValue; - } - else - { - endTransitionDate = dts[DstEndIndex]; - } - - int dstStartTypeIndex = typeOfLocalTime[DstStartIndex]; - int dstEndTypeIndex = typeOfLocalTime[DstEndIndex]; - - TimeSpan daylightBias = transitionType[dstStartTypeIndex].UtcOffset - transitionType[dstEndTypeIndex].UtcOffset; - // TZif supports seconds-level granularity with offsets but TimeZoneInfo only supports minutes since it aligns - // with DateTimeOffset, SQL Server, and the W3C XML Specification - if (daylightBias.Ticks % TimeSpan.TicksPerMinute != 0) - { - daylightBias = new TimeSpan(daylightBias.Hours, daylightBias.Minutes, 0); - } - - // - // the normal case is less than 12 months between transition times. However places like America/Catamarca - // have DST from 1946-1963 straight without a gap. In that case we need to create a series of Adjustment - // Rules to fudge the multi-year DST period - // - if ((endTransitionDate - startTransitionDate).Ticks <= TimeSpan.TicksPerDay * 364) - { - TransitionTime dstStart; - TransitionTime dstEnd; - TimeSpan startTransitionOffset = (DstStartIndex > 0 ? transitionType[typeOfLocalTime[DstStartIndex - 1]].UtcOffset : transitionType[dstEndTypeIndex].UtcOffset); - TimeSpan endTransitionOffset = (DstEndIndex > 0 ? transitionType[typeOfLocalTime[DstEndIndex - 1]].UtcOffset : transitionType[dstStartTypeIndex].UtcOffset); - - - dstStart = TZif_CalculateTransitionTime(startTransitionDate, - startTransitionOffset, - transitionType[dstStartTypeIndex], - StandardTime[dstStartTypeIndex], - GmtTime[dstStartTypeIndex], - out startDate); - - dstEnd = TZif_CalculateTransitionTime(endTransitionDate, - endTransitionOffset, - transitionType[dstEndTypeIndex], - StandardTime[dstEndTypeIndex], - GmtTime[dstEndTypeIndex], - out endDate); - - - - // calculate the AdjustmentRule end date - if (DstStartIndex >= DstEndIndex) - { - // we found a DST start but no DST end - endDate = DateTime.MaxValue.Date; - } - - AdjustmentRule r = AdjustmentRule.CreateAdjustmentRule(startDate, endDate, daylightBias, dstStart, dstEnd); - rulesList.Add(r); - } - else - { - // create the multi-year DST rule series: - // - // For example America/Catamarca: - // 1946-10-01T04:00:00.0000000Z {-03:00:00 DST=True} - // 1963-10-01T03:00:00.0000000Z {-04:00:00 DST=False} - // - // gets converted into a series of overlapping 5/7month adjustment rules: - // - // [AdjustmentRule #0] // start rule - // [1946/09/31 - 1947/06/15] // * starts 1 day prior to startTransitionDate - // [start: 10/01 @4:00 ] // * N months long, stopping at month 6 or 11 - // [end : 07/15 ] // notice how the _end_ is outside the range - // - // [AdjustmentRule #1] // middle-year all-DST rule - // [1947/06/16 - 1947/11/15] // * starts 1 day after last day in previous rule - // [start: 05/15 ] // * 5 months long, stopping at month 6 or 11 - // [end : 12/15 ] // notice how the _start and end_ are outside the range - // - // [AdjustmentRule #2] // middle-year all-DST rule - // [1947/11/16 - 1947/06/15] // * starts 1 day after last day in previous rule - // [start: 10/01 ] // * 7 months long, stopping at month 6 or 11 - // [end : 07/15 ] // notice how the _start and end_ are outside the range - // - // ......................... - // - // [AdjustmentRule #N] // end rule - // [1963/06/16 - 1946/10/02] // * starts 1 day after last day in previous rule - // [start: 05/15 ] // * N months long, stopping 1 day after endTransitionDate - // [end : 10/01 ] // notice how the _start_ is outside the range - // - - // create the first rule from N to either 06/15 or 11/15 - TZif_CreateFirstMultiYearRule(ref rulesList, daylightBias, startTransitionDate, DstStartIndex, dstStartTypeIndex, dstEndTypeIndex, - dts, transitionType, typeOfLocalTime, StandardTime, GmtTime); - - // create the filler rules - TZif_CreateMiddleMultiYearRules(ref rulesList, daylightBias, endTransitionDate); - - // create the last rule - TZif_CreateLastMultiYearRule(ref rulesList, daylightBias, endTransitionDate, DstStartIndex, dstStartTypeIndex, DstEndIndex, dstEndTypeIndex, - dts, transitionType, typeOfLocalTime, StandardTime, GmtTime); - } - - startIndex = index + 1; - return true; - } - - // setup the start values for the next call to TZif_GenerateAdjustmentRule(...) - startIndex = index + 1; - return false; // did not create a new AdjustmentRule - } - - private static void TZif_CreateFirstMultiYearRule(ref List rulesList, TimeSpan daylightBias, DateTime startTransitionDate, - int DstStartIndex, int dstStartTypeIndex, int dstEndTypeIndex, DateTime[] dts, TZifType[] transitionType, - Byte[] typeOfLocalTime, bool[] StandardTime, bool[] GmtTime) - { - // [AdjustmentRule #0] // start rule - // [1946/09/31 - 1947/06/15] // * starts 1 day prior to startTransitionDate - // [start: 10/01 @4:00 ] // * N months long, stopping at month 6 or 11 - // [end : 07/15 ] // notice how the _end_ is outside the range - - DateTime startDate; - DateTime endDate; - TransitionTime dstStart; - TransitionTime dstEnd; - - TimeSpan startTransitionOffset = (DstStartIndex > 0 ? transitionType[typeOfLocalTime[DstStartIndex - 1]].UtcOffset : transitionType[dstEndTypeIndex].UtcOffset); - - dstStart = TZif_CalculateTransitionTime(startTransitionDate, - startTransitionOffset, - transitionType[dstStartTypeIndex], - StandardTime[dstStartTypeIndex], - GmtTime[dstStartTypeIndex], - out startDate); - - // - // Choosing the endDate based on the startDate: - // - // startTransitionDate.Month -> end - // 1 4|5 8|9 12 - // [-> 06/15]|[-> 11/15]|[-> 06/15] - // - int startDateMonth = startDate.Month; - int startDateYear = startDate.Year; - - if (startDateMonth <= 4) - { - endDate = new DateTime(startDateYear, 06, 15); - dstEnd = s_transition7_15; - } - else if (startDateMonth <= 8) - { - endDate = new DateTime(startDateYear, 11, 15); - dstEnd = s_transition12_15; - } - else if (startDateYear < 9999) - { - endDate = new DateTime(startDateYear + 1, 06, 15); - dstEnd = s_transition7_15; - } - else - { - endDate = DateTime.MaxValue; - dstEnd = s_transition7_15; - } - - AdjustmentRule r = AdjustmentRule.CreateAdjustmentRule(startDate, endDate, daylightBias, dstStart, dstEnd); - rulesList.Add(r); - } - - - private static void TZif_CreateLastMultiYearRule(ref List rulesList, TimeSpan daylightBias, DateTime endTransitionDate, - int DstStartIndex, int dstStartTypeIndex, int DstEndIndex, int dstEndTypeIndex, DateTime[] dts, TZifType[] transitionType, - Byte[] typeOfLocalTime, bool[] StandardTime, bool[] GmtTime) - { - // [AdjustmentRule #N] // end rule - // [1963/06/16 - 1946/10/02] // * starts 1 day after last day in previous rule - // [start: 05/15 ] // * N months long, stopping 1 day after endTransitionDate - // [end : 10/01 ] // notice how the _start_ is outside the range - - DateTime endDate; - TransitionTime dstEnd; - - TimeSpan endTransitionOffset = (DstEndIndex > 0 ? transitionType[typeOfLocalTime[DstEndIndex - 1]].UtcOffset : transitionType[dstStartTypeIndex].UtcOffset); - - - dstEnd = TZif_CalculateTransitionTime(endTransitionDate, - endTransitionOffset, - transitionType[dstEndTypeIndex], - StandardTime[dstEndTypeIndex], - GmtTime[dstEndTypeIndex], - out endDate); - - if (DstStartIndex >= DstEndIndex) - { - // we found a DST start but no DST end - endDate = DateTime.MaxValue.Date; - } - - AdjustmentRule prevRule = rulesList[rulesList.Count - 1]; // grab the last element of the MultiYearRule sequence - int y = prevRule.DateEnd.Year; - if (prevRule.DateEnd.Month <= 6) - { - // create a rule from 06/16/YYYY to endDate - AdjustmentRule r = AdjustmentRule.CreateAdjustmentRule(new DateTime(y, 06, 16), endDate, daylightBias, s_transition5_15, dstEnd); - rulesList.Add(r); - } - else - { - // create a rule from 11/16/YYYY to endDate - AdjustmentRule r = AdjustmentRule.CreateAdjustmentRule(new DateTime(y, 11, 16), endDate, daylightBias, s_transition10_15, dstEnd); - rulesList.Add(r); - } - } - - - private static void TZif_CreateMiddleMultiYearRules(ref List rulesList, TimeSpan daylightBias, DateTime endTransitionDate) - { - // - // [AdjustmentRule #1] // middle-year all-DST rule - // [1947/06/16 - 1947/11/15] // * starts 1 day after last day in previous rule - // [start: 05/15 ] // * 5 months long, stopping at month 6 or 11 - // [end : 12/15 ] // notice how the _start and end_ are outside the range - // - // [AdjustmentRule #2] // middle-year all-DST rule - // [1947/11/16 - 1947/06/15] // * starts 1 day after last day in previous rule - // [start: 10/01 ] // * 7 months long, stopping at month 6 or 11 - // [end : 07/15 ] // notice how the _start and end_ are outside the range - // - // ......................... - - AdjustmentRule prevRule = rulesList[rulesList.Count - 1]; // grab the first element of the MultiYearRule sequence - DateTime endDate; - - // - // Choosing the last endDate based on the endTransitionDate - // - // endTransitionDate.Month -> end - // 1 4|5 8|9 12 - // [11/15 <-]|[11/15 <-]|[06/15 <-] - // - if (endTransitionDate.Month <= 8) - { - // set the end date to 11/15/YYYY-1 - endDate = new DateTime(endTransitionDate.Year - 1, 11, 15); - } - else - { - // set the end date to 06/15/YYYY - endDate = new DateTime(endTransitionDate.Year, 06, 15); - } - - while (prevRule.DateEnd < endDate) - { - // the last endDate will be on either 06/15 or 11/15 - int y = prevRule.DateEnd.Year; - if (prevRule.DateEnd.Month <= 6) - { - // create a rule from 06/16/YYYY to 11/15/YYYY - AdjustmentRule r = AdjustmentRule.CreateAdjustmentRule(new DateTime(y, 06, 16), new DateTime(y, 11, 15), - daylightBias, s_transition5_15, s_transition12_15); - prevRule = r; - rulesList.Add(r); - } - else - { - // create a rule from 11/16/YYYY to 06/15/YYYY+1 - AdjustmentRule r = AdjustmentRule.CreateAdjustmentRule(new DateTime(y, 11, 16), new DateTime(y + 1, 06, 15), - daylightBias, s_transition10_15, s_transition7_15); - prevRule = r; - rulesList.Add(r); - } - } - } - - - // Returns the Substring from zoneAbbreviations starting at index and ending at '\0' - // zoneAbbreviations is expected to be in the form: "PST\0PDT\0PWT\0\PPT" - private static String TZif_GetZoneAbbreviation(String zoneAbbreviations, int index) - { - int lastIndex = zoneAbbreviations.IndexOf('\0', index); - if (lastIndex > 0) - { - return zoneAbbreviations.Substring(index, lastIndex - index); - } - else - { - return zoneAbbreviations.Substring(index); - } - } - - // verify the 'index' is referenced from the typeOfLocalTime byte array. - // - private static Boolean TZif_ValidTransitionType(int index, Byte[] typeOfLocalTime) - { - Boolean result = false; - - if (typeOfLocalTime != null) - { - for (int i = 0; !result && i < typeOfLocalTime.Length; i++) - { - if (index == typeOfLocalTime[i]) - { - result = true; - } - } - } - return result; - } - - // Converts an array of bytes into an int - always using standard byte order (Big Endian) - // per TZif file standard - private static int TZif_ToInt32(byte[] value, int startIndex) - { - return (value[startIndex] << 24) | (value[startIndex + 1] << 16) | (value[startIndex + 2] << 8) | value[startIndex + 3]; - } - - private static void TZif_ParseRaw(Byte[] data, out TZifHead t, out DateTime[] dts, out Byte[] typeOfLocalTime, out TZifType[] transitionType, - out String zoneAbbreviations, out Boolean[] StandardTime, out Boolean[] GmtTime) - { - // initialize the out parameters in case the TZifHead ctor throws - dts = null; - typeOfLocalTime = null; - transitionType = null; - zoneAbbreviations = String.Empty; - StandardTime = null; - GmtTime = null; - - // read in the 44-byte TZ header containing the count/length fields - // - t = new TZifHead(data, 0); - int index = TZifHead.Length; - - // initialize the containers for the rest of the TZ data - dts = new DateTime[t.TimeCount]; - typeOfLocalTime = new Byte[t.TimeCount]; - transitionType = new TZifType[t.TypeCount]; - zoneAbbreviations = String.Empty; - StandardTime = new Boolean[t.TypeCount]; - GmtTime = new Boolean[t.TypeCount]; - - - // read in the 4-byte UTC transition points and convert them to Windows - // - for (int i = 0; i < t.TimeCount; i++) - { - int unixTime = TZif_ToInt32(data, index); - dts[i] = TZif_UnixTimeToWindowsTime(unixTime); - index += 4; - } - - // read in the Type Indices; there is a 1:1 mapping of UTC transition points to Type Indices - // these indices directly map to the array index in the transitionType array below - // - for (int i = 0; i < t.TimeCount; i++) - { - typeOfLocalTime[i] = data[index]; - index += 1; - } - - // read in the Type table. Each 6-byte entry represents - // {UtcOffset, IsDst, AbbreviationIndex} - // - // each AbbreviationIndex is a character index into the zoneAbbreviations string below - // - for (int i = 0; i < t.TypeCount; i++) - { - transitionType[i] = new TZifType(data, index); - index += 6; - } - - // read in the Abbreviation ASCII string. This string will be in the form: - // "PST\0PDT\0PWT\0\PPT" - // - System.Text.Encoding enc = new System.Text.UTF8Encoding(); - zoneAbbreviations = enc.GetString(data, index, (int)t.CharCount); - index += (int)t.CharCount; - - // skip ahead of the Leap-Seconds Adjustment data. In a future release, consider adding - // support for Leap-Seconds - // - index += (int)(t.LeapCount * 8); // skip the leap second transition times - - // read in the Standard Time table. There should be a 1:1 mapping between Type-Index and Standard - // Time table entries. - // - // TRUE = transition time is standard time - // FALSE = transition time is wall clock time - // ABSENT = transition time is wall clock time - // - for (int i = 0; i < t.IsStdCount && i < t.TypeCount && index < data.Length; i++) - { - StandardTime[i] = (data[index++] != 0); - } - - // read in the GMT Time table. There should be a 1:1 mapping between Type-Index and GMT Time table - // entries. - // - // TRUE = transition time is UTC - // FALSE = transition time is local time - // ABSENT = transition time is local time - // - for (int i = 0; i < t.IsGmtCount && i < t.TypeCount && index < data.Length; i++) - { - GmtTime[i] = (data[index++] != 0); - } - } - - - // Windows NT time is specified as the number of 100 nanosecond intervals since January 1, 1601. - // UNIX time is specified as the number of seconds since January 1, 1970. There are 134,774 days - // (or 11,644,473,600 seconds) between these dates. - // - private static DateTime TZif_UnixTimeToWindowsTime(int unixTime) - { - // Add 11,644,473,600 and multiply by 10,000,000. - Int64 ntTime = (((Int64)unixTime) + 11644473600) * 10000000; - return DateTime.FromFileTimeUtc(ntTime); - } - - private struct TZifType - { - private const int c_len = 6; - public static int Length - { - get - { - return c_len; - } - } - - public TimeSpan UtcOffset; - public Boolean IsDst; - public Byte AbbreviationIndex; - - public TZifType(Byte[] data, Int32 index) - { - if (data == null || data.Length < index + c_len) - { - throw new ArgumentException(SR.Argument_TimeZoneInfoInvalidTZif, nameof(data)); - } - UtcOffset = new TimeSpan(0, 0, TZif_ToInt32(data, index + 00)); - IsDst = (data[index + 4] != 0); - AbbreviationIndex = data[index + 5]; - } - } - - private struct TZifHead - { - private const int c_len = 44; - public static int Length - { - get - { - return c_len; - } - } - - public TZifHead(Byte[] data, Int32 index) - { - if (data == null || data.Length < c_len) - { - throw new ArgumentException("bad data", nameof(data)); - } - - Magic = (uint)TZif_ToInt32(data, index + 00); - - if (Magic != 0x545A6966) - { - // 0x545A6966 = {0x54, 0x5A, 0x69, 0x66} = "TZif" - throw new ArgumentException(SR.Argument_TimeZoneInfoBadTZif, nameof(data)); - } - - // don't use the BitConverter class which parses data - // based on the Endianess of the machine architecture. - // this data is expected to always be in "standard byte order", - // regardless of the machine it is being processed on. - - IsGmtCount = (uint)TZif_ToInt32(data, index + 20); - // skip the 16 byte reserved field - IsStdCount = (uint)TZif_ToInt32(data, index + 24); - LeapCount = (uint)TZif_ToInt32(data, index + 28); - TimeCount = (uint)TZif_ToInt32(data, index + 32); - TypeCount = (uint)TZif_ToInt32(data, index + 36); - CharCount = (uint)TZif_ToInt32(data, index + 40); - } - - public UInt32 Magic; // TZ_MAGIC "TZif" - // public Byte[16] Reserved; // reserved for future use - public UInt32 IsGmtCount; // number of transition time flags - public UInt32 IsStdCount; // number of transition time flags - public UInt32 LeapCount; // number of leap seconds - public UInt32 TimeCount; // number of transition times - public UInt32 TypeCount; // number of local time types - public UInt32 CharCount; // number of abbreviated characters - } - } -} diff --git a/external/corert/src/System.Private.CoreLib/src/System/TimeZoneInfo.Win32.cs b/external/corert/src/System.Private.CoreLib/src/System/TimeZoneInfo.Win32.cs deleted file mode 100644 index cbdf985602..0000000000 --- a/external/corert/src/System.Private.CoreLib/src/System/TimeZoneInfo.Win32.cs +++ /dev/null @@ -1,1161 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/*============================================================ -** -** -** -** Purpose: -** This class is used to represent a Dynamic TimeZone. It -** has methods for converting a DateTime between TimeZones, -** and for reading TimeZone data from the Windows Registry -** -** -============================================================*/ - -using Microsoft.Win32; -using Microsoft.Win32.SafeHandles; -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Diagnostics; -using System.Globalization; -using System.IO; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Runtime.Serialization; -using System.Runtime.Versioning; -using System.Security; -using System.Text; -using System.Threading; - -using TIME_ZONE_INFORMATION = Interop.mincore.TIME_ZONE_INFORMATION; -using TIME_DYNAMIC_ZONE_INFORMATION = Interop.mincore.TIME_DYNAMIC_ZONE_INFORMATION; -using REGISTRY_TIME_ZONE_INFORMATION = Interop.mincore.REGISTRY_TIME_ZONE_INFORMATION; - -namespace System -{ - sealed public partial class TimeZoneInfo - { - // registry constants for the 'Time Zones' hive - // - private const string c_timeZonesRegistryHive = @"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones"; - private const string c_timeZonesRegistryHivePermissionList = @"HKEY_LOCAL_MACHINE\" + c_timeZonesRegistryHive; - private const string c_displayValue = "Display"; - private const string c_daylightValue = "Dlt"; - private const string c_standardValue = "Std"; - private const string c_muiDisplayValue = "MUI_Display"; - private const string c_muiDaylightValue = "MUI_Dlt"; - private const string c_muiStandardValue = "MUI_Std"; - private const string c_timeZoneInfoValue = "TZI"; - private const string c_firstEntryValue = "FirstEntry"; - private const string c_lastEntryValue = "LastEntry"; - - private const int c_maxKeyLength = 255; - - private const int c_regByteLength = 44; - - // Number of 100ns ticks per time unit - private const long c_ticksPerMillisecond = 10000; - private const long c_ticksPerSecond = c_ticksPerMillisecond * 1000; - private const long c_ticksPerMinute = c_ticksPerSecond * 60; - private const long c_ticksPerHour = c_ticksPerMinute * 60; - private const long c_ticksPerDay = c_ticksPerHour * 24; - private const long c_ticksPerDayRange = c_ticksPerDay - c_ticksPerMillisecond; - - // ---- SECTION: public methods --------------* - - // - // GetAdjustmentRules - - // - // returns a cloned array of AdjustmentRule objects - // - public AdjustmentRule[] GetAdjustmentRules() - { - if (_adjustmentRules == null) - { - return Array.Empty(); - } - - return (AdjustmentRule[])_adjustmentRules.Clone(); - } - - private static void PopulateAllSystemTimeZones(CachedData cachedData) - { - Debug.Assert(Monitor.IsEntered(cachedData)); - - using (RegistryKey reg = RegistryKey.GetBaseKey(RegistryKey.HKEY_LOCAL_MACHINE).OpenSubKey(c_timeZonesRegistryHive, writable: false)) - { - if (reg != null) - { - foreach (string keyName in reg.GetSubKeyNames()) - { - TimeZoneInfo value; - Exception ex; - TryGetTimeZone(keyName, false, out value, out ex, cachedData); // populate the cache - } - } - } - } - - // -------- SECTION: constructors -----------------* - // - // TimeZoneInfo - - // - // private ctor - // - private unsafe TimeZoneInfo(TIME_ZONE_INFORMATION zone, Boolean dstDisabled) - { - if (String.IsNullOrEmpty(new String(zone.StandardName))) - { - _id = c_localId; // the ID must contain at least 1 character - initialize _id to "Local" - } - else - { - _id = new String(zone.StandardName); - } - _baseUtcOffset = new TimeSpan(0, -(zone.Bias), 0); - - if (!dstDisabled) - { - // only create the adjustment rule if DST is enabled - REGISTRY_TIME_ZONE_INFORMATION regZone = new REGISTRY_TIME_ZONE_INFORMATION(zone); - AdjustmentRule rule = CreateAdjustmentRuleFromTimeZoneInformation(regZone, DateTime.MinValue.Date, DateTime.MaxValue.Date, zone.Bias); - if (rule != null) - { - _adjustmentRules = new AdjustmentRule[1]; - _adjustmentRules[0] = rule; - } - } - - ValidateTimeZoneInfo(_id, _baseUtcOffset, _adjustmentRules, out _supportsDaylightSavingTime); - _displayName = new String(zone.StandardName); - _standardDisplayName = new String(zone.StandardName); - _daylightDisplayName = new String(zone.DaylightName); - } - - // ----- SECTION: internal static utility methods ----------------* - - // - // CheckDaylightSavingTimeNotSupported - - // - // Helper function to check if the current TimeZoneInformation struct does not support DST. This - // check returns true when the DaylightDate == StandardDate - // - // This check is only meant to be used for "Local". - // - private static Boolean CheckDaylightSavingTimeNotSupported(TIME_ZONE_INFORMATION timeZone) - { - return (timeZone.DaylightDate.wYear == timeZone.StandardDate.wYear - && timeZone.DaylightDate.wMonth == timeZone.StandardDate.wMonth - && timeZone.DaylightDate.wDayOfWeek == timeZone.StandardDate.wDayOfWeek - && timeZone.DaylightDate.wDay == timeZone.StandardDate.wDay - && timeZone.DaylightDate.wHour == timeZone.StandardDate.wHour - && timeZone.DaylightDate.wMinute == timeZone.StandardDate.wMinute - && timeZone.DaylightDate.wSecond == timeZone.StandardDate.wSecond - && timeZone.DaylightDate.wMilliseconds == timeZone.StandardDate.wMilliseconds); - } - - // - // CreateAdjustmentRuleFromTimeZoneInformation- - // - // Converts a REGISTRY_TIME_ZONE_INFORMATION (REG_TZI_FORMAT struct) to an AdjustmentRule - // - private static AdjustmentRule CreateAdjustmentRuleFromTimeZoneInformation(REGISTRY_TIME_ZONE_INFORMATION timeZoneInformation, DateTime startDate, DateTime endDate, int defaultBaseUtcOffset) - { - AdjustmentRule rule; - bool supportsDst = (timeZoneInformation.StandardDate.wMonth != 0); - - if (!supportsDst) - { - if (timeZoneInformation.Bias == defaultBaseUtcOffset) - { - // this rule will not contain any information to be used to adjust dates. just ignore it - return null; - } - - return rule = AdjustmentRule.CreateAdjustmentRule( - startDate, - endDate, - TimeSpan.Zero, // no daylight saving transition - TransitionTime.CreateFixedDateRule(DateTime.MinValue, 1, 1), - TransitionTime.CreateFixedDateRule(DateTime.MinValue.AddMilliseconds(1), 1, 1), - new TimeSpan(0, defaultBaseUtcOffset - timeZoneInformation.Bias, 0)); // Bias delta is all what we need from this rule - } - - // - // Create an AdjustmentRule with TransitionTime objects - // - TransitionTime daylightTransitionStart; - if (!TransitionTimeFromTimeZoneInformation(timeZoneInformation, out daylightTransitionStart, true /* start date */)) - { - return null; - } - - TransitionTime daylightTransitionEnd; - if (!TransitionTimeFromTimeZoneInformation(timeZoneInformation, out daylightTransitionEnd, false /* end date */)) - { - return null; - } - - if (daylightTransitionStart.Equals(daylightTransitionEnd)) - { - // this happens when the time zone does support DST but the OS has DST disabled - return null; - } - - rule = AdjustmentRule.CreateAdjustmentRule( - startDate, - endDate, - new TimeSpan(0, -timeZoneInformation.DaylightBias, 0), - (TransitionTime)daylightTransitionStart, - (TransitionTime)daylightTransitionEnd, - new TimeSpan(0, defaultBaseUtcOffset - timeZoneInformation.Bias, 0)); - - return rule; - } - - // - // FindIdFromTimeZoneInformation - - // - // Helper function that searches the registry for a time zone entry - // that matches the TimeZoneInformation struct - // - private static String FindIdFromTimeZoneInformation(TIME_ZONE_INFORMATION timeZone, out Boolean dstDisabled) - { - dstDisabled = false; - - using (RegistryKey key = RegistryKey.GetBaseKey(RegistryKey.HKEY_LOCAL_MACHINE).OpenSubKey( - c_timeZonesRegistryHive, - false - )) - { - if (key == null) - { - return null; - } - foreach (string keyName in key.GetSubKeyNames()) - { - if (TryCompareTimeZoneInformationToRegistry(timeZone, keyName, out dstDisabled)) - { - return keyName; - } - } - } - return null; - } - - // - // GetLocalTimeZone - - // - // Helper function for retrieving the local system time zone. - // - // returns a new TimeZoneInfo instance - // - // may throw COMException, TimeZoneNotFoundException, InvalidTimeZoneException - // - // assumes cachedData lock is taken - // - static unsafe private TimeZoneInfo GetLocalTimeZone(CachedData cachedData) - { - String id = null; - - // - // Try using the "kernel32!GetDynamicTimeZoneInformation" API to get the "id" - // - Interop.mincore.TIME_DYNAMIC_ZONE_INFORMATION dynamicTimeZoneInformation = - new Interop.mincore.TIME_DYNAMIC_ZONE_INFORMATION(); - - // call kernel32!GetDynamicTimeZoneInformation... - long result = Interop.mincore.GetDynamicTimeZoneInformation(out dynamicTimeZoneInformation); - if (result == Interop.mincore.TIME_ZONE_ID_INVALID) - { - // return a dummy entry - return CreateCustomTimeZone(c_localId, TimeSpan.Zero, c_localId, c_localId); - } - - TIME_ZONE_INFORMATION timeZoneInformation = - new TIME_ZONE_INFORMATION(dynamicTimeZoneInformation); - - Boolean dstDisabled = dynamicTimeZoneInformation.DynamicDaylightTimeDisabled != 0; - - // check to see if we can use the key name returned from the API call - if (!String.IsNullOrEmpty(new String(dynamicTimeZoneInformation.TimeZoneKeyName))) - { - TimeZoneInfo zone; - Exception ex; - - if (TryGetTimeZone(new String(dynamicTimeZoneInformation.TimeZoneKeyName), dstDisabled, out zone, out ex, cachedData) == TimeZoneInfoResult.Success) - { - // successfully loaded the time zone from the registry - return zone; - } - } - - // the key name was not returned or it pointed to a bogus entry - search for the entry ourselves - id = FindIdFromTimeZoneInformation(timeZoneInformation, out dstDisabled); - - if (id != null) - { - TimeZoneInfo zone; - Exception ex; - if (TryGetTimeZone(id, dstDisabled, out zone, out ex, cachedData) == TimeZoneInfoResult.Success) - { - // successfully loaded the time zone from the registry - return zone; - } - } - - // We could not find the data in the registry. Fall back to using - // the data from the Win32 API - return GetLocalTimeZoneFromWin32Data(timeZoneInformation, dstDisabled); - } - - // - // GetLocalTimeZoneFromWin32Data - - // - // Helper function used by 'GetLocalTimeZone()' - this function wraps a bunch of - // try/catch logic for handling the TimeZoneInfo private constructor that takes - // a TIME_ZONE_INFORMATION structure. - // - private static TimeZoneInfo GetLocalTimeZoneFromWin32Data(TIME_ZONE_INFORMATION timeZoneInformation, Boolean dstDisabled) - { - // first try to create the TimeZoneInfo with the original 'dstDisabled' flag - try - { - return new TimeZoneInfo(timeZoneInformation, dstDisabled); - } - catch (ArgumentException) { } - catch (InvalidTimeZoneException) { } - - // if 'dstDisabled' was false then try passing in 'true' as a last ditch effort - if (!dstDisabled) - { - try - { - return new TimeZoneInfo(timeZoneInformation, true); - } - catch (ArgumentException) { } - catch (InvalidTimeZoneException) { } - } - - // the data returned from Windows is completely bogus; return a dummy entry - return CreateCustomTimeZone(c_localId, TimeSpan.Zero, c_localId, c_localId); - } - - // - // FindSystemTimeZoneById - - // - // Helper function for retrieving a TimeZoneInfo object by . - // This function wraps the logic necessary to keep the private - // SystemTimeZones cache in working order - // - // This function will either return a valid TimeZoneInfo instance or - // it will throw 'InvalidTimeZoneException' / 'TimeZoneNotFoundException'. - // - public static TimeZoneInfo FindSystemTimeZoneById(string id) - { - // Special case for Utc as it will not exist in the dictionary with the rest - // of the system time zones. There is no need to do this check for Local.Id - // since Local is a real time zone that exists in the dictionary cache - if (String.Compare(id, c_utcId, StringComparison.OrdinalIgnoreCase) == 0) - { - return TimeZoneInfo.Utc; - } - - if (id == null) - { - throw new ArgumentNullException(nameof(id)); - } - if (id.Length == 0 || id.Length > c_maxKeyLength || id.Contains("\0")) - { - throw new TimeZoneNotFoundException(String.Format(SR.TimeZoneNotFound_MissingRegistryData, id)); - } - - TimeZoneInfo value; - Exception e; - - TimeZoneInfoResult result; - - CachedData cachedData = s_cachedData; - - lock (cachedData) - { - result = TryGetTimeZone(id, false, out value, out e, cachedData); - } - - if (result == TimeZoneInfoResult.Success) - { - return value; - } - else if (result == TimeZoneInfoResult.InvalidTimeZoneException) - { - throw new InvalidTimeZoneException(String.Format(SR.InvalidTimeZone_InvalidRegistryData, id), e); - } - else if (result == TimeZoneInfoResult.SecurityException) - { - throw new SecurityException(String.Format(SR.Security_CannotReadRegistryData, id), e); - } - else - { - throw new TimeZoneNotFoundException(String.Format(SR.TimeZoneNotFound_MissingRegistryData, id), e); - } - } - - // - // TransitionTimeFromTimeZoneInformation - - // - // Converts a REGISTRY_TIME_ZONE_INFORMATION (REG_TZI_FORMAT struct) to a TransitionTime - // - // * when the argument 'readStart' is true the corresponding daylightTransitionTimeStart field is read - // * when the argument 'readStart' is false the corresponding dayightTransitionTimeEnd field is read - // - private static bool TransitionTimeFromTimeZoneInformation(REGISTRY_TIME_ZONE_INFORMATION timeZoneInformation, out TransitionTime transitionTime, bool readStartDate) - { - // - // SYSTEMTIME - - // - // If the time zone does not support daylight saving time or if the caller needs - // to disable daylight saving time, the wMonth member in the SYSTEMTIME structure - // must be zero. If this date is specified, the DaylightDate value in the - // TIME_ZONE_INFORMATION structure must also be specified. Otherwise, the system - // assumes the time zone data is invalid and no changes will be applied. - // - bool supportsDst = (timeZoneInformation.StandardDate.wMonth != 0); - - if (!supportsDst) - { - transitionTime = default(TransitionTime); - return false; - } - - // - // SYSTEMTIME - - // - // * FixedDateRule - - // If the Year member is not zero, the transition date is absolute; it will only occur one time - // - // * FloatingDateRule - - // To select the correct day in the month, set the Year member to zero, the Hour and Minute - // members to the transition time, the DayOfWeek member to the appropriate weekday, and the - // Day member to indicate the occurence of the day of the week within the month (first through fifth). - // - // Using this notation, specify the 2:00a.m. on the first Sunday in April as follows: - // Hour = 2, - // Month = 4, - // DayOfWeek = 0, - // Day = 1. - // - // Specify 2:00a.m. on the last Thursday in October as follows: - // Hour = 2, - // Month = 10, - // DayOfWeek = 4, - // Day = 5. - // - if (readStartDate) - { - // - // read the "daylightTransitionStart" - // - if (timeZoneInformation.DaylightDate.wYear == 0) - { - transitionTime = TransitionTime.CreateFloatingDateRule( - new DateTime(1, /* year */ - 1, /* month */ - 1, /* day */ - timeZoneInformation.DaylightDate.wHour, - timeZoneInformation.DaylightDate.wMinute, - timeZoneInformation.DaylightDate.wSecond, - timeZoneInformation.DaylightDate.wMilliseconds), - timeZoneInformation.DaylightDate.wMonth, - timeZoneInformation.DaylightDate.wDay, /* Week 1-5 */ - (DayOfWeek)timeZoneInformation.DaylightDate.wDayOfWeek); - } - else - { - transitionTime = TransitionTime.CreateFixedDateRule( - new DateTime(1, /* year */ - 1, /* month */ - 1, /* day */ - timeZoneInformation.DaylightDate.wHour, - timeZoneInformation.DaylightDate.wMinute, - timeZoneInformation.DaylightDate.wSecond, - timeZoneInformation.DaylightDate.wMilliseconds), - timeZoneInformation.DaylightDate.wMonth, - timeZoneInformation.DaylightDate.wDay); - } - } - else - { - // - // read the "daylightTransitionEnd" - // - if (timeZoneInformation.StandardDate.wYear == 0) - { - transitionTime = TransitionTime.CreateFloatingDateRule( - new DateTime(1, /* year */ - 1, /* month */ - 1, /* day */ - timeZoneInformation.StandardDate.wHour, - timeZoneInformation.StandardDate.wMinute, - timeZoneInformation.StandardDate.wSecond, - timeZoneInformation.StandardDate.wMilliseconds), - timeZoneInformation.StandardDate.wMonth, - timeZoneInformation.StandardDate.wDay, /* Week 1-5 */ - (DayOfWeek)timeZoneInformation.StandardDate.wDayOfWeek); - } - else - { - transitionTime = TransitionTime.CreateFixedDateRule( - new DateTime(1, /* year */ - 1, /* month */ - 1, /* day */ - timeZoneInformation.StandardDate.wHour, - timeZoneInformation.StandardDate.wMinute, - timeZoneInformation.StandardDate.wSecond, - timeZoneInformation.StandardDate.wMilliseconds), - timeZoneInformation.StandardDate.wMonth, - timeZoneInformation.StandardDate.wDay); - } - } - - return true; - } - - // - // TryCreateAdjustmentRules - - // - // Helper function that takes - // 1. a string representing a registry key name - // 2. a RegistryTimeZoneInformation struct containing the default rule - // 3. an AdjustmentRule[] out-parameter - // - // returns - // TimeZoneInfoResult.InvalidTimeZoneException, - // TimeZoneInfoResult.TimeZoneNotFoundException, - // TimeZoneInfoResult.Success - // - // Optional, Dynamic Time Zone Registry Data - // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - // - // HKLM - // Software - // Microsoft - // Windows NT - // CurrentVersion - // Time Zones - // - // Dynamic DST - // * "FirstEntry" REG_DWORD "1980" - // First year in the table. If the current year is less than this value, - // this entry will be used for DST boundaries - // * "LastEntry" REG_DWORD "2038" - // Last year in the table. If the current year is greater than this value, - // this entry will be used for DST boundaries" - // * "" REG_BINARY REG_TZI_FORMAT - // See REGISTRY_TIME_ZONE_INFORMATION - // * "" REG_BINARY REG_TZI_FORMAT - // See REGISTRY_TIME_ZONE_INFORMATION - // * "" REG_BINARY REG_TZI_FORMAT - // See REGISTRY_TIME_ZONE_INFORMATION - // - // This method expects that its caller has already Asserted RegistryPermission.Read - // - private static bool TryCreateAdjustmentRules(string id, REGISTRY_TIME_ZONE_INFORMATION defaultTimeZoneInformation, out AdjustmentRule[] rules, out Exception e, int defaultBaseUtcOffset) - { - e = null; - - try - { - using (RegistryKey dynamicKey = RegistryKey.GetBaseKey(RegistryKey.HKEY_LOCAL_MACHINE).OpenSubKey( - c_timeZonesRegistryHive + "\\" + id + "\\Dynamic DST", - false - )) - { - if (dynamicKey == null) - { - AdjustmentRule rule = CreateAdjustmentRuleFromTimeZoneInformation( - defaultTimeZoneInformation, DateTime.MinValue.Date, DateTime.MaxValue.Date, defaultBaseUtcOffset); - - if (rule == null) - { - rules = null; - } - else - { - rules = new AdjustmentRule[1]; - rules[0] = rule; - } - - return true; - } - - // - // loop over all of the "\Dynamic DST" hive entries - // - // read FirstEntry {MinValue - (year1, 12, 31)} - // read MiddleEntry {(yearN, 1, 1) - (yearN, 12, 31)} - // read LastEntry {(yearN, 1, 1) - MaxValue } - - // read the FirstEntry and LastEntry key values (ex: "1980", "2038") - Int32 first = (Int32)dynamicKey.GetValue(c_firstEntryValue, -1, RegistryValueOptions.None); - Int32 last = (Int32)dynamicKey.GetValue(c_lastEntryValue, -1, RegistryValueOptions.None); - - if (first == -1 || last == -1 || first > last) - { - rules = null; - return false; - } - - // read the first year entry - REGISTRY_TIME_ZONE_INFORMATION dtzi; - Byte[] regValue = dynamicKey.GetValue(first.ToString(CultureInfo.InvariantCulture), null, RegistryValueOptions.None) as Byte[]; - if (regValue == null || regValue.Length != c_regByteLength) - { - rules = null; - return false; - } - dtzi = new REGISTRY_TIME_ZONE_INFORMATION(regValue); - - if (first == last) - { - // there is just 1 dynamic rule for this time zone. - AdjustmentRule rule = CreateAdjustmentRuleFromTimeZoneInformation(dtzi, DateTime.MinValue.Date, DateTime.MaxValue.Date, defaultBaseUtcOffset); - - if (rule == null) - { - rules = null; - } - else - { - rules = new AdjustmentRule[1]; - rules[0] = rule; - } - - return true; - } - - List rulesList = new List(1); - - // there are more than 1 dynamic rules for this time zone. - AdjustmentRule firstRule = CreateAdjustmentRuleFromTimeZoneInformation( - dtzi, - DateTime.MinValue.Date, // MinValue - new DateTime(first, 12, 31), // December 31, - defaultBaseUtcOffset); - if (firstRule != null) - { - rulesList.Add(firstRule); - } - - // read the middle year entries - for (Int32 i = first + 1; i < last; i++) - { - regValue = dynamicKey.GetValue(i.ToString(CultureInfo.InvariantCulture), null, RegistryValueOptions.None) as Byte[]; - if (regValue == null || regValue.Length != c_regByteLength) - { - rules = null; - return false; - } - dtzi = new REGISTRY_TIME_ZONE_INFORMATION(regValue); - AdjustmentRule middleRule = CreateAdjustmentRuleFromTimeZoneInformation( - dtzi, - new DateTime(i, 1, 1), // January 01, - new DateTime(i, 12, 31), // December 31, - defaultBaseUtcOffset); - if (middleRule != null) - { - rulesList.Add(middleRule); - } - } - // read the last year entry - regValue = dynamicKey.GetValue(last.ToString(CultureInfo.InvariantCulture), null, RegistryValueOptions.None) as Byte[]; - dtzi = new REGISTRY_TIME_ZONE_INFORMATION(regValue); - if (regValue == null || regValue.Length != c_regByteLength) - { - rules = null; - return false; - } - AdjustmentRule lastRule = CreateAdjustmentRuleFromTimeZoneInformation( - dtzi, - new DateTime(last, 1, 1), // January 01, - DateTime.MaxValue.Date, // MaxValue - defaultBaseUtcOffset); - if (lastRule != null) - { - rulesList.Add(lastRule); - } - - // convert the ArrayList to an AdjustmentRule array - rules = rulesList.ToArray(); - if (rules != null && rules.Length == 0) - { - rules = null; - } - } // end of: using (RegistryKey dynamicKey... - } - catch (InvalidCastException ex) - { - // one of the RegistryKey.GetValue calls could not be cast to an expected value type - rules = null; - e = ex; - return false; - } - catch (ArgumentOutOfRangeException ex) - { - rules = null; - e = ex; - return false; - } - catch (ArgumentException ex) - { - rules = null; - e = ex; - return false; - } - return true; - } - - // - // TryCompareStandardDate - - // - // Helper function that compares the StandardBias and StandardDate portion a - // TimeZoneInformation struct to a time zone registry entry - // - private static Boolean TryCompareStandardDate(TIME_ZONE_INFORMATION timeZone, REGISTRY_TIME_ZONE_INFORMATION registryTimeZoneInfo) - { - return timeZone.Bias == registryTimeZoneInfo.Bias - && timeZone.StandardBias == registryTimeZoneInfo.StandardBias - && timeZone.StandardDate.wYear == registryTimeZoneInfo.StandardDate.wYear - && timeZone.StandardDate.wMonth == registryTimeZoneInfo.StandardDate.wMonth - && timeZone.StandardDate.wDayOfWeek == registryTimeZoneInfo.StandardDate.wDayOfWeek - && timeZone.StandardDate.wDay == registryTimeZoneInfo.StandardDate.wDay - && timeZone.StandardDate.wHour == registryTimeZoneInfo.StandardDate.wHour - && timeZone.StandardDate.wMinute == registryTimeZoneInfo.StandardDate.wMinute - && timeZone.StandardDate.wSecond == registryTimeZoneInfo.StandardDate.wSecond - && timeZone.StandardDate.wMilliseconds == registryTimeZoneInfo.StandardDate.wMilliseconds; - } - - // - // TryCompareTimeZoneInformationToRegistry - - // - // Helper function that compares a TimeZoneInformation struct to a time zone registry entry - // - static unsafe private Boolean TryCompareTimeZoneInformationToRegistry(TIME_ZONE_INFORMATION timeZone, string id, out Boolean dstDisabled) - { - dstDisabled = false; - using (RegistryKey key = RegistryKey.GetBaseKey(RegistryKey.HKEY_LOCAL_MACHINE).OpenSubKey( - c_timeZonesRegistryHive + "\\" + id, - false - )) - { - if (key == null) - { - return false; - } - - REGISTRY_TIME_ZONE_INFORMATION registryTimeZoneInfo; - Byte[] regValue = (Byte[])key.GetValue(c_timeZoneInfoValue, null, RegistryValueOptions.None) as Byte[]; - if (regValue == null || regValue.Length != c_regByteLength) return false; - registryTimeZoneInfo = new REGISTRY_TIME_ZONE_INFORMATION(regValue); - - // - // first compare the bias and standard date information between the data from the Win32 API - // and the data from the registry... - // - Boolean result = TryCompareStandardDate(timeZone, registryTimeZoneInfo); - - if (!result) - { - return false; - } - - result = dstDisabled || CheckDaylightSavingTimeNotSupported(timeZone) - // - // since Daylight Saving Time is not "disabled", do a straight comparision between - // the Win32 API data and the registry data ... - // - || (timeZone.DaylightBias == registryTimeZoneInfo.DaylightBias - && timeZone.DaylightDate.wYear == registryTimeZoneInfo.DaylightDate.wYear - && timeZone.DaylightDate.wMonth == registryTimeZoneInfo.DaylightDate.wMonth - && timeZone.DaylightDate.wDayOfWeek == registryTimeZoneInfo.DaylightDate.wDayOfWeek - && timeZone.DaylightDate.wDay == registryTimeZoneInfo.DaylightDate.wDay - && timeZone.DaylightDate.wHour == registryTimeZoneInfo.DaylightDate.wHour - && timeZone.DaylightDate.wMinute == registryTimeZoneInfo.DaylightDate.wMinute - && timeZone.DaylightDate.wSecond == registryTimeZoneInfo.DaylightDate.wSecond - && timeZone.DaylightDate.wMilliseconds == registryTimeZoneInfo.DaylightDate.wMilliseconds); - - // Finally compare the "StandardName" string value... - // - // we do not compare "DaylightName" as this TimeZoneInformation field may contain - // either "StandardName" or "DaylightName" depending on the time of year and current machine settings - // - if (result) - { - String registryStandardName = key.GetValue(c_standardValue, String.Empty, RegistryValueOptions.None) as String; - result = String.Compare(registryStandardName, new String(timeZone.StandardName), StringComparison.Ordinal) == 0; - } - return result; - } - } - - // - // TryGetLocalizedNameByMuiNativeResource - - // - // Helper function for retrieving a localized string resource via MUI. - // The function expects a string in the form: "@resource.dll, -123" - // - // "resource.dll" is a language-neutral portable executable (LNPE) file in - // the %windir%\system32 directory. The OS is queried to find the best-fit - // localized resource file for this LNPE (ex: %windir%\system32\en-us\resource.dll.mui). - // If a localized resource file exists, we LoadString resource ID "123" and - // return it to our caller. - // - // - // - // - // - private static string TryGetLocalizedNameByMuiNativeResource(string resource) - { - if (String.IsNullOrEmpty(resource)) - { - return String.Empty; - } - - // parse "@tzres.dll, -100" - // - // filePath = "C:\Windows\System32\tzres.dll" - // resourceId = -100 - // - string[] resources = resource.Split(','); - if (resources.Length != 2) - { - return String.Empty; - } - - string filePath; - int resourceId; - - // get the path to Windows\System32 - StringBuilder sb = new StringBuilder(Interop.mincore.MAX_PATH); - int r = Interop.mincore.GetSystemDirectory(sb, Interop.mincore.MAX_PATH); - string system32 = sb.ToString(); - - // trim the string "@tzres.dll" => "tzres.dll" - string tzresDll = resources[0].TrimStart('@'); - - try - { - filePath = system32 + "\\" + tzresDll; - } - catch (ArgumentException) - { - // there were probably illegal characters in the path - return String.Empty; - } - - if (!Int32.TryParse(resources[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out resourceId)) - { - return String.Empty; - } - resourceId = -resourceId; - - - try - { - StringBuilder fileMuiPath = StringBuilderCache.Acquire(Interop.mincore.MAX_PATH); - fileMuiPath.Length = Interop.mincore.MAX_PATH; - int fileMuiPathLength = Interop.mincore.MAX_PATH; - int languageLength = 0; - Int64 enumerator = 0; - - Boolean succeeded = Interop.mincore.GetFileMUIPath( - Interop.mincore.MUI_PREFERRED_UI_LANGUAGES, - filePath, null /* language */, ref languageLength, - fileMuiPath, ref fileMuiPathLength, ref enumerator); - if (!succeeded) - { - StringBuilderCache.Release(fileMuiPath); - return String.Empty; - } - return TryGetLocalizedNameByNativeResource(StringBuilderCache.GetStringAndRelease(fileMuiPath), resourceId); - } - catch - { - return String.Empty; - } - } - - // - // TryGetLocalizedNameByNativeResource - - // - // Helper function for retrieving a localized string resource via a native resource DLL. - // The function expects a string in the form: "C:\Windows\System32\en-us\resource.dll" - // - // "resource.dll" is a language-specific resource DLL. - // If the localized resource DLL exists, LoadString(resource) is returned. - // - static unsafe private string TryGetLocalizedNameByNativeResource(string filePath, int resource) - { - using (SafeLibraryHandle handle = - Interop.Kernel32.LoadLibraryEx(filePath, IntPtr.Zero, Interop.Kernel32.LOAD_LIBRARY_AS_DATAFILE)) - { - if (!handle.IsInvalid) - { - const int LoadStringMaxLength = 500; - - StringBuilder localizedResource = new StringBuilder(LoadStringMaxLength); - - int result = Interop.User32.LoadString(handle, resource, - localizedResource, LoadStringMaxLength); - - if (result != 0) - { - return localizedResource.ToString(); - } - } - } - - return String.Empty; - } - - // - // TryGetLocalizedNamesByRegistryKey - - // - // Helper function for retrieving the DisplayName, StandardName, and DaylightName from the registry - // - // The function first checks the MUI_ key-values, and if they exist, it loads the strings from the MUI - // resource dll(s). When the keys do not exist, the function falls back to reading from the standard - // key-values - // - // This method expects that its caller has already Asserted RegistryPermission.Read - // - private static Boolean TryGetLocalizedNamesByRegistryKey(RegistryKey key, out String displayName, out String standardName, out String daylightName) - { - displayName = String.Empty; - standardName = String.Empty; - daylightName = String.Empty; - - // read the MUI_ registry keys - String displayNameMuiResource = key.GetValue(c_muiDisplayValue, String.Empty, RegistryValueOptions.None) as String; - String standardNameMuiResource = key.GetValue(c_muiStandardValue, String.Empty, RegistryValueOptions.None) as String; - String daylightNameMuiResource = key.GetValue(c_muiDaylightValue, String.Empty, RegistryValueOptions.None) as String; - - // try to load the strings from the native resource DLL(s) - if (!String.IsNullOrEmpty(displayNameMuiResource)) - { - displayName = TryGetLocalizedNameByMuiNativeResource(displayNameMuiResource); - } - - if (!String.IsNullOrEmpty(standardNameMuiResource)) - { - standardName = TryGetLocalizedNameByMuiNativeResource(standardNameMuiResource); - } - - if (!String.IsNullOrEmpty(daylightNameMuiResource)) - { - daylightName = TryGetLocalizedNameByMuiNativeResource(daylightNameMuiResource); - } - - // fallback to using the standard registry keys - if (String.IsNullOrEmpty(displayName)) - { - displayName = key.GetValue(c_displayValue, String.Empty, RegistryValueOptions.None) as String; - } - if (String.IsNullOrEmpty(standardName)) - { - standardName = key.GetValue(c_standardValue, String.Empty, RegistryValueOptions.None) as String; - } - if (String.IsNullOrEmpty(daylightName)) - { - daylightName = key.GetValue(c_daylightValue, String.Empty, RegistryValueOptions.None) as String; - } - - return true; - } - - // - // TryGetTimeZoneByRegistryKey - - // - // Helper function that takes a string representing a registry key name - // and returns a TimeZoneInfo instance. - // - // returns - // TimeZoneInfoResult.InvalidTimeZoneException, - // TimeZoneInfoResult.TimeZoneNotFoundException, - // TimeZoneInfoResult.SecurityException, - // TimeZoneInfoResult.Success - // - // - // Standard Time Zone Registry Data - // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= - // HKLM - // Software - // Microsoft - // Windows NT - // CurrentVersion - // Time Zones - // - // * STD, REG_SZ "Standard Time Name" - // (For OS installed zones, this will always be English) - // * MUI_STD, REG_SZ "@tzres.dll,-1234" - // Indirect string to localized resource for Standard Time, - // add "%windir%\system32\" after "@" - // * DLT, REG_SZ "Daylight Time Name" - // (For OS installed zones, this will always be English) - // * MUI_DLT, REG_SZ "@tzres.dll,-1234" - // Indirect string to localized resource for Daylight Time, - // add "%windir%\system32\" after "@" - // * Display, REG_SZ "Display Name like (GMT-8:00) Pacific Time..." - // * MUI_Display, REG_SZ "@tzres.dll,-1234" - // Indirect string to localized resource for the Display, - // add "%windir%\system32\" after "@" - // * TZI, REG_BINARY REG_TZI_FORMAT - // See REGISTRY_TIME_ZONE_INFORMATION - // - private static TimeZoneInfoResult TryGetTimeZoneByRegistryKey(string id, out TimeZoneInfo value, out Exception e) - { - e = null; - - using (RegistryKey key = RegistryKey.GetBaseKey(RegistryKey.HKEY_LOCAL_MACHINE).OpenSubKey( - c_timeZonesRegistryHive + "\\" + id, - false - )) - { - if (key == null) - { - value = null; - return TimeZoneInfoResult.TimeZoneNotFoundException; - } - - REGISTRY_TIME_ZONE_INFORMATION defaultTimeZoneInformation; - Byte[] regValue = key.GetValue(c_timeZoneInfoValue, null, RegistryValueOptions.None) as Byte[]; - if (regValue == null || regValue.Length != c_regByteLength) - { - // the registry value could not be cast to a byte array - value = null; - return TimeZoneInfoResult.InvalidTimeZoneException; - } - defaultTimeZoneInformation = new REGISTRY_TIME_ZONE_INFORMATION(regValue); - - AdjustmentRule[] adjustmentRules; - if (!TryCreateAdjustmentRules(id, defaultTimeZoneInformation, out adjustmentRules, out e, defaultTimeZoneInformation.Bias)) - { - value = null; - return TimeZoneInfoResult.InvalidTimeZoneException; - } - - string displayName; - string standardName; - string daylightName; - - if (!TryGetLocalizedNamesByRegistryKey(key, out displayName, out standardName, out daylightName)) - { - value = null; - return TimeZoneInfoResult.InvalidTimeZoneException; - } - - try - { - value = new TimeZoneInfo( - id, - new TimeSpan(0, -(defaultTimeZoneInformation.Bias), 0), - displayName, - standardName, - daylightName, - adjustmentRules, - false); - - return TimeZoneInfoResult.Success; - } - catch (ArgumentException ex) - { - // TimeZoneInfo constructor can throw ArgumentException and InvalidTimeZoneException - value = null; - e = ex; - return TimeZoneInfoResult.InvalidTimeZoneException; - } - catch (InvalidTimeZoneException ex) - { - // TimeZoneInfo constructor can throw ArgumentException and InvalidTimeZoneException - value = null; - e = ex; - return TimeZoneInfoResult.InvalidTimeZoneException; - } - } - } - - // - // TryGetTimeZone - - // - // Helper function for retrieving a TimeZoneInfo object by . - // - // This function may return null. - // - // assumes cachedData lock is taken - // - private static TimeZoneInfoResult TryGetTimeZone(string id, Boolean dstDisabled, out TimeZoneInfo value, out Exception e, CachedData cachedData) - { - TimeZoneInfoResult result = TimeZoneInfoResult.Success; - e = null; - TimeZoneInfo match = null; - - // check the cache - if (cachedData._systemTimeZones != null) - { - if (cachedData._systemTimeZones.TryGetValue(id, out match)) - { - if (dstDisabled && match._supportsDaylightSavingTime) - { - // we found a cache hit but we want a time zone without DST and this one has DST data - value = CreateCustomTimeZone(match._id, match._baseUtcOffset, match._displayName, match._standardDisplayName); - } - else - { - value = new TimeZoneInfo(match._id, match._baseUtcOffset, match._displayName, match._standardDisplayName, - match._daylightDisplayName, match._adjustmentRules, false); - } - return result; - } - } - - // fall back to reading from the local machine - // when the cache is not fully populated - if (!cachedData._allSystemTimeZonesRead) - { - result = TryGetTimeZoneByRegistryKey(id, out match, out e); - if (result == TimeZoneInfoResult.Success) - { - if (cachedData._systemTimeZones == null) - cachedData._systemTimeZones = new LowLevelDictionaryWithIEnumerable(); - - cachedData._systemTimeZones.Add(id, match); - - if (dstDisabled && match._supportsDaylightSavingTime) - { - // we found a cache hit but we want a time zone without DST and this one has DST data - value = CreateCustomTimeZone(match._id, match._baseUtcOffset, match._displayName, match._standardDisplayName); - } - else - { - value = new TimeZoneInfo(match._id, match._baseUtcOffset, match._displayName, match._standardDisplayName, - match._daylightDisplayName, match._adjustmentRules, false); - } - } - else - { - value = null; - } - } - else - { - result = TimeZoneInfoResult.TimeZoneNotFoundException; - value = null; - } - - return result; - } - } // TimezoneInfo -} // namespace System diff --git a/external/corert/src/System.Private.CoreLib/src/System/TimeZoneInfo.WinRT.cs b/external/corert/src/System.Private.CoreLib/src/System/TimeZoneInfo.WinRT.cs index faa851c709..4701b3e13a 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/TimeZoneInfo.WinRT.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/TimeZoneInfo.WinRT.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. @@ -32,6 +32,608 @@ namespace System { sealed public partial class TimeZoneInfo { +#pragma warning disable 0420 + private sealed partial class CachedData + { + private static TimeZoneInfo GetCurrentOneYearLocal() + { + // load the data from the OS + TimeZoneInfo match; + + TimeZoneInformation timeZoneInformation; + if (!GetTimeZoneInfo(out timeZoneInformation)) + match = CreateCustomTimeZone(LocalId, TimeSpan.Zero, LocalId, LocalId); + else + match = GetLocalTimeZoneFromWin32Data(timeZoneInformation, false); + return match; + } + + private volatile OffsetAndRule _oneYearLocalFromUtc; + + public OffsetAndRule GetOneYearLocalFromUtc(int year) + { + OffsetAndRule oneYearLocFromUtc = _oneYearLocalFromUtc; + if (oneYearLocFromUtc == null || oneYearLocFromUtc.Year != year) + { + TimeZoneInfo currentYear = GetCurrentOneYearLocal(); + AdjustmentRule rule = currentYear._adjustmentRules == null ? null : currentYear._adjustmentRules[0]; + oneYearLocFromUtc = new OffsetAndRule(year, currentYear.BaseUtcOffset, rule); + _oneYearLocalFromUtc = oneYearLocFromUtc; + } + return oneYearLocFromUtc; + } + } +#pragma warning restore 0420 + + private sealed class OffsetAndRule + { + public readonly int Year; + public readonly TimeSpan Offset; + public readonly AdjustmentRule Rule; + + public OffsetAndRule(int year, TimeSpan offset, AdjustmentRule rule) + { + Year = year; + Offset = offset; + Rule = rule; + } + } + + private static bool GetTimeZoneInfo(out TimeZoneInformation timeZoneInfo) + { + TIME_DYNAMIC_ZONE_INFORMATION dtzi; + long result = Interop.mincore.GetDynamicTimeZoneInformation(out dtzi); + if (result == Interop.mincore.TIME_ZONE_ID_INVALID) + { + timeZoneInfo = null; + return false; + } + + timeZoneInfo = new TimeZoneInformation(dtzi); + + return true; + } + + private TimeZoneInfo(TimeZoneInformation zone, Boolean dstDisabled) + { + if (String.IsNullOrEmpty(zone.StandardName)) + { + _id = LocalId; // the ID must contain at least 1 character - initialize m_id to "Local" + } + else + { + _id = zone.StandardName; + } + _baseUtcOffset = new TimeSpan(0, -(zone.Dtzi.Bias), 0); + + if (!dstDisabled) + { + // only create the adjustment rule if DST is enabled + AdjustmentRule rule = CreateAdjustmentRuleFromTimeZoneInformation(zone, DateTime.MinValue.Date, DateTime.MaxValue.Date, zone.Dtzi.Bias); + if (rule != null) + { + _adjustmentRules = new AdjustmentRule[1]; + _adjustmentRules[0] = rule; + } + } + + ValidateTimeZoneInfo(_id, _baseUtcOffset, _adjustmentRules, out _supportsDaylightSavingTime); + _displayName = zone.StandardName; + _standardDisplayName = zone.StandardName; + _daylightDisplayName = zone.DaylightName; + } + + private sealed class TimeZoneInformation + { + public string StandardName; + public string DaylightName; + public string TimeZoneKeyName; + + // we need to keep this one for subsequent interops. + public TIME_DYNAMIC_ZONE_INFORMATION Dtzi; + + public unsafe TimeZoneInformation(TIME_DYNAMIC_ZONE_INFORMATION dtzi) + { + StandardName = new String(dtzi.StandardName); + DaylightName = new String(dtzi.DaylightName); + TimeZoneKeyName = new String(dtzi.TimeZoneKeyName); + Dtzi = dtzi; + } + } + + // + // TryGetTimeZone - + // + // Helper function for retrieving a TimeZoneInfo object by . + // + // This function may return null. + // + // assumes cachedData lock is taken + // + private static TimeZoneInfoResult TryGetTimeZone(ref TimeZoneInformation timeZoneInformation, Boolean dstDisabled, out TimeZoneInfo value, out Exception e, CachedData cachedData) + { + TimeZoneInfoResult result = TimeZoneInfoResult.Success; + e = null; + TimeZoneInfo match = null; + + // check the cache + if (cachedData._systemTimeZones != null) + { + if (cachedData._systemTimeZones.TryGetValue(timeZoneInformation.TimeZoneKeyName, out match)) + { + if (dstDisabled && match._supportsDaylightSavingTime) + { + // we found a cache hit but we want a time zone without DST and this one has DST data + value = CreateCustomTimeZone(match._id, match._baseUtcOffset, match._displayName, match._standardDisplayName); + } + else + { + value = new TimeZoneInfo(match._id, match._baseUtcOffset, match._displayName, match._standardDisplayName, + match._daylightDisplayName, match._adjustmentRules, false); + } + return result; + } + } + + // fall back to reading from the local machine + // when the cache is not fully populated + result = TryGetFullTimeZoneInformation(timeZoneInformation, out match, out e, timeZoneInformation.Dtzi.Bias); + + if (result == TimeZoneInfoResult.Success) + { + if (cachedData._systemTimeZones == null) + cachedData._systemTimeZones = new Dictionary(); + + cachedData._systemTimeZones.Add(timeZoneInformation.TimeZoneKeyName, match); + + if (dstDisabled && match._supportsDaylightSavingTime) + { + // we found a cache hit but we want a time zone without DST and this one has DST data + value = CreateCustomTimeZone(match._id, match._baseUtcOffset, match._displayName, match._standardDisplayName); + } + else + { + value = new TimeZoneInfo(match._id, match._baseUtcOffset, match._displayName, match._standardDisplayName, + match._daylightDisplayName, match._adjustmentRules, false); + } + } + else + { + value = null; + } + + return result; + } + + private static TimeZoneInfoResult TryGetFullTimeZoneInformation(TimeZoneInformation timeZoneInformation, out TimeZoneInfo value, out Exception e, int defaultBaseUtcOffset) + { + uint firstYear, lastYear; + AdjustmentRule rule; + AdjustmentRule[] zoneRules = null; + + value = null; + e = null; + + // + // First get the adjustment rules + // + + if (Interop.mincore.GetDynamicTimeZoneInformationEffectiveYears(ref timeZoneInformation.Dtzi, out firstYear, out lastYear) != 0) + { + rule = CreateAdjustmentRuleFromTimeZoneInformation(timeZoneInformation, DateTime.MinValue.Date, DateTime.MaxValue.Date, defaultBaseUtcOffset); + if (rule != null) + { + zoneRules = new AdjustmentRule[1] { rule }; + } + } + else + { + if (firstYear == lastYear) + { + // there is just 1 dynamic rule for this time zone. + rule = CreateAdjustmentRuleFromTimeZoneInformation(timeZoneInformation, DateTime.MinValue.Date, DateTime.MaxValue.Date, defaultBaseUtcOffset); + if (rule != null) + { + zoneRules = new AdjustmentRule[1] { rule }; + } + } + else + { + TIME_ZONE_INFORMATION tzdi = new TIME_ZONE_INFORMATION(); + LowLevelList rules = new LowLevelList(); + + // + // First rule + // + + if (!Interop.mincore.GetTimeZoneInformationForYear((ushort)firstYear, ref timeZoneInformation.Dtzi, out tzdi)) + { + return TimeZoneInfoResult.InvalidTimeZoneException; + } + rule = CreateAdjustmentRuleFromTimeZoneInformation(ref tzdi, DateTime.MinValue.Date, new DateTime((int)firstYear, 12, 31), defaultBaseUtcOffset); + if (rule != null) + { + rules.Add(rule); + } + + for (uint i = firstYear + 1; i < lastYear; i++) + { + if (!Interop.mincore.GetTimeZoneInformationForYear((ushort)i, ref timeZoneInformation.Dtzi, out tzdi)) + { + return TimeZoneInfoResult.InvalidTimeZoneException; + } + rule = CreateAdjustmentRuleFromTimeZoneInformation(ref tzdi, new DateTime((int)i, 1, 1), new DateTime((int)i, 12, 31), defaultBaseUtcOffset); + if (rule != null) + { + rules.Add(rule); + } + } + + // + // Last rule + // + + if (!Interop.mincore.GetTimeZoneInformationForYear((ushort)lastYear, ref timeZoneInformation.Dtzi, out tzdi)) + { + return TimeZoneInfoResult.InvalidTimeZoneException; + } + rule = CreateAdjustmentRuleFromTimeZoneInformation(ref tzdi, new DateTime((int)lastYear, 1, 1), DateTime.MaxValue.Date, defaultBaseUtcOffset); + if (rule != null) + { + rules.Add(rule); + } + + if (rules.Count > 0) + { + zoneRules = rules.ToArray(); + } + } + } + + // + // Create TimeZoneInfo object + // + try + { + // Note that all names we have are localized names as Windows always return the localized names + value = new TimeZoneInfo( + timeZoneInformation.TimeZoneKeyName, + new TimeSpan(0, -(timeZoneInformation.Dtzi.Bias), 0), + timeZoneInformation.StandardName, // we use the display name as the standared names + timeZoneInformation.StandardName, + timeZoneInformation.DaylightName, + zoneRules, + false); + + return System.TimeZoneInfo.TimeZoneInfoResult.Success; + } + catch (ArgumentException ex) + { + // TimeZoneInfo constructor can throw ArgumentException and InvalidTimeZoneException + value = null; + e = ex; + return System.TimeZoneInfo.TimeZoneInfoResult.InvalidTimeZoneException; + } + catch (InvalidTimeZoneException ex) + { + // TimeZoneInfo constructor can throw ArgumentException and InvalidTimeZoneException + value = null; + e = ex; + return System.TimeZoneInfo.TimeZoneInfoResult.InvalidTimeZoneException; + } + } + + // + // CreateAdjustmentRuleFromTimeZoneInformation- + // + // Converts TimeZoneInformation to an AdjustmentRule + // + private static AdjustmentRule CreateAdjustmentRuleFromTimeZoneInformation(TimeZoneInformation timeZoneInformation, DateTime startDate, DateTime endDate, int defaultBaseUtcOffset) + { + bool supportsDst = (timeZoneInformation.Dtzi.StandardDate.wMonth != 0); + + if (!supportsDst) + { + if (timeZoneInformation.Dtzi.Bias == defaultBaseUtcOffset) + { + // this rule will not contain any information to be used to adjust dates. just ignore it + return null; + } + + return AdjustmentRule.CreateAdjustmentRule( + startDate, + endDate, + TimeSpan.Zero, // no daylight saving transition + TransitionTime.CreateFixedDateRule(DateTime.MinValue, 1, 1), + TransitionTime.CreateFixedDateRule(DateTime.MinValue.AddMilliseconds(1), 1, 1), + new TimeSpan(0, defaultBaseUtcOffset - timeZoneInformation.Dtzi.Bias, 0), // Bias delta is all what we need from this rule + noDaylightTransitions: false); + } + + // + // Create an AdjustmentRule with TransitionTime objects + // + TransitionTime daylightTransitionStart; + if (!TransitionTimeFromTimeZoneInformation(timeZoneInformation, out daylightTransitionStart, true /* start date */)) + { + return null; + } + + TransitionTime daylightTransitionEnd; + if (!TransitionTimeFromTimeZoneInformation(timeZoneInformation, out daylightTransitionEnd, false /* end date */)) + { + return null; + } + + if (daylightTransitionStart.Equals(daylightTransitionEnd)) + { + // this happens when the time zone does support DST but the OS has DST disabled + return null; + } + + return AdjustmentRule.CreateAdjustmentRule( + startDate, + endDate, + new TimeSpan(0, -timeZoneInformation.Dtzi.DaylightBias, 0), + (TransitionTime)daylightTransitionStart, + (TransitionTime)daylightTransitionEnd, + new TimeSpan(0, defaultBaseUtcOffset - timeZoneInformation.Dtzi.Bias, 0), + noDaylightTransitions: false); + } + + internal static AdjustmentRule CreateAdjustmentRuleFromTimeZoneInformation(ref TIME_ZONE_INFORMATION timeZoneInformation, DateTime startDate, DateTime endDate, int defaultBaseUtcOffset) + { + bool supportsDst = (timeZoneInformation.StandardDate.wMonth != 0); + + if (!supportsDst) + { + if (timeZoneInformation.Bias == defaultBaseUtcOffset) + { + // this rule will not contain any information to be used to adjust dates. just ignore it + return null; + } + + return AdjustmentRule.CreateAdjustmentRule( + startDate, + endDate, + TimeSpan.Zero, // no daylight saving transition + TransitionTime.CreateFixedDateRule(DateTime.MinValue, 1, 1), + TransitionTime.CreateFixedDateRule(DateTime.MinValue.AddMilliseconds(1), 1, 1), + new TimeSpan(0, defaultBaseUtcOffset - timeZoneInformation.Bias, 0), // Bias delta is all what we need from this rule + noDaylightTransitions: false); + } + + // + // Create an AdjustmentRule with TransitionTime objects + // + TransitionTime daylightTransitionStart; + if (!TransitionTimeFromTimeZoneInformation(timeZoneInformation, out daylightTransitionStart, true /* start date */)) + { + return null; + } + + TransitionTime daylightTransitionEnd; + if (!TransitionTimeFromTimeZoneInformation(timeZoneInformation, out daylightTransitionEnd, false /* end date */)) + { + return null; + } + + if (daylightTransitionStart.Equals(daylightTransitionEnd)) + { + // this happens when the time zone does support DST but the OS has DST disabled + return null; + } + + return AdjustmentRule.CreateAdjustmentRule( + startDate, + endDate, + new TimeSpan(0, -timeZoneInformation.DaylightBias, 0), + (TransitionTime)daylightTransitionStart, + (TransitionTime)daylightTransitionEnd, + new TimeSpan(0, defaultBaseUtcOffset - timeZoneInformation.Bias, 0), + noDaylightTransitions: false); + } + + private static bool TransitionTimeFromTimeZoneInformation(TimeZoneInformation timeZoneInformation, out TransitionTime transitionTime, bool readStartDate) + { + bool supportsDst = (timeZoneInformation.Dtzi.StandardDate.wMonth != 0); + + if (!supportsDst) + { + transitionTime = default(TransitionTime); + return false; + } + + if (readStartDate) + { + // + // read the "daylightTransitionStart" + // + if (timeZoneInformation.Dtzi.DaylightDate.wYear == 0) + { + transitionTime = TransitionTime.CreateFloatingDateRule( + new DateTime(1, /* year */ + 1, /* month */ + 1, /* day */ + timeZoneInformation.Dtzi.DaylightDate.wHour, + timeZoneInformation.Dtzi.DaylightDate.wMinute, + timeZoneInformation.Dtzi.DaylightDate.wSecond, + timeZoneInformation.Dtzi.DaylightDate.wMilliseconds), + timeZoneInformation.Dtzi.DaylightDate.wMonth, + timeZoneInformation.Dtzi.DaylightDate.wDay, /* Week 1-5 */ + (DayOfWeek)timeZoneInformation.Dtzi.DaylightDate.wDayOfWeek); + } + else + { + transitionTime = TransitionTime.CreateFixedDateRule( + new DateTime(1, /* year */ + 1, /* month */ + 1, /* day */ + timeZoneInformation.Dtzi.DaylightDate.wHour, + timeZoneInformation.Dtzi.DaylightDate.wMinute, + timeZoneInformation.Dtzi.DaylightDate.wSecond, + timeZoneInformation.Dtzi.DaylightDate.wMilliseconds), + timeZoneInformation.Dtzi.DaylightDate.wMonth, + timeZoneInformation.Dtzi.DaylightDate.wDay); + } + } + else + { + // + // read the "daylightTransitionEnd" + // + if (timeZoneInformation.Dtzi.StandardDate.wYear == 0) + { + transitionTime = TransitionTime.CreateFloatingDateRule( + new DateTime(1, /* year */ + 1, /* month */ + 1, /* day */ + timeZoneInformation.Dtzi.StandardDate.wHour, + timeZoneInformation.Dtzi.StandardDate.wMinute, + timeZoneInformation.Dtzi.StandardDate.wSecond, + timeZoneInformation.Dtzi.StandardDate.wMilliseconds), + timeZoneInformation.Dtzi.StandardDate.wMonth, + timeZoneInformation.Dtzi.StandardDate.wDay, /* Week 1-5 */ + (DayOfWeek)timeZoneInformation.Dtzi.StandardDate.wDayOfWeek); + } + else + { + transitionTime = TransitionTime.CreateFixedDateRule( + new DateTime(1, /* year */ + 1, /* month */ + 1, /* day */ + timeZoneInformation.Dtzi.StandardDate.wHour, + timeZoneInformation.Dtzi.StandardDate.wMinute, + timeZoneInformation.Dtzi.StandardDate.wSecond, + timeZoneInformation.Dtzi.StandardDate.wMilliseconds), + timeZoneInformation.Dtzi.StandardDate.wMonth, + timeZoneInformation.Dtzi.StandardDate.wDay); + } + } + + return true; + } + + // + // TransitionTimeFromTimeZoneInformation - + // + // Converts a TimeZoneInformation (REG_TZI_FORMAT struct) to a TransitionTime + // + // * when the argument 'readStart' is true the corresponding daylightTransitionTimeStart field is read + // * when the argument 'readStart' is false the corresponding dayightTransitionTimeEnd field is read + // + private static bool TransitionTimeFromTimeZoneInformation(TIME_ZONE_INFORMATION timeZoneInformation, out TransitionTime transitionTime, bool readStartDate) + { + // + // SYSTEMTIME - + // + // If the time zone does not support daylight saving time or if the caller needs + // to disable daylight saving time, the wMonth member in the SYSTEMTIME structure + // must be zero. If this date is specified, the DaylightDate value in the + // TIME_ZONE_INFORMATION structure must also be specified. Otherwise, the system + // assumes the time zone data is invalid and no changes will be applied. + // + bool supportsDst = (timeZoneInformation.StandardDate.wMonth != 0); + + if (!supportsDst) + { + transitionTime = default(TransitionTime); + return false; + } + + // + // SYSTEMTIME - + // + // * FixedDateRule - + // If the Year member is not zero, the transition date is absolute; it will only occur one time + // + // * FloatingDateRule - + // To select the correct day in the month, set the Year member to zero, the Hour and Minute + // members to the transition time, the DayOfWeek member to the appropriate weekday, and the + // Day member to indicate the occurence of the day of the week within the month (first through fifth). + // + // Using this notation, specify the 2:00a.m. on the first Sunday in April as follows: + // Hour = 2, + // Month = 4, + // DayOfWeek = 0, + // Day = 1. + // + // Specify 2:00a.m. on the last Thursday in October as follows: + // Hour = 2, + // Month = 10, + // DayOfWeek = 4, + // Day = 5. + // + if (readStartDate) + { + // + // read the "daylightTransitionStart" + // + if (timeZoneInformation.DaylightDate.wYear == 0) + { + transitionTime = TransitionTime.CreateFloatingDateRule( + new DateTime(1, /* year */ + 1, /* month */ + 1, /* day */ + timeZoneInformation.DaylightDate.wHour, + timeZoneInformation.DaylightDate.wMinute, + timeZoneInformation.DaylightDate.wSecond, + timeZoneInformation.DaylightDate.wMilliseconds), + timeZoneInformation.DaylightDate.wMonth, + timeZoneInformation.DaylightDate.wDay, /* Week 1-5 */ + (DayOfWeek)timeZoneInformation.DaylightDate.wDayOfWeek); + } + else + { + transitionTime = TransitionTime.CreateFixedDateRule( + new DateTime(1, /* year */ + 1, /* month */ + 1, /* day */ + timeZoneInformation.DaylightDate.wHour, + timeZoneInformation.DaylightDate.wMinute, + timeZoneInformation.DaylightDate.wSecond, + timeZoneInformation.DaylightDate.wMilliseconds), + timeZoneInformation.DaylightDate.wMonth, + timeZoneInformation.DaylightDate.wDay); + } + } + else + { + // + // read the "daylightTransitionEnd" + // + if (timeZoneInformation.StandardDate.wYear == 0) + { + transitionTime = TransitionTime.CreateFloatingDateRule( + new DateTime(1, /* year */ + 1, /* month */ + 1, /* day */ + timeZoneInformation.StandardDate.wHour, + timeZoneInformation.StandardDate.wMinute, + timeZoneInformation.StandardDate.wSecond, + timeZoneInformation.StandardDate.wMilliseconds), + timeZoneInformation.StandardDate.wMonth, + timeZoneInformation.StandardDate.wDay, /* Week 1-5 */ + (DayOfWeek)timeZoneInformation.StandardDate.wDayOfWeek); + } + else + { + transitionTime = TransitionTime.CreateFixedDateRule( + new DateTime(1, /* year */ + 1, /* month */ + 1, /* day */ + timeZoneInformation.StandardDate.wHour, + timeZoneInformation.StandardDate.wMinute, + timeZoneInformation.StandardDate.wSecond, + timeZoneInformation.StandardDate.wMilliseconds), + timeZoneInformation.StandardDate.wMonth, + timeZoneInformation.StandardDate.wDay); + } + } + + return true; + } + // ---- SECTION: public methods --------------* // @@ -65,6 +667,36 @@ namespace System } } + /// + /// Helper function used by 'GetLocalTimeZone()' - this function wraps a bunch of + /// try/catch logic for handling the TimeZoneInfo private constructor that takes + /// a Win32Native.TimeZoneInformation structure. + /// + private static TimeZoneInfo GetLocalTimeZoneFromWin32Data(TimeZoneInformation timeZoneInformation, bool dstDisabled) + { + // first try to create the TimeZoneInfo with the original 'dstDisabled' flag + try + { + return new TimeZoneInfo(timeZoneInformation, dstDisabled); + } + catch (ArgumentException) { } + catch (InvalidTimeZoneException) { } + + // if 'dstDisabled' was false then try passing in 'true' as a last ditch effort + if (!dstDisabled) + { + try + { + return new TimeZoneInfo(timeZoneInformation, dstDisabled: true); + } + catch (ArgumentException) { } + catch (InvalidTimeZoneException) { } + } + + // the data returned from Windows is completely bogus; return a dummy entry + return CreateCustomTimeZone(LocalId, TimeSpan.Zero, LocalId, LocalId); + } + public static TimeZoneInfo FindSystemTimeZoneById(string id) { if (id == null) @@ -73,7 +705,7 @@ namespace System } if (id.Length == 0 || id.Length > 255 || id.Contains("\0")) { - throw new TimeZoneNotFoundException(SR.Format(SR.TimeZoneNotFound_MissingRegistryData, id)); + throw new TimeZoneNotFoundException(SR.Format(SR.TimeZoneNotFound_MissingData, id)); } // @@ -108,7 +740,30 @@ namespace System } } } - throw new TimeZoneNotFoundException(SR.Format(SR.TimeZoneNotFound_MissingRegistryData, id)); + throw new TimeZoneNotFoundException(SR.Format(SR.TimeZoneNotFound_MissingData, id)); + } + + // DateTime.Now fast path that avoids allocating an historically accurate TimeZoneInfo.Local and just creates a 1-year (current year) accurate time zone + internal static TimeSpan GetDateTimeNowUtcOffsetFromUtc(DateTime time, out bool isAmbiguousLocalDst) + { + bool isDaylightSavings = false; + isAmbiguousLocalDst = false; + TimeSpan baseOffset; + int timeYear = time.Year; + + OffsetAndRule match = s_cachedData.GetOneYearLocalFromUtc(timeYear); + baseOffset = match.Offset; + + if (match.Rule != null) + { + baseOffset = baseOffset + match.Rule.BaseUtcOffsetDelta; + if (match.Rule.HasDaylightSaving) + { + isDaylightSavings = GetIsDaylightSavingsFromUtc(time, timeYear, match.Offset, match.Rule, null, out isAmbiguousLocalDst, Local); + baseOffset += (isDaylightSavings ? match.Rule.DaylightDelta : TimeSpan.Zero /* FUTURE: rule.StandardDelta */); + } + } + return baseOffset; } private static bool EqualStandardDates(TimeZoneInformation timeZone, ref TIME_DYNAMIC_ZONE_INFORMATION tdzi) @@ -153,7 +808,7 @@ namespace System // // enumerate all time zones till find a match and with valid key name // - internal static unsafe bool FindMatchToCurrentTimeZone(TimeZoneInformation timeZoneInformation) + private static unsafe bool FindMatchToCurrentTimeZone(TimeZoneInformation timeZoneInformation) { uint index = 0; uint result = 0; // ERROR_SUCCESS @@ -203,7 +858,7 @@ namespace System TimeZoneInformation timeZoneInformation; if (!GetTimeZoneInfo(out timeZoneInformation)) { - return CreateCustomTimeZone(c_localId, TimeSpan.Zero, c_localId, c_localId); + return CreateCustomTimeZone(LocalId, TimeSpan.Zero, LocalId, LocalId); } Boolean dstDisabled = timeZoneInformation.Dtzi.DynamicDaylightTimeDisabled != 0; @@ -223,5 +878,15 @@ namespace System // Fall back to using the data from the Win32 API return GetLocalTimeZoneFromWin32Data(timeZoneInformation, dstDisabled); } - } // TimezoneInfo -} // namespace System + + private static TimeZoneInfoResult TryGetTimeZoneFromLocalMachine(string id, out TimeZoneInfo value, out Exception e) + { + // This method should be unreachable + Debug.Assert(false); + + e = null; + value = null; + return TimeZoneInfoResult.InvalidTimeZoneException; + } + } +} diff --git a/external/corert/src/System.Private.CoreLib/src/System/TimeZoneInfo.cs.REMOVED.git-id b/external/corert/src/System.Private.CoreLib/src/System/TimeZoneInfo.cs.REMOVED.git-id deleted file mode 100644 index 12ed4e3eb2..0000000000 --- a/external/corert/src/System.Private.CoreLib/src/System/TimeZoneInfo.cs.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -eee72972b436f576dd749d3f4aaaa7e088a4efc7 \ No newline at end of file diff --git a/external/corert/src/System.Private.CoreLib/src/System/Type.CoreRT.cs b/external/corert/src/System.Private.CoreLib/src/System/Type.CoreRT.cs index 8c1ce16906..30970c3499 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Type.CoreRT.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Type.CoreRT.cs @@ -51,6 +51,7 @@ namespace System return Type.GetTypeFromCLSID(clsid, server, throwOnError); } + [Intrinsic] public static bool operator ==(Type left, Type right) { if (object.ReferenceEquals(left, right)) @@ -62,6 +63,7 @@ namespace System return left.Equals(right); } + [Intrinsic] public static bool operator !=(Type left, Type right) => !(left == right); public bool IsRuntimeImplemented() => this is IRuntimeImplementedType; // Not an api but needs to be public because of Reflection.Core/CoreLib divide. diff --git a/external/corert/src/System.Private.CoreLib/src/System/ValueType.cs b/external/corert/src/System.Private.CoreLib/src/System/ValueType.cs index d75dd2692e..2c71bbcfe2 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/ValueType.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/ValueType.cs @@ -11,8 +11,13 @@ ** ===========================================================*/ +using System.Runtime; + +using Internal.Runtime.CompilerServices; using Internal.Runtime.Augments; +using Debug = System.Diagnostics.Debug; + namespace System { // CONTRACT with Runtime @@ -26,6 +31,7 @@ namespace System return this.GetType().ToString(); } +#if PROJECTN public override bool Equals(object obj) { return RuntimeAugments.Callbacks.ValueTypeEqualsUsingReflection(this, obj); @@ -35,5 +41,162 @@ namespace System { return RuntimeAugments.Callbacks.ValueTypeGetHashCodeUsingReflection(this); } +#else + private const int UseFastHelper = -1; + private const int GetNumFields = -1; + + // An override of this method will be injected by the compiler into all valuetypes that cannot be compared + // using a simple memory comparison. + // This API is a bit awkward because we want to avoid burning more than one vtable slot on this. + // When index == GetNumFields, this method is expected to return the number of fields of this + // valuetype. Otherwise, it returns the offset and type handle of the index-th field on this type. + internal virtual int __GetFieldHelper(int index, out EETypePtr eeType) + { + // Value types that don't override this method will use the fast path that looks at bytes, not fields. + Debug.Assert(index == GetNumFields); + eeType = default; + return UseFastHelper; + } + + public override bool Equals(object obj) + { + if (obj == null || obj.EETypePtr != this.EETypePtr) + return false; + + int numFields = __GetFieldHelper(GetNumFields, out _); + + ref byte thisRawData = ref this.GetRawData(); + ref byte thatRawData = ref obj.GetRawData(); + + if (numFields == UseFastHelper) + { + // Sanity check - if there are GC references, we should not be comparing bytes + Debug.Assert(!this.EETypePtr.HasPointers); + + // Compare the memory + int valueTypeSize = (int)this.EETypePtr.ValueTypeSize; + for (int i = 0; i < valueTypeSize; i++) + { + if (Unsafe.Add(ref thisRawData, i) != Unsafe.Add(ref thatRawData, i)) + return false; + } + } + else + { + // Foreach field, box and call the Equals method. + for (int i = 0; i < numFields; i++) + { + int fieldOffset = __GetFieldHelper(i, out EETypePtr fieldType); + + // Fetch the value of the field on both types + object thisField = RuntimeImports.RhBoxAny(ref Unsafe.Add(ref thisRawData, fieldOffset), fieldType); + object thatField = RuntimeImports.RhBoxAny(ref Unsafe.Add(ref thatRawData, fieldOffset), fieldType); + + // Compare the fields + if (thisField == null) + { + if (thatField != null) + return false; + } + else if (!thisField.Equals(thatField)) + { + return false; + } + } + } + + return true; + } + + public override int GetHashCode() + { + int hashCode = this.EETypePtr.GetHashCode(); + + hashCode ^= GetHashCodeImpl(); + + return hashCode; + } + + private int GetHashCodeImpl() + { + int numFields = __GetFieldHelper(GetNumFields, out _); + + if (numFields == UseFastHelper) + return FastGetValueTypeHashCodeHelper(this.EETypePtr, ref this.GetRawData()); + + return RegularGetValueTypeHashCode(this.EETypePtr, ref this.GetRawData(), numFields); + } + + private static int FastGetValueTypeHashCodeHelper(EETypePtr type, ref byte data) + { + // Sanity check - if there are GC references, we should not be hashing bytes + Debug.Assert(!type.HasPointers); + + int size = (int)type.ValueTypeSize; + int hashCode = 0; + + for (int i = 0; i < size / 4; i++) + { + hashCode ^= Unsafe.As(ref Unsafe.Add(ref data, i * 4)); + } + + return hashCode; + } + + private int RegularGetValueTypeHashCode(EETypePtr type, ref byte data, int numFields) + { + int hashCode = 0; + + // We only take the hashcode for the first non-null field. That's what the CLR does. + for (int i = 0; i < numFields; i++) + { + int fieldOffset = __GetFieldHelper(i, out EETypePtr fieldType); + ref byte fieldData = ref Unsafe.Add(ref data, fieldOffset); + + Debug.Assert(!fieldType.IsPointer); + + if (fieldType.CorElementType == RuntimeImports.RhCorElementType.ELEMENT_TYPE_R4) + { + hashCode = Unsafe.Read(ref fieldData).GetHashCode(); + } + else if (fieldType.CorElementType == RuntimeImports.RhCorElementType.ELEMENT_TYPE_R8) + { + hashCode = Unsafe.Read(ref fieldData).GetHashCode(); + } + else if (fieldType.IsPrimitive) + { + hashCode = FastGetValueTypeHashCodeHelper(fieldType, ref fieldData); + } + else if (fieldType.IsValueType) + { + // We have no option but to box since this value type could have + // GC pointers (we could find out if we want though), or fields of type Double/Single (we can't + // really find out). Double/Single have weird requirements around -0.0 and +0.0. + // If this boxing becomes a problem, we could build a piece of infrastructure that determines the slot + // of __GetFieldHelper, decodes the unboxing stub pointed to by the slot to the real target + // (we already have that part), and calls the entrypoint that expects a byref `this`, and use the + // data to decide between calling fast or regular hashcode helper. + var fieldValue = (ValueType)RuntimeImports.RhBox(fieldType, ref fieldData); + hashCode = fieldValue.GetHashCodeImpl(); + } + else + { + object fieldValue = Unsafe.Read(ref fieldData); + if (fieldValue != null) + { + hashCode = fieldValue.GetHashCode(); + } + else + { + // null object reference, try next + continue; + } + } + break; + } + + return hashCode; + } +#endif } } diff --git a/external/corert/src/System.Private.Interop/src/Internal/Runtime/CompilerHelpers/RuntimeInteropData.CoreRT.cs b/external/corert/src/System.Private.Interop/src/Internal/Runtime/CompilerHelpers/RuntimeInteropData.CoreRT.cs index 4de8b46035..afd236171d 100644 --- a/external/corert/src/System.Private.Interop/src/Internal/Runtime/CompilerHelpers/RuntimeInteropData.CoreRT.cs +++ b/external/corert/src/System.Private.Interop/src/Internal/Runtime/CompilerHelpers/RuntimeInteropData.CoreRT.cs @@ -13,23 +13,25 @@ namespace Internal.Runtime.CompilerHelpers { internal partial class RuntimeInteropData { - public override bool TryGetMarshallerDataForDelegate(RuntimeTypeHandle delegateTypeHandle, out McgPInvokeDelegateData data) + public override IntPtr GetForwardDelegateCreationStub(RuntimeTypeHandle delegateTypeHandle) { IntPtr openStub, closedStub, delegateCreationStub; - if (!TryGetMarshallersForDelegate(delegateTypeHandle, out openStub, out closedStub, out delegateCreationStub)) - { - data = default(McgPInvokeDelegateData); - return false; - } - - data = new global::System.Runtime.InteropServices.McgPInvokeDelegateData() - { - ReverseOpenStaticDelegateStub = openStub, - ReverseStub = closedStub, - ForwardDelegateCreationStub = delegateCreationStub - }; - return true; + GetMarshallersForDelegate(delegateTypeHandle, out openStub, out closedStub, out delegateCreationStub); + if (delegateCreationStub == IntPtr.Zero) + throw new MissingInteropDataException(SR.DelegateMarshalling_MissingInteropData, Type.GetTypeFromHandle(delegateTypeHandle)); + return delegateCreationStub; } + + public override IntPtr GetDelegateMarshallingStub(RuntimeTypeHandle delegateTypeHandle, bool openStaticDelegate) + { + IntPtr openStub, closedStub, delegateCreationStub; + GetMarshallersForDelegate(delegateTypeHandle, out openStub, out closedStub, out delegateCreationStub); + IntPtr pStub = openStaticDelegate ? openStub : closedStub; + if (pStub == IntPtr.Zero) + throw new MissingInteropDataException(SR.DelegateMarshalling_MissingInteropData, Type.GetTypeFromHandle(delegateTypeHandle)); + return pStub; + } + #region "Struct Data" public override bool TryGetStructUnmarshalStub(RuntimeTypeHandle structureTypeHandle, out IntPtr unmarshalStub) { @@ -112,7 +114,7 @@ namespace Internal.Runtime.CompilerHelpers return false; } - private unsafe bool TryGetMarshallersForDelegate(RuntimeTypeHandle delegateTypeHandle, out IntPtr openStub, out IntPtr closedStub, out IntPtr delegateCreationStub) + private unsafe bool GetMarshallersForDelegate(RuntimeTypeHandle delegateTypeHandle, out IntPtr openStub, out IntPtr closedStub, out IntPtr delegateCreationStub) { int delegateHashcode = delegateTypeHandle.GetHashCode(); openStub = IntPtr.Zero; diff --git a/external/corert/src/System.Private.Interop/src/Internal/Runtime/CompilerHelpers/RuntimeInteropData.ProjectN.cs b/external/corert/src/System.Private.Interop/src/Internal/Runtime/CompilerHelpers/RuntimeInteropData.ProjectN.cs index 84678d1b97..cfc7ce822b 100644 --- a/external/corert/src/System.Private.Interop/src/Internal/Runtime/CompilerHelpers/RuntimeInteropData.ProjectN.cs +++ b/external/corert/src/System.Private.Interop/src/Internal/Runtime/CompilerHelpers/RuntimeInteropData.ProjectN.cs @@ -14,9 +14,22 @@ namespace Internal.Runtime.CompilerHelpers { internal partial class RuntimeInteropData : InteropCallbacks { - public override bool TryGetMarshallerDataForDelegate(RuntimeTypeHandle delegateTypeHandle, out McgPInvokeDelegateData data) + public override IntPtr GetForwardDelegateCreationStub(RuntimeTypeHandle delegateTypeHandle) { - return McgModuleManager.GetPInvokeDelegateData(delegateTypeHandle, out data); + McgModuleManager.GetPInvokeDelegateData(delegateTypeHandle, out McgPInvokeDelegateData data); + IntPtr pStub = data.ForwardDelegateCreationStub; + if (pStub == IntPtr.Zero) + throw new MissingInteropDataException(SR.DelegateMarshalling_MissingInteropData, Type.GetTypeFromHandle(delegateTypeHandle)); + return pStub; + } + + public override IntPtr GetDelegateMarshallingStub(RuntimeTypeHandle delegateTypeHandle, bool openStaticDelegate) + { + McgModuleManager.GetPInvokeDelegateData(delegateTypeHandle, out McgPInvokeDelegateData pinvokeDelegateData); + IntPtr pStub = openStaticDelegate ? pinvokeDelegateData.ReverseOpenStaticDelegateStub : pinvokeDelegateData.ReverseStub; + if (pStub == IntPtr.Zero) + throw new MissingInteropDataException(SR.DelegateMarshalling_MissingInteropData, Type.GetTypeFromHandle(delegateTypeHandle)); + return pStub; } #region "Struct Data" diff --git a/external/corert/src/System.Private.Interop/src/Interop/Interop.WinRT.cs b/external/corert/src/System.Private.Interop/src/Interop/Interop.WinRT.cs index 3545b0a19a..1f27aeb552 100644 --- a/external/corert/src/System.Private.Interop/src/Interop/Interop.WinRT.cs +++ b/external/corert/src/System.Private.Interop/src/Interop/Interop.WinRT.cs @@ -44,7 +44,7 @@ namespace System.Runtime.InteropServices [DllImport(Libraries.CORE_WINRT)] [McgGeneratedNativeCallCodeAttribute] [MethodImplAttribute(MethodImplOptions.NoInlining)] - public static extern unsafe int RoActivateInstance(void* hActivableClassId, out void* ppv); + public static extern unsafe int RoActivateInstance(void* hActivatableClassId, out void* ppv); [DllImport(Libraries.CORE_WINRT_ERROR, PreserveSig = true)] diff --git a/external/corert/src/System.Private.Interop/src/InteropExtensions/PInvokeMarshal.Unix.cs b/external/corert/src/System.Private.Interop/src/InteropExtensions/PInvokeMarshal.Unix.cs new file mode 100644 index 0000000000..dfd32c719d --- /dev/null +++ b/external/corert/src/System.Private.Interop/src/InteropExtensions/PInvokeMarshal.Unix.cs @@ -0,0 +1,81 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.CompilerServices; +using System.Security; + +namespace System.Runtime.InteropServices +{ + /// + /// This PInvokeMarshal class should provide full public Marshal + /// implementation for all things related to P/Invoke marshalling + /// + public partial class PInvokeMarshal + { + public static void ClearLastWin32Error() + { + // no-op + } + + private static bool IsWin32Atom(IntPtr ptr) + { + return false; + } + + // In CoreRT on Unix, there is not yet a BSTR implementation. On Windows, we would use SysAllocStringLen from OleAut32.dll. + internal static IntPtr AllocBSTR(int length) + { + throw new PlatformNotSupportedException(); + } + + internal static void FreeBSTR(IntPtr ptr) + { + throw new PlatformNotSupportedException(); + } + + #region String marshalling + + public static unsafe int ConvertMultiByteToWideChar(byte* multiByteStr, + int multiByteLen, + char* wideCharStr, + int wideCharLen) + { + return System.Text.Encoding.UTF8.GetChars(multiByteStr, multiByteLen, wideCharStr, wideCharLen); + } + + public static unsafe int ConvertWideCharToMultiByte(char* wideCharStr, + int wideCharLen, + byte* multiByteStr, + int multiByteLen, + bool bestFit, + bool throwOnUnmappableChar) + { + return System.Text.Encoding.UTF8.GetBytes(wideCharStr, wideCharLen, multiByteStr, multiByteLen); + } + + public static unsafe int ConvertWideCharToMultiByte(char* wideCharStr, + int wideCharLen, + byte* multiByteStr, + int multiByteLen) + { + return System.Text.Encoding.UTF8.GetBytes(wideCharStr, wideCharLen, multiByteStr, multiByteLen); + } + + public static unsafe int GetByteCount(char* wideCharStr, int wideCharLen) + { + return System.Text.Encoding.UTF8.GetByteCount(wideCharStr, wideCharLen); + } + + public static unsafe int GetCharCount(byte* multiByteStr, int multiByteLen) + { + return System.Text.Encoding.UTF8.GetCharCount(multiByteStr, multiByteLen); + } + + public static unsafe int GetSystemMaxDBCSCharSize() + { + return 3; + } + #endregion + } +} diff --git a/external/corert/src/System.Private.Interop/src/InteropExtensions/PInvokeMarshal.Windows.cs b/external/corert/src/System.Private.Interop/src/InteropExtensions/PInvokeMarshal.Windows.cs new file mode 100644 index 0000000000..6b85547560 --- /dev/null +++ b/external/corert/src/System.Private.Interop/src/InteropExtensions/PInvokeMarshal.Windows.cs @@ -0,0 +1,156 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Security; + +namespace System.Runtime.InteropServices +{ + /// + /// This PInvokeMarshal class should provide full public Marshal + /// implementation for all things related to P/Invoke marshalling + /// + public partial class PInvokeMarshal + { + private const long HIWORDMASK = unchecked((long)0xffffffffffff0000L); + + // Win32 has the concept of Atoms, where a pointer can either be a pointer + // or an int. If it's less than 64K, this is guaranteed to NOT be a + // pointer since the bottom 64K bytes are reserved in a process' page table. + // We should be careful about deallocating this stuff. Extracted to + // a function to avoid C# problems with lack of support for IntPtr. + // We have 2 of these methods for slightly different semantics for NULL. + private static bool IsWin32Atom(IntPtr ptr) + { + long lPtr = (long)ptr; + return 0 == (lPtr & HIWORDMASK); + } + + private static bool IsNotWin32Atom(IntPtr ptr) + { + long lPtr = (long)ptr; + return 0 != (lPtr & HIWORDMASK); + } + public static void ClearLastWin32Error() + { + Interop.mincore.SetLastError(0); + } + + #region String marshalling + + public static unsafe int ConvertMultiByteToWideChar(byte* buffer, int ansiLength, char* pWChar, int uniLength) + { + return Interop.Kernel32.MultiByteToWideChar(Interop.Kernel32.CP_ACP, 0, buffer, ansiLength, pWChar, uniLength); + } + + // Convert a UTF16 string to ANSI byte array + public static unsafe int ConvertWideCharToMultiByte(char* wideCharStr, int wideCharLen, byte* multiByteStr, int multiByteLen) + { + return Interop.Kernel32.WideCharToMultiByte(Interop.Kernel32.CP_ACP, + 0, + wideCharStr, + wideCharLen, + multiByteStr, + multiByteLen, + default(IntPtr), + default(IntPtr) + ); + } + + // Convert a UTF16 string to ANSI byte array using flags + public static unsafe int ConvertWideCharToMultiByte(char* wideCharStr, + int wideCharLen, + byte* multiByteStr, + int multiByteLen, + bool bestFit, + bool throwOnUnmappableChar) + { + uint flags = (bestFit ? 0 : Interop.Kernel32.WC_NO_BEST_FIT_CHARS); + int defaultCharUsed = 0; + int ret = Interop.Kernel32.WideCharToMultiByte(Interop.Kernel32.CP_ACP, + flags, + wideCharStr, + wideCharLen, + multiByteStr, + multiByteLen, + default(IntPtr), + throwOnUnmappableChar ? new System.IntPtr(&defaultCharUsed) : default(IntPtr) + ); + if (defaultCharUsed != 0) + { + throw new ArgumentException(SR.Arg_InteropMarshalUnmappableChar); + } + + return ret; + } + + // Return size in bytes required to convert a UTF16 string to byte array. + public static unsafe int GetByteCount(char* wStr, int wideStrLen) + { + return Interop.Kernel32.WideCharToMultiByte(Interop.Kernel32.CP_ACP, + 0, + wStr, + wideStrLen, + default(byte*), + 0, + default(IntPtr), + default(IntPtr) + ); + } + + // Return number of charaters encoded in native byte array lpMultiByteStr + unsafe public static int GetCharCount(byte* multiByteStr, int multiByteLen) + { + return Interop.Kernel32.MultiByteToWideChar(Interop.Kernel32.CP_ACP, 0, multiByteStr, multiByteLen, default(char*), 0); + } + + public static unsafe int GetSystemMaxDBCSCharSize() + { + Interop.Kernel32.CPINFO cpInfo; + if (Interop.Kernel32.GetCPInfo(Interop.Kernel32.CP_ACP, &cpInfo) != 0) + { + return cpInfo.MaxCharSize; + } + else + { + return 2; + } + } + #endregion + } +} + +internal static partial class Interop +{ + internal static partial class Libraries + { + internal const string Kernel32 = "kernel32.dll"; + } + + internal partial class Kernel32 + { + [DllImport(Libraries.Kernel32)] + internal static extern unsafe int WideCharToMultiByte( + uint CodePage, uint dwFlags, + char* lpWideCharStr, int cchWideChar, + byte* lpMultiByteStr, int cbMultiByte, + IntPtr lpDefaultChar, IntPtr lpUsedDefaultChar); + + internal const uint CP_ACP = 0; + internal const uint WC_NO_BEST_FIT_CHARS = 0x00000400; + + internal unsafe struct CPINFO + { + internal int MaxCharSize; + + internal fixed byte DefaultChar[2 /* MAX_DEFAULTCHAR */]; + internal fixed byte LeadByte[12 /* MAX_LEADBYTES */]; + } + + [DllImport(Libraries.Kernel32)] + internal static extern unsafe int GetCPInfo(uint codePage, CPINFO* lpCpInfo); + } +} diff --git a/external/corert/src/System.Private.Interop/src/InteropExtensions/PInvokeMarshal.cs b/external/corert/src/System.Private.Interop/src/InteropExtensions/PInvokeMarshal.cs index 46da09e118..4287d0e166 100644 --- a/external/corert/src/System.Private.Interop/src/InteropExtensions/PInvokeMarshal.cs +++ b/external/corert/src/System.Private.Interop/src/InteropExtensions/PInvokeMarshal.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using Debug = System.Diagnostics.Debug; using System.Runtime.CompilerServices; namespace System.Runtime.InteropServices @@ -11,34 +12,32 @@ namespace System.Runtime.InteropServices /// implementation for all things related to P/Invoke marshalling /// [CLSCompliant(false)] - public sealed class PInvokeMarshal - { - public static void SaveLastWin32Error() - { - // nop - } - - public static void ClearLastWin32Error() - { - // nop - } + public partial class PInvokeMarshal + { + [ThreadStatic] + internal static int s_lastWin32Error; public static int GetLastWin32Error() { - return 0; + return s_lastWin32Error; } public static void SetLastWin32Error(int errorCode) { - // nop + s_lastWin32Error = errorCode; + } + + public static void SaveLastWin32Error() + { + s_lastWin32Error = Marshal.GetLastWin32Error(); } - public static IntPtr GetStubForPInvokeDelegate(Delegate del) + public static IntPtr GetFunctionPointerForDelegate(Delegate del) { return IntPtr.Zero; } - public static Delegate GetPInvokeDelegateForStub(IntPtr pStub, RuntimeTypeHandle delegateType) + public static Delegate GetDelegateForFunctionPointer(IntPtr pStub, RuntimeTypeHandle delegateType) { return default(Delegate); } @@ -85,124 +84,410 @@ namespace System.Runtime.InteropServices public static unsafe void StringBuilderToUnicodeString(System.Text.StringBuilder stringBuilder, ushort* destination) { - // nop + stringBuilder.UnsafeCopyTo((char*)destination); } public static unsafe void UnicodeStringToStringBuilder(ushort* newBuffer, System.Text.StringBuilder stringBuilder) { - // nop + stringBuilder.ReplaceBuffer((char*)newBuffer); } public static unsafe void StringBuilderToAnsiString(System.Text.StringBuilder stringBuilder, byte* pNative, bool bestFit, bool throwOnUnmappableChar) { - // nop + int len; + + // Convert StringBuilder to UNICODE string + // Optimize for the most common case. If there is only a single char[] in the StringBuilder, + // get it and convert it to ANSI + char[] buffer = stringBuilder.GetBuffer(out len); + if (buffer != null) + { + fixed (char* pManaged = buffer) + { + StringToAnsiString(pManaged, len, pNative, /*terminateWithNull=*/true, bestFit, throwOnUnmappableChar); + } + } + else // Otherwise, convert StringBuilder to string and then convert to ANSI + { + string str = stringBuilder.ToString(); + + // Convert UNICODE string to ANSI string + fixed (char* pManaged = str) + { + StringToAnsiString(pManaged, str.Length, pNative, /*terminateWithNull=*/true, bestFit, throwOnUnmappableChar); + } + } } public static unsafe void AnsiStringToStringBuilder(byte* newBuffer, System.Text.StringBuilder stringBuilder) { - // nop - } + if (newBuffer == null) + throw new ArgumentNullException(nameof(newBuffer)); + int lenAnsi; + int lenUnicode; + CalculateStringLength(newBuffer, out lenAnsi, out lenUnicode); + + if (lenUnicode > 0) + { + char[] buffer = new char[lenUnicode]; + fixed (char* pTemp = &buffer[0]) + { + ConvertMultiByteToWideChar(newBuffer, + lenAnsi, + pTemp, + lenUnicode); + } + stringBuilder.ReplaceBuffer(buffer); + } + else + { + stringBuilder.Clear(); + } + } + public static unsafe string AnsiStringToString(byte* pchBuffer) { - return default(string); + if (pchBuffer == null) + { + return null; + } + + int lenAnsi; + int lenUnicode; + CalculateStringLength(pchBuffer, out lenAnsi, out lenUnicode); + + string result = String.Empty; + + if (lenUnicode > 0) + { + result = new string(' ',lenUnicode); + + fixed (char* pTemp = result) + { + ConvertMultiByteToWideChar(pchBuffer, + lenAnsi, + pTemp, + lenUnicode); + } + } + + return result; } public static unsafe byte* StringToAnsiString(string str, bool bestFit, bool throwOnUnmappableChar) { - return default(byte*); + if (str != null) + { + int lenUnicode = str.Length; + + fixed (char* pManaged = str) + { + return StringToAnsiString(pManaged, lenUnicode, null, /*terminateWithNull=*/true, bestFit, throwOnUnmappableChar); + } + } + + return null; } public static unsafe void ByValWideCharArrayToAnsiCharArray(char[] managedArray, byte* pNative, int expectedCharCount, bool bestFit, bool throwOnUnmappableChar) { - // nop + // Zero-init pNative if it is NULL + if (managedArray == null) + { + // @TODO - Create a more efficient version of zero initialization + for (int i = 0; i < expectedCharCount; i++) + { + pNative[i] = 0; + } + } + + + int lenUnicode = managedArray.Length; + if (lenUnicode < expectedCharCount) + + throw new ArgumentException(SR.WrongSizeArrayInNStruct); + + fixed (char* pManaged = managedArray) + { + StringToAnsiString(pManaged, lenUnicode, pNative, /*terminateWithNull=*/false, bestFit, throwOnUnmappableChar); + } } public static unsafe void ByValAnsiCharArrayToWideCharArray(byte* pNative, char[] managedArray) { - // nop + // This should never happen because it is a embedded array + Debug.Assert(pNative != null); + + // This should never happen because the array is always allocated by the marshaller + Debug.Assert(managedArray != null); + + // COMPAT: Use the managed array length as the maximum length of native buffer + // This obviously doesn't make sense but desktop CLR does that + int lenInBytes = managedArray.Length; + fixed (char* pManaged = managedArray) + { + ConvertMultiByteToWideChar(pNative, + lenInBytes, + pManaged, + lenInBytes); + } } public static unsafe void WideCharArrayToAnsiCharArray(char[] managedArray, byte* pNative, bool bestFit, bool throwOnUnmappableChar) { - // nop + // Do nothing if array is NULL. This matches desktop CLR behavior + if (managedArray == null) + return; + + // Desktop CLR crash (AV at runtime) - we can do better in .NET Native + if (pNative == null) + throw new ArgumentNullException(nameof(pNative)); + + int lenUnicode = managedArray.Length; + fixed (char* pManaged = managedArray) + { + StringToAnsiString(pManaged, lenUnicode, pNative, /*terminateWithNull=*/false, bestFit, throwOnUnmappableChar); + } } public static unsafe void AnsiCharArrayToWideCharArray(byte* pNative, char[] managedArray) { - // nop + // Do nothing if native is NULL. This matches desktop CLR behavior + if (pNative == null) + return; + + // Desktop CLR crash (AV at runtime) - we can do better in .NET Native + if (managedArray == null) + throw new ArgumentNullException(nameof(managedArray)); + + // COMPAT: Use the managed array length as the maximum length of native buffer + // This obviously doesn't make sense but desktop CLR does that + int lenInBytes = managedArray.Length; + fixed (char* pManaged = managedArray) + { + ConvertMultiByteToWideChar(pNative, + lenInBytes, + pManaged, + lenInBytes); + } } public static unsafe byte WideCharToAnsiChar(char managedValue, bool bestFit, bool throwOnUnmappableChar) { - return default(byte); + // @TODO - we really shouldn't allocate one-byte arrays and then destroy it + byte* nativeArray = StringToAnsiString(&managedValue, 1, null, /*terminateWithNull=*/false, bestFit, throwOnUnmappableChar); + byte native = (*nativeArray); + CoTaskMemFree(new IntPtr(nativeArray)); + return native; } public static unsafe char AnsiCharToWideChar(byte nativeValue) { - return default(char); + char ch; + ConvertMultiByteToWideChar(&nativeValue, 1, &ch, 1); + return ch; } public static unsafe void StringToByValAnsiString(string str, byte* pNative, int charCount, bool bestFit, bool throwOnUnmappableChar, bool truncate = true) { - // nop + if (pNative == null) + throw new ArgumentNullException(nameof(pNative)); + + if (str != null) + { + // Truncate the string if it is larger than specified by SizeConst + int lenUnicode; + + if (truncate) + { + lenUnicode = str.Length; + if (lenUnicode >= charCount) + lenUnicode = charCount - 1; + } + else + { + lenUnicode = charCount; + } + + fixed (char* pManaged = str) + { + StringToAnsiString(pManaged, lenUnicode, pNative, /*terminateWithNull=*/true, bestFit, throwOnUnmappableChar); + } + } + else + { + (*pNative) = (byte)'\0'; + } } public static unsafe string ByValAnsiStringToString(byte* pchBuffer, int charCount) { - return default(string); + // Match desktop CLR behavior + if (charCount == 0) + throw new MarshalDirectiveException(); + + int lenAnsi = GetAnsiStringLen(pchBuffer); + int lenUnicode = charCount; + + string result = String.Empty; + + if (lenUnicode > 0) + { + char* unicodeBuf = stackalloc char[lenUnicode]; + int unicodeCharWritten = ConvertMultiByteToWideChar(pchBuffer, + lenAnsi, + unicodeBuf, + lenUnicode); + + // If conversion failure, return empty string to match desktop CLR behavior + if (unicodeCharWritten > 0) + result = new string(unicodeBuf, 0, unicodeCharWritten); + } + + return result; + } + + + private static unsafe int GetAnsiStringLen(byte* pchBuffer) + { + byte* pchBufferOriginal = pchBuffer; + while (*pchBuffer != 0) + { + pchBuffer++; + } + + return (int)(pchBuffer - pchBufferOriginal); } - public static unsafe int ConvertMultiByteToWideChar(byte* buffer, int ansiLength, char* pWChar, int uniLength) + // c# string (UTF-16) to UTF-8 encoded byte array + private static unsafe byte* StringToAnsiString(char* pManaged, int lenUnicode, byte* pNative, bool terminateWithNull, + bool bestFit, bool throwOnUnmappableChar) { - return default(int); - } + bool allAscii = true; - public static unsafe int ConvertWideCharToMultiByte(char* wideCharStr, int wideCharLen, byte* multiByteStr, int multiByteLen) - { - return default(int); - } + for (int i = 0; i < lenUnicode; i++) + { + if (pManaged[i] >= 128) + { + allAscii = false; + break; + } + } - public static unsafe int ConvertWideCharToMultiByte(char* wideCharStr, - int wideCharLen, - byte* multiByteStr, - int multiByteLen, - uint flags, - IntPtr usedDefaultChar) - { - return default(int); - } + int length; - public static unsafe int GetByteCount(char* wStr, int wideStrLen) - { - return default(int); - } + if (allAscii) // If all ASCII, map one UNICODE character to one ANSI char + { + length = lenUnicode; + } + else // otherwise, let OS count number of ANSI chars + { + length = GetByteCount(pManaged, lenUnicode); + } - unsafe public static int GetCharCount(byte* multiByteStr, int multiByteLen) - { - return default(int); - } + if (pNative == null) + { + pNative = (byte*)CoTaskMemAlloc((System.UIntPtr)(length + 1)); + } + if (allAscii) // ASCII conversion + { + byte* pDst = pNative; + char* pSrc = pManaged; - public static unsafe int GetSystemMaxDBCSCharSize() - { - return default(int); + while (lenUnicode > 0) + { + unchecked + { + *pDst++ = (byte)(*pSrc++); + lenUnicode--; + } + } + } + else // Let OS convert + { + ConvertWideCharToMultiByte(pManaged, + lenUnicode, + pNative, + length, + bestFit, + throwOnUnmappableChar); + } + + // Zero terminate + if (terminateWithNull) + *(pNative + length) = 0; + + return pNative; } public static unsafe String PtrToStringUni(IntPtr ptr, int len) { - return default(String); + return Marshal.PtrToStringUni(ptr, len); } public static unsafe String PtrToStringUni(IntPtr ptr) { - return default(String); + return Marshal.PtrToStringUni(ptr); } - + + public static unsafe String PtrToStringAnsi(IntPtr ptr) + { + return Marshal.PtrToStringAnsi(ptr); + } + + public static unsafe String PtrToStringAnsi(IntPtr ptr, int len) + { + return Marshal.PtrToStringAnsi(ptr, len); + } + + //==================================================================== + // Copy blocks from CLR arrays to native memory. + //==================================================================== public static unsafe void CopyToNative(Array source, int startIndex, IntPtr destination, int length) { - // nop - } + throw new PlatformNotSupportedException(); + } + + /// + /// This is a auxiliary function that counts the length of the ansi buffer and + /// estimate the length of the buffer in Unicode. It returns true if all bytes + /// in the buffer are ANSII. + /// + private static unsafe bool CalculateStringLength(byte* pchBuffer, out int ansiBufferLen, out int unicodeBufferLen) + { + ansiBufferLen = 0; + + bool allAscii = true; + + { + byte* p = pchBuffer; + byte b = *p++; + + while (b != 0) + { + if (b >= 128) + { + allAscii = false; + } + + ansiBufferLen++; + + b = *p++; + } + } + + if (allAscii) + { + unicodeBufferLen = ansiBufferLen; + } + else // If non ASCII, let OS calculate number of characters + { + unicodeBufferLen = GetCharCount(pchBuffer, ansiBufferLen); + } + return allAscii; + } } } diff --git a/external/corert/src/System.Private.Interop/src/Resources/Strings.resx b/external/corert/src/System.Private.Interop/src/Resources/Strings.resx index a2d51ec829..636774c6b4 100644 --- a/external/corert/src/System.Private.Interop/src/Resources/Strings.resx +++ b/external/corert/src/System.Private.Interop/src/Resources/Strings.resx @@ -366,4 +366,10 @@ 'Type '{0}' is not a delegate type. EventTokenTable may only be used with delegate types.' + + Type could not be marshaled because the length of an embedded array instance does not match the declared length in the layout. + + + Cannot marshal: Encountered unmappable character. + \ No newline at end of file diff --git a/external/corert/src/System.Private.Interop/src/Shared/ComCallableObject.cs b/external/corert/src/System.Private.Interop/src/Shared/ComCallableObject.cs index 04ad4e4873..7bce62ca85 100644 --- a/external/corert/src/System.Private.Interop/src/Shared/ComCallableObject.cs +++ b/external/corert/src/System.Private.Interop/src/Shared/ComCallableObject.cs @@ -250,7 +250,7 @@ namespace System.Runtime.InteropServices /// Combined Ref Count of COM and Jupiter /// COM takes lower 32-bit while Jupiter takes higher 32-bit. /// It's OK for COM ref count to overflow - /// Be verycareful when you read this because you can't read this atomicly under x86 directly. + /// Be verycareful when you read this because you can't read this atomically under x86 directly. /// Only use CombinedRefCount property for thread-safety /// long m_lRefCount; diff --git a/external/corert/src/System.Private.Interop/src/Shared/Marshal.cs b/external/corert/src/System.Private.Interop/src/Shared/Marshal.cs index 4dfbd0bfff..6a0be9a501 100644 --- a/external/corert/src/System.Private.Interop/src/Shared/Marshal.cs +++ b/external/corert/src/System.Private.Interop/src/Shared/Marshal.cs @@ -93,7 +93,8 @@ namespace System.Runtime.InteropServices createCOMException : true, hasErrorInfo: false); #else - return new Exception(errorCode.ToString()); + // TODO: Map HR to exeption even without COM interop support? + return new COMException(errorCode); #endif } } diff --git a/external/corert/src/System.Private.Interop/src/Shared/McgMarshal.cs b/external/corert/src/System.Private.Interop/src/Shared/McgMarshal.cs index bf51b8d352..d6ef590c2e 100644 --- a/external/corert/src/System.Private.Interop/src/Shared/McgMarshal.cs +++ b/external/corert/src/System.Private.Interop/src/Shared/McgMarshal.cs @@ -990,7 +990,7 @@ namespace System.Runtime.InteropServices public static int GetHRForExceptionWinRT(Exception ex) { #if ENABLE_WINRT - return ExceptionHelpers.GetHRForExceptionWithErrorPropogationNoThrow(ex, true); + return ExceptionHelpers.GetHRForExceptionWithErrorPropagationNoThrow(ex, true); #else // TODO : ExceptionHelpers should be platform specific , move it to // seperate source files @@ -1003,7 +1003,7 @@ namespace System.Runtime.InteropServices public static int GetHRForException(Exception ex) { #if ENABLE_WINRT - return ExceptionHelpers.GetHRForExceptionWithErrorPropogationNoThrow(ex, false); + return ExceptionHelpers.GetHRForExceptionWithErrorPropagationNoThrow(ex, false); #else return ex.HResult; #endif @@ -1033,7 +1033,8 @@ namespace System.Runtime.InteropServices #elif CORECLR return Marshal.GetExceptionForHR(hr); #else - return new COMException(hr.ToString(), hr); + // TODO: Map HR to exeption even without COM interop support? + return new COMException(hr); #endif } @@ -1117,7 +1118,7 @@ namespace System.Runtime.InteropServices #if CORECLR throw new NotSupportedException(); #else - return PInvokeMarshal.GetStubForPInvokeDelegate(dele); + return PInvokeMarshal.GetFunctionPointerForDelegate(dele); #endif } @@ -1141,7 +1142,7 @@ namespace System.Runtime.InteropServices pStub ); #else - return PInvokeMarshal.GetPInvokeDelegateForStub(pStub, delegateType); + return PInvokeMarshal.GetDelegateForFunctionPointer(pStub, delegateType); #endif } diff --git a/external/corert/src/System.Private.Interop/src/Shared/McgModuleManager.cs b/external/corert/src/System.Private.Interop/src/Shared/McgModuleManager.cs index 0c7856dcb7..365509a588 100644 --- a/external/corert/src/System.Private.Interop/src/Shared/McgModuleManager.cs +++ b/external/corert/src/System.Private.Interop/src/Shared/McgModuleManager.cs @@ -724,11 +724,7 @@ namespace System.Runtime.InteropServices return true; } } -#if ENABLE_WINRT - throw new MissingInteropDataException(SR.DelegateMarshalling_MissingInteropData, Type.GetTypeFromHandle(delegateType)); -#else return false; -#endif } #endregion diff --git a/external/corert/src/Common/src/System/Runtime/InteropServices/McgPInvokeData.cs b/external/corert/src/System.Private.Interop/src/Shared/McgPInvokeData.cs similarity index 82% rename from external/corert/src/Common/src/System/Runtime/InteropServices/McgPInvokeData.cs rename to external/corert/src/System.Private.Interop/src/Shared/McgPInvokeData.cs index ceaaa1e51e..c0d01fce61 100644 --- a/external/corert/src/Common/src/System/Runtime/InteropServices/McgPInvokeData.cs +++ b/external/corert/src/System.Private.Interop/src/Shared/McgPInvokeData.cs @@ -102,25 +102,4 @@ namespace System.Runtime.InteropServices /// public IntPtr ForwardDelegateCreationStub; } - - - /// - /// Base class for all 'wrapper' classes that wraps a native function pointer - /// The forward delegates (that wraps native function pointers) points to derived Invoke method of this - /// class, and the Invoke method would implement the marshalling and making the call - /// - public abstract class NativeFunctionPointerWrapper - { - public NativeFunctionPointerWrapper(IntPtr nativeFunctionPointer) - { - m_nativeFunctionPointer = nativeFunctionPointer; - } - - IntPtr m_nativeFunctionPointer; - - public IntPtr NativeFunctionPointer - { - get { return m_nativeFunctionPointer; } - } - } } diff --git a/external/corert/src/System.Private.Interop/src/Shared/McgTypeHelpers.cs b/external/corert/src/System.Private.Interop/src/Shared/McgTypeHelpers.cs index a6e80880c6..25496e665f 100644 --- a/external/corert/src/System.Private.Interop/src/Shared/McgTypeHelpers.cs +++ b/external/corert/src/System.Private.Interop/src/Shared/McgTypeHelpers.cs @@ -1213,7 +1213,7 @@ namespace System.Runtime.InteropServices #region "CCWTemplate Data" internal static string GetCCWRuntimeClassName(this RuntimeTypeHandle ccwType) { - // Special case for Object type to aligh with desktop behavior + // Special case for Object type to align with desktop behavior if (ccwType.Equals(typeof(Object).TypeHandle)) return default(string); diff --git a/external/corert/src/System.Private.Interop/src/System.Private.Interop.CoreCLR.csproj b/external/corert/src/System.Private.Interop/src/System.Private.Interop.CoreCLR.csproj index 443e811f70..00f7d24f4c 100644 --- a/external/corert/src/System.Private.Interop/src/System.Private.Interop.CoreCLR.csproj +++ b/external/corert/src/System.Private.Interop/src/System.Private.Interop.CoreCLR.csproj @@ -50,12 +50,10 @@ - - System\Runtime\InteropServices\McgPInvokeData.cs - System\Runtime\InteropServices\McgGeneratedNativeCallCodeAttribute.cs + @@ -63,7 +61,24 @@ + + + + + Interop\Windows\kernel32\Interop.MultiByteToWideChar.cs + + + Interop\Windows\mincore\Interop.SetLastError.cs + + + Interop\Windows\Interop.Libraries.cs + + + + + + diff --git a/external/corert/src/System.Private.Interop/src/System.Private.Interop.Mono.csproj b/external/corert/src/System.Private.Interop/src/System.Private.Interop.Mono.csproj index efe03b78e3..04be684230 100644 --- a/external/corert/src/System.Private.Interop/src/System.Private.Interop.Mono.csproj +++ b/external/corert/src/System.Private.Interop/src/System.Private.Interop.Mono.csproj @@ -54,12 +54,10 @@ - - System\Runtime\InteropServices\McgPInvokeData.cs - System\Runtime\InteropServices\McgGeneratedNativeCallCodeAttribute.cs + @@ -101,7 +99,24 @@ - + + + + + Interop\Windows\kernel32\Interop.MultiByteToWideChar.cs + + + Interop\Windows\mincore\Interop.SetLastError.cs + + + Interop\Windows\Interop.Libraries.cs + + + + + + + diff --git a/external/corert/src/System.Private.Interop/src/System.Private.Interop.Shared.projitems b/external/corert/src/System.Private.Interop/src/System.Private.Interop.Shared.projitems index 394ff286f3..a76881f51e 100644 --- a/external/corert/src/System.Private.Interop/src/System.Private.Interop.Shared.projitems +++ b/external/corert/src/System.Private.Interop/src/System.Private.Interop.Shared.projitems @@ -11,8 +11,6 @@ - - @@ -38,6 +36,7 @@ + diff --git a/external/corert/src/System.Private.Interop/src/System.Private.Interop.csproj b/external/corert/src/System.Private.Interop/src/System.Private.Interop.csproj index 03ca929280..73411b2108 100644 --- a/external/corert/src/System.Private.Interop/src/System.Private.Interop.csproj +++ b/external/corert/src/System.Private.Interop/src/System.Private.Interop.csproj @@ -144,6 +144,10 @@ + + + + diff --git a/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/bindptr.cs b/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/bindptr.cs index 3405ef9a94..1dde60ab22 100644 --- a/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/bindptr.cs +++ b/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/bindptr.cs @@ -9,10 +9,13 @@ namespace System.Runtime.InteropServices.ComTypes [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)] public struct BINDPTR { + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2111:PointersShouldNotBeVisible", Justification="Backwards compatibility")] [FieldOffset(0)] public IntPtr lpfuncdesc; + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2111:PointersShouldNotBeVisible", Justification="Backwards compatibility")] [FieldOffset(0)] public IntPtr lpvardesc; + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2111:PointersShouldNotBeVisible", Justification="Backwards compatibility")] [FieldOffset(0)] public IntPtr lptcomp; } diff --git a/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/dispparams.cs b/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/dispparams.cs index bea6e7c378..404c768ff9 100644 --- a/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/dispparams.cs +++ b/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/dispparams.cs @@ -9,7 +9,9 @@ namespace System.Runtime.InteropServices.ComTypes [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct DISPPARAMS { + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2111:PointersShouldNotBeVisible", Justification="Backwards compatibility")] public IntPtr rgvarg; + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2111:PointersShouldNotBeVisible", Justification="Backwards compatibility")] public IntPtr rgdispidNamedArgs; public int cArgs; public int cNamedArgs; diff --git a/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/excepinfo.cs b/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/excepinfo.cs index bab6e5fa80..9a0187ddaa 100644 --- a/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/excepinfo.cs +++ b/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/excepinfo.cs @@ -18,7 +18,9 @@ namespace System.Runtime.InteropServices.ComTypes [MarshalAs(UnmanagedType.BStr)] public String bstrHelpFile; public int dwHelpContext; + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2111:PointersShouldNotBeVisible", Justification="Backwards compatibility")] public IntPtr pvReserved; + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2111:PointersShouldNotBeVisible", Justification="Backwards compatibility")] public IntPtr pfnDeferredFillIn; public Int32 scode; } diff --git a/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/formatetc.cs b/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/formatetc.cs index 2365cfe9af..b443c2b347 100644 --- a/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/formatetc.cs +++ b/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/formatetc.cs @@ -10,6 +10,7 @@ namespace System.Runtime.InteropServices.ComTypes { [MarshalAs(UnmanagedType.U2)] public short cfFormat; + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2111:PointersShouldNotBeVisible", Justification="Backwards compatibility")] public IntPtr ptd; [MarshalAs(UnmanagedType.U4)] public DVASPECT dwAspect; diff --git a/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/funcdesc.cs b/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/funcdesc.cs index ab249c4699..63e6653392 100644 --- a/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/funcdesc.cs +++ b/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/funcdesc.cs @@ -10,7 +10,9 @@ namespace System.Runtime.InteropServices.ComTypes public struct FUNCDESC { public int memid; //MEMBERID memid; + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2111:PointersShouldNotBeVisible", Justification="Backwards compatibility")] public IntPtr lprgscode; // /* [size_is(cScodes)] */ SCODE RPC_FAR *lprgscode; + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2111:PointersShouldNotBeVisible", Justification="Backwards compatibility")] public IntPtr lprgelemdescParam; // /* [size_is(cParams)] */ ELEMDESC __RPC_FAR *lprgelemdescParam; public FUNCKIND funckind; //FUNCKIND funckind; public INVOKEKIND invkind; //INVOKEKIND invkind; diff --git a/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/idldesc.cs b/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/idldesc.cs index 1892879246..31493355e6 100644 --- a/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/idldesc.cs +++ b/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/idldesc.cs @@ -9,6 +9,7 @@ namespace System.Runtime.InteropServices.ComTypes [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct IDLDESC { + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2111:PointersShouldNotBeVisible", Justification="Backwards compatibility")] public IntPtr dwReserved; public IDLFLAG wIDLFlags; } diff --git a/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/paramdesc.cs b/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/paramdesc.cs index bc0d107e19..809ce145cc 100644 --- a/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/paramdesc.cs +++ b/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/paramdesc.cs @@ -9,6 +9,7 @@ namespace System.Runtime.InteropServices.ComTypes [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct PARAMDESC { + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2111:PointersShouldNotBeVisible", Justification="Backwards compatibility")] public IntPtr lpVarValue; public PARAMFLAG wParamFlags; } diff --git a/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/stgmedium.cs b/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/stgmedium.cs index cdb8015acf..77505cd72a 100644 --- a/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/stgmedium.cs +++ b/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/stgmedium.cs @@ -9,6 +9,7 @@ namespace System.Runtime.InteropServices.ComTypes public struct STGMEDIUM { public TYMED tymed; + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2111:PointersShouldNotBeVisible", Justification="Backwards compatibility")] public IntPtr unionmember; [MarshalAs(UnmanagedType.IUnknown)] public object pUnkForRelease; diff --git a/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/typeattr.cs b/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/typeattr.cs index bf4488b725..3e63811924 100644 --- a/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/typeattr.cs +++ b/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/typeattr.cs @@ -18,6 +18,7 @@ namespace System.Runtime.InteropServices.ComTypes public Int32 dwReserved; public Int32 memidConstructor; public Int32 memidDestructor; + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2111:PointersShouldNotBeVisible", Justification="Backwards compatibility")] public IntPtr lpstrSchema; public Int32 cbSizeInstance; public TYPEKIND typekind; diff --git a/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/typedesc.cs b/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/typedesc.cs index 29d9a2e9ee..696f439adf 100644 --- a/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/typedesc.cs +++ b/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/typedesc.cs @@ -9,6 +9,7 @@ namespace System.Runtime.InteropServices.ComTypes [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct TYPEDESC { + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2111:PointersShouldNotBeVisible", Justification="Backwards compatibility")] public IntPtr lpValue; public Int16 vt; } diff --git a/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/vardesc.cs b/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/vardesc.cs index 2a349f42ae..abc4b70d7e 100644 --- a/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/vardesc.cs +++ b/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/ComTypes/vardesc.cs @@ -17,6 +17,7 @@ namespace System.Runtime.InteropServices.ComTypes { [FieldOffset(0)] public int oInst; + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2111:PointersShouldNotBeVisible", Justification="Backwards compatibility")] [FieldOffset(0)] public IntPtr lpvarValue; }; diff --git a/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/Marshal.cs b/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/Marshal.cs index f9e481abc3..d565e199f0 100644 --- a/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/Marshal.cs +++ b/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/Marshal.cs @@ -2,13 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -// -// This file provides an implementation of the pieces of the Marshal class which are required by the Interop -// API contract but are not provided by the version of Marshal which is part of the Redhawk test library. -// This partial class is combined with the version from the Redhawk test library, in order to provide the -// Marshal implementation for System.Private.CoreLib. -// - using System; using System.Collections.Generic; using System.Diagnostics; @@ -575,7 +568,7 @@ namespace System.Runtime.InteropServices createCOMException: false, hasErrorInfo: false); #else - throw new PlatformNotSupportedException("GetExceptionForHR"); + return new COMException(errorCode); #endif // ENABLE_WINRT } @@ -763,7 +756,7 @@ namespace System.Runtime.InteropServices { throw new ArgumentNullException(nameof(o)); } - return MarshalAdapter.GetIUnknownForObject(o); + return McgMarshal.ObjectToComInterface(o, InternalTypes.IUnknown); } //==================================================================== @@ -775,7 +768,7 @@ namespace System.Runtime.InteropServices { throw new ArgumentNullException(nameof(pUnk)); } - return MarshalAdapter.GetObjectForIUnknown(pUnk); + return McgMarshal.ComInterfaceToObject(pUnk, InternalTypes.IUnknown); } //==================================================================== @@ -1018,7 +1011,7 @@ namespace System.Runtime.InteropServices if (d == null) throw new ArgumentNullException(nameof(d)); - return PInvokeMarshal.GetStubForPInvokeDelegate(d); + return PInvokeMarshal.GetFunctionPointerForDelegate(d); } public static IntPtr GetFunctionPointerForDelegate(TDelegate d) @@ -1268,7 +1261,13 @@ namespace System.Runtime.InteropServices public static IntPtr /* IUnknown* */ GetComInterfaceForObject(Object o, Type T) { - return MarshalAdapter.GetComInterfaceForObject(o, T); + if (o == null) + throw new ArgumentNullException(nameof(o)); + + if (T == null) + throw new ArgumentNullException(nameof(T)); + + return McgMarshal.ObjectToComInterface(o, T.TypeHandle); } public static TDelegate GetDelegateForFunctionPointer(IntPtr ptr) @@ -1288,13 +1287,12 @@ namespace System.Runtime.InteropServices if (t.TypeHandle.IsGenericType() || t.TypeHandle.IsGenericTypeDefinition()) throw new ArgumentException(SR.Argument_NeedNonGenericType, nameof(t)); - bool isDelegateType = InteropExtensions.AreTypesAssignable(t.TypeHandle, typeof(MulticastDelegate).TypeHandle) || - InteropExtensions.AreTypesAssignable(t.TypeHandle, typeof(Delegate).TypeHandle); + bool isDelegateType = InteropExtensions.AreTypesAssignable(t.TypeHandle, typeof(Delegate).TypeHandle); if (!isDelegateType) throw new ArgumentException(SR.Arg_MustBeDelegateType, nameof(t)); - return MarshalAdapter.GetDelegateForFunctionPointer(ptr, t); + return McgMarshal.GetPInvokeDelegateForStub(ptr, t.TypeHandle); } //==================================================================== diff --git a/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/MarshalAdapter.cs b/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/MarshalAdapter.cs index 599eca594e..ecfe57beec 100644 --- a/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/MarshalAdapter.cs +++ b/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/MarshalAdapter.cs @@ -2,13 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -// -// This file provides an implementation of the pieces of the Marshal class which are required by the Interop -// API contract but are not provided by the version of Marshal which is part of the Redhawk test library. -// This partial class is combined with the version from the Redhawk test library, in order to provide the -// Marshal implementation for System.Private.CoreLib. -// - using System; using System.Collections.Generic; using System.Runtime.CompilerServices; @@ -36,7 +29,7 @@ namespace System.Runtime.InteropServices //==================================================================== public static IntPtr /* IUnknown* */ GetIUnknownForObject(Object o) { - return MarshalImpl.GetIUnknownForObject(o); + return McgMarshal.ObjectToComInterface(o, InternalTypes.IUnknown); } //==================================================================== @@ -44,7 +37,7 @@ namespace System.Runtime.InteropServices //==================================================================== public static Object GetObjectForIUnknown(IntPtr /* IUnknown* */ pUnk) { - object obj = MarshalImpl.GetObjectForIUnknown(pUnk); + object obj = McgMarshal.ComInterfaceToObject(pUnk, InternalTypes.IUnknown); #if CORECLR if (obj == null) { @@ -61,7 +54,13 @@ namespace System.Runtime.InteropServices public static IntPtr /* IUnknown* */ GetComInterfaceForObject(Object o, Type T) { - IntPtr ptr = MarshalImpl.GetComInterfaceForObject(o, T); + if (o == null) + throw new ArgumentNullException(nameof(o)); + + if (T == null) + throw new ArgumentNullException(nameof(T)); + + IntPtr ptr = McgMarshal.ObjectToComInterface(o, T.TypeHandle); #if CORECLR if (ptr == default(IntPtr)) { @@ -81,7 +80,7 @@ namespace System.Runtime.InteropServices //==================================================================== public static Delegate GetDelegateForFunctionPointer(IntPtr ptr, Type t) { - Delegate dlg = MarshalImpl.GetDelegateForFunctionPointer(ptr, t); + Delegate dlg = McgMarshal.GetPInvokeDelegateForStub(ptr, t.TypeHandle); #if CORECLR if (dlg == null) // fall back to public marshal API { @@ -93,32 +92,42 @@ namespace System.Runtime.InteropServices public static bool IsComObject(object o) { - return MarshalImpl.IsComObject(o); + if (o == null) + throw new ArgumentNullException(nameof(o)); + return McgMarshal.IsComObject(o); } public static int ReleaseComObject(object o) { - return MarshalImpl.ReleaseComObject(o); + if (o == null) + throw new ArgumentNullException(nameof(o)); + return McgMarshal.Release(o as __ComObject); } public static int FinalReleaseComObject(object o) { - return MarshalImpl.FinalReleaseComObject(o); + return McgMarshal.FinalReleaseComObject(o); } public static int QueryInterface(IntPtr pUnk, ref Guid iid, out IntPtr ppv) { - return MarshalImpl.QueryInterface(pUnk, ref iid, out ppv); + int hr = 0; + ppv = McgMarshal.ComQueryInterfaceNoThrow(pUnk, ref iid, out hr); +#if CORECLR + if (ppv == default(IntPtr)) + return Marshal.QueryInterface(pUnk, ref iid, out ppv); +#endif + return hr; } public static int AddRef(IntPtr pUnk) { - return MarshalImpl.AddRef(pUnk); + return McgMarshal.ComAddRef(pUnk); } public static int Release(IntPtr pUnk) { - return MarshalImpl.Release(pUnk); + return McgMarshal.ComRelease(pUnk); } } #pragma warning restore 618 diff --git a/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/MarshalImpl.cs b/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/MarshalImpl.cs deleted file mode 100644 index 20f08a9198..0000000000 --- a/external/corert/src/System.Private.Interop/src/System/Runtime/InteropServices/MarshalImpl.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Runtime.CompilerServices; - -namespace System.Runtime.InteropServices -{ - internal static partial class MarshalImpl - { - public static IntPtr /* IUnknown* */ GetIUnknownForObject(Object o) - { - return McgMarshal.ObjectToComInterface(o, InternalTypes.IUnknown); - } - - public static Object GetObjectForIUnknown(IntPtr /* IUnknown* */ pUnk) - { - return McgMarshal.ComInterfaceToObject(pUnk, InternalTypes.IUnknown); - } - - public static Delegate GetDelegateForFunctionPointer(IntPtr ptr, Type t) - { - return McgMarshal.GetPInvokeDelegateForStub(ptr, t.TypeHandle); - } - public static IntPtr /* IUnknown* */ GetComInterfaceForObject(Object o, Type t) - { - if (o == null) - throw new ArgumentNullException(nameof(o)); - - if (t == null) - throw new ArgumentNullException(nameof(t)); - - return McgMarshal.ObjectToComInterface(o, t.TypeHandle); - } - - public static bool IsComObject(object o) - { - if (o == null) - throw new ArgumentNullException(nameof(o)); - return McgMarshal.IsComObject(o); - } - public static int ReleaseComObject(object o) - { - if (o == null) - throw new ArgumentNullException(nameof(o)); - return McgMarshal.Release(o as __ComObject); - } - - public static int FinalReleaseComObject(object o) - { - return McgMarshal.FinalReleaseComObject(o); - } - - public static int QueryInterface(IntPtr pUnk, ref Guid iid, out IntPtr ppv) - { - int hr = 0; - ppv = McgMarshal.ComQueryInterfaceNoThrow(pUnk, ref iid, out hr); -#if CORECLR - if (ppv == default(IntPtr)) - return Marshal.QueryInterface(pUnk, ref iid, out ppv); -#endif - return hr; - } - - public static int AddRef(IntPtr pUnk) - { - return McgMarshal.ComAddRef(pUnk); - } - - public static int Release(IntPtr pUnk) - { - return McgMarshal.ComRelease(pUnk); - } - } -} diff --git a/external/corert/src/System.Private.Interop/src/TypeForwarders.cs b/external/corert/src/System.Private.Interop/src/TypeForwarders.cs index 03271b59aa..a056216a8e 100644 --- a/external/corert/src/System.Private.Interop/src/TypeForwarders.cs +++ b/external/corert/src/System.Private.Interop/src/TypeForwarders.cs @@ -2,5 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.InteropServices.DefaultCharSetAttribute))] +[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.InteropServices.DefaultDllImportSearchPathsAttribute))] +[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.InteropServices.DllImportSearchPath))] [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.InteropServices.GuidAttribute))] [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.InteropServices.HandleRef))] +[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.InteropServices.OptionalAttribute))] +[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.InteropServices.PreserveSigAttribute))] diff --git a/external/corert/src/System.Private.Interop/src/WinRT/ExceptionHelpers.cs b/external/corert/src/System.Private.Interop/src/WinRT/ExceptionHelpers.cs index c023d5c06d..6f9be707d4 100644 --- a/external/corert/src/System.Private.Interop/src/WinRT/ExceptionHelpers.cs +++ b/external/corert/src/System.Private.Interop/src/WinRT/ExceptionHelpers.cs @@ -185,7 +185,7 @@ namespace System.Runtime.InteropServices /// /// /// - internal static int GetHRForExceptionWithErrorPropogationNoThrow(Exception ex, bool isWinRTScenario) + internal static int GetHRForExceptionWithErrorPropagationNoThrow(Exception ex, bool isWinRTScenario) { int hr = ex.HResult; diff --git a/external/corert/src/System.Private.Jit/src/System.Private.Jit.csproj b/external/corert/src/System.Private.Jit/src/System.Private.Jit.csproj index 270c33469a..662339fa58 100644 --- a/external/corert/src/System.Private.Jit/src/System.Private.Jit.csproj +++ b/external/corert/src/System.Private.Jit/src/System.Private.Jit.csproj @@ -26,7 +26,9 @@ - + + global,System_Private_CoreLib + diff --git a/external/corert/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/FieldInfos/RuntimeFieldInfo.cs b/external/corert/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/FieldInfos/RuntimeFieldInfo.cs index 392f6db9e3..31de164abb 100644 --- a/external/corert/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/FieldInfos/RuntimeFieldInfo.cs +++ b/external/corert/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/FieldInfos/RuntimeFieldInfo.cs @@ -89,7 +89,13 @@ namespace System.Reflection.Runtime.FieldInfos { get { - return this.FieldRuntimeType; + Type fieldType = _lazyFieldType; + if (fieldType == null) + { + _lazyFieldType = fieldType = this.FieldRuntimeType; + } + + return fieldType; } } @@ -292,6 +298,8 @@ namespace System.Reflection.Runtime.FieldInfos private volatile FieldAccessor _lazyFieldAccessor = null; + private volatile Type _lazyFieldType = null; + private String _debugName; } } diff --git a/external/corert/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/Helpers.cs b/external/corert/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/Helpers.cs index 90943008c1..5d851fb097 100644 --- a/external/corert/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/Helpers.cs +++ b/external/corert/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/Helpers.cs @@ -189,8 +189,14 @@ namespace System.Reflection.Runtime.General object instantiatedAttribute = cad.Instantiate(); attributes.Add(instantiatedAttribute); } + + // This is here for desktop compatibility. ICustomAttribute.GetCustomAttributes() normally returns an array of the + // exact attribute type requested except in two cases: when the passed in type is an open type and when + // it is a value type. In these two cases, it returns an array of type Object[]. + bool useObjectArray = actualElementType.ContainsGenericParameters || actualElementType.IsValueType; int count = attributes.Count; - object[] result = (object[])Array.CreateInstance(actualElementType, count); + object[] result = useObjectArray ? new object[count] : (object[])Array.CreateInstance(actualElementType, count); + attributes.CopyTo(result, 0); return result; } diff --git a/external/corert/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/TypeUnifier.cs b/external/corert/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/TypeUnifier.cs index 98d3380200..aa3f0dc82d 100644 --- a/external/corert/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/TypeUnifier.cs +++ b/external/corert/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/TypeUnifier.cs @@ -210,6 +210,14 @@ namespace System.Reflection.Runtime.TypeInfos if (elementTypeHandle.IsNull()) return default(RuntimeTypeHandle); + // The check is here on purpose - one of the implementations of IsByRefLike contains a custom attribute + // search and those are very expensive from size on disk footprint perspective. We purposefully + // place this call in a path that won't be part of the executable image unless more advanced reflection services + // are also needed ("pay for play"). We really don't want a typeof() to push the app into requiring the full reflection + // stack to be compiled into the final executable. + if (elementType.IsByRefLike) + throw new TypeLoadException(SR.Format(SR.ArgumentException_InvalidArrayElementType, elementType)); + RuntimeTypeHandle typeHandle; if (!multiDim) { @@ -272,7 +280,7 @@ namespace System.Reflection.Runtime.TypeInfos { Debug.Assert(multiDim || rank == 1); - if (elementType.IsByRef || elementType.IsByRefLike) + if (elementType.IsByRef) throw new TypeLoadException(SR.Format(SR.ArgumentException_InvalidArrayElementType, elementType)); // We only permit creating parameterized types if the pay-for-play policy specifically allows them *or* if the result diff --git a/external/corert/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/RuntimePropertyInfo.cs b/external/corert/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/RuntimePropertyInfo.cs index 7691902beb..b8623f72c4 100644 --- a/external/corert/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/RuntimePropertyInfo.cs +++ b/external/corert/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/RuntimePropertyInfo.cs @@ -187,8 +187,14 @@ namespace System.Reflection.Runtime.PropertyInfos ReflectionTrace.PropertyInfo_PropertyType(this); #endif - TypeContext typeContext = ContextTypeInfo.TypeContext; - return PropertyTypeHandle.Resolve(typeContext); + Type propertyType = _lazyPropertyType; + if (propertyType == null) + { + TypeContext typeContext = ContextTypeInfo.TypeContext; + _lazyPropertyType = propertyType = PropertyTypeHandle.Resolve(typeContext); + } + + return propertyType; } } @@ -402,6 +408,8 @@ namespace System.Reflection.Runtime.PropertyInfos private volatile ParameterInfo[] _lazyIndexParameters; + private volatile Type _lazyPropertyType; + private String _debugName; } } diff --git a/external/corert/src/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/ExecutionEnvironmentImplementation.MappingTables.cs b/external/corert/src/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/ExecutionEnvironmentImplementation.MappingTables.cs index cd873da358..b583053d4d 100644 --- a/external/corert/src/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/ExecutionEnvironmentImplementation.MappingTables.cs +++ b/external/corert/src/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/ExecutionEnvironmentImplementation.MappingTables.cs @@ -1217,7 +1217,7 @@ namespace Internal.Reflection.Execution NativeParser entryParser = new NativeParser(invokeMapReader, parserOffset); - declaringTypeHandle = externalReferences.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned()); + RuntimeTypeHandle entryTypeHandle = externalReferences.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned()); // Hash table names / sigs are indirected through to the native layout info MethodNameAndSignature nameAndSignature; @@ -1236,8 +1236,9 @@ namespace Internal.Reflection.Execution if (functionPointer != canonOriginalLdFtnResult) return false; - if (TypeLoaderEnvironment.Instance.TryGetMetadataForTypeMethodNameAndSignature(declaringTypeHandle, nameAndSignature, out methodHandle)) + if (TypeLoaderEnvironment.Instance.TryGetMetadataForTypeMethodNameAndSignature(entryTypeHandle, nameAndSignature, out methodHandle)) { + declaringTypeHandle = entryTypeHandle; return true; } diff --git a/external/corert/src/System.Private.StackTraceMetadata/src/Internal/StackTraceMetadata/MethodNameFormatter.cs b/external/corert/src/System.Private.StackTraceMetadata/src/Internal/StackTraceMetadata/MethodNameFormatter.cs index 2d3bb5a0a9..feb7dccf73 100644 --- a/external/corert/src/System.Private.StackTraceMetadata/src/Internal/StackTraceMetadata/MethodNameFormatter.cs +++ b/external/corert/src/System.Private.StackTraceMetadata/src/Internal/StackTraceMetadata/MethodNameFormatter.cs @@ -345,9 +345,9 @@ namespace Internal.StackTraceMetadata /// When set to true, include namespace information private void EmitTypeInstantiationName(TypeInstantiationSignatureHandle typeInstHandle, bool namespaceQualified) { + // Stack trace metadata ignores the instantiation arguments of the type in the CLR TypeInstantiationSignature typeInst = _metadataReader.GetTypeInstantiationSignature(typeInstHandle); EmitTypeName(typeInst.GenericType, namespaceQualified); - EmitGenericArguments(typeInst.GenericTypeArguments); } /// diff --git a/external/corert/src/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.FieldAccess.cs b/external/corert/src/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.FieldAccess.cs index 2cd5b9156a..514cf8958a 100644 --- a/external/corert/src/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.FieldAccess.cs +++ b/external/corert/src/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.FieldAccess.cs @@ -110,7 +110,7 @@ namespace Internal.Runtime.TypeLoader } /// - /// Try to look up field acccess info for given canon in metadata blobs for all available modules. + /// Try to look up field access info for given canon in metadata blobs for all available modules. /// /// Metadata reader for the declaring type /// Declaring type for the method diff --git a/external/corert/src/System.Private.TypeLoader/src/Internal/TypeSystem/InstantiatedMethod.Runtime.cs b/external/corert/src/System.Private.TypeLoader/src/Internal/TypeSystem/InstantiatedMethod.Runtime.cs index 79baee7c95..a49f6ad782 100644 --- a/external/corert/src/System.Private.TypeLoader/src/Internal/TypeSystem/InstantiatedMethod.Runtime.cs +++ b/external/corert/src/System.Private.TypeLoader/src/Internal/TypeSystem/InstantiatedMethod.Runtime.cs @@ -63,5 +63,16 @@ namespace Internal.TypeSystem return _methodDef.UnboxingStub; } } + +#if DEBUG + public override string ToString() + { + var sb = new System.Text.StringBuilder(_methodDef.ToString()); + sb.Append('<'); + sb.Append(_instantiation.ToString()); + sb.Append('>'); + return sb.ToString(); + } +#endif } } diff --git a/external/corert/src/System.Private.TypeLoader/src/Internal/TypeSystem/MethodForInstantiatedType.Runtime.cs b/external/corert/src/System.Private.TypeLoader/src/Internal/TypeSystem/MethodForInstantiatedType.Runtime.cs index 21f887facd..d70c8a4a92 100644 --- a/external/corert/src/System.Private.TypeLoader/src/Internal/TypeSystem/MethodForInstantiatedType.Runtime.cs +++ b/external/corert/src/System.Private.TypeLoader/src/Internal/TypeSystem/MethodForInstantiatedType.Runtime.cs @@ -17,5 +17,12 @@ namespace Internal.TypeSystem return _typicalMethodDef.NameAndSignature; } } + +#if DEBUG + public override string ToString() + { + return OwningType.ToString() + "." + Name; + } +#endif } } diff --git a/external/corert/src/System.Private.TypeLoader/src/Internal/TypeSystem/RuntimeNoMetadataType.cs b/external/corert/src/System.Private.TypeLoader/src/Internal/TypeSystem/RuntimeNoMetadataType.cs index 15bcb28bb0..d9c688be6b 100644 --- a/external/corert/src/System.Private.TypeLoader/src/Internal/TypeSystem/RuntimeNoMetadataType.cs +++ b/external/corert/src/System.Private.TypeLoader/src/Internal/TypeSystem/RuntimeNoMetadataType.cs @@ -94,7 +94,6 @@ namespace Internal.TypeSystem.NoMetadata } else { - Debug.Assert(this.HasNativeLayout); // Parsing of the base type has not yet happened. Perform that part of native layout parsing // just-in-time TypeBuilderState state = GetOrCreateTypeBuilderState(); diff --git a/external/corert/src/System.Private.TypeLoader/src/System.Private.TypeLoader.csproj b/external/corert/src/System.Private.TypeLoader/src/System.Private.TypeLoader.csproj index 06eb54493d..1ba5ae8612 100644 --- a/external/corert/src/System.Private.TypeLoader/src/System.Private.TypeLoader.csproj +++ b/external/corert/src/System.Private.TypeLoader/src/System.Private.TypeLoader.csproj @@ -17,6 +17,10 @@ Library true TYPE_LOADER_IMPLEMENTATION;$(DefineConstants) + TYPE_LOADER_TRACE;$(DefineConstants) + GVM_RESOLUTION_TRACE;$(DefineConstants) + CCCONVERTER_TRACE;$(DefineConstants) + GENERICS_FORCE_USG;$(DefineConstants) true @@ -33,13 +37,7 @@ SUPPORT_JIT;$(DefineConstants) - TYPE_LOADER_IMPLEMENTATION;$(DefineConstants) FEATURE_INTERPRETER;$(DefineConstants) - CCCONVERTER_TRACE;$(DefineConstants) - TYPE_LOADER_TRACE;$(DefineConstants) - GENERICS_FORCE_USG;$(DefineConstants) - GVM_RESOLUTION_TRACE;$(DefineConstants) - TYPE_SYSTEM_SINGLE_THREADED;$(DefineConstants) @@ -534,9 +532,6 @@ Internal\TypeSystem\TypeDesc.ToString.cs - - Internal\TypeSystem\MethodDesc.ToString.cs - Internal\TypeSystem\FieldDesc.ToString.cs diff --git a/external/corert/src/Test.CoreLib/src/Test.CoreLib.csproj b/external/corert/src/Test.CoreLib/src/Test.CoreLib.csproj index a7588cad92..685a4fd63a 100644 --- a/external/corert/src/Test.CoreLib/src/Test.CoreLib.csproj +++ b/external/corert/src/Test.CoreLib/src/Test.CoreLib.csproj @@ -84,7 +84,7 @@ - + diff --git a/external/corert/src/dirs.proj b/external/corert/src/dirs.proj index 2356eef0de..bc9ce5cad2 100644 --- a/external/corert/src/dirs.proj +++ b/external/corert/src/dirs.proj @@ -6,17 +6,15 @@ - - - - - + + + diff --git a/external/corert/tests/CoreCLR.issues.targets b/external/corert/tests/CoreCLR.issues.targets index cababdc896..d7b9ad4860 100644 --- a/external/corert/tests/CoreCLR.issues.targets +++ b/external/corert/tests/CoreCLR.issues.targets @@ -2,17 +2,6 @@ xmlns="http://schemas.microsoft.com/developer/msbuild/2003" > - - - - - - - - - - - @@ -51,6 +40,13 @@ + + + + + + + @@ -224,6 +220,9 @@ + + + @@ -418,10 +417,8 @@ - - - - + + @@ -609,6 +606,328 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -635,6 +954,7 @@ + @@ -652,8 +972,8 @@ - - + + diff --git a/external/corert/tests/CoreCLR/build-and-run-test.cmd b/external/corert/tests/CoreCLR/build-and-run-test.cmd index 9b0feacc5a..4e8b7764b8 100644 --- a/external/corert/tests/CoreCLR/build-and-run-test.cmd +++ b/external/corert/tests/CoreCLR/build-and-run-test.cmd @@ -25,7 +25,7 @@ copy /Y %~dp0\Test.csproj %TestFolder% :: so override if we're doing a 64-bit test run :: if "%CoreRT_BuildArch%" == "x64" ( - call "%VS140COMNTOOLS%\..\..\VC\bin\amd64\vcvars64.bat" + call "%VS150COMNTOOLS%\..\..\VC\Auxiliary\Build\vcvarsall.bat" x64 ) echo msbuild /ConsoleLoggerParameters:ForceNoAlign "/p:IlcPath=%CoreRT_ToolchainDir%" "/p:Configuration=%CoreRT_BuildType%" "/p:RepoLocalBuild=true" "/p:FrameworkLibPath=%~dp0..\..\bin\%CoreRT_BuildOS%.%CoreRT_BuildArch%.%CoreRT_BuildType%\lib" "/p:FrameworkObjPath=%~dp0..\..\bin\obj\%CoreRT_BuildOS%.%CoreRT_BuildArch%.%CoreRT_BuildType%\Framework" /p:DisableFrameworkLibGeneration=true %TestFolder%\Test.csproj diff --git a/external/corert/tests/CoreCLRTestsURL.txt b/external/corert/tests/CoreCLRTestsURL.txt index 388aabee40..c5fd5d3cd8 100644 --- a/external/corert/tests/CoreCLRTestsURL.txt +++ b/external/corert/tests/CoreCLRTestsURL.txt @@ -1 +1 @@ -https://ci.dot.net/job/dotnet_coreclr/job/master/job/debug_windows_nt_prtest/4/artifact/bin/tests/tests.zip \ No newline at end of file +https://ci.dot.net/job/dotnet_coreclr/job/master/job/x64_checked_windows_nt_innerloop_prtest/839/artifact/bin/tests/tests.zip \ No newline at end of file diff --git a/external/corert/tests/Top200.CoreCLR.issues.targets b/external/corert/tests/Top200.CoreCLR.issues.targets index 8011498494..a2b5551c58 100644 --- a/external/corert/tests/Top200.CoreCLR.issues.targets +++ b/external/corert/tests/Top200.CoreCLR.issues.targets @@ -7,211 +7,132 @@ - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + - - - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + diff --git a/external/corert/tests/Top200.unix.txt b/external/corert/tests/Top200.unix.txt index a435e5db77..22f16baf91 100644 --- a/external/corert/tests/Top200.unix.txt +++ b/external/corert/tests/Top200.unix.txt @@ -205,7 +205,6 @@ Interop/PrimitiveMarshalling/EnumMarshalling/EnumTest/EnumTest.sh Interop/FuncPtrAsDelegateParam/FuncPtrAsDelegateParam/FuncPtrAsDelegateParam.sh Interop/MarshalAPI/FunctionPointer/FunctionPtrTest/FunctionPtrTest.sh Interop/MarshalAPI/GetObjectsForNativeVariants/GetObjectsForNativeVariants/GetObjectsForNativeVariants.sh -Interop/StringMarshalling/LPSTR/LPSTRTest/LPSTRTest.sh Interop/ArrayMarshalling/BoolArray/MarshalBoolArrayTest/MarshalBoolArrayTest.sh Interop/PrimitiveMarshalling/UIntPtr/PInvokeUIntPtrTest/PInvokeUIntPtrTest.sh Interop/MarshalAPI/ReadWrite/ReadWriteByte/ReadWriteByte.sh diff --git a/external/corert/tests/runtest.sh b/external/corert/tests/runtest.sh index 0144371de4..51104cf812 100755 --- a/external/corert/tests/runtest.sh +++ b/external/corert/tests/runtest.sh @@ -41,6 +41,9 @@ run_test_dir() if [ "${__mode}" = "Cpp" ]; then __extra_args="${__extra_args} /p:NativeCodeGen=cpp" fi + if [ "${__mode}" = "Wasm" ]; then + __extra_args="${__extra_args} /p:NativeCodeGen=wasm" + fi if [ -n "${__extra_cxxflags}" ]; then __extra_cxxflags="/p:AdditionalCppCompilerFlags=\"${__extra_cxxflags}\"" fi @@ -55,8 +58,8 @@ run_test_dir() local __msbuild_dir=${CoreRT_TestRoot}/../Tools - echo ${__msbuild_dir}/dotnetcli/dotnet ${__msbuild_dir}/MSBuild.dll /ds /m /p:IlcPath=${CoreRT_ToolchainDir} /p:Configuration=${CoreRT_BuildType} /p:Platform=${CoreRT_BuildArch} /p:RepoLocalBuild=true "/p:FrameworkLibPath=${CoreRT_TestRoot}/../bin/${CoreRT_BuildOS}.${CoreRT_BuildArch}.${CoreRT_BuildType}/lib" "/p:FrameworkObjPath=${CoreRT_TestRoot}/../bin/obj/${CoreRT_BuildOS}.${CoreRT_BuildArch}.${CoreRT_BuildType}/Framework" ${__extra_args} "${__extra_cxxflags}" "${__extra_linkflags}" ${__dir_path}/${__filename}.csproj - ${__msbuild_dir}/dotnetcli/dotnet ${__msbuild_dir}/MSBuild.dll /ds /m /p:IlcPath=${CoreRT_ToolchainDir} /p:Configuration=${CoreRT_BuildType} /p:Platform=${CoreRT_BuildArch} /p:OSGroup=${CoreRT_BuildOS} /p:RepoLocalBuild=true "/p:FrameworkLibPath=${CoreRT_TestRoot}/../bin/${CoreRT_BuildOS}.${CoreRT_BuildArch}.${CoreRT_BuildType}/lib" "/p:FrameworkObjPath=${CoreRT_TestRoot}/../bin/obj/${CoreRT_BuildOS}.${CoreRT_BuildArch}.${CoreRT_BuildType}/Framework" ${__extra_args} "${__extra_cxxflags}" "${__extra_linkflags}" ${__dir_path}/${__filename}.csproj + echo ${__msbuild_dir}/msbuild.sh /ds /m /p:IlcPath=${CoreRT_ToolchainDir} /p:Configuration=${CoreRT_BuildType} /p:Platform=${CoreRT_BuildArch} /p:RepoLocalBuild=true "/p:FrameworkLibPath=${CoreRT_TestRoot}/../bin/${CoreRT_BuildOS}.${CoreRT_BuildArch}.${CoreRT_BuildType}/lib" "/p:FrameworkObjPath=${CoreRT_TestRoot}/../bin/obj/${CoreRT_BuildOS}.${CoreRT_BuildArch}.${CoreRT_BuildType}/Framework" ${__extra_args} ${__extra_cxxflags} ${__extra_linkflags} ${__dir_path}/${__filename}.csproj + ${__msbuild_dir}/msbuild.sh /ds /m /p:IlcPath=${CoreRT_ToolchainDir} /p:Configuration=${CoreRT_BuildType} /p:Platform=${CoreRT_BuildArch} /p:OSGroup=${CoreRT_BuildOS} /p:RepoLocalBuild=true "/p:FrameworkLibPath=${CoreRT_TestRoot}/../bin/${CoreRT_BuildOS}.${CoreRT_BuildArch}.${CoreRT_BuildType}/lib" "/p:FrameworkObjPath=${CoreRT_TestRoot}/../bin/obj/${CoreRT_BuildOS}.${CoreRT_BuildArch}.${CoreRT_BuildType}/Framework" ${__extra_args} ${__extra_cxxflags} ${__extra_linkflags} ${__dir_path}/${__filename}.csproj local __exitcode=$? @@ -176,6 +179,12 @@ while [ "$1" != "" ]; do usage exit 1 ;; + wasm) + CoreRT_BuildArch=wasm + CoreRT_BuildOS=WebAssembly + CoreRT_TestCompileMode=wasm + CoreRT_TestRun=false + ;; x86) CoreRT_BuildArch=x86 ;; @@ -319,7 +328,8 @@ __CppTotalTests=0 __CppPassedTests=0 __JitTotalTests=0 __JitPassedTests=0 - +__WasmTotalTests=0 +__WasmPassedTests=0 if [ ! -d ${__CoreRTTestBinDir} ]; then mkdir -p ${__CoreRTTestBinDir} @@ -327,23 +337,31 @@ fi echo > ${__CoreRTTestBinDir}/testResults.tmp __BuildOsLowcase=$(echo "${CoreRT_BuildOS}" | tr '[:upper:]' '[:lower:]') -__TestSearchPath=src/Simple/${CoreRT_TestName} +__TestSearchPath=${CoreRT_TestRoot}/src/Simple/${CoreRT_TestName} for csproj in $(find ${__TestSearchPath} -name "*.csproj") do - if [ ! -e `dirname ${csproj}`/no_unix ]; then - if [ "${CoreRT_TestCompileMode}" != "cpp" ]; then + if [ -e `dirname ${csproj}`/no_unix ]; then continue; fi + if [ -e `dirname ${csproj}`/no_linux ] && [ "${CoreRT_HostOS}" != "OSX" ]; then continue; fi + + if [ "${CoreRT_TestCompileMode}" = "ryujit" ] || [ "${CoreRT_TestCompileMode}" = "" ]; then + if [ ! -e `dirname ${csproj}`/no_ryujit ]; then run_test_dir ${csproj} "Jit" fi + fi + if [ "${CoreRT_TestCompileMode}" = "cpp" ] || [ "${CoreRT_TestCompileMode}" = "" ]; then if [ ! -e `dirname ${csproj}`/no_cpp ]; then - if [ "${CoreRT_TestCompileMode}" != "ryujit" ]; then - run_test_dir ${csproj} "Cpp" "$CoreRT_ExtraCXXFlags" "$CoreRT_ExtraLinkFlags" - fi + run_test_dir ${csproj} "Cpp" "$CoreRT_ExtraCXXFlags" "$CoreRT_ExtraLinkFlags" + fi + fi + if [ "${CoreRT_TestCompileMode}" = "wasm" ]; then + if [ -e `dirname ${csproj}`/wasm ]; then + run_test_dir ${csproj} "Wasm" fi fi done -__TotalTests=$((${__JitTotalTests} + ${__CppTotalTests})) -__PassedTests=$((${__JitPassedTests} + ${__CppPassedTests})) +__TotalTests=$((${__JitTotalTests} + ${__CppTotalTests} + ${__WasmTotalTests})) +__PassedTests=$((${__JitPassedTests} + ${__CppPassedTests} + ${__WasmPassedTests})) __FailedTests=$((${__TotalTests} - ${__PassedTests})) if [ "$CoreRT_MultiFileConfiguration" = "MultiModule" ]; then @@ -366,19 +384,26 @@ echo "" >> ${__TestResultsLog} echo "JIT - TOTAL: ${__JitTotalTests} PASSED: ${__JitPassedTests}" echo "CPP - TOTAL: ${__CppTotalTests} PASSED: ${__CppPassedTests}" +echo "WASM - TOTAL: ${__WasmTotalTests} PASSED: ${__WasmPassedTests}" -if [ ${__JitTotalTests} == 0 ]; then +if [ ${__JitTotalTests} == 0 ] && [ "${CoreRT_TestCompileMode}" != "wasm" ]; then exit 1 fi - -if [ ${__CppTotalTests} == 0 ]; then +if [ ${__CppTotalTests} == 0 ] && [ "${CoreRT_TestCompileMode}" != "wasm" ]; then exit 1 fi +if [ ${__WasmTotalTests} == 0 ] && [ "${CoreRT_TestCompileMode}" = "wasm" ]; then + exit 1 +fi + if [ ${__JitTotalTests} -gt ${__JitPassedTests} ]; then exit 1 fi if [ ${__CppTotalTests} -gt ${__CppPassedTests} ]; then exit 1 fi +if [ ${__WasmTotalTests} -gt ${__WasmPassedTests} ]; then + exit 1 +fi exit 0 diff --git a/external/corert/tests/src/Simple/HelloWasm/HelloWasm.csproj b/external/corert/tests/src/Simple/HelloWasm/HelloWasm.csproj index b767a5dbd5..f070f287a0 100644 --- a/external/corert/tests/src/Simple/HelloWasm/HelloWasm.csproj +++ b/external/corert/tests/src/Simple/HelloWasm/HelloWasm.csproj @@ -2,9 +2,13 @@ - - + + + + PLATFORM_WINDOWS;$(DefineConstants) + + diff --git a/external/corert/tests/src/Simple/HelloWasm/Program.cs b/external/corert/tests/src/Simple/HelloWasm/Program.cs index 25886330ca..75864c2e03 100644 --- a/external/corert/tests/src/Simple/HelloWasm/Program.cs +++ b/external/corert/tests/src/Simple/HelloWasm/Program.cs @@ -4,7 +4,9 @@ using System; using System.Runtime.InteropServices; +#if PLATFORM_WINDOWS using CpObj; +#endif internal static class Program { @@ -62,6 +64,18 @@ internal static class Program var boxedStruct = (object)new BoxStubTest { Value = "Boxed Stub Test: Ok." }; PrintLine(boxedStruct.ToString()); + int subResult = tempInt - 1; + if (subResult == 8) + { + PrintLine("Subtraction Test: Ok."); + } + + int divResult = tempInt / 3; + if (divResult == 3) + { + PrintLine("Division Test: Ok."); + } + var not = Not(0xFFFFFFFF) == 0x00000000; if (not) { @@ -110,6 +124,7 @@ internal static class Program PrintLine("SwitchOpDefault test: Ok."); } +#if PLATFORM_WINDOWS var cpObjTestA = new TestValue { Field = 1234 }; var cpObjTestB = new TestValue { Field = 5678 }; CpObjTest.CpObj(ref cpObjTestB, ref cpObjTestA); @@ -117,6 +132,98 @@ internal static class Program { PrintLine("CpObj test: Ok."); } +#endif + + Func staticDelegate = StaticDelegateTarget; + if(staticDelegate() == 7) + { + PrintLine("Static delegate test: Ok."); + } + + tempObj.TestInt = 8; + Func instanceDelegate = tempObj.InstanceDelegateTarget; + if(instanceDelegate() == 8) + { + PrintLine("Instance delegate test: Ok."); + } + + Action virtualDelegate = tempObj.VirtualDelegateTarget; + virtualDelegate(); + + var arrayTest = new BoxStubTest[] { new BoxStubTest { Value = "Hello" }, new BoxStubTest { Value = "Array" }, new BoxStubTest { Value = "Test" } }; + foreach(var element in arrayTest) + PrintLine(element.Value); + + arrayTest[1].Value = "Array load/store test: Ok."; + PrintLine(arrayTest[1].Value); + + var largeArrayTest = new long[] { Int64.MaxValue, 0, Int64.MinValue, 0 }; + if(largeArrayTest[0] == Int64.MaxValue && + largeArrayTest[1] == 0 && + largeArrayTest[2] == Int64.MinValue && + largeArrayTest[3] == 0) + { + PrintLine("Large array load/store test: Ok."); + } + + var smallArrayTest = new long[] { Int16.MaxValue, 0, Int16.MinValue, 0 }; + if(smallArrayTest[0] == Int16.MaxValue && + smallArrayTest[1] == 0 && + smallArrayTest[2] == Int16.MinValue && + smallArrayTest[3] == 0) + { + PrintLine("Small array load/store test: Ok."); + } + + IntPtr returnedIntPtr = NewobjValueType(); + if (returnedIntPtr.ToInt32() == 3) + { + PrintLine("Newobj value type test: Ok."); + } + + StackallocTest(); + + IntToStringTest(); + + CastingTestClass castingTest = new DerivedCastingTestClass1(); + if (((DerivedCastingTestClass1)castingTest).GetValue() == 1 && !(castingTest is DerivedCastingTestClass2)) + { + PrintLine("Type casting with isinst & castclass to class test: Ok."); + } + + // Instead of checking the result of `GetValue`, we use null check by now until interface dispatch is implemented. + if ((ICastingTest1)castingTest != null && !(castingTest is ICastingTest2)) + { + PrintLine("Type casting with isinst & castclass to interface test: Ok."); + } + + object arrayCastingTest = new BoxStubTest[] { new BoxStubTest { Value = "Array" }, new BoxStubTest { Value = "Cast" }, new BoxStubTest { Value = "Test" } }; + PrintLine(((BoxStubTest[])arrayCastingTest)[0].Value); + PrintLine(((BoxStubTest[])arrayCastingTest)[1].Value); + PrintLine(((BoxStubTest[])arrayCastingTest)[2].Value); + if (!(arrayCastingTest is CastingTestClass[])) + { + PrintLine("Type casting with isinst & castclass to array test: Ok."); + } + + ldindTest(); + + System.Diagnostics.Debugger.Break(); + + var testRuntimeHelpersInitArray = new long[] {1, 2, 3}; + if(testRuntimeHelpersInitArray[0] == 1 && + testRuntimeHelpersInitArray[1] == 2 && + testRuntimeHelpersInitArray[2] == 3) + { + PrintLine("Runtime.Helpers array initialization test: Ok."); + } + + PrintLine("Done"); + } + + private static int StaticDelegateTarget() + { + return 7; } private static unsafe void PrintString(string s) @@ -186,6 +293,59 @@ internal static class Program } } + private static IntPtr NewobjValueType() + { + return new IntPtr(3); + } + + private unsafe static void StackallocTest() + { + int* intSpan = stackalloc int[2]; + intSpan[0] = 3; + intSpan[1] = 7; + + if (intSpan[0] == 3 && intSpan[1] == 7) + { + PrintLine("Stackalloc test: Ok."); + } + } + + private static void IntToStringTest() + { + PrintLine("Int to String Test: Ok if next line says 42."); + string intString = 42.ToString(); + PrintLine(intString); + } + + private unsafe static void ldindTest() + { + var ldindTarget = new TwoByteStr { first = byte.MaxValue, second = byte.MinValue }; + var ldindField = &ldindTarget.first; + if((*ldindField) == byte.MaxValue) + { + ldindTarget.second = byte.MaxValue; + *ldindField = byte.MinValue; + //ensure there isnt any overwrite of nearby fields + if(ldindTarget.first == byte.MinValue && ldindTarget.second == byte.MaxValue) + { + PrintLine("ldind test: Ok."); + } + else if(ldindTarget.first != byte.MinValue) + { + PrintLine("ldind test: Failed didnt update target."); + } + else + { + PrintLine("ldind test: Failed overwrote data"); + } + } + else + { + uint ldindFieldValue = *ldindField; + PrintLine("ldind test: Failed." + ldindFieldValue.ToString()); + } + } + [DllImport("*")] private static unsafe extern int printf(byte* str, byte* unused); } @@ -203,11 +363,19 @@ public struct BoxStubTest { return Value; } + + public string GetValue() + { + Program.PrintLine("BoxStubTest.GetValue called"); + Program.PrintLine(Value); + return Value; + } } public class TestClass { - public string TestString {get; set;} + public string TestString { get; set; } + public int TestInt { get; set; } public TestClass(int number) { @@ -230,6 +398,16 @@ public class TestClass { Program.PrintLine("Virtual Slot Test 2: Ok"); } + + public int InstanceDelegateTarget() + { + return TestInt; + } + + public virtual void VirtualDelegateTarget() + { + Program.PrintLine("Virtual delegate incorrectly dispatched to base."); + } } public class TestDerivedClass : TestClass @@ -248,5 +426,34 @@ public class TestDerivedClass : TestClass { throw new Exception(); } + + public override void VirtualDelegateTarget() + { + Program.PrintLine("Virtual Delegate Test: Ok"); + } } +public interface ICastingTest1 +{ + int GetValue(); +} + +public interface ICastingTest2 +{ + int GetValue(); +} + +public abstract class CastingTestClass +{ + public abstract int GetValue(); +} + +public class DerivedCastingTestClass1 : CastingTestClass, ICastingTest1 +{ + public override int GetValue() => 1; +} + +public class DerivedCastingTestClass2 : CastingTestClass, ICastingTest2 +{ + public override int GetValue() => 2; +} diff --git a/external/corert/tests/src/Simple/HelloWasm/no_unix b/external/corert/tests/src/Simple/HelloWasm/no_unix deleted file mode 100644 index e6c22996cd..0000000000 --- a/external/corert/tests/src/Simple/HelloWasm/no_unix +++ /dev/null @@ -1 +0,0 @@ -Doesn't work on OSX. \ No newline at end of file diff --git a/external/corert/tests/src/Simple/PInvoke/PInvoke.csproj b/external/corert/tests/src/Simple/PInvoke/PInvoke.csproj index 05f571f84e..d51b766760 100644 --- a/external/corert/tests/src/Simple/PInvoke/PInvoke.csproj +++ b/external/corert/tests/src/Simple/PInvoke/PInvoke.csproj @@ -19,7 +19,7 @@ - + diff --git a/external/corert/tests/src/Simple/Reflection/Reflection.cs b/external/corert/tests/src/Simple/Reflection/Reflection.cs index 4454e9415f..322650a2c1 100644 --- a/external/corert/tests/src/Simple/Reflection/Reflection.cs +++ b/external/corert/tests/src/Simple/Reflection/Reflection.cs @@ -423,6 +423,21 @@ internal class ReflectionTest } } + class Gen { } + + interface IFoo + { + string Frob(); + } + + class Foo : IFoo> + { + public string Frob() + { + return typeof(T).ToString(); + } + } + public static void Run() { Console.WriteLine(nameof(TestInterfaceMethod)); @@ -431,11 +446,16 @@ internal class ReflectionTest if (string.Empty.Length > 0) { ((IFoo)new Foo()).Frob(1); + ((IFoo)new Foo()).Frob(); } object result = InvokeTestMethod(typeof(IFoo), "Frob", new Foo(), 42); if ((string)result != "42") throw new Exception(); + + result = InvokeTestMethod(typeof(IFoo), "Frob", new Foo()); + if ((string)result != "System.String") + throw new Exception(); } } diff --git a/external/corert/tests/testenv.sh b/external/corert/tests/testenv.sh index 69a636bcae..f2b78e113c 100755 --- a/external/corert/tests/testenv.sh +++ b/external/corert/tests/testenv.sh @@ -14,6 +14,9 @@ for i in "$@" usage exit 1 ;; + wasm) + CoreRT_BuildArch=wasm + ;; x86) CoreRT_BuildArch=x86 ;; @@ -47,7 +50,7 @@ for i in "$@" done if [ -z ${CoreRT_BuildArch} ]; then - echo "Set CoreRT_BuildArch to x86/x64/arm/arm64" + echo "Set CoreRT_BuildArch to x86/x64/arm/arm64/wasm" exit -1 fi @@ -56,31 +59,39 @@ if [ -z ${CoreRT_BuildType} ]; then exit -1 fi + # Use uname to determine what the OS is. -OSName=$(uname -s) +export OSName=$(uname -s) case $OSName in - Darwin) - CoreRT_BuildOS=OSX - ;; + Darwin) + export CoreRT_HostOS=OSX + ;; - FreeBSD) - CoreRT_BuildOS=FreeBSD - ;; + FreeBSD) + export CoreRT_HostOS=FreeBSD + ;; - Linux) - CoreRT_BuildOS=Linux - ;; + Linux) + export CoreRT_HostOS=Linux + ;; - NetBSD) - CoreRT_BuildOS=NetBSD - ;; + NetBSD) + export CoreRT_HostOS=NetBSD + ;; - *) - echo "Unsupported OS $OSName detected, configuring as if for Linux" - CoreRT_BuildOS=Linux - ;; + *) + echo "Unsupported OS $OSName detected, configuring as if for Linux" + export CoreRT_HostOS=Linux + ;; esac +export CoreRT_BuildOS=${CoreRT_HostOS} + +# Overwrite __BuildOS with WebAssembly if wasm is target build arch, but keep the CoreRT_HostOS to match the Host OS +if [ "$__BuildArch" == "wasm" ]; then + export CoreRT_BuildOS=WebAssembly +fi + export CoreRT_BuildArch export CoreRT_BuildType export CoreRT_BuildOS @@ -88,3 +99,13 @@ export CoreRT_BuildOS __ScriptDir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) export CoreRT_ToolchainDir=${__ScriptDir}/../bin/${CoreRT_BuildOS}.${CoreRT_BuildArch}.${CoreRT_BuildType} + +# CI_SPECIFIC - On CI machines, $HOME may not be set. In such a case, create a subfolder and set the variable to set. +# This is needed by CLI to function. +if [ -z "$HOME" ]; then + if [ ! -d "$__ScriptDir/../temp_home" ]; then + mkdir "$__ScriptDir/../temp_home" + fi + export HOME=$__ScriptDir/../temp_home + echo "HOME not defined; setting it to $HOME" +fi diff --git a/external/ikdasm/CABlob.cs b/external/ikdasm/CABlob.cs index 108592f7e0..2711d6a3d6 100644 --- a/external/ikdasm/CABlob.cs +++ b/external/ikdasm/CABlob.cs @@ -99,7 +99,7 @@ namespace Ildasm } else if (typerefs.Contains(type)) { - sb.Append('[').Append(QuoteIdentifier(referencedAssemblies[type.Assembly])).Append(']'); + sb.Append('[').Append(QuoteIdentifier(FindReferencedAssembly(type.Assembly))).Append(']'); AppendTypeName(sb, type); } else diff --git a/external/ikdasm/Disassembler.cs.REMOVED.git-id b/external/ikdasm/Disassembler.cs.REMOVED.git-id index 5e6c8cb5c9..bdc5a8f79f 100644 --- a/external/ikdasm/Disassembler.cs.REMOVED.git-id +++ b/external/ikdasm/Disassembler.cs.REMOVED.git-id @@ -1 +1 @@ -b6f99400bfe7a0ff94e67097c4d5538edc782bd1 \ No newline at end of file +78ba95ec89a68e6196dc126e4be4b998303d98d0 \ No newline at end of file diff --git a/external/linker/README.md b/external/linker/README.md index be887510ef..d7c34548c7 100644 --- a/external/linker/README.md +++ b/external/linker/README.md @@ -6,6 +6,8 @@ programs might require to run as opposed to the full libraries. It is used by the various Xamarin products to extract only the bits of code that are needed to run an application on Android, iOS and other platforms. +It can also be used in the form of [ILLink.Tasks](corebuild/README.md) to reduce the size of .NET Core apps. + # [Analyzer](analyzer/README.md) The analyzer is a tool to analyze dependencies which were recorded during linker processing and led linker to mark an item to keep it in the resulting linked assembly. diff --git a/external/linker/corebuild/README.md b/external/linker/corebuild/README.md new file mode 100644 index 0000000000..5f815ecdb8 --- /dev/null +++ b/external/linker/corebuild/README.md @@ -0,0 +1,186 @@ +# ILLink.Tasks + +ILLink.Tasks is a package containing MSBuild tasks and targets that +will run the linker to run during publish of a .NET Core app. + +ILLink.Tasks provides an MSBuild task called ILLink that makes it easy +to run the linker from an MSBuild project file: + +```xml + +``` + +For a description of the options that this task supports, see the +comments in [LinkTask.cs](integration/ILLink.Tasks/LinkTask.cs). + + +In addition, ILLink.Tasks contains MSBuild logic that makes the linker +run automatically during `dotnet publish` for .NET Core apps. This +will: + +- Determine the assemblies and options to pass to illink. +- Remove unused native files from the publish output. +- Run crossgen on the linked assemblies to improve startup performance. + +The full set of options is described below. + +## Building + +``` +linker> ./corebuild/dotnet.{sh/ps1} restore ./corebuild/integration/linker.sln +linker> ./corebuild/dotnet.{sh/ps1} pack ./corebuild/integration/ILLink.Tasks/ILLink.Tasks.csproj +``` + +The output package will be placed in +`corebuild/integration/bin/nupkgs`. If you are building on unix, you +will need to adjust +[ILLink.Tasks.nuspec](integration/ILLink.Tasks/ILLink.Tasks.nuspec). Replace +the dll file includes with the following: + +`` + +## Using ILLink.Tasks + +Add a package reference to the linker. Ensure that either the +[dotnet-core](https://dotnet.myget.org/gallery/dotnet-core) myget feed +or the path to the locally-built linker package path exists in the +project's nuget.config. If using myget, you probably want to ensure +that you're using the latest version available at +https://dotnet.myget.org/feed/dotnet-core/package/nuget/ILLink.Tasks. + +After adding the package, linking will be turned on during `dotnet +publish`. The publish output will contain the linked assemblies. + +## Default behavior + +By default, the linker will operate in a conservative mode that keeps +all managed assemblies that aren't part of the framework (they are +kept intact, and the linker simply copies them). It also analyzes all +non-framework assemblies to find and keep code used by them (they are +roots for the analysis). This means that unanalyzed reflection calls +within the app should continue to work after linking. Reflection calls +to code in the framework can potentially break when using the linker, +if the target of the call is removed. + +For portable publish, framework assemblies usually do not get +published with the app. In this case they will not be analyzed or +linked. + +For self-contained publish, framework assemblies are part of the +publish output, and are analyzed by the linker. Any framework +assemblies that aren't predicted to be used at runtime based on the +linker analysis will be removed from the publish output. Used +framework assemblies will be kept, and any used code within these +assemblies will be compiled to native code. Unused parts of used +framework assemblies are kept as IL, so that reflection calls will +continue to work, with runtime JIT compilation. + +Native dependencies that aren't referenced by any of the kept managed +assemblies will be removed from the publish output as well. + +## Caveats + +You should make sure to test the publish output before deploying your +code, because the linker can potentially break apps that use +reflection. + +The linker does not analyze reflection calls, so any reflection +targets outside of the kept assemblies will need to be rooted +explicitly using either `LinkerRootAssemblies` or +`LinkerRootDescriptors` (see below). + +Sometimes an application may include multiple versions of the same +assembly. This may happen when portable apps include platform-specific +managed code, which gets placed in the `runtimes` directory of the +publish output. In such cases, the linker will pick one of the +duplicate assemblies to analyze. This means that dependencies of the +un-analyzed duplicates may not be included in the application, so you +may need to root such dependencies manually. + +Native compilation only works when the target platform is the same as +the host. To use the linker when cross-targeting (building a unix app +from windows, for example), disable `CrossGenDuringPublish`. + +## Options + +The following MSBuild properties can be used to control the behavior +of the linker, from the command-line (via `dotnet publish +/p:PropertyName=PropertyValue`), or from the .csproj file (via +`PropertyValue`). They are defined and +used in +[ILLink.Tasks.targets](integration/ILLink.Tasks/ILLink.Tasks.targets) +and +[ILLink.CrossGen.targets](integration/ILLink.Tasks/ILLink.CrossGen.targets) + +- `LinkDuringPublish` (default `true`) - Set to `false` to disable + linking. + +- `ShowLinkerSizeComparison` (default `false`) - Set to `true` to + print out a table showing the size impact of the linker. + +- `RootAllApplicationAssemblies` (default `true`) - If `true`, all + application assemblies are rooted by the linker. This means they are + kept in their entirety, and analyzed for dependencies. If `false`, + only the app dll's entry point is rooted. + +- `LinkerRootAssemblies` - The set of assemblies to root. The default + depends on the value of `RootAllApplicationAssemblies`. Additional + assemblies can be rooted by adding them to this ItemGroup. + +- `LinkerRootDescriptors` - The set of [xml descriptors](../linker#syntax-of-xml-descriptor) + specifying additional roots within assemblies. The default is to + include a generated descriptor that roots everything in the + application assembly if `RootAllApplicationAssemblies` is + `true`. Additional roots from descriptors can be included by adding + the descriptor files to this ItemGroup. + +- `ExtraLinkerArgs` - Extra arguments to pass to the linker. The + default sets some flags that output symbols, tolerate resolution + errors, log warnings, skip mono-specific localization assemblies, + and keep type-forwarder assemblies. See + [ILLink.Tasks.targets](integration/ILLink.Tasks/ILLink.Tasks.targets). + Setting this will override the defaults. + +- Assembly actions: illink has the ability to specify an [action](../linker#actions-on-the-assemblies) to + take per-assembly. ILLink.Tasks provides high-level switches that + control the action to take for a set of assemblies. The set of + managed files that make up the application are split into + "application" and "platform" assemblies. The "platform" represents + the .NET framework, while the "application" represents the rest of + the application and its other dependencies. The assembly action can + be set for each of these groups independently, for assemblies that + are analyzed as used and as unused, with the following switches: + + - `UsedApplicationAssemblyAction` - The default is to `Copy` any used + application assemblies to the output, leaving them as-is. + - `UnusedApplicationAssemblyAction` - The default is to `Delete` (not + publish) unused application assemblies. + - `UsedPlatformAssemblyAction` - For self-contained publish, the + default is `AddBypassNGen`, which will add the BypassNGenAttribute + to unused code in used platform assemblies. This causes the native + compilation step to compile only parts of these assemblies that + are used. For portable publish, the default is to `Skip` these, + because the platform assemblies are generally not published with + the app. + - `UnusedPlatformAssemblyAction` - For self-contained publish, the + default is to `Delete` (not publish) unused platform + assemblies. For portable publish, the default is to `Skip`. + + The full list of assembly actions is described in + [AssemblyAction.cs](../linker/Linker/AssemblyAction.cs) Some + combinations of actions may be disallowed if they do not make + sense. For more details, see + [SetAssemblyActions.cs](integration/ILLink.Tasks/SetAssemblyActions.cs). + +- `LinkerTrimNativeDeps` (default `true`) - If `true`, enable + detection and removal of unused native dependencies. If `false`, all + native dependencies are kept. + +- `CrossGenDuringPublish` (default `true`) - If `true`, run crossgen + on the set of assemblies modified by the linker that were crossgen'd + before linking. If `false`, just output IL for the linked + assemblies, even if they were crossgen'd before linking. \ No newline at end of file diff --git a/external/linker/corebuild/integration/ILLink.Tasks/ComputeReadyToRunAssemblies.cs b/external/linker/corebuild/integration/ILLink.Tasks/ComputeCrossgenedAssemblies.cs similarity index 51% rename from external/linker/corebuild/integration/ILLink.Tasks/ComputeReadyToRunAssemblies.cs rename to external/linker/corebuild/integration/ILLink.Tasks/ComputeCrossgenedAssemblies.cs index c5187e4fd5..8a7640eb1a 100644 --- a/external/linker/corebuild/integration/ILLink.Tasks/ComputeReadyToRunAssemblies.cs +++ b/external/linker/corebuild/integration/ILLink.Tasks/ComputeCrossgenedAssemblies.cs @@ -4,7 +4,7 @@ using Microsoft.Build.Utilities; namespace ILLink.Tasks { - public class ComputeReadyToRunAssemblies : Task + public class ComputeCrossgenedAssemblies : Task { /// /// Paths to assemblies. @@ -13,17 +13,17 @@ namespace ILLink.Tasks public ITaskItem[] Assemblies { get; set; } /// - /// This will contain the output list of - /// ready-to-run assemblies. Metadata from the input - /// parameter Assemblies is preserved. + /// This will contain the output list of crossgen-ed + /// assemblies. Metadata from the input parameter + /// Assemblies is preserved. /// [Output] - public ITaskItem[] ReadyToRunAssemblies { get; set; } + public ITaskItem[] CrossgenedAssemblies { get; set; } public override bool Execute() { - ReadyToRunAssemblies = Assemblies - .Where(f => Utils.IsReadyToRunAssembly(f.ItemSpec)) + CrossgenedAssemblies = Assemblies + .Where(f => Utils.IsCrossgenedAssembly(f.ItemSpec)) .ToArray(); return true; } diff --git a/external/linker/corebuild/integration/ILLink.Tasks/CreateRuntimeRootDescriptorFile.cs b/external/linker/corebuild/integration/ILLink.Tasks/CreateRuntimeRootDescriptorFile.cs index 3dd3f94c6f..7a0806c781 100644 --- a/external/linker/corebuild/integration/ILLink.Tasks/CreateRuntimeRootDescriptorFile.cs +++ b/external/linker/corebuild/integration/ILLink.Tasks/CreateRuntimeRootDescriptorFile.cs @@ -33,6 +33,12 @@ namespace ILLink.Tasks [Required] public ITaskItem RexcepFilePath { get; set; } + /// + /// The path to ILLinkTrim.xml. + /// + [Required] + public ITaskItem ILLinkTrimXmlFilePath { get; set; } + /// /// The path to the file to generate. /// @@ -76,6 +82,12 @@ namespace ILLink.Tasks return false; } + var iLLinkTrimXmlFilePath = ILLinkTrimXmlFilePath.ItemSpec; + if (!File.Exists (iLLinkTrimXmlFilePath)) { + Log.LogError ("File " + iLLinkTrimXmlFilePath + " doesn't exist."); + return false; + } + ProcessNamespaces (namespaceFilePath); ProcessMscorlib (mscorlibFilePath); @@ -84,7 +96,7 @@ namespace ILLink.Tasks ProcessExceptionTypes (rexcepFilePath); - OutputXml (RuntimeRootDescriptorFilePath.ItemSpec); + OutputXml (iLLinkTrimXmlFilePath, RuntimeRootDescriptorFilePath.ItemSpec); return true; } @@ -206,22 +218,17 @@ namespace ILLink.Tasks string classNamespace = defElements [1]; // g_InteropNS string className = defElements [2]; // MarshalDirectiveException AddClass (classNamespace, className, classId); + AddMethod (".ctor", classId, classNamespace, className); } } } - void OutputXml (string outputFileName) + void OutputXml (string iLLinkTrimXmlFilePath, string outputFileName) { XmlDocument doc = new XmlDocument (); - - XmlNode linkerNode = doc.CreateElement ("linker"); - doc.AppendChild (linkerNode); - - XmlNode assemblyNode = doc.CreateElement ("assembly"); - XmlAttribute assemblyFullName = doc.CreateAttribute ("fullname"); - assemblyFullName.Value = "System.Private.CoreLib"; - assemblyNode.Attributes.Append (assemblyFullName); - linkerNode.AppendChild (assemblyNode); + doc.Load (iLLinkTrimXmlFilePath); + XmlNode linkerNode = doc ["linker"]; + XmlNode assemblyNode = linkerNode ["assembly"]; foreach (string typeName in classNamesToClassMembers.Keys) { XmlNode typeNode = doc.CreateElement ("type"); @@ -273,20 +280,8 @@ namespace ILLink.Tasks void AddClass (string classNamespace, string className, string classId, bool keepAllFields = false) { - string prefixToRemove = "g_"; - if (classNamespace.StartsWith (prefixToRemove)) { - classNamespace = classNamespace.Substring (prefixToRemove.Length); - } - string suffixToRemove = "NS"; - if (classNamespace.EndsWith (suffixToRemove)) { - classNamespace = classNamespace.Substring (0, classNamespace.Length - suffixToRemove.Length); - } - string fullClassName = null; - if ((classNamespace != "NULL") && (className != "NULL")) { - if (!namespaceDictionary.ContainsKey (classNamespace)) { - Log.LogError ("Unknown namespace: " + classNamespace); - } - fullClassName = namespaceDictionary [classNamespace] + "." + className; + string fullClassName = GetFullClassName (classNamespace, className); + if (fullClassName != null) { if ((classId != null) && (classId != "NoClass")) { classIdsToClassNames [classId] = fullClassName; } @@ -311,16 +306,44 @@ namespace ILLink.Tasks members.fields.Add (fieldName); } - void AddMethod (string methodName, string classId) + void AddMethod (string methodName, string classId, string classNamespace = null, string className = null) { - string className = classIdsToClassNames [classId]; + string fullClassName; + if (classId != null) { + fullClassName = classIdsToClassNames [classId]; + } + else { + fullClassName = GetFullClassName (classNamespace, className); + } - ClassMembers members = classNamesToClassMembers [className]; + ClassMembers members = classNamesToClassMembers [fullClassName]; if (members.methods == null) { members.methods = new HashSet (); } members.methods.Add (methodName); } + + string GetFullClassName (string classNamespace, string className) + { + string prefixToRemove = "g_"; + if (classNamespace.StartsWith (prefixToRemove)) { + classNamespace = classNamespace.Substring (prefixToRemove.Length); + } + string suffixToRemove = "NS"; + if (classNamespace.EndsWith (suffixToRemove)) { + classNamespace = classNamespace.Substring (0, classNamespace.Length - suffixToRemove.Length); + } + + if ((classNamespace == "NULL") && (className == "NULL")) { + return null; + } + + if (!namespaceDictionary.ContainsKey (classNamespace)) { + Log.LogError ("Unknown namespace: " + classNamespace); + } + + return namespaceDictionary [classNamespace] + "." + className; + } } } diff --git a/external/linker/corebuild/integration/ILLink.Tasks/FindDuplicatesByMetadata.cs b/external/linker/corebuild/integration/ILLink.Tasks/FindDuplicatesByMetadata.cs new file mode 100644 index 0000000000..a784bfa27c --- /dev/null +++ b/external/linker/corebuild/integration/ILLink.Tasks/FindDuplicatesByMetadata.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +namespace ILLink.Tasks +{ + public class FindDuplicatesByMetadata : Task + { + /// + /// Items to scan. + /// + [Required] + public ITaskItem [] Items { get; set; } + + /// + /// Name of metadata to scan for. + /// + [Required] + public String MetadataName { get; set; } + + /// + /// Duplicate items: the input items for which the + /// specified metadata was shared by multiple input + /// items. + /// + [Output] + public ITaskItem [] DuplicateItems { get; set; } + + /// + /// Duplicate representatives: includes one input + /// item from each set of duplicates. + /// + [Output] + public ITaskItem [] DuplicateRepresentatives { get; set; } + + public override bool Execute () + { + var duplicateGroups = Items.GroupBy (i => i.GetMetadata (MetadataName)) + .Where (g => g.Count () > 1); + DuplicateItems = duplicateGroups.SelectMany (g => g).ToArray (); + DuplicateRepresentatives = duplicateGroups.Select (g => g.First ()).ToArray (); + return true; + } + } +} diff --git a/external/linker/corebuild/integration/ILLink.Tasks/ILLink.CrossGen.targets b/external/linker/corebuild/integration/ILLink.Tasks/ILLink.CrossGen.targets index 7d998d71e9..766b0d095a 100644 --- a/external/linker/corebuild/integration/ILLink.Tasks/ILLink.CrossGen.targets +++ b/external/linker/corebuild/integration/ILLink.Tasks/ILLink.CrossGen.targets @@ -1,7 +1,7 @@ - true + true @@ -28,8 +28,7 @@ <_CrossGenResolvedAssembliesToPublishCandidates Include="@(ResolvedAssembliesToPublish->'$(IntermediateOptimizedDir)/%(Filename)%(Extension)')" /> <_CrossGenResolvedAssembliesToPublish Include="@(_CrossGenResolvedAssembliesToPublishCandidates)" Condition="Exists('%(Identity)')" /> - + @@ -188,9 +187,9 @@ - - + - - - + + + - + - + diff --git a/external/linker/corebuild/integration/ILLink.Tasks/ILLink.Tasks.csproj b/external/linker/corebuild/integration/ILLink.Tasks/ILLink.Tasks.csproj index b5e37eebcd..907e5716c0 100644 --- a/external/linker/corebuild/integration/ILLink.Tasks/ILLink.Tasks.csproj +++ b/external/linker/corebuild/integration/ILLink.Tasks/ILLink.Tasks.csproj @@ -1,6 +1,6 @@ - 0.1.4-preview + 0.1.5-preview netcoreapp2.0;net46 netcoreapp2.0 false @@ -101,11 +101,12 @@ - + + diff --git a/external/linker/corebuild/integration/ILLink.Tasks/ILLink.Tasks.targets b/external/linker/corebuild/integration/ILLink.Tasks/ILLink.Tasks.targets index e4938b8362..45ca66cc2f 100644 --- a/external/linker/corebuild/integration/ILLink.Tasks/ILLink.Tasks.targets +++ b/external/linker/corebuild/integration/ILLink.Tasks/ILLink.Tasks.targets @@ -95,7 +95,7 @@ - + @@ -145,15 +145,21 @@ + the ComputeFilesToPublish, so it is output even during + incremental builds and takes into account all transformations + on the files to be published, including link and crossgen. --> + + + + LinkedAssemblies="@(_FinalAssembliesTouchedByLinker)" /> @@ -166,9 +172,10 @@ DependsOnTargets="_ComputeManagedResolvedAssembliesToPublish;ILLink"> <__LinkedResolvedAssemblies Include="@(_ManagedResolvedAssembliesToPublish->'$(IntermediateLinkDir)/%(Filename)%(Extension)')" /> + <__LinkedResolvedAssemblies Remove="@(_DuplicateManagedAssembliesToSkip->'$(IntermediateLinkDir)/%(Filename)%(Extension)')" /> <_LinkedResolvedAssemblies Include="@(__LinkedResolvedAssemblies)" Condition="Exists('%(Identity)')" /> - + <__LinkedIntermediateAssembly Include="@(IntermediateAssembly->'$(IntermediateLinkDir)/%(Filename)%(Extension)')" /> <_LinkedIntermediateAssembly Include="@(__LinkedIntermediateAssembly)" Condition="Exists('%(Identity)')" /> @@ -180,33 +187,62 @@ <_LinkedDebugSymbols Include="@(__LinkedDebugSymbols)" Condition="Exists('%(Identity)') And '$(_DebugSymbolsProduced)' == 'true' " /> + + + + + + + + + + + + + + + + <_LinkedAssembliesToCrossgen Include="@(_OriginalLinkedAssembliesThatWereCrossgened->'$(IntermediateLinkDir)/%(Filename)%(Extension)')" /> + + + - - <_PlatformAssembliesToLink Include="@(PlatformLibraries->'%(Filename)')" /> - <_PlatformAssembliesToLink Include="System.Private.CoreLib" /> - <_ApplicationAssembliesToLink Include="@(_ManagedAssembliesToLink->'%(Filename)')" /> - <_ApplicationAssembliesToLink Remove="@(_PlatformAssembliesToLink)" /> - + + <_PlatformAssembliesToLink Include="@(PlatformLibraries->'%(Filename)')" /> + <_ApplicationAssembliesToLink Include="@(_ManagedAssembliesToLink->'%(Filename)')" /> + <_ApplicationAssembliesToLink Remove="@(_PlatformAssembliesToLink)" /> + - - - + + + + + + <_ManagedAssembliesToLink Remove="@(_ManagedAssembliesToLink)" /> + <_ManagedAssembliesToLink Include="@(_ManagedAssembliesToLinkWithActions)" /> + - - <_ManagedAssembliesToLink Remove="@(_ManagedAssembliesToLink)" /> - <_ManagedAssembliesToLink Include="@(_ManagedAssembliesToLinkWithActions)" /> - + DependsOnTargets="_ComputeLinkedAssemblies" + Condition=" '$(LinkerTrimNativeDeps)' == 'true' "> <_NativeResolvedDepsToPublish Include="@(ResolvedAssembliesToPublish)" /> <_NativeResolvedDepsToPublish Remove="@(_ManagedResolvedAssembliesToPublish)" /> @@ -263,21 +300,18 @@ <_NativeDepsToAlwaysKeep Include="hostpolicy.dll;libhostpolicy.dylib;libhostpolicy.so" /> - - - <_NativeKeptDepsToPublish Condition=" '$(LinkerTrimNativeDeps)' != 'true' ">"@(_NativeResolvedDepsToPublish)" - + @@ -285,6 +319,22 @@ <_ManagedAssembliesToLink Include="@(_ManagedResolvedAssembliesToPublish)" /> + + + + + + + <_DuplicateManagedAssembliesToSkip Include="@(_DuplicateManagedAssemblies)" /> + <_DuplicateManagedAssembliesToSkip Remove="@(_DuplicateManagedAssembliesToLink)" /> + <_ManagedAssembliesToLink Remove="@(_DuplicateManagedAssembliesToSkip)" /> + + @@ -447,7 +511,7 @@ DependsOnTargets="_ComputeManagedResolvedAssembliesToPublish;_ComputeLinkedAssemblies;_FindNativeDeps;_HandlePublishFileConflicts" BeforeTargets="GeneratePublishDependencyFile" Condition=" '$(LinkDuringPublish)' == 'true' "> - diff --git a/external/linker/corebuild/integration/ILLink.Tasks/LinkTask.cs b/external/linker/corebuild/integration/ILLink.Tasks/LinkTask.cs index b6fb017630..159b0f8a4d 100644 --- a/external/linker/corebuild/integration/ILLink.Tasks/LinkTask.cs +++ b/external/linker/corebuild/integration/ILLink.Tasks/LinkTask.cs @@ -16,6 +16,9 @@ namespace ILLink.Tasks /// behavior should not be relied upon. Instead, work under /// the assumption that only the AssemblyPaths given will be /// resolved. + /// Each path can also have an "action" metadata, + /// which will set the illink action to take for + /// that assembly. /// [Required] public ITaskItem [] AssemblyPaths { get; set; } diff --git a/external/linker/corebuild/integration/ILLink.Tasks/Utils.cs b/external/linker/corebuild/integration/ILLink.Tasks/Utils.cs index dfeb17f677..dfe873f0e3 100644 --- a/external/linker/corebuild/integration/ILLink.Tasks/Utils.cs +++ b/external/linker/corebuild/integration/ILLink.Tasks/Utils.cs @@ -1,7 +1,8 @@ using System; using Mono.Cecil; +using Mono.Linker; -public class Utils +public static class Utils { public static bool IsManagedAssembly (string fileName) { @@ -13,12 +14,11 @@ public class Utils } } - public static bool IsReadyToRunAssembly (string fileName) + public static bool IsCrossgenedAssembly (string fileName) { try { ModuleDefinition module = ModuleDefinition.ReadModule (fileName); - return (module.Attributes & ModuleAttributes.ILOnly) == 0 && - (module.Attributes & (ModuleAttributes) 0x04) != 0; + return module.IsCrossgened (); } catch (BadImageFormatException) { return false; } diff --git a/external/linker/linker/Linker.Steps/BlacklistStep.cs b/external/linker/linker/Linker.Steps/BlacklistStep.cs index 01ac53ceaf..a438b5192b 100644 --- a/external/linker/linker/Linker.Steps/BlacklistStep.cs +++ b/external/linker/linker/Linker.Steps/BlacklistStep.cs @@ -39,15 +39,10 @@ namespace Mono.Linker.Steps { public class BlacklistStep : BaseStep { - protected override bool ConditionToProcess() - { - return Context.CoreAction == AssemblyAction.Link; - } - protected override void Process () { foreach (string name in Assembly.GetExecutingAssembly ().GetManifestResourceNames ()) { - if (!name.EndsWith (".xml", StringComparison.OrdinalIgnoreCase) || !IsReferenced (GetAssemblyName (name))) + if (!name.EndsWith (".xml", StringComparison.OrdinalIgnoreCase) || !ShouldProcessAssemblyResource (GetAssemblyName (name))) continue; try { @@ -64,7 +59,7 @@ namespace Mono.Linker.Steps { .SelectMany (mod => mod.Resources) .Where (res => res.ResourceType == ResourceType.Embedded) .Where (res => res.Name.EndsWith (".xml", StringComparison.OrdinalIgnoreCase)) - .Where (res => IsReferenced (GetAssemblyName (res.Name))) + .Where (res => ShouldProcessAssemblyResource (GetAssemblyName (res.Name))) .Cast ()) { try { Context.LogMessage ("Processing embedded resource linker descriptor: {0}", rsc.Name); @@ -87,13 +82,30 @@ namespace Mono.Linker.Steps { return descriptor.Substring (0, pos); } - bool IsReferenced (string name) + bool ShouldProcessAssemblyResource (string name) + { + AssemblyDefinition assembly = GetAssemblyIfReferenced (name); + + if (assembly == null) + return false; + + switch (Annotations.GetAction (assembly)) { + case AssemblyAction.Link: + case AssemblyAction.AddBypassNGen: + case AssemblyAction.AddBypassNGenUsed: + return true; + default: + return false; + } + } + + AssemblyDefinition GetAssemblyIfReferenced (string name) { foreach (AssemblyDefinition assembly in Context.GetAssemblies ()) if (assembly.Name.Name == name) - return true; + return assembly; - return false; + return null; } protected virtual IStep GetExternalResolveStep (EmbeddedResource resource, AssemblyDefinition assembly) diff --git a/external/linker/linker/Linker.Steps/MarkStep.cs b/external/linker/linker/Linker.Steps/MarkStep.cs index b63d8e48b9..8de88fd8a6 100644 --- a/external/linker/linker/Linker.Steps/MarkStep.cs +++ b/external/linker/linker/Linker.Steps/MarkStep.cs @@ -308,8 +308,18 @@ namespace Mono.Linker.Steps { protected virtual bool ShouldMarkCustomAttribute (CustomAttribute ca) { - if (_context.KeepUsedAttributeTypesOnly && !Annotations.IsMarked (ca.AttributeType.Resolve ())) - return false; + if (_context.KeepUsedAttributeTypesOnly) { + switch (ca.AttributeType.FullName) { + // [ThreadStatic] and [ContextStatic] are required by the runtime + case "System.ThreadStaticAttribute": + case "System.ContextStaticAttribute": + return true; + } + + if (!Annotations.IsMarked (ca.AttributeType.Resolve ())) + return false; + } + return true; } diff --git a/external/linker/linker/Linker.Steps/OutputStep.cs b/external/linker/linker/Linker.Steps/OutputStep.cs index dd70965de2..61852b7c13 100644 --- a/external/linker/linker/Linker.Steps/OutputStep.cs +++ b/external/linker/linker/Linker.Steps/OutputStep.cs @@ -87,12 +87,6 @@ namespace Mono.Linker.Steps { OutputAssembly (assembly); } - static bool IsReadyToRun (ModuleDefinition module) - { - return (module.Attributes & ModuleAttributes.ILOnly) == 0 && - (module.Attributes & (ModuleAttributes) 0x04) != 0; - } - protected void WriteAssembly (AssemblyDefinition assembly, string directory) { WriteAssembly (assembly, directory, SaveSymbols (assembly)); @@ -101,10 +95,10 @@ namespace Mono.Linker.Steps { protected virtual void WriteAssembly (AssemblyDefinition assembly, string directory, WriterParameters writerParameters) { foreach (var module in assembly.Modules) { - // Write back pure IL even for R2R assemblies - if (IsReadyToRun (module)) { + // Write back pure IL even for crossgen-ed assemblies + if (module.IsCrossgened ()) { module.Attributes |= ModuleAttributes.ILOnly; - module.Attributes ^= (ModuleAttributes) (uint) 0x04; + module.Attributes ^= ModuleAttributes.ILLibrary; module.Architecture = CalculateArchitecture (module.Architecture); } } @@ -168,11 +162,9 @@ namespace Mono.Linker.Steps { if (!assembly.MainModule.HasSymbols) return parameters; -#if NATIVE_READER_SUPPORT - // NativePdb's can't be written on non-windows platforms - if (Environment.OSVersion.Platform != PlatformID.Win32NT && assembly.MainModule.SymbolReader is Mono.Cecil.Pdb.NativePdbReader) + // Use a string check to avoid a hard dependency on Mono.Cecil.Pdb + if (Environment.OSVersion.Platform != PlatformID.Win32NT && assembly.MainModule.SymbolReader.GetType ().FullName == "Mono.Cecil.Pdb.NativePdbReader") return parameters; -#endif if (Context.SymbolWriterProvider != null) parameters.SymbolWriterProvider = Context.SymbolWriterProvider; diff --git a/external/linker/linker/Linker.Steps/ResolveFromXmlStep.cs b/external/linker/linker/Linker.Steps/ResolveFromXmlStep.cs index 4f80896aca..c9c8eac0cc 100644 --- a/external/linker/linker/Linker.Steps/ResolveFromXmlStep.cs +++ b/external/linker/linker/Linker.Steps/ResolveFromXmlStep.cs @@ -93,7 +93,7 @@ namespace Mono.Linker.Steps { try { ProcessAssemblies (Context, nav.SelectChildren ("assembly", _ns)); - if (!string.IsNullOrEmpty (_resourceName)) + if (!string.IsNullOrEmpty (_resourceName) && Context.StripResources) Context.Annotations.AddResourceToRemove (_resourceAssembly, _resourceName); } catch (Exception ex) when (!(ex is XmlResolutionException)) { throw new XmlResolutionException (string.Format ("Failed to process XML description: {0}", _xmlDocumentLocation), ex); diff --git a/external/linker/linker/Linker/AssemblyUtilities.cs b/external/linker/linker/Linker/AssemblyUtilities.cs new file mode 100644 index 0000000000..a0da2a92fb --- /dev/null +++ b/external/linker/linker/Linker/AssemblyUtilities.cs @@ -0,0 +1,16 @@ +using System; +using Mono.Cecil; + +namespace Mono.Linker { + + public static class AssemblyUtilities { + + public static bool IsCrossgened (this ModuleDefinition module) + { + return (module.Attributes & ModuleAttributes.ILOnly) == 0 && + (module.Attributes & ModuleAttributes.ILLibrary) != 0; + } + + } + +} diff --git a/external/linker/linker/Linker/Driver.cs b/external/linker/linker/Linker/Driver.cs index 699a34f447..6a45274258 100644 --- a/external/linker/linker/Linker/Driver.cs +++ b/external/linker/linker/Linker/Driver.cs @@ -143,6 +143,11 @@ namespace Mono.Linker { continue; } + if (token == "--strip-resources") { + context.StripResources = bool.Parse (GetParam ()); + continue; + } + switch (token [2]) { case 'v': Version (); @@ -316,6 +321,7 @@ namespace Mono.Linker { return assemblies; } + AssemblyAction ParseAssemblyAction (string s) { var assemblyAction = (AssemblyAction)Enum.Parse(typeof(AssemblyAction), s, true); @@ -362,6 +368,7 @@ namespace Mono.Linker { Console.WriteLine (" --reduced-tracing Reduces dependency output related to assemblies that will not be modified"); Console.WriteLine (" --used-attrs-only Attributes on types, methods, etc will be removed if the attribute type is not used"); Console.WriteLine (" --strip-security In linked assemblies, attributes on assemblies, types, and methods related to security will be removed"); + Console.WriteLine (" --strip-resources Remove link xml resources that were processed (true or false), default to true"); Console.WriteLine (" -out Specify the output directory, default to `output'"); Console.WriteLine (" -c Action on the core assemblies, skip, copy, copyused, addbypassngen, addbypassngenused or link, default to skip"); Console.WriteLine (" -u Action on the user assemblies, skip, copy, copyused, addbypassngen, addbypassngenused or link, default to link"); diff --git a/external/linker/linker/Linker/LinkContext.cs b/external/linker/linker/Linker/LinkContext.cs index c8594464ff..0ea7231425 100644 --- a/external/linker/linker/Linker/LinkContext.cs +++ b/external/linker/linker/Linker/LinkContext.cs @@ -111,6 +111,8 @@ namespace Mono.Linker { public bool KeepUsedAttributeTypesOnly { get; set; } + public bool StripResources { get; set; } + public System.Collections.IDictionary Actions { get { return _actions; } } @@ -171,6 +173,7 @@ namespace Mono.Linker { _annotations = factory.CreateAnnotationStore (this); MarkingHelpers = factory.CreateMarkingHelpers (this); Tracer = factory.CreateTracer (this); + StripResources = true; } public TypeDefinition GetType (string fullName) diff --git a/external/linker/linker/Mono.Linker.csproj b/external/linker/linker/Mono.Linker.csproj index d8c9d24508..0b858bcd72 100644 --- a/external/linker/linker/Mono.Linker.csproj +++ b/external/linker/linker/Mono.Linker.csproj @@ -33,7 +33,7 @@ full False bin\Debug\ - DEBUG;TRACE;NATIVE_READER_SUPPORT + DEBUG;TRACE prompt 4 @@ -41,7 +41,7 @@ pdbonly True bin\Release\ - TRACE;NATIVE_READER_SUPPORT + TRACE prompt 4 @@ -81,6 +81,7 @@ + diff --git a/external/linker/linker/README.md b/external/linker/linker/README.md index 35591daeaa..3b88e63a1f 100644 --- a/external/linker/linker/README.md +++ b/external/linker/linker/README.md @@ -48,11 +48,16 @@ the info file. You can specify what the linker should do exactly per assembly. -The linker can do 3 things: +The linker can do the following things: -- skip them, and do nothing with them, -- copy them to the output directory, -- link them, to reduce their size. +- Skip: skip them, and do nothing with them, +- Copy: copy them to the output directory, +- CopyUsed: copy used assemblies to the output directory, +- Link: link them, to reduce their size, +- Delete: remove them from the output, +- Save: save them in memory without linking +- AddBypassNGen: add BypassNGenAttribute to unmarked methods, +- AddBypassNgenUsed: add BypassNGenAttribute to unmarked methods in used assemblies. You can specify an action per assembly like this: diff --git a/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/build/Microsoft.Net.Compilers.props b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/build/Microsoft.Net.Compilers.props new file mode 100755 index 0000000000..829cbfffa2 --- /dev/null +++ b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/build/Microsoft.Net.Compilers.props @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + false + $(MSBuildThisFileDirectory)..\tools\Microsoft.CSharp.Core.targets + $(MSBuildThisFileDirectory)..\tools\Microsoft.VisualBasic.Core.targets + + + + + $(MSBuildThisFileDirectory)..\tools + csc.exe + $(MSBuildThisFileDirectory)..\tools + vbc.exe + + diff --git a/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.Build.Tasks.CodeAnalysis.dll.REMOVED.git-id b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.Build.Tasks.CodeAnalysis.dll.REMOVED.git-id new file mode 100644 index 0000000000..e21cd9eb02 --- /dev/null +++ b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.Build.Tasks.CodeAnalysis.dll.REMOVED.git-id @@ -0,0 +1 @@ +f05efc1a893862b0f114a0a76620b8661272148a \ No newline at end of file diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/Microsoft.CSharp.Core.targets b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.CSharp.Core.targets old mode 100644 new mode 100755 similarity index 97% rename from mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/Microsoft.CSharp.Core.targets rename to external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.CSharp.Core.targets index b7f0c9caff..8c535b2e29 --- a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/Microsoft.CSharp.Core.targets +++ b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.CSharp.Core.targets @@ -98,6 +98,7 @@ DelaySign="$(DelaySign)" DisabledWarnings="$(NoWarn)" DocumentationFile="@(DocFileItem)" + EmbedAllSources="$(EmbedAllSources)" EmbeddedFiles="@(EmbeddedFiles)" EmitDebugInformation="$(DebugSymbols)" EnvironmentVariables="$(CscEnvironment)" diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/Microsoft.CodeAnalysis.CSharp.Scripting.dll b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.CodeAnalysis.CSharp.Scripting.dll old mode 100644 new mode 100755 similarity index 54% rename from mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/Microsoft.CodeAnalysis.CSharp.Scripting.dll rename to external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.CodeAnalysis.CSharp.Scripting.dll index 3116242297..bb720f0289 Binary files a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/Microsoft.CodeAnalysis.CSharp.Scripting.dll and b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.CodeAnalysis.CSharp.Scripting.dll differ diff --git a/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.CodeAnalysis.CSharp.dll.REMOVED.git-id b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.CodeAnalysis.CSharp.dll.REMOVED.git-id new file mode 100644 index 0000000000..99798e7956 --- /dev/null +++ b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.CodeAnalysis.CSharp.dll.REMOVED.git-id @@ -0,0 +1 @@ +2ad58e695999acab255b43212777276fccf98b8a \ No newline at end of file diff --git a/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.CodeAnalysis.Scripting.dll.REMOVED.git-id b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.CodeAnalysis.Scripting.dll.REMOVED.git-id new file mode 100644 index 0000000000..2b5ab1250c --- /dev/null +++ b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.CodeAnalysis.Scripting.dll.REMOVED.git-id @@ -0,0 +1 @@ +b21fcbe9336c57e668847b417c21995036af1b62 \ No newline at end of file diff --git a/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.CodeAnalysis.VisualBasic.dll.REMOVED.git-id b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.CodeAnalysis.VisualBasic.dll.REMOVED.git-id new file mode 100644 index 0000000000..cb85e1db0d --- /dev/null +++ b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.CodeAnalysis.VisualBasic.dll.REMOVED.git-id @@ -0,0 +1 @@ +a3985f27509c583bdab4fbd2e12b931c96885f1d \ No newline at end of file diff --git a/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.CodeAnalysis.dll.REMOVED.git-id b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.CodeAnalysis.dll.REMOVED.git-id new file mode 100644 index 0000000000..f41349adf7 --- /dev/null +++ b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.CodeAnalysis.dll.REMOVED.git-id @@ -0,0 +1 @@ +270574d390a3ea048cafc086660206e2e9d17ab0 \ No newline at end of file diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/Microsoft.VisualBasic.Core.targets b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.VisualBasic.Core.targets old mode 100644 new mode 100755 similarity index 97% rename from mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/Microsoft.VisualBasic.Core.targets rename to external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.VisualBasic.Core.targets index 274622a28e..21099278f4 --- a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/Microsoft.VisualBasic.Core.targets +++ b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.VisualBasic.Core.targets @@ -84,6 +84,7 @@ DelaySign="$(DelaySign)" DisabledWarnings="$(NoWarn)" DocumentationFile="@(DocFileItem)" + EmbedAllSources="$(EmbedAllSources)" EmbeddedFiles="@(EmbeddedFiles)" EmitDebugInformation="$(DebugSymbols)" EnvironmentVariables="$(VbcEnvironment)" diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/System.Collections.Immutable.dll.REMOVED.git-id b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/System.Collections.Immutable.dll.REMOVED.git-id similarity index 100% rename from mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/System.Collections.Immutable.dll.REMOVED.git-id rename to external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/System.Collections.Immutable.dll.REMOVED.git-id diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/System.Reflection.Metadata.dll.REMOVED.git-id b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/System.Reflection.Metadata.dll.REMOVED.git-id similarity index 100% rename from mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/System.Reflection.Metadata.dll.REMOVED.git-id rename to external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/System.Reflection.Metadata.dll.REMOVED.git-id diff --git a/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/VBCSCompiler.exe b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/VBCSCompiler.exe new file mode 100755 index 0000000000..1d3856b685 Binary files /dev/null and b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/VBCSCompiler.exe differ diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/VBCSCompiler.exe.config b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/VBCSCompiler.exe.config old mode 100644 new mode 100755 similarity index 95% rename from mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/VBCSCompiler.exe.config rename to external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/VBCSCompiler.exe.config index b8d3b9bb72..6f76c76d18 --- a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/VBCSCompiler.exe.config +++ b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/VBCSCompiler.exe.config @@ -10,19 +10,19 @@ - + - + - + diff --git a/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/csc.exe b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/csc.exe new file mode 100755 index 0000000000..0a80c14413 Binary files /dev/null and b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/csc.exe differ diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/csc.exe.config b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/csc.exe.config old mode 100644 new mode 100755 similarity index 95% rename from mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/csc.exe.config rename to external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/csc.exe.config index 7ac30aa968..ce5472c93a --- a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/csc.exe.config +++ b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/csc.exe.config @@ -10,19 +10,19 @@ - + - + - + @@ -117,13 +117,13 @@ - + - + diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/csc.rsp b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/csc.rsp old mode 100644 new mode 100755 similarity index 100% rename from mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/csc.rsp rename to external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/csc.rsp diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/csi.exe b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/csi.exe old mode 100644 new mode 100755 similarity index 52% rename from mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/csi.exe rename to external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/csi.exe index ffe3e7b76b..5fcd12bc1c Binary files a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/csi.exe and b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/csi.exe differ diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/csi.exe.config b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/csi.exe.config old mode 100644 new mode 100755 similarity index 95% rename from mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/csi.exe.config rename to external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/csi.exe.config index f26e2926fa..937789ca32 --- a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/csi.exe.config +++ b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/csi.exe.config @@ -8,19 +8,19 @@ - + - + - + diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/csi.rsp b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/csi.rsp old mode 100644 new mode 100755 similarity index 100% rename from mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/csi.rsp rename to external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/csi.rsp diff --git a/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/vbc.exe b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/vbc.exe new file mode 100755 index 0000000000..24bb6aa7cc Binary files /dev/null and b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/vbc.exe differ diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/vbc.exe.config b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/vbc.exe.config old mode 100644 new mode 100755 similarity index 95% rename from mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/vbc.exe.config rename to external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/vbc.exe.config index a5de23dc75..ce5472c93a --- a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/vbc.exe.config +++ b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/vbc.exe.config @@ -10,19 +10,19 @@ - + - + - + diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/vbc.rsp b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/vbc.rsp old mode 100644 new mode 100755 similarity index 95% rename from mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/vbc.rsp rename to external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/vbc.rsp index c56b36c89b..52b4caceb9 --- a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/vbc.rsp +++ b/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/vbc.rsp @@ -30,7 +30,7 @@ /r:System.Web.RegularExpressions.dll /r:System.Web.Services.dll /r:System.Windows.Forms.dll -/r:System.Xml.dll +/r:System.XML.dll /r:System.Workflow.Activities.dll /r:System.Workflow.ComponentModel.dll diff --git a/ikvm-native/Makefile.in b/ikvm-native/Makefile.in index e1037e0360..0cadf0d4f4 100644 --- a/ikvm-native/Makefile.in +++ b/ikvm-native/Makefile.in @@ -84,8 +84,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs $(top_srcdir)/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -271,6 +269,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -289,7 +288,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -303,7 +301,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -417,7 +414,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ diff --git a/libgc/dyn_load.c b/libgc/dyn_load.c index 963f6e9542..c414c8788c 100644 --- a/libgc/dyn_load.c +++ b/libgc/dyn_load.c @@ -396,7 +396,8 @@ GC_bool GC_register_main_static_data() # if (defined(LINUX) || defined (__GLIBC__) || defined(NACL)) /* Are others OK here, too? */ \ && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) \ - || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && defined(DT_CONFIG))) + || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && defined(DT_CONFIG))) \ + || defined(OPENBSD) /* We have the header files for a glibc that includes dl_iterate_phdr. */ /* It may still not be available in the library on the target system. */ diff --git a/libgc/include/gc.h b/libgc/include/gc.h index e7929918ad..c9c20e65a6 100644 --- a/libgc/include/gc.h +++ b/libgc/include/gc.h @@ -835,6 +835,18 @@ typedef GC_PTR (*GC_fn_type) GC_PROTO((GC_PTR client_data)); GC_API GC_PTR GC_call_with_alloc_lock GC_PROTO((GC_fn_type fn, GC_PTR client_data)); +/* + * These are similar to GC_do_blocking () in upstream bdwgc. The design is + * simpler in that there is no distinction between active and inactive stack + * frames; instead, while a thread is in blocking state, it promises to not + * interact with the GC at all, and to not keep any pointers to GC memory + * around from before entering blocking state. Additionally, these can be + * called unbalanced (they simply set a flag internally). + */ +GC_API void GC_start_blocking GC_PROTO((void)); + +GC_API void GC_end_blocking GC_PROTO((void)); + /* The following routines are primarily intended for use with a */ /* preprocessor which inserts calls to check C pointer arithmetic. */ /* They indicate failure by invoking the corresponding _print_proc. */ diff --git a/libgc/pthread_support.c b/libgc/pthread_support.c index 6d240f65f0..3ff89b2922 100644 --- a/libgc/pthread_support.c +++ b/libgc/pthread_support.c @@ -1245,7 +1245,6 @@ void GC_start_blocking(void) { GC_thread me; LOCK(); me = GC_lookup_thread(pthread_self()); - GC_ASSERT(!(me -> thread_blocked)); # ifdef SPARC me -> stop_info.stack_ptr = (ptr_t)GC_save_regs_in_stack(); # else @@ -1273,7 +1272,6 @@ void GC_end_blocking(void) { GC_thread me; LOCK(); /* This will block if the world is stopped. */ me = GC_lookup_thread(pthread_self()); - GC_ASSERT(me -> thread_blocked); me -> thread_blocked = FALSE; UNLOCK(); } diff --git a/libgc/win32_threads.c b/libgc/win32_threads.c index 5533b8f2e2..425d41a989 100644 --- a/libgc/win32_threads.c +++ b/libgc/win32_threads.c @@ -48,6 +48,7 @@ struct GC_thread_Rep { /* 0 ==> entry not valid. */ /* !in_use ==> stack_base == 0 */ GC_bool suspended; + GC_bool thread_blocked; # ifdef CYGWIN32 void *status; /* hold exit value until join in case it's a pointer */ @@ -174,6 +175,7 @@ static GC_thread GC_new_thread(void) { /* the world, wait here. Hopefully this can't happen on any */ /* systems that don't allow us to block here. */ while (GC_please_stop) Sleep(20); + GC_ASSERT(!thread_table[i]->thread_blocked); return thread_table + i; } @@ -223,7 +225,6 @@ static void GC_delete_thread(DWORD thread_id) { } } - #ifdef CYGWIN32 /* Return a GC_thread corresponding to a given pthread_t. */ @@ -245,6 +246,20 @@ static GC_thread GC_lookup_thread(pthread_t id) return thread_table + i; } +#else + +static GC_thread GC_lookup_thread(DWORD id) +{ + int i; + LONG max = GC_get_max_thread_index(); + + for (i = 0; i <= max; i++) + if (thread_table[i].in_use && thread_table[i].id == id) + return &thread_table[i]; + + return NULL; +} + #endif /* CYGWIN32 */ void GC_push_thread_structures GC_PROTO((void)) @@ -264,6 +279,35 @@ void GC_push_thread_structures GC_PROTO((void)) # endif } +/* Wrappers for functions that are likely to block for an appreciable */ +/* length of time. Must be called in pairs, if at all. */ +/* Nothing much beyond the system call itself should be executed */ +/* between these. */ + +void GC_start_blocking(void) { + GC_thread me; + LOCK(); +#ifdef CYGWIN32 + me = GC_lookup_thread(pthread_self()); +#else + me = GC_lookup_thread(GetCurrentThreadId()); +#endif + me->thread_blocked = TRUE; + UNLOCK(); +} + +void GC_end_blocking(void) { + GC_thread me; + LOCK(); /* This will block if the world is stopped. */ +#ifdef CYGWIN32 + me = GC_lookup_thread(pthread_self()); +#else + me = GC_lookup_thread(GetCurrentThreadId()); +#endif + me->thread_blocked = FALSE; + UNLOCK(); +} + /* Defined in misc.c */ extern CRITICAL_SECTION GC_write_cs; @@ -281,6 +325,8 @@ void GC_stop_world() for (i = 0; i <= GC_get_max_thread_index(); i++) if (thread_table[i].stack_base != 0 && thread_table[i].id != thread_id) { + if (thread_table [i].thread_blocked) + continue; # ifdef MSWINCE /* SuspendThread will fail if thread is running kernel code */ while (SuspendThread(thread_table[i].handle) == (DWORD)-1) diff --git a/llvm/Makefile.in b/llvm/Makefile.in index 0b4ccb7800..185aa414f1 100644 --- a/llvm/Makefile.in +++ b/llvm/Makefile.in @@ -96,8 +96,6 @@ DIST_COMMON = $(top_srcdir)/scripts/submodules/versions.mk \ subdir = llvm ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -206,6 +204,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -224,7 +223,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -238,7 +236,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -352,7 +349,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ diff --git a/m4/Makefile.am b/m4/Makefile.am index 5d51ce8aa6..58684627ad 100644 --- a/m4/Makefile.am +++ b/m4/Makefile.am @@ -1 +1 @@ -EXTRA_DIST = iconv.m4 lib-ld.m4 lib-link.m4 lib-prefix.m4 $(wildcard *.m4) +EXTRA_DIST = lib-ld.m4 lib-link.m4 lib-prefix.m4 $(wildcard *.m4) diff --git a/m4/Makefile.in b/m4/Makefile.in index 02a219a778..3b62446462 100644 --- a/m4/Makefile.in +++ b/m4/Makefile.in @@ -83,8 +83,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -193,6 +191,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -211,7 +210,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -225,7 +223,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -339,7 +336,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ @@ -359,7 +355,7 @@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -EXTRA_DIST = iconv.m4 lib-ld.m4 lib-link.m4 lib-prefix.m4 $(wildcard *.m4) +EXTRA_DIST = lib-ld.m4 lib-link.m4 lib-prefix.m4 $(wildcard *.m4) all: all-am .SUFFIXES: diff --git a/m4/iconv.m4 b/m4/iconv.m4 deleted file mode 100644 index e2041b9b49..0000000000 --- a/m4/iconv.m4 +++ /dev/null @@ -1,214 +0,0 @@ -# iconv.m4 serial 11 (gettext-0.18.1) -dnl Copyright (C) 2000-2002, 2007-2010 Free Software Foundation, Inc. -dnl This file is free software; the Free Software Foundation -dnl gives unlimited permission to copy and/or distribute it, -dnl with or without modifications, as long as this notice is preserved. - -dnl From Bruno Haible. - -AC_DEFUN([AM_ICONV_LINKFLAGS_BODY], -[ - dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. - AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) - AC_REQUIRE([AC_LIB_RPATH]) - - dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV - dnl accordingly. - AC_LIB_LINKFLAGS_BODY([iconv]) -]) - -AC_DEFUN([AM_ICONV_LINK], -[ - dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and - dnl those with the standalone portable GNU libiconv installed). - AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles - - dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV - dnl accordingly. - AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) - - dnl Add $INCICONV to CPPFLAGS before performing the following checks, - dnl because if the user has installed libiconv and not disabled its use - dnl via --without-libiconv-prefix, he wants to use it. The first - dnl AC_TRY_LINK will then fail, the second AC_TRY_LINK will succeed. - am_save_CPPFLAGS="$CPPFLAGS" - AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCICONV]) - - AC_CACHE_CHECK([for iconv], [am_cv_func_iconv], [ - am_cv_func_iconv="no, consider installing GNU libiconv" - am_cv_lib_iconv=no - AC_TRY_LINK([#include -#include ], - [iconv_t cd = iconv_open("",""); - iconv(cd,NULL,NULL,NULL,NULL); - iconv_close(cd);], - [am_cv_func_iconv=yes]) - if test "$am_cv_func_iconv" != yes; then - am_save_LIBS="$LIBS" - LIBS="$LIBS $LIBICONV" - AC_TRY_LINK([#include -#include ], - [iconv_t cd = iconv_open("",""); - iconv(cd,NULL,NULL,NULL,NULL); - iconv_close(cd);], - [am_cv_lib_iconv=yes] - [am_cv_func_iconv=yes]) - LIBS="$am_save_LIBS" - fi - ]) - if test "$am_cv_func_iconv" = yes; then - AC_CACHE_CHECK([for working iconv], [am_cv_func_iconv_works], [ - dnl This tests against bugs in AIX 5.1, HP-UX 11.11, Solaris 10. - am_save_LIBS="$LIBS" - if test $am_cv_lib_iconv = yes; then - LIBS="$LIBS $LIBICONV" - fi - AC_TRY_RUN([ -#include -#include -int main () -{ - /* Test against AIX 5.1 bug: Failures are not distinguishable from successful - returns. */ - { - iconv_t cd_utf8_to_88591 = iconv_open ("ISO8859-1", "UTF-8"); - if (cd_utf8_to_88591 != (iconv_t)(-1)) - { - static const char input[] = "\342\202\254"; /* EURO SIGN */ - char buf[10]; - const char *inptr = input; - size_t inbytesleft = strlen (input); - char *outptr = buf; - size_t outbytesleft = sizeof (buf); - size_t res = iconv (cd_utf8_to_88591, - (char **) &inptr, &inbytesleft, - &outptr, &outbytesleft); - if (res == 0) - return 1; - } - } - /* Test against Solaris 10 bug: Failures are not distinguishable from - successful returns. */ - { - iconv_t cd_ascii_to_88591 = iconv_open ("ISO8859-1", "646"); - if (cd_ascii_to_88591 != (iconv_t)(-1)) - { - static const char input[] = "\263"; - char buf[10]; - const char *inptr = input; - size_t inbytesleft = strlen (input); - char *outptr = buf; - size_t outbytesleft = sizeof (buf); - size_t res = iconv (cd_ascii_to_88591, - (char **) &inptr, &inbytesleft, - &outptr, &outbytesleft); - if (res == 0) - return 1; - } - } -#if 0 /* This bug could be worked around by the caller. */ - /* Test against HP-UX 11.11 bug: Positive return value instead of 0. */ - { - iconv_t cd_88591_to_utf8 = iconv_open ("utf8", "iso88591"); - if (cd_88591_to_utf8 != (iconv_t)(-1)) - { - static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337"; - char buf[50]; - const char *inptr = input; - size_t inbytesleft = strlen (input); - char *outptr = buf; - size_t outbytesleft = sizeof (buf); - size_t res = iconv (cd_88591_to_utf8, - (char **) &inptr, &inbytesleft, - &outptr, &outbytesleft); - if ((int)res > 0) - return 1; - } - } -#endif - /* Test against HP-UX 11.11 bug: No converter from EUC-JP to UTF-8 is - provided. */ - if (/* Try standardized names. */ - iconv_open ("UTF-8", "EUC-JP") == (iconv_t)(-1) - /* Try IRIX, OSF/1 names. */ - && iconv_open ("UTF-8", "eucJP") == (iconv_t)(-1) - /* Try AIX names. */ - && iconv_open ("UTF-8", "IBM-eucJP") == (iconv_t)(-1) - /* Try HP-UX names. */ - && iconv_open ("utf8", "eucJP") == (iconv_t)(-1)) - return 1; - return 0; -}], [am_cv_func_iconv_works=yes], [am_cv_func_iconv_works=no], - [case "$host_os" in - aix* | hpux*) am_cv_func_iconv_works="guessing no" ;; - *) am_cv_func_iconv_works="guessing yes" ;; - esac]) - LIBS="$am_save_LIBS" - ]) - case "$am_cv_func_iconv_works" in - *no) am_func_iconv=no am_cv_lib_iconv=no ;; - *) am_func_iconv=yes ;; - esac - else - am_func_iconv=no am_cv_lib_iconv=no - fi - if test "$am_func_iconv" = yes; then - AC_DEFINE([HAVE_ICONV], [1], - [Define if you have the iconv() function and it works.]) - fi - if test "$am_cv_lib_iconv" = yes; then - AC_MSG_CHECKING([how to link with libiconv]) - AC_MSG_RESULT([$LIBICONV]) - else - dnl If $LIBICONV didn't lead to a usable library, we don't need $INCICONV - dnl either. - CPPFLAGS="$am_save_CPPFLAGS" - LIBICONV= - LTLIBICONV= - fi - AC_SUBST([LIBICONV]) - AC_SUBST([LTLIBICONV]) -]) - -dnl Define AM_ICONV using AC_DEFUN_ONCE for Autoconf >= 2.64, in order to -dnl avoid warnings like -dnl "warning: AC_REQUIRE: `AM_ICONV' was expanded before it was required". -dnl This is tricky because of the way 'aclocal' is implemented: -dnl - It requires defining an auxiliary macro whose name ends in AC_DEFUN. -dnl Otherwise aclocal's initial scan pass would miss the macro definition. -dnl - It requires a line break inside the AC_DEFUN_ONCE and AC_DEFUN expansions. -dnl Otherwise aclocal would emit many "Use of uninitialized value $1" -dnl warnings. -m4_define([gl_iconv_AC_DEFUN], - m4_version_prereq([2.64], - [[AC_DEFUN_ONCE( - [$1], [$2])]], - [[AC_DEFUN( - [$1], [$2])]])) -gl_iconv_AC_DEFUN([AM_ICONV], -[ - AM_ICONV_LINK - if test "$am_cv_func_iconv" = yes; then - AC_MSG_CHECKING([for iconv declaration]) - AC_CACHE_VAL([am_cv_proto_iconv], [ - AC_TRY_COMPILE([ -#include -#include -extern -#ifdef __cplusplus -"C" -#endif -#if defined(__STDC__) || defined(__cplusplus) -size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); -#else -size_t iconv(); -#endif -], [], [am_cv_proto_iconv_arg1=""], [am_cv_proto_iconv_arg1="const"]) - am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"]) - am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` - AC_MSG_RESULT([ - $am_cv_proto_iconv]) - AC_DEFINE_UNQUOTED([ICONV_CONST], [$am_cv_proto_iconv_arg1], - [Define as const if the declaration of iconv() needs const.]) - fi -]) diff --git a/man/Makefile.in b/man/Makefile.in index b29c0e0ce4..abd833a332 100644 --- a/man/Makefile.in +++ b/man/Makefile.in @@ -83,8 +83,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -225,6 +223,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -243,7 +242,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -257,7 +255,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -371,7 +368,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ diff --git a/man/mkbundle.1 b/man/mkbundle.1 index 7a9e22c205..32fcbc6cce 100644 --- a/man/mkbundle.1 +++ b/man/mkbundle.1 @@ -111,10 +111,11 @@ directory. .SH OPTIONS .TP .I "--config FILE" -Specifies that a machine.config file must be bundled as well. -Typically this is $prefix/etc/mono/1.0/machine.config or -$prefix/etc/mono/2.0/machine.config depending on the profile that you -are using (1.0 or 2.0) +Specifies that a DLLMAP Mono config file must be bundled as well. In +the simple and cross compiler modes, if no config file is specified +the one for the current target is picked (either the system one in the +case of the simple mode, or the one that came from the cross +compilation target for the cross compiling mode). .TP .I "--config-dir DIR" When passed, DIR will be set for the MONO_CFG_DIR environment variable @@ -202,13 +203,31 @@ Provides mkbundle access to a managed linker to preprocess the assemblies. .TP .I "--machine-config FILE" Uses the given FILE as the machine.config file for the generated -application. +application. The machine config contains an XML file that is used by +System.Configuration APIs to configure the .NET stack. Typically this +is +.I $prefix/etc/mono/4.5/machine.config. +.Sp +If you want to disable this automatic bundling, you can use the +.I "--no-machine-config" +flag. In the simple and cross compiler modes, if no machine.config file is specified +the one for the current target is picked (either the system one in the +case of the simple mode, or the one that came from the cross +compilation target for the cross compiling mode). +.TP +.I "--no-config" +In simple or cross compiling mode, this prevents mkbundle from +automatically bundling a config file. .TP .I "--nodeps" This is the default: \fImkbundle\fP will only include the assemblies that were specified on the command line to reduce the size of the resulting image created. .TP +.I "--no-machine-config" +In simple or cross compiling mode, this prevents mkbundle from +automatically bundling a machine.config file. +.TP .I "-o filename" Places the output on `out'. If the flag -c is specified, this is the C host program. If not, this contains the resulting executable. @@ -340,33 +359,80 @@ not require runtime code generation. The "llvmonly" setting does the same, but f to go through the llvm backend. .SH WINDOWS -If you are using the old embedding on Windows systems, it it necessary -to have Unix-like toolchain to be installed for \fImkbundle\fP to -work. You can use cygwin's and install gcc, gcc-mingw and as -packages. +If you are using the old embedding on Windows systems, it possible to use +a Unix-like toolchain like cygwin's and install gcc, gcc-mingw packages or +use Visual Studio 2015/2017 VC toolchain together with Clang for Visual Studio as assembler. +Clang can be installed as an individual component, "Clang/C2", using Visual Studio installer. +.PP +Using Visual Studio toolchain, mkbundle will, by default, use latest installed Visual Studio compiler +and linker as well as Windows SDK. If executed from one of the Visual Studio developer command prompts, +mkbundle will retrieve information directly from that build environment. .SH ENVIRONMENT VARIABLES .TP .I "AS" -Assembler command. The default is "as". +Assembler command. The default is "as". For Visual Studio, default is "clang.exe". +If "clang.exe" for Visual Studio is not installed, mkbundle will fall back using "as". .TP .I "CC" -C compiler command. The default is "cc" under Linux and "gcc" -under Windows. +C compiler command. The default is "cc" for Linux, "gcc" +for cygwin and "cl.exe" for Visual Studio. .TP .I "MONO_BUNDLED_OPTIONS" Options to be passed to the bundled Mono runtime, separated by spaces. See the mono(1) manual page or run mono --help. +.SH WINDOWS VISUAL STUDIO ENVIRONMENT VARIABLES +.TP +.I "VisualStudioVersion" +Visual Studio version used in mkbundle build. +Default, latest installed Visual Studio version. +Values, "14.0" for Visual Studio 2015 or "15.0" for Visual Studio 2017. +.TP +.I "WindowsSdkVersion" +Windows SDK version used in mkbundle build. +Default/unknown, latest installed Windows SDK. +Values, "8.1", "10.0.10240.0", "10.0.15063.0" etc. +.TP +.I "VSCMD_ARG_TGT_ARCH" +Output target architecture used in mkbundle build. +Default/unknown, use architecture of .NET runtime executing mkbundle. +Values, "x86" or "x64". +NOTE, when running from a Visual Studio command prompt, this variable should already be set +by the command prompt and match the rest of that build environment. +.TP +.I "INCLUDE" +Override all custom include paths passed to "cl.exe". +Predefined by Visual Studio developer command prompt or auto detected by mkbundle when undefined. +.TP +.I "LIB" +Override all custom library paths passed to "link.exe". +Predefined by Visual Studio developer command prompt or auto detected by mkbundle when undefined. +.TP +.I "MONOPREFIX" +Use a custom Mono SDK install root matching the output target architecture (x86/x64). +Default, mkbundle will look for installed Mono SDK’s matching targeted architecture. +.TP +.I "MONOLIB" +Use a different mono library name or an absolute path to the mono library passed to linker. +Default, mkbundle will use default mono library name depending on mkbundle dynamic/static use case. +NOTE, supplied mono library needs to match mkbundle dynamic/static use case and target architecture. +.TP +.I "VCCRT" +Override C-runtime library linker settings. +Default "MD", mkbundle will use dynamic C-runtime linking on Windows compatible with Mono SDK distribution. +If a custom built Mono runtime using static C-Runtime linkage is used, setting this variable to "MT" +will link using static C-runtime libraries. +.TP +.I "VCSUBSYSTEM" +Override Windows subsystem. +Default, "windows". If console subsystem is preferred, use "console". +NOTE, if console output is expected from output target process then +set this variable to "console". .SH FILES This program will load referenced assemblies from the Mono assembly cache. .PP Targets are loaded from ~/.mono/targets/TARGETNAME/mono .SH BUGS -The option "--static" is not supported under Windows when using the -old embedding. -Moreover, a full cygwin environment containing at least "gcc" and "as" -is required for the build process. The generated executable does not -depend on cygwin. .SH MAILING LISTS Visit http://lists.ximian.com/mailman/listinfo/mono-devel-list for details. .SH WEB SITE diff --git a/man/mono.1 b/man/mono.1 index 9ac128167c..c5c19f5274 100644 --- a/man/mono.1 +++ b/man/mono.1 @@ -1126,14 +1126,12 @@ When Mono is built with a soft float fallback on ARM and this variable is set to "1", Mono will always emit soft float code, even if a VFP unit is detected. .TP -\fBMONO_DARWIN_WATCHER_MAXFDS\fR -This is a debugging aid used to force limits on the FileSystemWatcher -implementation in Darwin. There is no limit by default. +\fBMONO_DARWIN_USE_KQUEUE_FSW\fR +Fall back on the kqueue FileSystemWatcher implementation in Darwin. The default is the FSEvent implementation. .TP -\fBMONO_DISABLE_AIO\fR -If set, tells mono NOT to attempt using native asynchronous I/O services. In -that case, a default select/poll implementation is used. Currently only epoll() -is supported. +\fBMONO_DARWIN_WATCHER_MAXFDS\fR +This is a debugging aid used to force limits on the kqueue FileSystemWatcher +implementation in Darwin. There is no limit by default. .TP \fBMONO_DISABLE_MANAGED_COLLATION\fR If this environment variable is `yes', the runtime uses unmanaged @@ -1160,6 +1158,11 @@ For platforms that do not otherwise have a way of obtaining random bytes this can be set to the name of a file system socket on which an egd or prngd daemon is listening. .TP +\fBMONO_ENABLE_AIO\fR +If set, tells mono to attempt using native asynchronous I/O services. If not +set, a default select/poll implementation is used. Currently epoll and kqueue +are supported. +.TP \fBMONO_ENABLE_COOP\fR This makes the Mono runtime and the SGen garbage collector run in cooperative mode as opposed to run on preemptive mode. Preemptive mode is the mode @@ -1596,12 +1599,6 @@ home directories that might be shared over the network. If set, extra checks are made during IO operations. Currently, this includes only advisory locks around file writes. .TP -\fBMONO_THEME\fR -The name of the theme to be used by Windows.Forms. Available themes today -include "clearlooks", "nice" and "win32". -.Sp -The default is "win32". -.TP \fBMONO_TLS_SESSION_CACHE_TIMEOUT\fR The time, in seconds, that the SSL/TLS session cache will keep it's entry to avoid a new negotiation between the client and a server. Negotiation are very diff --git a/mcs/build/common/Consts.cs b/mcs/build/common/Consts.cs index db5962eaad..8f0d92ea24 100644 --- a/mcs/build/common/Consts.cs +++ b/mcs/build/common/Consts.cs @@ -34,11 +34,11 @@ static class Consts // Use these assembly version constants to make code more maintainable. // - public const string MonoVersion = "5.12.0.234"; + public const string MonoVersion = "5.14.0.78"; public const string MonoCompany = "Mono development team"; public const string MonoProduct = "Mono Common Language Infrastructure"; public const string MonoCopyright = "(c) Various Mono authors"; - public const int MonoCorlibVersion = 1051200002; + public const int MonoCorlibVersion = 1051400003; #if MOBILE // Versions of .NET Framework for Silverlight 4.0 diff --git a/mcs/build/common/SR.cs b/mcs/build/common/SR.cs index a797d4bff6..a1e9cb0c1a 100644 --- a/mcs/build/common/SR.cs +++ b/mcs/build/common/SR.cs @@ -45,6 +45,8 @@ static partial class SR { return string.Format (CultureInfo.InvariantCulture, resourceFormat, p1, p2, p3); } + + internal static string GetResourceString (string str) => str; } #if !INSIDE_CORLIB diff --git a/mcs/build/common/basic-profile-check.cs b/mcs/build/common/basic-profile-check.cs index 9146477c4f..45050af7b2 100644 --- a/mcs/build/common/basic-profile-check.cs +++ b/mcs/build/common/basic-profile-check.cs @@ -42,9 +42,9 @@ class X { Version min_mono_version; #if __MonoCS__ - min_mono_version = new Version (5, 11); + min_mono_version = new Version (5, 13); #else - min_mono_version = new Version (4, 9); + min_mono_version = new Version (5, 10); #endif if (version < min_mono_version) diff --git a/mcs/build/config-default.make b/mcs/build/config-default.make index 124aafcecf..f9d2f21212 100644 --- a/mcs/build/config-default.make +++ b/mcs/build/config-default.make @@ -34,7 +34,8 @@ sysconfdir = $(prefix)/etc RUNTIME = false MONO_PATH_TOP = $(topdir)/class/lib/$(PROFILE_DIRECTORY)/ MONO_PATH_TESTS = $(MONO_PATH_TOP)/tests -TEST_RUNTIME = MONO_PATH="$(MONO_PATH_TOP)$(PLATFORM_PATH_SEPARATOR)$(TEST_MONO_PATH)$(PLATFORM_PATH_SEPARATOR)$(MONO_PATH_TESTS)$(PLATFORM_PATH_SEPARATOR).$(PLATFORM_PATH_SEPARATOR)$$MONO_PATH" $(RUNTIME) --debug +TEST_MONO_PATH = $(MONO_PATH_TOP)$(PLATFORM_PATH_SEPARATOR)$(MONO_PATH_TESTS) +TEST_RUNTIME = MONO_PATH="$(TEST_MONO_PATH)$(PLATFORM_PATH_SEPARATOR).$(PLATFORM_PATH_SEPARATOR)$$MONO_PATH" $(RUNTIME) --debug # In case you want to add MCS_FLAGS, this lets you not have to # keep track of the default value diff --git a/mcs/build/executable.make b/mcs/build/executable.make index 7ac941ca83..5a39dd9501 100644 --- a/mcs/build/executable.make +++ b/mcs/build/executable.make @@ -42,15 +42,17 @@ executable_CLEAN_FILES += $(build_lib) $(build_lib).so $(build_lib).mdb $(build_ makefrag = $(depsdir)/$(PROFILE)_$(base_prog).makefrag +LIB_REFS_ALL = $(DEFAULT_REFERENCES) $(LIB_REFS) + ifdef TARGET_NET_REFERENCE -# System.*.dll references come from the TARGET_NET_REFERENCE dir, others from the profile dir -LIB_REFS_MONO = $(call _FILTER_OUT,System,$(LIB_REFS)) -LIB_REFS_SYSTEM = $(filter-out $(LIB_REFS_MONO),$(LIB_REFS)) +# System*, mscorlib references come from the TARGET_NET_REFERENCE dir, others from the profile dir +LIB_REFS_MONO = $(call _FILTER_OUT,System,$(call _FILTER_OUT,mscorlib,$(LIB_REFS_ALL))) +LIB_REFS_SYSTEM = $(filter-out $(LIB_REFS_MONO),$(LIB_REFS_ALL)) MCS_REFERENCES = $(patsubst %,-r:$(topdir)/../external/binary-reference-assemblies/$(TARGET_NET_REFERENCE)/%.dll,$(LIB_REFS_SYSTEM)) MCS_REFERENCES += $(patsubst %,-r:$(topdir)/class/lib/$(PROFILE_DIRECTORY)/%.dll,$(LIB_REFS_MONO)) else -MCS_REFERENCES = $(patsubst %,-r:$(topdir)/class/lib/$(PROFILE_DIRECTORY)/%.dll,$(LIB_REFS)) +MCS_REFERENCES = $(patsubst %,-r:$(topdir)/class/lib/$(PROFILE_DIRECTORY)/%.dll,$(LIB_REFS_ALL)) endif ifdef KEYFILE diff --git a/mcs/build/library.make b/mcs/build/library.make index e7e1a556cc..5accc87be0 100644 --- a/mcs/build/library.make +++ b/mcs/build/library.make @@ -18,19 +18,19 @@ # Have to rename to handle differences between assembly/directory names DEP_LIBS=$(patsubst System.Xml,System.XML,$(LIB_REFS)) -LIB_REFS_FULL = $(call _FILTER_OUT,=, $(LIB_REFS)) +LIB_REFS_FULL = $(call _FILTER_OUT,=, $(LIB_REFS)) $(DEFAULT_REFERENCES) LIB_REFS_ALIAS = $(filter-out $(LIB_REFS_FULL),$(LIB_REFS)) ifdef TARGET_NET_REFERENCE -# System.*.dll references come from the TARGET_NET_REFERENCE dir, others from the profile dir -LIB_REFS_MONO_FULL = $(call _FILTER_OUT,System,$(LIB_REFS_FULL)) +# System*, mscorlib references come from the TARGET_NET_REFERENCE dir, others from the profile dir +LIB_REFS_MONO_FULL = $(call _FILTER_OUT,System,$(call _FILTER_OUT,mscorlib,$(LIB_REFS_FULL))) LIB_REFS_MONO_ALIAS = $(call _FILTER_OUT,System,$(LIB_REFS_ALIAS)) -LIB_REFS_SYSTEM_FULL = $(filter-out $(LIB_REFS_MONO_FULL),$(LIB_REFS_FULL)) -LIB_REFS_SYSTEM_ALIAS = $(filter-out $(LIB_REFS_MONO_ALIAS),$(LIB_REFS_ALIAS)) +LIB_REFS_NET_FULL = $(filter-out $(LIB_REFS_MONO_FULL),$(LIB_REFS_FULL)) +LIB_REFS_NET_ALIAS = $(filter-out $(LIB_REFS_MONO_ALIAS),$(LIB_REFS_ALIAS)) -LIB_MCS_FLAGS += $(patsubst %,-r:$(topdir)/../external/binary-reference-assemblies/$(TARGET_NET_REFERENCE)/%.dll,$(LIB_REFS_SYSTEM_FULL)) -LIB_MCS_FLAGS += $(patsubst %,-r:%.dll, $(subst =,=$(topdir)/../external/binary-reference-assemblies/$(TARGET_NET_REFERENCE)/,$(LIB_REFS_SYSTEM_ALIAS))) +LIB_MCS_FLAGS += $(patsubst %,-r:$(topdir)/../external/binary-reference-assemblies/$(TARGET_NET_REFERENCE)/%.dll,$(LIB_REFS_NET_FULL)) +LIB_MCS_FLAGS += $(patsubst %,-r:%.dll, $(subst =,=$(topdir)/../external/binary-reference-assemblies/$(TARGET_NET_REFERENCE)/,$(LIB_REFS_NET_ALIAS))) LIB_MCS_FLAGS += $(patsubst %,-r:$(topdir)/class/lib/$(PROFILE_DIRECTORY)/%.dll,$(LIB_REFS_MONO_FULL)) LIB_MCS_FLAGS += $(patsubst %,-r:%.dll, $(subst =,=$(topdir)/class/lib/$(PROFILE_DIRECTORY)/,$(LIB_REFS_MONO_ALIAS))) diff --git a/mcs/build/profiles/basic.make b/mcs/build/profiles/basic.make index 347b313308..3f85a63d0e 100644 --- a/mcs/build/profiles/basic.make +++ b/mcs/build/profiles/basic.make @@ -26,11 +26,13 @@ else endif endif +ILASM = $(PROFILE_RUNTIME) $(RUNTIME_FLAGS) $(topdir)/class/lib/$(BUILD_TOOLS_PROFILE)/ilasm.exe +STRING_REPLACER = $(PROFILE_RUNTIME) $(RUNTIME_FLAGS) $(topdir)/class/lib/$(BUILD_TOOLS_PROFILE)/tmp/cil-stringreplacer.exe MCS = $(BOOTSTRAP_MCS) -DEFAULT_REFERENCES = -r:$(topdir)/class/lib/$(PROFILE)/mscorlib.dll +DEFAULT_REFERENCES = mscorlib -PROFILE_MCS_FLAGS = -d:NET_4_0 -d:NET_4_5 -d:MONO -d:WIN_PLATFORM -d:BOOTSTRAP_BASIC -nowarn:1699 -nostdlib $(DEFAULT_REFERENCES) +PROFILE_MCS_FLAGS = -d:NET_4_0 -d:NET_4_5 -d:MONO -d:WIN_PLATFORM -d:BOOTSTRAP_BASIC -nowarn:1699 -nostdlib API_BIN_PROFILE = v4.7.1 NO_SIGN_ASSEMBLY = yes diff --git a/mcs/build/profiles/build.make b/mcs/build/profiles/build.make index a10cc31148..b152a3086d 100644 --- a/mcs/build/profiles/build.make +++ b/mcs/build/profiles/build.make @@ -13,8 +13,8 @@ PLATFORMS = darwin linux win32 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) +DEFAULT_REFERENCES = mscorlib +PROFILE_MCS_FLAGS = -d:NET_4_0 -d:NET_4_5 -d:MONO -d:WIN_PLATFORM -nowarn:1699 -nostdlib API_BIN_PROFILE = v4.7.1 NO_SIGN_ASSEMBLY = yes diff --git a/mcs/build/profiles/net_4_x.make b/mcs/build/profiles/net_4_x.make index 5463812acc..c9f491ed1d 100644 --- a/mcs/build/profiles/net_4_x.make +++ b/mcs/build/profiles/net_4_x.make @@ -12,8 +12,8 @@ PLATFORMS = darwin linux win32 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:WIN_PLATFORM -d:MULTIPLEX_OS -nowarn:1699 -nostdlib $(DEFAULT_REFERENCES) $(PLATFORM_DEBUG_FLAGS) +DEFAULT_REFERENCES = mscorlib +PROFILE_MCS_FLAGS = -d:NET_4_0 -d:NET_4_5 -d:NET_4_6 -d:MONO -d:WIN_PLATFORM -d:MULTIPLEX_OS -nowarn:1699 -nostdlib $(PLATFORM_DEBUG_FLAGS) API_BIN_PROFILE = v4.7.1 FRAMEWORK_VERSION = 4.5 diff --git a/mcs/build/profiles/xbuild_12.make b/mcs/build/profiles/xbuild_12.make index 2e66d59b31..842e64a2e0 100644 --- a/mcs/build/profiles/xbuild_12.make +++ b/mcs/build/profiles/xbuild_12.make @@ -5,7 +5,7 @@ include $(topdir)/build/profiles/net_4_x.make PLATFORMS:= PARENT_PROFILE = ../net_4_x$(if $(PROFILE_PLATFORM),-$(PROFILE_PLATFORM))/ -DEFAULT_REFERENCES = -r:$(topdir)/class/lib/net_4_x$(if $(PROFILE_PLATFORM),-$(PROFILE_PLATFORM))/mscorlib.dll +DEFAULT_REFERENCES = ../net_4_x/mscorlib PROFILE_MCS_FLAGS += -d:XBUILD_12 XBUILD_VERSION = 12.0 diff --git a/mcs/build/tests.make b/mcs/build/tests.make index a3592ff80a..63ecdd818a 100644 --- a/mcs/build/tests.make +++ b/mcs/build/tests.make @@ -25,8 +25,13 @@ xunit_deps := System.Runtime xunit_src := $(patsubst %,$(topdir)/../external/xunit-binaries/%,BenchmarkAttribute.cs BenchmarkDiscover.cs) $(topdir)/../mcs/class/test-helpers/PlatformDetection.cs ifeq ($(USE_XTEST_REMOTE_EXECUTOR), YES) -XTEST_REMOTE_EXECUTOR = $(xunit_test_lib)_RemoteExecuter.exe -xunit_src += $(topdir)/../mcs/class/test-helpers/AdminHelper.cs $(topdir)/../mcs/class/test-helpers/RemoteExecutorTestBase.Mono.cs $(topdir)/../external/corefx/src/CoreFx.Private.TestUtilities/src/System/IO/FileCleanupTestBase.cs $(topdir)/../external/corefx/src/CoreFx.Private.TestUtilities/src/System/Diagnostics/RemoteExecutorTestBase.Process.cs $(topdir)/../external/corefx/src/CoreFx.Private.TestUtilities/src/System/Diagnostics/RemoteExecutorTestBase.cs $(topdir)/../external/corefx/src/Common/src/System/PasteArguments.cs +XTEST_REMOTE_EXECUTOR = $(topdir)/class/lib/$(PROFILE)/RemoteExecutorConsoleApp.exe +xunit_src += $(topdir)/../mcs/class/test-helpers/AdminHelper.cs \ +$(topdir)/../mcs/class/test-helpers/RemoteExecutorTestBase.Mono.cs \ +$(topdir)/../external/corefx/src/CoreFx.Private.TestUtilities/src/System/IO/FileCleanupTestBase.cs \ +$(topdir)/../external/corefx/src/CoreFx.Private.TestUtilities/src/System/Diagnostics/RemoteExecutorTestBase.Process.cs \ +$(topdir)/../external/corefx/src/CoreFx.Private.TestUtilities/src/System/Diagnostics/RemoteExecutorTestBase.cs \ +$(topdir)/../external/corefx/src/Common/src/System/PasteArguments.cs endif xunit_class_deps := @@ -37,8 +42,8 @@ xunit_libs_ref += $(patsubst %,-r:$(topdir)/class/lib/$(PROFILE)/Facades/%.dll,$ xunit_libs_dep = $(xunit_class_deps:%=$(topdir)/class/lib/$(PROFILE)/$(PARENT_PROFILE)%.dll) xunit_libs_ref += $(xunit_libs_dep:%=-r:%) -TEST_LIB_MCS_FLAGS = $(patsubst %,-r:$(topdir)/class/lib/$(PROFILE)/%.dll,$(TEST_LIB_REFS)) -XTEST_LIB_MCS_FLAGS = $(patsubst %,-r:$(topdir)/class/lib/$(PROFILE)/%.dll,$(XTEST_LIB_REFS)) +TEST_LIB_MCS_FLAGS = $(patsubst %,-r:$(topdir)/class/lib/$(PROFILE)/%.dll,$(TEST_LIB_REFS) $(DEFAULT_REFERENCES)) +XTEST_LIB_MCS_FLAGS = $(patsubst %,-r:$(topdir)/class/lib/$(PROFILE)/%.dll,$(XTEST_LIB_REFS) $(DEFAULT_REFERENCES)) test_nunit_dep = $(test_nunit_lib:%=$(topdir)/class/lib/$(PROFILE)/$(PARENT_PROFILE)%) test_nunit_ref = $(test_nunit_dep:%=-r:%) @@ -200,7 +205,7 @@ ifneq ($(wildcard $(MKBUNDLE_TEST_BIN)),) TEST_HARNESS_EXEC=$(MKBUNDLE_TEST_BIN) TEST_HARNESS_EXCLUDES:=$(TEST_HARNESS_EXCLUDES),StaticLinkedAotNotWorking else -TEST_HARNESS_EXEC=$(TEST_RUNTIME) $(RUNTIME_FLAGS) $(TEST_COVERAGE_FLAGS) $(AOT_RUN_FLAGS) $(TEST_HARNESS) +TEST_HARNESS_EXEC=$(TEST_RUNTIME) $(TEST_RUNTIME_FLAGS) $(TEST_COVERAGE_FLAGS) $(AOT_RUN_FLAGS) $(TEST_HARNESS) endif ## FIXME: i18n problem in the 'sed' command below @@ -259,10 +264,11 @@ endif ifdef HAVE_CS_XTESTS -XTEST_HARNESS_PATH = $(topdir)/../external/xunit-binaries +XTEST_HARNESS_PATH := $(topdir)/../external/xunit-binaries XTEST_HARNESS = $(XTEST_HARNESS_PATH)/xunit.console.exe XTEST_HARNESS_FLAGS := -noappdomain -noshadow -parallel none -nunit TestResult-$(PROFILE)-xunit.xml XTEST_TRAIT := -notrait category=failing -notrait category=nonmonotests -notrait Benchmark=true -notrait category=outerloop +TEST_MONO_PATH := $(TEST_MONO_PATH)$(PLATFORM_PATH_SEPARATOR)$(XTEST_HARNESS_PATH) ifdef FIXTURE XTEST_HARNESS_FLAGS += -class $(FIXTURE) @@ -284,13 +290,13 @@ run-xunit-test-local: run-xunit-test-lib run-xunit-test-lib: xunit-test-local $(XTEST_REMOTE_EXECUTOR) @cp -rf $(XTEST_HARNESS_PATH)/xunit.execution.desktop.dll xunit.execution.desktop.dll ok=:; \ - PATH="$(TEST_RUNTIME_WRAPPERS_PATH):$(PATH)" $(TEST_RUNTIME) $(TEST_RUNTIME_FLAGS) $(XTEST_COVERAGE_FLAGS) $(AOT_RUN_FLAGS) $(XTEST_HARNESS) $(xunit_test_lib) $(XTEST_HARNESS_FLAGS) $(XTEST_TRAIT) || ok=false; \ + PATH="$(TEST_RUNTIME_WRAPPERS_PATH):$(PATH)" REMOTE_EXECUTOR=$(XTEST_REMOTE_EXECUTOR) $(TEST_RUNTIME) $(TEST_RUNTIME_FLAGS) $(XTEST_COVERAGE_FLAGS) $(AOT_RUN_FLAGS) $(XTEST_HARNESS) $(xunit_test_lib) $(XTEST_HARNESS_FLAGS) $(XTEST_TRAIT) || ok=false; \ $$ok @rm -f xunit.execution.desktop.dll # Some xunit tests want to be executed in a separate process (see RemoteExecutorTestBase) -$(XTEST_REMOTE_EXECUTOR): $(topdir)/../mcs/class/test-helpers/RemoteExecutorConsoleApp.cs - $(TEST_COMPILE) $(topdir)/../mcs/class/test-helpers/RemoteExecutorConsoleApp.cs -r:$(xunit_test_lib) $(xtest_flags) /debug- +$(XTEST_REMOTE_EXECUTOR): $(topdir)/../external/corefx/src/Common/tests/System/Diagnostics/RemoteExecutorConsoleApp/RemoteExecutorConsoleApp.cs + $(TEST_COMPILE) -r:$(topdir)/class/lib/$(PROFILE)/mscorlib.dll $< -out:$@ $(xunit_test_lib): $(the_assembly) $(xtest_response) $(xunit_libs_dep) $(xunit_src) $(TEST_COMPILE) $(LIBRARY_FLAGS) $(XTEST_LIB_FLAGS) -target:library -out:$@ $(xtest_flags) @$(xtest_response) $(xunit_src) diff --git a/mcs/class/Commons.Xml.Relaxng/Makefile b/mcs/class/Commons.Xml.Relaxng/Makefile index 1febae4eb1..f9b57fea26 100644 --- a/mcs/class/Commons.Xml.Relaxng/Makefile +++ b/mcs/class/Commons.Xml.Relaxng/Makefile @@ -22,7 +22,7 @@ EXTRA_DISTFILES = \ $(RESOURCE_FILES) Commons.Xml.Relaxng.Rnc/RncParser.cs: Commons.Xml.Relaxng.Rnc/RncParser.jay $(topdir)/jay/skeleton.cs - $(topdir)/jay/jay -ctv < $(topdir)/jay/skeleton.cs $(CURDIR)/Commons.Xml.Relaxng.Rnc/RncParser.jay > Commons.Xml.Relaxng.Rnc/RncParser.cs + $(topdir)/jay/jay -ctv -o Commons.Xml.Relaxng.Rnc/RncParser.cs $< < $(topdir)/jay/skeleton.cs BUILT_SOURCES = Commons.Xml.Relaxng.Rnc/RncParser.cs diff --git a/mcs/class/Cscompmgd/Test/Microsoft.CSharp/CompilerTest.cs b/mcs/class/Cscompmgd/Test/Microsoft.CSharp/CompilerTest.cs index b13ced3d46..3056d986f4 100644 --- a/mcs/class/Cscompmgd/Test/Microsoft.CSharp/CompilerTest.cs +++ b/mcs/class/Cscompmgd/Test/Microsoft.CSharp/CompilerTest.cs @@ -8,6 +8,7 @@ // using System; +using System.Collections.Generic; using Microsoft.CSharp; using NUnit.Framework; @@ -21,5 +22,11 @@ namespace MonoTests.Cscompmgd public void GetReady () { } + + [TestCase] + public void EmptySourceTexts () + { + Assert.Throws (() => Compiler.Compile (Array.Empty (), Array.Empty (), "", null, null)); + } } } diff --git a/mcs/class/Facades/Microsoft.Win32.Registry.AccessControl/Microsoft.Win32.Registry.AccessControl.dll.sources b/mcs/class/Facades/Microsoft.Win32.Registry.AccessControl/Microsoft.Win32.Registry.AccessControl.dll.sources index 0f59f0f2f4..eaf9a187ff 100644 --- a/mcs/class/Facades/Microsoft.Win32.Registry.AccessControl/Microsoft.Win32.Registry.AccessControl.dll.sources +++ b/mcs/class/Facades/Microsoft.Win32.Registry.AccessControl/Microsoft.Win32.Registry.AccessControl.dll.sources @@ -1,4 +1,4 @@ TypeForwarders.cs AssemblyInfo.cs -RegistryAclExtensions.cs +../../../../external/corefx/src/Microsoft.Win32.Registry.AccessControl/src/Microsoft/Win32/RegistryAclExtensions.cs diff --git a/mcs/class/Facades/Microsoft.Win32.Registry.AccessControl/RegistryAclExtensions.cs b/mcs/class/Facades/Microsoft.Win32.Registry.AccessControl/RegistryAclExtensions.cs deleted file mode 100644 index e32214de7d..0000000000 --- a/mcs/class/Facades/Microsoft.Win32.Registry.AccessControl/RegistryAclExtensions.cs +++ /dev/null @@ -1,63 +0,0 @@ -// -// RegistryAclExtensions.cs -// -// Author: -// Alexander Köplinger (alexander.koeplinger@xamarin.com) -// -// (C) 2016 Xamarin, Inc. -// - -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -using System; -using System.Security; -using System.Security.AccessControl; - -namespace Microsoft.Win32 -{ - public static class RegistryAclExtensions - { - public static RegistrySecurity GetAccessControl (this RegistryKey key) - { - if (key == null) - throw new ArgumentNullException (nameof (key)); - - return key.GetAccessControl (); - } - - public static RegistrySecurity GetAccessControl (this RegistryKey key, AccessControlSections includeSections) - { - if (key == null) - throw new ArgumentNullException (nameof (key)); - - return key.GetAccessControl (includeSections); - } - - public static void SetAccessControl (this RegistryKey key, RegistrySecurity registrySecurity) - { - if (key == null) - throw new ArgumentNullException (nameof (key)); - - key.SetAccessControl (registrySecurity); - } - } -} \ No newline at end of file diff --git a/mcs/class/Facades/System.Diagnostics.StackTrace/Makefile b/mcs/class/Facades/System.Diagnostics.StackTrace/Makefile index f7f79d2545..5e04aa4257 100644 --- a/mcs/class/Facades/System.Diagnostics.StackTrace/Makefile +++ b/mcs/class/Facades/System.Diagnostics.StackTrace/Makefile @@ -14,6 +14,8 @@ SIGN_FLAGS = /delaysign /nowarn:1616,1699 LIB_REFS = System LIB_MCS_FLAGS = $(SIGN_FLAGS) +PLATFORM_DEBUG_FLAGS = + NO_TEST = yes include $(MCS_BUILD_DIR)/library.make diff --git a/mcs/class/Facades/System.Diagnostics.StackTrace/StackFrameExtensions.cs b/mcs/class/Facades/System.Diagnostics.StackTrace/StackFrameExtensions.cs deleted file mode 100644 index 0b5d548674..0000000000 --- a/mcs/class/Facades/System.Diagnostics.StackTrace/StackFrameExtensions.cs +++ /dev/null @@ -1,91 +0,0 @@ -// -// StackFrameExtensions.cs -// -// Author: -// Alexander Köplinger (alexander.koeplinger@xamarin.com) -// -// (C) 2016 Xamarin, Inc. -// - -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -using System; - -namespace System.Diagnostics -{ - public static class StackFrameExtensions - { - [MonoTODO] - public static IntPtr GetNativeImageBase (this StackFrame stackFrame) - { - if (stackFrame == null) - throw new ArgumentNullException (nameof (stackFrame)); - - throw new NotImplementedException (); - } - - [MonoTODO] - public static IntPtr GetNativeIP (this StackFrame stackFrame) - { - if (stackFrame == null) - throw new ArgumentNullException (nameof (stackFrame)); - - throw new NotImplementedException (); - } - - [MonoTODO] - public static bool HasNativeImage (this StackFrame stackFrame) - { - if (stackFrame == null) - throw new ArgumentNullException (nameof (stackFrame)); - - throw new NotImplementedException (); - } - - [MonoTODO] - public static bool HasMethod (this StackFrame stackFrame) - { - if (stackFrame == null) - throw new ArgumentNullException (nameof (stackFrame)); - - throw new NotImplementedException (); - } - - [MonoTODO] - public static bool HasILOffset (this StackFrame stackFrame) - { - if (stackFrame == null) - throw new ArgumentNullException (nameof (stackFrame)); - - throw new NotImplementedException (); - } - - [MonoTODO] - public static bool HasSource (this StackFrame stackFrame) - { - if (stackFrame == null) - throw new ArgumentNullException (nameof (stackFrame)); - - throw new NotImplementedException (); - } - } -} \ No newline at end of file diff --git a/mcs/class/Facades/System.Diagnostics.StackTrace/System.Diagnostics.StackTrace.dll.sources b/mcs/class/Facades/System.Diagnostics.StackTrace/System.Diagnostics.StackTrace.dll.sources index 9d113cec20..719628dc7c 100644 --- a/mcs/class/Facades/System.Diagnostics.StackTrace/System.Diagnostics.StackTrace.dll.sources +++ b/mcs/class/Facades/System.Diagnostics.StackTrace/System.Diagnostics.StackTrace.dll.sources @@ -1,5 +1,2 @@ TypeForwarders.cs AssemblyInfo.cs - -../../../build/common/MonoTODOAttribute.cs -StackFrameExtensions.cs diff --git a/mcs/class/Facades/System.Diagnostics.StackTrace/TypeForwarders.cs b/mcs/class/Facades/System.Diagnostics.StackTrace/TypeForwarders.cs index b68327ecf2..56bf3a45c8 100644 --- a/mcs/class/Facades/System.Diagnostics.StackTrace/TypeForwarders.cs +++ b/mcs/class/Facades/System.Diagnostics.StackTrace/TypeForwarders.cs @@ -21,6 +21,7 @@ // [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.StackFrame))] +[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.StackFrameExtensions))] [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.StackTrace))] [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.SymbolStore.ISymbolBinder))] [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Diagnostics.SymbolStore.ISymbolBinder1))] diff --git a/mcs/class/Facades/System.Globalization.Extensions/Makefile b/mcs/class/Facades/System.Globalization.Extensions/Makefile index 8827c29172..892938a42b 100644 --- a/mcs/class/Facades/System.Globalization.Extensions/Makefile +++ b/mcs/class/Facades/System.Globalization.Extensions/Makefile @@ -14,6 +14,8 @@ SIGN_FLAGS = /delaysign /nowarn:1616,1699 LIB_REFS = System LIB_MCS_FLAGS = $(SIGN_FLAGS) +PLATFORM_DEBUG_FLAGS = + NO_TEST = yes include $(MCS_BUILD_DIR)/library.make diff --git a/mcs/class/Facades/System.Globalization.Extensions/SR.cs b/mcs/class/Facades/System.Globalization.Extensions/SR.cs deleted file mode 100644 index 52a75a8e6d..0000000000 --- a/mcs/class/Facades/System.Globalization.Extensions/SR.cs +++ /dev/null @@ -1,4 +0,0 @@ -partial class SR -{ - public const string Argument_InvalidFlag = "Value of flags is invalid."; -} \ No newline at end of file diff --git a/mcs/class/Facades/System.Globalization.Extensions/System.Globalization.Extensions.dll.sources b/mcs/class/Facades/System.Globalization.Extensions/System.Globalization.Extensions.dll.sources index 2c74bf66c4..719628dc7c 100644 --- a/mcs/class/Facades/System.Globalization.Extensions/System.Globalization.Extensions.dll.sources +++ b/mcs/class/Facades/System.Globalization.Extensions/System.Globalization.Extensions.dll.sources @@ -1,6 +1,2 @@ TypeForwarders.cs AssemblyInfo.cs - -SR.cs -../../../../external/corefx/src/System.Runtime.Extensions/src/System/Globalization/Extensions.cs -../../../../external/corefx/src/System.Runtime.Extensions/src/System/StringNormalizationExtensions.cs diff --git a/mcs/class/Facades/System.Globalization.Extensions/TypeForwarders.cs b/mcs/class/Facades/System.Globalization.Extensions/TypeForwarders.cs index ae5a0bbb41..74626bc238 100644 --- a/mcs/class/Facades/System.Globalization.Extensions/TypeForwarders.cs +++ b/mcs/class/Facades/System.Globalization.Extensions/TypeForwarders.cs @@ -20,5 +20,7 @@ // THE SOFTWARE. // +[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Globalization.GlobalizationExtensions))] [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Globalization.IdnMapping))] +[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.StringNormalizationExtensions))] [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Text.NormalizationForm))] diff --git a/mcs/class/Facades/System.IO.FileSystem.AccessControl/FileSystemAclExtensions.cs b/mcs/class/Facades/System.IO.FileSystem.AccessControl/FileSystemAclExtensions.cs deleted file mode 100644 index 6baeefd5dd..0000000000 --- a/mcs/class/Facades/System.IO.FileSystem.AccessControl/FileSystemAclExtensions.cs +++ /dev/null @@ -1,101 +0,0 @@ -// -// FileSystemAclExtensions.cs -// -// Author: -// Alexander Köplinger (alexander.koeplinger@xamarin.com) -// -// (C) 2016 Xamarin, Inc. -// - -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -using System.Security.AccessControl; - -namespace System.IO -{ - public static class FileSystemAclExtensions - { - public static DirectorySecurity GetAccessControl(this DirectoryInfo directoryInfo) - { - if (directoryInfo == null) - throw new ArgumentNullException (nameof (directoryInfo)); - - return directoryInfo.GetAccessControl (); - } - - public static DirectorySecurity GetAccessControl(this DirectoryInfo directoryInfo, AccessControlSections includeSections) - { - if (directoryInfo == null) - throw new ArgumentNullException (nameof (directoryInfo)); - - return directoryInfo.GetAccessControl (includeSections); - } - - public static FileSecurity GetAccessControl(this FileInfo fileInfo) - { - if (fileInfo == null) - throw new ArgumentNullException (nameof (fileInfo)); - - return fileInfo.GetAccessControl (); - } - - public static FileSecurity GetAccessControl(this FileInfo fileInfo, AccessControlSections includeSections) - { - if (fileInfo == null) - throw new ArgumentNullException (nameof (fileInfo)); - - return fileInfo.GetAccessControl (includeSections); - } - - public static FileSecurity GetAccessControl(this FileStream fileStream) - { - if (fileStream == null) - throw new ArgumentNullException (nameof (fileStream)); - - return fileStream.GetAccessControl (); - } - - public static void SetAccessControl(this DirectoryInfo directoryInfo, DirectorySecurity directorySecurity) - { - if (directoryInfo == null) - throw new ArgumentNullException (nameof (directoryInfo)); - - directoryInfo.SetAccessControl (directorySecurity); - } - - public static void SetAccessControl(this FileInfo fileInfo, FileSecurity fileSecurity) - { - if (fileInfo == null) - throw new ArgumentNullException (nameof (fileInfo)); - - fileInfo.SetAccessControl (fileSecurity); - } - - public static void SetAccessControl(this FileStream fileStream, FileSecurity fileSecurity) - { - if (fileStream == null) - throw new ArgumentNullException (nameof (fileStream)); - - fileStream.SetAccessControl (fileSecurity); - } - } -} \ No newline at end of file diff --git a/mcs/class/Facades/System.IO.FileSystem.AccessControl/System.IO.FileSystem.AccessControl.dll.sources b/mcs/class/Facades/System.IO.FileSystem.AccessControl/System.IO.FileSystem.AccessControl.dll.sources index d226e0d4c8..d89d8bd19b 100644 --- a/mcs/class/Facades/System.IO.FileSystem.AccessControl/System.IO.FileSystem.AccessControl.dll.sources +++ b/mcs/class/Facades/System.IO.FileSystem.AccessControl/System.IO.FileSystem.AccessControl.dll.sources @@ -1,5 +1,4 @@ TypeForwarders.cs AssemblyInfo.cs -../../../build/common/MonoTODOAttribute.cs -FileSystemAclExtensions.cs +../../../../external/corefx/src/System.IO.FileSystem.AccessControl/src/System/IO/FileSystemAclExtensions.net46.cs diff --git a/mcs/class/Facades/System.Reflection.Emit.Lightweight/System.Reflection.Emit.Lightweight.dll.sources b/mcs/class/Facades/System.Reflection.Emit.Lightweight/System.Reflection.Emit.Lightweight.dll.sources index 5d40b81fbf..719628dc7c 100644 --- a/mcs/class/Facades/System.Reflection.Emit.Lightweight/System.Reflection.Emit.Lightweight.dll.sources +++ b/mcs/class/Facades/System.Reflection.Emit.Lightweight/System.Reflection.Emit.Lightweight.dll.sources @@ -1,3 +1,2 @@ TypeForwarders.cs AssemblyInfo.cs -DynamicMethod.cs diff --git a/mcs/class/Facades/System.Reflection.Emit.Lightweight/TypeForwarders.cs b/mcs/class/Facades/System.Reflection.Emit.Lightweight/TypeForwarders.cs index 9fca03abaf..8cb053efa5 100644 --- a/mcs/class/Facades/System.Reflection.Emit.Lightweight/TypeForwarders.cs +++ b/mcs/class/Facades/System.Reflection.Emit.Lightweight/TypeForwarders.cs @@ -20,6 +20,4 @@ // THE SOFTWARE. // -#if !FULL_AOT_RUNTIME [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Reflection.Emit.DynamicMethod))] -#endif diff --git a/mcs/class/Facades/System.Runtime.Loader/System.Runtime.Loader.dll.sources b/mcs/class/Facades/System.Runtime.Loader/System.Runtime.Loader.dll.sources index adf4e593e3..566d59840c 100644 --- a/mcs/class/Facades/System.Runtime.Loader/System.Runtime.Loader.dll.sources +++ b/mcs/class/Facades/System.Runtime.Loader/System.Runtime.Loader.dll.sources @@ -1,3 +1,3 @@ AssemblyInfo.cs -AssemblyExtensions.cs AssemblyLoadContext.cs +TypeForwarders.cs diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/IBounds.cs b/mcs/class/Facades/System.Runtime.Loader/TypeForwarders.cs similarity index 79% rename from mcs/class/System.Windows.Forms/System.Windows.Forms/IBounds.cs rename to mcs/class/Facades/System.Runtime.Loader/TypeForwarders.cs index 9d06790c83..21225c007a 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/IBounds.cs +++ b/mcs/class/Facades/System.Runtime.Loader/TypeForwarders.cs @@ -1,5 +1,5 @@ -// -// IBounds.cs +// +// Copyright (C) 2018 Microsoft Corporation (http://www.microsoft.com) // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -20,21 +20,5 @@ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -// Copyright (c) 2008 Novell, Inc. -// -// Authors: -// Jonathan Pobst (monkey@jpobst.com) -// -using System; -using System.Collections.Generic; -using System.Text; -using System.Drawing; - -namespace System.Windows.Forms -{ - interface IBounds - { - Rectangle Bounds { get; } - } -} +[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Reflection.Metadata.AssemblyExtensions))] diff --git a/mcs/class/Facades/System.Runtime.Serialization.Primitives/System.Runtime.Serialization.Primitives.dll.sources b/mcs/class/Facades/System.Runtime.Serialization.Primitives/System.Runtime.Serialization.Primitives.dll.sources index fd4c99b18a..719628dc7c 100644 --- a/mcs/class/Facades/System.Runtime.Serialization.Primitives/System.Runtime.Serialization.Primitives.dll.sources +++ b/mcs/class/Facades/System.Runtime.Serialization.Primitives/System.Runtime.Serialization.Primitives.dll.sources @@ -1,4 +1,2 @@ TypeForwarders.cs AssemblyInfo.cs - -../../../../external/corefx/src/System.Runtime.Serialization.Primitives/src/System/Runtime/Serialization/ISerializationSurrogateProvider.cs diff --git a/mcs/class/Facades/System.Runtime.Serialization.Primitives/TypeForwarders.cs b/mcs/class/Facades/System.Runtime.Serialization.Primitives/TypeForwarders.cs index ea71c80449..8768234c08 100644 --- a/mcs/class/Facades/System.Runtime.Serialization.Primitives/TypeForwarders.cs +++ b/mcs/class/Facades/System.Runtime.Serialization.Primitives/TypeForwarders.cs @@ -30,6 +30,7 @@ [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.IExtensibleDataObject))] [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.IgnoreDataMemberAttribute))] [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.InvalidDataContractException))] +[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.ISerializationSurrogateProvider))] [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.KnownTypeAttribute))] [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.OnDeserializedAttribute))] [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.OnDeserializingAttribute))] diff --git a/mcs/class/Facades/System.Runtime.Serialization.Xml/Makefile b/mcs/class/Facades/System.Runtime.Serialization.Xml/Makefile index b1ac8e4fa8..33067e02f9 100644 --- a/mcs/class/Facades/System.Runtime.Serialization.Xml/Makefile +++ b/mcs/class/Facades/System.Runtime.Serialization.Xml/Makefile @@ -14,9 +14,7 @@ SIGN_FLAGS = /delaysign /nowarn:1616,1699 LIB_REFS = System System.Runtime.Serialization System.Xml Facades/System.Runtime.Serialization.Primitives LIB_MCS_FLAGS = $(SIGN_FLAGS) -ifeq (2.1, $(FRAMEWORK_VERSION)) -LIB_MCS_FLAGS += /d:NO_CODEDOM -endif +PLATFORM_DEBUG_FLAGS = NO_TEST = yes diff --git a/mcs/class/Facades/System.Runtime.Serialization.Xml/System.Runtime.Serialization.Xml.dll.sources b/mcs/class/Facades/System.Runtime.Serialization.Xml/System.Runtime.Serialization.Xml.dll.sources index d23128800b..719628dc7c 100644 --- a/mcs/class/Facades/System.Runtime.Serialization.Xml/System.Runtime.Serialization.Xml.dll.sources +++ b/mcs/class/Facades/System.Runtime.Serialization.Xml/System.Runtime.Serialization.Xml.dll.sources @@ -1,6 +1,2 @@ TypeForwarders.cs AssemblyInfo.cs - - -DataContractSerializerExtensions.cs -NotImplemented.cs diff --git a/mcs/class/Facades/System.Runtime.Serialization.Xml/TypeForwarders.cs b/mcs/class/Facades/System.Runtime.Serialization.Xml/TypeForwarders.cs index 38eea612a4..9f193bb93a 100644 --- a/mcs/class/Facades/System.Runtime.Serialization.Xml/TypeForwarders.cs +++ b/mcs/class/Facades/System.Runtime.Serialization.Xml/TypeForwarders.cs @@ -22,6 +22,7 @@ [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.DataContractResolver))] [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.DataContractSerializer))] +[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.DataContractSerializerExtensions))] [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.DataContractSerializerSettings))] [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.InvalidDataContractException))] [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.Serialization.XmlObjectSerializer))] diff --git a/mcs/class/Facades/System.Security.Cryptography.Algorithms/Makefile b/mcs/class/Facades/System.Security.Cryptography.Algorithms/Makefile index e7340a15c4..9e2f691b37 100644 --- a/mcs/class/Facades/System.Security.Cryptography.Algorithms/Makefile +++ b/mcs/class/Facades/System.Security.Cryptography.Algorithms/Makefile @@ -14,6 +14,8 @@ SIGN_FLAGS = /delaysign /nowarn:1616,1699 LIB_REFS = System System.Core LIB_MCS_FLAGS = $(SIGN_FLAGS) +PLATFORM_DEBUG_FLAGS = + NO_TEST = yes include $(MCS_BUILD_DIR)/library.make diff --git a/mcs/class/Facades/System.Security.Cryptography.Algorithms/SR.cs b/mcs/class/Facades/System.Security.Cryptography.Algorithms/SR.cs deleted file mode 100644 index 6b71c9563d..0000000000 --- a/mcs/class/Facades/System.Security.Cryptography.Algorithms/SR.cs +++ /dev/null @@ -1,10 +0,0 @@ -// -// This file was generated by resx2sr tool -// - -partial class SR -{ - public const string ArgumentOutOfRange_NeedNonNegNum = "Non-negative number required."; - public const string Argument_InvalidOffLen = "Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection."; - public const string Cryptography_HashAlgorithmNameNullOrEmpty = "The hash algorithm name cannot be null or empty."; -} diff --git a/mcs/class/Facades/System.Security.Cryptography.Algorithms/System.Security.Cryptography.Algorithms.dll.sources b/mcs/class/Facades/System.Security.Cryptography.Algorithms/System.Security.Cryptography.Algorithms.dll.sources index bc50224ae2..719628dc7c 100644 --- a/mcs/class/Facades/System.Security.Cryptography.Algorithms/System.Security.Cryptography.Algorithms.dll.sources +++ b/mcs/class/Facades/System.Security.Cryptography.Algorithms/System.Security.Cryptography.Algorithms.dll.sources @@ -1,4 +1,2 @@ TypeForwarders.cs AssemblyInfo.cs -SR.cs -../../../../external/corefx/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/IncrementalHash.net46.cs diff --git a/mcs/class/Facades/System.Security.Cryptography.Algorithms/TypeForwarders.cs b/mcs/class/Facades/System.Security.Cryptography.Algorithms/TypeForwarders.cs index 2a7c09f471..10ded3bedd 100644 --- a/mcs/class/Facades/System.Security.Cryptography.Algorithms/TypeForwarders.cs +++ b/mcs/class/Facades/System.Security.Cryptography.Algorithms/TypeForwarders.cs @@ -43,6 +43,7 @@ [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.HMACSHA256))] [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.HMACSHA384))] [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.HMACSHA512))] +[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.IncrementalHash))] [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.MaskGenerationMethod))] [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.MD5))] [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.Cryptography.PKCS1MaskGenerationMethod))] diff --git a/mcs/class/Facades/System.Security.SecureString/Makefile b/mcs/class/Facades/System.Security.SecureString/Makefile index c195a70652..4c72aaa63c 100644 --- a/mcs/class/Facades/System.Security.SecureString/Makefile +++ b/mcs/class/Facades/System.Security.SecureString/Makefile @@ -14,6 +14,8 @@ SIGN_FLAGS = /delaysign /nowarn:1616,1699 LIB_REFS = System LIB_MCS_FLAGS = $(SIGN_FLAGS) +PLATFORM_DEBUG_FLAGS = + NO_TEST = yes include $(MCS_BUILD_DIR)/library.make diff --git a/mcs/class/Facades/System.Security.SecureString/System.Security.SecureString.dll.sources b/mcs/class/Facades/System.Security.SecureString/System.Security.SecureString.dll.sources index d12a84b6ab..719628dc7c 100644 --- a/mcs/class/Facades/System.Security.SecureString/System.Security.SecureString.dll.sources +++ b/mcs/class/Facades/System.Security.SecureString/System.Security.SecureString.dll.sources @@ -1,3 +1,2 @@ TypeForwarders.cs AssemblyInfo.cs -../../../../external/corefx/src/System.Runtime.InteropServices/src/System/Security/SecureStringMarshal.cs diff --git a/mcs/class/Facades/System.Security.SecureString/TypeForwarders.cs b/mcs/class/Facades/System.Security.SecureString/TypeForwarders.cs index 4267f40e03..e34303ce19 100644 --- a/mcs/class/Facades/System.Security.SecureString/TypeForwarders.cs +++ b/mcs/class/Facades/System.Security.SecureString/TypeForwarders.cs @@ -21,3 +21,4 @@ // [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.SecureString))] +[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Security.SecureStringMarshal))] diff --git a/mcs/class/Facades/System.Threading.AccessControl/System.Threading.AccessControl.dll.sources b/mcs/class/Facades/System.Threading.AccessControl/System.Threading.AccessControl.dll.sources index 1b04113e43..20497b8477 100644 --- a/mcs/class/Facades/System.Threading.AccessControl/System.Threading.AccessControl.dll.sources +++ b/mcs/class/Facades/System.Threading.AccessControl/System.Threading.AccessControl.dll.sources @@ -1,4 +1,4 @@ TypeForwarders.cs AssemblyInfo.cs -ThreadingAclExtensions.cs +../../../../external/corefx/src/System.Threading.AccessControl/src/System/Threading/ThreadingAclExtensions.net46.cs diff --git a/mcs/class/Facades/System.Threading.AccessControl/ThreadingAclExtensions.cs b/mcs/class/Facades/System.Threading.AccessControl/ThreadingAclExtensions.cs deleted file mode 100644 index 99b03b28ed..0000000000 --- a/mcs/class/Facades/System.Threading.AccessControl/ThreadingAclExtensions.cs +++ /dev/null @@ -1,87 +0,0 @@ -// -// ThreadingAclExtensions.cs -// -// Author: -// Alexander Köplinger (alexander.koeplinger@xamarin.com) -// -// (C) 2016 Xamarin, Inc. -// - -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -using System; -using System.Security.AccessControl; -using System.Diagnostics.Contracts; - -namespace System.Threading -{ - public static class ThreadingAclExtensions - { - public static EventWaitHandleSecurity GetAccessControl (this EventWaitHandle handle) - { - if (handle == null) - throw new ArgumentNullException (nameof (handle)); - - return handle.GetAccessControl (); - } - - public static void SetAccessControl (this EventWaitHandle handle, EventWaitHandleSecurity eventSecurity) - { - if (handle == null) - throw new ArgumentNullException (nameof (handle)); - - handle.SetAccessControl (eventSecurity); - } - - public static MutexSecurity GetAccessControl (this Mutex mutex) - { - if (mutex == null) - throw new ArgumentNullException (nameof (mutex)); - - return mutex.GetAccessControl (); - } - - public static void SetAccessControl (this Mutex mutex, MutexSecurity mutexSecurity) - { - if (mutex == null) - throw new ArgumentNullException (nameof (mutex)); - - mutex.SetAccessControl (mutexSecurity); - } - - public static SemaphoreSecurity GetAccessControl (this Semaphore semaphore) - { - if (semaphore == null) - throw new ArgumentNullException (nameof (semaphore)); - - return semaphore.GetAccessControl (); - } - - public static void SetAccessControl (this Semaphore semaphore, SemaphoreSecurity semaphoreSecurity) - { - if (semaphore == null) - throw new ArgumentNullException (nameof (semaphore)); - - semaphore.SetAccessControl (semaphoreSecurity); - } - } -} \ No newline at end of file diff --git a/mcs/class/Facades/System.Xml.XPath.XDocument/Makefile b/mcs/class/Facades/System.Xml.XPath.XDocument/Makefile index 90037087ee..bff17d88f6 100644 --- a/mcs/class/Facades/System.Xml.XPath.XDocument/Makefile +++ b/mcs/class/Facades/System.Xml.XPath.XDocument/Makefile @@ -14,6 +14,8 @@ SIGN_FLAGS = /delaysign /nowarn:1616,1699 LIB_REFS = System System.Xml System.Xml.Linq LIB_MCS_FLAGS = $(SIGN_FLAGS) +PLATFORM_DEBUG_FLAGS = + NO_TEST = yes include $(MCS_BUILD_DIR)/library.make diff --git a/mcs/class/Facades/System.Xml.XPath.XDocument/System.Xml.XPath.XDocument.dll.sources b/mcs/class/Facades/System.Xml.XPath.XDocument/System.Xml.XPath.XDocument.dll.sources index 09a30c584f..719628dc7c 100644 --- a/mcs/class/Facades/System.Xml.XPath.XDocument/System.Xml.XPath.XDocument.dll.sources +++ b/mcs/class/Facades/System.Xml.XPath.XDocument/System.Xml.XPath.XDocument.dll.sources @@ -1,3 +1,2 @@ TypeForwarders.cs AssemblyInfo.cs -../../../../external/corefx/src/System.Xml.XPath.XDocument/src/System/Xml/XPath/XDocumentExtensions.cs diff --git a/mcs/class/Facades/System.Xml.XPath.XDocument/TypeForwarders.cs b/mcs/class/Facades/System.Xml.XPath.XDocument/TypeForwarders.cs index 0fec9f720b..5543b7de96 100644 --- a/mcs/class/Facades/System.Xml.XPath.XDocument/TypeForwarders.cs +++ b/mcs/class/Facades/System.Xml.XPath.XDocument/TypeForwarders.cs @@ -21,4 +21,4 @@ // [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Xml.XPath.Extensions))] - +[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Xml.XPath.XDocumentExtensions))] diff --git a/mcs/class/I18N/Rare/I18N.Rare_test.dll.sources b/mcs/class/I18N/Rare/I18N.Rare_test.dll.sources index 2a58d9447e..e787b1805c 100644 --- a/mcs/class/I18N/Rare/I18N.Rare_test.dll.sources +++ b/mcs/class/I18N/Rare/I18N.Rare_test.dll.sources @@ -1,2 +1,3 @@ ../../EncodingTestBase.cs I18N.Rare.EncodingTest.cs +I18N.Rare.Test.cs diff --git a/mcs/class/I18N/Rare/Makefile b/mcs/class/I18N/Rare/Makefile index a2863e797c..0eb6f79717 100644 --- a/mcs/class/I18N/Rare/Makefile +++ b/mcs/class/I18N/Rare/Makefile @@ -8,6 +8,7 @@ KEYFILE = ../../mono.pub LOCAL_MCS_FLAGS = /unsafe TEST_LIB_REFS = I18N -EXTRA_DISTFILES = $(wildcard *.ucm) +EXTRA_DISTFILES = $(wildcard *.ucm) \ + $(wildcard Test/texts/*.txt) include ../../../build/library.make diff --git a/mcs/class/I18N/Rare/Test/I18N.Rare.Test.cs b/mcs/class/I18N/Rare/Test/I18N.Rare.Test.cs new file mode 100644 index 0000000000..efdc5f7ad5 --- /dev/null +++ b/mcs/class/I18N/Rare/Test/I18N.Rare.Test.cs @@ -0,0 +1,74 @@ +// +// I18N.Rare.Test.cs +// +// Author: +// Alexander Köplinger (alexander.koeplinger@xamarin.com) +// +// Copyright (C) 2018 Microsoft +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.IO; +using System.Text; +using NUnit.Framework; + +namespace MonoTests.I18N.Rare +{ + [TestFixture] + public class TestRare + { + private global::I18N.Common.Manager Manager = global::I18N.Common.Manager.PrimaryManager; + + // ASCII compatible Rare codepages + int[] cps = { 708, 852, 855, 857, 858, 862, 864, 866, 869 }; + + void AssertDecode (string utf8file, string decfile, int codepage) + { + string decoded = null; + byte [] encoded = null; + using (StreamReader sr = new StreamReader (utf8file, + Encoding.UTF8)) { + decoded = sr.ReadToEnd (); + } + using (FileStream fs = File.OpenRead (decfile)) { + encoded = new byte [fs.Length]; + fs.Read (encoded, 0, (int) fs.Length); + } + Encoding enc = Manager.GetEncoding (codepage); + char [] actual; + + Assert.AreEqual (decoded.Length, + enc.GetCharCount (encoded, 0, encoded.Length), + "GetCharCount(byte[], 0, len)"); + actual = enc.GetChars (encoded, 0, encoded.Length); + Assert.AreEqual (decoded.ToCharArray (), actual, + "GetChars(byte[], 0, len)"); + } + + [Test] + [TestCaseSource (nameof (cps))] + public void Ascii_Test_All(int cp) + { + AssertDecode("Test/texts/ascii-test.txt", "Test/texts/ascii-test.txt", cp); + } + } +} diff --git a/mcs/class/I18N/Rare/Test/texts/ascii-test.txt b/mcs/class/I18N/Rare/Test/texts/ascii-test.txt new file mode 100644 index 0000000000..1dcfb42a86 --- /dev/null +++ b/mcs/class/I18N/Rare/Test/texts/ascii-test.txt @@ -0,0 +1 @@ +begin123end diff --git a/mcs/class/Makefile b/mcs/class/Makefile index 13d7aae287..8345de4ee1 100644 --- a/mcs/class/Makefile +++ b/mcs/class/Makefile @@ -14,6 +14,7 @@ basic_SUBDIRS := \ Mono.Security \ System \ System.XML \ + System.Security \ System.Core \ System.ComponentModel.Composition.4.5 \ System.Numerics \ @@ -31,8 +32,10 @@ build_SUBDIRS := \ Mono.Security \ System \ System.XML \ + System.Security \ Mono.Posix \ System.Core \ + System.Configuration \ System.ComponentModel.Composition.4.5 \ System.Numerics \ System.Xml.Linq \ @@ -45,8 +48,8 @@ build_SUBDIRS := \ ../tools/cil-stringreplacer ifdef MCS_MODE -basic_PARALLEL_SUBDIRS := ../mcs -build_PARALLEL_SUBDIRS := ../mcs +basic_PARALLEL_SUBDIRS := ../mcs $(pcl_facade_dirs) +build_PARALLEL_SUBDIRS := ../mcs $(pcl_facade_dirs) else basic_PARALLEL_SUBDIRS := $(pcl_facade_dirs) build_PARALLEL_SUBDIRS := $(pcl_facade_dirs) @@ -57,8 +60,8 @@ mobile_common_dirs := \ Mono.Security \ System \ System.Core \ - System.Security \ System.XML \ + System.Security \ I18N \ System.ServiceModel.Internals \ System.Runtime.Serialization \ @@ -154,10 +157,11 @@ xammac_4_5_dirs := \ corlib \ Mono.Security \ System \ - Mono.Posix \ - System.Core \ + System.XML \ System.Security \ - System.XML \ + Mono.Posix \ + System.Core \ + System.Configuration \ I18N \ System.ServiceModel.Internals \ SMDiagnostics \ @@ -204,10 +208,10 @@ net_4_x_dirs := \ Mono.Security \ System \ System.XML \ + System.Security \ Mono.CompilerServices.SymbolWriter \ Mono.Posix \ System.Core \ - System.Security \ System.Configuration \ System.Drawing \ System.IO.Compression \ @@ -227,9 +231,9 @@ net_4_x_dirs := \ System.Web.ApplicationServices \ Novell.Directory.Ldap \ System.DirectoryServices \ - System.Web \ - System.Web.Services \ System.Design \ + System.Web.Services \ + System.Web \ System.Runtime.Remoting \ System.Configuration.Install \ System.Management \ @@ -418,8 +422,8 @@ all-local-aot: monolite_dir = monolite-$(HOST_PLATFORM)/$(MONO_CORLIB_VERSION) -# Files needed to bootstrap C# compiler -build_files = mscorlib.dll System.dll System.Xml.dll Mono.Security.dll System.Core.dll System.Security.dll System.Configuration.dll \ +# Files needed to bootstrap C# compiler and cil-stringreplacer +build_files := mscorlib.dll System.dll System.Xml.dll Mono.Security.dll System.Core.dll System.Security.dll System.Configuration.dll \ System.Numerics.dll System.Xml.Linq.dll \ Facades/System.Collections.Concurrent.dll Facades/System.Linq.dll Facades/System.Runtime.dll Facades/System.Collections.dll \ Facades/System.Reflection.Extensions.dll Facades/System.Text.Encoding.Extensions.dll Facades/System.Diagnostics.Debug.dll \ @@ -429,7 +433,8 @@ build_files = mscorlib.dll System.dll System.Xml.dll Mono.Security.dll System.Co Facades/System.IO.dll Facades/System.Runtime.InteropServices.dll Facades/System.Xml.ReaderWriter.dll Facades/System.Linq.Expressions.dll \ Facades/System.Runtime.Numerics.dll Facades/System.Xml.XDocument.dll Facades/System.IO.FileSystem.Primitives.dll Facades/System.IO.FileSystem.dll \ Facades/System.Diagnostics.FileVersionInfo.dll Facades/System.Security.Cryptography.Primitives.dll Facades/System.Security.Cryptography.Algorithms.dll \ - Facades/System.ValueTuple.dll Facades/System.Text.Encoding.CodePages.dll + Facades/System.ValueTuple.dll Facades/System.Text.Encoding.CodePages.dll \ + Mono.Cecil.dll monolite_files = $(build_files:%=lib/$(monolite_dir)/%) diff --git a/mcs/class/Microsoft.Build.Engine/Makefile b/mcs/class/Microsoft.Build.Engine/Makefile index c8ce9a2281..30fdb0fd1e 100644 --- a/mcs/class/Microsoft.Build.Engine/Makefile +++ b/mcs/class/Microsoft.Build.Engine/Makefile @@ -23,7 +23,7 @@ EXTRA_DISTFILES = \ CLEAN_FILES = Test/resources/TestTasks-$(PROFILE).dll Test/resources/TestTasks-$(PROFILE).dll.mdb Test/resources/TestTasks-$(PROFILE).pdb Test/resources/TestTasks-$(PROFILE).dll: Test/resources/TestTasks.cs - $(CSCOMPILE) /out:$@ Test/resources/TestTasks.cs /r:$(topdir)/class/lib/$(PROFILE)/$(XBUILD_FRAMEWORK).dll /r:$(topdir)/class/lib/$(PROFILE)/$(XBUILD_UTILITIES).dll /target:library + $(CSCOMPILE) /out:$@ Test/resources/TestTasks.cs /r:$(topdir)/class/lib/$(PROFILE)/$(PARENT_PROFILE)/mscorlib.dll /r:$(topdir)/class/lib/$(PROFILE)/$(XBUILD_FRAMEWORK).dll /r:$(topdir)/class/lib/$(PROFILE)/$(XBUILD_UTILITIES).dll /target:library test-local: compile-resources diff --git a/mcs/class/Microsoft.Build.Tasks/Makefile b/mcs/class/Microsoft.Build.Tasks/Makefile index b926ba9ff3..09aeca3b10 100644 --- a/mcs/class/Microsoft.Build.Tasks/Makefile +++ b/mcs/class/Microsoft.Build.Tasks/Makefile @@ -29,7 +29,7 @@ EXTRA_DISTFILES = \ Test/resources/junk.txt Test/resources/test.dll: Test/resources/test.cs - $(CSCOMPILE) -target:library /out:$@ $< + $(CSCOMPILE) -r:$(topdir)/class/lib/$(PROFILE)/mscorlib.dll -target:library /out:$@ $< clean-test-resources: rm -f Test/resources/test.dll diff --git a/mcs/class/Microsoft.Build/Makefile b/mcs/class/Microsoft.Build/Makefile index 2dcbefdf7f..1a711069b0 100644 --- a/mcs/class/Microsoft.Build/Makefile +++ b/mcs/class/Microsoft.Build/Makefile @@ -26,7 +26,7 @@ EXTRA_DISTFILES = \ EXPR_PARSER = Microsoft.Build.Internal/ExpressionParser $(EXPR_PARSER).cs: $(EXPR_PARSER).jay $(topdir)/jay/skeleton.cs - (cd Microsoft.Build.Internal; $(topdir)/../jay/jay -ctv < $(topdir)/../jay/skeleton.cs ExpressionParser.jay > ExpressionParser.cs) + (cd Microsoft.Build.Internal; $(topdir)/../jay/jay -ctv -o ExpressionParser.cs ExpressionParser.jay < $(topdir)/../jay/skeleton.cs ) BUILT_SOURCES = $(EXPR_PARSER).cs diff --git a/mcs/class/Microsoft.VisualC/Assembly/AssemblyInfo.cs b/mcs/class/Microsoft.VisualC/Assembly/AssemblyInfo.cs index c6b2a0b65d..1a8eac06e7 100644 --- a/mcs/class/Microsoft.VisualC/Assembly/AssemblyInfo.cs +++ b/mcs/class/Microsoft.VisualC/Assembly/AssemblyInfo.cs @@ -33,7 +33,7 @@ using System.Reflection; using System.Runtime.InteropServices; using System.Resources; -[assembly: AssemblyVersion (Consts.VsVersion)] +[assembly: AssemblyVersion ("10.0.0.0")] /* TODO COMPLETE INFORMATION diff --git a/mcs/class/Mono.CSharp/Makefile b/mcs/class/Mono.CSharp/Makefile index 7b1986b78e..3615532853 100644 --- a/mcs/class/Mono.CSharp/Makefile +++ b/mcs/class/Mono.CSharp/Makefile @@ -24,7 +24,7 @@ LIB_MCS_FLAGS += $(REFERENCE_SOURCES_FLAGS) BUILT_SOURCES = $(PROFILE)-parser.cs $(PROFILE)-parser.cs: $(topdir)/mcs/cs-parser.jay $(topdir)/jay/skeleton.cs - $(topdir)/jay/jay -c < $(topdir)/jay/skeleton.cs $< > $(PROFILE)-jay-tmp.out && mv $(PROFILE)-jay-tmp.out $@ + $(topdir)/jay/jay -c -o $(PROFILE)-jay-tmp.out $< < $(topdir)/jay/skeleton.cs && mv $(PROFILE)-jay-tmp.out $@ include ../../build/library.make diff --git a/mcs/class/Mono.CompilerServices.SymbolWriter/Makefile b/mcs/class/Mono.CompilerServices.SymbolWriter/Makefile index 0c116da9d1..3f46ca4c08 100644 --- a/mcs/class/Mono.CompilerServices.SymbolWriter/Makefile +++ b/mcs/class/Mono.CompilerServices.SymbolWriter/Makefile @@ -18,10 +18,3 @@ LIBRARY_COMPILE = $(BOOT_COMPILE) endif include ../../build/library.make - -$(build_lib): $(bare_libdir)/System.dll - -$(bare_libdir)/System.dll: - (cd ../System; make $@) - -.NOTPARALLEL: $(bare_libdir)/System.dll diff --git a/mcs/class/Mono.Data.Sqlite/Mono.Data.Sqlite_2.0/SQLite3.cs b/mcs/class/Mono.Data.Sqlite/Mono.Data.Sqlite_2.0/SQLite3.cs index 6b2ee13e03..df1f227cd5 100644 --- a/mcs/class/Mono.Data.Sqlite/Mono.Data.Sqlite_2.0/SQLite3.cs +++ b/mcs/class/Mono.Data.Sqlite/Mono.Data.Sqlite_2.0/SQLite3.cs @@ -929,29 +929,25 @@ namespace Mono.Data.Sqlite return UnsafeNativeMethods.sqlite3_aggregate_context(context, 1); } -#if MONOTOUCH - internal override void SetPassword(byte[] passwordBytes) - { - throw new NotImplementedException (); - } - - internal override void ChangePassword(byte[] newPasswordBytes) - { - throw new NotImplementedException (); - } -#else internal override void SetPassword(byte[] passwordBytes) { +#if MOBILE + throw new PlatformNotSupportedException(); +#else int n = UnsafeNativeMethods.sqlite3_key(_sql, passwordBytes, passwordBytes.Length); if (n > 0) throw new SqliteException(n, SQLiteLastError()); +#endif } internal override void ChangePassword(byte[] newPasswordBytes) { +#if MOBILE + throw new PlatformNotSupportedException(); +#else int n = UnsafeNativeMethods.sqlite3_rekey(_sql, newPasswordBytes, (newPasswordBytes == null) ? 0 : newPasswordBytes.Length); if (n > 0) throw new SqliteException(n, SQLiteLastError()); - } #endif + } #if MONOTOUCH SQLiteUpdateCallback update_callback; diff --git a/mcs/class/Mono.Debugger.Soft/Makefile b/mcs/class/Mono.Debugger.Soft/Makefile index 4fb6f306a9..5b002b86ee 100644 --- a/mcs/class/Mono.Debugger.Soft/Makefile +++ b/mcs/class/Mono.Debugger.Soft/Makefile @@ -23,7 +23,7 @@ TEST_HELPERS_SOURCES = \ test-local: dtest-app.exe dtest-excfilter.exe dtest-app.exe: Test/dtest-app.cs $(TEST_HELPERS_SOURCES) - $(CSCOMPILE) -r:$(topdir)/class/lib/$(PROFILE)/System.Core.dll -r:$(topdir)/class/lib/$(PROFILE)/System.dll -out:$@ -unsafe $(PLATFORM_DEBUG_FLAGS) -optimize- Test/dtest-app.cs $(TEST_HELPERS_SOURCES) + $(CSCOMPILE) -r:$(topdir)/class/lib/$(PROFILE)/mscorlib.dll -r:$(topdir)/class/lib/$(PROFILE)/System.Core.dll -r:$(topdir)/class/lib/$(PROFILE)/System.dll -out:$@ -unsafe $(PLATFORM_DEBUG_FLAGS) -optimize- Test/dtest-app.cs $(TEST_HELPERS_SOURCES) dtest-excfilter.exe: Test/dtest-excfilter.il $(ILASM) -out:$@ /exe /debug Test/dtest-excfilter.il diff --git a/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/Connection.cs b/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/Connection.cs index 602c827091..e480555252 100644 --- a/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/Connection.cs +++ b/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/Connection.cs @@ -420,7 +420,7 @@ namespace Mono.Debugger.Soft * with newer runtimes, and vice versa. */ internal const int MAJOR_VERSION = 2; - internal const int MINOR_VERSION = 45; + internal const int MINOR_VERSION = 46; enum WPSuspendPolicy { NONE = 0, @@ -442,7 +442,8 @@ namespace Mono.Debugger.Soft TYPE = 23, MODULE = 24, FIELD = 25, - EVENT = 64 + EVENT = 64, + POINTER = 65 } enum EventKind { @@ -574,7 +575,8 @@ namespace Mono.Debugger.Soft GET_INTERFACES = 16, GET_INTERFACE_MAP = 17, IS_INITIALIZED = 18, - CREATE_INSTANCE = 19 + CREATE_INSTANCE = 19, + GET_VALUE_SIZE = 20 } enum CmdField { @@ -606,6 +608,10 @@ namespace Mono.Debugger.Soft GET_CHARS = 3 } + enum CmdPointer { + GET_VALUE = 1 + } + enum CmdObjectRef { GET_TYPE = 1, GET_VALUES = 2, @@ -730,10 +736,12 @@ namespace Mono.Debugger.Soft } class PacketReader { + Connection connection; byte[] packet; int offset; - public PacketReader (byte[] packet) { + public PacketReader (Connection connection, byte[] packet) { + this.connection = connection; this.packet = packet; // For event packets @@ -845,9 +853,16 @@ namespace Mono.Debugger.Soft return new ValueImpl { Type = etype, Value = ReadDouble () }; case ElementType.I: case ElementType.U: - case ElementType.Ptr: // FIXME: The client and the debuggee might have different word sizes return new ValueImpl { Type = etype, Value = ReadLong () }; + case ElementType.Ptr: + long value = ReadLong (); + if (connection.Version.AtLeast (2, 46)) { + long pointerClass = ReadId (); + return new ValueImpl { Type = etype, Klass = pointerClass, Value = value }; + } else { + return new ValueImpl { Type = etype, Value = value }; + } case ElementType.String: case ElementType.SzArray: case ElementType.Class: @@ -1283,7 +1298,7 @@ namespace Mono.Debugger.Soft if (cb != null) cb.Invoke (id, packet); } else { - PacketReader r = new PacketReader (packet); + PacketReader r = new PacketReader (this, packet); if (r.CommandSet == CommandSet.EVENT && r.Command == (int)CmdEvent.COMPOSITE) { int spolicy = r.ReadByte (); @@ -1502,7 +1517,7 @@ namespace Mono.Debugger.Soft if (EnableConnectionLogging) LogPacket (packet_id, encoded_packet, p, command_set, command, watch); /* Run the callback on a tp thread to avoid blocking the receive thread */ - PacketReader r = new PacketReader (p); + PacketReader r = new PacketReader (this, p); cb.BeginInvoke (r, null, null); }; reply_cb_counts [id] = count; @@ -1549,7 +1564,7 @@ namespace Mono.Debugger.Soft if (reply_packets.ContainsKey (packetId)) { byte[] reply = reply_packets [packetId]; reply_packets.Remove (packetId); - PacketReader r = new PacketReader (reply); + PacketReader r = new PacketReader (this, reply); if (EnableConnectionLogging) LogPacket (packetId, encoded_packet, reply, command_set, command, watch); @@ -2297,6 +2312,11 @@ namespace Mono.Debugger.Soft return r.ReadId (); } + internal int Type_GetValueSize (long id) { + PacketReader r = SendReceive (CommandSet.TYPE, (int)CmdType.GET_VALUE_SIZE, new PacketWriter ().WriteId (id)); + return r.ReadInt (); + } + /* * FIELD */ @@ -2475,7 +2495,16 @@ namespace Mono.Debugger.Soft for (int i = 0; i < length; ++i) res [i] = (char)r.ReadShort (); return res; - } + } + + /* + * POINTERS + */ + + internal ValueImpl Pointer_GetValue (long address, TypeMirror type) + { + return SendReceive (CommandSet.POINTER, (int)CmdPointer.GET_VALUE, new PacketWriter ().WriteLong (address).WriteId (type.Id)).ReadValue (); + } /* * OBJECTS diff --git a/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/PointerValue.cs b/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/PointerValue.cs index 3fa359fcb5..2cf9dfa418 100644 --- a/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/PointerValue.cs +++ b/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/PointerValue.cs @@ -48,6 +48,16 @@ namespace Mono.Debugger.Soft get { return type; } } + // Since protocol version 2.46 + public Value Value { + get { + if (Address == 0) + return null; + + return vm.DecodeValue (vm.conn.Pointer_GetValue (Address, Type)); + } + } + public override bool Equals (object obj) { if (obj != null && obj is PointerValue) return addr == (obj as PointerValue).addr; diff --git a/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/TypeMirror.cs b/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/TypeMirror.cs index f92dca0393..78c11a8d9a 100644 --- a/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/TypeMirror.cs +++ b/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/TypeMirror.cs @@ -842,6 +842,11 @@ namespace Mono.Debugger.Soft return vm.GetObject (vm.conn.Type_CreateInstance (id)); } + // Since protocol version 2.46 + public int GetValueSize () { + return vm.conn.Type_GetValueSize (id); + } + // Since protocol version 2.11 public TypeMirror[] GetInterfaces () { if (ifaces == null) diff --git a/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/VirtualMachine.cs b/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/VirtualMachine.cs index 1eaaac8ec9..9d60855a31 100644 --- a/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/VirtualMachine.cs +++ b/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/VirtualMachine.cs @@ -616,8 +616,11 @@ namespace Mono.Debugger.Soft } internal Value DecodeValue (ValueImpl v, Dictionary parent_vtypes) { - if (v.Value != null) + if (v.Value != null) { + if (Version.AtLeast (2, 46) && v.Type == ElementType.Ptr) + return new PointerValue(this, GetType(v.Klass), (long)v.Value); return new PrimitiveValue (this, v.Value); + } switch (v.Type) { case ElementType.Void: @@ -682,8 +685,11 @@ namespace Mono.Debugger.Soft duplicates.Add (v); return new ValueImpl { Type = ElementType.ValueType, Klass = (v as StructMirror).Type.Id, Fields = EncodeValues ((v as StructMirror).Fields, duplicates) }; + } else if (v is PointerValue) { + PointerValue val = (PointerValue)v; + return new ValueImpl { Type = ElementType.Ptr, Klass = val.Type.Id, Value = val.Address }; } else { - throw new NotSupportedException (); + throw new NotSupportedException ("Value of type " + v.GetType()); } } diff --git a/mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs b/mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs index 97202372c7..33ef36b6d5 100644 --- a/mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs +++ b/mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs @@ -145,6 +145,12 @@ public struct AStruct : ITest2 { } } + +public struct BlittableStruct { + public int i; + public double d; +} + public class GClass { public T field; public static T static_field; @@ -349,6 +355,7 @@ public class Tests : TestsBase, ITest2 gc_suspend (); set_ip (); step_filters (); + pointers (); if (args.Length > 0 && args [0] == "local-reflect") local_reflect (); if (args.Length > 0 && args [0] == "domain-test") @@ -1761,6 +1768,18 @@ public class Tests : TestsBase, ITest2 static void step_out_void_async_2 () { } + + public static unsafe void pointer_arguments (int* a, BlittableStruct* s) { + *a = 0; + } + + [MethodImplAttribute (MethodImplOptions.NoInlining)] + public static unsafe void pointers () { + int[] a = new [] {1,2,3}; + BlittableStruct s = new BlittableStruct () { i = 2, d = 3.0 }; + fixed (int* pa = a) + pointer_arguments (pa, &s); + } } public class SentinelClass : MarshalByRefObject { diff --git a/mcs/class/Mono.Debugger.Soft/Test/dtest.cs.REMOVED.git-id b/mcs/class/Mono.Debugger.Soft/Test/dtest.cs.REMOVED.git-id index 859ce2963f..aeb3f2a004 100644 --- a/mcs/class/Mono.Debugger.Soft/Test/dtest.cs.REMOVED.git-id +++ b/mcs/class/Mono.Debugger.Soft/Test/dtest.cs.REMOVED.git-id @@ -1 +1 @@ -96529d5a708f73c047a79844dc5eabe9042baa22 \ No newline at end of file +8fb43da5d617155a9e7868c8c32d0ea4cad9047c \ No newline at end of file diff --git a/mcs/class/Mono.Options/Makefile b/mcs/class/Mono.Options/Makefile index cf83d94457..28d27326fe 100644 --- a/mcs/class/Mono.Options/Makefile +++ b/mcs/class/Mono.Options/Makefile @@ -23,7 +23,7 @@ test-local: Mono.Options-PCL.dll clean-local: clean-pcl Mono.Options-PCL.dll: Mono.Options.dll.sources $(shell cat Mono.Options.dll.sources) - $(CSCOMPILE) -target:library -out:$@ -debug+ -d:PCL -r:../lib/$(PROFILE)/System.dll @$< + $(CSCOMPILE) -target:library -out:$@ -d:PCL -r:../lib/$(PROFILE)/mscorlib.dll -r:../lib/$(PROFILE)/System.dll @$< clean-pcl: -rm Mono.Options-PCL.dll diff --git a/mcs/class/Mono.Posix/Mono.Unix.Native/Syscall.cs.REMOVED.git-id b/mcs/class/Mono.Posix/Mono.Unix.Native/Syscall.cs.REMOVED.git-id index 19b3ed6ada..e6ee96ff8e 100644 --- a/mcs/class/Mono.Posix/Mono.Unix.Native/Syscall.cs.REMOVED.git-id +++ b/mcs/class/Mono.Posix/Mono.Unix.Native/Syscall.cs.REMOVED.git-id @@ -1 +1 @@ -c750e5fa86b353b625f01b0f5d1227c6a43c4dc4 \ No newline at end of file +a919644f85d6bc2807949463b1c8b703d5f58717 \ No newline at end of file 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 945584340d..e79a9e5263 100644 --- a/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogEnums.cs +++ b/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogEnums.cs @@ -66,6 +66,7 @@ namespace Mono.Profiler.Log { RuntimeJitHelper = 1 << 4, MetaSynchronizationPoint = 0 << 4, + MetaAotId = 1 << 4, } // mono/profiler/log.h : TYPE_* 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 79d6140523..1e5f338839 100644 --- a/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogEventVisitor.cs +++ b/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogEventVisitor.cs @@ -189,5 +189,9 @@ namespace Mono.Profiler.Log { public virtual void Visit (SynchronizationPointEvent ev) { } + + public virtual void Visit (AotIdEvent 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 faae978cd9..19d179015f 100644 --- a/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogEvents.cs +++ b/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogEvents.cs @@ -101,6 +101,8 @@ namespace Mono.Profiler.Log { public string Name { get; internal set; } + public Guid ModuleVersionId { get; internal set; } + internal override void Accept (LogEventVisitor visitor) { visitor.Visit (this); @@ -260,6 +262,8 @@ namespace Mono.Profiler.Log { public long ObjectSize { get; internal set; } + public int Generation { get; internal set; } + public IReadOnlyList References { get; internal set; } internal override void Accept (LogEventVisitor visitor) @@ -326,7 +330,7 @@ namespace Mono.Profiler.Log { public LogGCEvent Type { get; internal set; } - public byte Generation { get; internal set; } + public int Generation { get; internal set; } internal override void Accept (LogEventVisitor visitor) { @@ -554,6 +558,7 @@ namespace Mono.Profiler.Log { } } + [Obsolete ("This event is no longer produced.")] public sealed class UnmanagedBinaryEvent : LogEvent { public long SegmentPointer { get; internal set; } @@ -593,4 +598,14 @@ namespace Mono.Profiler.Log { visitor.Visit (this); } } + + public sealed class AotIdEvent : LogEvent { + + public Guid AotId { get; internal set; } + + internal override void Accept (LogEventVisitor visitor) + { + visitor.Visit (this); + } + } } 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 6e26d22786..62f9574295 100644 --- a/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogProcessor.cs +++ b/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogProcessor.cs @@ -232,10 +232,18 @@ namespace Mono.Profiler.Log { break; case LogMetadataType.Image: if (load) { - ev = new ImageLoadEvent { + var ile = new ImageLoadEvent { ImagePointer = ReadPointer (), Name = _reader.ReadCString (), }; + + if (StreamHeader.FormatVersion >= 16) { + var guid = _reader.ReadCString (); + + ile.ModuleVersionId = guid == string.Empty ? Guid.Empty : Guid.Parse (guid); + } + + ev = ile; } else if (unload) { ev = new ImageUnloadEvent { ImagePointer = ReadPointer (), @@ -408,6 +416,7 @@ namespace Mono.Profiler.Log { ClassPointer = StreamHeader.FormatVersion < 15 ? ReadPointer () : 0, VTablePointer = StreamHeader.FormatVersion >= 15 ? ReadPointer () : 0, ObjectSize = (long) _reader.ReadULeb128 (), + Generation = StreamHeader.FormatVersion >= 16 ? _reader.ReadByte () : 0, }; var list = new HeapObjectEvent.HeapObjectReference [(int) _reader.ReadULeb128 ()]; @@ -597,6 +606,11 @@ namespace Mono.Profiler.Log { Type = (LogSynchronizationPoint) _reader.ReadByte (), }; break; + case LogEventType.MetaAotId: + ev = new AotIdEvent { + AotId = Guid.Parse (_reader.ReadCString ()), + }; + break; default: throw new LogException ($"Invalid extended event type ({extType})."); } 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 aa86b75444..37128fc98c 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,8 @@ namespace Mono.Profiler.Log { public sealed class LogStreamHeader { const int MinVersion = 13; - const int MaxVersion = 15; + + const int MaxVersion = 16; const int Id = 0x4d505a01; @@ -21,6 +22,8 @@ namespace Mono.Profiler.Log { public ulong StartupTime { get; } + public ulong TimestampStartupTime { get; } + public int TimerOverhead { get; } public int Flags { get; } @@ -50,6 +53,10 @@ namespace Mono.Profiler.Log { PointerSize = reader.ReadByte (); StartupTime = reader.ReadUInt64 (); + + if (Version.Major >= 3) + TimestampStartupTime = reader.ReadUInt64 (); + TimerOverhead = reader.ReadInt32 (); Flags = reader.ReadInt32 (); ProcessId = reader.ReadInt32 (); diff --git a/mcs/class/Mono.Security/Makefile b/mcs/class/Mono.Security/Makefile index bed9511ec9..bac61387c5 100644 --- a/mcs/class/Mono.Security/Makefile +++ b/mcs/class/Mono.Security/Makefile @@ -4,7 +4,7 @@ include ../../build/rules.make LIBRARY = Mono.Security.dll LOCAL_MCS_FLAGS = -LIB_REFS = bare/System +API_BIN_REFS = System KEYFILE = ../mono.pub LIB_MCS_FLAGS = -unsafe -nowarn:1030,3009 TEST_MCS_FLAGS = $(LIB_MCS_FLAGS) -nowarn:169,219,618,672 @@ -25,16 +25,4 @@ endif include ../../build/library.make -$(build_lib): $(the_libdir_base)bare/System.dll - -$(the_libdir_base)bare/System.dll: - (cd ../System; $(MAKE) $@) - -.NOTPARALLEL: $(the_libdir_base)bare/System.dll - EXTRA_DISTFILES = Mono.Security.Interface/README.md - -# -# Update this comment to trigger a build in System -# +3 -# diff --git a/mcs/class/Mono.Security/Mono.Security.Interface/IMonoSslStream.cs b/mcs/class/Mono.Security/Mono.Security.Interface/IMonoSslStream.cs index 131ebab00e..ac03e7daa7 100644 --- a/mcs/class/Mono.Security/Mono.Security.Interface/IMonoSslStream.cs +++ b/mcs/class/Mono.Security/Mono.Security.Interface/IMonoSslStream.cs @@ -33,7 +33,6 @@ using SSA = System.Security.Authentication; using System.Security.Cryptography.X509Certificates; using System.Security.Principal; using System.Security.Cryptography; -using Mono.Net.Security; namespace Mono.Security.Interface { diff --git a/mcs/class/Mono.WebBrowser/Makefile b/mcs/class/Mono.WebBrowser/Makefile index 65b6d44df1..93cf7f6857 100644 --- a/mcs/class/Mono.WebBrowser/Makefile +++ b/mcs/class/Mono.WebBrowser/Makefile @@ -7,7 +7,7 @@ LIB_REFS = System KEYFILE = ../mono.snk LIB_MCS_FLAGS = -warn:1 -TEST_MCS_FLAGS = $(LIB_MCS_FLAGS) +TEST_MCS_FLAGS = EXTRA_DISTFILES = README diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ComposablePartCatalogCollection.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ComposablePartCatalogCollection.cs index 151162887f..ad2c78f52d 100644 --- a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ComposablePartCatalogCollection.cs +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/ComposablePartCatalogCollection.cs @@ -12,6 +12,7 @@ using System.Diagnostics; using Microsoft.Internal; using Microsoft.Internal.Collections; using System.Collections; +using Lock = Microsoft.Internal.Lock; namespace System.ComponentModel.Composition.Hosting { diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CompositionLock.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CompositionLock.cs index 4edf397418..55a5007e3e 100644 --- a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CompositionLock.cs +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/Hosting/CompositionLock.cs @@ -11,6 +11,7 @@ using System.Runtime.CompilerServices; using Microsoft.Internal; using Microsoft.Internal.Collections; using System.Threading; +using Lock = Microsoft.Internal.Lock; namespace System.ComponentModel.Composition.Hosting { diff --git a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/MetadataViewGenerator.cs b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/MetadataViewGenerator.cs index 28c8a94840..c05881e1a7 100644 --- a/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/MetadataViewGenerator.cs +++ b/mcs/class/System.ComponentModel.Composition.4.5/src/ComponentModel/System/ComponentModel/Composition/MetadataViewGenerator.cs @@ -13,6 +13,7 @@ using Microsoft.Internal; using System.Reflection.Emit; using System.Collections; using System.Security; +using Lock = Microsoft.Internal.Lock; namespace System.ComponentModel.Composition { diff --git a/mcs/class/System.ComponentModel.DataAnnotations/Makefile b/mcs/class/System.ComponentModel.DataAnnotations/Makefile index 53519907a9..a46151a796 100644 --- a/mcs/class/System.ComponentModel.DataAnnotations/Makefile +++ b/mcs/class/System.ComponentModel.DataAnnotations/Makefile @@ -7,7 +7,8 @@ LIB_REFS = System System.Core System.Data System.Xml KEYFILE = ../winfx.pub LIB_MCS_FLAGS = -nowarn:414 -TEST_MCS_FLAGS = $(LIB_MCS_FLAGS) +TEST_MCS_FLAGS = +TEST_LIB_REFS = System System.Core TXT_RESOURCE_STRINGS = ../referencesource/System.ComponentModel.DataAnnotations/System.ComponentModel.DataAnnotations.txt diff --git a/mcs/class/System.Configuration/Makefile b/mcs/class/System.Configuration/Makefile index e59076d70d..6e948af0a2 100644 --- a/mcs/class/System.Configuration/Makefile +++ b/mcs/class/System.Configuration/Makefile @@ -6,7 +6,7 @@ include ../../build/rules.make LIBRARY = System.Configuration.dll LOCAL_MCS_FLAGS = -LIB_REFS = secxml/System bare/System.Xml System.Security +LIB_REFS = System.Security System System.Xml KEYFILE = ../msfinal.pub LIB_MCS_FLAGS = -nowarn:618 TEST_MCS_FLAGS = @@ -16,27 +16,8 @@ LIBRARY_WARN_AS_ERROR = yes include ../../build/library.make -configuration_library_deps = \ - $(secxml_libdir)/System.dll \ - $(the_libdir_base)System.Security.dll \ - $(bare_libdir)/System.Xml.dll - -$(build_lib): $(configuration_library_deps) - test-local: cp Test/appSettings.config $(dir $(NUNITLITE_CONFIG_FILE))/Test-appSettings.config -.NOTPARALLEL: $(configuration_library_deps) - -$(secxml_libdir)/System.dll: - @echo System.Configuration: GETTING: $@ - (cd ../System; $(MAKE) $@) - -$(the_libdir_base)System.Security.dll: - (cd ../System.Security; $(MAKE) $@) - -$(bare_libdir)/System.Xml.dll: - (cd ../System.XML; $(MAKE) $@) - run-test: $(MAKE) -C Test/standalone diff --git a/mcs/class/System.Core/System.IO.MemoryMappedFiles/MemoryMappedFile.cs b/mcs/class/System.Core/System.IO.MemoryMappedFiles/MemoryMappedFile.cs index 45d6c4541e..aa31ccd637 100644 --- a/mcs/class/System.Core/System.IO.MemoryMappedFiles/MemoryMappedFile.cs +++ b/mcs/class/System.Core/System.IO.MemoryMappedFiles/MemoryMappedFile.cs @@ -37,10 +37,10 @@ namespace System.IO.MemoryMappedFiles { internal static class MemoryMapImpl { [MethodImplAttribute (MethodImplOptions.InternalCall)] - static extern IntPtr OpenFileInternal (string path, FileMode mode, string mapName, out long capacity, MemoryMappedFileAccess access, MemoryMappedFileOptions options, out int error); + static extern unsafe IntPtr OpenFileInternal (char* path, int path_length, FileMode mode, char* mapName, int mapName_length, out long capacity, MemoryMappedFileAccess access, MemoryMappedFileOptions options, out int error); [MethodImplAttribute (MethodImplOptions.InternalCall)] - static extern IntPtr OpenHandleInternal (IntPtr handle, string mapName, out long capacity, MemoryMappedFileAccess access, MemoryMappedFileOptions options, out int error); + static extern unsafe IntPtr OpenHandleInternal (IntPtr handle, char* mapName, int mapName_length, out long capacity, MemoryMappedFileAccess access, MemoryMappedFileOptions options, out int error); [MethodImplAttribute (MethodImplOptions.InternalCall)] internal extern static void CloseMapping (IntPtr handle); @@ -93,22 +93,41 @@ namespace System.IO.MemoryMappedFiles } } - internal static IntPtr OpenFile (string path, FileMode mode, string mapName, out long capacity, MemoryMappedFileAccess access, MemoryMappedFileOptions options) + static int StringLength (string a) { - int error = 0; - IntPtr res = OpenFileInternal (path, mode, mapName, out capacity, access, options, out error); - if (error != 0) - throw CreateException (error, path); - return res; + return a?.Length ?? 0; } - internal static IntPtr OpenHandle (IntPtr handle, string mapName, out long capacity, MemoryMappedFileAccess access, MemoryMappedFileOptions options) + static void CheckString (string name, string value) { - int error = 0; - IntPtr res = OpenHandleInternal (handle, mapName, out capacity, access, options, out error); - if (error != 0) - throw CreateException (error, ""); - return res; + // Native code tends to truncate at NUL which is incorrect. Guard it here. + if (value?.IndexOf((char)0) >= 0) + throw new ArgumentException ("String must not contain embedded NULs.", name); + } + + internal static unsafe IntPtr OpenFile (string path, FileMode mode, string mapName, out long capacity, MemoryMappedFileAccess access, MemoryMappedFileOptions options) + { + CheckString (nameof (path), path); + CheckString (nameof (mapName), mapName); + fixed (char* fpath = path, fmapName = mapName) { + int error = 0; + IntPtr res = OpenFileInternal (fpath, StringLength (path), mode, fmapName, StringLength (mapName), out capacity, access, options, out error); + if (error != 0) + throw CreateException (error, path); + return res; + } + } + + internal static unsafe IntPtr OpenHandle (IntPtr handle, string mapName, out long capacity, MemoryMappedFileAccess access, MemoryMappedFileOptions options) + { + CheckString (nameof (mapName), mapName); + fixed (char* fmapName = mapName) { + int error = 0; + IntPtr res = OpenHandleInternal (handle, fmapName, StringLength (mapName), out capacity, access, options, out error); + if (error != 0) + throw CreateException (error, ""); + return res; + } } } diff --git a/mcs/class/System.Core/System.Security.Cryptography.X509Certificates/RSACertificateExtensions.cs b/mcs/class/System.Core/System.Security.Cryptography.X509Certificates/RSACertificateExtensions.cs index a61b9f66ca..81c303bd09 100644 --- a/mcs/class/System.Core/System.Security.Cryptography.X509Certificates/RSACertificateExtensions.cs +++ b/mcs/class/System.Core/System.Security.Cryptography.X509Certificates/RSACertificateExtensions.cs @@ -28,12 +28,7 @@ namespace System.Security.Cryptography.X509Certificates { -#if SYSTEM_SECURITY_DLL - internal -#else - public -#endif - static class RSACertificateExtensions + public static class RSACertificateExtensions { public static RSA GetRSAPrivateKey(this X509Certificate2 certificate) { diff --git a/mcs/class/System.Core/common_System.Core.dll.sources b/mcs/class/System.Core/common_System.Core.dll.sources index cfe271aeee..6d2f6aaf34 100644 --- a/mcs/class/System.Core/common_System.Core.dll.sources +++ b/mcs/class/System.Core/common_System.Core.dll.sources @@ -289,3 +289,5 @@ System.Security.Cryptography/SHA512CryptoServiceProvider.cs ../../../external/corefx/src/System.Linq.Expressions/src/System/Linq/Expressions/Compiler/DelegateHelpers.cs ../../../external/corefx/src/System.Linq.Expressions/src/System/Linq/Expressions/Compiler/DelegateHelpers.Generated.cs + +../../../external/corefx/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/IncrementalHash.net46.cs diff --git a/mcs/class/System.Data.OracleClient/Makefile b/mcs/class/System.Data.OracleClient/Makefile index 66fbba3497..cebaa9b6ad 100644 --- a/mcs/class/System.Data.OracleClient/Makefile +++ b/mcs/class/System.Data.OracleClient/Makefile @@ -7,7 +7,8 @@ LIB_REFS = System System.Xml System.Data System.EnterpriseServices System.Drawin KEYFILE = ../ecma.pub LIB_MCS_FLAGS = -TEST_MCS_FLAGS = $(LIB_MCS_FLAGS) /nowarn:618 +TEST_MCS_FLAGS = /nowarn:618 +TEST_LIB_REFS = System System.Xml System.Data EXTRA_DISTFILES = Test/*.cs diff --git a/mcs/class/System.Data/Makefile b/mcs/class/System.Data/Makefile index 6d80a3b531..d777e8b430 100644 --- a/mcs/class/System.Data/Makefile +++ b/mcs/class/System.Data/Makefile @@ -45,8 +45,6 @@ TEST_NUNITLITE_APP_CONFIG_GLOBAL=Test/test-config-file USE_XTEST_REMOTE_EXECUTOR = YES XTEST_LIB_REFS = System System.Core System.Xml Facades/System.Text.Encoding.CodePages Facades/System.Threading.Tasks Facades/System.Runtime.InteropServices.RuntimeInformation -TEST_MONO_PATH = . - EXTRA_DISTFILES = \ $(wildcard Test/System.Data/*.xml) \ $(wildcard Test/System.Data/*.xsd) \ diff --git a/mcs/class/System.Design/Makefile b/mcs/class/System.Design/Makefile index 4ff4c5e8c4..08aaa81de8 100644 --- a/mcs/class/System.Design/Makefile +++ b/mcs/class/System.Design/Makefile @@ -4,21 +4,12 @@ include ../../build/rules.make LIBRARY = System.Design.dll -LIB_REFS = System System.Xml plainweb/System.Web System.Windows.Forms System.Drawing Accessibility System.Data System.Configuration +LIB_REFS = System System.Xml System.Windows.Forms System.Drawing Accessibility System.Data System.Configuration KEYFILE = ../msfinal.pub LIB_MCS_FLAGS = -nowarn:436 -nowarn:612,618,649,67,672 +API_BIN_REFS := System.Web TEST_LIB_REFS = System System.Drawing System.Windows.Forms TEST_MCS_FLAGS = include ../../build/library.make - -ifneq (plaindesign/,$(intermediate)) -csproj-local: - $(MAKE) csproj-local intermediate=plaindesign/ - -$(the_libdir_base)plaindesign/System.Design.dll: - $(MAKE) intermediate=plaindesign/ $(the_libdir_base)plaindesign/System.Design.dll - -endif - diff --git a/mcs/class/System.Drawing/Makefile b/mcs/class/System.Drawing/Makefile index 62d3ac085e..e980a944be 100644 --- a/mcs/class/System.Drawing/Makefile +++ b/mcs/class/System.Drawing/Makefile @@ -22,6 +22,8 @@ TEST_LIB_REFS = System.Drawing System.Runtime.Serialization.Formatters.Soap Syst TEST_MCS_FLAGS = $(LIB_MCS_FLAGS) -define:TEST -resource:Test/resources/indexed.png,indexed.png \ -nowarn:0618 -nowarn:219 -nowarn:169 +XTEST_LIB_REFS = System System.Core Facades/System.Threading.Tasks + include ../../build/library.make EXTRA_DISTFILES = Test/resources/indexed.png \ diff --git a/mcs/class/System.Drawing/Test/System.Drawing.Imaging/TestJpegCodec.cs b/mcs/class/System.Drawing/Test/System.Drawing.Imaging/TestJpegCodec.cs index e20460eb99..9ec46e2968 100644 --- a/mcs/class/System.Drawing/Test/System.Drawing.Imaging/TestJpegCodec.cs +++ b/mcs/class/System.Drawing/Test/System.Drawing.Imaging/TestJpegCodec.cs @@ -96,8 +96,6 @@ namespace MonoTests.System.Drawing.Imaging { Assert.AreEqual (72, bmp.HorizontalResolution, "HorizontalResolution"); Assert.AreEqual (72, bmp.VerticalResolution, "VerticalResolution"); - Assert.AreEqual (77896, bmp.Flags, "Flags"); - ColorPalette cp = bmp.Palette; Assert.AreEqual (256, cp.Entries.Length, "Palette.Entries"); Assert.AreEqual (0, cp.Flags, "Palette.Flags"); @@ -232,8 +230,6 @@ namespace MonoTests.System.Drawing.Imaging { Assert.AreEqual (72, bmp.HorizontalResolution, "HorizontalResolution"); Assert.AreEqual (72, bmp.VerticalResolution, "VerticalResolution"); - Assert.AreEqual (77960, bmp.Flags, "Flags"); - Assert.AreEqual (0, bmp.Palette.Entries.Length, "Palette.Entries"); /* note: under MS flags aren't constant between executions in this case (no palette) */ } diff --git a/mcs/class/System.IdentityModel/Makefile b/mcs/class/System.IdentityModel/Makefile index 000c536c02..5d00d28a47 100644 --- a/mcs/class/System.IdentityModel/Makefile +++ b/mcs/class/System.IdentityModel/Makefile @@ -29,7 +29,8 @@ LIB_REFS += System.Web.ApplicationServices endif endif -TEST_MCS_FLAGS = $(LIB_MCS_FLAGS) +TEST_MCS_FLAGS = +TEST_LIB_REFS = System System.Xml System.Security System.Runtime.Serialization ifdef MOBILE_PROFILE NO_TEST = yes diff --git a/mcs/class/System.Json.Microsoft/Makefile b/mcs/class/System.Json.Microsoft/Makefile index 56c51c6330..8938fa7e3c 100644 --- a/mcs/class/System.Json.Microsoft/Makefile +++ b/mcs/class/System.Json.Microsoft/Makefile @@ -18,6 +18,6 @@ ifdef MOBILE_DYNAMIC LIB_MCS_FLAGS += -d:FEATURE_DYNAMIC endif -TEST_MCS_FLAGS = $(LIB_MCS_FLAGS) +TEST_LIB_REFS = System.Core include ../../build/library.make diff --git a/mcs/class/System.Net.Http/System.Net.Http.Headers/HttpHeaders.cs b/mcs/class/System.Net.Http/System.Net.Http.Headers/HttpHeaders.cs index c22a669559..59ea2a3e77 100644 --- a/mcs/class/System.Net.Http/System.Net.Http.Headers/HttpHeaders.cs +++ b/mcs/class/System.Net.Http/System.Net.Http.Headers/HttpHeaders.cs @@ -193,7 +193,7 @@ namespace System.Net.Http.Headers continue; } - throw new FormatException (); + throw new FormatException ($"Could not parse value for header '{name}'"); } if (headerInfo.AllowsMany) { diff --git a/mcs/class/System.Reactive.Linq/Makefile b/mcs/class/System.Reactive.Linq/Makefile index 071bd7c245..2c79f2d108 100644 --- a/mcs/class/System.Reactive.Linq/Makefile +++ b/mcs/class/System.Reactive.Linq/Makefile @@ -29,7 +29,7 @@ ifdef NET_4_5 LIB_MCS_FLAGS += -d:HAS_EDI -d:PREFERASYNC -d:PREFER_ASYNC -d:HAS_AWAIT endif -TEST_MCS_FLAGS = $(LIB_MCS_FLAGS) +TEST_MCS_FLAGS = EXTRA_DISTFILES = $(RESX_RESOURCES:.resources=.resx) $(PREBUILT) diff --git a/mcs/class/System.Runtime.Remoting/Makefile b/mcs/class/System.Runtime.Remoting/Makefile index 4dc2f64f9d..3b4b390b4f 100644 --- a/mcs/class/System.Runtime.Remoting/Makefile +++ b/mcs/class/System.Runtime.Remoting/Makefile @@ -15,8 +15,6 @@ endif TEST_MCS_FLAGS = -nowarn:618 TEST_LIB_REFS = System System.Xml System.Core -TEST_MONO_PATH = . - EXTRA_DISTFILES = Test/corba-example.cs Test/simple-example.cs include ../../build/library.make diff --git a/mcs/class/Facades/System.Runtime.Serialization.Xml/DataContractSerializerExtensions.cs b/mcs/class/System.Runtime.Serialization/ReferenceSources/DataContractSerializerExtensions.cs similarity index 100% rename from mcs/class/Facades/System.Runtime.Serialization.Xml/DataContractSerializerExtensions.cs rename to mcs/class/System.Runtime.Serialization/ReferenceSources/DataContractSerializerExtensions.cs diff --git a/mcs/class/Facades/System.Runtime.Serialization.Xml/NotImplemented.cs b/mcs/class/System.Runtime.Serialization/ReferenceSources/NotImplemented.cs similarity index 100% rename from mcs/class/Facades/System.Runtime.Serialization.Xml/NotImplemented.cs rename to mcs/class/System.Runtime.Serialization/ReferenceSources/NotImplemented.cs diff --git a/mcs/class/System.Runtime.Serialization/System.Runtime.Serialization.dll.sources b/mcs/class/System.Runtime.Serialization/System.Runtime.Serialization.dll.sources index c1ebbd9815..9ba03a46a2 100644 --- a/mcs/class/System.Runtime.Serialization/System.Runtime.Serialization.dll.sources +++ b/mcs/class/System.Runtime.Serialization/System.Runtime.Serialization.dll.sources @@ -16,3 +16,7 @@ ReferenceSources/XmlDataContract_static.cs ReferenceSources/XmlFormatReaderGenerator_static.cs ReferenceSources/XmlFormatWriterGenerator_static.cs +ReferenceSources/DataContractSerializerExtensions.cs +ReferenceSources/NotImplemented.cs + +../../../external/corefx/src/System.Runtime.Serialization.Primitives/src/System/Runtime/Serialization/ISerializationSurrogateProvider.cs diff --git a/mcs/class/System.Security/Makefile b/mcs/class/System.Security/Makefile index 04a3bea4d1..ec2a1458d7 100644 --- a/mcs/class/System.Security/Makefile +++ b/mcs/class/System.Security/Makefile @@ -3,17 +3,14 @@ SUBDIRS = include ../../build/rules.make ifndef NO_MONO_SECURITY -MONO_SECURITY_DLL=$(the_libdir_base)/Mono.Security.dll -MONO_SECURITY=Mono.Security +MONO_SECURITY = Mono.Security endif LIBRARY = System.Security.dll -API_BIN_REFS := System.Numerics -LIB_REFS = secxml/System bare/System.Xml $(MONO_SECURITY) +API_BIN_REFS := System.Numerics System.Core +LIB_REFS = $(MONO_SECURITY) System System.Xml KEYFILE = ../msfinal.pub -LIB_MCS_FLAGS = \ - -nowarn:414,618 \ - -d:SECURITY_DEP,SYSTEM_SECURITY_DLL +LIB_MCS_FLAGS = -nowarn:414,618 -d:SECURITY_DEP LOCAL_MCS_FLAGS = @@ -30,13 +27,3 @@ EXTRA_DISTFILES = \ RESX_RESOURCE_STRING = ../../../external/corefx/src/System.Security.Cryptography.Xml/src/Resources/Strings.resx include ../../build/library.make - -$(build_lib): $(secxml_libdir)/System.dll $(MONO_SECURITY_DLL) - -$(secxml_libdir)/System.dll: - (cd ../System; $(MAKE) $@) - -$(the_libdir_base)/Mono.Security.dll: - (cd ../Mono.Security; $(MAKE)) - -.NOTPARALLEL: $(secxml_libdir)/System.dll $(bare_libdir)/Mono.Security.dll diff --git a/mcs/class/System.Security/System.Security.dll.sources b/mcs/class/System.Security/System.Security.dll.sources index e77373a0eb..906d3c35ca 100644 --- a/mcs/class/System.Security/System.Security.dll.sources +++ b/mcs/class/System.Security/System.Security.dll.sources @@ -10,7 +10,6 @@ System.Security.Cryptography.Pkcs/SignedCms.cs System.Security.Cryptography.Pkcs/SignerInfo.cs System.Security.Cryptography.Pkcs/SignerInfoCollection.cs System.Security.Cryptography.Pkcs/SignerInfoEnumerator.cs -../System.Core/System.Security.Cryptography.X509Certificates/RSACertificateExtensions.cs System.Security.Cryptography.X509Certificates/X509Certificate2UI.cs System.Security.Cryptography.X509Certificates/X509SelectionFlag.cs diff --git a/mcs/class/System.ServiceModel.Activation/Makefile b/mcs/class/System.ServiceModel.Activation/Makefile index e8c0e953fd..26249a02ac 100644 --- a/mcs/class/System.ServiceModel.Activation/Makefile +++ b/mcs/class/System.ServiceModel.Activation/Makefile @@ -4,20 +4,11 @@ include ../../build/rules.make LIBRARY = System.ServiceModel.Activation.dll -LIB_REFS = System.Core System plainservice/System.ServiceModel +LIB_REFS = System.Core System System.ServiceModel KEYFILE = ../winfx.pub LIB_MCS_FLAGS = TEST_MCS_FLAGS = TEST_LIB_REFS = System System.Core -servicemodel = $(the_libdir_base)plainservice/System.ServiceModel.dll - include ../../build/library.make - -$(the_libdir_base)$(LIBRARY): $(servicemodel) - -$(servicemodel): - (cd ../System.ServiceModel; $(MAKE) $@) - -.NOTPARALLEL: $(servicemodel) diff --git a/mcs/class/System.ServiceModel.Activation/System.ServiceModel.Activation.dll.sources b/mcs/class/System.ServiceModel.Activation/System.ServiceModel.Activation.dll.sources index 1d17a9ee4a..c62e7509bf 100644 --- a/mcs/class/System.ServiceModel.Activation/System.ServiceModel.Activation.dll.sources +++ b/mcs/class/System.ServiceModel.Activation/System.ServiceModel.Activation.dll.sources @@ -2,5 +2,5 @@ ../../build/common/MonoTODOAttribute.cs Assembly/AssemblyInfo.cs -../System.ServiceModel/System.ServiceModel/ServiceHostingEnvironment.cs -../System.ServiceModel/System.ServiceModel.Activation/ServiceHostFactory.cs +System.ServiceModel/ServiceHostingEnvironment.cs +System.ServiceModel.Activation/ServiceHostFactory.cs diff --git a/mcs/class/System.ServiceModel/System.ServiceModel.Activation/ServiceHostFactory.cs b/mcs/class/System.ServiceModel.Activation/System.ServiceModel.Activation/ServiceHostFactory.cs similarity index 98% rename from mcs/class/System.ServiceModel/System.ServiceModel.Activation/ServiceHostFactory.cs rename to mcs/class/System.ServiceModel.Activation/System.ServiceModel.Activation/ServiceHostFactory.cs index 895062e1b3..1c0b4f4701 100644 --- a/mcs/class/System.ServiceModel/System.ServiceModel.Activation/ServiceHostFactory.cs +++ b/mcs/class/System.ServiceModel.Activation/System.ServiceModel.Activation/ServiceHostFactory.cs @@ -26,8 +26,6 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -#if !HAS_ACTIVATION - namespace System.ServiceModel.Activation { [System.Runtime.CompilerServices.TypeForwardedFrom (Consts.AssemblySystemServiceModel_3_0)] @@ -48,5 +46,3 @@ namespace System.ServiceModel.Activation } } } - -#endif diff --git a/mcs/class/Facades/System.Runtime.Loader/AssemblyExtensions.cs b/mcs/class/System.ServiceModel.Activation/System.ServiceModel/ServiceHostingEnvironment.cs similarity index 70% rename from mcs/class/Facades/System.Runtime.Loader/AssemblyExtensions.cs rename to mcs/class/System.ServiceModel.Activation/System.ServiceModel/ServiceHostingEnvironment.cs index 105024bc12..504bf35464 100644 --- a/mcs/class/Facades/System.Runtime.Loader/AssemblyExtensions.cs +++ b/mcs/class/System.ServiceModel.Activation/System.ServiceModel/ServiceHostingEnvironment.cs @@ -1,10 +1,10 @@ // -// AssemblyExtensions.cs +// ServiceHostingEnvironment.cs // -// Authors: -// Marek Safar +// Author: +// Ankit Jain // -// Copyright (C) 2016 Xamarin Inc (http://www.xamarin.com) +// Copyright (C) 2006 Novell, Inc. http://www.novell.com // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -13,10 +13,10 @@ // 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 @@ -26,14 +26,15 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // - -namespace System.Reflection.Metadata -{ - public static class AssemblyExtensions +namespace System.ServiceModel { + + [System.Runtime.CompilerServices.TypeForwardedFrom (Consts.AssemblySystemServiceModel_3_0)] + public static class ServiceHostingEnvironment { - public static unsafe bool TryGetRawMetadata (this System.Reflection.Assembly assembly, out byte* blob, out int length) + public static bool AspNetCompatibilityEnabled { get; internal set; } + + public static void EnsureServiceAvailable (string virtualPath) { - throw new NotImplementedException (); } } } \ No newline at end of file diff --git a/mcs/class/System.ServiceModel.Internals/Makefile b/mcs/class/System.ServiceModel.Internals/Makefile index 2ddf10ebd2..c6ec76df04 100644 --- a/mcs/class/System.ServiceModel.Internals/Makefile +++ b/mcs/class/System.ServiceModel.Internals/Makefile @@ -8,9 +8,6 @@ endif LIBRARY = System.ServiceModel.Internals.dll LIB_REFS = System System.Core System.Xml -ifneq (2.1, $(FRAMEWORK_VERSION)) - LIB_REFS += System.Configuration -endif LIB_MCS_FLAGS = /unsafe $(REFERENCE_SOURCES_FLAGS) TEST_MCS_FLAGS = $(LIB_MCS_FLAGS) diff --git a/mcs/class/System.ServiceModel/Assembly/AssemblyInfo.cs b/mcs/class/System.ServiceModel/Assembly/AssemblyInfo.cs index f4779a1e60..87999d4b56 100644 --- a/mcs/class/System.ServiceModel/Assembly/AssemblyInfo.cs +++ b/mcs/class/System.ServiceModel/Assembly/AssemblyInfo.cs @@ -75,15 +75,12 @@ using System.Runtime.InteropServices; [assembly: InternalsVisibleTo ("System.ServiceModel.Discovery, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")] // AnnouncementChannelEndpointElementCollection requires it. #endif -#if HAS_ACTIVATION - +#if SERVICEMODEL_ACTIVATION_DEPENDENCY [assembly: TypeForwardedTo (typeof (System.ServiceModel.ServiceHostingEnvironment))] [assembly: TypeForwardedTo (typeof (System.ServiceModel.Activation.ServiceHostFactory))] - #endif #if !MOBILE - [assembly: TypeForwardedTo (typeof (System.ServiceModel.Security.BinarySecretKeyIdentifierClause))] [assembly: TypeForwardedTo (typeof (System.ServiceModel.Security.KeyNameIdentifierClause))] [assembly: TypeForwardedTo (typeof (System.ServiceModel.Security.SecurityContextKeyIdentifierClause))] diff --git a/mcs/class/System.ServiceModel/Makefile b/mcs/class/System.ServiceModel/Makefile index 683b096376..c563c1ad87 100644 --- a/mcs/class/System.ServiceModel/Makefile +++ b/mcs/class/System.ServiceModel/Makefile @@ -30,14 +30,9 @@ endif ifeq (4, $(FRAMEWORK_VERSION_MAJOR)) ifndef NO_SYSTEM_SERVICEMODEL_ACTIVATION_DEPENDENCY -activation = $(the_libdir_base)System.ServiceModel.Activation.dll -servicemodel_deps = $(activation) - -ifneq (plainservice/,$(intermediate)) -LIB_REFS += System.ServiceModel.Activation -LIB_MCS_FLAGS += -define:HAS_ACTIVATION -endif -endif # NO_SYSTEM_SERVICEMODEL_ACTIVATION_DEPENDENCY +API_BIN_REFS := System.ServiceModel.Activation +LIB_MCS_FLAGS += /d:SERVICEMODEL_ACTIVATION_DEPENDENCY +endif ifndef NO_SYSTEM_WEB_APPSERVICES_DEPENDENCY LIB_REFS += System.Web.ApplicationServices @@ -73,22 +68,3 @@ NO_TEST = yes endif include ../../build/library.make - -$(the_libdir_base)System.ServiceModel.dll: $(servicemodel_deps) - -$(activation): - (cd ../System.ServiceModel.Activation; $(MAKE) $@) - -ifneq (plainservice/,$(intermediate)) -$(the_libdir_base)plainservice/System.ServiceModel.dll: - $(MAKE) intermediate=plainservice/ $(the_libdir_base)plainservice/System.ServiceModel.dll -endif - -.NOTPARALLEL: $(servicemodel_deps) - -CLEAN_FILES = $(the_libdir_base)plainservice/System.ServiceModel.dll - -ifndef intermediate -csproj-local: - $(MAKE) csproj-local intermediate=plainservice/ -endif diff --git a/mcs/class/System.ServiceModel/System.ServiceModel.Channels.Http/HttpListenerManagerTable.cs b/mcs/class/System.ServiceModel/System.ServiceModel.Channels.Http/HttpListenerManagerTable.cs index 48a46ebf0b..aaebe298f3 100644 --- a/mcs/class/System.ServiceModel/System.ServiceModel.Channels.Http/HttpListenerManagerTable.cs +++ b/mcs/class/System.ServiceModel/System.ServiceModel.Channels.Http/HttpListenerManagerTable.cs @@ -107,6 +107,12 @@ namespace System.ServiceModel.Channels.Http if (m != null) return m; } + + // Lastly, try to match the listener to the start of the current request path + // This is to support WCF methods with path parameters in UriTemplate annotation + m = listeners.FirstOrDefault (p => absolutePath.StartsWith (p.Key.AbsolutePath, StringComparison.Ordinal)).Value; + if (m != null) + return m; } if (m == null) @@ -119,7 +125,7 @@ namespace System.ServiceModel.Channels.Http { HttpListenerManager m; - if (ServiceHostingEnvironment.InAspNet) + if (ServiceHostingEnvironmentInternal.InAspNet) m = new AspNetHttpListenerManager (uri); else m = new HttpStandaloneListenerManager (uri, element); diff --git a/mcs/class/System.ServiceModel/System.ServiceModel.Channels/SvcHttpHandler.cs b/mcs/class/System.ServiceModel/System.ServiceModel.Channels/SvcHttpHandler.cs index 912f8e79c6..3cd0860de8 100644 --- a/mcs/class/System.ServiceModel/System.ServiceModel.Channels/SvcHttpHandler.cs +++ b/mcs/class/System.ServiceModel/System.ServiceModel.Channels/SvcHttpHandler.cs @@ -28,6 +28,7 @@ // using System; using System.Collections.Generic; +using System.Collections.Concurrent; using System.Collections.ObjectModel; using System.Linq; using System.Web; @@ -51,7 +52,7 @@ namespace System.ServiceModel.Channels Type factory_type; string path; ServiceHostBase host; - Dictionary wcf_wait_handles = new Dictionary (); + ConcurrentDictionary wcf_wait_handles = new ConcurrentDictionary (); int close_state; public SvcHttpHandler (Type type, Type factoryType, string path) @@ -90,10 +91,9 @@ namespace System.ServiceModel.Channels public void EndHttpRequest (HttpContext context) { ManualResetEvent wait; - if (!wcf_wait_handles.TryGetValue (context, out wait)) + if (!wcf_wait_handles.TryRemove (context, out wait)) return; - wcf_wait_handles.Remove (context); if (wait != null) wait.Set (); } @@ -128,10 +128,10 @@ namespace System.ServiceModel.Channels //ServiceHost for this not created yet var baseUri = new Uri (new Uri (HttpContext.Current.Request.Url.GetLeftPart (UriPartial.Authority)), path); -// if (factory_type != null) { -// host = ((ServiceHostFactory) Activator.CreateInstance (factory_type)).CreateServiceHost (type, new Uri [] {baseUri}); -// } -// else + if (factory_type != null) { + host = ((ServiceHostFactory) Activator.CreateInstance (factory_type)).CreateServiceHost (type.ToString(), new Uri [] {baseUri}); + } + else host = new ServiceHost (type, baseUri); host.Extensions.Add (new VirtualPathExtension (baseUri.AbsolutePath)); diff --git a/mcs/class/System.ServiceModel/System.ServiceModel.Channels/SvcHttpHandlerFactory.cs b/mcs/class/System.ServiceModel/System.ServiceModel.Channels/SvcHttpHandlerFactory.cs index e757f00eb9..e8a5b73058 100644 --- a/mcs/class/System.ServiceModel/System.ServiceModel.Channels/SvcHttpHandlerFactory.cs +++ b/mcs/class/System.ServiceModel/System.ServiceModel.Channels/SvcHttpHandlerFactory.cs @@ -49,7 +49,7 @@ namespace System.ServiceModel.Channels { public SvcHttpHandlerFactory () { - ServiceHostingEnvironment.InAspNet = true; + ServiceHostingEnvironmentInternal.InAspNet = true; } public IHttpHandler GetHandler (HttpContext context, string requestType, string url, string pathTranslated) diff --git a/mcs/class/System.ServiceModel/System.ServiceModel.Configuration/ConfigUtil.cs b/mcs/class/System.ServiceModel/System.ServiceModel.Configuration/ConfigUtil.cs index 43918f6f60..e034fca0e9 100644 --- a/mcs/class/System.ServiceModel/System.ServiceModel.Configuration/ConfigUtil.cs +++ b/mcs/class/System.ServiceModel/System.ServiceModel.Configuration/ConfigUtil.cs @@ -48,7 +48,7 @@ namespace System.ServiceModel.Configuration #if !XAMMAC_4_5 static object GetSection (string name) { - if (ServiceHostingEnvironment.InAspNet) + if (ServiceHostingEnvironmentInternal.InAspNet) return WebConfigurationManager.GetSection (name); else return ConfigurationManager.GetSection (name); diff --git a/mcs/class/System.ServiceModel/System.ServiceModel.Description/ContractDescriptionGenerator.cs b/mcs/class/System.ServiceModel/System.ServiceModel.Description/ContractDescriptionGenerator.cs index 50ea0a9058..909952a541 100644 --- a/mcs/class/System.ServiceModel/System.ServiceModel.Description/ContractDescriptionGenerator.cs +++ b/mcs/class/System.ServiceModel/System.ServiceModel.Description/ContractDescriptionGenerator.cs @@ -497,7 +497,6 @@ namespace System.ServiceModel.Description mb.WrapperNamespace = mca.WrapperNamespace ?? defaultNamespace; } - int index = 0; foreach (MemberInfo bmi in messageType.GetMembers (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) { Type mtype = null; string mname = null; @@ -531,13 +530,14 @@ namespace System.ServiceModel.Description var mba = GetMessageBodyMemberAttribute (bmi); if (mba != null) { var pd = CreatePartCore (mba, mname, defaultNamespace); - if (pd.Index <= 0) - pd.Index = index++; pd.Type = MessageFilterOutByRef (mtype); pd.MemberInfo = bmi; mb.Parts.Add (pd); } } + int index = 0; + foreach (var part in mb.Parts) + part.Index = index++; return md; } diff --git a/mcs/class/System.ServiceModel/System.ServiceModel.Dispatcher/ChannelDispatcher.cs b/mcs/class/System.ServiceModel/System.ServiceModel.Dispatcher/ChannelDispatcher.cs index 9629532171..8336663034 100644 --- a/mcs/class/System.ServiceModel/System.ServiceModel.Dispatcher/ChannelDispatcher.cs +++ b/mcs/class/System.ServiceModel/System.ServiceModel.Dispatcher/ChannelDispatcher.cs @@ -615,7 +615,8 @@ namespace System.ServiceModel.Dispatcher if ((!(ex is SocketException)) && (!(ex is XmlException)) && - (!(ex is IOException))) + (!(ex is IOException)) && + rc != null) rc.Reply (res); reply.Close (owner.DefaultCloseTimeout); // close the channel diff --git a/mcs/class/System.ServiceModel/System.ServiceModel.dll.sources b/mcs/class/System.ServiceModel/System.ServiceModel.dll.sources index 5067f01abe..3754386ab5 100644 --- a/mcs/class/System.ServiceModel/System.ServiceModel.dll.sources +++ b/mcs/class/System.ServiceModel/System.ServiceModel.dll.sources @@ -130,7 +130,6 @@ System.Collections.Generic/SynchronizedKeyedCollection.cs System.Collections.Generic/SynchronizedReadOnlyCollection.cs System.IO/PipeException.cs System.ServiceModel.Activation/AspNetIntegrationRequirementsAttribute.cs -System.ServiceModel.Activation/ServiceHostFactory.cs System.ServiceModel.Activation/ServiceHostFactoryBase.cs System.ServiceModel.Activation/VirtualPathExtension.cs System.ServiceModel.Channels/AddressHeader.cs diff --git a/mcs/class/System.ServiceModel/System.ServiceModel/ServiceHostingEnvironment.cs b/mcs/class/System.ServiceModel/System.ServiceModel/ServiceHostingEnvironment.cs index e41c00bb19..a3377e029a 100644 --- a/mcs/class/System.ServiceModel/System.ServiceModel/ServiceHostingEnvironment.cs +++ b/mcs/class/System.ServiceModel/System.ServiceModel/ServiceHostingEnvironment.cs @@ -26,21 +26,10 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -#if !HAS_ACTIVATION - namespace System.ServiceModel { - [System.Runtime.CompilerServices.TypeForwardedFrom (Consts.AssemblySystemServiceModel_3_0)] - public static class ServiceHostingEnvironment + static class ServiceHostingEnvironmentInternal { internal static bool InAspNet { get; set; } - - public static bool AspNetCompatibilityEnabled { get; internal set; } - - public static void EnsureServiceAvailable (string virtualPath) - { - } } } - -#endif diff --git a/mcs/class/System.ServiceProcess/Makefile b/mcs/class/System.ServiceProcess/Makefile index 8414fa099f..13195ce8eb 100644 --- a/mcs/class/System.ServiceProcess/Makefile +++ b/mcs/class/System.ServiceProcess/Makefile @@ -6,7 +6,8 @@ LIBRARY = System.ServiceProcess.dll LIB_REFS = System System.Configuration.Install System.Windows.Forms KEYFILE = ../msfinal.pub LIB_MCS_FLAGS = /nowarn:0618 -TEST_MCS_FLAGS = $(LIB_MCS_FLAGS) +TEST_MCS_FLAGS = +TEST_LIB_REFS = System EXTRA_DISTFILES = diff --git a/mcs/class/System.Threading.Tasks.Dataflow/Makefile b/mcs/class/System.Threading.Tasks.Dataflow/Makefile index 77e279ebb2..6ca3d61e47 100644 --- a/mcs/class/System.Threading.Tasks.Dataflow/Makefile +++ b/mcs/class/System.Threading.Tasks.Dataflow/Makefile @@ -8,9 +8,9 @@ LIB_REFS += System.Core System KEYFILE = ../ecma.pub LIB_MCS_FLAGS += -d:CONCURRENT_COLLECTIONS -include ../../build/library.make - TEST_MCS_FLAGS = TEST_LIB_REFS = System.Core System EXTRA_DISTFILES=README.md + +include ../../build/library.make diff --git a/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/MetaColumnTest.cs b/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/MetaColumnTest.cs index 17766eae14..fa18a7e3b6 100644 --- a/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/MetaColumnTest.cs +++ b/mcs/class/System.Web.DynamicData/Test/System.Web.DynamicData/MetaColumnTest.cs @@ -109,32 +109,32 @@ namespace MonoTests.System.Web.DynamicData MetaColumn mc = t.GetColumn ("ColumnNoAttributes"); Assert.IsNotNull (mc, "#A1"); Assert.IsNotNull (mc.Attributes, "#A2"); - Assert.AreEqual (6, mc.Attributes.Count, "#A3"); + Assert.AreEqual (4, mc.Attributes.Count, "#A3"); Assert.IsTrue (mc.IsRequired, "#A3-1"); mc = t.GetColumn ("ColumnFormatInEditMode"); Assert.IsNotNull (mc, "#A4"); Assert.IsNotNull (mc.Attributes, "#A4-1"); - Assert.AreEqual (7, mc.Attributes.Count, "#A4-2"); + Assert.AreEqual (5, mc.Attributes.Count, "#A4-2"); Assert.AreEqual (1, mc.Attributes.OfType ().Count (), "#A4-3"); mc = t.GetColumn ("ColumnWithDataType"); Assert.IsNotNull (mc, "#A5"); Assert.IsNotNull (mc.Attributes, "#A5-1"); - Assert.AreEqual (7, mc.Attributes.Count, "#A5-2"); + Assert.AreEqual (5, mc.Attributes.Count, "#A5-2"); Assert.AreEqual (1, mc.Attributes.OfType ().Count (), "#A5-3"); t = m.Tables[TestDataContext.TableFooWithMetadataType]; mc = t.GetColumn ("Column1"); Assert.IsNotNull (mc, "#B1"); Assert.IsNotNull (mc.Attributes, "#B1-1"); - Assert.AreEqual (9, mc.Attributes.Count, "#B1-2"); + Assert.AreEqual (7, mc.Attributes.Count, "#B1-2"); Assert.AreEqual (1, mc.Attributes.OfType ().Count (), "#B1-3"); mc = t.GetColumn ("Column2"); Assert.IsNotNull (mc, "#B2"); Assert.IsNotNull (mc.Attributes, "#B2-1"); - Assert.AreEqual (8, mc.Attributes.Count, "#B2-2"); + Assert.AreEqual (6, mc.Attributes.Count, "#B2-2"); Assert.AreEqual (1, mc.Attributes.OfType ().Count (), "#B2-3"); } diff --git a/mcs/class/System.Web.Extensions/Makefile b/mcs/class/System.Web.Extensions/Makefile index 1d2c48154a..317cd32029 100644 --- a/mcs/class/System.Web.Extensions/Makefile +++ b/mcs/class/System.Web.Extensions/Makefile @@ -39,7 +39,7 @@ NUNIT_RESOURCE_FILES= \ CLASSLIB_DIR = $(topdir)/class/lib/$(PROFILE) STANDALONE_RUNNER_SUPPORT_ASSEMBLY = $(CLASSLIB_DIR)/standalone-runner-support.dll -STANDALONE_TEST_MCS_FLAGS = $(LIB_MCS_FLAGS) $(PROFILE_MCS_FLAGS) -r:$(STANDALONE_RUNNER_SUPPORT_ASSEMBLY) -r:$(topdir)/class/lib/$(PROFILE)/System.Web.dll -r:$(topdir)/class/lib/$(PROFILE)/System.Web.Extensions.dll -r:$(topdir)/class/lib/$(PROFILE)/nunit.framework.dll +STANDALONE_TEST_MCS_FLAGS = $(LIB_MCS_FLAGS) $(PROFILE_MCS_FLAGS) -r:$(STANDALONE_RUNNER_SUPPORT_ASSEMBLY) -r:$(topdir)/class/lib/$(PROFILE)/mscorlib.dll -r:$(topdir)/class/lib/$(PROFILE)/System.Web.dll -r:$(topdir)/class/lib/$(PROFILE)/System.Web.Extensions.dll -r:$(topdir)/class/lib/$(PROFILE)/nunit.framework.dll STANDALONE_TEST_ASSEMBLY = System.Web.Extensions_standalone_test_$(PROFILE).dll STANDALONE_TEST_MAKEFRAG = $(depsdir)/$(STANDALONE_TEST_ASSEMBLY).makefrag diff --git a/mcs/class/System.Web.Services/Makefile b/mcs/class/System.Web.Services/Makefile index 566da23778..308990590f 100644 --- a/mcs/class/System.Web.Services/Makefile +++ b/mcs/class/System.Web.Services/Makefile @@ -16,15 +16,11 @@ LIB_REFS = System System.EnterpriseServices System.Xml System.Data LIB_MCS_FLAGS = -nowarn:168,612,618,649 -d:MONO_BROKEN_CONFIGURATION_DLL ifndef NO_SYSTEM_WEB_DEPENDENCY -plainweb = $(the_libdir_base)plainweb/System.Web.dll -system_web_deps = $(plainweb) -LIB_REFS += plainweb/System.Web +API_BIN_REFS := System.Web endif ifndef NO_SYSTEM_DESIGN_DEPENDENCY -plaindesign = $(the_libdir_base)plaindesign/System.Design.dll -system_design_deps = $(plaindesign) -LIB_REFS += plaindesign/System.Design +LIB_REFS += System.Design endif ifndef NO_SYSTEM_DIRECTORY_SERVICES_DEPENDENCY @@ -56,13 +52,3 @@ EXTRA_DISTFILES = \ Test/System.Web.Services.Description/*.wsdl include ../../build/library.make - -$(the_libdir_base)$(LIBRARY): $(system_web_deps) $(system_design_deps) - -$(plainweb): - (cd ../System.Web; $(MAKE) $@) - -$(plaindesign): - (cd ../System.Design; $(MAKE) $@) - -.NOTPARALLEL: $(plainweb) $(plaindesign) diff --git a/mcs/class/System.Web/Makefile b/mcs/class/System.Web/Makefile index 495c1ea6b0..dd0a0f017e 100644 --- a/mcs/class/System.Web/Makefile +++ b/mcs/class/System.Web/Makefile @@ -242,7 +242,7 @@ endif TXT_RESOURCE_STRINGS = ../referencesource/System.Web/System.Web.txt LIB_REFS = System System.Core System.Drawing System.Data System.Xml System.EnterpriseServices System.Runtime.Serialization.Formatters.Soap \ - System.ComponentModel.DataAnnotations System.Web.ApplicationServices System.Configuration Mono.Data.Sqlite + System.ComponentModel.DataAnnotations System.Web.ApplicationServices System.Configuration Mono.Data.Sqlite System.Web.Services System.Design KEYFILE = ../msfinal.pub LIB_MCS_FLAGS = \ -unsafe \ @@ -251,13 +251,7 @@ LIB_MCS_FLAGS = \ $(RESX_RES:%=/resource:%) \ $(OTHER_RES:%=/resource:%) -ifneq (plainweb/,$(intermediate)) -LIB_REFS += System.Web.Services plaindesign/System.Design -LIB_MCS_FLAGS += -define:WEBSERVICES_DEP - -all-local: System.Web/UplevelHelper.cs - -endif +#all-local: System.Web/UplevelHelper.cs TEST_LIB_REFS = SystemWebTestShim TEST_MCS_FLAGS = $(LIB_MCS_FLAGS) -doc:$(test_lib:.dll=.xml) -nowarn:219,169,1591 \ @@ -287,19 +281,6 @@ BUILT_SOURCES = System.Web/UplevelHelper.cs include ../../build/library.make -$(the_libdir_base)System.Web.dll: $(the_libdir_base)System.Web.Services.dll - -$(the_libdir_base)System.Web.Services.dll: - (cd ../System.Web.Services; $(MAKE) $@) - -ifneq (plainweb/,$(intermediate)) -$(the_libdir_base)plainweb/System.Web.dll: - $(MAKE) intermediate=plainweb/ $(the_libdir_base)plainweb/System.Web.dll - -endif - -.NOTPARALLEL: $(the_libdir_base)plainweb/System.Web.dll $(the_libdir_base)System.Web.Services.dll - ifdef DEBUG LIB_MCS_FLAGS += -define:DEBUG endif @@ -430,10 +411,3 @@ ifdef STANDALONE_TEST_COMPILABLE_TESTS $(MAKE) -C Test/standalone/$$d clean ; \ done endif - -ifndef intermediate -ifneq ($(PROFILE),basic) -csproj-local: - $(MAKE) csproj-local intermediate=plainweb/ -endif -endif diff --git a/mcs/class/System.Web/System.Web.Configuration_2.0/SystemWebSectionGroup.cs b/mcs/class/System.Web/System.Web.Configuration_2.0/SystemWebSectionGroup.cs index 4492ffb0cc..d7a0cf141a 100644 --- a/mcs/class/System.Web/System.Web.Configuration_2.0/SystemWebSectionGroup.cs +++ b/mcs/class/System.Web/System.Web.Configuration_2.0/SystemWebSectionGroup.cs @@ -31,9 +31,7 @@ using System; using System.Configuration; -#if WEBSERVICES_DEP using System.Web.Services.Configuration; -#endif namespace System.Web.Configuration { @@ -205,12 +203,10 @@ namespace System.Web.Configuration get { return (WebPartsSection)Sections ["webParts"]; } } -#if WEBSERVICES_DEP [ConfigurationProperty ("webServices")] public WebServicesSection WebServices { get { return (WebServicesSection)Sections ["webServices"]; } } -#endif [ConfigurationProperty ("xhtmlConformance")] public XhtmlConformanceSection XhtmlConformance { diff --git a/mcs/class/System.Web/System.Web/HttpRequest.cs b/mcs/class/System.Web/System.Web/HttpRequest.cs index 8e9359a9f8..98c1238a41 100755 --- a/mcs/class/System.Web/System.Web/HttpRequest.cs +++ b/mcs/class/System.Web/System.Web/HttpRequest.cs @@ -841,7 +841,7 @@ namespace System.Web byte [] buffer; buffer = worker_request.GetPreloadedEntityBody (); // we check the instance field 'content_length' here, not the local var. - if (this.content_length <= 0 || worker_request.IsEntireEntityBodyIsPreloaded ()) { + if (this.content_length == 0 || worker_request.IsEntireEntityBodyIsPreloaded ()) { if (buffer == null || content_length == 0) { input_stream = new MemoryStream (new byte [0], 0, 0, false, true); } else { @@ -2068,11 +2068,19 @@ namespace System.Web static string GetContentDispositionAttribute (string l, string name) { - int idx = l.IndexOf (name + "=\""); + int idx = l.IndexOf (name + "="); if (idx < 0) return null; - int begin = idx + name.Length + "=\"".Length; - int end = l.IndexOf ('"', begin); + int begin = idx + name.Length + "=".Length; + int end; + if (l.Length > begin && l [begin] == '"') { + begin++; + end = l.IndexOf ('"', begin); + } else { + end = l.IndexOf (';', begin); + if (end == -1) + end = l.Length; + } if (end < 0) return null; if (begin == end) @@ -2082,11 +2090,19 @@ namespace System.Web string GetContentDispositionAttributeWithEncoding (string l, string name) { - int idx = l.IndexOf (name + "=\""); + int idx = l.IndexOf (name + "="); if (idx < 0) return null; - int begin = idx + name.Length + "=\"".Length; - int end = l.IndexOf ('"', begin); + int begin = idx + name.Length + "=".Length; + int end; + if (l.Length > begin && l [begin] == '"') { + begin++; + end = l.IndexOf ('"', begin); + } else { + end = l.IndexOf (';', begin); + if (end == -1) + end = l.Length; + } if (end < 0) return null; if (begin == end) diff --git a/mcs/class/System.Web/Test/System.Web/HttpRequestTest.cs b/mcs/class/System.Web/Test/System.Web/HttpRequestTest.cs index 117648b6e8..83cb7dca27 100644 --- a/mcs/class/System.Web/Test/System.Web/HttpRequestTest.cs +++ b/mcs/class/System.Web/Test/System.Web/HttpRequestTest.cs @@ -1055,5 +1055,47 @@ namespace MonoTests.System.Web { } } + + // This test ensures the HttpRequest object's InputStream property + // gets properly constructed and populated when the request is not + // preloaded. + [TestFixture] + public class Test_NonPreloadedRequest + { + private const string expected = "Hello, World!\n"; + + class FakeHttpWorkerRequest : BaseFakeHttpWorkerRequest + { + private readonly Stream body = new MemoryStream(Encoding.UTF8.GetBytes(expected)); + + public override string GetHttpVerbName() + { + return "POST"; + } + + public override int ReadEntityBody(byte[] buffer, int size) + { + return body.Read(buffer, 0, size); + } + } + + HttpContext context = null; + + [SetUp] + [Category ("NotDotNet")] // Cannot be runned on .net with no web context + public void SetUp() + { + HttpWorkerRequest workerRequest = new FakeHttpWorkerRequest(); + context = new HttpContext(workerRequest); + } + + [Test] + [Category ("NotDotNet")] // Cannot be runned on .net with no web context + public void InputStream_Contents() + { + Assert.AreEqual(expected, new StreamReader(context.Request.InputStream, Encoding.UTF8).ReadToEnd()); + } + + } } diff --git a/mcs/class/System.Web/Test/tools/Makefile b/mcs/class/System.Web/Test/tools/Makefile index 9cbb4159d0..09755061ff 100644 --- a/mcs/class/System.Web/Test/tools/Makefile +++ b/mcs/class/System.Web/Test/tools/Makefile @@ -12,7 +12,8 @@ STANDALONE_RUNNER_SOURCES = \ STANDALONE_RUNNER_REFERENCES = \ -r:$(STANDALONE_RUNNER_SUPPORT_ASSEMBLY) \ -r:$(CLASSLIB_DIR)/System.Web.dll \ - -r:$(CLASSLIB_DIR)/System.dll + -r:$(CLASSLIB_DIR)/System.dll \ + -r:$(CLASSLIB_DIR)/mscorlib.dll CACHE_PQ_TEST_GENERATOR_SOURCES = \ CachePQTestGenerator/CacheItemComparer.cs \ diff --git a/mcs/class/System.Windows.Forms/Assembly/AssemblyInfo.cs b/mcs/class/System.Windows.Forms/Assembly/AssemblyInfo.cs index 9f94433c9b..a407331a12 100644 --- a/mcs/class/System.Windows.Forms/Assembly/AssemblyInfo.cs +++ b/mcs/class/System.Windows.Forms/Assembly/AssemblyInfo.cs @@ -45,4 +45,5 @@ using System.Diagnostics; [assembly: InternalsVisibleTo("UIAutomationWinforms, PublicKey=00240000048000009400000006020000002400005253413100040000110000004bb98b1af6c1df0df8c02c380e116b7a7f0c8c827aecfccddc6e29b7c754cd608b49dfcef4df9699ad182e50f66afa4e68dabc7b6aeeec0aa4719a5f8e0aae8c193080a706adc3443a8356b1f254142034995532ac176398e12a30f6a74a119a89ac47672c9ae24d7e90de686557166e3b873cd707884431a0451d9d6f7fe795")] [assembly: InternalsVisibleTo("Mono.WinformsSupport, PublicKey=00240000048000009400000006020000002400005253413100040000110000004bb98b1af6c1df0df8c02c380e116b7a7f0c8c827aecfccddc6e29b7c754cd608b49dfcef4df9699ad182e50f66afa4e68dabc7b6aeeec0aa4719a5f8e0aae8c193080a706adc3443a8356b1f254142034995532ac176398e12a30f6a74a119a89ac47672c9ae24d7e90de686557166e3b873cd707884431a0451d9d6f7fe795")] +[assembly: InternalsVisibleTo("CocoaDriver, PublicKey=0024000004800000940000000602000000240000525341310004000001000100dfb6f531e52a405fce7bb127fdff8b462a29426618ae319093a6479dbc037c76ce025581c272d47806d3c4c9a65304b7ddacff806e6c7e6483f985a5ac39498190c87b7ddb13d3e9c7107f0ceef392ce3fd01391fd9f61199449fd8702ab0d9c2d32dee637bc557ecc7f75c85b350d0d80d8efdb5bdaa6ecaddae0a23a1eb8db")] diff --git a/mcs/class/System.Windows.Forms/Makefile b/mcs/class/System.Windows.Forms/Makefile index 325be31652..43be6492b3 100644 --- a/mcs/class/System.Windows.Forms/Makefile +++ b/mcs/class/System.Windows.Forms/Makefile @@ -110,7 +110,7 @@ TEST_MCS_FLAGS = \ DummyAssembly.dll: $(CSCOMPILE) /target:library /out:$@ Test/DummyAssembly/AnotherSerializable.cs Test/DummyAssembly/Convertable.cs Test/DummyAssembly/Properties/AssemblyInfo.cs \ - -r:$(topdir)/class/lib/$(PROFILE)/System.dll + -r:$(topdir)/class/lib/$(PROFILE)/mscorlib.dll -r:$(topdir)/class/lib/$(PROFILE)/System.dll test-local: DummyAssembly.dll @@ -131,8 +131,14 @@ $(PREBUILT): %.prebuilt: % dist-default: $(PREBUILT) -simple-test.exe: Test/simple/Program.cs $(topdir)/class/lib/$(PROFILE)/System.Windows.Forms.dll - $(CSCOMPILE) -out:$@ Test/simple/Program.cs -r:$(topdir)/class/lib/$(PROFILE)/System.Windows.Forms.dll +simple-test.exe: Test/simple/Program.cs $(topdir)/class/lib/$(PROFILE)/System.Windows.Forms.dll $(topdir)/class/lib/$(PROFILE)/mscorlib.dll + $(CSCOMPILE) -out:$@ Test/simple/Program.cs -r:$(topdir)/class/lib/$(PROFILE)/System.Windows.Forms.dll -r:$(topdir)/class/lib/$(PROFILE)/mscorlib.dll test-simple: simple-test.exe $(TEST_RUNTIME) $(TEST_RUNTIME_FLAGS) simple-test.exe + +notepad.exe: samples/notepad.cs $(topdir)/class/lib/$(PROFILE)/System.Windows.Forms.dll $(topdir)/class/lib/$(PROFILE)/System.Drawing.dll $(topdir)/class/lib/$(PROFILE)/System.dll $(topdir)/class/lib/$(PROFILE)/mscorlib.dll + $(CSCOMPILE) -out:$@ samples/notepad.cs -r:$(topdir)/class/lib/$(PROFILE)/System.Windows.Forms.dll -r:$(topdir)/class/lib/$(PROFILE)/System.Drawing.dll -r:$(topdir)/class/lib/$(PROFILE)/System.dll -r:$(topdir)/class/lib/$(PROFILE)/mscorlib.dll + +test-notepad: notepad.exe + $(TEST_RUNTIME) $(TEST_RUNTIME_FLAGS) notepad.exe diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms.Layout/DefaultLayout.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms.Layout/DefaultLayout.cs index c3a4463c65..d9513c3726 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms.Layout/DefaultLayout.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms.Layout/DefaultLayout.cs @@ -29,31 +29,47 @@ using System; using System.Drawing; +using System.Collections; namespace System.Windows.Forms.Layout { class DefaultLayout : LayoutEngine { - void LayoutDockedChildren (Control parent, Control[] controls) + internal static readonly DefaultLayout Instance = new DefaultLayout(); + + private DefaultLayout () + { + } + + public override void InitLayout (object child, BoundsSpecified specified) + { + IArrangedElement control = (IArrangedElement)child; + IArrangedElement parent = control.Parent; + if (parent != null) { + Rectangle bounds = control.Bounds; + if ((specified & (BoundsSpecified.Width | BoundsSpecified.X)) != BoundsSpecified.None) + control.DistanceRight = parent.DisplayRectangle.Right - bounds.X - bounds.Width; + if ((specified & (BoundsSpecified.Height | BoundsSpecified.Y)) != BoundsSpecified.None) + control.DistanceBottom = parent.DisplayRectangle.Bottom - bounds.Y - bounds.Height; + } + } + + static void LayoutDockedChildren (IArrangedElement parent, IList controls) { Rectangle space = parent.DisplayRectangle; - MdiClient mdi = null; + IArrangedElement mdi = null; // Deal with docking; go through in reverse, MS docs say that lowest Z-order is closest to edge - for (int i = controls.Length - 1; i >= 0; i--) { - Control child = controls[i]; - Size child_size = child.Size; + for (int i = controls.Count - 1; i >= 0; i--) { + IArrangedElement child = (IArrangedElement)controls[i]; + Size child_size = child.Bounds.Size; - if (child.AutoSize) - child_size = GetPreferredControlSize (child); - - if (!child.VisibleInternal - || child.ControlLayoutType == Control.LayoutType.Anchor) + if (!child.Visible || child.Dock == DockStyle.None) continue; // MdiClient never fills the whole area like other controls, have to do it later if (child is MdiClient) { - mdi = (MdiClient)child; + mdi = child; continue; } @@ -63,193 +79,139 @@ namespace System.Windows.Forms.Layout break; case DockStyle.Left: - child.SetBoundsInternal (space.Left, space.Y, child_size.Width, space.Height, BoundsSpecified.None); - space.X += child.Width; - space.Width -= child.Width; + if (child.AutoSize) + child_size = child.GetPreferredSize(new Size(0, space.Height)); + child.SetBounds (space.Left, space.Y, child_size.Width, space.Height, BoundsSpecified.None); + space.X += child_size.Width; + space.Width -= child_size.Width; break; case DockStyle.Top: - child.SetBoundsInternal (space.Left, space.Y, space.Width, child_size.Height, BoundsSpecified.None); - space.Y += child.Height; - space.Height -= child.Height; + if (child.AutoSize) + child_size = child.GetPreferredSize(new Size(space.Width, 0)); + child.SetBounds (space.Left, space.Y, space.Width, child_size.Height, BoundsSpecified.None); + space.Y += child_size.Height; + space.Height -= child_size.Height; break; case DockStyle.Right: - child.SetBoundsInternal (space.Right - child_size.Width, space.Y, child_size.Width, space.Height, BoundsSpecified.None); - space.Width -= child.Width; + if (child.AutoSize) + child_size = child.GetPreferredSize(new Size(0, space.Height)); + child.SetBounds (space.Right - child_size.Width, space.Y, child_size.Width, space.Height, BoundsSpecified.None); + space.Width -= child_size.Width; break; case DockStyle.Bottom: - child.SetBoundsInternal (space.Left, space.Bottom - child_size.Height, space.Width, child_size.Height, BoundsSpecified.None); - space.Height -= child.Height; + if (child.AutoSize) + child_size = child.GetPreferredSize(new Size(space.Width, 0)); + child.SetBounds (space.Left, space.Bottom - child_size.Height, space.Width, child_size.Height, BoundsSpecified.None); + space.Height -= child_size.Height; break; case DockStyle.Fill: - child.SetBoundsInternal (space.Left, space.Top, space.Width, space.Height, BoundsSpecified.None); + child.SetBounds (space.Left, space.Top, space.Width, space.Height, BoundsSpecified.None); break; } } // MdiClient gets whatever space is left if (mdi != null) - mdi.SetBoundsInternal (space.Left, space.Top, space.Width, space.Height, BoundsSpecified.None); + mdi.SetBounds (space.Left, space.Top, space.Width, space.Height, BoundsSpecified.None); } - void LayoutAnchoredChildren (Control parent, Control[] controls) + static void LayoutAnchoredChildren (IArrangedElement parent, IList controls) { - Rectangle space = parent.ClientRectangle; + Rectangle space = parent.DisplayRectangle; - for (int i = 0; i < controls.Length; i++) { - int left; - int top; - int width; - int height; - - Control child = controls[i]; - - if (!child.VisibleInternal - || child.ControlLayoutType == Control.LayoutType.Dock) + foreach (IArrangedElement child in controls) { + if (!child.Visible || child.Dock != DockStyle.None) continue; AnchorStyles anchor = child.Anchor; - - left = child.Left; - top = child.Top; - - width = child.Width; - height = child.Height; + Rectangle bounds = child.Bounds; + int left = bounds.Left; + int top = bounds.Top; + int width = bounds.Width; + int height = bounds.Height; if ((anchor & AnchorStyles.Right) != 0) { if ((anchor & AnchorStyles.Left) != 0) - width = space.Width - child.dist_right - left; + width = space.Right - child.DistanceRight - left; else - left = space.Width - child.dist_right - width; + left = space.Right - child.DistanceRight - width; } else if ((anchor & AnchorStyles.Left) == 0) { // left+=diff_width/2 will introduce rounding errors (diff_width removed from svn after r51780) // This calculates from scratch every time: - left = left + (space.Width - (left + width + child.dist_right)) / 2; - child.dist_right = space.Width - (left + width); + left += (space.Width - (left + width + child.DistanceRight)) / 2; + child.DistanceRight = space.Width - (left + width); } if ((anchor & AnchorStyles.Bottom) != 0) { if ((anchor & AnchorStyles.Top) != 0) - height = space.Height - child.dist_bottom - top; + height = space.Bottom - child.DistanceBottom - top; else - top = space.Height - child.dist_bottom - height; + top = space.Bottom - child.DistanceBottom - height; } else if ((anchor & AnchorStyles.Top) == 0) { // top += diff_height/2 will introduce rounding errors (diff_height removed from after r51780) // This calculates from scratch every time: - top = top + (space.Height - (top + height + child.dist_bottom)) / 2; - child.dist_bottom = space.Height - (top + height); + top += (space.Height - (top + height + child.DistanceBottom)) / 2; + child.DistanceBottom = space.Height - (top + height); } // Sanity if (width < 0) width = 0; - if (height < 0) height = 0; - child.SetBoundsInternal (left, top, width, height, BoundsSpecified.None); + if (child.AutoSize) { + Size proposed_size = Size.Empty; + if ((anchor & (AnchorStyles.Left | AnchorStyles.Right)) == (AnchorStyles.Left | AnchorStyles.Right)) + proposed_size.Width = width; + if ((anchor & (AnchorStyles.Top | AnchorStyles.Bottom)) == (AnchorStyles.Top | AnchorStyles.Bottom)) + proposed_size.Height = height; + + Size preferred_size = GetPreferredControlSize (child, proposed_size); + + if ((anchor & (AnchorStyles.Left | AnchorStyles.Right)) != AnchorStyles.Right) + child.DistanceRight += width - preferred_size.Width; + else + left += width - preferred_size.Width; + if ((anchor & (AnchorStyles.Top | AnchorStyles.Bottom)) != AnchorStyles.Bottom) + child.DistanceBottom += height - preferred_size.Height; + else + top += height - preferred_size.Height; + + child.SetBounds (left, top, preferred_size.Width, preferred_size.Height, BoundsSpecified.None); + } else { + child.SetBounds (left, top, width, height, BoundsSpecified.None); + } } } - - void LayoutAutoSizedChildren (Control parent, Control[] controls) - { - for (int i = 0; i < controls.Length; i++) { - int left; - int top; - - Control child = controls[i]; - if (!child.VisibleInternal - || child.ControlLayoutType == Control.LayoutType.Dock - || !child.AutoSize) - continue; - - AnchorStyles anchor = child.Anchor; - left = child.Left; - top = child.Top; - - Size preferredsize = GetPreferredControlSize (child); - - if (((anchor & AnchorStyles.Left) != 0) || ((anchor & AnchorStyles.Right) == 0)) - child.dist_right += child.Width - preferredsize.Width; - if (((anchor & AnchorStyles.Top) != 0) || ((anchor & AnchorStyles.Bottom) == 0)) - child.dist_bottom += child.Height - preferredsize.Height; - - child.SetBoundsInternal (left, top, preferredsize.Width, preferredsize.Height, BoundsSpecified.None); - } - } - - void LayoutAutoSizeContainer (Control container) - { - int left; - int top; - int width; - int height; - - if (!container.VisibleInternal || container.ControlLayoutType == Control.LayoutType.Dock || !container.AutoSize) - return; - - left = container.Left; - top = container.Top; - - Size preferredsize = container.PreferredSize; - - if (container.GetAutoSizeMode () == AutoSizeMode.GrowAndShrink) { - width = preferredsize.Width; - height = preferredsize.Height; - } else { - width = container.ExplicitBounds.Width; - height = container.ExplicitBounds.Height; - if (preferredsize.Width > width) - width = preferredsize.Width; - if (preferredsize.Height > height) - height = preferredsize.Height; - } - - // Sanity - if (width < container.MinimumSize.Width) - width = container.MinimumSize.Width; - - if (height < container.MinimumSize.Height) - height = container.MinimumSize.Height; - - if (container.MaximumSize.Width != 0 && width > container.MaximumSize.Width) - width = container.MaximumSize.Width; - - if (container.MaximumSize.Height != 0 && height > container.MaximumSize.Height) - height = container.MaximumSize.Height; - - container.SetBoundsInternal (left, top, width, height, BoundsSpecified.None); - } public override bool Layout (object container, LayoutEventArgs args) { - Control parent = container as Control; + IArrangedContainer parent = (IArrangedContainer)container; - Control[] controls = parent.Controls.GetAllControls (); + LayoutDockedChildren (parent, parent.Controls); + LayoutAnchoredChildren (parent, parent.Controls); - LayoutDockedChildren (parent, controls); - LayoutAnchoredChildren (parent, controls); - LayoutAutoSizedChildren (parent, controls); - if (parent is Form) LayoutAutoSizeContainer (parent); - - return false; + return parent.AutoSize; } - private Size GetPreferredControlSize (Control child) + static private Size GetPreferredControlSize (IArrangedElement child, Size proposed) { - int width; - int height; - Size preferredsize = child.PreferredSize; - - if (child.GetAutoSizeMode () == AutoSizeMode.GrowAndShrink || (child.Dock != DockStyle.None && !(child is Button) && !(child is FlowLayoutPanel))) { + var preferredsize = child.GetPreferredSize (proposed); + int width, height; + if (child.GetAutoSizeMode () == AutoSizeMode.GrowAndShrink) + { width = preferredsize.Width; height = preferredsize.Height; - } else { + } + else + { width = child.ExplicitBounds.Width; height = child.ExplicitBounds.Height; if (preferredsize.Width > width) @@ -257,34 +219,64 @@ namespace System.Windows.Forms.Layout if (preferredsize.Height > height) height = preferredsize.Height; } - if (child.AutoSize && child is FlowLayoutPanel && child.Dock != DockStyle.None) { - switch (child.Dock) { - case DockStyle.Left: - case DockStyle.Right: - if (preferredsize.Width < child.ExplicitBounds.Width && preferredsize.Height < child.Parent.PaddingClientRectangle.Height) - width = preferredsize.Width; - break; - case DockStyle.Top: - case DockStyle.Bottom: - if (preferredsize.Height < child.ExplicitBounds.Height && preferredsize.Width < child.Parent.PaddingClientRectangle.Width) - height = preferredsize.Height; - break; + return new Size(width, height); + } + + internal override Size GetPreferredSize (object container, Size proposedConstraints) + { + IArrangedContainer parent = (IArrangedContainer)container; + IList controls = parent.Controls; + Size retsize = Size.Empty; + + // Add up the requested sizes for Docked controls + for (int i = controls.Count - 1; i >= 0; i--) { + IArrangedElement child = (IArrangedElement)controls[i]; + if (!child.Visible || child.Dock == DockStyle.None) + continue; + + if (child.Dock == DockStyle.Left || child.Dock == DockStyle.Right) { + Size sz = child.AutoSize ? child.GetPreferredSize (new Size(0, proposedConstraints.Height)) : child.Bounds.Size; + retsize.Width += sz.Width; + } else if (child.Dock == DockStyle.Top || child.Dock == DockStyle.Bottom) { + Size sz = child.AutoSize ? child.GetPreferredSize (new Size(proposedConstraints.Width, 0)) : child.Bounds.Size; + retsize.Height += sz.Height; + } else if (child.Dock == DockStyle.Fill && child.AutoSize) { + Size sz = child.GetPreferredSize (proposedConstraints); + retsize += sz; } } - // Sanity - if (width < child.MinimumSize.Width) - width = child.MinimumSize.Width; - if (height < child.MinimumSize.Height) - height = child.MinimumSize.Height; + // See if any non-Docked control is positioned lower or more right than our size + foreach (IArrangedElement child in parent.Controls) { + if (!child.Visible || child.Dock != DockStyle.None) + continue; + + // If its anchored to the bottom or right, that doesn't really count + if ((child.Anchor & (AnchorStyles.Bottom | AnchorStyles.Top)) == AnchorStyles.Bottom || + (child.Anchor & (AnchorStyles.Right | AnchorStyles.Left)) == AnchorStyles.Right) + continue; - if (child.MaximumSize.Width != 0 && width > child.MaximumSize.Width) - width = child.MaximumSize.Width; + Rectangle child_bounds = child.Bounds; + if (child.AutoSize) { + Size proposed_child_size = Size.Empty; + if ((child.Anchor & (AnchorStyles.Left | AnchorStyles.Right)) == (AnchorStyles.Left | AnchorStyles.Right)) { + proposed_child_size.Width = proposedConstraints.Width - child.DistanceRight - (child_bounds.Left - parent.DisplayRectangle.Left); + } + if ((child.Anchor & (AnchorStyles.Top | AnchorStyles.Bottom)) == (AnchorStyles.Top | AnchorStyles.Bottom)) { + proposed_child_size.Height = proposedConstraints.Height - child.DistanceBottom - (child_bounds.Top - parent.DisplayRectangle.Top); + } + Size preferred_size = GetPreferredControlSize (child, proposed_child_size); + child_bounds = new Rectangle (child_bounds.Location, preferred_size); + } - if (child.MaximumSize.Height != 0 && height > child.MaximumSize.Height) - height = child.MaximumSize.Height; - - return new Size (width, height); - } + // This is the non-sense Microsoft uses (Padding vs DisplayRectangle) + retsize.Width = Math.Max (retsize.Width, child_bounds.Right - parent.Padding.Left + child.Margin.Right); + retsize.Height = Math.Max (retsize.Height, child_bounds.Bottom - parent.Padding.Top + child.Margin.Bottom); + //retsize.Width = Math.Max (retsize.Width, child_bounds.Right - parent.DisplayRectangle.Left + child.Margin.Right); + //retsize.Height = Math.Max (retsize.Height, child_bounds.Bottom - parent.DisplayRectangle.Top + child.Margin.Bottom); + } + + return retsize; + } } } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms.Layout/FlowLayout.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms.Layout/FlowLayout.cs index 12df600746..811c46a3f1 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms.Layout/FlowLayout.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms.Layout/FlowLayout.cs @@ -34,9 +34,11 @@ namespace System.Windows.Forms.Layout { class FlowLayout : LayoutEngine { + internal static readonly FlowLayout Instance = new FlowLayout(); + private static FlowLayoutSettings default_settings = new FlowLayoutSettings (); - public FlowLayout () + private FlowLayout () { } @@ -45,24 +47,26 @@ namespace System.Windows.Forms.Layout base.InitLayout (child, specified); } + private static FlowLayoutSettings GetLayoutSettings (IArrangedContainer container) + { + if (container is FlowLayoutPanel flp) + return flp.LayoutSettings; + if (container is ToolStrip ts) + return (FlowLayoutSettings)ts.LayoutSettings; + return default_settings; + } + public override bool Layout (object container, LayoutEventArgs args) { + // TODO: Handle ToolStripPanel/ToolStripPanelRow if (container is ToolStripPanel) return false; - if (container is ToolStrip) - return LayoutToolStrip ((ToolStrip)container); - - Control parent = container as Control; - - FlowLayoutSettings settings; - if (parent is FlowLayoutPanel) - settings = (parent as FlowLayoutPanel).LayoutSettings; - else - settings = default_settings; + IArrangedContainer parent = (IArrangedContainer)container; + if (parent.Controls.Count == 0) + return false; - // Nothing to layout, exit method - if (parent.Controls.Count == 0) return false; + FlowLayoutSettings settings = GetLayoutSettings (parent); // Use DisplayRectangle so that parent.Padding is honored. Rectangle parentDisplayRectangle = parent.DisplayRectangle; @@ -85,16 +89,19 @@ namespace System.Windows.Forms.Layout bool forceFlowBreak = false; - List rowControls = new List (); + List rowControls = new List (); - foreach (Control c in parent.Controls) { + foreach (IArrangedElement c in parent.Controls) { // Only apply layout to visible controls. if (!c.Visible) { continue; } // Resize any AutoSize controls to their preferred size if (c.AutoSize == true) { - Size new_size = c.GetPreferredSize (c.Size); - c.SetBoundsInternal (c.Left, c.Top, new_size.Width, new_size.Height, BoundsSpecified.None); + Size proposed_constraints = new Size(int.MaxValue, Math.Max(1, parentDisplayRectangle.Height - c.Margin.Vertical)); + if (currentLocation.X == parentDisplayRectangle.Left) + proposed_constraints.Width = Math.Max(1, parentDisplayRectangle.Width - c.Margin.Horizontal); + Size new_size = c.GetPreferredSize (proposed_constraints); + c.SetBounds (c.Bounds.Left, c.Bounds.Top, new_size.Width, new_size.Height, BoundsSpecified.None); } switch (settings.FlowDirection) { @@ -102,7 +109,7 @@ namespace System.Windows.Forms.Layout // Decide if it's time to start a new column // - Our settings must be WrapContents, and we ran out of room or the previous control's FlowBreak == true if (settings.WrapContents) - if ((currentLocation.Y) < (c.Height + c.Margin.Top + c.Margin.Bottom) || forceFlowBreak) { + if ((currentLocation.Y) < (c.Bounds.Height + c.Margin.Top + c.Margin.Bottom) || forceFlowBreak) { currentLocation.X = FinishColumn (rowControls); currentLocation.Y = parentDisplayRectangle.Bottom; @@ -113,17 +120,17 @@ namespace System.Windows.Forms.Layout // Offset the right margin and set the control to our point currentLocation.Offset (0, c.Margin.Bottom * -1); - c.SetBoundsInternal (currentLocation.X + c.Margin.Left, currentLocation.Y - c.Height, c.Width, c.Height, BoundsSpecified.None); + c.SetBounds (currentLocation.X + c.Margin.Left, currentLocation.Y - c.Bounds.Height, c.Bounds.Width, c.Bounds.Height, BoundsSpecified.None); // Update our location pointer - currentLocation.Y -= (c.Height + c.Margin.Top); + currentLocation.Y -= (c.Bounds.Height + c.Margin.Top); break; case FlowDirection.LeftToRight: default: // Decide if it's time to start a new row // - Our settings must be WrapContents, and we ran out of room or the previous control's FlowBreak == true if (settings.WrapContents && !(parent is ToolStripPanel)) - if ((parentDisplayRectangle.Width + parentDisplayRectangle.Left - currentLocation.X) < (c.Width + c.Margin.Left + c.Margin.Right) || forceFlowBreak) { + if ((parentDisplayRectangle.Width + parentDisplayRectangle.Left - currentLocation.X) < (c.Bounds.Width + c.Margin.Left + c.Margin.Right) || forceFlowBreak) { currentLocation.Y = FinishRow (rowControls); currentLocation.X = parentDisplayRectangle.Left; @@ -134,16 +141,16 @@ namespace System.Windows.Forms.Layout // Offset the left margin and set the control to our point currentLocation.Offset (c.Margin.Left, 0); - c.SetBoundsInternal (currentLocation.X, currentLocation.Y + c.Margin.Top, c.Width, c.Height, BoundsSpecified.None); + c.SetBounds (currentLocation.X, currentLocation.Y + c.Margin.Top, c.Bounds.Width, c.Bounds.Height, BoundsSpecified.None); // Update our location pointer - currentLocation.X += c.Width + c.Margin.Right; + currentLocation.X += c.Bounds.Width + c.Margin.Right; break; case FlowDirection.RightToLeft: // Decide if it's time to start a new row // - Our settings must be WrapContents, and we ran out of room or the previous control's FlowBreak == true if (settings.WrapContents) - if ((currentLocation.X) < (c.Width + c.Margin.Left + c.Margin.Right) || forceFlowBreak) { + if ((currentLocation.X) < (c.Bounds.Width + c.Margin.Left + c.Margin.Right) || forceFlowBreak) { currentLocation.Y = FinishRow (rowControls); currentLocation.X = parentDisplayRectangle.Right; @@ -154,16 +161,16 @@ namespace System.Windows.Forms.Layout // Offset the right margin and set the control to our point currentLocation.Offset (c.Margin.Right * -1, 0); - c.SetBoundsInternal (currentLocation.X - c.Width, currentLocation.Y + c.Margin.Top, c.Width, c.Height, BoundsSpecified.None); + c.SetBounds (currentLocation.X - c.Bounds.Width, currentLocation.Y + c.Margin.Top, c.Bounds.Width, c.Bounds.Height, BoundsSpecified.None); // Update our location pointer - currentLocation.X -= (c.Width + c.Margin.Left); + currentLocation.X -= (c.Bounds.Width + c.Margin.Left); break; case FlowDirection.TopDown: // Decide if it's time to start a new column // - Our settings must be WrapContents, and we ran out of room or the previous control's FlowBreak == true if (settings.WrapContents) - if ((parentDisplayRectangle.Height + parentDisplayRectangle.Top - currentLocation.Y) < (c.Height + c.Margin.Top + c.Margin.Bottom) || forceFlowBreak) { + if ((parentDisplayRectangle.Height + parentDisplayRectangle.Top - currentLocation.Y) < (c.Bounds.Height + c.Margin.Top + c.Margin.Bottom) || forceFlowBreak) { currentLocation.X = FinishColumn (rowControls); currentLocation.Y = parentDisplayRectangle.Top; @@ -174,10 +181,10 @@ namespace System.Windows.Forms.Layout // Offset the top margin and set the control to our point currentLocation.Offset (0, c.Margin.Top); - c.SetBoundsInternal (currentLocation.X + c.Margin.Left, currentLocation.Y, c.Width, c.Height, BoundsSpecified.None); + c.SetBounds (currentLocation.X + c.Margin.Left, currentLocation.Y, c.Bounds.Width, c.Bounds.Height, BoundsSpecified.None); // Update our location pointer - currentLocation.Y += c.Height + c.Margin.Bottom; + currentLocation.Y += c.Bounds.Height + c.Margin.Bottom; break; } // Add it to our list of things to adjust the second dimension of @@ -194,281 +201,77 @@ namespace System.Windows.Forms.Layout else FinishColumn (rowControls); - return false; + return parent.AutoSize; } - // Calculate the heights of the controls, returns the y coordinate of the greatest height it uses - private int FinishRow (List row) + internal override Size GetPreferredSize (object container, Size proposedSize) { - // Nothing to do - if (row.Count == 0) return 0; + IArrangedContainer parent = (IArrangedContainer)container; + FlowLayoutSettings settings = GetLayoutSettings (parent); + int width = 0; + int height = 0; + bool horizontal = settings.FlowDirection == FlowDirection.LeftToRight || settings.FlowDirection == FlowDirection.RightToLeft; + int size_in_flow_direction = 0; + int size_in_other_direction = 0; + int increase; + Size margin = new Size (0, 0); + bool force_flow_break = false; + bool wrap = settings.WrapContents; - int rowTop = int.MaxValue; - int rowBottom = 0; - bool allDockFill = true; - bool noAuto = true; - - // Special semantics if all controls are Dock.Fill/Anchor:Top,Bottom or AutoSize = true - foreach (Control c in row) { - if (c.Dock != DockStyle.Fill && !((c.Anchor & AnchorStyles.Top) == AnchorStyles.Top && (c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom)) - allDockFill = false; - if (c.AutoSize == true) - noAuto = false; - } - - // Find the tallest control with a concrete height - foreach (Control c in row) { - if (c.Bottom + c.Margin.Bottom > rowBottom && (c.Dock != DockStyle.Fill) && ((c.Anchor & AnchorStyles.Top) != AnchorStyles.Top || (c.Anchor & AnchorStyles.Bottom) != AnchorStyles.Bottom || c.AutoSize == true)) - rowBottom = c.Bottom + c.Margin.Bottom; - if (c.Top - c.Margin.Top < rowTop) - rowTop = c.Top - c.Margin.Top; - } - - // Find the tallest control that is AutoSize = true - if (rowBottom == 0) - foreach (Control c in row) - if (c.Bottom + c.Margin.Bottom > rowBottom && (c.Dock != DockStyle.Fill && c.AutoSize == true)) - rowBottom = c.Bottom + c.Margin.Bottom; - - // Find the tallest control that is Dock = Fill - if (rowBottom == 0) - foreach (Control c in row) - if (c.Bottom + c.Margin.Bottom > rowBottom && (c.Dock == DockStyle.Fill)) - rowBottom = c.Bottom + c.Margin.Bottom; - - // Set the new heights for each control - foreach (Control c in row) - if (allDockFill && noAuto) - c.SetBoundsInternal (c.Left, c.Top, c.Width, 0, BoundsSpecified.None); - else if (c.Dock == DockStyle.Fill || ((c.Anchor & AnchorStyles.Top) == AnchorStyles.Top) && ((c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom)) - c.SetBoundsInternal (c.Left, c.Top, c.Width, rowBottom - c.Top - c.Margin.Bottom, BoundsSpecified.None); - else if (c.Dock == DockStyle.Bottom || ((c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom)) - c.SetBoundsInternal (c.Left, rowBottom - c.Margin.Bottom - c.Height, c.Width, c.Height, BoundsSpecified.None); - else if (c.Dock == DockStyle.Top || ((c.Anchor & AnchorStyles.Top) == AnchorStyles.Top)) + foreach (IArrangedElement control in parent.Controls) { + if (!control.Visible) continue; - else - c.SetBoundsInternal (c.Left, ((rowBottom - rowTop) / 2) - (c.Height / 2) + (int)Math.Floor (((c.Margin.Top - c.Margin.Bottom) / 2.0)) + rowTop, c.Width, c.Height, BoundsSpecified.None); - - // Return bottom y of this row used - if (rowBottom == 0) - return rowTop; - - return rowBottom; - } - - // Calculate the widths of the controls, returns the x coordinate of the greatest width it uses - private int FinishColumn (List col) - { - // Nothing to do - if (col.Count == 0) return 0; - - int rowLeft = int.MaxValue; - int rowRight = 0; - bool allDockFill = true; - bool noAuto = true; - - // Special semantics if all controls are Dock.Fill/Anchor:Left,Right or AutoSize = true - foreach (Control c in col) { - if (c.Dock != DockStyle.Fill && !((c.Anchor & AnchorStyles.Left) == AnchorStyles.Left && (c.Anchor & AnchorStyles.Right) == AnchorStyles.Right)) - allDockFill = false; - if (c.AutoSize == true) - noAuto = false; - } - - // Find the widest control with a concrete width - foreach (Control c in col) { - if (c.Right + c.Margin.Right > rowRight && (c.Dock != DockStyle.Fill) && ((c.Anchor & AnchorStyles.Left) != AnchorStyles.Left || (c.Anchor & AnchorStyles.Right) != AnchorStyles.Right || c.AutoSize == true)) - rowRight = c.Right + c.Margin.Right; - if (c.Left - c.Margin.Left < rowLeft) - rowLeft = c.Left - c.Margin.Left; - } - - // Find the widest control that is AutoSize = true - if (rowRight == 0) - foreach (Control c in col) - if (c.Right + c.Margin.Right > rowRight && (c.Dock != DockStyle.Fill && c.AutoSize == true)) - rowRight = c.Right + c.Margin.Right; - - // Find the widest control that is Dock = Fill - if (rowRight == 0) - foreach (Control c in col) - if (c.Right + c.Margin.Right > rowRight && (c.Dock == DockStyle.Fill)) - rowRight = c.Right + c.Margin.Right; - - // Set the new widths for each control - foreach (Control c in col) - if (allDockFill && noAuto) - c.SetBoundsInternal (c.Left, c.Top, 0, c.Height, BoundsSpecified.None); - else if (c.Dock == DockStyle.Fill || ((c.Anchor & AnchorStyles.Left) == AnchorStyles.Left) && ((c.Anchor & AnchorStyles.Right) == AnchorStyles.Right)) - c.SetBoundsInternal (c.Left, c.Top, rowRight - c.Left - c.Margin.Right, c.Height, BoundsSpecified.None); - else if (c.Dock == DockStyle.Right || ((c.Anchor & AnchorStyles.Right) == AnchorStyles.Right)) - c.SetBoundsInternal (rowRight - c.Margin.Right - c.Width, c.Top, c.Width, c.Height, BoundsSpecified.None); - else if (c.Dock == DockStyle.Left || ((c.Anchor & AnchorStyles.Left) == AnchorStyles.Left)) - continue; - else - c.SetBoundsInternal (((rowRight - rowLeft) / 2) - (c.Width / 2) + (int)Math.Floor (((c.Margin.Left - c.Margin.Right) / 2.0)) + rowLeft, c.Top, c.Width, c.Height, BoundsSpecified.None); - - // Return rightmost x of this row used - if (rowRight == 0) - return rowLeft; - - return rowRight; - } - - #region Layout for ToolStrip - // ToolStrips use the same FlowLayout, but is made up of ToolStripItems which - // are Components instead of Controls, so we have to duplicate this login for - // ToolStripItems. - private bool LayoutToolStrip (ToolStrip parent) - { - FlowLayoutSettings settings; - settings = (FlowLayoutSettings)parent.LayoutSettings; - - // Nothing to layout, exit method - if (parent.Items.Count == 0) return false; - - foreach (ToolStripItem tsi in parent.Items) - tsi.SetPlacement (ToolStripItemPlacement.Main); - - // Use DisplayRectangle so that parent.Padding is honored. - Rectangle parentDisplayRectangle = parent.DisplayRectangle; - Point currentLocation; - - // Set our starting point based on flow direction - switch (settings.FlowDirection) { - case FlowDirection.BottomUp: - currentLocation = new Point (parentDisplayRectangle.Left, parentDisplayRectangle.Bottom); - break; - case FlowDirection.LeftToRight: - case FlowDirection.TopDown: - default: - currentLocation = parentDisplayRectangle.Location; - break; - case FlowDirection.RightToLeft: - currentLocation = new Point (parentDisplayRectangle.Right, parentDisplayRectangle.Top); - break; - } - - bool forceFlowBreak = false; - - List rowControls = new List (); - - foreach (ToolStripItem c in parent.Items) { - // Only apply layout to visible controls. - if (!c.Available) { continue; } - - // Resize any AutoSize controls to their preferred size - if (c.AutoSize == true) - c.SetBounds (new Rectangle (c.Location, c.GetPreferredSize (c.Size))); - - switch (settings.FlowDirection) { - case FlowDirection.BottomUp: - // Decide if it's time to start a new column - // - Our settings must be WrapContents, and we ran out of room or the previous control's FlowBreak == true - if (settings.WrapContents) - if ((currentLocation.Y) < (c.Height + c.Margin.Top + c.Margin.Bottom) || forceFlowBreak) { - - currentLocation.X = FinishColumn (rowControls); - currentLocation.Y = parentDisplayRectangle.Bottom; - - forceFlowBreak = false; - rowControls.Clear (); - } - - // Offset the right margin and set the control to our point - currentLocation.Offset (0, c.Margin.Bottom * -1); - c.Location = new Point (currentLocation.X + c.Margin.Left, currentLocation.Y - c.Height); - - // Update our location pointer - currentLocation.Y -= (c.Height + c.Margin.Top); - break; - case FlowDirection.LeftToRight: - default: - // Decide if it's time to start a new row - // - Our settings must be WrapContents, and we ran out of room or the previous control's FlowBreak == true - if (settings.WrapContents) - if ((parentDisplayRectangle.Width - currentLocation.X) < (c.Width + c.Margin.Left + c.Margin.Right) || forceFlowBreak) { - - currentLocation.Y = FinishRow (rowControls); - currentLocation.X = parentDisplayRectangle.Left; - - forceFlowBreak = false; - rowControls.Clear (); - } - - // Offset the left margin and set the control to our point - currentLocation.Offset (c.Margin.Left, 0); - c.Location = new Point (currentLocation.X, currentLocation.Y + c.Margin.Top); - - // Update our location pointer - currentLocation.X += c.Width + c.Margin.Right; - break; - case FlowDirection.RightToLeft: - // Decide if it's time to start a new row - // - Our settings must be WrapContents, and we ran out of room or the previous control's FlowBreak == true - if (settings.WrapContents) - if ((currentLocation.X) < (c.Width + c.Margin.Left + c.Margin.Right) || forceFlowBreak) { - - currentLocation.Y = FinishRow (rowControls); - currentLocation.X = parentDisplayRectangle.Right; - - forceFlowBreak = false; - rowControls.Clear (); - } - - // Offset the right margin and set the control to our point - currentLocation.Offset (c.Margin.Right * -1, 0); - c.Location = new Point (currentLocation.X - c.Width, currentLocation.Y + c.Margin.Top); - - // Update our location pointer - currentLocation.X -= (c.Width + c.Margin.Left); - break; - case FlowDirection.TopDown: - // Decide if it's time to start a new column - // - Our settings must be WrapContents, and we ran out of room or the previous control's FlowBreak == true - if (settings.WrapContents) - if ((parentDisplayRectangle.Height - currentLocation.Y) < (c.Height + c.Margin.Top + c.Margin.Bottom) || forceFlowBreak) { - - currentLocation.X = FinishColumn (rowControls); - currentLocation.Y = parentDisplayRectangle.Top; - - forceFlowBreak = false; - rowControls.Clear (); - } - - // Offset the top margin and set the control to our point - currentLocation.Offset (0, c.Margin.Top); - c.Location = new Point (currentLocation.X + c.Margin.Left, currentLocation.Y); - - // Update our location pointer - currentLocation.Y += c.Height + c.Margin.Bottom; - break; + Size control_preferred_size; + if (control.AutoSize) { + Size proposed_constraints = new Size(int.MaxValue, Math.Max(1, proposedSize.Height - control.Margin.Vertical)); + if (size_in_flow_direction == 0) + proposed_constraints.Width = Math.Max(1, proposedSize.Width - control.Margin.Horizontal); + control_preferred_size = control.GetPreferredSize(proposed_constraints); + } else { + control_preferred_size = control.ExplicitBounds.Size; + if ((control.Anchor & (AnchorStyles.Top | AnchorStyles.Bottom)) == (AnchorStyles.Top | AnchorStyles.Bottom)) + control_preferred_size.Height = control.MinimumSize.Height; + } + Padding control_margin = control.Margin; + if (horizontal) { + increase = control_preferred_size.Width + control_margin.Horizontal; + if (wrap && ((proposedSize.Width > 0 && size_in_flow_direction != 0 && size_in_flow_direction + increase >= proposedSize.Width) || force_flow_break)) { + width = Math.Max (width, size_in_flow_direction); + size_in_flow_direction = 0; + height += size_in_other_direction; + size_in_other_direction = 0; + } + size_in_flow_direction += increase; + size_in_other_direction = Math.Max (size_in_other_direction, control_preferred_size.Height + control_margin.Vertical); + } else { + increase = control_preferred_size.Height + control_margin.Vertical; + if (wrap && ((proposedSize.Height > 0 && size_in_flow_direction != 0 && size_in_flow_direction + increase >= proposedSize.Height) || force_flow_break)) { + height = Math.Max (height, size_in_flow_direction); + size_in_flow_direction = 0; + width += size_in_other_direction; + size_in_other_direction = 0; + } + size_in_flow_direction += increase; + size_in_other_direction = Math.Max (size_in_other_direction, control_preferred_size.Width + control_margin.Horizontal); } - // Add it to our list of things to adjust the second dimension of - rowControls.Add (c); - // If user set a flowbreak on this control, it will be the last one in this row/column - if (settings.GetFlowBreak (c)) - forceFlowBreak = true; + if (parent != null) + force_flow_break = settings.GetFlowBreak(control); } - int final_height = 0; - - // Set the control heights/widths for the last row/column - if (settings.FlowDirection == FlowDirection.LeftToRight || settings.FlowDirection == FlowDirection.RightToLeft) - final_height = FinishRow (rowControls); - else - FinishColumn (rowControls); - - if (final_height > 0) - parent.SetBoundsInternal (parent.Left, parent.Top, parent.Width, final_height + parent.Padding.Bottom, BoundsSpecified.None); - - return false; + if (horizontal) { + width = Math.Max (width, size_in_flow_direction); + height += size_in_other_direction; + } else { + height = Math.Max (height, size_in_flow_direction); + width += size_in_other_direction; + } + return new Size (width, height); } - + // Calculate the heights of the controls, returns the y coordinate of the greatest height it uses - private int FinishRow (List row) + private int FinishRow (List row) { // Nothing to do if (row.Count == 0) return 0; @@ -479,7 +282,7 @@ namespace System.Windows.Forms.Layout bool noAuto = true; // Special semantics if all controls are Dock.Fill/Anchor:Top,Bottom or AutoSize = true - foreach (ToolStripItem c in row) { + foreach (IArrangedElement c in row) { if (c.Dock != DockStyle.Fill && !((c.Anchor & AnchorStyles.Top) == AnchorStyles.Top && (c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom)) allDockFill = false; if (c.AutoSize == true) @@ -487,37 +290,36 @@ namespace System.Windows.Forms.Layout } // Find the tallest control with a concrete height - foreach (ToolStripItem c in row) { - if (c.Bottom + c.Margin.Bottom > rowBottom && (c.Dock != DockStyle.Fill) && ((c.Anchor & AnchorStyles.Top) != AnchorStyles.Top || (c.Anchor & AnchorStyles.Bottom) != AnchorStyles.Bottom || c.AutoSize == true)) - rowBottom = c.Bottom + c.Margin.Bottom; - if (c.Top - c.Margin.Top < rowTop) - rowTop = c.Top - c.Margin.Top; + foreach (IArrangedElement c in row) { + if (c.Dock != DockStyle.Fill && ((c.Anchor & AnchorStyles.Top) != AnchorStyles.Top || (c.Anchor & AnchorStyles.Bottom) != AnchorStyles.Bottom || c.AutoSize == true)) + rowBottom = Math.Max (rowBottom, c.Bounds.Bottom + c.Margin.Bottom); + rowTop = Math.Min (rowTop, c.Bounds.Top - c.Margin.Top); } // Find the tallest control that is AutoSize = true if (rowBottom == 0) - foreach (ToolStripItem c in row) - if (c.Bottom + c.Margin.Bottom > rowBottom && (c.Dock != DockStyle.Fill && c.AutoSize == true)) - rowBottom = c.Bottom + c.Margin.Bottom; + foreach (IArrangedElement c in row) + if (c.Dock != DockStyle.Fill && c.AutoSize == true) + rowBottom = Math.Max (rowBottom, c.Bounds.Bottom + c.Margin.Bottom); // Find the tallest control that is Dock = Fill if (rowBottom == 0) - foreach (ToolStripItem c in row) - if (c.Bottom + c.Margin.Bottom > rowBottom && (c.Dock == DockStyle.Fill)) - rowBottom = c.Bottom + c.Margin.Bottom; + foreach (IArrangedElement c in row) + if (c.Dock == DockStyle.Fill) + rowBottom = Math.Max (rowBottom, c.Bounds.Bottom + c.Margin.Bottom); // Set the new heights for each control - foreach (ToolStripItem c in row) + foreach (IArrangedElement c in row) if (allDockFill && noAuto) - c.Height = 0; + c.SetBounds (c.Bounds.Left, c.Bounds.Top, c.Bounds.Width, 0, BoundsSpecified.None); else if (c.Dock == DockStyle.Fill || ((c.Anchor & AnchorStyles.Top) == AnchorStyles.Top) && ((c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom)) - c.Height = rowBottom - c.Top - c.Margin.Bottom; + c.SetBounds (c.Bounds.Left, c.Bounds.Top, c.Bounds.Width, rowBottom - c.Bounds.Top - c.Margin.Bottom, BoundsSpecified.None); else if (c.Dock == DockStyle.Bottom || ((c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom)) - c.Top = rowBottom - c.Margin.Bottom - c.Height; + c.SetBounds (c.Bounds.Left, rowBottom - c.Margin.Bottom - c.Bounds.Height, c.Bounds.Width, c.Bounds.Height, BoundsSpecified.None); else if (c.Dock == DockStyle.Top || ((c.Anchor & AnchorStyles.Top) == AnchorStyles.Top)) continue; else - c.Top = ((rowBottom - rowTop) / 2) - (c.Height / 2) + (int)Math.Floor (((c.Margin.Top - c.Margin.Bottom) / 2.0)) + rowTop; + c.SetBounds (c.Bounds.Left, ((rowBottom - rowTop) / 2) - (c.Bounds.Height / 2) + (int)Math.Floor (((c.Margin.Top - c.Margin.Bottom) / 2.0)) + rowTop, c.Bounds.Width, c.Bounds.Height, BoundsSpecified.None); // Return bottom y of this row used if (rowBottom == 0) @@ -527,7 +329,7 @@ namespace System.Windows.Forms.Layout } // Calculate the widths of the controls, returns the x coordinate of the greatest width it uses - private int FinishColumn (List col) + private int FinishColumn (List col) { // Nothing to do if (col.Count == 0) return 0; @@ -538,7 +340,7 @@ namespace System.Windows.Forms.Layout bool noAuto = true; // Special semantics if all controls are Dock.Fill/Anchor:Left,Right or AutoSize = true - foreach (ToolStripItem c in col) { + foreach (IArrangedElement c in col) { if (c.Dock != DockStyle.Fill && !((c.Anchor & AnchorStyles.Left) == AnchorStyles.Left && (c.Anchor & AnchorStyles.Right) == AnchorStyles.Right)) allDockFill = false; if (c.AutoSize == true) @@ -546,37 +348,36 @@ namespace System.Windows.Forms.Layout } // Find the widest control with a concrete width - foreach (ToolStripItem c in col) { - if (c.Right + c.Margin.Right > rowRight && (c.Dock != DockStyle.Fill) && ((c.Anchor & AnchorStyles.Left) != AnchorStyles.Left || (c.Anchor & AnchorStyles.Right) != AnchorStyles.Right || c.AutoSize == true)) - rowRight = c.Right + c.Margin.Right; - if (c.Left - c.Margin.Left < rowLeft) - rowLeft = c.Left - c.Margin.Left; + foreach (IArrangedElement c in col) { + if (c.Dock != DockStyle.Fill && ((c.Anchor & AnchorStyles.Left) != AnchorStyles.Left || (c.Anchor & AnchorStyles.Right) != AnchorStyles.Right || c.AutoSize == true)) + rowRight = Math.Max (rowRight, c.Bounds.Right + c.Margin.Right); + rowLeft = Math.Min (rowLeft, c.Bounds.Left - c.Margin.Left); } // Find the widest control that is AutoSize = true if (rowRight == 0) - foreach (ToolStripItem c in col) - if (c.Right + c.Margin.Right > rowRight && (c.Dock != DockStyle.Fill && c.AutoSize == true)) - rowRight = c.Right + c.Margin.Right; + foreach (IArrangedElement c in col) + if (c.Dock != DockStyle.Fill && c.AutoSize == true) + rowRight = Math.Max (rowRight, c.Bounds.Right + c.Margin.Right); // Find the widest control that is Dock = Fill if (rowRight == 0) - foreach (ToolStripItem c in col) - if (c.Right + c.Margin.Right > rowRight && (c.Dock == DockStyle.Fill)) - rowRight = c.Right + c.Margin.Right; + foreach (IArrangedElement c in col) + if (c.Dock == DockStyle.Fill) + rowRight = Math.Max (rowRight, c.Bounds.Right + c.Margin.Right); // Set the new widths for each control - foreach (ToolStripItem c in col) + foreach (IArrangedElement c in col) if (allDockFill && noAuto) - c.Width = 0; + c.SetBounds (c.Bounds.Left, c.Bounds.Top, 0, c.Bounds.Height, BoundsSpecified.None); else if (c.Dock == DockStyle.Fill || ((c.Anchor & AnchorStyles.Left) == AnchorStyles.Left) && ((c.Anchor & AnchorStyles.Right) == AnchorStyles.Right)) - c.Width = rowRight - c.Left - c.Margin.Right; + c.SetBounds (c.Bounds.Left, c.Bounds.Top, rowRight - c.Bounds.Left - c.Margin.Right, c.Bounds.Height, BoundsSpecified.None); else if (c.Dock == DockStyle.Right || ((c.Anchor & AnchorStyles.Right) == AnchorStyles.Right)) - c.Left = rowRight - c.Margin.Right - c.Width; + c.SetBounds (rowRight - c.Margin.Right - c.Bounds.Width, c.Bounds.Top, c.Bounds.Width, c.Bounds.Height, BoundsSpecified.None); else if (c.Dock == DockStyle.Left || ((c.Anchor & AnchorStyles.Left) == AnchorStyles.Left)) continue; else - c.Left = ((rowRight - rowLeft) / 2) - (c.Width / 2) + (int)Math.Floor (((c.Margin.Left - c.Margin.Right) / 2.0)) + rowLeft; + c.SetBounds (((rowRight - rowLeft) / 2) - (c.Bounds.Width / 2) + (int)Math.Floor (((c.Margin.Left - c.Margin.Right) / 2.0)) + rowLeft, c.Bounds.Top, c.Bounds.Width, c.Bounds.Height, BoundsSpecified.None); // Return rightmost x of this row used if (rowRight == 0) @@ -584,6 +385,5 @@ namespace System.Windows.Forms.Layout return rowRight; } - #endregion } } diff --git a/mcs/class/System/System.Net/FtpRequestCreator.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms.Layout/IArrangedContainer.cs similarity index 77% rename from mcs/class/System/System.Net/FtpRequestCreator.cs rename to mcs/class/System.Windows.Forms/System.Windows.Forms.Layout/IArrangedContainer.cs index e72266fbea..c3823c9bbf 100644 --- a/mcs/class/System/System.Net/FtpRequestCreator.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms.Layout/IArrangedContainer.cs @@ -1,12 +1,5 @@ // -// System.Net.FtpbRequestCreator.cs -// -// Authors: -// Carlos Alberto Cortez (calberto.cortez@gmail.com) -// -// (c) Copyright 2006 Novell, Inc. (http://www.novell.com) -// - +// IArrangedElement.cs // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -27,17 +20,17 @@ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // +// Copyright (c) 2018 Filip Navara +// +using System.Collections; +using System.Drawing; -namespace System.Net +namespace System.Windows.Forms.Layout { - class FtpRequestCreator : IWebRequestCreate + interface IArrangedContainer : IArrangedElement { - public WebRequest Create (Uri uri) - { - return new FtpWebRequest (uri); - } + ArrangedElementCollection Controls { get; } + void PerformLayout (IArrangedElement affectedElement, string affectedProperty); } } - - diff --git a/mcs/class/System/System.Net/FtpStatus.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms.Layout/IArrangedElement.cs similarity index 58% rename from mcs/class/System/System.Net/FtpStatus.cs rename to mcs/class/System.Windows.Forms/System.Windows.Forms.Layout/IArrangedElement.cs index 9b6afa543b..88f778d866 100644 --- a/mcs/class/System/System.Net/FtpStatus.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms.Layout/IArrangedElement.cs @@ -1,51 +1,52 @@ -// System.Net.FtpStatus.cs -// -// Authors: -// David Elkind (davide@mainsoft.com) -// -// Copyright (C) 2006 Mainsoft Corp. -// http://www.mainsoft.com -// - -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -namespace System.Net -{ - internal class FtpStatus - { - readonly FtpStatusCode statusCode; - readonly string statusDescription; - - public FtpStatus (FtpStatusCode statusCode, string statusDescription) { - this.statusCode = statusCode; - this.statusDescription = statusDescription; - } - - public FtpStatusCode StatusCode { - get { return statusCode; } - } - - public string StatusDescription { - get { return statusDescription; } - } - } -} +// +// IArrangedElement.cs +// +// 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. +// +// Copyright (c) 2018 Filip Navara +// + +using System.Collections; +using System.Drawing; +using System.ComponentModel; + +namespace System.Windows.Forms.Layout +{ + interface IArrangedElement : IComponent + { + bool Visible { get; } + bool AutoSize { get; } + AutoSizeMode GetAutoSizeMode(); + Rectangle Bounds { get; } + Rectangle ExplicitBounds { get; } + Padding Padding { get; } + Padding Margin { get; } + Size MinimumSize { get; } + AnchorStyles Anchor { get; } + DockStyle Dock { get; } + Rectangle DisplayRectangle { get; } + IArrangedContainer Parent { get; } + string Name { get; } + void SetBounds(int x, int y, int width, int height, BoundsSpecified specified); + Size GetPreferredSize(Size proposedSize); + int DistanceRight { get; set; } + int DistanceBottom { get; set; } + } +} diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms.Layout/LayoutEngine.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms.Layout/LayoutEngine.cs index b6199764b2..a939d894c8 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms.Layout/LayoutEngine.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms.Layout/LayoutEngine.cs @@ -26,6 +26,7 @@ using System; using System.ComponentModel; +using System.Drawing; namespace System.Windows.Forms.Layout { @@ -39,5 +40,10 @@ namespace System.Windows.Forms.Layout { { return false; } + + internal virtual Size GetPreferredSize (object container, Size proposedSize) + { + return Size.Empty; + } } } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms.Layout/TableLayout.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms.Layout/TableLayout.cs index 7d306658c6..f746c55620 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms.Layout/TableLayout.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms.Layout/TableLayout.cs @@ -31,14 +31,20 @@ using System; using System.Drawing; +using System.Collections.Generic; +using System.Diagnostics; namespace System.Windows.Forms.Layout { internal class TableLayout : LayoutEngine { - private static Control dummy_control = new Control ("Dummy"); // Used as a placeholder for row/col spans + internal static readonly TableLayout Instance = new TableLayout(); - public TableLayout () : base () + private static Control dummy_control = new Control ("Dummy"); // Used as a placeholder for row/col spans + private static ColumnStyle default_column_style = new ColumnStyle(); + private static RowStyle default_row_style = new RowStyle(); + + private TableLayout () : base () { } @@ -53,8 +59,8 @@ namespace System.Windows.Forms.Layout // 3) Size and position each control public override bool Layout (object container, LayoutEventArgs args) { - TableLayoutPanel panel = container as TableLayoutPanel; - TableLayoutSettings settings = panel.LayoutSettings; + IArrangedContainer panel = (IArrangedContainer)container; + TableLayoutSettings settings = GetLayoutSettings (panel); #if TABLE_DEBUG Console.WriteLine ("Beginning layout on panel: {0}, control count: {1}, col/row count: {2}x{3}", panel.Name, panel.Controls.Count, settings.ColumnCount, settings.RowCount); @@ -63,43 +69,58 @@ namespace System.Windows.Forms.Layout // STEP 1: // - Figure out which row/column each control goes into // - Store data in the TableLayoutPanel.actual_positions - panel.actual_positions = CalculateControlPositions (panel, Math.Max (settings.ColumnCount, 1), Math.Max (settings.RowCount, 1)); + var actual_positions = CalculateControlPositions (panel, Math.Max (settings.ColumnCount, 1), Math.Max (settings.RowCount, 1)); // STEP 2: // - Figure out the sizes of each row/column // - Store data in the TableLayoutPanel.widths/heights - CalculateColumnRowSizes (panel, panel.actual_positions.GetLength (0), panel.actual_positions.GetLength (1)); + int[] widths, heights; + CalculateColumnRowSizes (panel, actual_positions, out widths, out heights, panel.DisplayRectangle.Size, false); + + if (panel is TableLayoutPanel table_panel) { + table_panel.actual_positions = actual_positions; + table_panel.column_widths = widths; + table_panel.row_heights = heights; + } // STEP 3: // - Size and position each control - LayoutControls(panel); + LayoutControls (panel, actual_positions, widths, heights); #if TABLE_DEBUG Console.WriteLine ("-- CalculatedPositions:"); - OutputControlGrid (panel.actual_positions, panel); + OutputControlGrid (actual_positions, widths, heights); Console.WriteLine ("Finished layout on panel: {0}", panel.Name); Console.WriteLine (); #endif - return false; + return ((IArrangedElement)panel).AutoSize; } - internal Control[,] CalculateControlPositions (TableLayoutPanel panel, int columns, int rows) + private static TableLayoutSettings GetLayoutSettings (IArrangedContainer container) { - Control[,] grid = new Control[columns, rows]; + if (container is TableLayoutPanel panel) + return panel.LayoutSettings; + else if (container is ToolStrip tool_strip) + return (TableLayoutSettings)tool_strip.LayoutSettings; + throw new NotSupportedException (); + } - TableLayoutSettings settings = panel.LayoutSettings; + private IArrangedElement[,] CalculateControlPositions (IArrangedContainer container, int columns, int rows) + { + IArrangedElement[,] grid = new IArrangedElement[columns, rows]; + TableLayoutSettings settings = GetLayoutSettings (container); // First place all controls that have an explicit col/row - foreach (Control c in panel.Controls) { + foreach (IArrangedElement c in container.Controls) { int col = settings.GetColumn (c); int row = settings.GetRow (c); if (col >= 0 && row >= 0) { if (col >= columns) - return CalculateControlPositions (panel, col + 1, rows); + return CalculateControlPositions (container, col + 1, rows); if (row >= rows) - return CalculateControlPositions (panel, columns, row + 1); + return CalculateControlPositions (container, columns, row + 1); if (grid[col, row] == null) { int col_span = Math.Min (settings.GetColumnSpan (c), columns); @@ -112,14 +133,14 @@ namespace System.Windows.Forms.Layout col = 0; } else if (settings.GrowStyle == TableLayoutPanelGrowStyle.AddColumns) - return CalculateControlPositions (panel, columns + 1, rows); + return CalculateControlPositions (container, columns + 1, rows); else throw new ArgumentException (); } if (row + row_span > rows) { if (settings.GrowStyle == TableLayoutPanelGrowStyle.AddRows) - return CalculateControlPositions (panel, columns, rows + 1); + return CalculateControlPositions (container, columns, rows + 1); else throw new ArgumentException (); } @@ -140,7 +161,7 @@ namespace System.Windows.Forms.Layout int y_pointer = 0; // Fill in gaps with controls that do not have an explicit col/row - foreach (Control c in panel.Controls) { + foreach (IArrangedElement c in container.Controls) { int col = settings.GetColumn (c); int row = settings.GetRow (c); @@ -162,7 +183,7 @@ namespace System.Windows.Forms.Layout if (y + 1 < rows) break; else if (settings.GrowStyle == TableLayoutPanelGrowStyle.AddColumns) - return CalculateControlPositions (panel, columns + 1, rows); + return CalculateControlPositions (container, columns + 1, rows); else throw new ArgumentException (); } @@ -171,7 +192,7 @@ namespace System.Windows.Forms.Layout if (x + 1 < columns) break; else if (settings.GrowStyle == TableLayoutPanelGrowStyle.AddRows) - return CalculateControlPositions (panel, columns, rows + 1); + return CalculateControlPositions (container, columns, rows + 1); else throw new ArgumentException (); } @@ -210,10 +231,10 @@ namespace System.Windows.Forms.Layout switch (adjustedGrowStyle) { case TableLayoutPanelGrowStyle.AddColumns: - return CalculateControlPositions (panel, columns + 1, rows); + return CalculateControlPositions (container, columns + 1, rows); case TableLayoutPanelGrowStyle.AddRows: default: - return CalculateControlPositions (panel, columns, rows + 1); + return CalculateControlPositions (container, columns, rows + 1); case TableLayoutPanelGrowStyle.FixedSize: throw new ArgumentException (); } @@ -224,64 +245,23 @@ namespace System.Windows.Forms.Layout return grid; } - private void CalculateColumnRowSizes (TableLayoutPanel panel, int columns, int rows) + private static void CalculateColumnWidths (TableLayoutSettings settings, IArrangedElement[,] actual_positions, int max_colspan, TableLayoutColumnStyleCollection col_styles, bool auto_size, int[] column_widths, bool minimum_sizes) { - TableLayoutSettings settings = panel.LayoutSettings; + Size proposed_size = minimum_sizes ? new Size(1, 0) : Size.Empty; + int rows = actual_positions.GetLength(1); + float max_percent_size = 0; - panel.column_widths = new int[panel.actual_positions.GetLength (0)]; - panel.row_heights = new int[panel.actual_positions.GetLength (1)]; - - int border_width = TableLayoutPanel.GetCellBorderWidth (panel.CellBorderStyle); - - Rectangle parentDisplayRectangle = panel.DisplayRectangle; - - TableLayoutColumnStyleCollection col_styles = new TableLayoutColumnStyleCollection (panel); - - foreach (ColumnStyle cs in settings.ColumnStyles) - col_styles.Add( new ColumnStyle(cs.SizeType, cs.Width)); - - TableLayoutRowStyleCollection row_styles = new TableLayoutRowStyleCollection (panel); - - foreach (RowStyle rs in settings.RowStyles) - row_styles.Add (new RowStyle (rs.SizeType, rs.Height)); - - // If we have more columns than columnstyles, temporarily add enough columnstyles - if (columns > col_styles.Count) - { - for (int i = col_styles.Count; i < columns; i++) - col_styles.Add(new ColumnStyle()); - } - - // Same for rows.. - if (rows > row_styles.Count) - { - for (int i = row_styles.Count; i < rows; i++) - row_styles.Add (new RowStyle ()); - } - - while (row_styles.Count > rows) - row_styles.RemoveAt (row_styles.Count - 1); - while (col_styles.Count > columns) - col_styles.RemoveAt (col_styles.Count - 1); - - // Find the largest column-span/row-span values. - int max_colspan = 0, max_rowspan = 0; - foreach (Control c in panel.Controls) { - max_colspan = Math.Max (max_colspan, settings.GetColumnSpan (c)); - max_rowspan = Math.Max (max_rowspan, settings.GetRowSpan (c)); - } - - // Figure up all the column widths - int total_width = parentDisplayRectangle.Width - (border_width * (columns + 1)); + // First assign all the Absolute sized columns int index = 0; - - // First assign all the Absolute sized columns.. foreach (ColumnStyle cs in col_styles) { - if (cs.SizeType == SizeType.Absolute) { - panel.column_widths[index] = (int)cs.Width; - total_width -= (int)cs.Width; - } - + if (index >= column_widths.Length) + break; + if (cs.SizeType == SizeType.Absolute) + column_widths[index] = (int)cs.Width; + index++; + } + while (index < column_widths.Length) { + column_widths[index] = 0; index++; } @@ -289,218 +269,326 @@ namespace System.Windows.Forms.Layout // control. If the table-layout is auto-sized, then make sure that // no column with Percent styling clips its contents. // (per http://msdn.microsoft.com/en-us/library/ms171690.aspx) - for (int colspan = 0; colspan < max_colspan; ++colspan) - { - for (index = colspan; index < col_styles.Count - colspan; ++index) - { - ColumnStyle cs = col_styles[index]; - if (cs.SizeType == SizeType.AutoSize - || (panel.AutoSize && cs.SizeType == SizeType.Percent)) - { - int max_width = panel.column_widths[index]; - + for (int colspan = 0; colspan < max_colspan; ++colspan) { + for (index = colspan; index < column_widths.Length - colspan; ++index) { + ColumnStyle cs = index < col_styles.Count ? col_styles[index] : default_column_style; + if (cs.SizeType == SizeType.AutoSize || (auto_size && cs.SizeType == SizeType.Percent)) { + int max_width = column_widths[index]; // Find the widest control in the column - for (int i = 0; i < rows; i ++) - { - Control c = panel.actual_positions[index - colspan, i]; - - if (c != null && c != dummy_control && c.VisibleInternal) - { + for (int i = 0; i < rows; i ++) { + IArrangedElement c = actual_positions[index - colspan, i]; + if (c != null && c != dummy_control && c.Visible) { // Skip any controls not being sized in this pass. if (settings.GetColumnSpan (c) != colspan + 1) continue; - // Calculate the maximum control width. - if (c.AutoSize) - max_width = Math.Max (max_width, c.PreferredSize.Width + c.Margin.Horizontal); - else - max_width = Math.Max (max_width, c.ExplicitBounds.Width + c.Margin.Horizontal); - max_width = Math.Max (max_width, c.Width + c.Margin.Left + c.Margin.Right); + max_width = Math.Max(max_width, GetControlSize (c, proposed_size).Width + c.Margin.Horizontal); } } + if (cs.SizeType == SizeType.Percent) + max_percent_size = Math.Max(max_percent_size, max_width / cs.Width); + // Subtract the width of prior columns, if any. for (int i = Math.Max (index - colspan, 0); i < index; ++i) - max_width -= panel.column_widths[i]; + max_width -= column_widths[i]; // If necessary, increase this column's width. - if (max_width > panel.column_widths[index]) - { - max_width -= panel.column_widths[index]; - panel.column_widths[index] += max_width; - total_width -= max_width; - } + if (max_width > column_widths[index]) + column_widths[index] = max_width; } } } - - index = 0; - float total_percent = 0; - - // Finally, assign the remaining space to Percent columns, if any. - if (total_width > 0) - { - int percent_width = total_width; - - // Find the total percent (not always 100%) - foreach (ColumnStyle cs in col_styles) - { - if (cs.SizeType == SizeType.Percent) - total_percent += cs.Width; - } - // Divvy up the space.. - foreach (ColumnStyle cs in col_styles) - { - if (cs.SizeType == SizeType.Percent) - { - int width_change = (int)(((cs.Width / total_percent) * percent_width) - - panel.column_widths[index]); - if (width_change > 0) - { - panel.column_widths[index] += width_change; - total_width -= width_change; - } - } - - index++; - } + for (index = 0; index < col_styles.Count && index < column_widths.Length; ++index) { + ColumnStyle cs = col_styles[index]; + if (cs.SizeType == SizeType.Percent) + column_widths[index] = Math.Max(column_widths[index], (int)Math.Ceiling(max_percent_size * cs.Width)); } + } - if (total_width > 0) - { - // Find the last column that isn't an Absolute SizeType, and give it - // all this free space. (Absolute sized columns need to retain their - // absolute width if at all possible!) - int col = col_styles.Count - 1; - for (; col >= 0; --col) - { - if (col_styles[col].SizeType != SizeType.Absolute) - break; - } - if (col < 0) - col = col_styles.Count - 1; - panel.column_widths[col] += total_width; - } - - // Figure up all the row heights - int total_height = parentDisplayRectangle.Height - (border_width * (rows + 1)); - index = 0; + private static void CalculateRowHeights (TableLayoutSettings settings, IArrangedElement[,] actual_positions, int max_rowspan, TableLayoutRowStyleCollection row_styles, bool auto_size, int[] column_widths, int[] row_heights) + { + int columns = actual_positions.GetLength(0); + float max_percent_size = 0; // First assign all the Absolute sized rows.. + int index = 0; foreach (RowStyle rs in row_styles) { - if (rs.SizeType == SizeType.Absolute) { - panel.row_heights[index] = (int)rs.Height; - total_height -= (int)rs.Height; - } - + if (index >= row_heights.Length) + break; + if (rs.SizeType == SizeType.Absolute) + row_heights[index] = (int)rs.Height; + index++; + } + while (index < row_heights.Length) { + row_heights[index] = 0; index++; } - - index = 0; // Next, assign all the AutoSize rows to the height of their tallest // control. If the table-layout is auto-sized, then make sure that // no row with Percent styling clips its contents. // (per http://msdn.microsoft.com/en-us/library/ms171690.aspx) - for (int rowspan = 0; rowspan < max_rowspan; ++rowspan) - { - for (index = rowspan; index < row_styles.Count - rowspan; ++index) - { - RowStyle rs = row_styles[index]; - if (rs.SizeType == SizeType.AutoSize - || (panel.AutoSize && rs.SizeType == SizeType.Percent)) - { - int max_height = panel.row_heights[index]; - + for (int rowspan = 0; rowspan < max_rowspan; ++rowspan) { + for (index = rowspan; index < row_heights.Length - rowspan; ++index) { + RowStyle rs = index < row_styles.Count ? row_styles[index] : default_row_style; + if (rs.SizeType == SizeType.AutoSize || (auto_size && rs.SizeType == SizeType.Percent)) { + int max_height = row_heights[index]; // Find the tallest control in the row for (int i = 0; i < columns; i++) { - Control c = panel.actual_positions[i, index - rowspan]; - - if (c != null && c != dummy_control && c.VisibleInternal) - { + IArrangedElement c = actual_positions[i, index - rowspan]; + if (c != null && c != dummy_control && c.Visible) { // Skip any controls not being sized in this pass. if (settings.GetRowSpan (c) != rowspan + 1) continue; + int current_width = 0; + int column_span = settings.GetColumnSpan(c); + for (int j = i; j < i + column_span && j < column_widths.Length; j++) { + current_width += column_widths[j]; + } + // Calculate the maximum control height. - if (c.AutoSize) - max_height = Math.Max (max_height, c.PreferredSize.Height + c.Margin.Vertical); - else - max_height = Math.Max (max_height, c.ExplicitBounds.Height + c.Margin.Vertical); - max_height = Math.Max (max_height, c.Height + c.Margin.Top + c.Margin.Bottom); + max_height = Math.Max (max_height, GetControlSize(c, new Size(current_width - c.Margin.Horizontal, 0)).Height + c.Margin.Vertical); } } + if (rs.SizeType == SizeType.Percent) + max_percent_size = Math.Max(max_percent_size, max_height / rs.Height); + // Subtract the height of prior rows, if any. for (int i = Math.Max (index - rowspan, 0); i < index; ++i) - max_height -= panel.row_heights[i]; + max_height -= row_heights[i]; // If necessary, increase this row's height. - if (max_height > panel.row_heights[index]) - { - max_height -= panel.row_heights[index]; - panel.row_heights[index] += max_height; - total_height -= max_height; - } + if (max_height > row_heights[index]) + row_heights[index] = max_height; } } } - index = 0; - total_percent = 0; + // Resize the percent columns to match other percent columns relatively. + for (index = 0; index < row_styles.Count && index < row_heights.Length; ++index) { + RowStyle rs = row_styles[index]; + if (rs.SizeType == SizeType.Percent) + row_heights[index] = Math.Max(row_heights[index], (int)Math.Ceiling(max_percent_size * rs.Height)); + } + } - // Finally, assign the remaining space to Percent rows, if any. - if (total_height > 0) { - int percent_height = total_height; - + private static int RedistributePercents (int overlap, TableLayoutColumnStyleCollection styles, int[] column_widths) + { + int saved = 0; + + if (overlap > 0) { // Find the total percent (not always 100%) - foreach (RowStyle rs in row_styles) { - if (rs.SizeType == SizeType.Percent) - total_percent += rs.Height; + float total_percent = 0; + int index = 0; + foreach (ColumnStyle cs in styles) { + if (index >= column_widths.Length) + break; + if (cs.SizeType == SizeType.Percent) + total_percent += cs.Width; } // Divvy up the space.. - foreach (RowStyle rs in row_styles) { - if (rs.SizeType == SizeType.Percent) { - int height_change = (int)(((rs.Height / total_percent) * percent_height) - - panel.row_heights[index]); - if (height_change > 0) - { - panel.row_heights[index] += height_change; - total_height -= height_change; + index = 0; + foreach (ColumnStyle cs in styles) { + if (index >= column_widths.Length) + break; + if (cs.SizeType == SizeType.Percent) { + int width_change = (int)((cs.Width / total_percent) * overlap); + if (width_change > 0) { + column_widths[index] += width_change; + saved += width_change; } } - index++; } } - if (total_height > 0) - { + return saved; + } + + private static int RedistributePercents (int overlap, TableLayoutRowStyleCollection styles, int[] row_heights) + { + int saved = 0; + + if (overlap > 0) { + // Find the total percent (not always 100%) + float total_percent = 0; + int index = 0; + foreach (RowStyle rs in styles) { + if (index >= row_heights.Length) + break; + if (rs.SizeType == SizeType.Percent) + total_percent += rs.Height; + index++; + } + + // Divvy up the space.. + index = 0; + foreach (RowStyle rs in styles) { + if (index >= row_heights.Length) + break; + if (rs.SizeType == SizeType.Percent) { + int height_change = (int)((rs.Height / total_percent) * overlap); + if (height_change > 0) { + row_heights[index] += height_change; + saved += height_change; + } + } + index++; + } + } + + return saved; + } + + private void CalculateColumnRowSizes (IArrangedContainer panel, IArrangedElement[,] actual_positions, out int[] column_widths, out int[] row_heights, Size size, bool measureOnly) + { + TableLayoutPanel table_panel = panel as TableLayoutPanel; + TableLayoutSettings settings = GetLayoutSettings (panel); + int columns = actual_positions.GetLength(0); + int rows = actual_positions.GetLength(1); + bool auto_size = ((IArrangedElement)panel).AutoSize && measureOnly; + bool boundBySize = !measureOnly; + + column_widths = new int[actual_positions.GetLength (0)]; + row_heights = new int[actual_positions.GetLength (1)]; + + // Calculate the bounded size only if we are in default layout and docked, otherwise calculate unbounded. + if (measureOnly && size.Width > 0) { + if (table_panel != null && table_panel.Parent != null && table_panel.Parent.LayoutEngine is DefaultLayout) { + boundBySize |= panel.Dock == DockStyle.Top || panel.Dock == DockStyle.Bottom || panel.Dock == DockStyle.Fill; + boundBySize |= (panel.Anchor & (AnchorStyles.Left | AnchorStyles.Right)) == (AnchorStyles.Left | AnchorStyles.Right); + } + } + + int border_width = 0; + if (table_panel != null) { + border_width = TableLayoutPanel.GetCellBorderWidth (table_panel.CellBorderStyle); + } + + // Find the largest column-span/row-span values. + int max_colspan = 0, max_rowspan = 0; + foreach (IArrangedElement c in panel.Controls) { + if (c.Visible && c != dummy_control) { + max_colspan = Math.Max(max_colspan, settings.GetColumnSpan(c)); + max_rowspan = Math.Max(max_rowspan, settings.GetRowSpan(c)); + } + } + + // Figure up all the column widths + CalculateColumnWidths (settings, actual_positions, max_colspan, settings.ColumnStyles, auto_size, column_widths, false); + + // Calculate available width + int available_width = size.Width - (border_width * (columns + 1)); + foreach (int width in column_widths) + available_width -= width; + + // Shrink the table horizontally by shrinking it's columns, if necessary + if (boundBySize && size.Width > 0 && available_width < 0) { + // Calculate the minimum widths for each column + int[] col_min_widths = new int[column_widths.Length]; + CalculateColumnWidths (settings, actual_positions, max_colspan, settings.ColumnStyles, auto_size, col_min_widths, true); + available_width += Shrink(column_widths, col_min_widths, -available_width, max_colspan); + } + + // Finally, assign the remaining space to Percent columns, if any. + if (available_width > 0) + available_width -= RedistributePercents(available_width, settings.ColumnStyles, column_widths); + + if (available_width > 0 && column_widths.Length > 0) { + // Find the last column that isn't an Absolute SizeType, and give it + // all this free space. (Absolute sized columns need to retain their + // absolute width if at all possible!) + int col = Math.Min(settings.ColumnStyles.Count, column_widths.Length) - 1; + for (; col >= 0; --col) + if (settings.ColumnStyles[col].SizeType != SizeType.Absolute) + break; + if (col < 0) + col = column_widths.Length - 1; + column_widths[col] += available_width; + } + + // Figure up all the row heights + CalculateRowHeights (settings, actual_positions, max_rowspan, settings.RowStyles, auto_size, column_widths, row_heights); + + // Calculate available height + int available_height = size.Height - (border_width * (rows + 1)); + foreach (int height in row_heights) + available_height -= height; + + // NOTE: We don't do shrinking here, since there's no space to save. + + // Finally, assign the remaining space to Percent rows, if any. + if (available_height > 0) + available_height -= RedistributePercents(available_height, settings.RowStyles, row_heights); + + if (available_height > 0 && row_heights.Length > 0 && !measureOnly) { // Find the last row that isn't an Absolute SizeType, and give it // all this free space. (Absolute sized rows need to retain their // absolute height if at all possible!) - int row = row_styles.Count - 1; + int row = Math.Min(settings.RowStyles.Count, row_heights.Length) - 1; for (; row >= 0; --row) - { - if (row_styles[row].SizeType != SizeType.Absolute) + if (settings.RowStyles[row].SizeType != SizeType.Absolute) break; - } if (row < 0) - row = row_styles.Count - 1; - panel.row_heights[row] += total_height; + row = row_heights.Length - 1; + row_heights[row] += available_height; } } - - private void LayoutControls (TableLayoutPanel panel) - { - TableLayoutSettings settings = panel.LayoutSettings; - - int border_width = TableLayoutPanel.GetCellBorderWidth (panel.CellBorderStyle); - int columns = panel.actual_positions.GetLength(0); - int rows = panel.actual_positions.GetLength(1); + // Shrinks values in 'sizes' array using values in 'reserves' array, so that the sum of 'sizes' does not exceed the 'max'. + // The max_span represent max_colspan, max_rowspan values. + // The 'min_sizes' array tells the smalles appropriate values for column sizes. + static int Shrink (int[] sizes, int[] min_sizes, int overlap, int max_span) + { + int n = 0; + for (int index = 0; index < sizes.Length; ++index) + if (sizes[index] > min_sizes[index]) + n++; + + int saved = 0; + if (n != 0) { + int step = overlap < n ? 1 : overlap / n; + for (int span = 0; span < max_span && overlap > 0; ++span) { + for (int index = span; index < sizes.Length - span && overlap > 0; ++index) { + int reserve = sizes[index] - min_sizes[index]; + if (reserve > 0 && reserve != int.MaxValue) { + int d = step > reserve ? reserve : step; + sizes[index] -= d; + overlap -= d; + saved += d; + } + } + } + } + + return saved; + } + + private static Size GetControlSize (IArrangedElement c, Size proposedSize) + { + if (c.AutoSize) { + return c.GetPreferredSize (proposedSize); + } else { + return c.ExplicitBounds.Size; + } + } + + private void LayoutControls (IArrangedContainer panel, IArrangedElement[,] actual_positions, int[] column_widths, int[] row_heights) + { + TableLayoutSettings settings = GetLayoutSettings (panel); + + int border_width = 0; + if (panel is TableLayoutPanel table_panel) { + border_width = TableLayoutPanel.GetCellBorderWidth (table_panel.CellBorderStyle); + } + + int columns = actual_positions.GetLength(0); + int rows = actual_positions.GetLength(1); Point current_pos = new Point (panel.DisplayRectangle.Left + border_width, panel.DisplayRectangle.Top + border_width); @@ -508,38 +596,32 @@ namespace System.Windows.Forms.Layout { for (int x = 0; x < columns; x++) { - Control c = panel.actual_positions[x,y]; - - if(c != null && c != dummy_control) { + IArrangedElement c = actual_positions[x,y]; + if(c != null && c != dummy_control && c.Visible) { Size preferred; - if (c.AutoSize) - preferred = c.PreferredSize; - else - preferred = c.ExplicitBounds.Size; - int new_x = 0; int new_y = 0; int new_width = 0; int new_height = 0; - - // Figure out the width of the control - int column_width = panel.column_widths[x]; - - for (int i = 1; i < Math.Min (settings.GetColumnSpan(c), panel.column_widths.Length); i++) - column_width += panel.column_widths[x + i]; + int column_width = column_widths[x]; + for (int i = 1; i < Math.Min (settings.GetColumnSpan(c), column_widths.Length - x); i++) + column_width += column_widths[x + i]; + + int column_height = row_heights[y]; + for (int i = 1; i < Math.Min (settings.GetRowSpan(c), row_heights.Length - y); i++) + column_height += row_heights[y + i]; + + preferred = GetControlSize(c, new Size(column_width - c.Margin.Horizontal, column_height - c.Margin.Vertical)); + + // Figure out the width of the control if (c.Dock == DockStyle.Fill || c.Dock == DockStyle.Top || c.Dock == DockStyle.Bottom || ((c.Anchor & AnchorStyles.Left) == AnchorStyles.Left && (c.Anchor & AnchorStyles.Right) == AnchorStyles.Right)) new_width = column_width - c.Margin.Left - c.Margin.Right; else new_width = Math.Min (preferred.Width, column_width - c.Margin.Left - c.Margin.Right); // Figure out the height of the control - int column_height = panel.row_heights[y]; - - for (int i = 1; i < Math.Min (settings.GetRowSpan (c), panel.row_heights.Length); i++) - column_height += panel.row_heights[y + i]; - if (c.Dock == DockStyle.Fill || c.Dock == DockStyle.Left || c.Dock == DockStyle.Right || ((c.Anchor & AnchorStyles.Top) == AnchorStyles.Top && (c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom)) new_height = column_height - c.Margin.Top - c.Margin.Bottom; else @@ -561,30 +643,61 @@ namespace System.Windows.Forms.Layout else // (center control) new_y = (current_pos.Y + (column_height - c.Margin.Top - c.Margin.Bottom) / 2) + c.Margin.Top - (new_height / 2); - c.SetBoundsInternal (new_x, new_y, new_width, new_height, BoundsSpecified.None); + c.SetBounds (new_x, new_y, new_width, new_height, BoundsSpecified.None); } - current_pos.Offset (panel.column_widths[x] + border_width, 0); + current_pos.Offset (column_widths[x] + border_width, 0); } - current_pos.Offset ((-1 * current_pos.X) + border_width + panel.DisplayRectangle.Left, panel.row_heights[y] + border_width); + current_pos.Offset ((-1 * current_pos.X) + border_width + panel.DisplayRectangle.Left, row_heights[y] + border_width); } } -#if TABLE_DEBUG - private void OutputControlGrid (Control[,] grid, TableLayoutPanel panel) + internal override Size GetPreferredSize (object container, Size proposedSize) + { + IArrangedContainer panel = (IArrangedContainer) container; + TableLayoutSettings settings = GetLayoutSettings (panel); + + // If the tablelayoutowner is autosize, we have to make sure it is big enough + // to hold every non-autosize control + var actual_positions = CalculateControlPositions (panel, Math.Max (settings.ColumnCount, 1), Math.Max (settings.RowCount, 1)); + + int[] column_sizes; + int[] row_sizes; + int border_width = 0; + if (panel is TableLayoutPanel table_panel) { + border_width = TableLayoutPanel.GetCellBorderWidth (table_panel.CellBorderStyle); + } + CalculateColumnRowSizes(panel, actual_positions, out column_sizes, out row_sizes, proposedSize, true); + OutputControlGrid(actual_positions, column_sizes, row_sizes); + + int needed_width = (column_sizes.Length + 1) * border_width; + for (int i = 0; i < column_sizes.Length; i++) { + needed_width += column_sizes[i]; + } + + int needed_height = (row_sizes.Length + 1) * border_width; + for (int i = 0; i < row_sizes.Length; i++) { + needed_height += row_sizes[i]; + } + + return new Size(needed_width, needed_height); + } + + [Conditional("TABLE_DEBUG")] + private void OutputControlGrid (IArrangedElement[,] grid, int[] column_widths, int[] row_heights) { Console.WriteLine (" Size: {0}x{1}", grid.GetLength (0), grid.GetLength (1)); Console.Write (" "); - foreach (int i in panel.column_widths) + foreach (int i in column_widths) Console.Write (" {0}px ", i.ToString ().PadLeft (3)); Console.WriteLine (); for (int y = 0; y < grid.GetLength (1); y++) { - Console.Write (" {0}px |", panel.row_heights[y].ToString ().PadLeft (3)); + Console.Write (" {0}px |", row_heights[y].ToString ().PadLeft (3)); for (int x = 0; x < grid.GetLength (0); x++) { if (grid[x, y] == null) @@ -598,6 +711,5 @@ namespace System.Windows.Forms.Layout Console.WriteLine (); } } -#endif } } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms.Theming/ThemeElements.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms.Theming/ThemeElements.cs index ee653bbc9a..737a358d80 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms.Theming/ThemeElements.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms.Theming/ThemeElements.cs @@ -38,36 +38,10 @@ namespace System.Windows.Forms.Theming static ThemeElements () { - string theme_var; - - theme_var = Environment.GetEnvironmentVariable ("MONO_THEME"); - - if (theme_var == null) - theme_var = "win32"; + if (Application.VisualStylesEnabled) + theme = new ThemeElementsVisualStyles (); else - theme_var = theme_var.ToLower (); - - theme = LoadTheme (theme_var); - - } - - private static ThemeElementsDefault LoadTheme (string themeName) - { - if (themeName == "visualstyles") - if (Application.VisualStylesEnabled) - return new ThemeElementsVisualStyles (); - else - return new ThemeElementsDefault (); - Assembly ass = Assembly.GetExecutingAssembly (); - string iname = typeof(ThemeElements).FullName; - string assemblyname = iname + themeName; - Type type = ass.GetType (assemblyname, false, true); - if (type != null) { - object o = ass.CreateInstance (type.FullName); - if (o != null) - return (ThemeElementsDefault) o; - } - return new ThemeElementsDefault (); + theme = new ThemeElementsDefault (); } #region Buttons diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms.dll.sources b/mcs/class/System.Windows.Forms/System.Windows.Forms.dll.sources index 5774443e80..0655e69127 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms.dll.sources +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms.dll.sources @@ -382,7 +382,6 @@ System.Windows.Forms/HtmlWindowCollection.cs System.Windows.Forms/Hwnd.cs System.Windows.Forms/IButtonControl.cs System.Windows.Forms/IBindableComponent.cs -System.Windows.Forms/IBounds.cs System.Windows.Forms/ICommandExecutor.cs System.Windows.Forms/IComponentEditorPageSite.cs System.Windows.Forms/IContainerControl.cs @@ -821,6 +820,8 @@ System.Windows.Forms/XplatUIX11.cs System.Windows.Forms.Layout/ArrangedElementCollection.cs System.Windows.Forms.Layout/DefaultLayout.cs System.Windows.Forms.Layout/FlowLayout.cs +System.Windows.Forms.Layout/IArrangedContainer.cs +System.Windows.Forms.Layout/IArrangedElement.cs System.Windows.Forms.Layout/TableLayout.cs System.Windows.Forms.Layout/TableLayoutSettingsTypeConverter.cs System.Windows.Forms.Layout/LayoutEngine.cs diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/AccessibleObject.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/AccessibleObject.cs index 9ba2f9ab23..3a0e24896d 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/AccessibleObject.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/AccessibleObject.cs @@ -125,17 +125,17 @@ namespace System.Windows.Forms { public virtual AccessibleStates State { get { -#if not if (owner!=null) { if (owner.Focused) { state |= AccessibleStates.Focused; } - + if (owner.CanFocus) { + state |= AccessibleStates.Focusable; + } if (!owner.Visible) { state |= AccessibleStates.Invisible; } } -#endif return state; } } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/Application.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/Application.cs index 07353efcb7..2b1b1d6a0c 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/Application.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/Application.cs @@ -878,28 +878,26 @@ namespace System.Windows.Forms if (keyboard_capture != null) { Control c2 = Control.FromHandle (msg.hwnd); - // the target is not a winforms control (an embedded control, perhaps), so + // The target is not a winforms control (an embedded control, perhaps), so // release everything if (c2 == null) { ToolStripManager.FireAppClicked (); goto default; } - // If we clicked a ToolStrip, we have to make sure it isn't - // the one we are on, or any of its parents or children - // If we clicked off the dropped down menu, release everything - if (c2 is ToolStrip) { - if ((c2 as ToolStrip).GetTopLevelToolStrip () != keyboard_capture.GetTopLevelToolStrip ()) - ToolStripManager.FireAppClicked (); - } else { - if (c2.Parent != null) - if (c2.Parent is ToolStripDropDownMenu) - if ((c2.Parent as ToolStripDropDownMenu).GetTopLevelToolStrip () == keyboard_capture.GetTopLevelToolStrip ()) - goto default; - if (c2.TopLevelControl == null) - goto default; - - ToolStripManager.FireAppClicked (); + // Skip clicks on owner windows, eg. expanded ComboBox + if (Control.IsChild (keyboard_capture.Handle, msg.hwnd)) { + goto default; + } + + // Close any active toolstrips drop-downs if we click outside of them, + // but also don't close them all if we click outside of the top-most + // one, but into its owner. + Point c2_point = c2.PointToScreen (new Point ( + (int)(short)(m.LParam.ToInt32() & 0xffff), + (int)(short)(m.LParam.ToInt32() >> 16))); + while (keyboard_capture != null && !keyboard_capture.ClientRectangle.Contains (keyboard_capture.PointToClient (c2_point))) { + keyboard_capture.Dismiss (); } } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/BindingCompleteEventArgs.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/BindingCompleteEventArgs.cs index 37f18f4125..d90e5ca680 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/BindingCompleteEventArgs.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/BindingCompleteEventArgs.cs @@ -45,12 +45,12 @@ namespace System.Windows.Forms } public BindingCompleteEventArgs(Binding binding, BindingCompleteState state, BindingCompleteContext context, string errorText) - : this (binding, state, context, errorText, null, false) + : this (binding, state, context, errorText, null, true) { } public BindingCompleteEventArgs(Binding binding, BindingCompleteState state, BindingCompleteContext context, string errorText, Exception exception) - : this (binding, state, context, errorText, exception, false) + : this (binding, state, context, errorText, exception, true) { } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/Button.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/Button.cs index e04f399716..829c55012f 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/Button.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/Button.cs @@ -188,10 +188,18 @@ namespace System.Windows.Forms { internal override Size GetPreferredSizeCore (Size proposedSize) { + Size size; + if (this.AutoSize) - return ThemeEngine.Current.CalculateButtonAutoSize (this); - - return base.GetPreferredSizeCore (proposedSize); + size = ThemeEngine.Current.CalculateButtonAutoSize (this); + else + size = base.GetPreferredSizeCore (proposedSize); + + // Button has a special legacy behavior and implements AutoSizeMode itself + if (AutoSizeMode == AutoSizeMode.GrowOnly) + size = new Size (Math.Max (size.Width, Width), Math.Max (size.Height, Height)); + + return size; } #endregion // Internal methods } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/ButtonBase.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/ButtonBase.cs index 3b223ff93d..dce7999a5a 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/ButtonBase.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/ButtonBase.cs @@ -93,6 +93,8 @@ namespace System.Windows.Forms { ControlStyles.CacheText | ControlStyles.OptimizedDoubleBuffer, true); SetStyle (ControlStyles.StandardClick, false); + + can_cache_preferred_size = true; } #endregion // Public Constructors diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/CheckBox.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/CheckBox.cs index 3e26f77917..3d8ac10005 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/CheckBox.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/CheckBox.cs @@ -111,6 +111,7 @@ namespace System.Windows.Forms { TextAlign = ContentAlignment.MiddleLeft; SetStyle(ControlStyles.StandardDoubleClick, false); SetAutoSizeMode (AutoSizeMode.GrowAndShrink); + can_cache_preferred_size = true; } #endregion // Public Constructors diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/CheckedListBox.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/CheckedListBox.cs index 772eeb32bf..47a8ae31d7 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/CheckedListBox.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/CheckedListBox.cs @@ -423,7 +423,19 @@ namespace System.Windows.Forms owner.UpdateCollections (); return idx; } - } + + public override void Clear () + { + owner.check_states.Clear (); + base.Clear (); + } + + internal override void UpdateSelection (int removed_index) + { + owner.check_states.Remove (this[removed_index]); + base.UpdateSelection (removed_index); + } + } public class CheckedIndexCollection : IList, ICollection, IEnumerable { diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/ColorDialog.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/ColorDialog.cs index 599cb3d916..9d7ed0645b 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/ColorDialog.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/ColorDialog.cs @@ -165,7 +165,7 @@ namespace System.Windows.Forms { greenLabel.TextAlign = ContentAlignment.MiddleRight; // colorBaseLabel colorBaseLabel.Location = new Point (228, 247); - colorBaseLabel.Size = new Size (60, 25); + colorBaseLabel.Size = new Size (60, 16); colorBaseLabel.TabIndex = 28; colorBaseLabel.Text = Locale.GetText ("Color"); colorBaseLabel.TextAlign = ContentAlignment.MiddleCenter; @@ -384,11 +384,11 @@ namespace System.Windows.Forms { if (fullOpen && allowFullOpen) { defineColoursButton.Enabled = false; colorMatrixControl.ColorToShow = baseColorControl.ColorToShow; - form.Size = GetFormSize (true); + form.ClientSize = GetFormClientSize (true); } else { if (allowFullOpen) defineColoursButton.Enabled = true; - form.Size = GetFormSize (false); + form.ClientSize = GetFormClientSize (false); } } } @@ -483,7 +483,7 @@ namespace System.Windows.Forms { defineColoursButton.Enabled = (AllowFullOpen && !FullOpen); defineColoursButton.Refresh (); - form.Size = GetFormSize (FullOpen && AllowFullOpen); + form.ClientSize = GetFormClientSize (FullOpen && AllowFullOpen); // currently needed, otherwise there are a lot of drawing artefacts/transparent controls if the same dialog gets opened again form.Refresh (); @@ -493,12 +493,12 @@ namespace System.Windows.Forms { #region Private Methods - Size GetFormSize (bool fullOpen) + Size GetFormClientSize (bool fullOpen) { if (fullOpen) - return new Size (448, 332); + return new Size (446, 300); else - return new Size (221, 332); // 300 + return new Size (219, 300); } void OnClickCancelButton (object sender, EventArgs e) @@ -521,7 +521,7 @@ namespace System.Windows.Forms { if (allowFullOpen) { defineColoursButton.Enabled = false; colorMatrixControl.ColorToShow = baseColorControl.ColorToShow; - form.Size = GetFormSize (true); + form.ClientSize = GetFormClientSize (true); } } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/ColumnStyle.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/ColumnStyle.cs index 6e5dddef3d..5170ba2278 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/ColumnStyle.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/ColumnStyle.cs @@ -60,8 +60,8 @@ namespace System.Windows.Forms if (width != value) { width = value; - if (base.Owner != null) - base.Owner.PerformLayout (); + if (Owner != null) + Owner.PerformLayout (Owner, "Style"); } } } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/ComboBox.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/ComboBox.cs index 58a6f94bd3..5e532be9f8 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/ComboBox.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/ComboBox.cs @@ -98,7 +98,8 @@ namespace System.Windows.Forms items = new ObjectCollection (this); DropDownStyle = ComboBoxStyle.DropDown; item_height = FontHeight + 2; - background_color = ThemeEngine.Current.ColorControl; + background_color = ThemeEngine.Current.ColorWindow; + foreground_color = ThemeEngine.Current.ColorWindowText; border_style = BorderStyle.None; drop_down_height = default_drop_down_height; @@ -111,7 +112,9 @@ namespace System.Windows.Forms MouseWheel += new MouseEventHandler (OnMouseWheelCB); MouseEnter += new EventHandler (OnMouseEnter); MouseLeave += new EventHandler (OnMouseLeave); - KeyDown +=new KeyEventHandler(OnKeyDownCB); + KeyDown += new KeyEventHandler (OnKeyDownCB); + + can_cache_preferred_size = true; } #region events @@ -1111,7 +1114,7 @@ namespace System.Windows.Forms { base.OnHandleCreated (e); - SetBoundsInternal (Left, Top, Width, PreferredHeight, BoundsSpecified.None); + SetBoundsCore (Left, Top, Width, PreferredHeight, BoundsSpecified.None); if (textbox_ctrl != null) Controls.AddImplicit (textbox_ctrl); @@ -2419,6 +2422,7 @@ namespace System.Windows.Forms SetStyle (ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true); SetStyle (ControlStyles.ResizeRedraw | ControlStyles.Opaque, true); + SetTopLevel (true); this.is_visible = false; @@ -2534,9 +2538,8 @@ namespace System.Windows.Forms } } - var borderWidth = Hwnd.GetBorderWidth (CreateParams); var borderAdjustment = dropdown_style == ComboBoxStyle.Simple ? new Size (0, 0) : - new Size (borderWidth.top + borderWidth.bottom, borderWidth.left + borderWidth.right); + SizeFromClientSize(Size.Empty); Size = new Size (width, height + borderAdjustment.Height); textarea_drawable = new Rectangle (ClientRectangle.Location, new Size (width - borderAdjustment.Width, height)); @@ -2773,6 +2776,7 @@ namespace System.Windows.Forms if (this.Location.Y + this.Height >= scrn_rect.Bottom) this.Location = new Point (this.Location.X, this.Location.Y - (this.Height + owner.TextArea.Height)); Show (); + XplatUI.SetOwner (Handle, owner.Handle); Refresh (); owner.OnDropDown (EventArgs.Empty); diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/ContainerControl.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/ContainerControl.cs index 24a3d88d53..78100f8fec 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/ContainerControl.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/ContainerControl.cs @@ -57,6 +57,7 @@ namespace System.Windows.Forms { ControlRemoved += new ControlEventHandler(OnControlRemoved); auto_scale_dimensions = SizeF.Empty; auto_scale_mode = AutoScaleMode.Inherit; + can_cache_preferred_size = true; } #endregion // Public Constructors @@ -805,6 +806,15 @@ namespace System.Windows.Forms { { base.OnLayout (e); } + + internal override Size GetPreferredSizeCore (Size proposedSize) + { + // Translating 0,0 from ClientSize to actual Size tells us how much space + // is required for the borders. + Size borderSize = SizeFromClientSize(Size.Empty); + Size totalPadding = borderSize + Padding.Size; + return LayoutEngine.GetPreferredSize(this, proposedSize) + totalPadding; + } AutoValidate auto_validate = AutoValidate.Inherit; diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/Control.cs.REMOVED.git-id b/mcs/class/System.Windows.Forms/System.Windows.Forms/Control.cs.REMOVED.git-id index 27774ba43e..118985492d 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/Control.cs.REMOVED.git-id +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/Control.cs.REMOVED.git-id @@ -1 +1 @@ -d763afde5a3248c92c7881e016679594b83a0af9 \ No newline at end of file +85d042e97b012302035f328d2e42cf2c38c8385d \ No newline at end of file diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/ErrorProvider.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/ErrorProvider.cs index bcebe4bd89..e7510a263e 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/ErrorProvider.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/ErrorProvider.cs @@ -278,17 +278,15 @@ namespace System.Windows.Forms { private void window_Tick(object sender, EventArgs e) { if (timer.Enabled && control.IsHandleCreated && control.Visible) { - Graphics g; - blink_count++; - g = window.CreateGraphics(); - if ((blink_count % 2) == 0) { - g.FillRectangle(ThemeEngine.Current.ResPool.GetSolidBrush(window.Parent.BackColor), window.ClientRectangle); - } else { - g.DrawIcon(this.ep.icon, 0, 0); + using (Graphics g = window.CreateGraphics()) { + if ((blink_count % 2) == 0) { + g.FillRectangle(ThemeEngine.Current.ResPool.GetSolidBrush(window.Parent.BackColor), window.ClientRectangle); + } else { + g.DrawIcon(this.ep.icon, 0, 0); + } } - g.Dispose(); switch (ep.blinkstyle) { case ErrorBlinkStyle.AlwaysBlink: diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/FileDialog.cs.REMOVED.git-id b/mcs/class/System.Windows.Forms/System.Windows.Forms/FileDialog.cs.REMOVED.git-id index db05bdc152..75af1ca6a3 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/FileDialog.cs.REMOVED.git-id +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/FileDialog.cs.REMOVED.git-id @@ -1 +1 @@ -ef65c5b54b4bc8c52fb1c210031b3f1641bba8d9 \ No newline at end of file +557f45ec14d79dd122db7f2dba217520322e51d9 \ No newline at end of file diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/FlowLayoutPanel.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/FlowLayoutPanel.cs index 0bd776c2de..a3b492bc9d 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/FlowLayoutPanel.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/FlowLayoutPanel.cs @@ -64,7 +64,7 @@ namespace System.Windows.Forms } public override LayoutEngine LayoutEngine { - get { return this.LayoutSettings.LayoutEngine; } + get { return System.Windows.Forms.Layout.FlowLayout.Instance; } } internal FlowLayoutSettings LayoutSettings { @@ -102,94 +102,5 @@ namespace System.Windows.Forms return false; } #endregion - - #region Internal Methods - internal override void CalculateCanvasSize (bool canOverride) - { - if (canOverride) - canvas_size = ClientSize; - else - base.CalculateCanvasSize (canOverride); - } - - protected override void OnLayout (LayoutEventArgs levent) - { - base.OnLayout (levent); - - // base.OnLayout() calls CalculateCanvasSize(true) in which we just set the canvas to - // clientsize so we could re-layout everything according to the flow. - // This time we want to actually calculate the canvas. - CalculateCanvasSize (false); - if (AutoSize && (canvas_size.Width > ClientSize.Width || canvas_size.Height > ClientSize.Height)) { - ClientSize = canvas_size; - } - AdjustFormScrollbars (AutoScroll); - } - - internal override Size GetPreferredSizeCore (Size proposedSize) - { - int width = 0; - int height = 0; - bool horizontal = FlowDirection == FlowDirection.LeftToRight || FlowDirection == FlowDirection.RightToLeft; - if (!WrapContents || (horizontal && proposedSize.Width == 0) || (!horizontal && proposedSize.Height == 0)) { - foreach (Control control in Controls) { - Size control_preferred_size; - if (control.AutoSize) - control_preferred_size = control.PreferredSize; - else - control_preferred_size = control.Size; - Padding control_margin = control.Margin; - if (horizontal) { - width += control_preferred_size.Width + control_margin.Horizontal; - height = Math.Max (height, control_preferred_size.Height + control_margin.Vertical); - } else { - height += control_preferred_size.Height + control_margin.Vertical; - width = Math.Max (width, control_preferred_size.Width + control_margin.Horizontal); - } - } - } else { - int size_in_flow_direction = 0; - int size_in_other_direction = 0; - int increase; - foreach (Control control in Controls) { - Size control_preferred_size; - if (control.AutoSize) - control_preferred_size = control.PreferredSize; - else - control_preferred_size = control.ExplicitBounds.Size; - Padding control_margin = control.Margin; - if (horizontal) { - increase = control_preferred_size.Width + control_margin.Horizontal; - if (size_in_flow_direction != 0 && size_in_flow_direction + increase >= proposedSize.Width) { - width = Math.Max (width, size_in_flow_direction); - size_in_flow_direction = 0; - height += size_in_other_direction; - size_in_other_direction = 0; - } - size_in_flow_direction += increase; - size_in_other_direction = Math.Max (size_in_other_direction, control_preferred_size.Height + control_margin.Vertical); - } else { - increase = control_preferred_size.Height + control_margin.Vertical; - if (size_in_flow_direction != 0 && size_in_flow_direction + increase >= proposedSize.Height) { - height = Math.Max (height, size_in_flow_direction); - size_in_flow_direction = 0; - width += size_in_other_direction; - size_in_other_direction = 0; - } - size_in_flow_direction += increase; - size_in_other_direction = Math.Max (size_in_other_direction, control_preferred_size.Width + control_margin.Horizontal); - } - } - if (horizontal) { - width = Math.Max (width, size_in_flow_direction); - height += size_in_other_direction; - } else { - height = Math.Max (height, size_in_flow_direction); - width += size_in_other_direction; - } - } - return new Size (width, height); - } - #endregion } } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/FlowLayoutSettings.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/FlowLayoutSettings.cs index a56ac0517a..11d11b55ac 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/FlowLayoutSettings.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/FlowLayoutSettings.cs @@ -37,7 +37,6 @@ namespace System.Windows.Forms { private FlowDirection flow_direction; private bool wrap_contents; - private LayoutEngine layout_engine; private Dictionary flow_breaks; private Control owner; @@ -68,10 +67,7 @@ namespace System.Windows.Forms public override LayoutEngine LayoutEngine { get { - if (this.layout_engine == null) - this.layout_engine = new FlowLayout (); - - return this.layout_engine; + return System.Windows.Forms.Layout.DefaultLayout.Instance; } } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/Form.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/Form.cs index 5b6ed663ee..419564b99b 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/Form.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/Form.cs @@ -78,6 +78,7 @@ namespace System.Windows.Forms { private Icon icon; private Size maximum_size; private Size minimum_size; + private Size minimum_auto_size; private SizeGripStyle size_grip_style; private SizeGrip size_grip; private Rectangle maximized_bounds; @@ -159,44 +160,6 @@ namespace System.Windows.Forms { this.OnClosed (EventArgs.Empty); this.OnFormClosed (new FormClosedEventArgs (reason)); } - - internal override Size GetPreferredSizeCore (Size proposedSize) - { - Size retsize = Size.Empty; - - foreach (Control child in Controls) { - Size child_preferred_size; - if (child.AutoSize) - child_preferred_size = child.PreferredSize; - else - child_preferred_size = child.ExplicitBounds.Size; - int child_right = child.Bounds.X + child_preferred_size.Width; - int child_bottom = child.Bounds.Y + child_preferred_size.Height; - - if (child.Dock == DockStyle.Fill) { - if (child_right > retsize.Width) - retsize.Width = child_right; - } - else if (child.Dock != DockStyle.Top && child.Dock != DockStyle.Bottom && child_right > retsize.Width) - retsize.Width = child_right + child.Margin.Right; - - if (child.Dock == DockStyle.Fill) { - if (child_bottom > retsize.Height) - retsize.Height = child_bottom; - } - else if (child.Dock != DockStyle.Left && child.Dock != DockStyle.Right && child_bottom > retsize.Height) - retsize.Height = child_bottom + child.Margin.Bottom; - } - - if (retsize == Size.Empty) { // no child controls - retsize.Height += this.Padding.Top; - retsize.Width += this.Padding.Left; - } - retsize.Height += this.Padding.Bottom; - retsize.Width += this.Padding.Right; - - return SizeFromClientSize (retsize); - } [EditorBrowsable (EditorBrowsableState.Advanced)] protected override Rectangle GetScaledBounds (Rectangle bounds, SizeF factor, BoundsSpecified specified) @@ -552,6 +515,10 @@ namespace System.Windows.Forms { set { if (base.AutoSize != value) { base.AutoSize = value; + if (!value) { + minimum_auto_size = Size.Empty; + UpdateMinMax (); + } PerformLayout (this, "AutoSize"); } } @@ -865,7 +832,7 @@ namespace System.Windows.Forms { OnMaximumSizeChanged(EventArgs.Empty); if (IsHandleCreated) { - XplatUI.SetWindowMinMax(Handle, maximized_bounds, minimum_size, maximum_size); + UpdateMinMax(); } } } @@ -1052,7 +1019,7 @@ namespace System.Windows.Forms { OnMinimumSizeChanged(EventArgs.Empty); if (IsHandleCreated) { - XplatUI.SetWindowMinMax(Handle, maximized_bounds, minimum_size, maximum_size); + UpdateMinMax(); } } } @@ -1551,7 +1518,7 @@ namespace System.Windows.Forms { maximized_bounds = value; OnMaximizedBoundsChanged(EventArgs.Empty); if (IsHandleCreated) { - XplatUI.SetWindowMinMax(Handle, maximized_bounds, minimum_size, maximum_size); + UpdateMinMax(); } } } @@ -1924,7 +1891,7 @@ namespace System.Windows.Forms { } } - XplatUI.SetWindowMinMax(window.Handle, maximized_bounds, minimum_size, maximum_size); + UpdateMinMax(); if (show_icon && (FormBorderStyle != FormBorderStyle.FixedDialog) && (icon != null)) { XplatUI.SetIcon(window.Handle, icon); @@ -2403,6 +2370,8 @@ namespace System.Windows.Forms { if (value && IsMdiChild){ PerformLayout (); ThemeEngine.Current.ManagedWindowSetButtonLocations (window_manager); + if (ActivateOnShow && MdiParent != null) + MdiParent.ActivateMdiChild (this); } // Shown event is only called once, the first time the form is made visible @@ -2673,7 +2642,7 @@ namespace System.Windows.Forms { IsActive = true; } else { - if (XplatUI.IsEnabled (Handle) && XplatUI.GetParent (m.LParam) != Handle) + if (XplatUI.IsEnabled (Handle) && !IsChild (Handle, m.LParam)) ToolStripManager.FireAppFocusChanged (this); IsActive = false; } @@ -2787,7 +2756,7 @@ namespace System.Windows.Forms { if (ActiveMaximizedMdiChild != null) ActiveMaximizedMdiChild.DrawMaximizedButtons (ActiveMenu, pe); - XplatUI.PaintEventEnd (ref m, Handle, false); + XplatUI.PaintEventEnd (ref m, Handle, false, pe); } base.WndProc (ref m); @@ -2926,6 +2895,13 @@ namespace System.Windows.Forms { is_loaded = true; } + + private void UpdateMinMax() + { + var min_size = AutoSize ? new Size (Math.Max (minimum_auto_size.Width, minimum_size.Width), Math.Max (minimum_auto_size.Height, minimum_size.Height)) : minimum_size; + if (IsHandleCreated) + XplatUI.SetWindowMinMax (Handle, maximized_bounds, min_size, maximum_size); + } #endregion #region Events @@ -3175,10 +3151,12 @@ namespace System.Windows.Forms { protected override void OnLayout (LayoutEventArgs levent) { - base.OnLayout (levent); - if (AutoSize) { Size new_size = GetPreferredSizeCore (Size.Empty); + if (new_size != minimum_auto_size) { + minimum_auto_size = new_size; + UpdateMinMax(); + } if (AutoSizeMode == AutoSizeMode.GrowOnly) { new_size.Width = Math.Max (new_size.Width, Width); new_size.Height = Math.Max (new_size.Height, Height); @@ -3186,8 +3164,10 @@ namespace System.Windows.Forms { if (new_size == Size) return; - SetBoundsInternal (bounds.X, bounds.Y, new_size.Width, new_size.Height, BoundsSpecified.None); + SetBoundsCore (bounds.X, bounds.Y, new_size.Width, new_size.Height, BoundsSpecified.None); } + + base.OnLayout (levent); } [EditorBrowsable (EditorBrowsableState.Advanced)] diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/GroupBox.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/GroupBox.cs index aaeb9227c0..c047a77ebf 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/GroupBox.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/GroupBox.cs @@ -153,6 +153,8 @@ namespace System.Windows.Forms SetStyle(ControlStyles.ContainerControl | ControlStyles.ResizeRedraw | ControlStyles.SupportsTransparentBackColor, true); SetStyle(ControlStyles.Selectable, false); + + can_cache_preferred_size = true; } #region Public Properties diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/Hwnd.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/Hwnd.cs index b926e4ed1a..a4d39fea3f 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/Hwnd.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/Hwnd.cs @@ -55,6 +55,7 @@ namespace System.Windows.Forms { internal int height; internal bool allow_drop; internal Hwnd parent; + internal Hwnd owner; internal bool visible; internal bool mapped; internal uint opacity; @@ -67,10 +68,8 @@ namespace System.Windows.Forms { internal bool configure_pending; internal bool resizing_or_moving; // Used by the X11 backend to track form resize/move internal bool reparented; - internal Stack drawing_stack; internal object user_data; internal Rectangle client_rectangle; - internal ArrayList marshal_free_list; internal int caption_height; internal int tool_caption_height; internal bool whacky_wm; @@ -116,10 +115,8 @@ namespace System.Windows.Forms { enabled = true; reparented = false; client_rectangle = Rectangle.Empty; - marshal_free_list = new ArrayList(2); opacity = 0xffffffff; fixed_size = false; - drawing_stack = new Stack (); children = new ArrayList (); resizing_or_moving = false; whacky_wm = false; @@ -136,11 +133,7 @@ namespace System.Windows.Forms { } client_window = IntPtr.Zero; whole_window = IntPtr.Zero; - zombie = false; - for (int i = 0; i < marshal_free_list.Count; i++) { - Marshal.FreeHGlobal((IntPtr)marshal_free_list[i]); - } - marshal_free_list.Clear(); + zombie = true; } #endregion @@ -813,28 +806,22 @@ namespace System.Windows.Forms { return String.Format("Hwnd, Mapped:{3} ClientWindow:0x{0:X}, WholeWindow:0x{1:X}, Zombie={4}, Parent:[{2:X}]", client_window.ToInt32(), whole_window.ToInt32(), parent != null ? parent.ToString() : "", Mapped, zombie); } - public static Point GetNextStackedFormLocation (CreateParams cp, Hwnd parent_hwnd) + public static Point GetNextStackedFormLocation (CreateParams cp) { if (cp.control == null) return Point.Empty; + MdiClient parent = cp.control.Parent as MdiClient; + if (parent != null) + return parent.GetNextStackedFormLocation (cp); + int X = cp.X; int Y = cp.Y; Point previous, next; Rectangle within; - if (parent_hwnd != null) { - Control parent = cp.control.Parent; - previous = parent_hwnd.previous_child_startup_location; - if (parent_hwnd.client_rectangle == Rectangle.Empty && parent != null) { - within = parent.ClientRectangle; - } else { - within = parent_hwnd.client_rectangle; - } - } else { - previous = Hwnd.previous_main_startup_location; - within = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea; - } + previous = Hwnd.previous_main_startup_location; + within = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea; if (previous.X == int.MinValue || previous.Y == int.MinValue) { next = Point.Empty; @@ -850,18 +837,9 @@ namespace System.Windows.Forms { next = new Point (22, 22); } - if (parent_hwnd != null) { - parent_hwnd.previous_child_startup_location = next; - } else { - Hwnd.previous_main_startup_location = next; - } + Hwnd.previous_main_startup_location = next; - if (X == int.MinValue && Y == int.MinValue) { - X = next.X; - Y = next.Y; - } - - return new Point (X, Y); + return next; } #endregion // Methods diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/InternalWindowManager.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/InternalWindowManager.cs index ea58417925..62a5c9286a 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/InternalWindowManager.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/InternalWindowManager.cs @@ -265,7 +265,7 @@ namespace System.Windows.Forms { clip = new Rectangle (0, 0, form.Width, form.Height); ThemeEngine.Current.DrawManagedWindowDecorations (pe.Graphics, clip, this); } - XplatUI.PaintEventEnd (ref m, form.Handle, false); + XplatUI.PaintEventEnd (ref m, form.Handle, false, pe); return true; } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/KeysConverter.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/KeysConverter.cs index a485a4c50b..ae33708356 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/KeysConverter.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/KeysConverter.cs @@ -27,11 +27,33 @@ // COMPLETE using System.Collections; +using System.Collections.Generic; using System.ComponentModel; using System.Text; namespace System.Windows.Forms { public class KeysConverter : TypeConverter, IComparer { + private static Dictionary key_names; + + static KeysConverter() { + key_names = new Dictionary(15); + key_names.Add("Ctrl", Keys.Control); + key_names.Add("Del", Keys.Delete); + key_names.Add("Enter", Keys.Return); + key_names.Add("PgDn", Keys.PageDown); + key_names.Add("PgUp", Keys.PageUp); + key_names.Add("0", Keys.D0); + key_names.Add("1", Keys.D1); + key_names.Add("2", Keys.D2); + key_names.Add("3", Keys.D3); + key_names.Add("4", Keys.D4); + key_names.Add("5", Keys.D5); + key_names.Add("6", Keys.D6); + key_names.Add("7", Keys.D7); + key_names.Add("8", Keys.D8); + key_names.Add("9", Keys.D9); + } + #region Public Constructors public KeysConverter() { } @@ -63,22 +85,22 @@ namespace System.Windows.Forms { public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) { if (value is string) { string[] keys; - Keys key; + Keys key, special_key; keys = ((string)value).Split(new char[] {'+'}); key = Keys.None; if (keys.Length > 1) { for (int i = 0; i < keys.Length - 1; i++) { - if (keys[i].Equals("Ctrl")) { - key |= Keys.Control; + if (key_names.TryGetValue (keys[i], out special_key)) { + key |= special_key; } else { key |= (Keys)Enum.Parse(typeof(Keys), keys[i], true); } } } - if (keys [keys.Length - 1].Equals ("Ctrl")) - key |= Keys.Control; + if (key_names.TryGetValue (keys[keys.Length - 1], out special_key)) + key |= special_key; else key |= (Keys)Enum.Parse(typeof(Keys), keys[keys.Length - 1], true); return key; diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/Label.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/Label.cs index b29d6d0acc..a69ea27edc 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/Label.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/Label.cs @@ -57,7 +57,6 @@ namespace System.Windows.Forms internal ContentAlignment image_align; internal StringFormat string_format; internal ContentAlignment text_align; - static SizeF req_witdthsize = new SizeF (0,0); #region Events static object AutoSizeChangedEvent = new object (); @@ -147,8 +146,8 @@ namespace System.Windows.Forms ControlStyles.SupportsTransparentBackColor | ControlStyles.OptimizedDoubleBuffer , true); - - HandleCreated += new EventHandler (OnHandleCreatedLB); + + can_cache_preferred_size = true; } #region Public Properties @@ -384,48 +383,46 @@ namespace System.Windows.Forms set { base.ImeMode = value; } } - internal virtual Size InternalGetPreferredSize (Size proposed) + internal override Size GetPreferredSizeCore (Size proposed) { + Size borders_and_paddings = new Size(Padding.Horizontal, Padding.Vertical); Size size; + if (use_compatible_text_rendering) { + borders_and_paddings.Height += border_style == BorderStyle.None ? 3 : 6; + } + if (Text == string.Empty) { size = new Size (0, Font.Height); } else { - size = Size.Ceiling (TextRenderer.MeasureString (Text, Font, req_witdthsize, string_format)); + int proposed_width = proposed.Width <= 1 ? int.MaxValue : (proposed.Width - borders_and_paddings.Width); + size = Size.Ceiling (TextRenderer.MeasureString (Text, Font, proposed_width, string_format)); size.Width += 3; } - - size.Width += Padding.Horizontal; - size.Height += Padding.Vertical; - if (!use_compatible_text_rendering) - return size; - - if (border_style == BorderStyle.None) - size.Height += 3; - else - size.Height += 6; - - return size; + return size + borders_and_paddings; } public override Size GetPreferredSize (Size proposedSize) { - return InternalGetPreferredSize (proposedSize); + // This is consistent with GetPreferredSizeCore and enables caching. + if (proposedSize.Width == 1) + proposedSize.Width = 0; + return base.GetPreferredSize(proposedSize); } [Browsable(false)] [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)] [EditorBrowsable(EditorBrowsableState.Advanced)] public virtual int PreferredHeight { - get { return InternalGetPreferredSize (Size.Empty).Height; } + get { return GetPreferredSizeCore (Size.Empty).Height; } } [Browsable(false)] [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)] [EditorBrowsable(EditorBrowsableState.Advanced)] public virtual int PreferredWidth { - get { return InternalGetPreferredSize (Size.Empty).Width; } + get { return GetPreferredSizeCore (Size.Empty).Width; } } [Obsolete ("This property has been deprecated. Use BackColor instead.")] @@ -586,7 +583,7 @@ namespace System.Windows.Forms protected override void OnFontChanged (EventArgs e) { base.OnFontChanged (e); - if (autosize) + if (SelfSizing) CalcAutoSize(); Invalidate (); } @@ -605,6 +602,8 @@ namespace System.Windows.Forms protected override void OnParentChanged (EventArgs e) { base.OnParentChanged (e); + if (SelfSizing) + CalcAutoSize(); } protected override void OnRightToLeftChanged (EventArgs e) @@ -622,8 +621,10 @@ namespace System.Windows.Forms protected override void OnTextChanged (EventArgs e) { base.OnTextChanged (e); - if (autosize) + if (SelfSizing) CalcAutoSize (); + else if (Parent != null) + Parent.PerformLayout (this, "Text"); Invalidate (); } @@ -646,6 +647,11 @@ namespace System.Windows.Forms protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified) { + if (SelfSizing) { + Size preferredSize = PreferredSize; + width = preferredSize.Width; + height = preferredSize.Height; + } base.SetBoundsCore (x, y, width, height, specified); } @@ -668,6 +674,16 @@ namespace System.Windows.Forms #endregion Public Methods + #region Private Properties + + bool SelfSizing { + get { + return AutoSize && Parent != null && Parent.LayoutEngine is Layout.DefaultLayout; + } + } + + #endregion + #region Private Methods private void CalcAutoSize () @@ -675,17 +691,11 @@ namespace System.Windows.Forms if (!AutoSize) return; - Size s = InternalGetPreferredSize (Size.Empty); - + cached_preferred_size = Size.Empty; + Size s = PreferredSize; SetBounds (Left, Top, s.Width, s.Height, BoundsSpecified.Size); } - private void OnHandleCreatedLB (Object o, EventArgs e) - { - if (autosize) - CalcAutoSize (); - } - private void SetUseMnemonic (bool use) { if (use) diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/ListBox.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/ListBox.cs index 538e9e5ead..fbc74eed38 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/ListBox.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/ListBox.cs @@ -2125,7 +2125,7 @@ namespace System.Windows.Forms private void UpdateListBoxBounds () { if (IsHandleCreated) - SetBoundsInternal (bounds.X, bounds.Y, bounds.Width, IntegralHeight ? SnapHeightToIntegral (requested_height) : requested_height, BoundsSpecified.None); + SetBoundsCore (bounds.X, bounds.Y, bounds.Width, IntegralHeight ? SnapHeightToIntegral (requested_height) : requested_height, BoundsSpecified.None); } private void UpdateScrollBars () @@ -2681,7 +2681,7 @@ namespace System.Windows.Forms } // we receive the index to be removed - void UpdateSelection (int removed_index) + internal virtual void UpdateSelection (int removed_index) { owner.selected_indices.Remove (removed_index); diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/MainMenu.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/MainMenu.cs index 9164bf2410..d9e3ad8b71 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/MainMenu.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/MainMenu.cs @@ -128,7 +128,7 @@ namespace System.Windows.Forms PaintEventArgs pevent = XplatUI.PaintEventStart (ref m, Wnd.window.Handle, false); pevent.Graphics.SetClip (new Rectangle (rect.X + pt.X, rect.Y + pt.Y, rect.Width, rect.Height)); Draw (pevent, Rect); - XplatUI.PaintEventEnd (ref m, Wnd.window.Handle, false); + XplatUI.PaintEventEnd (ref m, Wnd.window.Handle, false, pevent); } } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/MdiClient.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/MdiClient.cs index 2a6ef608e7..56cb6e9c94 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/MdiClient.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/MdiClient.cs @@ -52,6 +52,7 @@ namespace System.Windows.Forms { private string form_text; private bool setting_form_text; private Form active_child; + private Point next_child_stack_location; #endregion // Local Variables @@ -173,7 +174,7 @@ namespace System.Windows.Forms { clip = new Rectangle (0, 0, Width, Height); ControlPaint.DrawBorder3D (pe.Graphics, clip, Border3DStyle.Sunken); - XplatUI.PaintEventEnd (ref m, Handle, false); + XplatUI.PaintEventEnd (ref m, Handle, false, pe); m.Result = IntPtr.Zero; return ; } @@ -997,6 +998,16 @@ namespace System.Windows.Forms { } } } + + internal Point GetNextStackedFormLocation (CreateParams cp) + { + Point previous = next_child_stack_location; + next_child_stack_location = new Point (previous.X + 22, previous.Y + 22); + if (!ClientRectangle.Contains (next_child_stack_location.X * 3, next_child_stack_location.Y * 3)) { + next_child_stack_location = Point.Empty; + } + return previous; + } } } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/MenuAPI.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/MenuAPI.cs index c5a7abe1b1..3c1d4b5991 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/MenuAPI.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/MenuAPI.cs @@ -315,6 +315,8 @@ namespace System.Windows.Forms { } } + XplatUI.EndLoop(Thread.CurrentThread); + if (tracker.GrabControl.IsDisposed) return true; @@ -837,6 +839,7 @@ namespace System.Windows.Forms { this.form = form; SetStyle (ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true); SetStyle (ControlStyles.ResizeRedraw | ControlStyles.Opaque, true); + SetTopLevel (true); is_visible = false; } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/MenuItem.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/MenuItem.cs index 9505fc79e1..37c4c95d06 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/MenuItem.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/MenuItem.cs @@ -568,8 +568,8 @@ namespace System.Windows.Forms ShowShortcut = itemSrc.ShowShortcut; Text = itemSrc.Text; Visible = itemSrc.Visible; - Name = itemSrc.Name; - Tag = itemSrc.Tag; + // Name and Tag are not cloned + Name = ""; // Events Events[ClickEvent] = itemSrc.Events[ClickEvent]; diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/MonthCalendar.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/MonthCalendar.cs index e542440c01..158e7d50d1 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/MonthCalendar.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/MonthCalendar.cs @@ -194,6 +194,8 @@ namespace System.Windows.Forms { this.owner = owner; this.is_visible = false; this.Size = this.DefaultSize; + if (owner != null) + SetTopLevel (true); } #endregion // Public Constructors diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/Panel.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/Panel.cs index 343925d616..79fa9b0462 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/Panel.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/Panel.cs @@ -44,6 +44,7 @@ namespace System.Windows.Forms { base.TabStop = false; SetStyle(ControlStyles.Selectable, false); SetStyle (ControlStyles.SupportsTransparentBackColor, true); + can_cache_preferred_size = true; } #endregion // Constructors & Destructors @@ -162,23 +163,11 @@ namespace System.Windows.Forms { #region Internal Methods internal override Size GetPreferredSizeCore (Size proposedSize) { - Size retsize = Size.Empty; - - foreach (Control child in Controls) { - if (child.Dock == DockStyle.Fill) { - if (child.Bounds.Right > retsize.Width) - retsize.Width = child.Bounds.Right; - } else if (child.Dock != DockStyle.Top && child.Dock != DockStyle.Bottom && (child.Anchor & AnchorStyles.Right) == 0 && (child.Bounds.Right + child.Margin.Right) > retsize.Width) - retsize.Width = child.Bounds.Right + child.Margin.Right; - - if (child.Dock == DockStyle.Fill) { - if (child.Bounds.Bottom > retsize.Height) - retsize.Height = child.Bounds.Bottom; - } else if (child.Dock != DockStyle.Left && child.Dock != DockStyle.Right && (child.Anchor & AnchorStyles.Bottom) == 0 && (child.Bounds.Bottom + child.Margin.Bottom) > retsize.Height) - retsize.Height = child.Bounds.Bottom + child.Margin.Bottom; - } - - return retsize; + // Translating 0, 0 from ClientSize to actual Size tells us how much space + // is required for the borders. + Size borderSize = SizeFromClientSize(Size.Empty); + Size totalPadding = borderSize + Padding.Size; + return LayoutEngine.GetPreferredSize(this, proposedSize - totalPadding) + totalPadding; } #endregion } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/PreviewKeyDownEventArgs.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/PreviewKeyDownEventArgs.cs index e16bf9c4c3..261f0b6637 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/PreviewKeyDownEventArgs.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/PreviewKeyDownEventArgs.cs @@ -63,7 +63,7 @@ namespace System.Windows.Forms } public int KeyValue { - get { return Convert.ToInt32 (this.key_data); } + get { return (int) (this.key_data & Keys.KeyCode); } } public Keys Modifiers { diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/PrintPreviewControl.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/PrintPreviewControl.cs index 1118944d0e..a9c3918531 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/PrintPreviewControl.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/PrintPreviewControl.cs @@ -62,8 +62,8 @@ namespace System.Windows.Forms { public PrintPreviewControl() { autozoom = true; columns = 1; - rows = 0; - startPage = 1; + rows = 1; + startPage = 0; this.BackColor = SystemColors.AppWorkspace; @@ -127,15 +127,16 @@ namespace System.Windows.Forms { } [DefaultValue(0)] public int StartPage { - get { return startPage; } - set { - if (value < 1) - return; - if (document != null && value + (Rows + 1) * Columns > page_infos.Length + 1) { - value = page_infos.Length + 1 - (Rows + 1) * Columns; - if (value < 1) - value = 1; + get { + int value = startPage; + if (page_infos != null) { + value = Math.Min (value, page_infos.Length - (rows * columns)); } + return Math.Max (value, 0); + } + set { + if (value < 0) + throw new ArgumentOutOfRangeException ("StartPage"); int start = StartPage; startPage = value; @@ -195,14 +196,17 @@ namespace System.Windows.Forms { if (page_infos.Length > 0) { image_size = ThemeEngine.Current.PrintPreviewControlGetPageSize (this); - if (image_size.Width >= 0 && image_size.Width < page_infos[0].Image.Width - && image_size.Height >= 0 && image_size.Height < page_infos[0].Image.Height) { + // Only resize the pages if they are stored as bitmaps. The print controller + // could internally use scalable metafiles and they should be preserved to + // allow loss-less resizing. + for (int i = 0; i < page_infos.Length; i ++) { + if (page_infos[i].Image is Bitmap + && image_size.Width >= 0 && image_size.Width < page_infos[i].Image.Width + && image_size.Height >= 0 && image_size.Height < page_infos[i].Image.Height) { - for (int i = 0; i < page_infos.Length; i ++) { image_cache[i] = new Bitmap (image_size.Width, image_size.Height); - Graphics g = Graphics.FromImage (image_cache[i]); - g.DrawImage (page_infos[i].Image, new Rectangle (new Point (0, 0), image_size), 0, 0, page_infos[i].Image.Width, page_infos[i].Image.Height, GraphicsUnit.Pixel); - g.Dispose (); + using (Graphics g = Graphics.FromImage (image_cache[i])) + g.DrawImage (page_infos[i].Image, new Rectangle (new Point (0, 0), image_size), 0, 0, page_infos[i].Image.Width, page_infos[i].Image.Height, GraphicsUnit.Pixel); } } } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/RichTextBox.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/RichTextBox.cs index 01edb7e0a1..9073f2c10c 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/RichTextBox.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/RichTextBox.cs @@ -1779,10 +1779,14 @@ namespace System.Windows.Forms { if (rtf_section_stack != null) rtf_section_stack.Clear(); - document.RecalculateDocument(CreateGraphicsInternal(), cursor_y, document.Lines, false); - document.ResumeRecalc (true); - - document.Invalidate (document.GetLine(cursor_y), 0, document.GetLine(document.Lines), -1); + if (IsHandleCreated) { + using (var graphics = CreateGraphics()) + document.RecalculateDocument(graphics, cursor_y, document.Lines, false); + document.ResumeRecalc (true); + document.Invalidate (document.GetLine(cursor_y), 0, document.GetLine(document.Lines), -1); + } else { + document.ResumeRecalc (false); + } } private void RichTextBox_HScrolled(object sender, EventArgs e) { diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/RowStyle.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/RowStyle.cs index 6e033819d3..4895d0aaa6 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/RowStyle.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/RowStyle.cs @@ -61,8 +61,8 @@ namespace System.Windows.Forms if (height != value) { height = value; - if (base.Owner != null) - base.Owner.PerformLayout (); + if (Owner != null) + Owner.PerformLayout (Owner, "Style"); } } } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/ScrollableControl.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/ScrollableControl.cs index 0568593eae..8ead086df3 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/ScrollableControl.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/ScrollableControl.cs @@ -692,6 +692,8 @@ namespace System.Windows.Forms { autosized_child = false; for (int i = 0; i < num_of_children; i++) { child = Controls[i]; + if (!child.VisibleInternal) + continue; if (child.AutoSize) autosized_child = true; if (child.Dock == DockStyle.Right) { @@ -708,6 +710,8 @@ namespace System.Windows.Forms { for (int i = 0; i < num_of_children; i++) { child = Controls[i]; + if (!child.VisibleInternal) + continue; switch(child.Dock) { case DockStyle.Left: { @@ -877,12 +881,12 @@ namespace System.Windows.Forms { SuspendLayout (); - hscrollbar.SetBoundsInternal (hscroll_bounds.X, hscroll_bounds.Y, hscroll_bounds.Width, hscroll_bounds.Height, BoundsSpecified.None); + hscrollbar.SetBounds (hscroll_bounds.X, hscroll_bounds.Y, hscroll_bounds.Width, hscroll_bounds.Height, BoundsSpecified.All); hscrollbar.Visible = hscroll_visible; if (hscrollbar.Visible) XplatUI.SetZOrder (hscrollbar.Handle, IntPtr.Zero, true, false); - vscrollbar.SetBoundsInternal (vscroll_bounds.X, vscroll_bounds.Y, vscroll_bounds.Width, vscroll_bounds.Height, BoundsSpecified.None); + vscrollbar.SetBounds (vscroll_bounds.X, vscroll_bounds.Y, vscroll_bounds.Width, vscroll_bounds.Height, BoundsSpecified.All); vscrollbar.Visible = vscroll_visible; if (vscrollbar.Visible) XplatUI.SetZOrder (vscrollbar.Handle, IntPtr.Zero, true, false); diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/StatusStrip.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/StatusStrip.cs index 3d3d8a51d5..30e641445e 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/StatusStrip.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/StatusStrip.cs @@ -113,7 +113,13 @@ namespace System.Windows.Forms } protected override Padding DefaultPadding { - get { return new Padding (1, 0, 14, 0); } + get { + if (Orientation == Orientation.Horizontal) { + return new Padding (1, 0, 14, 0); + } else { + return new Padding (1, 3, 1, 22); + } + } } protected override bool DefaultShowItemToolTips { @@ -136,7 +142,7 @@ namespace System.Windows.Forms if (text == "-") return new ToolStripSeparator (); - return new ToolStripLabel (text, image, false, onClick); + return new ToolStripStatusLabel (text, image, onClick); } protected override void Dispose (bool disposing) @@ -146,8 +152,9 @@ namespace System.Windows.Forms protected override void OnLayout (LayoutEventArgs levent) { - this.OnSpringTableLayoutCore (); - this.Invalidate (); + if (this.LayoutStyle == ToolStripLayoutStyle.Table) + this.OnSpringTableLayoutCore (); + base.OnLayout (levent); } protected override void OnPaintBackground (PaintEventArgs e) @@ -160,87 +167,45 @@ namespace System.Windows.Forms protected virtual void OnSpringTableLayoutCore () { - if (!this.Created) - return; + this.SuspendLayout (); - ToolStripItemOverflow[] overflow = new ToolStripItemOverflow[this.Items.Count]; - ToolStripItemPlacement[] placement = new ToolStripItemPlacement[this.Items.Count]; - Size proposedSize = new Size (0, Bounds.Height); - int[] widths = new int[this.Items.Count]; - int total_width = 0; - int toolstrip_width = DisplayRectangle.Width; - int i = 0; - int spring_count = 0; + TableLayoutSettings layoutSettings = (TableLayoutSettings) LayoutSettings; + layoutSettings.RowCount = 0; + layoutSettings.ColumnCount = 0; + layoutSettings.ColumnStyles.Clear (); + layoutSettings.RowStyles.Clear (); - foreach (ToolStripItem tsi in this.Items) { - overflow[i] = tsi.Overflow; - widths[i] = tsi.GetPreferredSize (proposedSize).Width + tsi.Margin.Horizontal; - placement[i] = tsi.Overflow == ToolStripItemOverflow.Always ? ToolStripItemPlacement.None : ToolStripItemPlacement.Main; - placement[i] = tsi.Available && tsi.InternalVisible ? placement[i] : ToolStripItemPlacement.None; - total_width += placement[i] == ToolStripItemPlacement.Main ? widths[i] : 0; - if (tsi is ToolStripStatusLabel && (tsi as ToolStripStatusLabel).Spring) - spring_count++; - - i++; - } - - while (total_width > toolstrip_width) { - bool removed_one = false; - - // Start at the right, removing Overflow.AsNeeded first - for (int j = widths.Length - 1; j >= 0; j--) - if (overflow[j] == ToolStripItemOverflow.AsNeeded && placement[j] == ToolStripItemPlacement.Main) { - placement[j] = ToolStripItemPlacement.None; - total_width -= widths[j]; - removed_one = true; - break; - } - - // If we didn't remove any AsNeeded ones, we have to start removing Never ones - // These are not put on the Overflow, they are simply not shown - if (!removed_one) - for (int j = widths.Length - 1; j >= 0; j--) - if (overflow[j] == ToolStripItemOverflow.Never && placement[j] == ToolStripItemPlacement.Main) { - placement[j] = ToolStripItemPlacement.None; - total_width -= widths[j]; - removed_one = true; - break; - } - - // There's nothing left to remove, break or we will loop forever - if (!removed_one) - break; - } - - if (spring_count > 0) { - int per_item = (toolstrip_width - total_width) / spring_count; - i = 0; - + if (Orientation == Orientation.Horizontal) { foreach (ToolStripItem tsi in this.Items) { - if (tsi is ToolStripStatusLabel && (tsi as ToolStripStatusLabel).Spring) - widths[i] += per_item; - - i++; + ColumnStyle style = new ColumnStyle (); + if (tsi is ToolStripStatusLabel status_label && status_label.Spring) { + style.SizeType = SizeType.Percent; + style.Width = 100; + tsi.Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom; + } else { + tsi.Anchor = AnchorStyles.Top | AnchorStyles.Bottom; + } + layoutSettings.ColumnStyles.Add (style); } + layoutSettings.ColumnStyles.Add (new ColumnStyle ()); + layoutSettings.ColumnCount = layoutSettings.ColumnStyles.Count; + } else { + foreach (ToolStripItem tsi in this.Items) { + RowStyle style = new RowStyle (); + if (tsi is ToolStripStatusLabel status_label && status_label.Spring) { + style.SizeType = SizeType.Percent; + style.Height = 100; + tsi.Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom; + } else { + tsi.Anchor = AnchorStyles.Left | AnchorStyles.Right; + } + layoutSettings.RowStyles.Add (style); + } + layoutSettings.RowStyles.Add (new RowStyle ()); + layoutSettings.RowCount = layoutSettings.RowStyles.Count; } - i = 0; - Point layout_pointer = new Point (this.DisplayRectangle.Left, this.DisplayRectangle.Top); - int button_height = this.DisplayRectangle.Height; - - // Now we should know where everything goes, so lay everything out - foreach (ToolStripItem tsi in this.Items) { - tsi.SetPlacement (placement[i]); - - if (placement[i] == ToolStripItemPlacement.Main) { - tsi.SetBounds (new Rectangle (layout_pointer.X + tsi.Margin.Left, layout_pointer.Y + tsi.Margin.Top, widths[i] - tsi.Margin.Horizontal, button_height - tsi.Margin.Vertical)); - layout_pointer.X += widths[i]; - } - - i++; - } - - this.SetDisplayedItems (); + this.ResumeLayout (false); } protected override void SetDisplayedItems () diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/TableLayoutColumnStyleCollection.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/TableLayoutColumnStyleCollection.cs index 4527a23f84..5dc70f0ded 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/TableLayoutColumnStyleCollection.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/TableLayoutColumnStyleCollection.cs @@ -33,7 +33,7 @@ namespace System.Windows.Forms { public class TableLayoutColumnStyleCollection : TableLayoutStyleCollection { - internal TableLayoutColumnStyleCollection (TableLayoutPanel panel) : base (panel) + internal TableLayoutColumnStyleCollection (IArrangedContainer panel) : base (panel, "ColumnStyles") { } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/TableLayoutPanel.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/TableLayoutPanel.cs index 4ba18553c3..b34cc6365f 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/TableLayoutPanel.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/TableLayoutPanel.cs @@ -50,11 +50,10 @@ namespace System.Windows.Forms public class TableLayoutPanel : Panel, IExtenderProvider { private TableLayoutSettings settings; - private static TableLayout layout_engine = new TableLayout (); private TableLayoutPanelCellBorderStyle cell_border_style; // This is the row/column the Control actually got placed - internal Control[,] actual_positions; + internal IArrangedElement[,] actual_positions; // Widths and heights of each column/row internal int[] column_widths; @@ -121,7 +120,7 @@ namespace System.Windows.Forms } public override System.Windows.Forms.Layout.LayoutEngine LayoutEngine { - get { return TableLayoutPanel.layout_engine; } + get { return System.Windows.Forms.Layout.TableLayout.Instance; } } [Browsable (false)] @@ -131,12 +130,11 @@ namespace System.Windows.Forms get { return this.settings; } set { if (value.isSerialized) { + this.settings = new TableLayoutSettings(this, value); // Serialized version doesn't calculate these. - value.ColumnCount = value.ColumnStyles.Count; - value.RowCount = value.RowStyles.Count; - value.panel = this; - - this.settings = value; + this.settings.ColumnCount = value.ColumnStyles.Count; + this.settings.RowCount = value.RowStyles.Count; + this.PerformLayout(); } else throw new NotSupportedException ("LayoutSettings value cannot be set directly."); } @@ -504,263 +502,6 @@ namespace System.Windows.Forms g.DrawLine (ThemeEngine.Current.ResPool.GetPen (BackColor), new Point (3, y + 1), new Point (Right - 4, y + 1)); } } - - internal override Size GetPreferredSizeCore (Size proposedSize) - { - // If the tablelayoutowner is autosize, we have to make sure it is big enough - // to hold every non-autosize control - actual_positions = (LayoutEngine as TableLayout).CalculateControlPositions (this, Math.Max (ColumnCount, 1), Math.Max (RowCount, 1)); - - // Use actual row/column counts, not user set ones - int actual_cols = actual_positions.GetLength (0); - int actual_rows = actual_positions.GetLength (1); - - // Find the largest column-span/row-span values. A table entry that spans more than one - // column (row) should not be treated as though it's width (height) all belongs to the - // first column (row), but should be spread out across all the columns (rows) that are - // spanned. So we need to keep track of the widths (heights) of spans as well as - // individual columns (rows). - int max_colspan = 1, max_rowspan = 1; - foreach (Control c in Controls) - { - max_colspan = Math.Max(max_colspan, GetColumnSpan(c)); - max_rowspan = Math.Max(max_rowspan, GetRowSpan(c)); - } - - // Figure out how wide the owner needs to be - int[] column_widths = new int[actual_cols]; - // Keep track of widths for spans as well as columns. column_span_widths[i,j] stores - // the maximum width for items column i than have a span of j+1 (ie, covers columns - // i through i+j). - int[,] column_span_widths = new int[actual_cols, max_colspan]; - int[] biggest = new int[max_colspan]; - float total_column_percentage = 0f; - - // Figure out how wide each column wants to be - for (int i = 0; i < actual_cols; i++) { - if (i < ColumnStyles.Count && ColumnStyles[i].SizeType == SizeType.Percent) - total_column_percentage += ColumnStyles[i].Width; - int absolute_width = -1; - if (i < ColumnStyles.Count && ColumnStyles[i].SizeType == SizeType.Absolute) - absolute_width = (int)ColumnStyles[i].Width; // use the absolute width if it's absolute! - - for (int s = 0; s < max_colspan; ++s) - biggest[s] = 0; - - for (int j = 0; j < actual_rows; j++) { - Control c = actual_positions[i, j]; - - if (c != null) { - int colspan = GetColumnSpan (c); - if (colspan == 0) - continue; - if (colspan == 1 && absolute_width > -1) - biggest[0] = absolute_width; // use the absolute width if the column has absolute width assigned! - else if (!c.AutoSize) - biggest[colspan-1] = Math.Max (biggest[colspan-1], c.ExplicitBounds.Width + c.Margin.Horizontal + Padding.Horizontal); - else - biggest[colspan-1] = Math.Max (biggest[colspan-1], c.PreferredSize.Width + c.Margin.Horizontal + Padding.Horizontal); - } - else if (absolute_width > -1) { - biggest[0] = absolute_width; - } - } - - for (int s = 0; s < max_colspan; ++s) - column_span_widths[i,s] = biggest[s]; - } - - for (int i = 0; i < actual_cols; ++i) { - for (int s = 1; s < max_colspan; ++s) { - if (column_span_widths[i,s] > 0) - AdjustWidthsForSpans (column_span_widths, i, s); - } - column_widths[i] = column_span_widths[i,0]; - } - - // Because percentage based rows divy up the remaining space, - // we have to make the owner big enough so that all the rows - // get bigger, even if we only need one to be bigger. - int non_percent_total_width = 0; - int percent_total_width = 0; - - for (int i = 0; i < actual_cols; i++) { - if (i < ColumnStyles.Count && ColumnStyles[i].SizeType == SizeType.Percent) - percent_total_width = Math.Max (percent_total_width, (int)(column_widths[i] / ((ColumnStyles[i].Width) / total_column_percentage))); - else - non_percent_total_width += column_widths[i]; - } - - int border_width = GetCellBorderWidth (CellBorderStyle); - int needed_width = non_percent_total_width + percent_total_width + (border_width * (actual_cols + 1)); - - // Figure out how tall the owner needs to be - int[] row_heights = new int[actual_rows]; - int[,] row_span_heights = new int[actual_rows, max_rowspan]; - biggest = new int[max_rowspan]; - float total_row_percentage = 0f; - - // Figure out how tall each row wants to be - for (int j = 0; j < actual_rows; j++) { - if (j < RowStyles.Count && RowStyles[j].SizeType == SizeType.Percent) - total_row_percentage += RowStyles[j].Height; - int absolute_height = -1; - if (j < RowStyles.Count && RowStyles[j].SizeType == SizeType.Absolute) - absolute_height = (int)RowStyles[j].Height; // use the absolute height if it's absolute! - - for (int s = 0; s < max_rowspan; ++s) - biggest[s] = 0; - - for (int i = 0; i < actual_cols; i++) { - Control c = actual_positions[i, j]; - - if (c != null) { - int rowspan = GetRowSpan (c); - if (rowspan == 0) - continue; - if (rowspan == 1 && absolute_height > -1) - biggest[0] = absolute_height; // use the absolute height if the row has absolute height assigned! - else if (!c.AutoSize) - biggest[rowspan-1] = Math.Max (biggest[rowspan-1], c.ExplicitBounds.Height + c.Margin.Vertical + Padding.Vertical); - else - biggest[rowspan-1] = Math.Max (biggest[rowspan-1], c.PreferredSize.Height + c.Margin.Vertical + Padding.Vertical); - } - else if (absolute_height > -1) { - biggest[0] = absolute_height; - } - } - - for (int s = 0; s < max_rowspan; ++s) - row_span_heights[j,s] = biggest[s]; - } - - for (int j = 0; j < actual_rows; ++j) { - for (int s = 1; s < max_rowspan; ++s) { - if (row_span_heights[j,s] > 0) - AdjustHeightsForSpans (row_span_heights, j, s); - } - row_heights[j] = row_span_heights[j,0]; - } - - // Because percentage based rows divy up the remaining space, - // we have to make the owner big enough so that all the rows - // get bigger, even if we only need one to be bigger. - int non_percent_total_height = 0; - int percent_total_height = 0; - - for (int j = 0; j < actual_rows; j++) { - if (j < RowStyles.Count && RowStyles[j].SizeType == SizeType.Percent) - percent_total_height = Math.Max (percent_total_height, (int)(row_heights[j] / ((RowStyles[j].Height) / total_row_percentage))); - else - non_percent_total_height += row_heights[j]; - } - - int needed_height = non_percent_total_height + percent_total_height + (border_width * (actual_rows + 1)); - - return new Size (needed_width, needed_height); - } - - /// - /// Adjust the widths of the columns underlying a span if necessary. - /// - private void AdjustWidthsForSpans (int[,] widths, int col, int span) - { - // Get the combined width of the columns underlying the span. - int existing_width = 0; - for (int i = col; i <= col+span; ++i) - existing_width += widths[i,0]; - if (widths[col,span] > existing_width) - { - // We need to expand one or more of the underlying columns to fit the span, - // preferably ones that are not Absolute style. - int excess = widths[col,span] - existing_width; - int remaining = excess; - List adjusting = new List(); - List adjusting_widths = new List(); - for (int i = col; i <= col+span; ++i) { - if (i < ColumnStyles.Count && ColumnStyles[i].SizeType != SizeType.Absolute) { - adjusting.Add(i); - adjusting_widths.Add((float)widths[i,0]); - } - } - if (adjusting.Count == 0) { - // if every column is Absolute, spread the gain across every column - for (int i = col; i <= col+span; ++i) { - adjusting.Add(i); - adjusting_widths.Add((float)widths[i,0]); - } - } - float original_total = 0f; - foreach (var w in adjusting_widths) - original_total += w; - // Divide up the needed additional width proportionally. - for (int i = 0; i < adjusting.Count; ++i) { - var idx = adjusting[i]; - var percent = adjusting_widths[i] / original_total; - var adjust = (int)(percent * excess); - widths[idx,0] += adjust; - remaining -= adjust; - } - // Any remaining fragment (1 or 2 pixels?) is divided evenly. - while (remaining > 0) { - for (int i = 0; i < adjusting.Count && remaining > 0; ++i) { - ++widths[adjusting[i],0]; - --remaining; - } - } - } - } - - /// - /// Adjust the heights of the rows underlying a span if necessary. - /// - private void AdjustHeightsForSpans (int[,] heights, int row, int span) - { - // Get the combined height of the rows underlying the span. - int existing_height = 0; - for (int i = row; i <= row+span; ++i) - existing_height += heights[i,0]; - if (heights[row,span] > existing_height) - { - // We need to expand one or more of the underlying rows to fit the span, - // preferably ones that are not Absolute style. - int excess = heights[row,span] - existing_height; - int remaining = excess; - List adjusting = new List(); - List adjusting_heights = new List(); - for (int i = row; i <= row+span; ++i) { - if (i < RowStyles.Count && RowStyles[i].SizeType != SizeType.Absolute) { - adjusting.Add(i); - adjusting_heights.Add((float)heights[i,0]); - } - } - if (adjusting.Count == 0) { - // if every row is Absolute, spread the gain across every row - for (int i = row; i <= row+span; ++i) { - adjusting.Add(i); - adjusting_heights.Add((float)heights[i,0]); - } - } - float original_total = 0f; - foreach (var w in adjusting_heights) - original_total += w; - // Divide up the needed additional height proportionally. - for (int i = 0; i < adjusting.Count; ++i) { - var idx = adjusting[i]; - var percent = adjusting_heights[i] / original_total; - var adjust = (int)(percent * excess); - heights[idx,0] += adjust; - remaining -= adjust; - } - // Any remaining fragment (1 or 2 pixels?) is divided evenly. - while (remaining > 0) { - for (int i = 0; i < adjusting.Count && remaining > 0; ++i) { - ++heights[adjusting[i],0]; - --remaining; - } - } - } - } #endregion #region Public Events diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/TableLayoutRowStyleCollection.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/TableLayoutRowStyleCollection.cs index c5b9537432..020f7878e0 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/TableLayoutRowStyleCollection.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/TableLayoutRowStyleCollection.cs @@ -33,7 +33,7 @@ namespace System.Windows.Forms { public class TableLayoutRowStyleCollection : TableLayoutStyleCollection { - internal TableLayoutRowStyleCollection (TableLayoutPanel panel) : base (panel) + internal TableLayoutRowStyleCollection (IArrangedContainer panel) : base (panel, "RowStyles") { } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/TableLayoutSettings.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/TableLayoutSettings.cs index 1fee1ca35f..9ff8e33e47 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/TableLayoutSettings.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/TableLayoutSettings.cs @@ -47,11 +47,11 @@ namespace System.Windows.Forms private Dictionary column_spans; private Dictionary rows; private Dictionary row_spans; - internal TableLayoutPanel panel; + private IArrangedContainer panel; internal bool isSerialized; #region Internal Constructor - internal TableLayoutSettings (TableLayoutPanel panel) + internal TableLayoutSettings (IArrangedContainer panel) { this.column_styles = new TableLayoutColumnStyleCollection (panel); this.row_styles = new TableLayoutRowStyleCollection (panel); @@ -65,6 +65,24 @@ namespace System.Windows.Forms this.panel = panel; } + internal TableLayoutSettings (IArrangedContainer panel, TableLayoutSettings settings) + { + this.column_styles = new TableLayoutColumnStyleCollection (panel); + this.row_styles = new TableLayoutRowStyleCollection (panel); + this.grow_style = settings.grow_style; + this.column_count = settings.column_count; + this.row_count = settings.row_count; + this.columns = new Dictionary (settings.columns); + this.column_spans = new Dictionary (settings.column_spans); + this.rows = new Dictionary (settings.rows); + this.row_spans = new Dictionary (settings.row_spans); + this.panel = panel; + foreach (ColumnStyle column_style in settings.column_styles) + this.column_styles.Add(new ColumnStyle(column_style.SizeType, column_style.Width)); + foreach (RowStyle row_style in settings.row_styles) + this.row_styles.Add(new RowStyle(row_style.SizeType, row_style.Height)); + } + private TableLayoutSettings (SerializationInfo serializationInfo, StreamingContext context) { TypeConverter converter = TypeDescriptor.GetConverter (this); @@ -124,9 +142,7 @@ namespace System.Windows.Forms public override LayoutEngine LayoutEngine { get { - if (panel != null) - return panel.LayoutEngine; - return base.LayoutEngine; + return System.Windows.Forms.Layout.TableLayout.Instance; } } @@ -141,7 +157,7 @@ namespace System.Windows.Forms row_count = value; if (panel != null) - panel.PerformLayout (); + panel.PerformLayout (panel, "Rows"); } } } @@ -248,7 +264,7 @@ namespace System.Windows.Forms rows[control] = cellPosition.Row; if (panel != null) - panel.PerformLayout (); + panel.PerformLayout ((IArrangedElement) control, "TableIndex"); } public void SetColumn (Object control, int column) @@ -261,7 +277,7 @@ namespace System.Windows.Forms columns[control] = column; if (panel != null) - panel.PerformLayout (); + panel.PerformLayout ((IArrangedElement) control, "TableIndex"); } public void SetColumnSpan (Object control, int value) @@ -274,7 +290,7 @@ namespace System.Windows.Forms column_spans[control] = value; if (panel != null) - panel.PerformLayout (); + panel.PerformLayout ((IArrangedElement) control, "ColumnSpan"); } public void SetRow (Object control, int row) @@ -287,7 +303,7 @@ namespace System.Windows.Forms rows[control] = row; if (panel != null) - panel.PerformLayout (); + panel.PerformLayout ((IArrangedElement) control, "TableIndex"); } public void SetRowSpan (Object control, int value) @@ -300,7 +316,7 @@ namespace System.Windows.Forms row_spans[control] = value; if (panel != null) - panel.PerformLayout (); + panel.PerformLayout ((IArrangedElement) control, "RowSpan"); } #endregion diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/TableLayoutStyle.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/TableLayoutStyle.cs index b561fa763e..6ee67be2d6 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/TableLayoutStyle.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/TableLayoutStyle.cs @@ -28,6 +28,7 @@ using System; using System.ComponentModel; +using System.Windows.Forms.Layout; namespace System.Windows.Forms { @@ -35,7 +36,7 @@ namespace System.Windows.Forms public abstract class TableLayoutStyle { private SizeType size_type; - private TableLayoutPanel owner; + private IArrangedContainer owner; protected TableLayoutStyle () { @@ -49,12 +50,12 @@ namespace System.Windows.Forms if (size_type != value) { size_type = value; if (owner != null) - owner.PerformLayout (); + owner.PerformLayout (owner, "Style"); } } } - internal TableLayoutPanel Owner { + internal IArrangedContainer Owner { get { return owner; } set { owner = value; } } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/TableLayoutStyleCollection.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/TableLayoutStyleCollection.cs index df0558da93..36e745e11e 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/TableLayoutStyleCollection.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/TableLayoutStyleCollection.cs @@ -34,11 +34,13 @@ namespace System.Windows.Forms { public abstract class TableLayoutStyleCollection : IList, ICollection, IEnumerable { ArrayList al = new ArrayList (); - TableLayoutPanel table; + IArrangedContainer table; + string property_name; - internal TableLayoutStyleCollection (TableLayoutPanel table) + internal TableLayoutStyleCollection (IArrangedContainer table, string propertyName) { this.table = table; + this.property_name = propertyName; } public int Add (TableLayoutStyle style) @@ -52,7 +54,7 @@ namespace System.Windows.Forms { style.Owner = null; al.Clear (); if (table != null) - table.PerformLayout (); + table.PerformLayout (table, this.property_name); } public int Count { @@ -64,7 +66,7 @@ namespace System.Windows.Forms { ((TableLayoutStyle)al[index]).Owner = null; al.RemoveAt (index); if (table != null) - table.PerformLayout (); + table.PerformLayout (table, this.property_name); } #region IList methods @@ -81,7 +83,7 @@ namespace System.Windows.Forms { int result = al.Add (layoutStyle); if (table != null) - table.PerformLayout (); + table.PerformLayout (table, this.property_name); return result; } @@ -103,7 +105,7 @@ namespace System.Windows.Forms { ((TableLayoutStyle)style).Owner = table; al.Insert (index, (TableLayoutStyle) style); if (table != null) - table.PerformLayout (); + table.PerformLayout (table, this.property_name); } void IList.Remove (object style) @@ -111,7 +113,7 @@ namespace System.Windows.Forms { ((TableLayoutStyle)style).Owner = null; al.Remove ((TableLayoutStyle) style); if (table != null) - table.PerformLayout (); + table.PerformLayout (table, this.property_name); } bool IList.IsFixedSize { @@ -136,7 +138,7 @@ namespace System.Windows.Forms { ((TableLayoutStyle)value).Owner = table; al [index] = value; if (table != null) - table.PerformLayout (); + table.PerformLayout (table, this.property_name); } } #endregion @@ -175,6 +177,5 @@ namespace System.Windows.Forms { ((IList)this)[index] = value; } } - } - + } } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/TextBox.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/TextBox.cs index 0a9a486cff..4cac8fe51f 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/TextBox.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/TextBox.cs @@ -69,12 +69,11 @@ namespace System.Windows.Forms { this.RightToLeftChanged += new EventHandler (TextBox_RightToLeftChanged); MouseWheel += new MouseEventHandler (TextBox_MouseWheel); - BackColor = ThemeEngine.Current.ColorControl; - ForeColor = ThemeEngine.Current.ColorControlText; + BackColor = ThemeEngine.Current.ColorWindow; + ForeColor = ThemeEngine.Current.ColorWindowText; backcolor_set = false; SetStyle (ControlStyles.StandardClick | ControlStyles.StandardDoubleClick, false); - SetStyle (ControlStyles.FixedHeight, true); undo = new MenuItem(Locale.GetText("&Undo")); cut = new MenuItem(Locale.GetText("Cu&t")); @@ -346,7 +345,11 @@ namespace System.Windows.Forms { document.GetLine (i).Alignment = new_alignment; } - document.RecalculateDocument (CreateGraphicsInternal ()); + if (!IsHandleCreated) + return; + + using (var graphics = CreateGraphics()) + document.RecalculateDocument (graphics); Invalidate (); // Make sure we refresh } @@ -791,6 +794,8 @@ namespace System.Windows.Forms { is_visible = false; InternalBorderStyle = BorderStyle.FixedSingle; + + SetTopLevel (true); } protected override CreateParams CreateParams { diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/TextBoxBase.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/TextBoxBase.cs index e3c1a70f5c..7270fdc68f 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/TextBoxBase.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/TextBoxBase.cs @@ -83,7 +83,7 @@ namespace System.Windows.Forms internal int click_point_x; internal int click_point_y; internal CaretSelection click_mode; - internal BorderStyle actual_border_style; + internal BorderStyle actual_border_style = BorderStyle.Fixed3D; internal bool shortcuts_enabled = true; #if Debug internal static bool draw_lines = false; @@ -100,7 +100,6 @@ namespace System.Windows.Forms accepts_tab = false; auto_size = true; InternalBorderStyle = BorderStyle.Fixed3D; - actual_border_style = BorderStyle.Fixed3D; character_casing = CharacterCasing.Normal; hide_selection = true; max_length = short.MaxValue; @@ -151,10 +150,11 @@ namespace System.Windows.Forms this.Controls.AddImplicit (vscroll); ResumeLayout (); - SetStyle(ControlStyles.UserPaint | ControlStyles.StandardClick, false); - SetStyle(ControlStyles.UseTextForAccessibility, false); + SetStyle (ControlStyles.UserPaint | ControlStyles.StandardClick, false); + SetStyle (ControlStyles.UseTextForAccessibility, false); + SetStyle (ControlStyles.FixedHeight, true); - base.SetAutoSizeMode (AutoSizeMode.GrowAndShrink); + //base.SetAutoSizeMode (AutoSizeMode.GrowAndShrink); canvas_width = ClientSize.Width; canvas_height = ClientSize.Height; @@ -162,6 +162,8 @@ namespace System.Windows.Forms document.ViewPortHeight = canvas_height; Cursor = Cursors.IBeam; + + can_cache_preferred_size = true; } #endregion // Internal Constructor @@ -177,7 +179,20 @@ namespace System.Windows.Forms internal override Size GetPreferredSizeCore (Size proposedSize) { - return new Size (Width, Height); + Size bordersAndPadding = SizeFromClientSize(Size.Empty) + Padding.Size; + if (BorderStyle != BorderStyle.None) + bordersAndPadding += new Size(0, 7); + proposedSize -= bordersAndPadding; + + TextFormatFlags format = TextFormatFlags.NoPrefix; + if (!Multiline) + format |= TextFormatFlags.SingleLine; + else if (WordWrap) + format |= TextFormatFlags.WordBreak; + + Size textSize = TextRenderer.MeasureText(this.Text, this.Font, proposedSize, format); + textSize.Height = Math.Max(textSize.Height, FontHeight); + return textSize + bordersAndPadding; } internal override void HandleClick (int clicks, MouseEventArgs me) @@ -431,12 +446,8 @@ namespace System.Windows.Forms if (value != document.multiline) { document.multiline = value; - if (this is TextBox) - SetStyle (ControlStyles.FixedHeight, !value); - - // SetBoundsCore overrides the Height for multiline if it needs to, - // so we don't need to worry about it here. - SetBoundsCore (Left, Top, Width, ExplicitBounds.Height, BoundsSpecified.None); + SetStyle (ControlStyles.FixedHeight, !value); + FixupHeight (); if (Parent != null) Parent.PerformLayout (); @@ -458,8 +469,7 @@ namespace System.Windows.Forms } } - if (IsHandleCreated) - CalculateDocument (); + CalculateDocument (); } } @@ -469,13 +479,11 @@ namespace System.Windows.Forms // This returns the preferred outer height, not the client height. public int PreferredHeight { get { - int clientDelta = Height - ClientSize.Height; - if (BorderStyle != BorderStyle.None) - return Font.Height + 7 + clientDelta; - - // usually in borderless mode the top margin is 0, but - // try to access it, in case it was set manually, as ToolStrip* controls do - return Font.Height + TopMargin + clientDelta; + int height = FontHeight; + if (BorderStyle != BorderStyle.None) { + height += 7; + } + return height; } } @@ -702,7 +710,7 @@ namespace System.Windows.Forms protected override System.Drawing.Size DefaultSize { get { - return new Size(100, 20); + return new Size(100, PreferredHeight); } } @@ -969,7 +977,8 @@ namespace System.Windows.Forms case Keys.PageUp: case Keys.PageDown: case Keys.Home: - case Keys.End: { + case Keys.End: + case Keys.Back: { return true; } } @@ -993,12 +1002,7 @@ namespace System.Windows.Forms protected override void OnFontChanged (EventArgs e) { base.OnFontChanged (e); - - if (auto_size && !document.multiline) { - if (PreferredHeight != Height) { - Height = PreferredHeight; - } - } + FixupHeight (); } protected override void OnHandleCreated (EventArgs e) @@ -1719,7 +1723,7 @@ namespace System.Windows.Forms internal int TopMargin { get { - return document.top_margin; + return document == null ? 0 : document.top_margin; } set { document.top_margin = value; @@ -1738,14 +1742,6 @@ namespace System.Windows.Forms #endregion UIA Framework Properties - internal Graphics CreateGraphicsInternal () - { - if (IsHandleCreated) - return base.CreateGraphics(); - - return DeviceContext; - } - internal override void OnPaintInternal (PaintEventArgs pevent) { Draw (pevent.Graphics, pevent.ClipRectangle); @@ -1769,8 +1765,10 @@ namespace System.Windows.Forms if (!richtext) { if (!document.multiline) { if (PreferredHeight != Height) { - Height = PreferredHeight; + SetBoundsCore (Left, Top, Width, PreferredHeight, BoundsSpecified.None); } + } else { + SetBoundsCore (Left, Top, Width, Math.Max(PreferredHeight, ExplicitBounds.Height), BoundsSpecified.None); } } } @@ -1959,14 +1957,12 @@ namespace System.Windows.Forms private void TextBoxBase_SizeChanged (object sender, EventArgs e) { - if (IsHandleCreated) - CalculateDocument (); + CalculateDocument (); } private void TextBoxBase_RightToLeftChanged (object o, EventArgs e) { - if (IsHandleCreated) - CalculateDocument (); + CalculateDocument (); } private void TextBoxBase_MouseWheel (object sender, MouseEventArgs e) @@ -2027,9 +2023,12 @@ namespace System.Windows.Forms internal void CalculateDocument() { - CalculateScrollBars (); - document.RecalculateDocument (CreateGraphicsInternal ()); + if (!IsHandleCreated) + return; + CalculateScrollBars (); + using (var graphics = CreateGraphics()) + document.RecalculateDocument (graphics); if (document.caret.line != null && document.caret.line.Y < document.ViewPortHeight) { // The window has probably been resized, making the entire thing visible, so @@ -2239,13 +2238,18 @@ namespace System.Windows.Forms { Line line; + if (!IsHandleCreated) + return; + document.SuspendRecalc (); // Font changes apply to the whole document for (int i = 1; i <= document.Lines; i++) { line = document.GetLine(i); if (LineTag.FormatText(line, 1, line.text.Length, Font, ForeColor, - Color.Empty, FormatSpecified.Font | FormatSpecified.Color)) - document.RecalculateDocument (CreateGraphicsInternal (), line.LineNo, line.LineNo, false); + Color.Empty, FormatSpecified.Font | FormatSpecified.Color)) { + using (var graphics = CreateGraphics()) + document.RecalculateDocument (graphics, line.LineNo, line.LineNo, false); + } } document.ResumeRecalc (false); diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/TextControl.cs.REMOVED.git-id b/mcs/class/System.Windows.Forms/System.Windows.Forms/TextControl.cs.REMOVED.git-id index eccead436f..abc6834f93 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/TextControl.cs.REMOVED.git-id +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/TextControl.cs.REMOVED.git-id @@ -1 +1 @@ -0452c2c6fa30f98c9ddc59221d008d5d545a805f \ No newline at end of file +24859dbf3fb500cd8b45e0af3aeca79ebb6a1f29 \ No newline at end of file diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/ThemeEngine.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/ThemeEngine.cs index f3b482d64b..41f58ff75e 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/ThemeEngine.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/ThemeEngine.cs @@ -35,16 +35,6 @@ namespace System.Windows.Forms static ThemeEngine () { - string theme_var; - - theme_var = Environment.GetEnvironmentVariable("MONO_THEME"); - - if (theme_var == null) { - theme_var = "win32"; - } else { - theme_var = theme_var.ToLower (); - } - if (Application.VisualStylesEnabled) { theme = new ThemeVisualStyles (); } else { diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/ThemeVisualStyles.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/ThemeVisualStyles.cs index 72034979fd..424e91d650 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/ThemeVisualStyles.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/ThemeVisualStyles.cs @@ -35,7 +35,7 @@ namespace System.Windows.Forms /// /// /// This theme uses only the managed VisualStyles API. - /// To select it, set MONO_THEME to VisualStyles and call . + /// To select it, call . /// class ThemeVisualStyles : ThemeWin32Classic { @@ -680,9 +680,9 @@ namespace System.Windows.Forms VisualStyleElement element = VisualStyleElement.DatePicker.DateBorder.Normal; if (!VisualStyleRenderer.IsElementDefined (element)) return base.DateTimePickerGetDateArea (dateTimePicker); - Graphics g = dateTimePicker.CreateGraphics (); - Rectangle result = new VisualStyleRenderer (element).GetBackgroundContentRectangle (g, dateTimePicker.ClientRectangle); - g.Dispose (); + Rectangle result; + using (Graphics g = dateTimePicker.CreateGraphics ()) + result = new VisualStyleRenderer (element).GetBackgroundContentRectangle (g, dateTimePicker.ClientRectangle); result.Width -= DateTimePickerDropDownWidthOnWindowsVista; return result; } @@ -747,17 +747,15 @@ namespace System.Windows.Forms VisualStyleElement element = VisualStyleElement.Header.Item.Normal; if (!VisualStyleRenderer.IsElementDefined (element)) return base.ListViewGetHeaderHeight (listView, font); - Control control = null; - Graphics g; + int result; if (listView == null) { - control = new Control (); - g = control.CreateGraphics (); - } else - g = listView.CreateGraphics (); - int result = new VisualStyleRenderer (element).GetPartSize (g, ThemeSizeType.True).Height; - g.Dispose (); - if (listView == null) - control.Dispose (); + using (Control control = new Control ()) + using (Graphics g = control.CreateGraphics ()) + result = new VisualStyleRenderer (element).GetPartSize (g, ThemeSizeType.True).Height; + } else { + using (Graphics g = listView.CreateGraphics ()) + result = new VisualStyleRenderer (element).GetPartSize (g, ThemeSizeType.True).Height; + } return result; } #endregion @@ -1544,7 +1542,7 @@ namespace System.Windows.Forms new Rectangle (new Point ((textBoxBase.Width - textBoxBase.ClientSize.Width) / 2, (textBoxBase.Height - textBoxBase.ClientSize.Height) / 2), textBoxBase.ClientSize)); - XplatUI.PaintEventEnd (ref m, textBoxBase.Handle, false); + XplatUI.PaintEventEnd (ref m, textBoxBase.Handle, false, e); return true; } public override bool TextBoxBaseShouldPaintBackground (TextBoxBase textBoxBase) @@ -1753,9 +1751,9 @@ namespace System.Windows.Forms VisualStyleElement element = TrackBarGetThumbVisualStyleElement (trackBar); if (!VisualStyleRenderer.IsElementDefined (element)) return base.TrackBarGetThumbSize (trackBar); - Graphics g = trackBar.CreateGraphics (); - Size result = new VisualStyleRenderer (element).GetPartSize (g, ThemeSizeType.True); - g.Dispose (); + Size result; + using (Graphics g = trackBar.CreateGraphics ()) + result = new VisualStyleRenderer (element).GetPartSize (g, ThemeSizeType.True); return trackBar.Orientation == Orientation.Horizontal ? result : TrackBarRotateVerticalThumbSize (result); } static VisualStyleElement TrackBarGetThumbVisualStyleElement (TrackBar trackBar) diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/ThemeWin32Classic.cs.REMOVED.git-id b/mcs/class/System.Windows.Forms/System.Windows.Forms/ThemeWin32Classic.cs.REMOVED.git-id index bf8df94fc1..074d1ee957 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/ThemeWin32Classic.cs.REMOVED.git-id +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/ThemeWin32Classic.cs.REMOVED.git-id @@ -1 +1 @@ -b60c42b346611dc2e9d9b68824662ca4cb5f0d9f \ No newline at end of file +63320f8d8b7e2390d21a00b0d924b79927ce507f \ No newline at end of file diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStrip.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStrip.cs index 0c505ead94..59a289ef42 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStrip.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStrip.cs @@ -42,7 +42,7 @@ namespace System.Windows.Forms [DefaultProperty ("Items")] [Designer ("System.Windows.Forms.Design.ToolStripDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")] [DesignerSerializer ("System.Windows.Forms.Design.ToolStripCodeDomSerializer, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.Serialization.CodeDomSerializer, " + Consts.AssemblySystem_Design)] - public class ToolStrip : ScrollableControl, IComponent, IDisposable, IToolStripData + public class ToolStrip : ScrollableControl, IComponent, IDisposable, IToolStripData, IArrangedContainer { #region Private Variables private bool allow_item_reorder; @@ -108,7 +108,7 @@ namespace System.Windows.Forms this.default_drop_down_direction = ToolStripDropDownDirection.BelowRight; this.displayed_items = new ToolStripItemCollection (this, null, true); this.Dock = this.DefaultDock; - base.Font = new Font ("Tahoma", 8.25f); + base.Font = ToolStripManager.DefaultFont; this.fore_color = Control.DefaultForeColor; this.grip_margin = this.DefaultGripMargin; this.grip_style = ToolStripGripStyle.Visible; @@ -122,7 +122,7 @@ namespace System.Windows.Forms this.show_item_tool_tips = this.DefaultShowItemToolTips; base.TabStop = false; this.text_direction = ToolStripTextDirection.Horizontal; - this.ResumeLayout (); + this.ResumeLayout (false); // Register with the ToolStripManager ToolStripManager.AddToolStrip (this); @@ -425,7 +425,9 @@ namespace System.Windows.Forms this.layout_style = value; if (this.layout_style == ToolStripLayoutStyle.Flow) - this.layout_engine = new FlowLayout (); + this.layout_engine = FlowLayout.Instance; + else if (this.layout_style == ToolStripLayoutStyle.Table) + this.layout_engine = TableLayout.Instance; else this.layout_engine = new ToolStripSplitStackLayout (); @@ -714,7 +716,7 @@ namespace System.Windows.Forms case ToolStripLayoutStyle.Flow: return new FlowLayoutSettings (this); case ToolStripLayoutStyle.Table: - //return new TableLayoutSettings (); + return new TableLayoutSettings (this); case ToolStripLayoutStyle.StackWithOverflow: case ToolStripLayoutStyle.HorizontalStackWithOverflow: case ToolStripLayoutStyle.VerticalStackWithOverflow: @@ -840,7 +842,6 @@ namespace System.Windows.Forms protected override void OnLayout (LayoutEventArgs e) { base.OnLayout (e); - this.SetDisplayedItems (); this.OnLayoutCompleted (EventArgs.Empty); this.Invalidate (); @@ -1412,80 +1413,7 @@ namespace System.Windows.Forms internal override Size GetPreferredSizeCore (Size proposedSize) { - return GetToolStripPreferredSize (proposedSize); - } - - internal virtual Size GetToolStripPreferredSize (Size proposedSize) - { - Size new_size = Size.Empty; - - // TODO: This is total duct tape. We really have to call into the correct - // layout engine, do a dry run of the layout, and find out our true - // preferred dimensions. - if (this.LayoutStyle == ToolStripLayoutStyle.Flow) { - Point currentLocation = Point.Empty; - int tallest = 0; - - foreach (ToolStripItem tsi in items) - if (tsi.Available) { - Size tsi_preferred = tsi.GetPreferredSize (Size.Empty); - - if ((DisplayRectangle.Width - currentLocation.X) < (tsi_preferred.Width + tsi.Margin.Horizontal)) { - - currentLocation.Y += tallest; - tallest = 0; - - currentLocation.X = DisplayRectangle.Left; - } - - // Offset the left margin and set the control to our point - currentLocation.Offset (tsi.Margin.Left, 0); - tallest = Math.Max (tallest, tsi_preferred.Height + tsi.Margin.Vertical); - - // Update our location pointer - currentLocation.X += tsi_preferred.Width + tsi.Margin.Right; - } - - currentLocation.Y += tallest; - return new Size (currentLocation.X + this.Padding.Horizontal, currentLocation.Y + this.Padding.Vertical); - } - - if (this.orientation == Orientation.Vertical) { - foreach (ToolStripItem tsi in this.items) - if (tsi.Available) { - Size tsi_preferred = tsi.GetPreferredSize (Size.Empty); - new_size.Height += tsi_preferred.Height + tsi.Margin.Top + tsi.Margin.Bottom; - - if (new_size.Width < (this.Padding.Horizontal + tsi_preferred.Width + tsi.Margin.Horizontal)) - new_size.Width = (this.Padding.Horizontal + tsi_preferred.Width + tsi.Margin.Horizontal); - } - - new_size.Height += (this.GripRectangle.Height + this.GripMargin.Vertical + this.Padding.Vertical + 4); - - if (new_size.Width == 0) - new_size.Width = ExplicitBounds.Width; - - return new_size; - } else { - foreach (ToolStripItem tsi in this.items) - if (tsi.Available) { - Size tsi_preferred = tsi.GetPreferredSize (Size.Empty); - new_size.Width += tsi_preferred.Width + tsi.Margin.Left + tsi.Margin.Right; - - if (new_size.Height < (this.Padding.Vertical + tsi_preferred.Height + tsi.Margin.Vertical)) - new_size.Height = (this.Padding.Vertical + tsi_preferred.Height + tsi.Margin.Vertical); - } - - new_size.Width += (this.GripRectangle.Width + this.GripMargin.Horizontal + this.Padding.Horizontal + 4); - - if (new_size.Height == 0) - new_size.Height = ExplicitBounds.Height; - - if (this is StatusStrip) - new_size.Height = Math.Max (new_size.Height, 22); - - return new_size; - } + return LayoutEngine.GetPreferredSize (this, proposedSize - Padding.Size) + Padding.Size; } internal virtual ToolStrip GetTopLevelToolStrip () @@ -1593,6 +1521,10 @@ namespace System.Windows.Forms return next_item; } + ArrangedElementCollection IArrangedContainer.Controls { + get { return Items; } + } + #region Stuff for ToolTips private void MouseEnteredItem (ToolStripItem item) { diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripDropDown.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripDropDown.cs index f47ca8a835..33eb3c50b9 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripDropDown.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripDropDown.cs @@ -50,11 +50,17 @@ namespace System.Windows.Forms SetStyle (ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true); SetStyle (ControlStyles.ResizeRedraw, true); + SetTopLevel (true); + + SuspendLayout (); + this.LayoutStyle = ToolStripLayoutStyle.Flow; this.auto_close = true; is_visible = false; this.DefaultDropDownDirection = ToolStripDropDownDirection.Right; this.GripStyle = ToolStripGripStyle.Hidden; this.is_toplevel = true; + this.AutoSize = true; + ResumeLayout (false); } #endregion @@ -548,7 +554,11 @@ namespace System.Windows.Forms protected override LayoutSettings CreateLayoutSettings (ToolStripLayoutStyle style) { - return base.CreateLayoutSettings (style); + LayoutSettings layout_settings = base.CreateLayoutSettings (style); + if (style == ToolStripLayoutStyle.Flow) { + ((FlowLayoutSettings)layout_settings).FlowDirection = FlowDirection.TopDown; + } + return layout_settings; } protected override void Dispose (bool disposing) @@ -585,49 +595,9 @@ namespace System.Windows.Forms protected override void OnLayout (LayoutEventArgs e) { - // Find the widest menu item, so we know how wide to make our dropdown - int widest = 0; - - foreach (ToolStripItem tsi in this.Items) { - if (!tsi.Available) - continue; - - tsi.SetPlacement (ToolStripItemPlacement.Main); - - widest = Math.Max (widest, tsi.GetPreferredSize (Size.Empty).Width + tsi.Margin.Horizontal); - } - - // Add any padding our dropdown has set - widest += this.Padding.Horizontal; - - int x = this.Padding.Left; - int y = this.Padding.Top; - - foreach (ToolStripItem tsi in this.Items) { - if (!tsi.Available) - continue; - - y += tsi.Margin.Top; - - int height = 0; - - Size preferred_size = tsi.GetPreferredSize (Size.Empty); - - if (preferred_size.Height > 22) - height = preferred_size.Height; - else if (tsi is ToolStripSeparator) - height = 7; - else - height = 22; - - tsi.SetBounds (new Rectangle (x, y, preferred_size.Width, height)); - y += height + tsi.Margin.Bottom; - } - - this.Size = new Size (widest, y + this.Padding.Bottom); - this.SetDisplayedItems (); - this.OnLayoutCompleted (EventArgs.Empty); - this.Invalidate (); + if (AutoSize) + this.Size = GetPreferredSize (Size.Empty); + base.OnLayout (e); } protected override void OnMouseUp (MouseEventArgs mea) diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripDropDownItem.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripDropDownItem.cs index 4b429c9dae..3160e6ac08 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripDropDownItem.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripDropDownItem.cs @@ -58,6 +58,7 @@ namespace System.Windows.Forms protected ToolStripDropDownItem (string text, Image image, EventHandler onClick, string name) : base (text, image, onClick, name) { + this.drop_down_direction = ToolStripDropDownDirection.Default; } #endregion @@ -80,7 +81,11 @@ namespace System.Windows.Forms [Browsable (false)] public ToolStripDropDownDirection DropDownDirection { - get { return this.drop_down_direction; } + get { + if (this.drop_down_direction == ToolStripDropDownDirection.Default && Parent != null) + return Parent.DefaultDropDownDirection; + return this.drop_down_direction; + } set { if (!Enum.IsDefined (typeof (ToolStripDropDownDirection), value)) throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ToolStripDropDownDirection", value)); @@ -111,13 +116,10 @@ namespace System.Windows.Forms get { Point p; - if (this.IsOnDropDown) { - p = Parent.PointToScreen (new Point (this.Bounds.Left, this.Bounds.Top - 1)); - p.X += this.Bounds.Width; - p.Y += this.Bounds.Left; - return p; + if (DropDownDirection == ToolStripDropDownDirection.Right) { + p = new Point (this.Bounds.Left + this.Bounds.Width - 1, this.Bounds.Top); } - else + else // TODO: Other directions; p = new Point (this.Bounds.Left, this.Bounds.Bottom - 1); return Parent.PointToScreen (p); diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripDropDownMenu.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripDropDownMenu.cs index d2ef6821f8..07da50a3fd 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripDropDownMenu.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripDropDownMenu.cs @@ -38,14 +38,13 @@ namespace System.Windows.Forms [Designer ("System.Windows.Forms.Design.ToolStripDropDownDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")] public class ToolStripDropDownMenu : ToolStripDropDown { - private ToolStripLayoutStyle layout_style; private bool show_check_margin; private bool show_image_margin; #region Public Constructors public ToolStripDropDownMenu () : base () { - this.layout_style = ToolStripLayoutStyle.Flow; + base.LayoutStyle = ToolStripLayoutStyle.Flow; this.show_image_margin = true; } #endregion @@ -61,8 +60,8 @@ namespace System.Windows.Forms [DefaultValue (ToolStripLayoutStyle.Flow)] public new ToolStripLayoutStyle LayoutStyle { - get { return this.layout_style; } - set { this.layout_style = value; } + get { return base.LayoutStyle; } + set { base.LayoutStyle = value; } } [DefaultValue (false)] @@ -96,6 +95,7 @@ namespace System.Windows.Forms protected internal override Size MaxItemSize { get { return Size; } } + #endregion #region Protected Methods diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripItem.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripItem.cs index d2d2e62cc7..e8a3736f14 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripItem.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripItem.cs @@ -31,6 +31,7 @@ using System; using System.Drawing; using System.ComponentModel; using System.Runtime.InteropServices; +using System.Windows.Forms.Layout; namespace System.Windows.Forms { @@ -39,7 +40,7 @@ namespace System.Windows.Forms [DesignTimeVisible (false)] [ToolboxItem (false)] [Designer ("System.Windows.Forms.Design.ToolStripItemDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")] - public abstract class ToolStripItem : Component, IDropTarget, IComponent, IDisposable + public abstract class ToolStripItem : Component, IDropTarget, IComponent, IDisposable, IArrangedElement { #region Private Variables private AccessibleObject accessibility_object; @@ -411,7 +412,7 @@ namespace System.Windows.Forms if (Parent != null) return Parent.Font; - return DefaultFont; + return ToolStripManager.DefaultFont; } set { if (this.font != value) { @@ -569,9 +570,10 @@ namespace System.Windows.Forms [Browsable (false)] public bool IsOnDropDown { get { - if (this.parent != null && this.parent is ToolStripDropDown) - return true; - + if (this.parent != null) + return this.parent is ToolStripDropDown; + if (this.owner != null) + return this.owner is ToolStripDropDown; return false; } } @@ -1282,8 +1284,11 @@ namespace System.Windows.Forms protected internal virtual void SetBounds (Rectangle bounds) { if (this.bounds != bounds) { + Point old_location = bounds.Location; this.bounds = bounds; OnBoundsChanged (); + if (old_location != bounds.Location) + OnLocationChanged (EventArgs.Empty); } } @@ -1657,8 +1662,6 @@ namespace System.Windows.Forms } } - private static Font DefaultFont { get { return new Font ("Tahoma", 8.25f); } } - internal virtual ToolStripTextDirection DefaultTextDirection { get { return ToolStripTextDirection.Inherit; } } internal virtual void Dismiss (ToolStripDropDownCloseReason reason) @@ -1880,7 +1883,7 @@ namespace System.Windows.Forms return true; if (!(this.Owner is ToolStripDropDownMenu)) - return false; + return true; ToolStripDropDownMenu tsddm = (ToolStripDropDownMenu)this.Owner; @@ -1936,6 +1939,47 @@ namespace System.Windows.Forms internal int Right { get { return this.bounds.Right; } } internal int Bottom { get { return this.bounds.Bottom; } } + + bool IArrangedElement.Visible { + get { return InternalVisible; } + } + + Rectangle IArrangedElement.DisplayRectangle { + get { return this.Bounds; } + } + + int IArrangedElement.DistanceRight { + get { throw new NotSupportedException(); } + set { throw new NotSupportedException(); } + } + + int IArrangedElement.DistanceBottom { + get { throw new NotSupportedException(); } + set { throw new NotSupportedException(); } + } + + AutoSizeMode IArrangedElement.GetAutoSizeMode () + { + return AutoSizeMode.GrowAndShrink; + } + + Rectangle IArrangedElement.ExplicitBounds { + get { return this.bounds; } + } + + Size IArrangedElement.MinimumSize { + get { return Size.Empty; } + } + + void IArrangedElement.SetBounds (int left, int top, int width, int height, BoundsSpecified specified) + { + SetBounds (new Rectangle (left, top, width, height)); + } + + IArrangedContainer IArrangedElement.Parent { + get { return this.Parent ?? this.Owner; } + } + #endregion #region IDropTarget Members diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripManager.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripManager.cs index 1ef4f318eb..0c9685e252 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripManager.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripManager.cs @@ -349,21 +349,27 @@ namespace System.Windows.Forms public static bool RevertMerge (string targetName) { + if (targetName == null) + return false; + return RevertMerge (FindToolStrip (targetName)); } public static bool RevertMerge (ToolStrip targetToolStrip) { if (targetToolStrip == null) - return false; + throw new ArgumentNullException ("targetToolStrip"); return RevertMerge (targetToolStrip, targetToolStrip.CurrentlyMergedWith); } public static bool RevertMerge (ToolStrip targetToolStrip, ToolStrip sourceToolStrip) { + if (targetToolStrip == null) + throw new ArgumentNullException ("targetToolStrip"); + if (sourceToolStrip == null) - return false; + throw new ArgumentNullException ("sourceToolStrip"); List items_to_move = new List (); @@ -430,6 +436,11 @@ namespace System.Windows.Forms #endregion #region Private/Internal Methods + + internal static Font DefaultFont { + get { return SystemFonts.MessageBoxFont; } + } + internal static bool ActivatedByKeyboard { get { return activated_by_keyboard; } set { activated_by_keyboard = value; } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripOverflow.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripOverflow.cs index 6c8f6f3158..66d778b79a 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripOverflow.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripOverflow.cs @@ -36,10 +36,8 @@ namespace System.Windows.Forms { [ComVisible (true)] [ClassInterface (ClassInterfaceType.AutoDispatch)] - public class ToolStripOverflow : ToolStripDropDown, IComponent, IDisposable + public class ToolStripOverflow : ToolStripDropDown, IComponent, IDisposable, IArrangedContainer { - private LayoutEngine layout_engine; - #region Public Constructors public ToolStripOverflow (ToolStripItem parentItem) { @@ -52,15 +50,6 @@ namespace System.Windows.Forms public override ToolStripItemCollection Items { get { return base.Items; } } - - public override LayoutEngine LayoutEngine { - get { - if (this.layout_engine == null) - this.layout_engine = new FlowLayout (); - - return base.LayoutEngine; - } - } #endregion #region Protected Properties @@ -72,7 +61,8 @@ namespace System.Windows.Forms #region Public Methods public override Size GetPreferredSize (Size constrainingSize) { - return base.GetToolStripPreferredSize (constrainingSize); + constrainingSize.Width = 200; + return base.GetPreferredSize (constrainingSize); } #endregion @@ -81,46 +71,16 @@ namespace System.Windows.Forms { return new ToolStripOverflowAccessibleObject (); } - - [MonoInternalNote ("This should stack in rows of ~3, but for now 1 column will work.")] - protected override void OnLayout (LayoutEventArgs e) - { - SetDisplayedItems (); - - // Find the widest menu item - int widest = 0; - foreach (ToolStripItem tsi in this.DisplayedItems) { - if (!tsi.Available) - continue; - if (tsi.GetPreferredSize (Size.Empty).Width > widest) - widest = tsi.GetPreferredSize (Size.Empty).Width; + protected override LayoutSettings CreateLayoutSettings(ToolStripLayoutStyle style) { + LayoutSettings layout_settings = base.CreateLayoutSettings (style); + if (style == ToolStripLayoutStyle.Flow) { + ((FlowLayoutSettings)layout_settings).FlowDirection = FlowDirection.LeftToRight; + ((FlowLayoutSettings)layout_settings).WrapContents = true; } - - int x = this.Padding.Left; - widest += this.Padding.Horizontal; - int y = this.Padding.Top; - - foreach (ToolStripItem tsi in this.DisplayedItems) { - if (!tsi.Available) - continue; - - y += tsi.Margin.Top; - - int height = 0; - - if (tsi is ToolStripSeparator) - height = 7; - else - height = tsi.GetPreferredSize (Size.Empty).Height; - - tsi.SetBounds (new Rectangle (x, y, widest, height)); - y += tsi.Height + tsi.Margin.Bottom; - } - - this.Size = new Size (widest + this.Padding.Horizontal, y + this.Padding.Bottom);// + 2); + return layout_settings; } - + protected override void SetDisplayedItems () { this.displayed_items.ClearInternal (); @@ -140,6 +100,11 @@ namespace System.Windows.Forms internal ToolStrip ParentToolStrip { get { return (ToolStrip)this.OwnerItem.Parent; } } + + ArrangedElementCollection IArrangedContainer.Controls { + get { return DisplayedItems; } + } + #endregion #region ToolStripOverflowAccessibleObject Class diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripPanel.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripPanel.cs index 80ed816461..176554cbf4 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripPanel.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripPanel.cs @@ -42,7 +42,6 @@ namespace System.Windows.Forms public class ToolStripPanel : ContainerControl, IComponent, IDisposable, IBindableComponent, IDropTarget { private bool done_first_layout; - private LayoutEngine layout_engine; private bool locked; private Orientation orientation; private ToolStripRenderer renderer; @@ -121,10 +120,7 @@ namespace System.Windows.Forms public override LayoutEngine LayoutEngine { get { - if (this.layout_engine == null) - this.layout_engine = new FlowLayout (); - - return this.layout_engine; + return System.Windows.Forms.Layout.FlowLayout.Instance; } } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripPanelRow.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripPanelRow.cs index daa1b2a25c..ab3f1b56e2 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripPanelRow.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripPanelRow.cs @@ -35,11 +35,10 @@ using System.Collections.Generic; namespace System.Windows.Forms { [ToolboxItem (false)] - public class ToolStripPanelRow : Component, IComponent, IDisposable, IBounds + public class ToolStripPanelRow : Component, IComponent, IDisposable { private Rectangle bounds; internal List controls; - private LayoutEngine layout_engine; private Padding margin; private Padding padding; private ToolStripPanel parent; @@ -49,7 +48,6 @@ namespace System.Windows.Forms { this.bounds = Rectangle.Empty; this.controls = new List (); - this.layout_engine = new DefaultLayout (); this.parent = parent; } #endregion @@ -71,10 +69,7 @@ namespace System.Windows.Forms public LayoutEngine LayoutEngine { get { - if (this.layout_engine == null) - this.layout_engine = new DefaultLayout (); - - return this.layout_engine; + return DefaultLayout.Instance; } } @@ -195,7 +190,7 @@ namespace System.Windows.Forms if (ts.Stretch) ts.Width = this.bounds.Width - ts.Margin.Horizontal - this.Padding.Horizontal; else - ts.Width = ts.GetToolStripPreferredSize (Size.Empty).Width; + ts.Width = ts.GetPreferredSize (Size.Empty).Width; position.X += ts.Margin.Left; ts.Location = position; @@ -203,9 +198,9 @@ namespace System.Windows.Forms position.X += (ts.Width + ts.Margin.Left); } else { if (ts.Stretch) - ts.Size = new Size (ts.GetToolStripPreferredSize (Size.Empty).Width, this.bounds.Height - ts.Margin.Vertical - this.Padding.Vertical); + ts.Size = new Size (ts.GetPreferredSize (Size.Empty).Width, this.bounds.Height - ts.Margin.Vertical - this.Padding.Vertical); else - ts.Size = ts.GetToolStripPreferredSize (Size.Empty); + ts.Size = ts.GetPreferredSize (Size.Empty); position.Y += ts.Margin.Top; ts.Location = position; diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripSplitStackLayout.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripSplitStackLayout.cs index 1f997ba9bd..b1871cb079 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripSplitStackLayout.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripSplitStackLayout.cs @@ -53,7 +53,7 @@ namespace System.Windows.Forms else LayoutVerticalToolStrip (ts, ts_rect); - return false; + return ts.AutoSize; } else { ToolStripContentPanel ts = (ToolStripContentPanel)container; int x = ts.DisplayRectangle.Left; @@ -66,15 +66,15 @@ namespace System.Windows.Forms new_bounds.Location = new Point (x, y + tsi.Margin.Top); new_bounds.Height = ts.DisplayRectangle.Height - tsi.Margin.Vertical; - new_bounds.Width = tsi.GetToolStripPreferredSize (new Size (0, new_bounds.Height)).Width; + new_bounds.Width = tsi.GetPreferredSize (new Size (0, new_bounds.Height)).Width; tsi.Width = new_bounds.Width + 12; x += new_bounds.Width + tsi.Margin.Right; } - } - return false; + return ts.AutoSize; + } } private void LayoutHorizontalToolStrip (ToolStrip ts, Rectangle bounds) @@ -260,5 +260,43 @@ namespace System.Windows.Forms i++; } } + + internal override Size GetPreferredSize(object container, Size proposedSize) { + ToolStrip ts = (ToolStrip) container; + Size new_size = Size.Empty; + + if (ts.Orientation == Orientation.Vertical) { + foreach (ToolStripItem tsi in ts.Items) + if (tsi.Available) { + Size tsi_preferred = tsi.GetPreferredSize (Size.Empty); + new_size.Height += tsi_preferred.Height + tsi.Margin.Top + tsi.Margin.Bottom; + new_size.Width = Math.Max (new_size.Width, tsi_preferred.Width + tsi.Margin.Horizontal); + } + + new_size.Height += (ts.GripRectangle.Height + ts.GripMargin.Vertical + 4); + + if (new_size.Width == 0) + new_size.Width = ts.ExplicitBounds.Width; + + return new_size; + } else { + foreach (ToolStripItem tsi in ts.Items) + if (tsi.Available) { + Size tsi_preferred = tsi.GetPreferredSize (Size.Empty); + new_size.Width += tsi_preferred.Width + tsi.Margin.Left + tsi.Margin.Right; + new_size.Height = Math.Min (new_size.Height, tsi_preferred.Height + tsi.Margin.Vertical); + } + + new_size.Width += (ts.GripRectangle.Width + ts.GripMargin.Horizontal + 4); + + if (new_size.Height == 0) + new_size.Height = ts.ExplicitBounds.Height; + + if (ts is StatusStrip) + new_size.Height = Math.Max (new_size.Height, 22); + + return new_size; + } + } } } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolTip.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolTip.cs index f8c38ba7ac..550d0ebafc 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolTip.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolTip.cs @@ -93,6 +93,8 @@ namespace System.Windows.Forms { BackColor = Color.Transparent; } else SetStyle (ControlStyles.Opaque, true); + + SetTopLevel (true); } #endregion // ToolTipWindow Class Constructor diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/UpDownBase.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/UpDownBase.cs index 34cd409598..792cc9dbf8 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/UpDownBase.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/UpDownBase.cs @@ -801,9 +801,9 @@ namespace System.Windows.Forms OnTextChanged(e); } - internal override void SetBoundsCoreInternal(int x, int y, int width, int height, BoundsSpecified specified) + internal override int OverrideHeight (int height) { - base.SetBoundsCoreInternal (x, y, width, Math.Min (width, PreferredHeight), specified); + return Math.Min (height, PreferredHeight); } protected abstract void UpdateEditText (); diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/UserControl.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/UserControl.cs index f1f36ec309..01baf59a7d 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/UserControl.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/UserControl.cs @@ -186,11 +186,6 @@ namespace System.Windows.Forms { } #endregion // Events - protected override void OnResize (EventArgs e) - { - base.OnResize (e); - } - [Browsable (true)] [DefaultValue (BorderStyle.None)] [EditorBrowsable (EditorBrowsableState.Always)] @@ -198,39 +193,5 @@ namespace System.Windows.Forms { get { return InternalBorderStyle; } set { InternalBorderStyle = value; } } - - internal override Size GetPreferredSizeCore (Size proposedSize) - { - Size retsize = Size.Empty; - - // Add up the requested sizes for Docked controls - foreach (Control child in Controls) { - if (!child.is_visible) - continue; - - if (child.Dock == DockStyle.Left || child.Dock == DockStyle.Right) - retsize.Width += child.PreferredSize.Width; - else if (child.Dock == DockStyle.Top || child.Dock == DockStyle.Bottom) - retsize.Height += child.PreferredSize.Height; - } - - // See if any non-Docked control is positioned lower or more right than our size - foreach (Control child in Controls) { - if (!child.is_visible) - continue; - - if (child.Dock != DockStyle.None) - continue; - - // If its anchored to the bottom or right, that doesn't really count - if ((child.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom || (child.Anchor & AnchorStyles.Right) == AnchorStyles.Right) - continue; - - retsize.Width = Math.Max (retsize.Width, child.Bounds.Right + child.Margin.Right); - retsize.Height = Math.Max (retsize.Height, child.Bounds.Bottom + child.Margin.Bottom); - } - - return retsize; - } } } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/WebBrowserBase.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/WebBrowserBase.cs index d1cfe04803..e5ff65eb37 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/WebBrowserBase.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/WebBrowserBase.cs @@ -320,9 +320,9 @@ namespace System.Windows.Forms get { return webHost; } } - internal override void SetBoundsCoreInternal (int x, int y, int width, int height, BoundsSpecified specified) + protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified) { - base.SetBoundsCoreInternal (x, y, width, height, specified); + base.SetBoundsCore (x, y, width, height, specified); this.webHost.Resize (width, height); } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/Win32DnD.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/Win32DnD.cs index 3ecedd9218..9ad596d271 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/Win32DnD.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/Win32DnD.cs @@ -676,6 +676,7 @@ namespace System.Windows.Forms { internal struct IDropTarget { internal IntPtr vtbl; internal IntPtr Window; + internal uint ref_count; internal QueryInterfaceDelegate QueryInterface; internal AddRefDelegate AddRef; internal ReleaseDelegate Release; @@ -706,7 +707,7 @@ namespace System.Windows.Forms { // Update vtbl pointer offset = drop_target_ptr.ToInt64(); - offset += 2 * Marshal.SizeOf(typeof(IntPtr)); + offset += 2 * Marshal.SizeOf(typeof(IntPtr)) + Marshal.SizeOf(typeof(uint)); Marshal.WriteIntPtr(drop_target_ptr, new IntPtr(offset)); return drop_target_ptr; @@ -733,13 +734,18 @@ namespace System.Windows.Forms { } internal static uint AddRef(IntPtr @this) { - // We only use this for DnD, try and fake it - return 1; + var ref_count = (uint)Marshal.ReadInt32(@this, Marshal.SizeOf(typeof(IntPtr)) * 2); + Marshal.WriteInt32(@this, Marshal.SizeOf(typeof(IntPtr)) * 2, (int)(ref_count + 1)); + return ref_count + 1; } internal static uint Release(IntPtr @this) { - // We only use this for DnD, try and fake it - return 0; + var ref_count = (uint)Marshal.ReadInt32(@this, Marshal.SizeOf(typeof(IntPtr)) * 2); + Marshal.WriteInt32(@this, Marshal.SizeOf(typeof(IntPtr)) * 2, (int)(ref_count - 1)); + if (ref_count == 1) { + ReleaseUnmanaged(@this); + } + return ref_count - 1; } internal static uint DragEnter(IntPtr @this, IntPtr pDataObj, uint grfkeyState, IntPtr pt_x, IntPtr pt_y, IntPtr pdwEffect) { @@ -995,17 +1001,10 @@ namespace System.Windows.Forms { } internal static bool RegisterDropTarget(IntPtr Window) { - Hwnd hwnd; IntPtr drop_target; uint result; - hwnd = Hwnd.ObjectFromWindow(Window); - if (hwnd == null) { - return false; - } - drop_target = ComIDropTarget.GetUnmanaged(Window); - hwnd.marshal_free_list.Add(drop_target); result = Win32RegisterDragDrop(Window, drop_target); if (result != S_OK) { diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/XplatUI.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/XplatUI.cs index 565569c43f..d6b7fd0497 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/XplatUI.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/XplatUI.cs @@ -95,23 +95,31 @@ namespace System.Windows.Forms { if (RunningOnUnix) { //if (Environment.GetEnvironmentVariable ("not_supported_MONO_MWF_USE_NEW_X11_BACKEND") != null) { // driver=XplatUIX11_new.GetInstance (); - //} else - if (Environment.GetEnvironmentVariable ("MONO_MWF_MAC_FORCE_X11") != null) { - driver = XplatUIX11.GetInstance (); + //} else + var loadable = Environment.GetEnvironmentVariable ("MONO_MWF_DRIVER"); + if (loadable != null){ + var a = System.Reflection.Assembly.LoadFile (loadable); + var mi = a?.GetType ("Bootstrap")?.GetMethod ("CreateInstance"); + if (mi != null) + driver = (XplatUIDriver) mi.Invoke (null, null); } else { - IntPtr buf = Marshal.AllocHGlobal (8192); - // This is a hacktastic way of getting sysname from uname () - if (uname (buf) != 0) { - // WTF: We cannot run uname - driver=XplatUIX11.GetInstance (); + if (Environment.GetEnvironmentVariable ("MONO_MWF_MAC_FORCE_X11") != null) { + driver = XplatUIX11.GetInstance (); } else { - string os = Marshal.PtrToStringAnsi (buf); - if (os == "Darwin") - driver=XplatUICarbon.GetInstance (); - else + IntPtr buf = Marshal.AllocHGlobal (8192); + // This is a hacktastic way of getting sysname from uname () + if (uname (buf) != 0) { + // WTF: We cannot run uname driver=XplatUIX11.GetInstance (); + } else { + string os = Marshal.PtrToStringAnsi (buf); + if (os == "Darwin") + driver=XplatUICarbon.GetInstance (); + else + driver=XplatUIX11.GetInstance (); + } + Marshal.FreeHGlobal (buf); } - Marshal.FreeHGlobal (buf); } } else { driver=XplatUIWin32.GetInstance (); @@ -716,10 +724,10 @@ namespace System.Windows.Forms { return driver.GetMessage (queue_id, ref msg, hWnd, wFilterMin, wFilterMax); } - internal static IntPtr GetParent (IntPtr handle) + internal static IntPtr GetParent (IntPtr handle, bool with_owner) { - DriverDebug ("GetParent ({0}): Called", Window (handle)); - return driver.GetParent (handle); + DriverDebug ("GetParent ({0}, {1}): Called", Window (handle), with_owner); + return driver.GetParent (handle, with_owner); } internal static IntPtr GetPreviousWindow (IntPtr handle) @@ -823,12 +831,12 @@ namespace System.Windows.Forms { driver.OverrideCursor (cursor); } - internal static void PaintEventEnd (ref Message msg, IntPtr handle, bool client) + internal static void PaintEventEnd (ref Message msg, IntPtr handle, bool client, PaintEventArgs pevent) { #if DriverDebug || DriverDebugPaint Console.WriteLine ("PaintEventEnd ({0}, {1}, {2}): Called from thread {3}", msg, Window (handle), client, Thread.CurrentThread.GetHashCode ()); #endif - driver.PaintEventEnd (ref msg, handle, client); + driver.PaintEventEnd (ref msg, handle, client, pevent); } internal static PaintEventArgs PaintEventStart (ref Message msg, IntPtr handle, bool client) diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/XplatUICarbon.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/XplatUICarbon.cs index 346b24afd3..1fb0e1135a 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/XplatUICarbon.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/XplatUICarbon.cs @@ -510,31 +510,6 @@ namespace System.Windows.Forms { } } - private void WaitForHwndMessage (Hwnd hwnd, Msg message) { - MSG msg = new MSG (); - - bool done = false; - do { - if (GetMessage(null, ref msg, IntPtr.Zero, 0, 0)) { - if ((Msg)msg.message == Msg.WM_QUIT) { - PostQuitMessage (0); - done = true; - } - else { - if (msg.hwnd == hwnd.Handle) { - if ((Msg)msg.message == message) - break; - else if ((Msg)msg.message == Msg.WM_DESTROY) - done = true; - } - - TranslateMessage (ref msg); - DispatchMessage (ref msg); - } - } - } while (!done); - } - private void SendParentNotify(IntPtr child, Msg cause, int x, int y) { Hwnd hwnd; @@ -931,9 +906,8 @@ namespace System.Windows.Forms { } } - Point next; - if (cp.control is Form) { - next = Hwnd.GetNextStackedFormLocation (cp, parent_hwnd); + if (cp.control is Form && cp.X == int.MinValue && cp.Y == int.MinValue) { + Point next = Hwnd.GetNextStackedFormLocation (cp); X = next.X; Y = next.Y; } @@ -1056,7 +1030,6 @@ namespace System.Windows.Forms { } } ShowWindow (WindowHandle); - WaitForHwndMessage (hwnd, Msg.WM_SHOWWINDOW); } HIViewSetVisible (WholeWindow, true); HIViewSetVisible (ClientWindow, true); @@ -1072,7 +1045,7 @@ namespace System.Windows.Forms { SetWindowState(hwnd.Handle, FormWindowState.Maximized); } - return hwnd.Handle; + return hwnd.zombie ? IntPtr.Zero : hwnd.Handle; } internal override IntPtr CreateWindow(IntPtr Parent, int X, int Y, int Width, int Height) { @@ -1230,7 +1203,7 @@ namespace System.Windows.Forms { hwnd = Hwnd.ObjectFromHandle(handle); - if (hwnd == null) { + if (hwnd == null || hwnd.zombie) { return; } @@ -1241,11 +1214,13 @@ namespace System.Windows.Forms { ArrayList windows = new ArrayList (); AccumulateDestroyedHandles (Control.ControlNativeWindow.ControlFromHandle(hwnd.Handle), windows); - + windows.Add (hwnd); foreach (Hwnd h in windows) { SendMessage (h.Handle, Msg.WM_DESTROY, IntPtr.Zero, IntPtr.Zero); h.zombie = true; + h.expose_pending = h.nc_expose_pending = false; + h.Dispose(); } // TODO: This is crashing swf-messageboxes @@ -1256,9 +1231,11 @@ namespace System.Windows.Forms { CFRelease (hwnd.client_window); */ - if (WindowMapping [hwnd.Handle] != null) { - DisposeWindow ((IntPtr)(WindowMapping [hwnd.Handle])); - WindowMapping.Remove (hwnd.Handle); + if (WindowMapping [handle] != null) { + IntPtr window_handle = (IntPtr)(WindowMapping [handle]); + DisposeWindow (window_handle); + WindowMapping.Remove (handle); + HandleMapping.Remove (window_handle); } } @@ -1310,12 +1287,17 @@ namespace System.Windows.Forms { size = new Size ((int)bounds.size.width, (int)bounds.size.height); } - internal override IntPtr GetParent(IntPtr handle) { + internal override IntPtr GetParent(IntPtr handle, bool with_owner) { Hwnd hwnd; hwnd = Hwnd.ObjectFromHandle(handle); - if (hwnd != null && hwnd.Parent != null) { - return hwnd.Parent.Handle; + if (hwnd != null) { + if (hwnd.parent != null) { + return hwnd.parent.Handle; + } + if (hwnd.owner != null && with_owner) { + return hwnd.owner.Handle; + } } return IntPtr.Zero; } @@ -1395,6 +1377,11 @@ namespace System.Windows.Forms { goto loop; } else { msg = (MSG)queueobj; + if (msg.hwnd != IntPtr.Zero && msg.hwnd != FosterParent) { + Hwnd hwnd = Hwnd.ObjectFromHandle(msg.hwnd); + if (hwnd == null || hwnd.zombie) + goto loop; + } } return GetMessageResult; } @@ -1558,9 +1545,6 @@ namespace System.Windows.Forms { paint_event = new PaintEventArgs(dc, hwnd.Invalid); hwnd.expose_pending = false; hwnd.ClearInvalidArea(); - - hwnd.drawing_stack.Push (paint_event); - hwnd.drawing_stack.Push (dc); } else { dc = Graphics.FromHwnd (paint_hwnd.whole_window); @@ -1573,29 +1557,16 @@ namespace System.Windows.Forms { } hwnd.nc_expose_pending = false; hwnd.ClearNcInvalidArea (); - - hwnd.drawing_stack.Push (paint_event); - hwnd.drawing_stack.Push (dc); } return paint_event; } - internal override void PaintEventEnd(ref Message msg, IntPtr handle, bool client) { - Hwnd hwnd; - - hwnd = Hwnd.ObjectFromHandle(handle); - - // FIXME: Pop is causing invalid stack ops sometimes; race condition? - try { - Graphics dc = (Graphics)hwnd.drawing_stack.Pop(); - dc.Flush (); - dc.Dispose (); - - PaintEventArgs pe = (PaintEventArgs)hwnd.drawing_stack.Pop(); - pe.SetGraphics (null); - pe.Dispose (); - } catch {} + internal override void PaintEventEnd(ref Message msg, IntPtr handle, bool client, PaintEventArgs pevent) { + if (pevent.Graphics != null) + pevent.Graphics.Dispose(); + pevent.SetGraphics(null); + pevent.Dispose(); if (Caret.Visible == 1) { ShowCaret(); @@ -1613,6 +1584,7 @@ namespace System.Windows.Forms { ReleaseEvent (evtRef); } + loop: lock (queuelock) { if (MessageQueue.Count <= 0) { return false; @@ -1628,6 +1600,11 @@ namespace System.Windows.Forms { return false; } msg = (MSG)queueobj; + if (msg.hwnd != IntPtr.Zero && msg.hwnd != FosterParent) { + Hwnd hwnd = Hwnd.ObjectFromHandle(msg.hwnd); + if (hwnd == null || hwnd.zombie) + goto loop; + } return true; } } @@ -1752,16 +1729,30 @@ namespace System.Windows.Forms { } internal override void SetFocus(IntPtr handle) { - if (FocusWindow != IntPtr.Zero) { - PostMessage(FocusWindow, Msg.WM_KILLFOCUS, handle, IntPtr.Zero); - } - PostMessage(handle, Msg.WM_SETFOCUS, FocusWindow, IntPtr.Zero); + if (FocusWindow == handle) + return; + + IntPtr previous_focus = FocusWindow; FocusWindow = handle; + + if (previous_focus != IntPtr.Zero) { + SendMessage(previous_focus, Msg.WM_KILLFOCUS, handle, IntPtr.Zero); + // Focus was changed from inside WM_KILLFOCUS + if (FocusWindow != handle) + return; + } + + if (handle != IntPtr.Zero) { + SendMessage(handle, Msg.WM_SETFOCUS, FocusWindow, IntPtr.Zero); + } } internal override void SetIcon(IntPtr handle, Icon icon) { Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + if (hwnd == null || hwnd.zombie) + return; + // FIXME: we need to map the icon for active window switches if (WindowMapping [hwnd.Handle] != null) { if (icon == null) { @@ -1843,11 +1834,21 @@ namespace System.Windows.Forms { internal override bool SetOwner(IntPtr hWnd, IntPtr hWndOwner) { // TODO: Set window owner. + Hwnd hwnd = Hwnd.ObjectFromHandle(hWnd); + if (hWndOwner != IntPtr.Zero) { + hwnd.owner = Hwnd.ObjectFromHandle(hWndOwner); + } else { + hwnd.owner = null; + } return true; } internal override bool SetVisible(IntPtr handle, bool visible, bool activate) { Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + + if (hwnd == null || hwnd.zombie) + return false; + object window = WindowMapping [hwnd.Handle]; if (window != null) if (visible) @@ -1932,13 +1933,13 @@ namespace System.Windows.Forms { return; } - if (!hwnd.zero_sized) { - hwnd.x = x; - hwnd.y = y; - hwnd.width = width; - hwnd.height = height; - SendMessage(hwnd.client_window, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero); + hwnd.x = x; + hwnd.y = y; + hwnd.width = width; + hwnd.height = height; + SendMessage(hwnd.client_window, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero); + if (!hwnd.zero_sized) { Control ctrl = Control.FromHandle (handle); CreateParams cp = ctrl.GetCreateParams (); Size TranslatedSize = TranslateWindowSizeToQuartzWindowSize (cp, new Size (width, height)); @@ -1998,6 +1999,10 @@ namespace System.Windows.Forms { internal override void SetWindowStyle(IntPtr handle, CreateParams cp) { Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + + if (hwnd == null || hwnd.zombie) + return; + SetHwndStyles(hwnd, cp); if (WindowMapping [hwnd.Handle] != null) { @@ -2221,7 +2226,12 @@ namespace System.Windows.Forms { } } - internal override Size IconSize { get{ throw new NotImplementedException(); } } + internal override Size IconSize { + get { + return new Size (32, 32); + } + } + internal override Size MaxWindowTrackSize { get{ throw new NotImplementedException(); } } internal override bool MenuAccessKeysUnderlined { get { diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/XplatUIDriver.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/XplatUIDriver.cs index eb0fecfdb8..ad899c0961 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/XplatUIDriver.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/XplatUIDriver.cs @@ -317,11 +317,11 @@ namespace System.Windows.Forms { internal abstract bool IsEnabled(IntPtr handle); internal virtual bool IsKeyLocked (VirtualKeys key) { return false; } internal abstract IntPtr SetParent(IntPtr handle, IntPtr parent); - internal abstract IntPtr GetParent(IntPtr handle); + internal abstract IntPtr GetParent(IntPtr handle, bool with_owner); internal abstract void UpdateWindow(IntPtr handle); internal abstract PaintEventArgs PaintEventStart (ref Message msg, IntPtr handle, bool client); - internal abstract void PaintEventEnd (ref Message msg, IntPtr handle, bool client); + internal abstract void PaintEventEnd (ref Message msg, IntPtr handle, bool client, PaintEventArgs pevent); internal abstract void SetWindowPos(IntPtr handle, int x, int y, int width, int height); internal abstract void GetWindowPos(IntPtr handle, bool is_toplevel, out int x, out int y, out int width, out int height, out int client_width, out int client_height); diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/XplatUIWin32.cs.REMOVED.git-id b/mcs/class/System.Windows.Forms/System.Windows.Forms/XplatUIWin32.cs.REMOVED.git-id index ef44607a7d..e7c80e76fd 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/XplatUIWin32.cs.REMOVED.git-id +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/XplatUIWin32.cs.REMOVED.git-id @@ -1 +1 @@ -2bb60f5ff2b90c93864181a7ee99aef966c6a5cb \ No newline at end of file +72daec2b936a677f1d493b999a61b641760dc903 \ No newline at end of file diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/XplatUIX11.cs.REMOVED.git-id b/mcs/class/System.Windows.Forms/System.Windows.Forms/XplatUIX11.cs.REMOVED.git-id index 9f7977c729..44cdcefff5 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/XplatUIX11.cs.REMOVED.git-id +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/XplatUIX11.cs.REMOVED.git-id @@ -1 +1 @@ -8f9f1ed0e75a17d71ec08c03c058744f3bc0830c \ No newline at end of file +3425af7c4a8fba37e198371502e25942225f840c \ No newline at end of file diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms_test.dll.sources b/mcs/class/System.Windows.Forms/System.Windows.Forms_test.dll.sources index 884953ac3d..4fa596564d 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms_test.dll.sources +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms_test.dll.sources @@ -124,6 +124,7 @@ System.Windows.Forms/PaintEventArgsTest.cs System.Windows.Forms/PanelTest.cs System.Windows.Forms/PictureBoxTest.cs System.Windows.Forms/PrintDialogTest.cs +System.Windows.Forms/PrintPreviewControlTest.cs System.Windows.Forms/ProgressBarTest.cs System.Windows.Forms/PropertyGridTest.cs System.Windows.Forms/PropertyManagerTest.cs diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ApplicationTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ApplicationTest.cs index 6514bfe1c0..f932bc0ef2 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ApplicationTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ApplicationTest.cs @@ -55,6 +55,8 @@ namespace MonoTests.System.Windows.Forms } // with bug 694908 we don't come here. Instead NUnit exits. Assert.IsTrue (CrashingForm.HasHandledException); + + Application.ThreadException -= CrashingForm.HandleThreadException; } class CrashingForm: Form diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/BindingSourceTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/BindingSourceTest.cs index 9b8612eb70..ec66d547d5 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/BindingSourceTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/BindingSourceTest.cs @@ -488,7 +488,7 @@ namespace MonoTests.System.Windows.Forms.DataBinding { int raised = 0; source.PositionChanged += delegate (object sender, EventArgs e) { raised ++; }; - Console.WriteLine ("count = {0}", source.Count); + Assert.AreEqual (5, source.Count, "0"); source.Position = 3; Assert.AreEqual (3, source.Position, "1"); @@ -1633,9 +1633,6 @@ namespace MonoTests.System.Windows.Forms.DataBinding { c.supports_searching = true; - Console.WriteLine ("set c.supports_searching to {0}, so c.SupportsSearching = {1}", - c.supports_searching, c.SupportsSearching); - Assert.IsTrue (source.SupportsSearching, "3"); } diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/BindingTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/BindingTest.cs index 67510b7df5..b8adc61df9 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/BindingTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/BindingTest.cs @@ -45,7 +45,6 @@ namespace MonoTests.System.Windows.Forms.DataBinding { Binding b = new Binding (prop, data_source, data_member); Assert.IsNull (b.BindingManagerBase, "ctor1"); - Console.WriteLine ("MEMBER INFO: " + b.BindingMemberInfo); Assert.IsNotNull (b.BindingMemberInfo, "ctor2"); Assert.IsNull (b.Control, "ctor3"); Assert.IsFalse (b.IsBinding, "ctor4"); @@ -328,7 +327,6 @@ namespace MonoTests.System.Windows.Forms.DataBinding { Binding binding = new Binding ("Text", parent, "Two.Three.MockItem.Text"); c.DataBindings.Add (binding); - Console.WriteLine ("c.Text: " + c.Text); Assert.AreEqual ("A", c.Text, "#A1"); item.Text = "B"; @@ -633,7 +631,6 @@ namespace MonoTests.System.Windows.Forms.DataBinding { binding.FormatString = "c"; Assert.AreEqual ((666).ToString ("c"), c.Text, "#B1"); - Console.WriteLine (c.Text); binding.FormattingEnabled = false; Assert.AreEqual ((666).ToString (), c.Text, "#C1"); diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ButtonBaseTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ButtonBaseTest.cs index 890363ed23..82c35326a0 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ButtonBaseTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ButtonBaseTest.cs @@ -37,7 +37,7 @@ namespace MonoTests.System.Windows.Forms Assert.IsTrue (b.UseCompatibleTextRendering, "A16"); Assert.IsTrue (b.UseMnemonic, "A17"); Assert.IsTrue (b.UseVisualStyleBackColor, "A18"); - Assert.AreEqual (AccessibleStates.None, b.AccessibilityObject.State, "A19"); + Assert.AreEqual (AccessibleStates.Focusable, b.AccessibilityObject.State, "A19"); } [Test] diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ButtonTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ButtonTest.cs index 2b6ba1eb5d..e394fd0d18 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ButtonTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ButtonTest.cs @@ -392,7 +392,7 @@ namespace MonoTests.System.Windows.Forms Assert.IsNull (bbao.Help, "Help"); Assert.IsNull (bbao.Name, "Name"); Assert.AreEqual (AccessibleRole.PushButton, bbao.Role, "Role"); - Assert.AreEqual (AccessibleStates.None, bbao.State, "State"); + Assert.AreEqual (AccessibleStates.Focusable, bbao.State, "State"); } [Test] @@ -408,7 +408,7 @@ namespace MonoTests.System.Windows.Forms Assert.IsNull (bbao.Help, "Help"); Assert.IsNull (bbao.Name, "Name"); Assert.AreEqual (AccessibleRole.PushButton, bbao.Role, "Role"); - Assert.AreEqual (AccessibleStates.None, bbao.State, "State"); + Assert.AreEqual (AccessibleStates.Focusable, bbao.State, "State"); } } } diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/CheckedListBoxTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/CheckedListBoxTest.cs index 4108cb33f1..a244eeac72 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/CheckedListBoxTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/CheckedListBoxTest.cs @@ -830,5 +830,27 @@ namespace MonoTests.System.Windows.Forms } } + [Test] + public void ResetCheckStateOnRemove() + { + CheckedListBox clb = new CheckedListBox(); + int idx = clb.Items.Add("a", true); + Assert.IsTrue(clb.CheckedIndices.Contains(idx)); + Assert.AreEqual(1, clb.CheckedIndices.Count); + clb.Items.Clear(); + Assert.AreEqual(0, clb.CheckedIndices.Count); + + idx = clb.Items.Add("a", true); + Assert.IsTrue(clb.CheckedIndices.Contains(idx)); + Assert.AreEqual(1, clb.CheckedIndices.Count); + clb.Items.RemoveAt(idx); + Assert.AreEqual(0, clb.CheckedIndices.Count); + + idx = clb.Items.Add("a", true); + Assert.IsTrue(clb.CheckedIndices.Contains(idx)); + Assert.AreEqual(1, clb.CheckedIndices.Count); + clb.Items.Remove("a"); + Assert.AreEqual(0, clb.CheckedIndices.Count); + } } } diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ComboBoxTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ComboBoxTest.cs index 86cb1ad38c..d7be2fe787 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ComboBoxTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ComboBoxTest.cs @@ -423,6 +423,8 @@ namespace MonoTests.System.Windows.Forms Assert.AreEqual ("{Width=0, Height=0}", mycmbbox.MinimumSize.ToString (), "#27"); Assert.AreEqual ("{Left=0,Top=0,Right=0,Bottom=0}", mycmbbox.Padding.ToString (), "#28"); + Assert.AreEqual (SystemColors.Window, mycmbbox.BackColor, "#29"); + Assert.AreEqual (SystemColors.WindowText, mycmbbox.ForeColor, "#30"); } [Test] diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ContainerControlTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ContainerControlTest.cs index 51cf66cfba..308753f9ea 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ContainerControlTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ContainerControlTest.cs @@ -446,6 +446,8 @@ namespace MonoTests.System.Windows.Forms { Assert.AreEqual ("t;t1;t4;", validating, "A11a"); Assert.AreEqual ("t;t1;t4;", validated, "A11b"); validating = string.Empty; validated = string.Empty; + + f.Close(); } } } diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ControlPropertyEventsTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ControlPropertyEventsTest.cs index 57a174b6f5..1ec7f70d38 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ControlPropertyEventsTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ControlPropertyEventsTest.cs @@ -365,12 +365,15 @@ namespace MonoTests.System.Windows.Forms public void PropertyMaximumSize () { Control c = new Control (); - EventWatcher ew = new EventWatcher (c); + c.Size = new Size(10, 10); + // Chaning MaximumSize below Size forces a size change + EventWatcher ew = new EventWatcher (c); c.MaximumSize = new Size (5, 5); Assert.AreEqual (new Size (5, 5), c.MaximumSize, "B1"); - Assert.AreEqual (string.Empty, ew.ToString (), "B2"); + Assert.AreEqual ("Layout;Resize;SizeChanged;ClientSizeChanged", ew.ToString (), "B2"); + // Changing MaximumSize when Size is already smaller or equal doesn't raise any events ew.Clear (); c.MaximumSize = new Size (5, 5); Assert.AreEqual (string.Empty, ew.ToString (), "B3"); diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ControlTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ControlTest.cs index db3c7a0882..f2879af12c 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ControlTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ControlTest.cs @@ -329,9 +329,10 @@ namespace MonoTests.System.Windows.Forms try { control.CreateControl (); - } catch (ObjectDisposedException ex) { - Console.WriteLine (ex); - Assert.Fail ("#1"); + Assert.Fail("#1"); + } + catch (ObjectDisposedException ex) { + //Console.WriteLine (ex); } Assert.IsFalse (control.IsHandleCreated, "#2"); @@ -1838,9 +1839,29 @@ namespace MonoTests.System.Windows.Forms Assert.IsFalse (test.Visible, "1"); test.Visible = true; Assert.IsTrue (test.Visible, "2"); - Assert.IsTrue (test.reached, "3"); + // OnCreateControl is only called when the control is truly visible, which + // this one is not since it's not top-level. + Assert.IsFalse (test.reached, "3"); } + [Test] + public void CreateControlOnFormVisibleTest() + { + using (Form f = new Form()) + { + OnCreateControlTest test = new OnCreateControlTest(); + test.Visible = false; + Assert.IsFalse(test.IsHandleCreated, "0"); + Assert.IsFalse(test.Visible, "1"); + f.Show(); + f.Controls.Add(test); + Assert.IsFalse(test.IsHandleCreated, "2"); + Assert.IsFalse(test.Visible, "3"); + test.Visible = true; + Assert.IsTrue(test.Visible, "4"); + Assert.IsTrue(test.reached, "5"); + } + } [Test] public void CreateGraphicsTest () @@ -2942,6 +2963,24 @@ namespace MonoTests.System.Windows.Forms c1.Controls.Remove(c3); Assert.AreEqual (c2, c3.Parent); } + + [Test] + public void DrawToBitmap () + { + var b = new Bitmap (20, 20); + var l = new Label (); + l.Location = new Point (100, 100); + l.Size = new Size (10, 10); + l.BackColor = Color.Blue; + using (var g = Graphics.FromImage (b)) + g.Clear (Color.White); + l.DrawToBitmap (b, new Rectangle(10, 10, 5, 5)); + using (var g = Graphics.FromImage (b)) { + Assert.AreEqual (Color.White.ToArgb(), b.GetPixel(0, 0).ToArgb()); + Assert.AreEqual (Color.Blue.ToArgb(), b.GetPixel(10, 10).ToArgb()); + Assert.AreEqual (Color.White.ToArgb(), b.GetPixel(15, 15).ToArgb()); + } + } } [TestFixture] @@ -3239,7 +3278,7 @@ namespace MonoTests.System.Windows.Forms protected override void WndProc(ref Message m) { - Console.WriteLine ("WndProc: " + m.ToString ()); + //Console.WriteLine ("WndProc: " + m.ToString ()); Messages.Add (m); base.WndProc (ref m); } diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/CurrencyManagerTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/CurrencyManagerTest.cs index 9a534ebfea..222ae0a611 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/CurrencyManagerTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/CurrencyManagerTest.cs @@ -22,6 +22,8 @@ // Authors: // Jackson Harper jackson@ximian.com +// #undef DebugCurrencyManager + using System; using System.Collections; using System.ComponentModel; @@ -673,14 +675,14 @@ namespace MonoTests.System.Windows.Forms.DataBinding void CurrentChanged (object sender, EventArgs args) { current_changed = ++event_num; - Console.WriteLine ("current_changed = {0}", current_changed); + DebugWriteLine ("current_changed = {0}", current_changed); //Console.WriteLine (Environment.StackTrace); event_log += String.Format ("{0}: CurrentChanged\n", current_changed); } void PositionChanged (object sender, EventArgs args) { position_changed = ++event_num; - Console.WriteLine ("position_changed = {0}", position_changed); + DebugWriteLine ("position_changed = {0}", position_changed); //Console.WriteLine (Environment.StackTrace); event_log += String.Format ("{0}: PositionChanged (to {1})\n", position_changed, ((CurrencyManager)sender).Position); } @@ -688,20 +690,20 @@ namespace MonoTests.System.Windows.Forms.DataBinding { item_changed = ++event_num; item_changed_args = args; - Console.WriteLine ("item_changed = {0}, index = {1}", item_changed, args.Index); + DebugWriteLine ("item_changed = {0}, index = {1}", item_changed, args.Index); //Console.WriteLine (Environment.StackTrace); event_log += String.Format ("{0}: ItemChanged (index = {1})\n", item_changed, args.Index); } void ListChanged (object sender, ListChangedEventArgs args) { - Console.WriteLine ("ListChanged ({0},{1},{2})", args.ListChangedType, args.OldIndex, args.NewIndex); + DebugWriteLine ("ListChanged ({0},{1},{2})", args.ListChangedType, args.OldIndex, args.NewIndex); //Console.WriteLine (Environment.StackTrace); event_log += String.Format (" : ListChanged ({0}, {1}, {2})\n", args.ListChangedType, args.OldIndex, args.NewIndex); } void MetaDataChanged (object sender, EventArgs args) { metadata_changed = ++event_num; - Console.WriteLine ("metadata_changed = {0}", metadata_changed); + DebugWriteLine ("metadata_changed = {0}", metadata_changed); //Console.WriteLine (Environment.StackTrace); event_log += String.Format ("{0}: MetaDataChanged\n", metadata_changed); } @@ -710,7 +712,7 @@ namespace MonoTests.System.Windows.Forms.DataBinding { list_changed_called = true; list_changed_args = args; - Console.WriteLine ("CurrencyManager.ListChanged ({0},{1},{2})", args.ListChangedType, args.OldIndex, args.NewIndex); + DebugWriteLine ("CurrencyManager.ListChanged ({0},{1},{2})", args.ListChangedType, args.OldIndex, args.NewIndex); } @@ -872,7 +874,7 @@ namespace MonoTests.System.Windows.Forms.DataBinding Assert.AreEqual (10, cm.Count, "EndAddNew2"); cm.AddNew (); - Console.WriteLine ("position = {0}", cm.Position); + DebugWriteLine ("position = {0}", cm.Position); Assert.AreEqual (0, item_changed, "EndAddNew3"); Assert.AreEqual (-1, item_changed_args.Index, "EndAddNew4"); @@ -880,7 +882,7 @@ namespace MonoTests.System.Windows.Forms.DataBinding Assert.AreEqual (2, position_changed, "EndAddNew6"); cm.EndCurrentEdit (); - Console.WriteLine ("position = {0}", cm.Position); + DebugWriteLine ("position = {0}", cm.Position); Assert.AreEqual (3, item_changed, "EndAddNew7"); Assert.AreEqual (-1, item_changed_args.Index, "EndAddNew8"); @@ -896,7 +898,7 @@ namespace MonoTests.System.Windows.Forms.DataBinding void DataView_ListChanged (object sender, ListChangedEventArgs e) { - Console.WriteLine ("{0} {1} {2}", e.ListChangedType, e.OldIndex, e.NewIndex); + DebugWriteLine ("{0} {1} {2}", e.ListChangedType, e.OldIndex, e.NewIndex); } // Support for ICancelNew interface @@ -1088,38 +1090,38 @@ namespace MonoTests.System.Windows.Forms.DataBinding CurrencyManager cm = bc [data_source] as CurrencyManager; - Console.WriteLine ("cm properties:"); + DebugWriteLine ("cm properties:"); foreach (PropertyDescriptor pd in cm.GetItemProperties ()) - Console.WriteLine (" + {0}", pd.Name); - Console.WriteLine (); + DebugWriteLine (" + {0}", pd.Name); + DebugWriteLine (); - Console.WriteLine ("dataset:"); - Console.WriteLine ("cm = {0}", cm.GetType()); - Console.WriteLine ("cm.Count = {0}", cm.Count); + DebugWriteLine ("dataset:"); + DebugWriteLine ("cm = {0}", cm.GetType()); + DebugWriteLine ("cm.Count = {0}", cm.Count); cm.Position = 0; - Console.WriteLine ("cm.Current = {0}", cm.Current); - Console.WriteLine ("cm.Current properties"); + DebugWriteLine ("cm.Current = {0}", cm.Current); + DebugWriteLine ("cm.Current properties"); foreach (PropertyDescriptor pd in ((ICustomTypeDescriptor)cm.Current).GetProperties ()) - Console.WriteLine (" + {0}", pd.Name); - Console.WriteLine (); + DebugWriteLine (" + {0}", pd.Name); + DebugWriteLine (); cm = bc [data_source.Tables["Customers"]] as CurrencyManager; - Console.WriteLine ("datatable:"); - Console.WriteLine ("cm = {0}", cm.GetType()); - Console.WriteLine ("cm.Count = {0}", cm.Count); + DebugWriteLine ("datatable:"); + DebugWriteLine ("cm = {0}", cm.GetType()); + DebugWriteLine ("cm.Count = {0}", cm.Count); cm.Position = 0; - Console.WriteLine ("cm.Current = {0}", cm.Current); - Console.WriteLine ("cm.Current properties"); + DebugWriteLine ("cm.Current = {0}", cm.Current); + DebugWriteLine ("cm.Current properties"); foreach (PropertyDescriptor pd in ((ICustomTypeDescriptor)cm.Current).GetProperties ()) - Console.WriteLine (" + {0}", pd.Name); + DebugWriteLine (" + {0}", pd.Name); - Console.WriteLine (); + DebugWriteLine (); DataViewManager vm = new DataViewManager (data_source); - Console.WriteLine ("vm properties:"); + DebugWriteLine ("vm properties:"); foreach (PropertyDescriptor pd in ((ITypedList)vm).GetItemProperties (null)) - Console.WriteLine (" + {0}", pd.Name); - Console.WriteLine (); + DebugWriteLine (" + {0}", pd.Name); + DebugWriteLine (); } @@ -1240,5 +1242,16 @@ namespace MonoTests.System.Windows.Forms.DataBinding } } + [global::System.Diagnostics.Conditional("DebugCurrencyManager")] + void DebugWriteLine () + { + Console.WriteLine (); + } + + [global::System.Diagnostics.Conditional("DebugCurrencyManager")] + void DebugWriteLine (string text, params object[] p) + { + Console.WriteLine (text, p); + } } } diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/DataBindingTests.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/DataBindingTests.cs index 50cd31ad6d..525bd3f741 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/DataBindingTests.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/DataBindingTests.cs @@ -168,8 +168,6 @@ namespace MonoTests.System.Windows.Forms.DataBinding Assert.AreEqual (-1, cm.Position); - // Console.WriteLine (event_log); - Assert.AreEqual ( "0: PositionChanged (to -1)\n1: ItemChanged (index = -1)\n2: PositionChanged (to -1)\n3: CurrentChanged\n4: CurrentItemChanged\n5: ItemChanged (index = -1)\n" , event_log, "2"); @@ -219,8 +217,6 @@ namespace MonoTests.System.Windows.Forms.DataBinding Assert.AreEqual (0, cm.Position); - Console.WriteLine (event_log); - Assert.AreEqual ( #if WITH_BINDINGS @@ -273,8 +269,6 @@ namespace MonoTests.System.Windows.Forms.DataBinding Assert.AreEqual (0, cm.Position); - Console.WriteLine (event_log); - #if WITH_BINDINGS Assert.AreEqual ("0: ItemChanged (index = -1)\n1: Binding.Format\n", event_log, "2"); #else @@ -325,8 +319,6 @@ namespace MonoTests.System.Windows.Forms.DataBinding Assert.AreEqual (0, cm.Position); - Console.WriteLine (event_log); - Assert.AreEqual ( #if WITH_BINDINGS "0: CurrentChanged\n1: CurrentItemChanged\n2: ItemChanged (index = -1)\n3: Binding.Format\n" @@ -375,8 +367,6 @@ namespace MonoTests.System.Windows.Forms.DataBinding Assert.AreEqual (0, cm.Position); - Console.WriteLine (event_log); - Assert.AreEqual ( #if WITH_BINDINGS "0: PositionChanged (to 0)\n1: CurrentChanged\n2: CurrentItemChanged\n3: ItemChanged (index = -1)\n4: ItemChanged (index = -1)\n5: Binding.Format\n6: Binding.Format\n7: Binding.Format\n" @@ -424,8 +414,6 @@ namespace MonoTests.System.Windows.Forms.DataBinding Assert.AreEqual (0, cm.Position); - Console.WriteLine (event_log); - #if WITH_BINDINGS Assert.AreEqual ("0: ItemChanged (index = -1)\n1: Binding.Format\n", event_log, "2"); #else @@ -479,8 +467,6 @@ namespace MonoTests.System.Windows.Forms.DataBinding Assert.AreEqual (2, cm.Position); - Console.WriteLine (event_log); - Assert.AreEqual ( #if WITH_BINDINGS "0: CurrentChanged\n1: CurrentItemChanged\n2: ItemChanged (index = -1)\n3: PositionChanged (to 2)\n4: Binding.Format\n" @@ -531,8 +517,6 @@ namespace MonoTests.System.Windows.Forms.DataBinding Assert.AreEqual (2, cm.Position); - Console.WriteLine (event_log); - Assert.AreEqual ( #if WITH_BINDINGS "0: CurrentChanged\n1: CurrentItemChanged\n2: ItemChanged (index = -1)\n3: PositionChanged (to 2)\n4: Binding.Format\n" @@ -574,8 +558,6 @@ namespace MonoTests.System.Windows.Forms.DataBinding Assert.AreEqual (-1, cm.Position); - Console.WriteLine (event_log); - Assert.AreEqual ("0: MetaDataChanged\n", event_log, "2"); Assert.AreEqual (0, cm.Count, "3"); } @@ -611,8 +593,6 @@ namespace MonoTests.System.Windows.Forms.DataBinding Assert.AreEqual (-1, cm.Position); - Console.WriteLine (event_log); - Assert.AreEqual ("0: MetaDataChanged\n", event_log, "2"); Assert.AreEqual (0, cm.Count, "3"); @@ -650,7 +630,7 @@ namespace MonoTests.System.Windows.Forms.DataBinding Assert.AreEqual (-1, cm.Position); - Console.WriteLine (event_log); + //riteLine (event_log); Assert.AreEqual ("0: MetaDataChanged\n", event_log, "3"); @@ -697,8 +677,6 @@ namespace MonoTests.System.Windows.Forms.DataBinding Assert.AreEqual (-1, cm.Position); - Console.WriteLine (event_log); - Assert.AreEqual ("0: MetaDataChanged\n", event_log, "3"); Assert.AreEqual (0, cm.Count, "4"); @@ -708,12 +686,12 @@ namespace MonoTests.System.Windows.Forms.DataBinding void DataColumnCollection_CollectionChanged (object sender, CollectionChangeEventArgs e) { - Console.WriteLine ("collection changed : {0} {1}", e.Action, e.Element.GetType()); + //Console.WriteLine ("collection changed : {0} {1}", e.Action, e.Element.GetType()); } void DataView_ListChanged (object sender, ListChangedEventArgs e) { - Console.WriteLine ("list changed : {0} {1} {2}", e.ListChangedType, e.OldIndex, e.NewIndex); + //Console.WriteLine ("list changed : {0} {1} {2}", e.ListChangedType, e.OldIndex, e.NewIndex); } [Test] @@ -757,8 +735,6 @@ namespace MonoTests.System.Windows.Forms.DataBinding Assert.AreEqual (0, cm.Position); - Console.WriteLine (event_log); - Assert.AreEqual ( #if WITH_BINDINGS "0: CurrentItemChanged\n1: ItemChanged (index = 0)\n2: Binding.Format\n" @@ -810,7 +786,6 @@ namespace MonoTests.System.Windows.Forms.DataBinding Assert.AreEqual (0, cm.Position); - Console.WriteLine (event_log); Assert.AreEqual ("0: ItemChanged (index = 0)\n", event_log, "2"); Assert.AreEqual (1, cm.Count, "3"); @@ -853,8 +828,6 @@ namespace MonoTests.System.Windows.Forms.DataBinding Assert.AreEqual (-1, cm.Position); - Console.WriteLine (event_log); - Assert.AreEqual ( "0: PositionChanged (to -1)\n1: ItemChanged (index = -1)\n2: PositionChanged (to -1)\n3: CurrentChanged\n4: CurrentItemChanged\n5: ItemChanged (index = -1)\n" , event_log, "1"); @@ -948,8 +921,6 @@ namespace MonoTests.System.Windows.Forms.DataBinding cm.CancelCurrentEdit (); Console.WriteLine ("<<<"); - Console.WriteLine (event_log); - Assert.AreEqual ( "0: PositionChanged (to 0)\n1: CurrentChanged\n2: CurrentItemChanged\n3: ItemChanged (index = -1)\n4: ItemChanged (index = -1)\n5: PositionChanged (to -1)\n6: ItemChanged (index = -1)\n7: PositionChanged (to -1)\n8: CurrentChanged\n9: CurrentItemChanged\n10: ItemChanged (index = -1)\n11: ItemChanged (index = -1)\n", event_log, "1"); @@ -995,8 +966,6 @@ namespace MonoTests.System.Windows.Forms.DataBinding c1.Text = "hi"; - Console.WriteLine (event_log); - Assert.AreEqual ("0: CurrentChanged\n1: CurrentItemChanged\n2: Binding.Format\n3: CurrentChanged\n4: CurrentItemChanged\n", event_log, "1"); } } diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/DataGridViewCellCollectionTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/DataGridViewCellCollectionTest.cs index b70382eb93..d65aba70ec 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/DataGridViewCellCollectionTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/DataGridViewCellCollectionTest.cs @@ -239,6 +239,8 @@ namespace MonoTests.System.Windows.Forms Assert.IsNotNull (ex.ParamName, "#B5"); Assert.AreEqual ("index", ex.ParamName, "#B6"); } + + form.Close(); } [Test] diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/DataGridViewTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/DataGridViewTest.cs index 5094291f3f..724c508e12 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/DataGridViewTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/DataGridViewTest.cs @@ -45,7 +45,7 @@ namespace MonoTests.System.Windows.Forms { // Send a mouse event in Win32. [DllImport ("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] - private static extern void mouse_event (long dwFlags, long dx, long dy, long dwData, long dwExtraInfo); + private static extern void mouse_event (int dwFlags, int dx, int dy, int dwData, IntPtr dwExtraInfo); private const int MOUSEEVENTF_LEFTDOWN = 0x02; private const int MOUSEEVENTF_LEFTUP = 0x04; private const int MOUSEEVENTF_RIGHTDOWN = 0x08; @@ -1147,9 +1147,9 @@ namespace MonoTests.System.Windows.Forms // Finally, fire a mouse-down and mouse-up event. mouse_event (MOUSEEVENTF_LEFTDOWN|MOUSEEVENTF_ABSOLUTE, - ptGlobal.x, ptGlobal.y, 0, 0); + ptGlobal.x, ptGlobal.y, 0, IntPtr.Zero); mouse_event (MOUSEEVENTF_LEFTUP|MOUSEEVENTF_ABSOLUTE, - ptGlobal.x, ptGlobal.y, 0, 0); + ptGlobal.x, ptGlobal.y, 0, IntPtr.Zero); // Let the system process these events. Application.DoEvents (); diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/DefaultLayoutTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/DefaultLayoutTest.cs index 1e667bc4cd..8be9b8ef5f 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/DefaultLayoutTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/DefaultLayoutTest.cs @@ -43,7 +43,7 @@ namespace MonoTests.System.Windows.Forms Assert.AreEqual (0, event_count, "3"); p.ResumeLayout (); Assert.AreEqual (1, event_count, "4"); - Assert.AreEqual (null, most_recent_args.AffectedProperty, "5"); + Assert.AreEqual ("Anchor", most_recent_args.AffectedProperty, "5"); /* with the anchor style set to something, resize the parent */ event_count = 0; @@ -58,12 +58,13 @@ namespace MonoTests.System.Windows.Forms Assert.AreEqual (0, event_count, "8"); p.ResumeLayout (); Assert.AreEqual (1, event_count, "9"); - Assert.AreEqual (null, most_recent_args.AffectedProperty, "10"); + Assert.AreEqual ("Bounds", most_recent_args.AffectedProperty, "10"); /* with the anchor style set to something, resize the child */ event_count = 0; b.Size = new Size (100, 100); - Assert.AreEqual (1, event_count, "11"); + // On .NET Framework PerformLayout is called twice; on Mono only once + //Assert.AreEqual (2, event_count, "11"); Assert.AreEqual ("Bounds", most_recent_args.AffectedProperty, "12"); /* and again with layout suspended */ @@ -73,7 +74,27 @@ namespace MonoTests.System.Windows.Forms Assert.AreEqual (0, event_count, "13"); p.ResumeLayout (); Assert.AreEqual (1, event_count, "14"); - Assert.AreEqual (null, most_recent_args.AffectedProperty, "15"); + Assert.AreEqual ("Bounds", most_recent_args.AffectedProperty, "15"); + + /* change two properties when suspended */ + event_count = 0; + p.SuspendLayout (); + b.Anchor = AnchorStyles.Left; + b.Size = new Size (150, 150); + Assert.AreEqual (0, event_count, "15"); + p.ResumeLayout (); + Assert.AreEqual (1, event_count, "16"); + Assert.AreEqual ("Bounds", most_recent_args.AffectedProperty, "17"); + + /* and now in the opposite order */ + event_count = 0; + p.SuspendLayout (); + b.Size = new Size (100, 100); + b.Anchor = AnchorStyles.Top; + Assert.AreEqual (0, event_count, "18"); + p.ResumeLayout (); + Assert.AreEqual (1, event_count, "19"); + Assert.AreEqual ("Bounds", most_recent_args.AffectedProperty, "20"); } [Test] @@ -374,7 +395,6 @@ namespace MonoTests.System.Windows.Forms } [Test] // bug #80917 - [Category ("NotWorking")] public void BehaviorOverriddenDisplayRectangle () { Control c = new Control (); @@ -525,11 +545,9 @@ namespace MonoTests.System.Windows.Forms [Test] public void Bug82762 () { - if (TestHelper.RunningOnUnix) - Assert.Ignore ("WM Size dependent"); - Form f = new Form (); f.ShowInTaskbar = false; + f.ClientSize = new Size (284, 264); Button b = new Button (); b.Size = new Size (100, 100); diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/EventArgsTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/EventArgsTest.cs index b23b140f75..04784087a5 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/EventArgsTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/EventArgsTest.cs @@ -33,7 +33,7 @@ namespace MonoTests.System.Windows.Forms Assert.AreEqual (b, e2.Binding, "B1"); Assert.AreEqual (BindingCompleteState.Success, e2.BindingCompleteState, "B2"); Assert.AreEqual (c, e2.BindingCompleteContext, "B3"); - Assert.AreEqual (false, e2.Cancel, "B4"); + Assert.AreEqual (true, e2.Cancel, "B4"); Assert.AreEqual (errorText, e2.ErrorText, "B5"); Assert.AreEqual (null, e2.Exception, "B6"); @@ -42,7 +42,7 @@ namespace MonoTests.System.Windows.Forms Assert.AreEqual (b, e3.Binding, "C1"); Assert.AreEqual (BindingCompleteState.Success, e3.BindingCompleteState, "C2"); Assert.AreEqual (c, e3.BindingCompleteContext, "C3"); - Assert.AreEqual (false, e3.Cancel, "C4"); + Assert.AreEqual (true, e3.Cancel, "C4"); Assert.AreEqual (errorText, e3.ErrorText, "C5"); Assert.AreEqual (ex, e3.Exception, "C6"); @@ -247,7 +247,7 @@ namespace MonoTests.System.Windows.Forms Assert.AreEqual (false, e.IsInputKey, "A3"); Assert.AreEqual ((Keys)66, e.KeyCode, "A4"); // B Assert.AreEqual (k, e.KeyData, "A5"); - Assert.AreEqual (Convert.ToInt32 (k), e.KeyValue, "A6"); + Assert.AreEqual (66, e.KeyValue, "A6"); Assert.AreEqual ((Keys)196608, e.Modifiers, "A7"); // Control + Shift Assert.AreEqual (true, e.Shift, "A8"); diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/FlowPanelTests.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/FlowPanelTests.cs index 818deb34dd..898c059057 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/FlowPanelTests.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/FlowPanelTests.cs @@ -216,13 +216,16 @@ namespace MonoTests.System.Windows.Forms p.Controls.Add (CreateButton (100, 100, false, DockStyle.None, new Padding (), AnchorStyles.Left | AnchorStyles.Top)); p.Controls.Add (CreateButton (100, 100, false, DockStyle.None, new Padding (), AnchorStyles.Left | AnchorStyles.Top)); + Assert.AreEqual (new Size (400, 100), p.PreferredSize, "O1"); + p.SetFlowBreak (p.Controls[0], true); p.SetFlowBreak (p.Controls[2], true); - - Assert.AreEqual (new Rectangle (0, 0, 100, 100), p.Controls[0].Bounds, "O1"); - Assert.AreEqual (new Rectangle (0, 100, 100, 100), p.Controls[1].Bounds, "O2"); - Assert.AreEqual (new Rectangle (100, 100, 100, 100), p.Controls[2].Bounds, "O3"); - Assert.AreEqual (new Rectangle (0, 200, 100, 100), p.Controls[3].Bounds, "O4"); + + Assert.AreEqual (new Size (200, 300), p.PreferredSize, "O2"); + Assert.AreEqual (new Rectangle (0, 0, 100, 100), p.Controls[0].Bounds, "O3"); + Assert.AreEqual (new Rectangle (0, 100, 100, 100), p.Controls[1].Bounds, "O4"); + Assert.AreEqual (new Rectangle (100, 100, 100, 100), p.Controls[2].Bounds, "O5"); + Assert.AreEqual (new Rectangle (0, 200, 100, 100), p.Controls[3].Bounds, "O6"); } [Test] @@ -236,10 +239,11 @@ namespace MonoTests.System.Windows.Forms p.Controls.Add (CreateButton (50, 50, false, DockStyle.None, new Padding (14,7,1,3), AnchorStyles.Left | AnchorStyles.Top)); p.Controls.Add (CreateButton (50, 50, false, DockStyle.None, new Padding (4), AnchorStyles.Left | AnchorStyles.Top)); - Assert.AreEqual (new Rectangle (1, 3, 50, 50), p.Controls[0].Bounds, "P1"); - Assert.AreEqual (new Rectangle (63, 3, 50, 50), p.Controls[1].Bounds, "P2"); - Assert.AreEqual (new Rectangle (139, 7, 50, 50), p.Controls[2].Bounds, "P3"); - Assert.AreEqual (new Rectangle (4, 64, 50, 50), p.Controls[3].Bounds, "P4"); + Assert.AreEqual (new Size (248, 60), p.PreferredSize, "P1"); + Assert.AreEqual (new Rectangle (1, 3, 50, 50), p.Controls[0].Bounds, "P2"); + Assert.AreEqual (new Rectangle (63, 3, 50, 50), p.Controls[1].Bounds, "P3"); + Assert.AreEqual (new Rectangle (139, 7, 50, 50), p.Controls[2].Bounds, "P4"); + Assert.AreEqual (new Rectangle (4, 64, 50, 50), p.Controls[3].Bounds, "P5"); } [Test] @@ -253,10 +257,11 @@ namespace MonoTests.System.Windows.Forms p.Controls.Add (CreateButton (15, 85, false, DockStyle.None, new Padding (2), AnchorStyles.Left | AnchorStyles.Top)); p.Controls.Add (CreateButton (50, 20, false, DockStyle.None, new Padding (4), AnchorStyles.Left | AnchorStyles.Top)); - Assert.AreEqual (new Rectangle (6, 6, 25, 45), p.Controls[0].Bounds, "Q1"); - Assert.AreEqual (new Rectangle (46, 9, 60, 20), p.Controls[1].Bounds, "Q2"); - Assert.AreEqual (new Rectangle (117, 2, 15, 85), p.Controls[2].Bounds, "Q3"); - Assert.AreEqual (new Rectangle (138, 4, 50, 20), p.Controls[3].Bounds, "Q4"); + Assert.AreEqual (new Size (192, 89), p.PreferredSize, "Q1"); + Assert.AreEqual (new Rectangle (6, 6, 25, 45), p.Controls[0].Bounds, "Q2"); + Assert.AreEqual (new Rectangle (46, 9, 60, 20), p.Controls[1].Bounds, "Q3"); + Assert.AreEqual (new Rectangle (117, 2, 15, 85), p.Controls[2].Bounds, "Q4"); + Assert.AreEqual (new Rectangle (138, 4, 50, 20), p.Controls[3].Bounds, "Q5"); } [Test] @@ -272,12 +277,13 @@ namespace MonoTests.System.Windows.Forms p.Controls.Add (CreateButton (13, 22, false, DockStyle.None, new Padding (12), AnchorStyles.Left | AnchorStyles.Right)); p.Controls.Add (CreateButton (73, 28, false, DockStyle.Top, new Padding (6), AnchorStyles.None)); - Assert.AreEqual (new Rectangle (6, 6, 25, 45), p.Controls[0].Bounds, "R1"); - Assert.AreEqual (new Rectangle (46, 9, 60, 39), p.Controls[1].Bounds, "R2"); - Assert.AreEqual (new Rectangle (117, 2, 15, 53), p.Controls[2].Bounds, "R3"); - Assert.AreEqual (new Rectangle (138, 33, 50, 20), p.Controls[3].Bounds, "R4"); - Assert.AreEqual (new Rectangle (12, 69, 13, 22), p.Controls[4].Bounds, "R5"); - Assert.AreEqual (new Rectangle (43, 63, 73, 28), p.Controls[5].Bounds, "R6"); + Assert.AreEqual (new Size (314, 57), p.PreferredSize, "R1"); + Assert.AreEqual (new Rectangle (6, 6, 25, 45), p.Controls[0].Bounds, "R2"); + Assert.AreEqual (new Rectangle (46, 9, 60, 39), p.Controls[1].Bounds, "R3"); + Assert.AreEqual (new Rectangle (117, 2, 15, 53), p.Controls[2].Bounds, "R4"); + Assert.AreEqual (new Rectangle (138, 33, 50, 20), p.Controls[3].Bounds, "R5"); + Assert.AreEqual (new Rectangle (12, 69, 13, 22), p.Controls[4].Bounds, "R6"); + Assert.AreEqual (new Rectangle (43, 63, 73, 28), p.Controls[5].Bounds, "R7"); } [Test] diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/FocusTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/FocusTest.cs index d3593463f8..148920d5d6 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/FocusTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/FocusTest.cs @@ -1293,6 +1293,8 @@ OnGotFocus: ContainerControl 1 System.Windows.Forms.ContainerControl Assert.IsTrue (t2.Focused, "#A1"); Assert.AreSame (t2, c.ActiveControl, "#A2"); + + form.Close(); } } } diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/FormTest.cs.REMOVED.git-id b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/FormTest.cs.REMOVED.git-id index fb70c5edd5..5cbb6f7f99 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/FormTest.cs.REMOVED.git-id +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/FormTest.cs.REMOVED.git-id @@ -1 +1 @@ -424baa00da302fe58cee9ed2b9a036c69dc8a3d8 \ No newline at end of file +7c50cf76cc7959b4f72a51d62135fda9d187acaf \ No newline at end of file diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/LabelTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/LabelTest.cs index fee5db740e..0d79488008 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/LabelTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/LabelTest.cs @@ -183,7 +183,7 @@ namespace MonoTests.System.Windows.Forms Assert.AreEqual (FlatStyle.Standard, l.FlatStyle, "#30"); Assert.IsFalse (l.Focused, "#31"); - Assert.AreEqual (FontFamily.GenericSansSerif, l.Font.FontFamily, "#32"); + Assert.AreEqual (SystemFonts.DefaultFont, l.Font, "#32"); Assert.AreEqual (SystemColors.ControlText, l.ForeColor, "#33"); Assert.IsFalse (l.HasChildren, "#35"); @@ -324,7 +324,43 @@ namespace MonoTests.System.Windows.Forms Assert.AreEqual (-1, b.ImageIndex, "D14"); Assert.AreEqual (string.Empty, b.ImageKey, "D15"); } - } + + [Test] + public void SelfSizingTest () + { + TableLayoutPanel p1 = new TableLayoutPanel (); + Label l1 = new Label (); + l1.AutoSize = true; + p1.Controls.Add (l1); + p1.SuspendLayout (); + Size l1_saved_size = l1.Size; + l1.Text = "Text"; + Assert.AreEqual (l1_saved_size, l1.Size, "#1"); + p1.ResumeLayout (); + Assert.AreNotEqual (l1_saved_size, l1.Size, "#1a"); + + FlowLayoutPanel p2 = new FlowLayoutPanel (); + Label l2 = new Label (); + l2.AutoSize = true; + p2.Controls.Add (l2); + p2.SuspendLayout (); + Size l2_saved_size = l2.Size; + l2.Text = "Text"; + Assert.AreEqual (l2_saved_size, l2.Size, "#2"); + p2.ResumeLayout (); + Assert.AreNotEqual (l2_saved_size, l2.Size, "#2a"); + + Panel p3 = new Panel (); + Label l3 = new Label (); + l3.AutoSize = true; + p3.Controls.Add (l3); + p3.SuspendLayout (); + Size l3_saved_size = l3.Size; + l3.Text = "Text"; + Assert.AreNotEqual (l3_saved_size, l3.Size, "#2"); + p3.ResumeLayout (); + } + } [TestFixture] public class LabelEventTest : TestHelper diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ListBoxTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ListBoxTest.cs index ce2032a93a..bd02ba088c 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ListBoxTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ListBoxTest.cs @@ -489,7 +489,6 @@ namespace MonoTests.System.Windows.Forms listBox.SelectedIndices.Add (0); Assert.Fail ("#B"); } catch (InvalidOperationException e) { - Console.WriteLine (e.Message); } try { diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/MaskedTextBoxTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/MaskedTextBoxTest.cs index cad0285caa..ccb04b07c4 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/MaskedTextBoxTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/MaskedTextBoxTest.cs @@ -937,6 +937,7 @@ namespace MonoTests.System.Windows.Forms case Keys.Right: case Keys.Up: case Keys.Down: + case Keys.Back: is_input = true; break; } diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/MdiFormHandleTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/MdiFormHandleTest.cs index b5d7bf94b5..8b2b257ec1 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/MdiFormHandleTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/MdiFormHandleTest.cs @@ -1096,16 +1096,14 @@ namespace MonoTests.System.Windows.Forms [Test] public void Show () { + bool handle_created_called = false; + SetUp (); Assert.IsFalse (child1.IsHandleCreated, "A1"); - child1.HandleCreated += new EventHandler (HandleCreated_WriteStackTrace); + child1.HandleCreated += (sender, e) => handle_created_called = true; child1.Show (); - Assert.IsTrue (child1.IsHandleCreated, "A2"); - } - - void HandleCreated_WriteStackTrace (object sender, EventArgs e) - { - Console.WriteLine ("Stacktrace?");//Environment.StackTrace); + Assert.IsTrue (handle_created_called, "A2"); + Assert.IsTrue (child1.IsHandleCreated, "A3"); } public delegate void InvokeDelegate (); diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/MenuItemTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/MenuItemTest.cs index 7c13926785..55498ef4cb 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/MenuItemTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/MenuItemTest.cs @@ -253,8 +253,8 @@ namespace MonoTests.System.Windows.Forms Assert.AreEqual(mi1.Text, mi2.Text, "Text #1"); Assert.AreEqual(mi1.Visible, mi2.Visible, "Visible #1"); - Assert.AreEqual(mi1.Name, mi2.Name, "Name #1"); - Assert.AreEqual(mi1.Tag, mi2.Tag, "Tag #1"); + Assert.AreEqual("", mi2.Name, "Name #1"); + Assert.AreEqual(null, mi2.Tag, "Tag #1"); mi1.BarBreak = false; mi1.Break = false; @@ -288,8 +288,8 @@ namespace MonoTests.System.Windows.Forms Assert.AreEqual(mi1.ShowShortcut, mi2.ShowShortcut, "ShowShortcut #2"); Assert.AreEqual(mi1.Text, mi2.Text, "Text #2"); Assert.AreEqual(mi1.Visible, mi2.Visible, "Visible #2"); - Assert.AreEqual(mi1.Name, mi2.Name, "Name #2"); - Assert.AreEqual(mi1.Tag, mi2.Tag, "Tag #2"); + Assert.AreEqual("", mi2.Name, "Name #2"); + Assert.AreEqual(null, mi2.Tag, "Tag #2"); } [Test] diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/NotifyIconTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/NotifyIconTest.cs index e99ae188a5..e021ffa92f 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/NotifyIconTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/NotifyIconTest.cs @@ -42,8 +42,10 @@ namespace MonoTests.System.Windows.Forms ni.BalloonTipTitle = "Balloon Tip Title"; ni.BalloonTipText = "Balloon Tip Text."; ni.BalloonTipIcon = ToolTipIcon.None; + ni.Icon = SystemIcons.Information; ni.Visible = true; ni.ShowBalloonTip (1); + ni.Dispose (); } } } diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/PrintPreviewControlTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/PrintPreviewControlTest.cs new file mode 100644 index 0000000000..402d42db63 --- /dev/null +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/PrintPreviewControlTest.cs @@ -0,0 +1,69 @@ +// 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. +// +// Copyright (c) 2018 Filip Navara +// + +using System; +using System.Drawing; +using System.Drawing.Printing; +using System.Windows.Forms; +using NUnit.Framework; + +namespace MonoTests.System.Windows.Forms +{ + [TestFixture] + public class PrintPreviewControlTest + { + [Test] + public void StartPage () + { + if (PrinterSettings.InstalledPrinters.Count == 0) + Assert.Ignore ("The test depends on printer being available."); + + using (Form f = new Form ()) + { + PrintPreviewControl p = new PrintPreviewControl (); + f.Controls.Add (p); + f.Show (); + + Assert.AreEqual (0, p.StartPage); + Assert.AreEqual (1, p.Rows); + Assert.AreEqual (1, p.Columns); + p.StartPage = 4; + Assert.AreEqual (4, p.StartPage); + + PrintDocument document = new PrintDocument (); + int page_number = 0; + int page_count = 1; + document.BeginPrint += (sender, e) => page_number = 0; + document.PrintPage += (sender, e) => e.HasMorePages = ++page_number < page_count; + + p.Document = document; + p.Refresh (); + Assert.AreEqual (0, p.StartPage); + + page_count = 8; + p.InvalidatePreview (); + p.Refresh (); + Assert.AreEqual (4, p.StartPage); + } + } + } +} diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ScrollBarTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ScrollBarTest.cs index c07388d612..e7c59f37c0 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ScrollBarTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ScrollBarTest.cs @@ -589,21 +589,6 @@ public class MyScrollBar : HScrollBar myform.Dispose (); } - [Test] - public void ImeModehangedTest () - { - Form myform = new Form (); - myform.ShowInTaskbar = false; - myform.Visible = true; - ScrollBar myHscrlbar = new HScrollBar (); - myform.Controls.Add (myHscrlbar); - myHscrlbar.ImeModeChanged += new EventHandler (ScrollBar_EventHandler); - myHscrlbar.ImeMode = ImeMode.Katakana; - Assert.AreEqual (true, eventhandled, "I2"); - eventhandled = false; - myform.Dispose (); - } - //[Test] //public void MouseDownTest () // { diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ScrollableControlTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ScrollableControlTest.cs index 57a8298ed0..00096aa420 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ScrollableControlTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ScrollableControlTest.cs @@ -341,6 +341,8 @@ namespace MonoTests.System.Windows.Forms scrollable.PerformLayout (); Assert.AreEqual (true, scrollable.VerticalScroll.Visible, "#C0"); + + f.Close(); } // Tests Xamarin-2562 @@ -377,5 +379,25 @@ namespace MonoTests.System.Windows.Forms Assert.AreEqual (4, c.DockPadding.All); } } + + [Test] + public void DisplayRectangeTest () + { + using (var sc = new ScrollableControl ()) + { + sc.Size = new Size (100, 100); + sc.AutoScroll = true; + + Control c; + c = new Control (); + c.Location = new Point (0, 0); + c.Size = new Size (200, 200); + sc.Controls.Add (c); + Assert.AreEqual (new Rectangle (0, 0, 200, 200), sc.DisplayRectangle); + + c.Visible = false; + Assert.AreEqual (new Rectangle (0, 0, 100, 100), sc.DisplayRectangle); + } + } } } diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/StatusStripTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/StatusStripTest.cs index eed45f2822..1455fecf74 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/StatusStripTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/StatusStripTest.cs @@ -56,6 +56,7 @@ namespace MonoTests.System.Windows.Forms Assert.AreEqual (ToolStripRenderMode.System, ts.RenderMode, "A11"); Assert.AreEqual ("System.Windows.Forms.StatusStrip+StatusStripAccessibleObject", ts.AccessibilityObject.GetType ().ToString ()); + Assert.AreEqual ("System.Windows.Forms.Layout.TableLayout", ts.LayoutEngine.ToString ()); } [Test] @@ -185,6 +186,34 @@ namespace MonoTests.System.Windows.Forms Assert.AreEqual (false, ts.Stretch, "B1"); } + [Test] + public void Layout () + { + StatusStrip ss = new StatusStrip(); + ToolStripStatusLabel label; + + ss.SuspendLayout (); + ss.Items.Add (""); + ss.Items.Add (label = new ToolStripStatusLabel("")); + ss.Items.Add (""); + ss.ResumeLayout (); + + Assert.AreEqual (new Rectangle (0, 0, 200, 22), ss.Bounds); + Assert.AreEqual (new Rectangle (188, 0, 12, 22), ss.SizeGripBounds); + Assert.AreEqual (new Size (0, 17), ss.Items[0].Size); + Assert.AreEqual (new Size (0, 17), label.Size); + + Assert.AreEqual (new Rectangle (1, 3, 0, 17), ss.Items[0].Bounds); + Assert.AreEqual (new Rectangle (1, 3, 0, 17), ss.Items[1].Bounds); + Assert.AreEqual (new Rectangle (1, 3, 0, 17), ss.Items[2].Bounds); + + label.Spring = true; + + Assert.AreEqual (new Rectangle(1, 3, 0, 17), ss.Items[0].Bounds); + Assert.AreEqual (new Rectangle(1, 3, 185, 17), ss.Items[1].Bounds); + Assert.AreEqual (new Rectangle(186, 3, 0, 17), ss.Items[2].Bounds); + } + private class ExposeProtectedProperties : StatusStrip { public new DockStyle DefaultDock { get { return base.DefaultDock; } } diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/TabControlTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/TabControlTest.cs index 97c3c3ae88..d4dd56391f 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/TabControlTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/TabControlTest.cs @@ -724,6 +724,8 @@ namespace MonoTests.System.Windows.Forms b2.Focus (); Assert.AreEqual ("tc_OnGotFocus0;p2_OnEnter1;tc_OnSelectedIndexChanged1;", events, "A1"); Assert.IsTrue (tc.Focused, "A2"); + + f.Close (); } // Make sure that setting focus for TabControl is *not* resetting SelectedIndex when @@ -749,6 +751,8 @@ namespace MonoTests.System.Windows.Forms tc.Focus (); Assert.AreEqual (-1, tc.SelectedIndex, "#A0"); + + f.Close (); } } diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/TableLayoutTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/TableLayoutTest.cs index 18271cfba2..73d4e67f9b 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/TableLayoutTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/TableLayoutTest.cs @@ -517,7 +517,6 @@ namespace MonoTests.System.Windows.Forms } [Test] - [Category ("NotWorking")] public void TestCellPositioning14 () { // Col span = 3, fixed grow style diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/TestHelper.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/TestHelper.cs index 0d11647eaa..6a7101b00a 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/TestHelper.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/TestHelper.cs @@ -33,6 +33,7 @@ namespace MonoTests.System.Windows.Forms if (c > 0) { Console.WriteLine ("HEY! You created " + c.ToString () + " form(s) and you didn't dispose of them!"); Console.WriteLine ("Please modify your test to shut me up."); + Console.WriteLine ("Test: " + NUnit.Framework.TestContext.CurrentContext.Test.FullName); } for (int i = Application.OpenForms.Count - 1; i >= 0; i--) { Application.OpenForms[i].Dispose (); diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/TextBoxTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/TextBoxTest.cs index 9ae9d4122f..265230186b 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/TextBoxTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/TextBoxTest.cs @@ -10,6 +10,7 @@ using System.ComponentModel; using System.Drawing; using System.Reflection; using System.Windows.Forms; +using System.Text; using NUnit.Framework; using CategoryAttribute = NUnit.Framework.CategoryAttribute; @@ -35,7 +36,6 @@ namespace MonoTests.System.Windows.Forms } [Test] - [Category ("NotWorking")] public void TextBoxBasePropertyTest () { Assert.AreEqual (false, textBox.AcceptsTab, "#1a"); @@ -206,7 +206,7 @@ namespace MonoTests.System.Windows.Forms [Test] public void BackColorTest () { - Assert.AreEqual (SystemColors.Control, textBox.BackColor, "#A1"); + Assert.AreEqual (SystemColors.Window, textBox.BackColor, "#A1"); textBox.BackColor = Color.Red; Assert.AreEqual (Color.Red, textBox.BackColor, "#A2"); textBox.BackColor = Color.White; @@ -348,6 +348,18 @@ namespace MonoTests.System.Windows.Forms Assert.AreEqual (25, textBox.PreferredHeight, "#B3"); } + [Test] + public void PreferredSizeTest () + { + textBox.Size = new Size (1, textBox.PreferredHeight); + textBox.Text = "Text"; + Size saved_preferred_size = textBox.PreferredSize; + // Ensure that the preferred size reflects the Text + Assert.AreNotEqual (saved_preferred_size, textBox.Size); + textBox.Text = "Long Text"; + Assert.AreNotEqual (saved_preferred_size, textBox.PreferredSize); + } + [Test] public void SelectTest () { @@ -414,8 +426,7 @@ namespace MonoTests.System.Windows.Forms form.Dispose (); } - [Test] - [Category ("NotWorking")] + [Test] public void ForeColorTest () { Assert.AreEqual (SystemColors.WindowText, textBox.ForeColor, "#A1"); @@ -446,6 +457,8 @@ namespace MonoTests.System.Windows.Forms Assert.AreEqual (Color.Blue, textBox.ForeColor, "#B10"); Assert.AreEqual (2, _invalidated, "#B11"); Assert.AreEqual (0, _paint, "#B12"); + + form.Close (); } [Test] @@ -712,6 +725,52 @@ namespace MonoTests.System.Windows.Forms f.Dispose (); } + [Test] + public void Bug6357 () + { + Form f = new Form (); + f.ShowInTaskbar = false; + f.Visible = true; + f.ClientSize = new Size (300, 130); + textBox.Visible = true; + textBox.AppendText( + "Achtung! Passwort für URL angepasst! Anführungszeichen im Passwort funktionieren in URL nur mit Escape.\r\n" + + "\r\n" + + "{S:fileFilepath} -> {S:##volumeDriveLetter}:\\\r\n" + + "\r\n" + + "Verschlüsselter Kontainer (VeraCrypt).\r\n" + + "\r\n" + + "URL-Anmerkungen:\r\n" + + "- nur für Windows\r\n" + + "- volumeDriveLetter muss frei sein\r\n" + + "\r\n" + + "veracrypt --mount /media/NAS_container_flo/test.vc -p '1 1' --fs-options=X-mount.mkdir=0700 /media/vera\r\n" + + "\r\n" + + "cmd://veracrypt --mount {S:fFilepath} -p '{PASSWORD}' --pim='{S:#pim}' --fs-options=X-mount.mkdir=0700 {S:mPoint}" + + "\r\n" + + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\n" + + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); + textBox.Multiline = true; + textBox.ScrollBars = ScrollBars.Vertical; + textBox.Dock = DockStyle.Fill; + f.Controls.Add (textBox); + + Assert.AreEqual (textBox.TextLength, textBox.SelectionStart); + + textBox.Focus (); + // Select a bit of the text + SendKeys.SendWait ("+{UP}"); + SendKeys.SendWait ("+{UP}"); + SendKeys.SendWait ("+{UP}"); + SendKeys.SendWait ("+{UP}"); + SendKeys.SendWait ("+{UP}"); + SendKeys.SendWait ("{BS}"); // Remove the text with Backspace + Assert.AreEqual (0, textBox.SelectionLength); + + f.Dispose (); + } + + [Test] public void ModifiedEventTest () { diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/TimerTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/TimerTest.cs index 110dc71a66..976349758d 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/TimerTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/TimerTest.cs @@ -142,8 +142,13 @@ namespace MonoTests.System.Windows.Forms [Test] // bug #325033 public void RunningThread () { - Application.Run (new Bug325033Form ()); - Application.Run (new Bug325033Form2 ()); + var f1 = new Bug325033Form (); + Application.Run (f1); + var f2 = new Bug325033Form2 (); + Application.Run (f2); + + f1.Dispose (); + f2.Dispose (); } class Bug325033Form : Form diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ToolStripControlHostTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ToolStripControlHostTest.cs index baec48a796..895e3732b1 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ToolStripControlHostTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ToolStripControlHostTest.cs @@ -108,7 +108,7 @@ namespace MonoTests.System.Windows.Forms Assert.AreEqual (SystemColors.Control, tsi.BackColor, "B4"); tsi = new ToolStripControlHost (new TextBox ()); - Assert.AreEqual (SystemColors.Control, tsi.BackColor, "B5"); + Assert.AreEqual (SystemColors.Window, tsi.BackColor, "B5"); tsi = new ToolStripControlHost (new ProgressBar ()); Assert.AreEqual (SystemColors.Control, tsi.BackColor, "B6"); @@ -239,7 +239,7 @@ namespace MonoTests.System.Windows.Forms Assert.AreEqual (SystemColors.ControlText, tsi.ForeColor, "B4"); tsi = new ToolStripControlHost (new TextBox ()); - Assert.AreEqual (SystemColors.ControlText, tsi.ForeColor, "B5"); + Assert.AreEqual (SystemColors.WindowText, tsi.ForeColor, "B5"); } [Test] diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ToolStripDropDownTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ToolStripDropDownTest.cs index 20856807e6..04f073c425 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ToolStripDropDownTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ToolStripDropDownTest.cs @@ -112,8 +112,11 @@ namespace MonoTests.System.Windows.Forms Assert.AreEqual ("System.Windows.Forms.FlowLayoutSettings", ts.PublicCreateLayoutSettings (ToolStripLayoutStyle.Flow).ToString (), "A1"); Assert.AreEqual (null, ts.PublicCreateLayoutSettings (ToolStripLayoutStyle.HorizontalStackWithOverflow), "A2"); Assert.AreEqual (null, ts.PublicCreateLayoutSettings (ToolStripLayoutStyle.StackWithOverflow), "A3"); - //Assert.AreEqual ("System.Windows.Forms.TableLayoutSettings", ts.PublicCreateLayoutSettings (ToolStripLayoutStyle.Table).ToString (), "A4"); + Assert.AreEqual ("System.Windows.Forms.TableLayoutSettings", ts.PublicCreateLayoutSettings (ToolStripLayoutStyle.Table).ToString (), "A4"); Assert.AreEqual (null, ts.PublicCreateLayoutSettings (ToolStripLayoutStyle.VerticalStackWithOverflow), "A5"); + + FlowLayoutSettings flow_settings = (FlowLayoutSettings) ts.PublicCreateLayoutSettings (ToolStripLayoutStyle.Flow); + Assert.AreEqual (FlowDirection.TopDown, flow_settings.FlowDirection, "A6"); } //[Test] diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ToolStripItemTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ToolStripItemTest.cs index b19514164b..1d4628a405 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ToolStripItemTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ToolStripItemTest.cs @@ -821,7 +821,7 @@ namespace MonoTests.System.Windows.Forms Assert.AreEqual (null, ao.Name, "L6"); //Assert.AreEqual (null, ao.Parent, "L7"); Assert.AreEqual (AccessibleRole.ToolBar, ao.Role, "L8"); - Assert.AreEqual (AccessibleStates.None, ao.State, "L9"); + Assert.AreEqual (AccessibleStates.Focusable, ao.State, "L9"); Assert.AreEqual (null, ao.Value, "L10"); ts.Name = "Label1"; @@ -836,7 +836,7 @@ namespace MonoTests.System.Windows.Forms //Assert.AreEqual ("Test Label", ao.Name, "L16"); //Assert.AreEqual (null, ao.Parent, "L17"); Assert.AreEqual (AccessibleRole.ToolBar, ao.Role, "L18"); - Assert.AreEqual (AccessibleStates.None, ao.State, "L19"); + Assert.AreEqual (AccessibleStates.Focusable, ao.State, "L19"); Assert.AreEqual (null, ao.Value, "L20"); ts.AccessibleName = "Access Label"; diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ToolStripManagerTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ToolStripManagerTest.cs index f0f27f3776..5da21fb215 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ToolStripManagerTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ToolStripManagerTest.cs @@ -586,19 +586,19 @@ namespace MonoTests.System.Windows.Forms } [Test] + [ExpectedException (typeof (ArgumentNullException))] public void MethodRevertMergeNullArgument2 () { ToolStrip ts = null; - - Assert.AreEqual (false, ToolStripManager.RevertMerge (ts), "C2"); + ToolStripManager.RevertMerge (ts); } [Test] + [ExpectedException (typeof (ArgumentNullException))] public void MethodRevertMergeNullArgument3 () { ToolStrip ts = new ToolStrip (); - - Assert.AreEqual (false, ToolStripManager.RevertMerge (ts, null), "C3"); + ToolStripManager.RevertMerge (ts, null); } [Test] diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ToolStripOverflowTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ToolStripOverflowTest.cs index 3ef7a589f0..351832337b 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ToolStripOverflowTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ToolStripOverflowTest.cs @@ -38,7 +38,6 @@ namespace MonoTests.System.Windows.Forms public class ToolStripOverflowTests : TestHelper { [Test] - [Category ("NotWorking")] public void Constructor () { ToolStripOverflow tso = (ToolStripOverflow)new ToolStrip ().OverflowButton.DropDown; diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ToolStripTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ToolStripTest.cs index cdf1f0dfc7..d32dd9861b 100644 --- a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ToolStripTest.cs +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ToolStripTest.cs @@ -59,7 +59,7 @@ namespace MonoTests.System.Windows.Forms Assert.AreEqual (ToolStripDropDownDirection.BelowRight, ts.DefaultDropDownDirection, "A11"); Assert.AreEqual (new Rectangle (7, 0, 92, 25), ts.DisplayRectangle, "A12"); Assert.AreEqual (DockStyle.Top, ts.Dock, "A13"); - Assert.AreEqual (new Font ("Tahoma", 8.25f), ts.Font, "A14"); + Assert.AreEqual (SystemFonts.MessageBoxFont, ts.Font, "A14"); Assert.AreEqual (SystemColors.ControlText, ts.ForeColor, "A15"); Assert.AreEqual (ToolStripGripDisplayStyle.Vertical, ts.GripDisplayStyle, "A16"); Assert.AreEqual (new Padding (2), ts.GripMargin, "A17"); @@ -458,6 +458,16 @@ namespace MonoTests.System.Windows.Forms ew.Clear (); ts.LayoutStyle = ToolStripLayoutStyle.VerticalStackWithOverflow; Assert.AreEqual (string.Empty, ew.ToString (), "B3"); + + ew.Clear (); + ts.LayoutStyle = ToolStripLayoutStyle.Flow; + Assert.AreEqual ("LayoutCompleted;LayoutStyleChanged", ew.ToString (), "B4"); + Assert.AreEqual (typeof (FlowLayoutSettings), ts.LayoutSettings.GetType(), "B5"); + + ew.Clear (); + ts.LayoutStyle = ToolStripLayoutStyle.Table; + Assert.AreEqual ("LayoutCompleted;LayoutStyleChanged", ew.ToString (), "B6"); + Assert.AreEqual (typeof (TableLayoutSettings), ts.LayoutSettings.GetType(), "B7"); } [Test] diff --git a/mcs/class/System.XML/Makefile b/mcs/class/System.XML/Makefile index 59a3bae402..3031c13c3c 100644 --- a/mcs/class/System.XML/Makefile +++ b/mcs/class/System.XML/Makefile @@ -4,15 +4,6 @@ include ../../build/rules.make LIBRARY = System.Xml.dll -lib_file := $(wildcard ../lib/$(PROFILE)/System.Xml.dll) -ifndef lib_file -USE_BOOT_COMPILE = yes -endif - -ifdef USE_BOOT_COMPILE -LIBRARY_COMPILE = $(BOOT_COMPILE) -endif - TXT_RESOURCE_STRINGS = \ ../referencesource/System.Xml/System.Xml.txt \ ../referencesource/System.Data.SqlXml/System.Xml.Utils.txt @@ -28,15 +19,12 @@ TEST_MCS_FLAGS = $(LIB_MCS_FLAGS) -nowarn:0618 -nowarn:219 -nowarn:169 LIBRARY_WARN_AS_ERROR = yes -ifneq (bare/,$(intermediate)) -LIB_REFS += secxml/System +LIB_REFS = System + ifndef MOBILE_PROFILE -LIB_REFS += System.Configuration +API_BIN_REFS += System.Configuration LIB_MCS_FLAGS += -d:CONFIGURATION_DEP endif -else -LIB_REFS += $(intermediate)System -endif nist_dom_files = \ ITest.cs readme.txt util.cs \ @@ -64,40 +52,3 @@ EXTRA_DISTFILES = \ $(nist_dom_files:%=Test/System.Xml/nist_dom/%) include ../../build/library.make - -ifeq (bare/,$(intermediate)) -build-bare: -else -$(bare_libdir)/System.Xml.dll: - $(MAKE) intermediate=bare/ $(bare_libdir)/System.Xml.dll -endif - -system_xml_library_deps := \ - $(bare_libdir)/System.dll \ - $(bare_libdir)/System.Xml.dll - -ifndef MOBILE_PROFILE -system_xml_library_deps += $(the_libdir_base)System.Configuration.dll -endif - -artifacts = $(system_xml_library_deps) \ - $(the_libdir_base)System.Configuration.dll - -.NOTPARALLEL: $(artifacts) - -CLEAN_FILES = $(bare_libdir)/System.Xml.dll $(bare_libdir)/System.Xml.dll.pdb -$(the_libdir_base)System.Xml.dll: $(system_xml_library_deps) -$(bare_libdir)/System.dll: - (cd ../System; $(MAKE) $@) -$(bare_libdir)/System.Xml.dll: $(bare_libdir)/System.dll - -$(the_libdir_base)System.Configuration.dll: - (cd ../System.Configuration; $(MAKE) $@) - - -ifndef intermediate -ifneq ($(PROFILE),basic) -csproj-local: - $(MAKE) csproj-local intermediate=bare/ -endif -endif diff --git a/mcs/class/System.Xml.Linq/Makefile b/mcs/class/System.Xml.Linq/Makefile index 3b058bd9c4..c2355bac19 100644 --- a/mcs/class/System.Xml.Linq/Makefile +++ b/mcs/class/System.Xml.Linq/Makefile @@ -16,8 +16,8 @@ ifeq (2.1, $(FRAMEWORK_VERSION)) LIB_MCS_FLAGS += -d:MONO_HYBRID_SYSTEM_XML endif -TEST_MCS_FLAGS = $(LIB_MCS_FLAGS) - +TEST_LIB_REFS = System.Core System.Xml System +TEST_MCS_FLAGS = EXTRA_DISTFILES = include ../../build/library.make diff --git a/mcs/class/System.Xml.Linq/System.Xml.Linq.dll.sources b/mcs/class/System.Xml.Linq/System.Xml.Linq.dll.sources index bb17125d98..35b1d72966 100644 --- a/mcs/class/System.Xml.Linq/System.Xml.Linq.dll.sources +++ b/mcs/class/System.Xml.Linq/System.Xml.Linq.dll.sources @@ -3,3 +3,5 @@ Assembly/AssemblyInfo.cs ../referencesource/System.Xml.Linq/System/Xml/Linq/XNodeNavigator.cs ../referencesource/System.Xml.Linq/System/Xml/Linq/XLinq.cs ../referencesource/System.Xml.Linq/System/Xml/Linq/XComponentModel.cs + +../../../external/corefx/src/System.Xml.XPath.XDocument/src/System/Xml/XPath/XDocumentExtensions.cs diff --git a/mcs/class/System/Makefile b/mcs/class/System/Makefile index 3cff1fb25b..e3c2adc9f6 100644 --- a/mcs/class/System/Makefile +++ b/mcs/class/System/Makefile @@ -30,13 +30,12 @@ TEST_RESOURCES = \ USE_XTEST_REMOTE_EXECUTOR = YES XTEST_LIB_REFS = System System.Core System.Net Facades/System.Threading.Tasks Facades/System.Runtime.InteropServices.RuntimeInformation System.Net.Http -LIB_MCS_FLAGS = -d:CONFIGURATION_2_0 $(REFERENCE_SOURCES_FLAGS) -unsafe $(RESOURCE_FILES:%=-resource:%) -nowarn:436 +LIB_MCS_FLAGS = -d:COREFX -d:CONFIGURATION_2_0 -d:XML_DEP -d:SECURITY_DEP $(REFERENCE_SOURCES_FLAGS) -unsafe $(RESOURCE_FILES:%=-resource:%) -nowarn:436 ifndef NO_MONO_SECURITY -MONO_SECURITY=Mono.Security -MONO_SECURITY_REF=MonoSecurity=Mono.Security -MONO_SECURITY_DLL=$(the_libdir_base)Mono.Security.dll -EXTERN_ALIAS_FLAGS = -d:MONO_SECURITY_ALIAS +MONO_SECURITY := Mono.Security +LIB_MCS_FLAGS += -d:MONO_SECURITY_ALIAS +LIB_REFS += MonoSecurity=Mono.Security else LIB_MCS_FLAGS += -d:INSIDE_SYSTEM endif @@ -69,6 +68,10 @@ ifdef MONO_FEATURE_APPLETLS LIB_MCS_FLAGS += -d:MONO_FEATURE_APPLETLS endif +ifndef AOT_FRIENDLY_PROFILE +LIB_MCS_FLAGS += -d:FEATURE_COMPILED +endif + ifdef ONLY_APPLETLS LIB_MCS_FLAGS += -d:ONLY_APPLETLS endif @@ -99,34 +102,17 @@ endif TXT_RESOURCE_STRINGS = ../referencesource/System/System.txt -API_BIN_REFS := System.Net.Http - -# -# Flags used to build the secxml version of System. -# -ifeq (secxml/, $(intermediate)) -LOCAL_MCS_FLAGS = -LIB_REFS += bare/System.Xml $(MONO_SECURITY_REF) -LIB_MCS_FLAGS += -d:SECURITY_DEP -d:XML_DEP $(EXTERN_ALIAS_FLAGS) -endif - -# -# Flags used to build the final version of System (when intermediate is not defined) -# -ifndef intermediate -LIB_REFS += System.Xml $(MONO_SECURITY_REF) -LIB_MCS_FLAGS += -d:SECURITY_DEP -d:XML_DEP $(EXTERN_ALIAS_FLAGS) +API_BIN_REFS := System.Net.Http System.Xml ifndef MOBILE_PROFILE -LIB_REFS += System.Configuration +API_BIN_REFS += System.Configuration LIB_MCS_FLAGS += -d:CONFIGURATION_DEP endif -endif - EXTRA_DISTFILES = \ common.sources \ common_networking.sources \ + corefx.unix.sources \ Test/test-config-file \ Test/System.Security.Cryptography.X509Certificates/pkits/Makefile \ Test/System.Security.Cryptography.X509Certificates/pkits/README \ @@ -136,69 +122,8 @@ EXTRA_DISTFILES = \ include ../../build/library.make -system_library_deps := \ - $(secxml_libdir)/System.dll \ - $(the_libdir_base)System.Xml.dll \ - $(MONO_SECURITY_DLL) \ - $(bare_libdir)/System.dll - -ifndef MOBILE_PROFILE -system_library_deps += $(the_libdir_base)System.Configuration.dll -endif - -artifacts = $(system_library_deps) \ - $(bare_libdir)/System.Xml.dll \ - $(MONO_SECURITY_DLL) \ - $(the_libdir_base)System.Configuration.dll - -.NOTPARALLEL: $(system_library_deps) - -$(the_libdir_base)System.dll: $(system_library_deps) ../Mono.Security/Makefile - -ifeq (bare/,$(intermediate)) -build-bare: -else -$(bare_libdir)/System.dll: - $(MAKE) intermediate=bare/ $(bare_libdir)/System.dll -endif - -ifneq (secxml/,$(intermediate)) -$(secxml_libdir)/System.dll: $(bare_libdir)/System.dll $(bare_libdir)/System.Xml.dll $(MONO_SECURITY_DLL) $(bare_libdir)/System.dll - $(MAKE) intermediate=secxml/ $(secxml_libdir)/System.dll -else -build-sec: -endif - -$(the_libdir_base)System.Xml.dll: - (cd ../System.XML; $(MAKE) $@) - -$(bare_libdir)/System.Xml.dll: - (cd ../System.XML; $(MAKE) $@) - -$(the_libdir_base)Mono.Security.dll: ../Mono.Security/Makefile - (cd ../Mono.Security; $(MAKE)) - -$(the_libdir_base)System.Configuration.dll: - (cd ../System.Configuration; $(MAKE)) - -$(build_lib): $(CYCLIC_DEP_FILES) - $(test_lib_output): $(TEST_RESOURCES) $(test_lib_dir) -CLEAN_FILES = $(test_lib).config $(bare_libdir)/System.dll $(secxml_libdir)/System.dll $(bare_libdir)/System.dll.mdb $(secxml_libdir)/System.dll.mdb - # Helper target to run the perl regex test suite regex-check: $(MAKE) check FIXTURE=System.Text.RegularExpressions.PerlTest - -#Debuging target -fresh: clean - rm -rf ../../class/lib/$(PROFILE)/bare ../../class/lib/$(PROFILE)/bare/ $(system_library_deps) - -ifndef intermediate -ifneq ($(PROFILE),basic) -csproj-local: - $(MAKE) csproj-local intermediate=bare/ - $(MAKE) csproj-local intermediate=secxml/ -endif -endif diff --git a/mcs/class/System/System.IO/CoreFXFileSystemWatcherProxy.cs b/mcs/class/System/System.IO/CoreFXFileSystemWatcherProxy.cs new file mode 100644 index 0000000000..92e04c3445 --- /dev/null +++ b/mcs/class/System/System.IO/CoreFXFileSystemWatcherProxy.cs @@ -0,0 +1,189 @@ +// Bridges the Mono and CoreFX FileSystemWatcher types. + +using System.Collections.Generic; +using System.Collections.Concurrent; +using System.Threading; +using System.Threading.Tasks; +using System.Runtime.CompilerServices; + +using C = System.IO.CoreFX.FileSystemWatcher; +using M = System.IO.FileSystemWatcher; +using Handle = System.Object; + +namespace System.IO { + + internal class CoreFXFileSystemWatcherProxy : IFileWatcher + { + static IFileWatcher instance; // Mono FSW objects -> this + static IDictionary internal_map; // this -> CoreFX FSW objects + static ConditionalWeakTable external_map; // this -> Mono FSW objects + static IDictionary event_map; // CoreFX FSW events -> this + + const int INTERRUPT_MS = 300; + + protected void Operation (Action, ConditionalWeakTable, IDictionary, Handle> map_op = null, Action object_op = null, object handle = null, Action cancel_op = null) + { + C internal_fsw = null; + M fsw = null; + bool live, havelock; + + if (cancel_op != null) { // highest priority and must not lock + havelock = Monitor.TryEnter (instance, INTERRUPT_MS); + live = (handle != null && (internal_map.TryGetValue (handle, out internal_fsw) || external_map.TryGetValue (handle, out fsw))) ; + if (live && havelock) + try { cancel_op (internal_fsw, fsw); } + catch (Exception) { }; + + if (havelock) + Monitor.Exit (instance); + if (live && !havelock) + try { + var t = Task.Run( () => { cancel_op (internal_fsw, fsw); return true;}); + t.Wait (INTERRUPT_MS); + } + catch (Exception) { }; + return; + } + if (map_op != null && handle == null) { + lock (instance) { + try { map_op (internal_map, external_map, event_map, null); } + catch (Exception e) { throw new InvalidOperationException (nameof(map_op), e); } + } + return; + } + + if (handle == null) + return; + + lock (instance) { + live = (internal_map.TryGetValue (handle, out internal_fsw) && external_map.TryGetValue (handle, out fsw)) ; + if (live && map_op != null) { + try { map_op (internal_map, external_map, event_map, handle); } + catch (Exception e) { throw new InvalidOperationException (nameof(map_op), e); }; + } + } + if (!live || object_op == null) + return; + + try { object_op (internal_fsw, fsw); } + catch (Exception e) { throw new InvalidOperationException (nameof(object_op), e); }; + } + + protected void ProxyDispatch (object sender, FileAction action, FileSystemEventArgs args) + { + RenamedEventArgs renamed = + action == FileAction.RenamedNewName ? (RenamedEventArgs) args : null; + + object handle = null; + + Operation (map_op: (in_map, out_map, event_map, h) => event_map.TryGetValue (sender, out handle)); + + Operation (object_op: (_, fsw) => { + if (!fsw.EnableRaisingEvents) + return; + fsw.DispatchEvents (action, args.Name, ref renamed); + if (fsw.Waiting) { + fsw.Waiting = false; + System.Threading.Monitor.PulseAll (fsw); + } + }, handle: handle); + } + + protected void ProxyDispatchError (object sender, ErrorEventArgs args) + { + object handle = null; + + Operation (map_op: (in_map, out_map, event_map, _) => event_map.TryGetValue (sender, out handle)); + + Operation (object_op: (_, fsw) => fsw.DispatchErrorEvents (args), + handle: handle); + } + + public object NewWatcher (M fsw) + { + var handle = new object (); + var result = new C (); + + result.Changed += (object o, FileSystemEventArgs args) => + { ProxyDispatch (o, FileAction.Modified, args); }; + result.Created += (object o, FileSystemEventArgs args) => + { ProxyDispatch (o, FileAction.Added, args); }; + result.Deleted += (object o, FileSystemEventArgs args) => + { ProxyDispatch (o, FileAction.Removed, args); }; + result.Renamed += (object o, RenamedEventArgs args) => + { ProxyDispatch (o, FileAction.RenamedNewName, args); }; + + result.Error += (object o, ErrorEventArgs args) => + { ProxyDispatchError (handle, args); }; + + Operation (map_op: (in_map, out_map, event_map, _) => { + in_map.Add (handle, result); + out_map.Add (handle, fsw); + event_map.Add (result, handle); + }); + + return handle; + } + + public void StartDispatching (object handle) + { + if (handle == null) + return; + + Operation (object_op: (internal_fsw, fsw) => { + internal_fsw.Path = fsw.Path; + internal_fsw.Filter = fsw.Filter; + internal_fsw.IncludeSubdirectories = fsw.IncludeSubdirectories; + internal_fsw.InternalBufferSize = fsw.InternalBufferSize; + internal_fsw.NotifyFilter = fsw.NotifyFilter; + internal_fsw.Site = fsw.Site; + internal_fsw.EnableRaisingEvents = true; + }, handle: handle); + } + + public void StopDispatching (object handle) + { + if (handle == null) + return; + + Operation (handle: handle, + cancel_op: (internal_fsw, fsw) => + { + if (internal_fsw != null) + internal_fsw.EnableRaisingEvents = false; + + }); + } + + public void Dispose (object handle) + { + if (handle == null) + return; + + Operation (handle: handle, + cancel_op: (internal_fsw, fsw) => { + if (internal_fsw != null) + internal_fsw.Dispose (); + var inner_key = internal_map [handle]; + internal_map.Remove (handle); + external_map.Remove (handle); + event_map.Remove (inner_key); + handle = null; + }); + } + + public static bool GetInstance (out IFileWatcher watcher) + { + if (instance != null) { + watcher = instance; + return true; + } + + internal_map = new ConcurrentDictionary (); + external_map = new ConditionalWeakTable (); + event_map = new ConcurrentDictionary (); + instance = watcher = new CoreFXFileSystemWatcherProxy (); + return true; + } + } +} diff --git a/mcs/class/System/System.IO/DefaultWatcher.cs b/mcs/class/System/System.IO/DefaultWatcher.cs index cbda2b294a..28186f8451 100644 --- a/mcs/class/System/System.IO/DefaultWatcher.cs +++ b/mcs/class/System/System.IO/DefaultWatcher.cs @@ -79,8 +79,9 @@ namespace System.IO { return true; } - public void StartDispatching (FileSystemWatcher fsw) + public void StartDispatching (object handle) { + var fsw = handle as FileSystemWatcher; DefaultWatcherData data; lock (this) { if (watches == null) @@ -116,8 +117,9 @@ namespace System.IO { } } - public void StopDispatching (FileSystemWatcher fsw) + public void StopDispatching (object handle) { + var fsw = handle as FileSystemWatcher; DefaultWatcherData data; lock (this) { if (watches == null) return; @@ -132,6 +134,11 @@ namespace System.IO { } } + public void Dispose (object handle) + { + // does nothing + } + void Monitor () { diff --git a/mcs/class/System/System.IO/FAMWatcher.cs b/mcs/class/System/System.IO/FAMWatcher.cs index 63faf5fed7..d0ee6526ee 100644 --- a/mcs/class/System/System.IO/FAMWatcher.cs +++ b/mcs/class/System/System.IO/FAMWatcher.cs @@ -110,8 +110,9 @@ namespace System.IO { return true; } - public void StartDispatching (FileSystemWatcher fsw) + public void StartDispatching (object handle) { + var fsw = handle as FileSystemWatcher; FAMData data; lock (this) { if (thread == null) { @@ -199,8 +200,9 @@ namespace System.IO { } } - public void StopDispatching (FileSystemWatcher fsw) + public void StopDispatching (object handle) { + var fsw = handle as FileSystemWatcher; FAMData data; lock (this) { data = (FAMData) watches [fsw]; @@ -408,6 +410,10 @@ namespace System.IO { return fam_Pending (ref fc); } + public void Dispose (object handle) + { + // does nothing + } [DllImport ("libfam.so.0", EntryPoint="FAMOpen")] diff --git a/mcs/class/System/System.IO/FileSystemWatcher.cs b/mcs/class/System/System.IO/FileSystemWatcher.cs index 53e31d61f7..e3b1d7ac81 100644 --- a/mcs/class/System/System.IO/FileSystemWatcher.cs +++ b/mcs/class/System/System.IO/FileSystemWatcher.cs @@ -45,6 +45,8 @@ namespace System.IO { #region Fields + bool inited; + bool start_requested; bool enableRaisingEvents; string filter; bool includeSubdirectories; @@ -59,6 +61,7 @@ namespace System.IO { bool disposed; string mangledFilter; static IFileWatcher watcher; + object watcher_handle; static object lockobj = new object (); #endregion // Fields @@ -95,6 +98,8 @@ namespace System.IO { if (!Directory.Exists (path)) throw new ArgumentException ("Directory does not exist", "path"); + this.inited = false; + this.start_requested = false; this.enableRaisingEvents = false; this.filter = filter; this.includeSubdirectories = false; @@ -121,28 +126,39 @@ namespace System.IO { switch (mode) { case 1: // windows ok = DefaultWatcher.GetInstance (out watcher); - //ok = WindowsWatcher.GetInstance (out watcher); + watcher_handle = this; break; case 2: // libfam ok = FAMWatcher.GetInstance (out watcher, false); + watcher_handle = this; break; case 3: // kevent ok = KeventWatcher.GetInstance (out watcher); + watcher_handle = this; break; case 4: // libgamin ok = FAMWatcher.GetInstance (out watcher, true); + watcher_handle = this; break; case 5: // inotify ok = InotifyWatcher.GetInstance (out watcher, true); + watcher_handle = this; + break; + case 6: // CoreFX + ok = CoreFXFileSystemWatcherProxy.GetInstance (out watcher); + watcher_handle = (watcher as CoreFXFileSystemWatcherProxy).NewWatcher (this); break; } if (mode == 0 || !ok) { if (String.Compare (managed, "disabled", true) == 0) NullFileWatcher.GetInstance (out watcher); - else + else { DefaultWatcher.GetInstance (out watcher); + watcher_handle = this; + } } + this.inited = true; ShowWatcherInfo (); } @@ -173,9 +189,6 @@ namespace System.IO { return mangledFilter; string filterLocal = "*.*"; - if (!(watcher.GetType () == typeof (WindowsWatcher))) - filterLocal = "*"; - return filterLocal; } } @@ -183,7 +196,7 @@ namespace System.IO { internal SearchPattern2 Pattern { get { if (pattern == null) { - if (watcher.GetType () == typeof (KeventWatcher)) + if (watcher?.GetType () == typeof (KeventWatcher)) pattern = new SearchPattern2 (MangledFilter, true); //assume we want to ignore case (OS X) else pattern = new SearchPattern2 (MangledFilter); @@ -210,6 +223,12 @@ namespace System.IO { public bool EnableRaisingEvents { get { return enableRaisingEvents; } set { + if (disposed) + throw new ObjectDisposedException (GetType().Name); + + start_requested = true; + if (!inited) + return; if (value == enableRaisingEvents) return; // Do nothing @@ -218,6 +237,7 @@ namespace System.IO { Start (); } else { Stop (); + start_requested = false; } } } @@ -232,7 +252,7 @@ namespace System.IO { if (value == null || value == "") value = "*.*"; - if (filter != value) { + if (!string.Equals(filter, value, PathInternal.StringComparison)) { filter = value; pattern = null; mangledFilter = null; @@ -264,8 +284,8 @@ namespace System.IO { if (internalBufferSize == value) return; - if (value < 4196) - value = 4196; + if (value < 4096) + value = 4096; internalBufferSize = value; if (enableRaisingEvents) { @@ -299,7 +319,11 @@ namespace System.IO { public string Path { get { return path; } set { - if (path == value) + if (disposed) + throw new ObjectDisposedException (GetType().Name); + + value = (value == null) ? string.Empty : value; + if (string.Equals(path, value, PathInternal.StringComparison)) return; bool exists = false; @@ -312,10 +336,10 @@ namespace System.IO { } if (exc != null) - throw new ArgumentException ("Invalid directory name", "value", exc); + throw new ArgumentException(SR.Format(SR.InvalidDirName, value), nameof(Path)); if (!exists) - throw new ArgumentException ("Directory does not exist", "value"); + throw new ArgumentException(SR.Format(SR.InvalidDirName_NotExists, value), nameof(Path)); path = value; fullpath = null; @@ -329,7 +353,12 @@ namespace System.IO { [Browsable(false)] public override ISite Site { get { return base.Site; } - set { base.Site = value; } + set + { + base.Site = value; + if (Site != null && Site.DesignMode) + this.EnableRaisingEvents = true; + } } [DefaultValue(null)] @@ -347,27 +376,41 @@ namespace System.IO { public void BeginInit () { // Not necessary in Mono + // but if called, EndInit() must be called + inited = false; } protected override void Dispose (bool disposing) { - if (!disposed) { - disposed = true; - Stop (); - } + if (disposed) + return; + try { + watcher?.StopDispatching (watcher_handle); + watcher?.Dispose (watcher_handle); + } catch (Exception) { } + + watcher_handle = null; + watcher = null; + + disposed = true; base.Dispose (disposing); + GC.SuppressFinalize (this); } ~FileSystemWatcher () { - disposed = true; - Stop (); + if (disposed) + return; + + Dispose (false); } public void EndInit () { - // Not necessary in Mono + inited = true; + if (start_requested) + this.EnableRaisingEvents = true; } enum EventType { @@ -384,13 +427,13 @@ namespace System.IO { foreach (var target in ev.GetInvocationList()) { switch (evtype) { case EventType.RenameEvent: - ((RenamedEventHandler)target).BeginInvoke (this, (RenamedEventArgs)arg, null, null); + ((RenamedEventHandler)target).Invoke (this, (RenamedEventArgs)arg); break; case EventType.ErrorEvent: - ((ErrorEventHandler)target).BeginInvoke (this, (ErrorEventArgs)arg, null, null); + ((ErrorEventHandler)target).Invoke (this, (ErrorEventArgs)arg); break; case EventType.FileSystemEvent: - ((FileSystemEventHandler)target).BeginInvoke (this, (FileSystemEventArgs)arg, null, null); + ((FileSystemEventHandler)target).Invoke (this, (FileSystemEventArgs)arg); break; } } @@ -503,12 +546,20 @@ namespace System.IO { void Start () { - watcher.StartDispatching (this); + if (disposed) + return; + if (watcher_handle == null) + return; + watcher?.StartDispatching (watcher_handle); } void Stop () { - watcher.StopDispatching (this); + if (disposed) + return; + if (watcher_handle == null) + return; + watcher?.StopDispatching (watcher_handle); } #endregion // Methods @@ -537,6 +588,7 @@ namespace System.IO { /* 3 -> Kevent */ /* 4 -> gamin */ /* 5 -> inotify */ + /* 6 -> CoreFX */ [MethodImplAttribute(MethodImplOptions.InternalCall)] static extern int InternalSupportsFSW (); } diff --git a/mcs/class/System/System.IO/FileSystemWatcher_mobile.cs b/mcs/class/System/System.IO/FileSystemWatcher_mobile.cs deleted file mode 100644 index 1ac0655936..0000000000 --- a/mcs/class/System/System.IO/FileSystemWatcher_mobile.cs +++ /dev/null @@ -1,64 +0,0 @@ -// -// FileSystemWatcher.cs -// -// Authors: -// Marek Safar -// -// Copyright (C) 2016 Xamarin Inc (http://www.xamarin.com) -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -using System.ComponentModel; - -#pragma warning disable 67 - -namespace System.IO -{ - public class FileSystemWatcher : Component, IDisposable, ISupportInitialize - { - public FileSystemWatcher () { throw new NotImplementedException (); } - public FileSystemWatcher (string path) { throw new NotImplementedException (); } - public FileSystemWatcher (string path, string filter) { throw new NotImplementedException (); } - public bool EnableRaisingEvents { get { throw new NotImplementedException (); } set { throw new NotImplementedException (); } } - public string Filter { get { throw new NotImplementedException (); } set { } } - public bool IncludeSubdirectories { get { throw new NotImplementedException (); } set { } } - public int InternalBufferSize { get { throw new NotImplementedException (); } set { } } - public NotifyFilters NotifyFilter { get { throw new NotImplementedException (); } set { } } - public string Path { get { throw new NotImplementedException (); } set { } } - public override ISite Site { get { throw new NotImplementedException (); } set { } } - public ISynchronizeInvoke SynchronizingObject { get { throw new NotImplementedException (); } set { } } - public event FileSystemEventHandler Changed; - public event FileSystemEventHandler Created; - public event FileSystemEventHandler Deleted; - public event ErrorEventHandler Error; - public event RenamedEventHandler Renamed; - public void BeginInit() { throw new NotImplementedException (); } - public void EndInit() { throw new NotImplementedException (); } - protected void OnChanged (FileSystemEventArgs e) { throw new NotImplementedException (); } - protected void OnCreated (FileSystemEventArgs e) { throw new NotImplementedException (); } - protected void OnDeleted (System.IO.FileSystemEventArgs e) { throw new NotImplementedException (); } - protected void OnError (ErrorEventArgs e) { throw new NotImplementedException (); } - protected void OnRenamed (RenamedEventArgs e) { throw new NotImplementedException (); } - public WaitForChangedResult WaitForChanged (WatcherChangeTypes changeType) { throw new NotImplementedException (); } - public WaitForChangedResult WaitForChanged (WatcherChangeTypes changeType, int timeout) { throw new NotImplementedException (); } - protected override void Dispose (bool disposing) { } - } -} \ No newline at end of file diff --git a/mcs/class/System/System.IO/IFileWatcher.cs b/mcs/class/System/System.IO/IFileWatcher.cs index 7ed4878fa6..d7e6055a1d 100644 --- a/mcs/class/System/System.IO/IFileWatcher.cs +++ b/mcs/class/System/System.IO/IFileWatcher.cs @@ -30,8 +30,9 @@ namespace System.IO { interface IFileWatcher { - void StartDispatching (FileSystemWatcher fsw); - void StopDispatching (FileSystemWatcher fsw); + void StartDispatching (object fsw); + void StopDispatching (object fsw); + void Dispose (object fsw); } } diff --git a/mcs/class/System/System.IO/InotifyWatcher.cs b/mcs/class/System/System.IO/InotifyWatcher.cs index fe023429a0..789567d0b9 100644 --- a/mcs/class/System/System.IO/InotifyWatcher.cs +++ b/mcs/class/System/System.IO/InotifyWatcher.cs @@ -133,8 +133,11 @@ namespace System.IO { return true; } - public void StartDispatching (FileSystemWatcher fsw) + public void StartDispatching (object handle) { + if (handle == null) + return; + var fsw = handle as FileSystemWatcher; ParentInotifyData parent; lock (this) { if ((long) FD == -1) @@ -328,8 +331,11 @@ namespace System.IO { } } - public void StopDispatching (FileSystemWatcher fsw) + public void StopDispatching (object handle) { + if (handle == null) + return; + var fsw = handle as FileSystemWatcher; ParentInotifyData parent; lock (this) { parent = (ParentInotifyData) watches [fsw]; @@ -608,6 +614,11 @@ namespace System.IO { return AddWatch (fd, directory, mask); } + public void Dispose (object handle) + { + // does nothing + } + [DllImport ("libc", EntryPoint="close")] internal extern static int Close (IntPtr fd); diff --git a/mcs/class/System/System.IO/KeventWatcher.cs b/mcs/class/System/System.IO/KeventWatcher.cs index 778671764e..5a1984f709 100644 --- a/mcs/class/System/System.IO/KeventWatcher.cs +++ b/mcs/class/System/System.IO/KeventWatcher.cs @@ -736,8 +736,9 @@ namespace System.IO { return true; } - public void StartDispatching (FileSystemWatcher fsw) + public void StartDispatching (object handle) { + var fsw = handle as FileSystemWatcher; KqueueMonitor monitor; if (watches.ContainsKey (fsw)) { @@ -750,14 +751,20 @@ namespace System.IO { monitor.Start (); } - public void StopDispatching (FileSystemWatcher fsw) + public void StopDispatching (object handle) { + var fsw = handle as FileSystemWatcher; KqueueMonitor monitor = (KqueueMonitor)watches [fsw]; if (monitor == null) return; monitor.Stop (); } + + public void Dispose (object handle) + { + // does nothing + } [DllImport ("libc")] extern static int close (int fd); diff --git a/mcs/class/System/System.IO/NullFileWatcher.cs b/mcs/class/System/System.IO/NullFileWatcher.cs index 33f314f55b..ea1cbccfae 100644 --- a/mcs/class/System/System.IO/NullFileWatcher.cs +++ b/mcs/class/System/System.IO/NullFileWatcher.cs @@ -35,12 +35,17 @@ namespace System.IO { static IFileWatcher instance; - public void StartDispatching (FileSystemWatcher fsw) + public void StartDispatching (object handle) { // does nothing } - public void StopDispatching (FileSystemWatcher fsw) + public void StopDispatching (object handle) + { + // does nothing + } + + public void Dispose (object handle) { // does nothing } diff --git a/mcs/class/System/System.IO/WaitForChangedResult.cs b/mcs/class/System/System.IO/WaitForChangedResult.cs deleted file mode 100644 index 7a6765b1e0..0000000000 --- a/mcs/class/System/System.IO/WaitForChangedResult.cs +++ /dev/null @@ -1,69 +0,0 @@ -// -// System.IO.WaitForChangedResult.cs -// -// Author: -// Tim Coleman (tim@timcoleman.com) -// -// Copyright (C) Tim Coleman, 2002 -// - -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -using System; - -namespace System.IO { - public struct WaitForChangedResult { - - #region Fields - - WatcherChangeTypes changeType; - string name; - string oldName; - bool timedOut; - - #endregion // Fields - - #region Properties - - public WatcherChangeTypes ChangeType { - get { return changeType; } - set { changeType = value; } - } - - public string Name { - get { return name; } - set { name = value; } - } - - public string OldName { - get { return oldName; } - set { oldName = value; } - } - - public bool TimedOut { - get { return timedOut; } - set { timedOut = value; } - } - - #endregion // Properties - } -} diff --git a/mcs/class/System/System.IO/WindowsWatcher.cs b/mcs/class/System/System.IO/WindowsWatcher.cs deleted file mode 100644 index dc5e848f13..0000000000 --- a/mcs/class/System/System.IO/WindowsWatcher.cs +++ /dev/null @@ -1,53 +0,0 @@ -// -// System.IO.WindowsWatcher.cs: windows IFileWatcher -// -// Authors: -// Gonzalo Paniagua Javier (gonzalo@ximian.com) -// -// (c) 2004 Novell, Inc. (http://www.novell.com) -// - -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -namespace System.IO { - class WindowsWatcher : IFileWatcher - { - private WindowsWatcher () - { - } - - // Locked by caller - public static bool GetInstance (out IFileWatcher watcher) - { - throw new NotSupportedException (); - } - - public void StartDispatching (FileSystemWatcher fsw) - { - } - - public void StopDispatching (FileSystemWatcher fsw) - { - } - } -} - diff --git a/mcs/class/System/System.Net.NetworkInformation/IPGlobalProperties.cs b/mcs/class/System/System.Net.NetworkInformation/IPGlobalProperties.cs index 92bd3ffb36..3d5476a67c 100644 --- a/mcs/class/System/System.Net.NetworkInformation/IPGlobalProperties.cs +++ b/mcs/class/System/System.Net.NetworkInformation/IPGlobalProperties.cs @@ -613,6 +613,9 @@ namespace System.Net.NetworkInformation { [DllImport ("iphlpapi.dll")] static extern int GetIpStatisticsEx (out Win32_MIB_IPSTATS pStats, int dwFamily); + [DllImport ("Ws2_32.dll")] + static extern ushort ntohs (ushort netshort); + // Win32 structures [StructLayout (LayoutKind.Explicit)] @@ -673,10 +676,10 @@ namespace System.Net.NetworkInformation { class Win32_MIB_UDPROW { public uint LocalAddr; - public int LocalPort; + public uint LocalPort; public IPEndPoint LocalEndPoint { - get { return new IPEndPoint (LocalAddr, LocalPort); } + get { return new IPEndPoint (LocalAddr, ntohs((ushort)LocalPort)); } } } diff --git a/mcs/class/System/System.Net/FtpAsyncResult.cs b/mcs/class/System/System.Net/FtpAsyncResult.cs deleted file mode 100644 index 33e67372c4..0000000000 --- a/mcs/class/System/System.Net/FtpAsyncResult.cs +++ /dev/null @@ -1,162 +0,0 @@ -// -// System.Net.FtpAsyncResult.cs -// -// Authors: -// Carlos Alberto Cortez (calberto.cortez@gmail.com) -// -// (c) Copyright 2006 Novell, Inc. (http://www.novell.com) -// - -using System; -using System.IO; -using System.Threading; -using System.Net; - -namespace System.Net -{ - class FtpAsyncResult : IAsyncResult - { - FtpWebResponse response; - ManualResetEvent waitHandle; - Exception exception; - AsyncCallback callback; - Stream stream; - object state; - bool completed; - bool synch; - object locker = new object (); - - public FtpAsyncResult (AsyncCallback callback, object state) - { - this.callback = callback; - this.state = state; - } - - public object AsyncState { - get { - return state; - } - } - - public WaitHandle AsyncWaitHandle { - get { - lock (locker) { - if (waitHandle == null) - waitHandle = new ManualResetEvent (false); - } - - return waitHandle; - } - } - - public bool CompletedSynchronously { - get { - return synch; - } - } - - public bool IsCompleted { - get { - lock (locker) { - return completed; - } - } - } - - internal bool GotException { - get { - return exception != null; - } - } - - internal Exception Exception { - get { - return exception; - } - } - - internal FtpWebResponse Response { - get { - return response; - } - set { - response = value; - } - } - - internal Stream Stream { - get { - return stream; - } - - set { stream = value; } - } - - internal void WaitUntilComplete () - { - if (IsCompleted) - return; - - AsyncWaitHandle.WaitOne (); - } - - internal bool WaitUntilComplete (int timeout, bool exitContext) - { - if (IsCompleted) - return true; - - return AsyncWaitHandle.WaitOne (timeout, exitContext); - } - - internal void SetCompleted (bool synch, Exception exc, FtpWebResponse response) - { - this.synch = synch; - this.exception = exc; - this.response = response; - lock (locker) { - completed = true; - if (waitHandle != null) - waitHandle.Set (); - } - DoCallback (); - } - - internal void SetCompleted (bool synch, FtpWebResponse response) - { - SetCompleted (synch, null, response); - } - - internal void SetCompleted (bool synch, Exception exc) - { - SetCompleted (synch, exc, null); - } - - internal void DoCallback () - { - if (callback != null) - try { - callback (this); - } - catch (Exception) { - } - } - - // Cleanup resources - internal void Reset () - { - exception = null; - synch = false; - response = null; - state = null; - - lock (locker) { - completed = false; - if (waitHandle != null) - waitHandle.Reset (); - } - } - - } -} - - diff --git a/mcs/class/System/System.Net/FtpDataStream.cs b/mcs/class/System/System.Net/FtpDataStream.cs deleted file mode 100644 index 7bb47468c3..0000000000 --- a/mcs/class/System/System.Net/FtpDataStream.cs +++ /dev/null @@ -1,252 +0,0 @@ -// -// System.Net.FtpDataStream.cs -// -// Authors: -// Carlos Alberto Cortez (calberto.cortez@gmail.com) -// -// (c) Copyright 2006 Novell, Inc. (http://www.novell.com) -// - -using System; -using System.IO; -using System.Net.Sockets; -using System.Runtime.Remoting.Messaging; -using System.Threading; -using System.Net; - -namespace System.Net -{ - class FtpDataStream : Stream, IDisposable - { - FtpWebRequest request; - Stream networkStream; - bool disposed; - bool isRead; - int totalRead; - - internal FtpDataStream (FtpWebRequest request, Stream stream, bool isRead) - { - if (request == null) - throw new ArgumentNullException ("request"); - - this.request = request; - this.networkStream = stream; - this.isRead = isRead; - } - - public override bool CanRead { - get { - return isRead; - } - } - - public override bool CanWrite { - get { - return !isRead; - } - } - - public override bool CanSeek { - get { - return false; - } - } - - public override long Length { - get { - throw new NotSupportedException (); - } - } - - public override long Position { - get { - throw new NotSupportedException (); - } - set { - throw new NotSupportedException (); - } - } - - internal Stream NetworkStream { - get { - CheckDisposed (); - return networkStream; - } - } - - public override void Close () - { - Dispose (true); - } - - public override void Flush () - { - // Do nothing. - } - - public override long Seek (long offset, SeekOrigin origin) - { - throw new NotSupportedException (); - } - - public override void SetLength (long value) - { - throw new NotSupportedException (); - } - - int ReadInternal (byte [] buffer, int offset, int size) - { - int nbytes = 0; - request.CheckIfAborted (); - - try { - // Probably it would be better to have the socket here - nbytes = networkStream.Read (buffer, offset, size); - } catch (IOException) { - throw new ProtocolViolationException ("Server commited a protocol violation"); - } - - totalRead += nbytes; - if (nbytes == 0) { - networkStream = null; - request.CloseDataConnection (); - request.SetTransferCompleted (); - } - - return nbytes; - } - - public override IAsyncResult BeginRead (byte [] buffer, int offset, int size, AsyncCallback cb, object state) - { - CheckDisposed (); - - if (!isRead) - throw new NotSupportedException (); - if (buffer == null) - throw new ArgumentNullException ("buffer"); - if (offset < 0 || offset > buffer.Length) - throw new ArgumentOutOfRangeException ("offset"); - if (size < 0 || size > buffer.Length - offset) - throw new ArgumentOutOfRangeException ("offset+size"); - - ReadDelegate del = ReadInternal; - return del.BeginInvoke (buffer, offset, size, cb, state); - } - - public override int EndRead (IAsyncResult asyncResult) - { - if (asyncResult == null) - throw new ArgumentNullException ("asyncResult"); - - AsyncResult ar = asyncResult as AsyncResult; - if (ar == null) - throw new ArgumentException ("Invalid asyncResult", "asyncResult"); - - ReadDelegate del = ar.AsyncDelegate as ReadDelegate; - if (del == null) - throw new ArgumentException ("Invalid asyncResult", "asyncResult"); - - return del.EndInvoke (asyncResult); - } - - public override int Read (byte [] buffer, int offset, int size) - { - request.CheckIfAborted (); - IAsyncResult ar = BeginRead (buffer, offset, size, null, null); - if (!ar.IsCompleted && !ar.AsyncWaitHandle.WaitOne (request.ReadWriteTimeout, false)) - throw new WebException ("Read timed out.", WebExceptionStatus.Timeout); - return EndRead (ar); - } - - - delegate void WriteDelegate (byte [] buffer, int offset, int size); - - void WriteInternal (byte [] buffer, int offset, int size) - { - request.CheckIfAborted (); - - try { - networkStream.Write (buffer, offset, size); - } catch (IOException) { - throw new ProtocolViolationException (); - } - } - - public override IAsyncResult BeginWrite (byte [] buffer, int offset, int size, AsyncCallback cb, object state) - { - CheckDisposed (); - if (isRead) - throw new NotSupportedException (); - if (buffer == null) - throw new ArgumentNullException ("buffer"); - if (offset < 0 || offset > buffer.Length) - throw new ArgumentOutOfRangeException ("offset"); - if (size < 0 || size > buffer.Length - offset) - throw new ArgumentOutOfRangeException ("offset+size"); - - WriteDelegate del = WriteInternal; - return del.BeginInvoke (buffer, offset, size, cb, state); - } - - public override void EndWrite (IAsyncResult asyncResult) - { - if (asyncResult == null) - throw new ArgumentNullException ("asyncResult"); - - AsyncResult ar = asyncResult as AsyncResult; - if (ar == null) - throw new ArgumentException ("Invalid asyncResult.", "asyncResult"); - - WriteDelegate del = ar.AsyncDelegate as WriteDelegate; - if (del == null) - throw new ArgumentException ("Invalid asyncResult.", "asyncResult"); - - del.EndInvoke (asyncResult); - } - - public override void Write (byte [] buffer, int offset, int size) - { - request.CheckIfAborted (); - IAsyncResult ar = BeginWrite (buffer, offset, size, null, null); - if (!ar.IsCompleted && !ar.AsyncWaitHandle.WaitOne (request.ReadWriteTimeout, false)) - throw new WebException ("Read timed out.", WebExceptionStatus.Timeout); - - EndWrite (ar); - } - - ~FtpDataStream () - { - Dispose (false); - } - - void IDisposable.Dispose () - { - Dispose (true); - GC.SuppressFinalize (this); - } - - protected override void Dispose (bool disposing) - { - if (disposed) - return; - - disposed = true; - if (networkStream != null) { - request.CloseDataConnection (); - request.SetTransferCompleted (); - request = null; - networkStream = null; - } - } - - void CheckDisposed () - { - if (disposed) - throw new ObjectDisposedException (GetType ().FullName); - } - - delegate int ReadDelegate (byte [] buffer, int offset, int size); - } -} - - diff --git a/mcs/class/System/System.Net/FtpRequestCreator.platformnotsupported.cs b/mcs/class/System/System.Net/FtpRequestCreator.platformnotsupported.cs index ae365c2815..1f0253a8a9 100644 --- a/mcs/class/System/System.Net/FtpRequestCreator.platformnotsupported.cs +++ b/mcs/class/System/System.Net/FtpRequestCreator.platformnotsupported.cs @@ -28,9 +28,9 @@ namespace System.Net { - class FtpRequestCreator : IWebRequestCreate + class FtpWebRequestCreator : IWebRequestCreate { - internal const string EXCEPTION_MESSAGE = "System.Net.FtpRequestCreator is not supported on the current platform."; + internal const string EXCEPTION_MESSAGE = "System.Net.FtpWebRequestCreator is not supported on the current platform."; public WebRequest Create (Uri uri) { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); diff --git a/mcs/class/System/System.Net/FtpWebRequest.cs b/mcs/class/System/System.Net/FtpWebRequest.cs deleted file mode 100644 index 3121db3d17..0000000000 --- a/mcs/class/System/System.Net/FtpWebRequest.cs +++ /dev/null @@ -1,1257 +0,0 @@ -// -// System.Net.FtpWebRequest.cs -// -// Authors: -// Carlos Alberto Cortez (calberto.cortez@gmail.com) -// -// (c) Copyright 2006 Novell, Inc. (http://www.novell.com) -// - -#if SECURITY_DEP -#if MONO_SECURITY_ALIAS -extern alias MonoSecurity; -using MSI = MonoSecurity::Mono.Security.Interface; -#else -using MSI = Mono.Security.Interface; -#endif -#endif - -using System; -using System.Globalization; -using System.IO; -using System.Net.Sockets; -using System.Text; -using System.Threading; -using System.Net.Cache; -using System.Security.Cryptography.X509Certificates; -using System.Net; -using System.Net.Security; -using System.Security.Authentication; -using Mono.Net.Security; - -namespace System.Net -{ - public sealed class FtpWebRequest : WebRequest - { - Uri requestUri; - string file_name; // By now, used for upload - ServicePoint servicePoint; - Stream origDataStream; - Stream dataStream; - Stream controlStream; - StreamReader controlReader; - NetworkCredential credentials; - IPHostEntry hostEntry; - IPEndPoint localEndPoint; - IPEndPoint remoteEndPoint; - IWebProxy proxy; - int timeout = 100000; - int rwTimeout = 300000; - long offset = 0; - bool binary = true; - bool enableSsl = false; - bool usePassive = true; - bool keepAlive = false; - string method = WebRequestMethods.Ftp.DownloadFile; - string renameTo; - object locker = new object (); - - RequestState requestState = RequestState.Before; - FtpAsyncResult asyncResult; - FtpWebResponse ftpResponse; - Stream requestStream; - string initial_path; - - const string ChangeDir = "CWD"; - const string UserCommand = "USER"; - const string PasswordCommand = "PASS"; - const string TypeCommand = "TYPE"; - const string PassiveCommand = "PASV"; - const string ExtendedPassiveCommand = "EPSV"; - const string PortCommand = "PORT"; - const string ExtendedPortCommand = "EPRT"; - const string AbortCommand = "ABOR"; - const string AuthCommand = "AUTH"; - const string RestCommand = "REST"; - const string RenameFromCommand = "RNFR"; - const string RenameToCommand = "RNTO"; - const string QuitCommand = "QUIT"; - const string EOL = "\r\n"; // Special end of line - - enum RequestState - { - Before, - Scheduled, - Connecting, - Authenticating, - OpeningData, - TransferInProgress, - Finished, - Aborted, - Error - } - - // sorted commands - static readonly string [] supportedCommands = new string [] { - WebRequestMethods.Ftp.AppendFile, // APPE - WebRequestMethods.Ftp.DeleteFile, // DELE - WebRequestMethods.Ftp.ListDirectoryDetails, // LIST - WebRequestMethods.Ftp.GetDateTimestamp, // MDTM - WebRequestMethods.Ftp.MakeDirectory, // MKD - WebRequestMethods.Ftp.ListDirectory, // NLST - WebRequestMethods.Ftp.PrintWorkingDirectory, // PWD - WebRequestMethods.Ftp.Rename, // RENAME - WebRequestMethods.Ftp.DownloadFile, // RETR - WebRequestMethods.Ftp.RemoveDirectory, // RMD - WebRequestMethods.Ftp.GetFileSize, // SIZE - WebRequestMethods.Ftp.UploadFile, // STOR - WebRequestMethods.Ftp.UploadFileWithUniqueName // STUR - }; - - Encoding dataEncoding = Encoding.UTF8; - - internal FtpWebRequest (Uri uri) - { - this.requestUri = uri; -#pragma warning disable 618 - this.proxy = GlobalProxySelection.Select; -#pragma warning restore 618 - } - - static Exception GetMustImplement () - { - return new NotImplementedException (); - } - - [MonoTODO] - public X509CertificateCollection ClientCertificates - { - get { - throw GetMustImplement (); - } - set { - throw GetMustImplement (); - } - } - - [MonoTODO] - public override string ConnectionGroupName - { - get { - throw GetMustImplement (); - } - set { - throw GetMustImplement (); - } - } - - public override string ContentType { - get { - throw new NotSupportedException (); - } - set { - throw new NotSupportedException (); - } - } - - public override long ContentLength { - get { - return 0; - } - set { - // DO nothing - } - } - - public long ContentOffset { - get { - return offset; - } - set { - CheckRequestStarted (); - if (value < 0) - throw new ArgumentOutOfRangeException (); - - offset = value; - } - } - - public override ICredentials Credentials { - get { - return credentials; - } - set { - CheckRequestStarted (); - if (value == null) - throw new ArgumentNullException (); - if (!(value is NetworkCredential)) - throw new ArgumentException (); - - credentials = value as NetworkCredential; - } - } - -#if !MOBILE - [MonoTODO] - public static new RequestCachePolicy DefaultCachePolicy - { - get { - throw GetMustImplement (); - } - set { - throw GetMustImplement (); - } - } -#endif - - public bool EnableSsl { - get { - return enableSsl; - } - set { - CheckRequestStarted (); - enableSsl = value; - } - } - - [MonoTODO] - public override WebHeaderCollection Headers - { - get { - throw GetMustImplement (); - } - set { - throw GetMustImplement (); - } - } - - [MonoTODO ("We don't support KeepAlive = true")] - public bool KeepAlive { - get { - return keepAlive; - } - set { - CheckRequestStarted (); - //keepAlive = value; - } - } - - public override string Method { - get { - return method; - } - set { - CheckRequestStarted (); - if (value == null) - throw new ArgumentNullException ("Method string cannot be null"); - - if (value.Length == 0 || Array.BinarySearch (supportedCommands, value) < 0) - throw new ArgumentException ("Method not supported", "value"); - - method = value; - } - } - - public override bool PreAuthenticate { - get { - throw new NotSupportedException (); - } - set { - throw new NotSupportedException (); - } - } - - public override IWebProxy Proxy { - get { - return proxy; - } - set { - CheckRequestStarted (); - proxy = value; - } - } - - public int ReadWriteTimeout { - get { - return rwTimeout; - } - set { - CheckRequestStarted (); - - if (value < - 1) - throw new ArgumentOutOfRangeException (); - else - rwTimeout = value; - } - } - - public string RenameTo { - get { - return renameTo; - } - set { - CheckRequestStarted (); - if (value == null || value.Length == 0) - throw new ArgumentException ("RenameTo value can't be null or empty", "RenameTo"); - - renameTo = value; - } - } - - public override Uri RequestUri { - get { - return requestUri; - } - } - - public ServicePoint ServicePoint { - get { - return GetServicePoint (); - } - } - - public bool UsePassive { - get { - return usePassive; - } - set { - CheckRequestStarted (); - usePassive = value; - } - } - - [MonoTODO] - public override bool UseDefaultCredentials - { - get { - throw GetMustImplement (); - } - set { - throw GetMustImplement (); - } - } - - public bool UseBinary { - get { - return binary; - } set { - CheckRequestStarted (); - binary = value; - } - } - - public override int Timeout { - get { - return timeout; - } - set { - CheckRequestStarted (); - - if (value < -1) - throw new ArgumentOutOfRangeException (); - else - timeout = value; - } - } - - string DataType { - get { - return binary ? "I" : "A"; - } - } - - RequestState State { - get { - lock (locker) { - return requestState; - } - } - - set { - lock (locker) { - CheckIfAborted (); - CheckFinalState (); - requestState = value; - } - } - } - - public override void Abort () { - lock (locker) { - if (State == RequestState.TransferInProgress) { - /*FtpStatus status = */ - SendCommand (false, AbortCommand); - } - - if (!InFinalState ()) { - State = RequestState.Aborted; - ftpResponse = new FtpWebResponse (this, requestUri, method, FtpStatusCode.FileActionAborted, "Aborted by request"); - } - } - } - - public override IAsyncResult BeginGetResponse (AsyncCallback callback, object state) { - if (asyncResult != null && !asyncResult.IsCompleted) { - throw new InvalidOperationException ("Cannot re-call BeginGetRequestStream/BeginGetResponse while a previous call is still in progress"); - } - - CheckIfAborted (); - - asyncResult = new FtpAsyncResult (callback, state); - - lock (locker) { - if (InFinalState ()) - asyncResult.SetCompleted (true, ftpResponse); - else { - if (State == RequestState.Before) - State = RequestState.Scheduled; - - Thread thread = new Thread (ProcessRequest); - thread.IsBackground = true; - thread.Start (); - } - } - - return asyncResult; - } - - public override WebResponse EndGetResponse (IAsyncResult asyncResult) { - if (asyncResult == null) - throw new ArgumentNullException ("AsyncResult cannot be null!"); - - if (!(asyncResult is FtpAsyncResult) || asyncResult != this.asyncResult) - throw new ArgumentException ("AsyncResult is from another request!"); - - FtpAsyncResult asyncFtpResult = (FtpAsyncResult) asyncResult; - if (!asyncFtpResult.WaitUntilComplete (timeout, false)) { - Abort (); - throw new WebException ("Transfer timed out.", WebExceptionStatus.Timeout); - } - - CheckIfAborted (); - - asyncResult = null; - - if (asyncFtpResult.GotException) - throw asyncFtpResult.Exception; - - return asyncFtpResult.Response; - } - - public override WebResponse GetResponse () { - IAsyncResult asyncResult = BeginGetResponse (null, null); - return EndGetResponse (asyncResult); - } - - public override IAsyncResult BeginGetRequestStream (AsyncCallback callback, object state) { - if (method != WebRequestMethods.Ftp.UploadFile && method != WebRequestMethods.Ftp.UploadFileWithUniqueName && - method != WebRequestMethods.Ftp.AppendFile) - throw new ProtocolViolationException (); - - lock (locker) { - CheckIfAborted (); - - if (State != RequestState.Before) - throw new InvalidOperationException ("Cannot re-call BeginGetRequestStream/BeginGetResponse while a previous call is still in progress"); - - State = RequestState.Scheduled; - } - - asyncResult = new FtpAsyncResult (callback, state); - Thread thread = new Thread (ProcessRequest); - thread.IsBackground = true; - thread.Start (); - - return asyncResult; - } - - public override Stream EndGetRequestStream (IAsyncResult asyncResult) { - if (asyncResult == null) - throw new ArgumentNullException ("asyncResult"); - - if (!(asyncResult is FtpAsyncResult)) - throw new ArgumentException ("asyncResult"); - - if (State == RequestState.Aborted) { - throw new WebException ("Request aborted", WebExceptionStatus.RequestCanceled); - } - - if (asyncResult != this.asyncResult) - throw new ArgumentException ("AsyncResult is from another request!"); - - FtpAsyncResult res = (FtpAsyncResult) asyncResult; - - if (!res.WaitUntilComplete (timeout, false)) { - Abort (); - throw new WebException ("Request timed out"); - } - - if (res.GotException) - throw res.Exception; - - return res.Stream; - } - - public override Stream GetRequestStream () { - IAsyncResult asyncResult = BeginGetRequestStream (null, null); - return EndGetRequestStream (asyncResult); - } - - ServicePoint GetServicePoint () - { - if (servicePoint == null) - servicePoint = ServicePointManager.FindServicePoint (requestUri, proxy); - - return servicePoint; - } - - // Probably move some code of command connection here - void ResolveHost () - { - CheckIfAborted (); - hostEntry = GetServicePoint ().HostEntry; - - if (hostEntry == null) { - ftpResponse.UpdateStatus (new FtpStatus(FtpStatusCode.ActionAbortedLocalProcessingError, "Cannot resolve server name")); - throw new WebException ("The remote server name could not be resolved: " + requestUri, - null, WebExceptionStatus.NameResolutionFailure, ftpResponse); - } - } - - void ProcessRequest () { - - if (State == RequestState.Scheduled) { - ftpResponse = new FtpWebResponse (this, requestUri, method, keepAlive); - - try { - ProcessMethod (); - //State = RequestState.Finished; - //finalResponse = ftpResponse; - asyncResult.SetCompleted (false, ftpResponse); - } - catch (Exception e) { - if (!GetServicePoint ().UsesProxy) - State = RequestState.Error; - SetCompleteWithError (e); - } - } - else { - if (InProgress ()) { - FtpStatus status = GetResponseStatus (); - - ftpResponse.UpdateStatus (status); - - if (ftpResponse.IsFinal ()) { - State = RequestState.Finished; - } - } - - asyncResult.SetCompleted (false, ftpResponse); - } - } - - void SetType () - { - if (binary) { - FtpStatus status = SendCommand (TypeCommand, DataType); - if ((int) status.StatusCode < 200 || (int) status.StatusCode >= 300) - throw CreateExceptionFromResponse (status); - } - } - - string GetRemoteFolderPath (Uri uri) - { - string result; - string local_path = Uri.UnescapeDataString (uri.LocalPath); - if (initial_path == null || initial_path == "/") { - result = local_path; - } else { - if (local_path [0] == '/') - local_path = local_path.Substring (1); - - UriBuilder initialBuilder = new UriBuilder () { - Scheme = "ftp", - Host = "dummy-host", - Path = initial_path, - }; - Uri initial = initialBuilder.Uri; - result = new Uri (initial, local_path).LocalPath; - } - - int last = result.LastIndexOf ('/'); - if (last == -1) - return null; - - return result.Substring (0, last + 1); - } - - void CWDAndSetFileName (Uri uri) - { - string remote_folder = GetRemoteFolderPath (uri); - FtpStatus status; - if (remote_folder != null) { - status = SendCommand (ChangeDir, remote_folder); - if ((int) status.StatusCode < 200 || (int) status.StatusCode >= 300) - throw CreateExceptionFromResponse (status); - - int last = uri.LocalPath.LastIndexOf ('/'); - if (last >= 0) { - file_name = Uri.UnescapeDataString (uri.LocalPath.Substring (last + 1)); - } - } - } - - void ProcessMethod () - { - ServicePoint sp = GetServicePoint (); - if (sp.UsesProxy) { - if (method != WebRequestMethods.Ftp.DownloadFile) - throw new NotSupportedException ("FTP+proxy only supports RETR"); - - HttpWebRequest req = (HttpWebRequest) WebRequest.Create (proxy.GetProxy (requestUri)); - req.Address = requestUri; - requestState = RequestState.Finished; - WebResponse response = req.GetResponse (); - ftpResponse.Stream = new FtpDataStream (this, response.GetResponseStream (), true); - ftpResponse.StatusCode = FtpStatusCode.CommandOK; - return; - } - State = RequestState.Connecting; - - ResolveHost (); - - OpenControlConnection (); - CWDAndSetFileName (requestUri); - SetType (); - - switch (method) { - // Open data connection and receive data - case WebRequestMethods.Ftp.DownloadFile: - case WebRequestMethods.Ftp.ListDirectory: - case WebRequestMethods.Ftp.ListDirectoryDetails: - DownloadData (); - break; - // Open data connection and send data - case WebRequestMethods.Ftp.AppendFile: - case WebRequestMethods.Ftp.UploadFile: - case WebRequestMethods.Ftp.UploadFileWithUniqueName: - UploadData (); - break; - // Get info from control connection - case WebRequestMethods.Ftp.GetFileSize: - case WebRequestMethods.Ftp.GetDateTimestamp: - case WebRequestMethods.Ftp.PrintWorkingDirectory: - case WebRequestMethods.Ftp.MakeDirectory: - case WebRequestMethods.Ftp.Rename: - case WebRequestMethods.Ftp.DeleteFile: - ProcessSimpleMethod (); - break; - default: // What to do here? - throw new Exception (String.Format ("Support for command {0} not implemented yet", method)); - } - - CheckIfAborted (); - } - - private void CloseControlConnection () { - if (controlStream != null) { - SendCommand (QuitCommand); - controlStream.Close (); - controlStream = null; - } - } - - internal void CloseDataConnection () { - if(origDataStream != null) { - origDataStream.Close (); - origDataStream = null; - } - } - - private void CloseConnection () { - CloseControlConnection (); - CloseDataConnection (); - } - - void ProcessSimpleMethod () - { - State = RequestState.TransferInProgress; - - FtpStatus status; - - if (method == WebRequestMethods.Ftp.PrintWorkingDirectory) - method = "PWD"; - - if (method == WebRequestMethods.Ftp.Rename) - method = RenameFromCommand; - - status = SendCommand (method, file_name); - - ftpResponse.Stream = Stream.Null; - - string desc = status.StatusDescription; - - switch (method) { - case WebRequestMethods.Ftp.GetFileSize: { - if (status.StatusCode != FtpStatusCode.FileStatus) - throw CreateExceptionFromResponse (status); - - int i, len; - long size; - for (i = 4, len = 0; i < desc.Length && Char.IsDigit (desc [i]); i++, len++) - ; - - if (len == 0) - throw new WebException ("Bad format for server response in " + method); - - if (!Int64.TryParse (desc.Substring (4, len), out size)) - throw new WebException ("Bad format for server response in " + method); - - ftpResponse.contentLength = size; - } - break; - case WebRequestMethods.Ftp.GetDateTimestamp: - if (status.StatusCode != FtpStatusCode.FileStatus) - throw CreateExceptionFromResponse (status); - ftpResponse.LastModified = DateTime.ParseExact (desc.Substring (4), "yyyyMMddHHmmss", null); - break; - case WebRequestMethods.Ftp.MakeDirectory: - if (status.StatusCode != FtpStatusCode.PathnameCreated) - throw CreateExceptionFromResponse (status); - break; - case ChangeDir: - method = WebRequestMethods.Ftp.PrintWorkingDirectory; - - if (status.StatusCode != FtpStatusCode.FileActionOK) - throw CreateExceptionFromResponse (status); - - status = SendCommand (method); - - if (status.StatusCode != FtpStatusCode.PathnameCreated) - throw CreateExceptionFromResponse (status); - break; - case RenameFromCommand: - method = WebRequestMethods.Ftp.Rename; - if (status.StatusCode != FtpStatusCode.FileCommandPending) - throw CreateExceptionFromResponse (status); - // Pass an empty string if RenameTo wasn't specified - status = SendCommand (RenameToCommand, renameTo != null ? renameTo : String.Empty); - if (status.StatusCode != FtpStatusCode.FileActionOK) - throw CreateExceptionFromResponse (status); - break; - case WebRequestMethods.Ftp.DeleteFile: - if (status.StatusCode != FtpStatusCode.FileActionOK) { - throw CreateExceptionFromResponse (status); - } - break; - } - - State = RequestState.Finished; - } - - void UploadData () - { - State = RequestState.OpeningData; - - OpenDataConnection (); - - State = RequestState.TransferInProgress; - requestStream = new FtpDataStream (this, dataStream, false); - asyncResult.Stream = requestStream; - } - - void DownloadData () - { - State = RequestState.OpeningData; - - OpenDataConnection (); - - State = RequestState.TransferInProgress; - ftpResponse.Stream = new FtpDataStream (this, dataStream, true); - } - - void CheckRequestStarted () - { - if (State != RequestState.Before) - throw new InvalidOperationException ("There is a request currently in progress"); - } - - void OpenControlConnection () - { - Exception exception = null; - Socket sock = null; - foreach (IPAddress address in hostEntry.AddressList) { - sock = new Socket (address.AddressFamily, SocketType.Stream, ProtocolType.Tcp); - - remoteEndPoint = new IPEndPoint (address, requestUri.Port); - - if (!ServicePoint.CallEndPointDelegate (sock, remoteEndPoint)) { - sock.Close (); - sock = null; - } else { - try { - sock.Connect (remoteEndPoint); - localEndPoint = (IPEndPoint) sock.LocalEndPoint; - break; - } catch (SocketException exc) { - exception = exc; - sock.Close (); - sock = null; - } - } - } - - // Couldn't connect to any address - if (sock == null) - throw new WebException ("Unable to connect to remote server", exception, - WebExceptionStatus.UnknownError, ftpResponse); - - controlStream = new NetworkStream (sock); - controlReader = new StreamReader (controlStream, Encoding.ASCII); - - State = RequestState.Authenticating; - - Authenticate (); - FtpStatus status = SendCommand ("OPTS", "utf8", "on"); - if ((int)status.StatusCode < 200 || (int)status.StatusCode > 300) - dataEncoding = Encoding.Default; - else - dataEncoding = Encoding.UTF8; - - status = SendCommand (WebRequestMethods.Ftp.PrintWorkingDirectory); - initial_path = GetInitialPath (status); - } - - static string GetInitialPath (FtpStatus status) - { - int s = (int) status.StatusCode; - if (s < 200 || s > 300 || status.StatusDescription.Length <= 4) - throw new WebException ("Error getting current directory: " + status.StatusDescription, null, - WebExceptionStatus.UnknownError, null); - - string msg = status.StatusDescription.Substring (4); - if (msg [0] == '"') { - int next_quote = msg.IndexOf ('\"', 1); - if (next_quote == -1) - throw new WebException ("Error getting current directory: PWD -> " + status.StatusDescription, null, - WebExceptionStatus.UnknownError, null); - - msg = msg.Substring (1, next_quote - 1); - } - - if (!msg.EndsWith ("/")) - msg += "/"; - return msg; - } - - // Probably we could do better having here a regex - Socket SetupPassiveConnection (string statusDescription, bool ipv6) - { - // Current response string - string response = statusDescription; - if (response.Length < 4) - throw new WebException ("Cannot open passive data connection"); - - int port = ipv6 ? GetPortV6 (response) : GetPortV4 (response); - - if (port < IPEndPoint.MinPort || port > IPEndPoint.MaxPort) - throw new WebException ("Cannot open passive data connection"); - - IPEndPoint ep = new IPEndPoint (remoteEndPoint.Address, port); - Socket sock = new Socket (ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp); - try { - sock.Connect (ep); - } catch (SocketException) { - sock.Close (); - throw new WebException ("Cannot open passive data connection"); - } - - return sock; - } - - // GetPortV4, GetPortV6, FormatAddress and FormatAddressV6 are copied from referencesource - // TODO: replace FtpWebRequest completely. - private int GetPortV4(string responseString) - { - string [] parsedList = responseString.Split(new char [] {' ', '(', ',', ')'}); - - // We need at least the status code and the port - if (parsedList.Length <= 7) { - throw new FormatException(SR.GetString(SR.net_ftp_response_invalid_format, responseString)); - } - - int index = parsedList.Length-1; - // skip the last non-number token (e.g. terminating '.') -#if MONO - // the MS code expects \r\n here in parsedList[index], - // but we're stripping the EOL off earlier so the array contains - // an empty string here which would make Char.IsNumber throw - // TODO: this can be removed once we switch FtpWebRequest to referencesource - if (parsedList[index] == "" || !Char.IsNumber(parsedList[index], 0)) -#else - if (!Char.IsNumber(parsedList[index], 0)) -#endif - index--; - - int port = Convert.ToByte(parsedList[index--], NumberFormatInfo.InvariantInfo); - port = port | - (Convert.ToByte(parsedList[index--], NumberFormatInfo.InvariantInfo) << 8); - - return port; - } - - private int GetPortV6(string responseString) - { - int pos1 = responseString.LastIndexOf("("); - int pos2 = responseString.LastIndexOf(")"); - if (pos1 == -1 || pos2 <= pos1) - throw new FormatException(SR.GetString(SR.net_ftp_response_invalid_format, responseString)); - - // addressInfo will contain a string of format "||||" - string addressInfo = responseString.Substring(pos1+1, pos2-pos1-1); - - // Although RFC2428 recommends using "|" as the delimiter, - // It allows ASCII characters in range 33-126 inclusive. - // We should consider allowing the full range. - - string [] parsedList = addressInfo.Split(new char [] {'|'}); - if (parsedList.Length < 4) - throw new FormatException(SR.GetString(SR.net_ftp_response_invalid_format, responseString)); - - return Convert.ToInt32(parsedList[3], NumberFormatInfo.InvariantInfo); - } - - private String FormatAddress(IPAddress address, int Port ) - { - byte [] localAddressInBytes = address.GetAddressBytes(); - - // produces a string in FTP IPAddress/Port encoding (a1, a2, a3, a4, p1, p2), for sending as a parameter - // to the port command. - StringBuilder sb = new StringBuilder(32); - foreach (byte element in localAddressInBytes) { - sb.Append(element); - sb.Append(','); - } - sb.Append(Port / 256 ); - sb.Append(','); - sb.Append(Port % 256 ); - return sb.ToString(); - } - - private string FormatAddressV6(IPAddress address, int port) { - StringBuilder sb = new StringBuilder(43); // based on max size of IPv6 address + port + seperators - String addressString = address.ToString(); - sb.Append("|2|"); - sb.Append(addressString); - sb.Append('|'); - sb.Append(port.ToString(NumberFormatInfo.InvariantInfo)); - sb.Append('|'); - return sb.ToString(); - } - // - - Exception CreateExceptionFromResponse (FtpStatus status) - { - FtpWebResponse ftpResponse = new FtpWebResponse (this, requestUri, method, status); - - WebException exc = new WebException ("Server returned an error: " + status.StatusDescription, - null, WebExceptionStatus.ProtocolError, ftpResponse); - return exc; - } - - // Here we could also get a server error, so be cautious - internal void SetTransferCompleted () - { - if (InFinalState ()) - return; - - State = RequestState.Finished; - FtpStatus status = GetResponseStatus (); - ftpResponse.UpdateStatus (status); - if(!keepAlive) - CloseConnection (); - } - - internal void OperationCompleted () - { - if(!keepAlive) - CloseConnection (); - } - - void SetCompleteWithError (Exception exc) - { - if (asyncResult != null) { - asyncResult.SetCompleted (false, exc); - } - } - - Socket InitDataConnection () - { - FtpStatus status; - bool ipv6 = remoteEndPoint.AddressFamily == AddressFamily.InterNetworkV6; - - if (usePassive) { - status = SendCommand (ipv6 ? ExtendedPassiveCommand : PassiveCommand); - if (status.StatusCode != (ipv6 ? (FtpStatusCode)229 : FtpStatusCode.EnteringPassive)) { // FtpStatusCode doesn't contain code 229 for EPSV so we need to cast... - throw CreateExceptionFromResponse (status); - } - - return SetupPassiveConnection (status.StatusDescription, ipv6); - } - - // Open a socket to listen the server's connection - Socket sock = new Socket (remoteEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); - try { - sock.Bind (new IPEndPoint (localEndPoint.Address, 0)); - sock.Listen (1); // We only expect a connection from server - - } catch (SocketException e) { - sock.Close (); - - throw new WebException ("Couldn't open listening socket on client", e); - } - - IPEndPoint ep = (IPEndPoint) sock.LocalEndPoint; - - var portParam = ipv6 ? FormatAddressV6 (ep.Address, ep.Port) : FormatAddress (ep.Address, ep.Port); - - status = SendCommand (ipv6 ? ExtendedPortCommand : PortCommand, portParam); - - if (status.StatusCode != FtpStatusCode.CommandOK) { - sock.Close (); - throw (CreateExceptionFromResponse (status)); - } - - return sock; - } - - void OpenDataConnection () - { - FtpStatus status; - - Socket s = InitDataConnection (); - - // Handle content offset - if (offset > 0) { - status = SendCommand (RestCommand, offset.ToString ()); - if (status.StatusCode != FtpStatusCode.FileCommandPending) - throw CreateExceptionFromResponse (status); - } - - if (method != WebRequestMethods.Ftp.ListDirectory && method != WebRequestMethods.Ftp.ListDirectoryDetails && - method != WebRequestMethods.Ftp.UploadFileWithUniqueName) { - status = SendCommand (method, file_name); - } else { - status = SendCommand (method); - } - - if (status.StatusCode != FtpStatusCode.OpeningData && status.StatusCode != FtpStatusCode.DataAlreadyOpen) - throw CreateExceptionFromResponse (status); - - if (usePassive) { - origDataStream = new NetworkStream (s, true); - dataStream = origDataStream; - if (EnableSsl) - ChangeToSSLSocket (ref dataStream); - } - else { - - // Active connection (use Socket.Blocking to true) - Socket incoming = null; - try { - incoming = s.Accept (); - } - catch (SocketException) { - s.Close (); - if (incoming != null) - incoming.Close (); - - throw new ProtocolViolationException ("Server commited a protocol violation."); - } - - s.Close (); - origDataStream = new NetworkStream (incoming, true); - dataStream = origDataStream; - if (EnableSsl) - ChangeToSSLSocket (ref dataStream); - } - - ftpResponse.UpdateStatus (status); - } - - void Authenticate () - { - string username = null; - string password = null; - string domain = null; - - if (credentials != null) { - username = credentials.UserName; - password = credentials.Password; - domain = credentials.Domain; - } - - if (username == null) - username = "anonymous"; - if (password == null) - password = "@anonymous"; - if (!string.IsNullOrEmpty (domain)) - username = domain + '\\' + username; - - // Connect to server and get banner message - FtpStatus status = GetResponseStatus (); - ftpResponse.BannerMessage = status.StatusDescription; - - if (EnableSsl) { - InitiateSecureConnection (ref controlStream); - controlReader = new StreamReader (controlStream, Encoding.ASCII); - status = SendCommand ("PBSZ", "0"); - int st = (int) status.StatusCode; - if (st < 200 || st >= 300) - throw CreateExceptionFromResponse (status); - // TODO: what if "PROT P" is denied by the server? What does MS do? - status = SendCommand ("PROT", "P"); - st = (int) status.StatusCode; - if (st < 200 || st >= 300) - throw CreateExceptionFromResponse (status); - - status = new FtpStatus (FtpStatusCode.SendUserCommand, ""); - } - - if (status.StatusCode != FtpStatusCode.SendUserCommand) - throw CreateExceptionFromResponse (status); - - status = SendCommand (UserCommand, username); - - switch (status.StatusCode) { - case FtpStatusCode.SendPasswordCommand: - status = SendCommand (PasswordCommand, password); - if (status.StatusCode != FtpStatusCode.LoggedInProceed) - throw CreateExceptionFromResponse (status); - break; - case FtpStatusCode.LoggedInProceed: - break; - default: - throw CreateExceptionFromResponse (status); - } - - ftpResponse.WelcomeMessage = status.StatusDescription; - ftpResponse.UpdateStatus (status); - } - - FtpStatus SendCommand (string command, params string [] parameters) { - return SendCommand (true, command, parameters); - } - - FtpStatus SendCommand (bool waitResponse, string command, params string [] parameters) - { - byte [] cmd; - string commandString = command; - if (parameters.Length > 0) - commandString += " " + String.Join (" ", parameters); - - commandString += EOL; - cmd = dataEncoding.GetBytes (commandString); - try { - controlStream.Write (cmd, 0, cmd.Length); - } catch (IOException) { - //controlStream.Close (); - return new FtpStatus(FtpStatusCode.ServiceNotAvailable, "Write failed"); - } - - if(!waitResponse) - return null; - - FtpStatus result = GetResponseStatus (); - if (ftpResponse != null) - ftpResponse.UpdateStatus (result); - return result; - } - - internal static FtpStatus ServiceNotAvailable () - { - return new FtpStatus (FtpStatusCode.ServiceNotAvailable, Locale.GetText ("Invalid response from server")); - } - - internal FtpStatus GetResponseStatus () - { - while (true) { - string response = null; - - try { - response = controlReader.ReadLine (); - } catch (IOException) { - } - - if (response == null || response.Length < 3) - return ServiceNotAvailable (); - - int code; - if (!Int32.TryParse (response.Substring (0, 3), out code)) - return ServiceNotAvailable (); - - if (response.Length > 3 && response [3] == '-'){ - string line = null; - string find = code.ToString() + ' '; - while (true){ - line = null; - try { - line = controlReader.ReadLine(); - } catch (IOException) { - } - if (line == null) - return ServiceNotAvailable (); - - response += Environment.NewLine + line; - - if (line.StartsWith(find, StringComparison.Ordinal)) - break; - } - } - return new FtpStatus ((FtpStatusCode) code, response); - } - } - - private void InitiateSecureConnection (ref Stream stream) { - FtpStatus status = SendCommand (AuthCommand, "TLS"); - if (status.StatusCode != FtpStatusCode.ServerWantsSecureSession) - throw CreateExceptionFromResponse (status); - - ChangeToSSLSocket (ref stream); - } - - internal bool ChangeToSSLSocket (ref Stream stream) { -#if SECURITY_DEP - var provider = MonoTlsProviderFactory.GetProviderInternal (); - var settings = MSI.MonoTlsSettings.CopyDefaultSettings (); - settings.UseServicePointManagerCallback = true; - var sslStream = provider.CreateSslStream (stream, true, settings); - sslStream.AuthenticateAsClient (requestUri.Host, null, SslProtocols.Default, false); - stream = sslStream.AuthenticatedStream; - return true; -#else - throw new NotImplementedException (); -#endif - } - - bool InFinalState () { - return (State == RequestState.Aborted || State == RequestState.Error || State == RequestState.Finished); - } - - bool InProgress () { - return (State != RequestState.Before && !InFinalState ()); - } - - internal void CheckIfAborted () { - if (State == RequestState.Aborted) - throw new WebException ("Request aborted", WebExceptionStatus.RequestCanceled); - } - - void CheckFinalState () { - if (InFinalState ()) - throw new InvalidOperationException ("Cannot change final state"); - } - } -} - - diff --git a/mcs/class/System/System.Net/FtpWebResponse.cs b/mcs/class/System/System.Net/FtpWebResponse.cs deleted file mode 100644 index ba47bdfb36..0000000000 --- a/mcs/class/System/System.Net/FtpWebResponse.cs +++ /dev/null @@ -1,184 +0,0 @@ -// -// System.Net.FtpWebResponse.cs -// -// Authors: -// Carlos Alberto Cortez (calberto.cortez@gmail.com) -// -// (c) Copyright 2006 Novell, Inc. (http://www.novell.com) -// - -using System; -using System.IO; -using System.Runtime.Serialization; -using System.Net; - -namespace System.Net -{ - public class FtpWebResponse : WebResponse - { - Stream stream; - Uri uri; - FtpStatusCode statusCode; - DateTime lastModified = DateTime.MinValue; - string bannerMessage = String.Empty; - string welcomeMessage = String.Empty; - string exitMessage = String.Empty; - string statusDescription; - string method; - //bool keepAlive; - bool disposed; - FtpWebRequest request; - internal long contentLength = -1; - - internal FtpWebResponse (FtpWebRequest request, Uri uri, string method, bool keepAlive) - { - this.request = request; - this.uri = uri; - this.method = method; - //this.keepAlive = keepAlive; - } - - internal FtpWebResponse (FtpWebRequest request, Uri uri, string method, FtpStatusCode statusCode, string statusDescription) - { - this.request = request; - this.uri = uri; - this.method = method; - this.statusCode = statusCode; - this.statusDescription = statusDescription; - } - - internal FtpWebResponse (FtpWebRequest request, Uri uri, string method, FtpStatus status) : - this (request, uri, method, status.StatusCode, status.StatusDescription) - { - } - - public override long ContentLength { - get { - return contentLength; - } - } - - public override WebHeaderCollection Headers { - get { - return new WebHeaderCollection (); - } - } - - public override Uri ResponseUri { - get { - return uri; - } - } - - public DateTime LastModified { - get { - return lastModified; - } - internal set { - lastModified = value; - } - } - - public string BannerMessage { - get { - return bannerMessage; - } - internal set { - bannerMessage = value; - } - } - - public string WelcomeMessage { - get { - return welcomeMessage; - } - internal set { - welcomeMessage = value; - } - } - - public string ExitMessage { - get { - return exitMessage; - } - internal set { - exitMessage = value; - } - } - - public FtpStatusCode StatusCode { - get { - return statusCode; - } - internal set { - statusCode = value; - } - } - - public override bool SupportsHeaders { - get { - return true; - } - } - - public string StatusDescription { - get { - return statusDescription; - } - internal set { - statusDescription = value; - } - } - - public override void Close () - { - if (disposed) - return; - - disposed = true; - if (stream != null) { - stream.Close (); - if (stream == Stream.Null) - request.OperationCompleted (); - } - stream = null; - } - - public override Stream GetResponseStream () - { - if (stream == null) - return Stream.Null; // After a STOR we get this - - if (method != WebRequestMethods.Ftp.DownloadFile && - method != WebRequestMethods.Ftp.ListDirectory) - CheckDisposed (); - - return stream; - } - - internal Stream Stream { - set { - stream = value; - } - - get { return stream; } - } - - internal void UpdateStatus (FtpStatus status) { - statusCode = status.StatusCode; - statusDescription = status.StatusDescription; - } - - void CheckDisposed () - { - if (disposed) - throw new ObjectDisposedException (GetType ().FullName); - } - - internal bool IsFinal () { - return ((int) statusCode >= 200); - } - } -} - - diff --git a/mcs/class/System/System.Security.Cryptography.X509Certificates/PublicKey.cs b/mcs/class/System/System.Security.Cryptography.X509Certificates/PublicKey.cs index 15641f2642..00069db119 100644 --- a/mcs/class/System/System.Security.Cryptography.X509Certificates/PublicKey.cs +++ b/mcs/class/System/System.Security.Cryptography.X509Certificates/PublicKey.cs @@ -42,10 +42,14 @@ using Mono.Security.Cryptography; using MSX = Mono.Security.X509; #endif +#endif + namespace System.Security.Cryptography.X509Certificates { public sealed class PublicKey { +#if SECURITY_DEP + private const string rsaOid = "1.2.840.113549.1.1.1"; private const string dsaOid = "1.2.840.10040.4.1"; @@ -223,7 +227,17 @@ namespace System.Security.Cryptography.X509Certificates { rsa.ImportParameters (rsaParams); return rsa; } +#else + private PublicKey () + { + } + + + public AsymmetricAlgorithm Key { + get { + return null; + } + } +#endif } } - -#endif diff --git a/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2.cs b/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2.cs index ef10413f59..c31141c3cb 100644 --- a/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2.cs +++ b/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2.cs @@ -27,8 +27,6 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -#if SECURITY_DEP - #if MONO_SECURITY_ALIAS extern alias MonoSecurity; using MonoSecurity::Mono.Security; @@ -40,8 +38,6 @@ using Mono.Security.Cryptography; using MX = Mono.Security.X509; #endif -#endif - using System.IO; using System.Text; using System.Collections; @@ -52,13 +48,6 @@ namespace System.Security.Cryptography.X509Certificates { [Serializable] public class X509Certificate2 : X509Certificate { -#if !SECURITY_DEP - // Used in Mono.Security HttpsClientStream - public X509Certificate2 (byte[] rawData) - { - } -#endif -#if SECURITY_DEP new internal X509Certificate2Impl Impl { get { var impl2 = base.Impl as X509Certificate2Impl; @@ -405,13 +394,5 @@ namespace System.Security.Cryptography.X509Certificates { return X509Helper2.GetMonoCertificate (this); } } - -#else - // HACK - this ensure the type X509Certificate2 and PrivateKey property exists in the build before - // Mono.Security.dll is built. This is required to get working client certificate in SSL/TLS - public AsymmetricAlgorithm PrivateKey { - get { return null; } - } -#endif } } diff --git a/mcs/class/System/System_test.dll.sources b/mcs/class/System/System_test.dll.sources index 150b363b6a..00be693eaf 100644 --- a/mcs/class/System/System_test.dll.sources +++ b/mcs/class/System/System_test.dll.sources @@ -199,6 +199,7 @@ System.Diagnostics/EventSourceCreationDataTest.cs System.Diagnostics/FileVersionInfoTest.cs System.Diagnostics/PerformanceCounterPermissionAttributeTest.cs System.Diagnostics/PerformanceCounterPermissionTest.cs +System.Diagnostics/PerformanceCounterTest.cs System.Diagnostics/ProcessStartInfoTest.cs System.Diagnostics/ProcessTest.cs System.Diagnostics/CounterCreationDataTest.cs @@ -217,7 +218,7 @@ System.Net/DnsTest.cs System.Net/EndPointTest.cs System.Net/FileWebRequestTest.cs System.Net/FileWebResponseTest.cs -System.Net/FtpWebRequestTest.cs +#System.Net/FtpWebRequestTest.cs System.Net/HttpWebRequestTest.cs System.Net/HttpWebResponseTest.cs System.Net/HttpListenerTest.cs diff --git a/mcs/class/System/Test/System.Configuration/ApplicationSettingsBaseTest.cs b/mcs/class/System/Test/System.Configuration/ApplicationSettingsBaseTest.cs index e80672a91d..562e524601 100644 --- a/mcs/class/System/Test/System.Configuration/ApplicationSettingsBaseTest.cs +++ b/mcs/class/System/Test/System.Configuration/ApplicationSettingsBaseTest.cs @@ -418,6 +418,7 @@ namespace MonoTests.System.Configuration { } [Test] + [Category ("NotOnWindows")] // https://github.com/mono/mono/issues/7343 public void TestBug8592BasicOperations () { var holder = new Bug8592ConfHolder (); diff --git a/mcs/class/System/Test/System.Diagnostics/PerformanceCounterTest.cs b/mcs/class/System/Test/System.Diagnostics/PerformanceCounterTest.cs new file mode 100644 index 0000000000..ae076113ef --- /dev/null +++ b/mcs/class/System/Test/System.Diagnostics/PerformanceCounterTest.cs @@ -0,0 +1,332 @@ +// This test code derives from two places: +// +// 1. +// originally copied from external/corefx +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// +// 2. MSDN +// https://msdn.microsoft.com/en-us/library/system.diagnostics.countercreationdata(v=vs.110).aspx +// +// Neither has been very significantly changed. +// + +using NUnit.Framework; +using System; +using System.Threading; +using System.Diagnostics; +using System.Collections; +using System.Collections.Specialized; + +#if !MOBILE + +namespace MonoTests.System.Diagnostics +{ + // The first part is from external/corefx. + internal class Common + { + internal string guid; + internal string baseName; + internal string name; + internal string category; + internal CounterCreationDataCollection counterDataCollection; + internal CounterCreationData counter; + internal CounterCreationData counterBase; + internal PerformanceCounter counterSample; + internal PerformanceCounterCategory pcc; + + internal Common () + { + guid = Guid.NewGuid ().ToString ("N"); + name = guid + "_Counter"; + category = name + "_Category"; + counterDataCollection = new CounterCreationDataCollection (); + + // Add the counter. + counter = new CounterCreationData (); + counter.CounterType = PerformanceCounterType.AverageCount64; + counter.CounterName = name; + counterDataCollection.Add (counter); + + // Add the base counter. + counterBase = new CounterCreationData (); + counterBase.CounterType = PerformanceCounterType.AverageBase; + baseName = name + "Base"; + counterBase.CounterName = baseName; + counterDataCollection.Add (counterBase); + + // Create the category. + PerformanceCounterCategory.Create (category, "description", + PerformanceCounterCategoryType.SingleInstance, counterDataCollection); + + counterSample = new PerformanceCounter (category, name, false); + + counterSample.RawValue = 0; + + pcc = new PerformanceCounterCategory (category); + } + } + + [TestFixture] + public class PerformanceCounterTest + { + bool verbose = Environment.GetEnvironmentVariable ("V") != null; + + Common a = new Common (); + + void WriteLine (string arg) + { + if (!verbose) + return; + Console.WriteLine (arg); + } + + [Test] + public void PerformanceCounterCategory_CreateCategory () + { + WriteLine ("PerformanceCounterCategory_CreateCategory"); + + var guid = Guid.NewGuid ().ToString ("N"); + string name = "AverageCounter64Sample" + guid; + + Assert.False (PerformanceCounterCategory.Exists (name + "Category")); + + CounterCreationDataCollection counterDataCollection = new CounterCreationDataCollection (); + + // Add the counter. + CounterCreationData averageCount64 = new CounterCreationData (); + averageCount64.CounterType = PerformanceCounterType.AverageCount64; + averageCount64.CounterName = name; + counterDataCollection.Add (averageCount64); + + // Add the base counter. + CounterCreationData averageCount64Base = new CounterCreationData (); + averageCount64Base.CounterType = PerformanceCounterType.AverageBase; + averageCount64Base.CounterName = name + "Base"; + counterDataCollection.Add (averageCount64Base); + + // Create the category. + PerformanceCounterCategory.Create (name + "Category", + "Demonstrates usage of the AverageCounter64 performance counter type.", + PerformanceCounterCategoryType.SingleInstance, counterDataCollection); + + Assert.True (PerformanceCounterCategory.Exists (name + "Category")); + + WriteLine ("PerformanceCounterCategory_CreateCategory end"); + } + + [Test] + public void PerformanceCounter_CreateCounter_Count0 () + { + WriteLine ("PerformanceCounter_CreateCounter_Count0 start"); + Assert.AreEqual (0, a.counterSample.RawValue); + a.counterSample.Increment (); + Assert.AreEqual (1, a.counterSample.RawValue); + WriteLine ("PerformanceCounter_CreateCounter_Count0 end"); + } + + [Test] + public void PerformanceCounter_InstanceNames () + { + WriteLine ("PerformanceCounter_InstanceNames start"); + var names = a.pcc.GetInstanceNames (); + WriteLine ($"\nPerformanceCounter_InstanceNames {a.name} {a.pcc} {names} {names.Length}"); + Assert.That (new [] { a.baseName, a.name }, Is.EquivalentTo (names)); + WriteLine ("PerformanceCounter_InstanceNames end"); + } + + [Test] + public void PerformanceCounter_Counters () + { + WriteLine ("PerformanceCounter_Counters start"); + var counters = a.pcc.GetCounters (a.name); + Assert.AreEqual (2, counters.Length); + Assert.That (new [ ] { + new string [ ] { counters[0].CategoryName, counters[0].CounterName, counters[0].InstanceName, counters[0].RawValue.ToString () }, + new string [ ] { counters[1].CategoryName, counters[1].CounterName, counters[1].InstanceName, counters[1].RawValue.ToString () } + }, + Is.EquivalentTo (new [ ] { + new string [ ] { a.category, a.baseName, a.name, "0" }, + new string [ ] { a.category, a.name, a.name, "0" } + })); + int i = 0; + foreach (var b in counters) + { + var category = b.CategoryName; + var name = b.CounterName; + var instance = b.InstanceName; + var value = b.RawValue; + WriteLine ($"i:{i} category:{category} counter:{name} instance:{instance} value:{value}"); + ++i; + Assert.True (name == a.name || name == a.baseName); + Assert.AreEqual (a.name, instance); + Assert.AreEqual (a.category, category); + Assert.AreEqual (0, value); + } + WriteLine ("PerformanceCounter_Counters end"); + } + +// The rest of this file is from MSDN. +// https://msdn.microsoft.com/en-us/library/system.diagnostics.countercreationdata(v=vs.110).aspx + + [Test] + public void MsdnTest1 () + { + WriteLine ("MsdnTest1 2"); + ArrayList samplesList = new ArrayList (); + + SetupCategory (); + + WriteLine ("MsdnTest1 3"); + CreateCounters (); + WriteLine ("MsdnTest1 4"); + CollectSamples (samplesList); + WriteLine ("MsdnTest1 5"); + CalculateResults (samplesList); + WriteLine ("MsdnTest1 6"); + } + + static PerformanceCounter avgCounter64Sample; + static PerformanceCounter avgCounter64SampleBase; + + bool SetupCategory () + { + WriteLine ("MsdnTest1 SetupCategory start"); + + if (!PerformanceCounterCategory.Exists ("AverageCounter64SampleCategory")) + { + CounterCreationDataCollection counterDataCollection = new CounterCreationDataCollection (); + + // Add the counter. + CounterCreationData averageCount64 = new CounterCreationData (); + averageCount64.CounterType = PerformanceCounterType.AverageCount64; + averageCount64.CounterName = "AverageCounter64Sample"; + counterDataCollection.Add (averageCount64); + + // Add the base counter. + CounterCreationData averageCount64Base = new CounterCreationData (); + averageCount64Base.CounterType = PerformanceCounterType.AverageBase; + averageCount64Base.CounterName = "AverageCounter64SampleBase"; + counterDataCollection.Add (averageCount64Base); + + // Create the category. + PerformanceCounterCategory.Create ("AverageCounter64SampleCategory", + "Demonstrates usage of the AverageCounter64 performance counter type.", + PerformanceCounterCategoryType.SingleInstance, counterDataCollection); + + return true; + } + WriteLine ("Category exists - AverageCounter64SampleCategory"); + WriteLine ("MSDN_PerformanceCounterTest SetupCategory end"); + return false; + } + + void CreateCounters () + { + // Create the counters. + avgCounter64Sample = new PerformanceCounter ("AverageCounter64SampleCategory", + "AverageCounter64Sample", + false); + + avgCounter64SampleBase = new PerformanceCounter ("AverageCounter64SampleCategory", + "AverageCounter64SampleBase", + false); + + avgCounter64Sample.RawValue = 0; + avgCounter64SampleBase.RawValue = 0; + } + + void CollectSamples (ArrayList samplesList) + { + Random r = new Random (DateTime.Now.Millisecond); + + // Loop for the samples. + for (int j = 0; j < 100; j++) + { + int value = r.Next (1, 10); + if (verbose) + Console.Write (j + " = " + value); + + avgCounter64Sample.IncrementBy (value); + + avgCounter64SampleBase.Increment (); + + if ( (j % 10) == 9) + { + OutputSample (avgCounter64Sample.NextSample ()); + samplesList.Add ( avgCounter64Sample.NextSample () ); + } + else if (verbose) + Console.WriteLine (); + + Thread.Sleep (50); + } + } + + void CalculateResults (ArrayList samplesList) + { + for (int i = 0; i < (samplesList.Count - 1); i++) + { + // Output the sample. + OutputSample ( (CounterSample)samplesList[i] ); + OutputSample ( (CounterSample)samplesList[i+1] ); + + // Use .NET to calculate the counter value. + if (verbose) + { + Console.WriteLine (".NET computed counter value = " + + CounterSampleCalculator.ComputeCounterValue ( (CounterSample)samplesList[i], + (CounterSample)samplesList[i+1]) ); + + // Calculate the counter value manually. + Console.WriteLine ("My computed counter value = " + + MyComputeCounterValue ( (CounterSample)samplesList[i], + (CounterSample)samplesList[i+1]) ); + } + } + } + + //++++++++//++++++++//++++++++//++++++++//++++++++//++++++++//++++++++//++++++++ + // Description - This counter type shows how many items are processed, on average, + // during an operation. Counters of this type display a ratio of the items + // processed (such as bytes sent) to the number of operations completed. The + // ratio is calculated by comparing the number of items processed during the + // last interval to the number of operations completed during the last interval. + // Generic type - Average + // Formula - (N1 - N0) / (D1 - D0), where the numerator (N) represents the number + // of items processed during the last sample interval and the denominator (D) + // represents the number of operations completed during the last two sample + // intervals. + // Average (Nx - N0) / (Dx - D0) + // Example PhysicalDisk\ Avg. Disk Bytes/Transfer + //++++++++//++++++++//++++++++//++++++++//++++++++//++++++++//++++++++//++++++++ + Single MyComputeCounterValue (CounterSample s0, CounterSample s1) + { + Single numerator = (Single)s1.RawValue - (Single)s0.RawValue; + Single denomenator = (Single)s1.BaseValue - (Single)s0.BaseValue; + Single counterValue = numerator / denomenator; + return counterValue; + } + + // Output information about the counter sample. + void OutputSample (CounterSample s) + { + if (!verbose) + return; + WriteLine ("\r\n+++++++++++"); + WriteLine ("Sample values - \r\n"); + WriteLine (" BaseValue = " + s.BaseValue); + WriteLine (" CounterFrequency = " + s.CounterFrequency); + WriteLine (" CounterTimeStamp = " + s.CounterTimeStamp); + WriteLine (" CounterType = " + s.CounterType); + WriteLine (" RawValue = " + s.RawValue); + WriteLine (" SystemFrequency = " + s.SystemFrequency); + WriteLine (" TimeStamp = " + s.TimeStamp); + WriteLine (" TimeStamp100nSec = " + s.TimeStamp100nSec); + WriteLine ("++++++++++++++++++++++"); + } + } +} + +#endif diff --git a/mcs/class/System/Test/System.Net/FtpWebRequestTest.cs b/mcs/class/System/Test/System.Net/FtpWebRequestTest.cs deleted file mode 100644 index dd5df82310..0000000000 --- a/mcs/class/System/Test/System.Net/FtpWebRequestTest.cs +++ /dev/null @@ -1,864 +0,0 @@ -// -// FtpWebRequestTest.cs - NUnit Test Cases for System.Net.FtpWebRequest -// -// Authors: -// Carlos Alberto Cortez -// Gonzalo Paniagua Javier -// -// Copyright (c) 2006,2007,2008 Novell, Inc. (http://www.novell.com) -// -using NUnit.Framework; -using System; -using System.Collections.Generic; -using System.IO; -using System.Net; -using System.Net.Sockets; -using System.Text; -using System.Threading; - -namespace MonoTests.System.Net -{ - [TestFixture] - public class FtpWebRequestTest - { - FtpWebRequest _defaultRequest; - FtpWebRequest defaultRequest { - get { return _defaultRequest ?? (_defaultRequest = (FtpWebRequest) WebRequest.Create ("ftp://www.contoso.com")); } - } - - private string _tempDirectory; - private string _tempFile; - - [SetUp] - public void SetUp () - { - _tempDirectory = Path.Combine (Path.GetTempPath (), "MonoTests.System.Net.FileWebRequestTest"); - _tempFile = Path.Combine (_tempDirectory, "FtpWebRequestTest.tmp"); - if (!Directory.Exists (_tempDirectory)) { - Directory.CreateDirectory (_tempDirectory); - } else { - // ensure no files are left over from previous runs - string [] files = Directory.GetFiles (_tempDirectory, "*"); - foreach (string file in files) - File.Delete (file); - } - } - - [TearDown] - public void TearDown () - { - if (Directory.Exists (_tempDirectory)) - Directory.Delete (_tempDirectory, true); - } - - [Test] - public void ContentLength () - { - try { - long l = defaultRequest.ContentLength; -#if FEATURE_NO_BSD_SOCKETS - Assert.Fail ("#1a"); - } catch (PlatformNotSupportedException) { - // OK. -#else - } catch (NotSupportedException) { - Assert.Fail ("#1"); // Not overriden -#endif - } - - try { - defaultRequest.ContentLength = 2; -#if FEATURE_NO_BSD_SOCKETS - Assert.Fail ("#2a"); - } catch (PlatformNotSupportedException) { - // OK. -#else - } catch (NotSupportedException) { - Assert.Fail ("#2"); // Not overriden -#endif - } - } - - [Test] - public void ContentType () - { - try { - string t = defaultRequest.ContentType; - Assert.Fail ("#1"); - } catch (NotSupportedException) { - } - - try { - defaultRequest.ContentType = String.Empty; - Assert.Fail ("#2"); - } catch (NotSupportedException) { - } - } - - [Test] -#if FEATURE_NO_BSD_SOCKETS - [ExpectedException (typeof (PlatformNotSupportedException))] -#endif - public void ContentOffset () - { - try { - defaultRequest.ContentOffset = -2; - Assert.Fail ("#1"); - } catch (ArgumentOutOfRangeException) { - } - } - - [Test] -#if FEATURE_NO_BSD_SOCKETS - [ExpectedException (typeof (PlatformNotSupportedException))] -#endif - public void Credentials () - { - try { - defaultRequest.Credentials = null; - Assert.Fail ("#1"); - } catch (ArgumentNullException) { - } - - } - - [Test] -#if FEATURE_NO_BSD_SOCKETS - [ExpectedException (typeof (PlatformNotSupportedException))] -#endif - public void Method () - { - try { - defaultRequest.Method = null; - Assert.Fail ("#1"); - } catch (ArgumentNullException) { - } - - try { - defaultRequest.Method = String.Empty; - Assert.Fail ("#2"); - } catch (ArgumentException) { - } - - try { - defaultRequest.Method = "WrongValue"; - Assert.Fail ("#3"); - } catch (ArgumentException) { - } - } - - [Test] - public void PreAuthenticate () - { - try { - bool p = defaultRequest.PreAuthenticate; - Assert.Fail ("#1"); - } catch (NotSupportedException) { - } - - try { - defaultRequest.PreAuthenticate = true; - } catch (NotSupportedException) { - } - } - - [Test] -#if FEATURE_NO_BSD_SOCKETS - [ExpectedException (typeof (PlatformNotSupportedException))] -#endif - public void ReadWriteTimeout () - { - try { - defaultRequest.ReadWriteTimeout = -2; - Assert.Fail ("#2"); - } catch (ArgumentOutOfRangeException) { - } - } - - [Test] -#if FEATURE_NO_BSD_SOCKETS - [ExpectedException (typeof (PlatformNotSupportedException))] -#endif - public void Timeout () - { - try { - defaultRequest.Timeout = -2; - Assert.Fail ("#2"); - } catch (ArgumentOutOfRangeException) { - } - } - - [Test] -#if FEATURE_NO_BSD_SOCKETS - [ExpectedException (typeof (PlatformNotSupportedException))] -#endif - public void DefaultValues () - { - FtpWebRequest request = (FtpWebRequest) WebRequest.Create ("ftp://www.contoso.com"); - - Assert.AreEqual (0, request.ContentOffset, "ContentOffset"); - Assert.AreEqual (false, request.EnableSsl, "EnableSsl"); - // FIXME: Disabled this one by now. KeepAlive is not well supported. - // Assert.AreEqual (true, request.KeepAlive, "KeepAlive"); - Assert.AreEqual (WebRequestMethods.Ftp.DownloadFile, request.Method, "#1"); - Assert.AreEqual (300000, request.ReadWriteTimeout, "ReadWriteTimeout"); - Assert.IsNull (request.RenameTo, "RenameTo"); - Assert.AreEqual (true, request.UseBinary, "UseBinary"); - Assert.AreEqual (100000, request.Timeout, "Timeout"); - Assert.AreEqual (true, request.UsePassive, "UsePassive"); - } - - [Test] -#if FEATURE_NO_BSD_SOCKETS - [ExpectedException (typeof (PlatformNotSupportedException))] -#endif - public void RenameTo () - { - try { - defaultRequest.RenameTo = null; - Assert.Fail ("#1"); - } catch (ArgumentException) { - } - - try { - defaultRequest.RenameTo = String.Empty; - Assert.Fail ("#2"); - } catch (ArgumentException) { - } - } - - [Test] -#if FEATURE_NO_BSD_SOCKETS - [ExpectedException (typeof (PlatformNotSupportedException))] -#endif - public void UploadFile1_v4 () - { - UploadFile1 (false); - } - - [Test] -#if FEATURE_NO_BSD_SOCKETS - [ExpectedException (typeof (PlatformNotSupportedException))] -#endif - public void UploadFile1_v6 () - { - if (!Socket.OSSupportsIPv6) - Assert.Ignore ("IPv6 not supported."); - - UploadFile1 (true); - } - - void UploadFile1 (bool ipv6) - { - ServerPut sp = new ServerPut (ipv6); - sp.Start (); - string uri = String.Format ("ftp://{0}:{1}/uploads/file.txt", EncloseIPv6 (sp.IPAddress), sp.Port); - try { - FtpWebRequest ftp = (FtpWebRequest) WebRequest.Create (uri); - ftp.KeepAlive = false; - ftp.Timeout = 5000; - ftp.Method = WebRequestMethods.Ftp.UploadFile; - ftp.ContentLength = 10; - ftp.UseBinary = true; - Stream stream = ftp.GetRequestStream (); - for (int i = 0; i < 10; i++) - stream.WriteByte ((byte)i); - stream.Close (); - FtpWebResponse response = (FtpWebResponse) ftp.GetResponse (); - Assert.IsTrue ((int) response.StatusCode >= 200 && (int) response.StatusCode < 300, "UP#01"); - Assert.AreEqual (10, sp.result.Count, "UP#02"); - response.Close (); - } catch (Exception) { - if (!String.IsNullOrEmpty (sp.Where)) - throw new Exception (sp.Where); - throw; - } finally { - sp.Stop (); - } - } - - [Test] -#if FEATURE_NO_BSD_SOCKETS - [ExpectedException (typeof (PlatformNotSupportedException))] -#endif - public void UploadFile_WebClient_v4 () - { - UploadFile_WebClient (false); - } - - [Test] -#if FEATURE_NO_BSD_SOCKETS - [ExpectedException (typeof (PlatformNotSupportedException))] -#endif - public void UploadFile_WebClient_v6 () - { - if (!Socket.OSSupportsIPv6) - Assert.Ignore ("IPv6 not supported."); - - UploadFile_WebClient (true); - } - - public void UploadFile_WebClient (bool ipv6) - { - ServerPut sp = new ServerPut (ipv6); - File.WriteAllText (_tempFile, "0123456789"); - sp.Start (); - - using (WebClient m_WebClient = new WebClient()) - { - string uri = String.Format ("ftp://{0}:{1}/uploads/file.txt", EncloseIPv6 (sp.IPAddress), sp.Port); - - m_WebClient.UploadFile(uri, _tempFile); - } - Assert.AreEqual (10, sp.result.Count, "WebClient/Ftp#01"); - - sp.Stop (); - } - - [Test] -#if FEATURE_NO_BSD_SOCKETS - [ExpectedException (typeof (PlatformNotSupportedException))] -#endif - public void DownloadFile1_v4 () - { - DownloadFile (new ServerDownload (false)); - } - - [Test] -#if FEATURE_NO_BSD_SOCKETS - [ExpectedException (typeof (PlatformNotSupportedException))] -#endif - public void DownloadFile1_v6 () - { - if (!Socket.OSSupportsIPv6) - Assert.Ignore ("IPv6 not supported."); - - DownloadFile (new ServerDownload (true)); - } - - [Test] -#if FEATURE_NO_BSD_SOCKETS - [ExpectedException (typeof (PlatformNotSupportedException))] -#endif - public void DownloadFileNonLatinChars () - { - string filename = "\u0411\u0430\u0448\u043DRowan-\u041F\u0435\u0441\u043D\u043F\u0440\u043E\u043C\u043E\u043D\u0430\u0445\u0430\u0422\u0435\u043E\u0434\u043E\u0440\u0443\u0441\u0430\u0438\u0437\u0413\u0430\u043C\u043C\u0435\u043B\u044C\u043D\u0430.mp3"; - DownloadFile (new ServerDownload (null, null, filename, false), "ftp://{0}:{1}/" + filename); - } - - void DownloadFile (ServerDownload sp, string uriTemplate = "ftp://{0}:{1}/file.txt") - { - sp.Start (); - string uri = String.Format (uriTemplate, EncloseIPv6 (sp.IPAddress), sp.Port); - try { - FtpWebRequest ftp = (FtpWebRequest) WebRequest.Create (uri); - ftp.KeepAlive = false; - ftp.Timeout = 5000; - ftp.Method = WebRequestMethods.Ftp.DownloadFile; - ftp.UseBinary = true; - FtpWebResponse response = (FtpWebResponse) ftp.GetResponse (); - Assert.IsTrue ((int) response.StatusCode >= 100 && (int) response.StatusCode < 200, "DL#01"); - using (Stream st = response.GetResponseStream ()) { - } - // This should be "220 Bye" or similar (no KeepAlive) - Assert.IsTrue ((int) response.StatusCode >= 200 && (int) response.StatusCode < 300, "DL#02"); - response.Close (); - } catch (Exception) { - if (!String.IsNullOrEmpty (sp.Where)) - throw new Exception (sp.Where); - throw; - } finally { - sp.Stop (); - } - } - - [Test] -#if FEATURE_NO_BSD_SOCKETS - [ExpectedException (typeof (PlatformNotSupportedException))] -#endif - public void DownloadFile2_v4 () - { - // Some embedded FTP servers in Industrial Automation Hardware report - // the PWD using backslashes, but allow forward slashes for CWD. - DownloadFile (new ServerDownload (@"\Users\someuser", "/Users/someuser/", null, false)); - } - - [Test] -#if FEATURE_NO_BSD_SOCKETS - [ExpectedException (typeof (PlatformNotSupportedException))] -#endif - public void DownloadFile2_v6 () - { - if (!Socket.OSSupportsIPv6) - Assert.Ignore ("IPv6 not supported."); - - // Some embedded FTP servers in Industrial Automation Hardware report - // the PWD using backslashes, but allow forward slashes for CWD. - DownloadFile (new ServerDownload (@"\Users\someuser", "/Users/someuser/", null, true)); - } - - [Test] -#if FEATURE_NO_BSD_SOCKETS - [ExpectedException (typeof (PlatformNotSupportedException))] -#endif - public void DeleteFile1_v4 () - { - DeleteFile1 (false); - } - - [Test] -#if FEATURE_NO_BSD_SOCKETS - [ExpectedException (typeof (PlatformNotSupportedException))] -#endif - public void DeleteFile1_v6 () - { - if (!Socket.OSSupportsIPv6) - Assert.Ignore ("IPv6 not supported."); - - DeleteFile1 (true); - } - - void DeleteFile1 (bool ipv6) - { - ServerDeleteFile sp = new ServerDeleteFile (ipv6); - sp.Start (); - string uri = String.Format ("ftp://{0}:{1}/file.txt", EncloseIPv6 (sp.IPAddress), sp.Port); - try { - FtpWebRequest ftp = (FtpWebRequest) WebRequest.Create (uri); - Console.WriteLine (ftp.RequestUri); - ftp.KeepAlive = false; - ftp.Timeout = 5000; - ftp.Method = WebRequestMethods.Ftp.DeleteFile; - ftp.UseBinary = true; - FtpWebResponse response = (FtpWebResponse) ftp.GetResponse (); - Assert.IsTrue ((int) response.StatusCode >= 200 && (int) response.StatusCode < 300, "DF#01"); - response.Close (); - } catch (Exception e) { - Console.WriteLine (e); - if (!String.IsNullOrEmpty (sp.Where)) - throw new Exception (sp.Where); - throw; - } finally { - sp.Stop (); - } - } - - [Test] -#if FEATURE_NO_BSD_SOCKETS - [ExpectedException (typeof (PlatformNotSupportedException))] -#endif - public void ListDirectory1_v4 () - { - ListDirectory1 (false); - } - - [Test] -#if FEATURE_NO_BSD_SOCKETS - [ExpectedException (typeof (PlatformNotSupportedException))] -#endif - public void ListDirectory1_v6 () - { - if (!Socket.OSSupportsIPv6) - Assert.Ignore ("IPv6 not supported."); - - ListDirectory1 (true); - } - - void ListDirectory1 (bool ipv6) - { - ServerListDirectory sp = new ServerListDirectory (ipv6); - sp.Start (); - string uri = String.Format ("ftp://{0}:{1}/somedir/", EncloseIPv6 (sp.IPAddress), sp.Port); - try { - FtpWebRequest ftp = (FtpWebRequest) WebRequest.Create (uri); - Console.WriteLine (ftp.RequestUri); - ftp.KeepAlive = false; - ftp.Timeout = 5000; - ftp.Method = WebRequestMethods.Ftp.ListDirectoryDetails; - ftp.UseBinary = true; - using (FtpWebResponse response = (FtpWebResponse) ftp.GetResponse ()) { - StreamReader reader = new StreamReader (response.GetResponseStream ()); - string result = reader.ReadToEnd (); - Assert.IsTrue ((int) response.StatusCode >= 200 && (int) response.StatusCode < 300, "DF#01"); - } - } catch (Exception e) { - Console.WriteLine (e); - if (!String.IsNullOrEmpty (sp.Where)) - throw new Exception (sp.Where); - throw; - } finally { - sp.Stop (); - } - } - - string EncloseIPv6 (IPAddress address) - { - if (address.AddressFamily == AddressFamily.InterNetwork) - return address.ToString (); - - return String.Format ("[{0}]", address.ToString ()); - } - - class ServerListDirectory : FtpServer { - public ServerListDirectory (bool ipv6) - : base (ipv6) - { - } - - protected override void Run () - { - Socket client = control.Accept (); - NetworkStream ns = new NetworkStream (client, false); - StreamWriter writer = new StreamWriter (ns, Encoding.ASCII); - StreamReader reader = new StreamReader (ns, Encoding.UTF8); - if (!DoAnonymousLogin (writer, reader)) { - client.Close (); - return; - } - - if (!DoInitialDialog (writer, reader, "/home/someuser", "/home/someuser/somedir/")) { - client.Close (); - return; - } - - string str = reader.ReadLine (); - string resp = FormatPassiveResponse (str); - if (resp == null) { - client.Close (); - return; - } - writer.WriteLine (resp); - writer.Flush (); - - str = reader.ReadLine (); - if (str != "LIST") { - Where = "LIST - '" + str + "'"; - client.Close (); - return; - } - writer.WriteLine ("150 Here comes the directory listing"); - writer.Flush (); - - Socket data_cnc = data.Accept (); - byte [] dontcare = Encoding.ASCII.GetBytes ("drwxr-xr-x 2 ftp ftp 4096 Oct 27 20:17 tests"); - data_cnc.Send (dontcare, 1, SocketFlags.None); - data_cnc.Close (); - writer.WriteLine ("226 Directory send Ok"); - writer.Flush (); - if (!EndConversation (writer, reader)) { - client.Close (); - return; - } - client.Close (); - } - } - - class ServerDeleteFile : FtpServer { - public ServerDeleteFile (bool ipv6) - : base (ipv6) - { - } - - protected override void Run () - { - Socket client = control.Accept (); - NetworkStream ns = new NetworkStream (client, false); - StreamWriter writer = new StreamWriter (ns, Encoding.ASCII); - StreamReader reader = new StreamReader (ns, Encoding.UTF8); - if (!DoAnonymousLogin (writer, reader)) { - client.Close (); - return; - } - - if (!DoInitialDialog (writer, reader, "/home/someuser", "/home/someuser/")) { - client.Close (); - return; - } - - string str = reader.ReadLine (); - if (str.Trim () != "DELE file.txt") { - Where = "DELE - " + str; - client.Close (); - return; - } - writer.WriteLine ("250 Delete operation successful"); - writer.Flush (); - if (!EndConversation (writer, reader)) { - client.Close (); - return; - } - client.Close (); - } - } - - class ServerDownload : FtpServer { - - string Pwd, Cwd, Filename; - - public ServerDownload (bool ipv6) - : this (null, null, null, ipv6) - { - } - - public ServerDownload (string pwd, string cwd, string filename, bool ipv6) - : base (ipv6) - { - Pwd = pwd ?? "/home/someuser"; - Cwd = cwd ?? "/home/someuser/"; - Filename = filename ?? "file.txt"; - } - - protected override void Run () - { - Socket client = control.Accept (); - NetworkStream ns = new NetworkStream (client, false); - StreamWriter writer = new StreamWriter (ns, Encoding.ASCII); - StreamReader reader = new StreamReader (ns, Encoding.UTF8); - if (!DoAnonymousLogin (writer, reader)) { - client.Close (); - return; - } - - if (!DoInitialDialog (writer, reader, Pwd, Cwd)) { - client.Close (); - return; - } - - string str = reader.ReadLine (); - string resp = FormatPassiveResponse (str); - if (resp == null) { - client.Close (); - return; - } - writer.WriteLine (resp); - writer.Flush (); - - str = reader.ReadLine (); - if (str != $"RETR {Filename}") { - Where = $"RETR - got: {str}, expected: RETR {Filename}"; - client.Close (); - return; - } - writer.WriteLine ("150 Opening BINARY mode data connection for blah (n bytes)"); - writer.Flush (); - - Socket data_cnc = data.Accept (); - byte [] dontcare = new byte [1]; - data_cnc.Receive (dontcare, 1, SocketFlags.None); - data_cnc.Close (); - writer.WriteLine ("226 File send Ok"); - writer.Flush (); - if (!EndConversation (writer, reader)) { - client.Close (); - return; - } - client.Close (); - } - } - - class ServerPut : FtpServer { - public List result = new List (); - - public ServerPut (bool ipv6) - : base (ipv6) - { - } - - protected override void Run () - { - Socket client = control.Accept (); - NetworkStream ns = new NetworkStream (client, false); - StreamWriter writer = new StreamWriter (ns, Encoding.ASCII); - StreamReader reader = new StreamReader (ns, Encoding.UTF8); - if (!DoAnonymousLogin (writer, reader)) { - client.Close (); - return; - } - - if (!DoInitialDialog (writer, reader, "/home/someuser", "/home/someuser/uploads/")) { - client.Close (); - return; - } - - string str = reader.ReadLine (); - string resp = FormatPassiveResponse (str); - if (resp == null) { - client.Close (); - return; - } - writer.WriteLine (resp); - writer.Flush (); - - str = reader.ReadLine (); - if (str != "STOR file.txt") { - Where = "STOR - " + str; - client.Close (); - return; - } - writer.WriteLine ("150 Ok to send data"); - writer.Flush (); - - Socket data_cnc = data.Accept (); - var datastr = new NetworkStream (data_cnc, false); - int ch; - while ((ch = datastr.ReadByte ()) != -1){ - result.Add ((byte)ch); - - } - data_cnc.Close (); - writer.WriteLine ("226 File received Ok"); - writer.Flush (); - if (!EndConversation (writer, reader)) { - client.Close (); - return; - } - client.Close (); - } - } - - abstract class FtpServer { - protected Socket control; - protected Socket data; - protected ManualResetEvent evt; - protected bool ipv6; - public string Where = ""; - - public FtpServer (bool ipv6) - { - control = new Socket (ipv6 ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - control.Bind (new IPEndPoint (ipv6 ? IPAddress.IPv6Loopback : IPAddress.Loopback, 0)); - control.Listen (1); - data = new Socket (ipv6 ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - data.Bind (new IPEndPoint (ipv6 ? IPAddress.IPv6Loopback : IPAddress.Loopback, 0)); - data.Listen (1); - this.ipv6 = ipv6; - } - - public void Start () - { - evt = new ManualResetEvent (false); - Thread th = new Thread (new ThreadStart (Run)); - th.Start (); - } - - public void Stop () - { - evt.Set (); - data.Close (); - control.Close (); - } - - // PWD, CWD and TYPE I (type could be moved out of here) - protected bool DoInitialDialog (StreamWriter writer, StreamReader reader, string pwd, string cwd) - { - string str = reader.ReadLine (); - if (!str.StartsWith ("OPTS utf8 on")) { - Where = "OPTS utf8 - " + str; - return false; - } - writer.WriteLine ("200 Always in UTF8 mode"); // vsftpd - writer.Flush (); - str = reader.ReadLine (); - if (!str.StartsWith ("PWD")) { - Where = "PWD - " + str; - return false; - } - writer.WriteLine ("257 \"{0}\"", pwd); - writer.Flush (); - str = reader.ReadLine (); - if (str != ("CWD " + cwd)) { - Where = "CWD - " + str; - return false; - } - writer.WriteLine ("250 Directory changed"); - writer.Flush (); - str = reader.ReadLine (); - if (str != ("TYPE I")) { - Where = "TYPE - " + str; - return false; - } - writer.WriteLine ("200 Switching to binary mode"); - writer.Flush (); - return true; - } - - protected bool EndConversation (StreamWriter writer, StreamReader reader) - { - string str = reader.ReadLine (); - if (str != "QUIT") { - Where = "QUIT"; - return false; - } - writer.WriteLine ("220 Bye"); - writer.Flush (); - Thread.Sleep (250); - return true; - } - - protected bool DoAnonymousLogin (StreamWriter writer, StreamReader reader) - { - writer.WriteLine ("220 Welcome to the jungle"); - writer.Flush (); - string str = reader.ReadLine (); - if (!str.StartsWith ("USER ")) { - Where = "USER"; - return false; - } - writer.WriteLine ("331 Say 'Mellon'"); - writer.Flush (); - str = reader.ReadLine (); - if (!str.StartsWith ("PASS ")) { - Where = "PASS"; - return false; - } - writer.WriteLine ("230 Logged in"); - writer.Flush (); - return true; - } - - protected string FormatPassiveResponse (string request) - { - if (ipv6) { - if (request != "EPSV") { - Where = "EPSV"; - return null; - } - - IPEndPoint end_data = (IPEndPoint) data.LocalEndPoint; - return String.Format ("229 Extended Passive (|||{0}|)", end_data.Port); - } - else { - if (request != "PASV") { - Where = "PASV"; - return null; - } - - IPEndPoint end_data = (IPEndPoint) data.LocalEndPoint; - byte [] addr_bytes = end_data.Address.GetAddressBytes (); - byte [] port = new byte [2]; - port[0] = (byte) ((end_data.Port >> 8) & 255); - port[1] = (byte) (end_data.Port & 255); - StringBuilder sb = new StringBuilder ("227 Passive ("); - foreach (byte b in addr_bytes) { - sb.AppendFormat ("{0},", b); - } - sb.AppendFormat ("{0},", port [0]); - sb.AppendFormat ("{0})", port [1]); - return sb.ToString (); - } - } - - public IPAddress IPAddress { - get { return ((IPEndPoint) control.LocalEndPoint).Address; } - } - - public int Port { - get { return ((IPEndPoint) control.LocalEndPoint).Port; } - } - - protected abstract void Run (); - } - } -} - - diff --git a/mcs/class/System/Test/System.Text.RegularExpressions/RegexCas.cs b/mcs/class/System/Test/System.Text.RegularExpressions/RegexCas.cs index a3e7fa4851..8ac03b74d8 100644 --- a/mcs/class/System/Test/System.Text.RegularExpressions/RegexCas.cs +++ b/mcs/class/System/Test/System.Text.RegularExpressions/RegexCas.cs @@ -26,7 +26,7 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -#if !MOBILE +#if MONO_FEATURE_CAS using NUnit.Framework; diff --git a/mcs/class/System/basic_System.dll.sources b/mcs/class/System/basic_System.dll.sources index ee2d1a0d96..fa6e1453a9 100644 --- a/mcs/class/System/basic_System.dll.sources +++ b/mcs/class/System/basic_System.dll.sources @@ -1,2 +1,3 @@ #include net_4_x_System.dll.sources - +../../../external/corefx/src/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.UnknownUnix.cs +../../../external/corefx/src/Common/src/System/Net/ContextAwareResult.Unix.cs diff --git a/mcs/class/System/build_System.dll.sources b/mcs/class/System/build_System.dll.sources index ee2d1a0d96..fa6e1453a9 100644 --- a/mcs/class/System/build_System.dll.sources +++ b/mcs/class/System/build_System.dll.sources @@ -1,2 +1,3 @@ #include net_4_x_System.dll.sources - +../../../external/corefx/src/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.UnknownUnix.cs +../../../external/corefx/src/Common/src/System/Net/ContextAwareResult.Unix.cs diff --git a/mcs/class/System/common.sources b/mcs/class/System/common.sources index 785ea5e351..5024ccd5c5 100644 --- a/mcs/class/System/common.sources +++ b/mcs/class/System/common.sources @@ -1,7 +1,6 @@ Assembly/AssemblyInfo.cs ../../build/common/SR.cs - -corefx/ZLibNative.cs +corefx/*.cs Microsoft.Win32.SafeHandles/SafeX509ChainHandle.cs @@ -39,7 +38,6 @@ System.IO/IODescriptionAttribute.cs System.IO/NotifyFilters.cs System.IO/RenamedEventArgs.cs System.IO/RenamedEventHandler.cs -System.IO/WaitForChangedResult.cs System.IO/WatcherChangeTypes.cs System.Net/BasicClient.cs @@ -279,49 +277,48 @@ ReferenceSources/SR2.cs ReferenceSources/SRCategoryAttribute.cs ReferenceSources/Win32Exception.cs -../referencesource/System/regex/system/text/regularexpressions/Regex.cs -../referencesource/System/regex/system/text/regularexpressions/RegexBoyerMoore.cs -../referencesource/System/regex/system/text/regularexpressions/RegexCapture.cs -../referencesource/System/regex/system/text/regularexpressions/RegexCaptureCollection.cs -../referencesource/System/regex/system/text/regularexpressions/RegexCharClass.cs -../referencesource/System/regex/system/text/regularexpressions/RegexCode.cs -../referencesource/System/regex/system/text/regularexpressions/RegexCompilationInfo.cs -../referencesource/System/regex/system/text/regularexpressions/RegexCompiler.cs -../referencesource/System/regex/system/text/regularexpressions/RegexFCD.cs -../referencesource/System/regex/system/text/regularexpressions/RegexGroup.cs -../referencesource/System/regex/system/text/regularexpressions/RegexGroupCollection.cs -../referencesource/System/regex/system/text/regularexpressions/RegexInterpreter.cs -../referencesource/System/regex/system/text/regularexpressions/RegexMatch.cs -../referencesource/System/regex/system/text/regularexpressions/RegexMatchCollection.cs -../referencesource/System/regex/system/text/regularexpressions/RegexMatchTimeoutException.cs -../referencesource/System/regex/system/text/regularexpressions/RegexNode.cs -../referencesource/System/regex/system/text/regularexpressions/RegexOptions.cs -../referencesource/System/regex/system/text/regularexpressions/RegexParser.cs -../referencesource/System/regex/system/text/regularexpressions/RegexReplacement.cs -../referencesource/System/regex/system/text/regularexpressions/RegexRunner.cs -../referencesource/System/regex/system/text/regularexpressions/RegexRunnerFactory.cs -../referencesource/System/regex/system/text/regularexpressions/RegexTree.cs -../referencesource/System/regex/system/text/regularexpressions/RegexWriter.cs -../referencesource/System/regex/system/text/regularexpressions/compiledregexrunner.cs -../referencesource/System/regex/system/text/regularexpressions/compiledregexrunnerfactory.cs +../../../external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.cs +../../../external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexBoyerMoore.cs +../../../external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCapture.cs +../../../external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCaptureCollection.cs +../../../external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCharClass.cs +../../../external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCode.cs +../../../external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompilationInfo.cs +../../../external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexFCD.cs +../../../external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexGroup.cs +../../../external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexGroupCollection.cs +../../../external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexInterpreter.cs +../../../external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexMatch.cs +../../../external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexMatchCollection.cs +../../../external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexMatchTimeoutException.cs +../../../external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs +../../../external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexOptions.cs +../../../external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexParser.cs +../../../external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexReplacement.cs +../../../external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexRunner.cs +../../../external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexRunnerFactory.cs +../../../external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexTree.cs +../../../external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexWriter.cs +../../../external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/CompiledRegexRunner.cs +../../../external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/HashtableExtensions.cs +../../../external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCollectionDebuggerProxy.cs +../../../external/corefx/src/Common/src/System/NotImplemented.cs -../referencesource/System/compmod/system/collections/objectmodel/observablecollection.cs -../referencesource/System/compmod/system/collections/objectmodel/readonlyobservablecollection.cs - -../referencesource/System/compmod/system/collections/specialized/bitvector32.cs -../referencesource/System/compmod/system/collections/specialized/casesensitivestringdictionary.cs -../referencesource/System/compmod/system/collections/specialized/collectionsutil.cs -../referencesource/System/compmod/system/collections/specialized/hybriddictionary.cs -../referencesource/System/compmod/system/collections/specialized/inotifycollectionchanged.cs -../referencesource/System/compmod/system/collections/specialized/iordereddictionary.cs -../referencesource/System/compmod/system/collections/specialized/listdictionary.cs -../referencesource/System/compmod/system/collections/specialized/nameobjectcollectionbase.cs -../referencesource/System/compmod/system/collections/specialized/namevaluecollection.cs -../referencesource/System/compmod/system/collections/specialized/notifycollectionchangedeventargs.cs -../referencesource/System/compmod/system/collections/specialized/ordereddictionary.cs -../referencesource/System/compmod/system/collections/specialized/stringcollection.cs +../../../external/corefx/src/System.Collections.Specialized/src/System/Collections/Specialized/BitVector32.cs +../../../external/corefx/src/System.Collections.Specialized/src/System/Collections/Specialized/HybridDictionary.cs +../../../external/corefx/src/System.Collections.Specialized/src/System/Collections/Specialized/IOrderedDictionary.cs +../../../external/corefx/src/System.Collections.Specialized/src/System/Collections/Specialized/ListDictionary.cs +../../../external/corefx/src/System.Collections.Specialized/src/System/Collections/Specialized/OrderedDictionary.cs +../../../external/corefx/src/System.Collections.Specialized/src/System/Collections/Specialized/StringCollection.cs +../../../external/corefx/src/System.Collections.Specialized/src/System/Collections/Specialized/NameValueCollection.cs ../referencesource/System/compmod/system/collections/specialized/stringdictionary.cs -../referencesource/System/compmod/system/collections/specialized/stringdictionarywithcomparer.cs +../../../external/corefx/src/System.Collections.Specialized/src/System/Collections/Specialized/StringDictionary.cs +../referencesource/System/compmod/system/collections/specialized/nameobjectcollectionbase.cs +../referencesource/System/compmod/system/collections/specialized/casesensitivestringdictionary.cs +../../../external/corefx/src/System.Collections.NonGeneric/src/System/Collections/Specialized/CollectionsUtil.cs +../../../external/corefx/src/System.ObjectModel/src/System/Collections/ObjectModel/ReadOnlyObservableCollection.cs +../../../external/corefx/src/System.ObjectModel/src/System/Collections/ObjectModel/ObservableCollection.cs +../../../external/corefx/src/System.ObjectModel/src/System/Collections/Specialized/*.cs ../referencesource/System/compmod/system/componentmodel/AddingNewEventArgs.cs ../referencesource/System/compmod/system/componentmodel/AddingNewEventHandler.cs @@ -854,8 +851,6 @@ ReferenceSources/Win32Exception.cs ../referencesource/System/compmod/microsoft/win32/safehandles/SafeProcessHandle.cs -corefx/SR.cs - ../../../external/corefx/src/Common/src/System/StringExtensions.cs ../../../external/corefx/src/Common/src/System/Collections/Generic/ArrayBuilder.cs @@ -877,14 +872,9 @@ corefx/SR.cs ../../../external/corefx/src/System.Runtime/src/System/Collections/Generic/ISet.cs -../../../external/corefx/src/System.Buffers/src/System/Buffers/ArrayPool.cs -../../../external/corefx/src/System.Buffers/src/System/Buffers/ArrayPoolEventSource.cs -../../../external/corefx/src/System.Buffers/src/System/Buffers/DefaultArrayPool.cs -../../../external/corefx/src/System.Buffers/src/System/Buffers/DefaultArrayPoolBucket.cs -../../../external/corefx/src/System.Buffers/src/System/Buffers/Utilities.cs - ../../../external/corefx/src/System.Collections/src/System/Collections/Generic/BitHelper.cs ../../../external/corefx/src/System.Collections/src/System/Collections/Generic/ICollectionDebugView.cs +../../../external/corefx/src/System.ObjectModel/src/System/Collections/Generic/DebugView.cs ../../../external/corefx/src/System.Collections/src/System/Collections/Generic/IDictionaryDebugView.cs ../../../external/corefx/src/System.Collections/src/System/Collections/Generic/LinkedList.cs ../../../external/corefx/src/System.Collections/src/System/Collections/Generic/Queue.cs @@ -928,3 +918,12 @@ corefx/SR.cs ../../../external/corefx/src/System.Private.Uri/src/System/UriBuilder.cs ../../../external/corefx/src/System.Runtime.Extensions/src/System/CodeDom/Compiler/IndentedTextWriter.cs +../../../external/corefx/src/System.IO.FileSystem.Watcher/src/System/IO/WaitForChangedResult.cs + +../../../external/corefx/src/System.Runtime.InteropServices/src/System/Security/SecureStringMarshal.cs +../../../external/corefx/src/System.Runtime.Extensions/src/System/StringNormalizationExtensions.cs +../../../external/corefx/src/System.Diagnostics.StackTrace/src/System/Diagnostics/StackFrameExtensions.cs + +../../../external/corefx/src/Common/src/System/IO/PathInternal.CaseSensitivity.cs +../../../external/corefx/src/System.IO.FileSystem.Watcher/src/System/IO/PatternMatcher.cs +../../../external/corefx/src/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.cs diff --git a/mcs/class/System/common_networking.sources b/mcs/class/System/common_networking.sources index fe979005fe..a0e2095d5a 100644 --- a/mcs/class/System/common_networking.sources +++ b/mcs/class/System/common_networking.sources @@ -20,12 +20,16 @@ System.Net/AuthenticationManager.cs System.Net/ChunkedInputStream.cs System.Net/EndPointListener.cs System.Net/EndPointManager.cs -System.Net/FtpAsyncResult.cs -System.Net/FtpDataStream.cs -System.Net/FtpRequestCreator.cs -System.Net/FtpStatus.cs -System.Net/FtpWebRequest.cs -System.Net/FtpWebResponse.cs + +../../../external/corefx/src/Common/src/System/Net/TlsStream.cs +../../../external/corefx/src/Common/src/System/Net/ContextAwareResult.cs +../../../external/corefx/src/System.Net.Requests/src/System/Net/NetworkStreamWrapper.cs +../../../external/corefx/src/System.Net.Requests/src/System/Net/CommandStream.cs +../../../external/corefx/src/System.Net.Requests/src/System/Net/FtpControlStream.cs +../../../external/corefx/src/System.Net.Requests/src/System/Net/FtpDataStream.cs +../../../external/corefx/src/System.Net.Requests/src/System/Net/FtpWebRequest.cs +../../../external/corefx/src/System.Net.Requests/src/System/Net/FtpWebResponse.cs + System.Net/HttpConnection.cs System.Net/HttpListener.cs System.Net/HttpListener.Mono.cs diff --git a/mcs/class/System/corefx.unix.sources b/mcs/class/System/corefx.unix.sources new file mode 100644 index 0000000000..bec78d856d --- /dev/null +++ b/mcs/class/System/corefx.unix.sources @@ -0,0 +1 @@ +../../../external/corefx/src/Common/src/Interop/Unix/*.cs diff --git a/mcs/class/System/corefx/NameValueCollection.cs b/mcs/class/System/corefx/NameValueCollection.cs new file mode 100644 index 0000000000..b7dca40da4 --- /dev/null +++ b/mcs/class/System/corefx/NameValueCollection.cs @@ -0,0 +1,17 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.Serialization; +using System.Text; + +namespace System.Collections.Specialized +{ + partial class NameValueCollection + { + // Allow internal extenders to avoid creating the hashtable/arraylist. + internal NameValueCollection (DBNull dummy) : base (dummy) + { + } + } +} \ No newline at end of file diff --git a/mcs/class/System/corefx/SR.cs b/mcs/class/System/corefx/SR.cs index d83dc9b869..257551aec9 100644 --- a/mcs/class/System/corefx/SR.cs +++ b/mcs/class/System/corefx/SR.cs @@ -46,6 +46,257 @@ partial class SR public const string PartitionerStatic_CurrentCalledBeforeMoveNext = "MoveNext must be called at least once before calling Current."; public const string ConcurrentBag_Enumerator_EnumerationNotStartedOrAlreadyFinished = "Enumeration has either not started or has already finished."; public const string Arg_KeyNotFoundWithKey = "The given key '{0}' was not present in the dictionary."; + public const string IO_FileExists_Name = "The file '{0}' already exists."; + public const string IO_FileName_Name = "File name: '{0}'"; + public const string IO_FileNotFound = "Unable to find the specified file."; + public const string IO_FileNotFound_FileName = "Could not load file or assembly '{0}'. The system cannot find the file specified."; + public const string IO_FileLoad = "Could not load the specified file."; + public const string IO_NoPermissionToDirectoryName = " AsGenericDictionary () + { + return new GenericAdapter(this); + } + } +} \ No newline at end of file diff --git a/mcs/class/System/darwin_net_4_x_System.dll.sources b/mcs/class/System/darwin_net_4_x_System.dll.sources new file mode 100644 index 0000000000..7a4b90afb9 --- /dev/null +++ b/mcs/class/System/darwin_net_4_x_System.dll.sources @@ -0,0 +1,14 @@ +#include corefx.unix.sources +#include net_4_x_System.dll.sources + +../../../external/corefx/src/Common/src/Interop/OSX/Interop.Libraries.cs +../../../external/corefx/src/Common/src/Interop/OSX/Interop.EventStream.cs +../../../external/corefx/src/Common/src/Interop/OSX/Interop.RunLoop.cs +../../../external/corefx/src/Common/src/Interop/OSX/Interop.CoreFoundation.cs +../../../external/corefx/src/Common/src/Interop/Unix/System.Native/Interop.Sync.cs +../../../external/corefx/src/Common/src/Interop/Unix/System.Native/Interop.RealPath.cs +../../../external/corefx/src/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.OSX.cs +../../../external/corefx/src/Common/src/Microsoft/Win32/SafeHandles/SafeCreateHandle.OSX.cs +../../../external/corefx/src/Common/src/Microsoft/Win32/SafeHandles/SafeEventStreamHandle.OSX.cs +../../../external/corefx/src/Common/src/System/Net/ContextAwareResult.OSX.cs + diff --git a/mcs/class/System/linux_net_4_x_System.dll.sources b/mcs/class/System/linux_net_4_x_System.dll.sources new file mode 100644 index 0000000000..ad3a599b15 --- /dev/null +++ b/mcs/class/System/linux_net_4_x_System.dll.sources @@ -0,0 +1,17 @@ +#include corefx.unix.sources +#include net_4_x_System.dll.sources + +../../../external/corefx/src/Common/src/Interop/Linux/Interop.Libraries.cs +../../../external/corefx/src/Common/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs +../../../external/corefx/src/Common/src/Microsoft/Win32/SafeHandles/SafeDirectoryHandle.Unix.cs +../../../external/corefx/src/Common/src/Interop/Linux/System.Native/Interop.INotify.cs +../../../external/corefx/src/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.Linux.cs +../../../external/corefx/src/Common/src/Interop/Unix/System.Native/Interop.OpenFlags.cs +../../../external/corefx/src/Common/src/Interop/Unix/System.Native/Interop.ReadDir.cs +../../../external/corefx/src/Common/src/Interop/Unix/System.Native/Interop.FLock.cs +../../../external/corefx/src/Common/src/Interop/Unix/System.Native/Interop.Stat.cs +../../../external/corefx/src/Common/src/Interop/Unix/System.Native/Interop.Poll.cs +../../../external/corefx/src/Common/src/Interop/Unix/System.Native/Interop.Open.cs +../../../external/corefx/src/Common/src/Interop/Unix/System.Native/Interop.Read.cs +../../../external/corefx/src/Common/src/Interop/Unix/System.Native/Interop.Close.cs +../../../external/corefx/src/Common/src/System/Net/ContextAwareResult.Unix.cs diff --git a/mcs/class/System/mobile_System.dll.sources b/mcs/class/System/mobile_System.dll.sources index 738753a16c..2b750726b8 100644 --- a/mcs/class/System/mobile_System.dll.sources +++ b/mcs/class/System/mobile_System.dll.sources @@ -1,3 +1,4 @@ #include common.sources #include common_networking.sources -System.IO/FileSystemWatcher_mobile.cs +../../../external/corefx/src/Common/src/System/Net/ContextAwareResult.Unix.cs +../../../external/corefx/src/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.UnknownUnix.cs diff --git a/mcs/class/System/monodroid_System.dll.sources b/mcs/class/System/monodroid_System.dll.sources index c6769c373a..9997a9b690 100644 --- a/mcs/class/System/monodroid_System.dll.sources +++ b/mcs/class/System/monodroid_System.dll.sources @@ -1,3 +1,7 @@ #include mobile_System.dll.sources System/AndroidPlatform.cs Mono.Btls/MonoBtlsX509LookupAndroid.cs +../../../external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs +../../../external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/CompiledRegexRunnerFactory.cs +../../../external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexLWCGCompiler.cs + diff --git a/mcs/class/System/net_4_x_System.dll.sources b/mcs/class/System/net_4_x_System.dll.sources index 1b60069cf8..0176854196 100644 --- a/mcs/class/System/net_4_x_System.dll.sources +++ b/mcs/class/System/net_4_x_System.dll.sources @@ -142,7 +142,8 @@ System.IO/IFileWatcher.cs System.IO/InotifyWatcher.cs System.IO/KeventWatcher.cs System.IO/SearchPattern.cs -System.IO/WindowsWatcher.cs + +System.IO/CoreFXFileSystemWatcherProxy.cs System.IO.Ports/Handshake.cs System.IO.Ports/ISerialStream.cs @@ -378,3 +379,6 @@ ReferenceSources/ConfigurationManagerInternalFactory.cs ../../../external/corefx/src/System.CodeDom/src/System/CodeDom/FieldDirection.cs ../../../external/corefx/src/System.CodeDom/src/System/CodeDom/MemberAttributes.cs ../../../external/corefx/src/System.CodeDom/src/System/Collections/Specialized/FixedStringLookup.cs +../../../external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs +../../../external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/CompiledRegexRunnerFactory.cs +../../../external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexLWCGCompiler.cs diff --git a/mcs/class/System/unreal_System.dll.sources b/mcs/class/System/unreal_System.dll.sources index 70a77a6dbf..756aa3683d 100644 --- a/mcs/class/System/unreal_System.dll.sources +++ b/mcs/class/System/unreal_System.dll.sources @@ -1 +1,4 @@ #include mobile_System.dll.sources +../../../external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs +../../../external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/CompiledRegexRunnerFactory.cs +../../../external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexLWCGCompiler.cs diff --git a/mcs/class/System/win32_net_4_x_System.dll.sources b/mcs/class/System/win32_net_4_x_System.dll.sources new file mode 100644 index 0000000000..c0b68e4bff --- /dev/null +++ b/mcs/class/System/win32_net_4_x_System.dll.sources @@ -0,0 +1,12 @@ +#include net_4_x_System.dll.sources + +../../../external/corefx/src/Common/src/Interop/Windows/Interop.Libraries.cs +../../../external/corefx/src/Common/src/Interop/Windows/kernel32/Interop.CreateFile.cs +../../../external/corefx/src/Common/src/Interop/Windows/kernel32/Interop.FileOperations.cs +../../../external/corefx/src/Common/src/Interop/Windows/kernel32/Interop.SECURITY_ATTRIBUTES.cs +../../../external/corefx/src/Common/src/Interop/Windows/Interop.BOOL.cs +../../../external/corefx/src/Common/src/Interop/Windows/kernel32/Interop.CloseHandle.cs +../../../external/corefx/src/Common/src/Interop/Windows/kernel32/Interop.ReadDirectoryChangesW.cs +../../../external/corefx/src/Common/src/System/IO/PathInternal.Windows.cs +../../../external/corefx/src/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.Win32.cs +../../../external/corefx/src/Common/src/System/Net/ContextAwareResult.Windows.cs diff --git a/mcs/class/System/xammac_System.dll.sources b/mcs/class/System/xammac_System.dll.sources index 70a77a6dbf..756aa3683d 100644 --- a/mcs/class/System/xammac_System.dll.sources +++ b/mcs/class/System/xammac_System.dll.sources @@ -1 +1,4 @@ #include mobile_System.dll.sources +../../../external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs +../../../external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/CompiledRegexRunnerFactory.cs +../../../external/corefx/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexLWCGCompiler.cs diff --git a/mcs/class/System/xammac_net_4_5_System.dll.sources b/mcs/class/System/xammac_net_4_5_System.dll.sources index beb6f2415c..502ec37dff 100644 --- a/mcs/class/System/xammac_net_4_5_System.dll.sources +++ b/mcs/class/System/xammac_net_4_5_System.dll.sources @@ -1 +1 @@ -#include net_4_x_System.dll.sources +#include darwin_net_4_x_System.dll.sources diff --git a/mcs/class/corlib/Assembly/AssemblyInfo.cs b/mcs/class/corlib/Assembly/AssemblyInfo.cs index 54b21cdf3b..6e1e9ef126 100644 --- a/mcs/class/corlib/Assembly/AssemblyInfo.cs +++ b/mcs/class/corlib/Assembly/AssemblyInfo.cs @@ -79,8 +79,6 @@ using System.Runtime.InteropServices; [assembly: InternalsVisibleTo ("System.Runtime.WindowsRuntime, PublicKey=00000000000000000400000000000000")] [assembly: InternalsVisibleTo ("System.Runtime.WindowsRuntime.UI.Xaml, PublicKey=00000000000000000400000000000000")] -[assembly: InternalsVisibleTo ("System.Runtime.InteropServices.RuntimeInformation, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] - #if MONOTOUCH #if MONOTOUCH_TV [assembly: InternalsVisibleTo ("Xamarin.TVOS, PublicKey=0024000004800000940000000602000000240000525341310004000011000000438ac2a5acfbf16cbd2b2b47a62762f273df9cb2795ceccdf77d10bf508e69e7a362ea7a45455bbf3ac955e1f2e2814f144e5d817efc4c6502cc012df310783348304e3ae38573c6d658c234025821fda87a0be8a0d504df564e2c93b2b878925f42503e9d54dfef9f9586d9e6f38a305769587b1de01f6c0410328b2c9733db")] diff --git a/mcs/class/corlib/LinkerDescriptor/mscorlib.xml b/mcs/class/corlib/LinkerDescriptor/mscorlib.xml index 3ca101e24c..1b490e429b 100644 --- a/mcs/class/corlib/LinkerDescriptor/mscorlib.xml +++ b/mcs/class/corlib/LinkerDescriptor/mscorlib.xml @@ -252,10 +252,6 @@ - - - - @@ -296,6 +292,9 @@ + + + diff --git a/mcs/class/corlib/Makefile b/mcs/class/corlib/Makefile index 5c1c87c8d6..6e28723c44 100644 --- a/mcs/class/corlib/Makefile +++ b/mcs/class/corlib/Makefile @@ -8,6 +8,7 @@ LIBRARY_NAME = mscorlib.dll LIB_MCS_FLAGS = $(REFERENCE_SOURCES_FLAGS) $(RESOURCE_FILES:%=-resource:%) +USE_XTEST_REMOTE_EXECUTOR = YES LIBRARY_WARN_AS_ERROR = yes #LIBRARY_USE_INTERMEDIATE_FILE = yes @@ -30,6 +31,7 @@ RESX_RESOURCE_STRING = \ ../../../external/corefx/src/System.Collections.Concurrent/src/Resources/Strings.resx \ ../../../external/corefx/src/System.Memory/src/Resources/Strings.resx \ ../../../external/corefx/src/System.Runtime.InteropServices.RuntimeInformation/src/Resources/Strings.resx \ + ../../../external/corefx/src/System.Threading.Tasks.Parallel/src/Resources/Strings.resx \ LIBRARY_COMPILE = $(BOOT_COMPILE) LIBRARY_INSTALL_DIR = $(mono_libdir)/mono/$(FRAMEWORK_VERSION) @@ -208,9 +210,6 @@ $(vtsdir)/$(PROFILE)_TestLib/BinarySerializationOverVersions.exe: $(vtsdir)/Bina $(vtsdir)/BinarySerializationOverVersions.cs -out:$@ @cp $(vtsdir)/$(PROFILE)_TestLib/1.0/Address.dll $(vtsdir)/$(PROFILE)_TestLib -# Need to define TEST_MONO_PATH to an absolute dir since the test is ran from a subdir -TEST_MONO_PATH=$(PWD)/../lib/$(PROFILE) - run-test-vts: test-vts @echo Running vts tests... PATH="$(TEST_RUNTIME_WRAPPERS_PATH):$(PATH)" $(TEST_RUNTIME) $(TEST_RUNTIME_FLAGS) $(TEST_HARNESS) $(NOSHADOW_FLAG) \ diff --git a/mcs/class/corlib/Mono.Globalization.Unicode/SimpleCollator.cs b/mcs/class/corlib/Mono.Globalization.Unicode/SimpleCollator.cs index 2482eb8f15..c40dd21cc2 100644 --- a/mcs/class/corlib/Mono.Globalization.Unicode/SimpleCollator.cs +++ b/mcs/class/corlib/Mono.Globalization.Unicode/SimpleCollator.cs @@ -77,13 +77,14 @@ namespace Mono.Globalization.Unicode { internal class SimpleCollator { +/* // this environment variable is for debugging quick check. #pragma warning disable 169, 414 static bool QuickCheckDisabled = Environment.internalGetEnvironmentVariable ( "MONO_COLLATION_QUICK_CHECK_DISABLED") == "yes"; #pragma warning restore 169, 414 - +*/ unsafe internal struct Context { public Context (CompareOptions opt, byte* alwaysMatchFlags, byte* neverMatchFlags, byte* buffer1, byte* buffer2, byte* prev1/*, bool quickCheckPossible*/) @@ -1660,7 +1661,7 @@ Console.WriteLine ("==== {0} {1} {2} {3} {4} {5} {6} {7} {8}", s, si, send, leng public unsafe int LastIndexOf (string s, string target, int start, int length, CompareOptions opt) { if (opt == CompareOptions.Ordinal) - return LastIndexOfOrdinal (s, target, start, length); + throw new NotSupportedException ("Should not be reached"); if (opt == CompareOptions.OrdinalIgnoreCase) throw new NotSupportedException ("Should not be reached"); byte* alwaysMatchFlags = stackalloc byte [16]; diff --git a/mcs/class/corlib/Mono.Globalization.Unicode/SortKey.cs b/mcs/class/corlib/Mono.Globalization.Unicode/SortKey.cs index 19c70b207e..b9b0eefcaa 100644 --- a/mcs/class/corlib/Mono.Globalization.Unicode/SortKey.cs +++ b/mcs/class/corlib/Mono.Globalization.Unicode/SortKey.cs @@ -91,6 +91,11 @@ namespace System.Globalization this.options = opt; } + internal SortKey (String localeName, String str, CompareOptions options, byte[] keyData) + { + throw new NotImplementedException (); + } + public virtual string OriginalString { get { return source; } } diff --git a/mcs/class/corlib/ReferenceSources/Buffer.cs b/mcs/class/corlib/ReferenceSources/Buffer.cs index f13d7d3699..d22747789c 100644 --- a/mcs/class/corlib/ReferenceSources/Buffer.cs +++ b/mcs/class/corlib/ReferenceSources/Buffer.cs @@ -181,34 +181,39 @@ namespace System ((byte*)dest) [0] = ((byte*)src) [0]; } - internal static unsafe void Memcpy (byte *dest, byte *src, int size) { + internal static unsafe void Memcpy (byte *dest, byte *src, int len) { // FIXME: if pointers are not aligned, try to align them // so a faster routine can be used. Handle the case where // the pointers can't be reduced to have the same alignment // (just ignore the issue on x86?) if ((((int)dest | (int)src) & 3) != 0) { - if (((int)dest & 1) != 0 && ((int)src & 1) != 0 && size >= 1) { + if (((int)dest & 1) != 0 && ((int)src & 1) != 0 && len >= 1) { dest [0] = src [0]; ++dest; ++src; - --size; + --len; } - if (((int)dest & 2) != 0 && ((int)src & 2) != 0 && size >= 2) { + if (((int)dest & 2) != 0 && ((int)src & 2) != 0 && len >= 2) { ((short*)dest) [0] = ((short*)src) [0]; dest += 2; src += 2; - size -= 2; + len -= 2; } if ((((int)dest | (int)src) & 1) != 0) { - memcpy1 (dest, src, size); + memcpy1 (dest, src, len); return; } if ((((int)dest | (int)src) & 2) != 0) { - memcpy2 (dest, src, size); + memcpy2 (dest, src, len); return; } } - memcpy4 (dest, src, size); + memcpy4 (dest, src, len); + } + + internal static unsafe void Memmove (byte *dest, byte *src, uint len) + { + Memcpy (dest, src, (int) len); } } } \ No newline at end of file diff --git a/mcs/class/corlib/ReferenceSources/CompareInfo.cs b/mcs/class/corlib/ReferenceSources/CompareInfo.cs index 77adfa6f77..25c77f425a 100644 --- a/mcs/class/corlib/ReferenceSources/CompareInfo.cs +++ b/mcs/class/corlib/ReferenceSources/CompareInfo.cs @@ -64,9 +64,9 @@ namespace System.Globalization } lock (collators) { - if (!collators.TryGetValue (m_sortName, out collator)) { + if (!collators.TryGetValue (_sortName, out collator)) { collator = new SimpleCollator (CultureInfo.GetCultureInfo (m_name)); - collators [m_sortName] = collator; + collators [_sortName] = collator; } } @@ -88,20 +88,11 @@ namespace System.Globalization return(key); } - int internal_index_switch (string s, int sindex, int count, char c, CompareOptions opt, bool first) - { - if (opt == CompareOptions.Ordinal && first) - return s.IndexOfUnchecked (c, sindex, count); - - return UseManagedCollation ? - internal_index_managed (s, sindex, count, c, opt, first) : - internal_index (s, sindex, count, c, opt, first); - } - int internal_index_switch (string s1, int sindex, int count, string s2, CompareOptions opt, bool first) { - if (opt == CompareOptions.Ordinal && first) - return s1.IndexOfUnchecked (s2, sindex, count); + // TODO: should not be needed, why is there specialization for OrdinalIgnore and not for Ordinal + if (opt == CompareOptions.Ordinal) + return first ? s1.IndexOfUnchecked (s2, sindex, count) : s1.LastIndexOfUnchecked (s2, sindex, count); return UseManagedCollation ? internal_index_managed (s1, sindex, count, s2, opt, first) : diff --git a/mcs/class/corlib/ReferenceSources/MethodBase.cs b/mcs/class/corlib/ReferenceSources/MethodBase.cs index 8cd0005632..37eccac596 100644 --- a/mcs/class/corlib/ReferenceSources/MethodBase.cs +++ b/mcs/class/corlib/ReferenceSources/MethodBase.cs @@ -30,15 +30,15 @@ namespace System.Reflection throw new NotImplementedException (); } - internal virtual int get_next_table_index (object obj, int table, bool inc) { + internal virtual int get_next_table_index (object obj, int table, int count) { #if !FULL_AOT_RUNTIME if (this is MethodBuilder) { MethodBuilder mb = (MethodBuilder)this; - return mb.get_next_table_index (obj, table, inc); + return mb.get_next_table_index (obj, table, count); } if (this is ConstructorBuilder) { ConstructorBuilder mb = (ConstructorBuilder)this; - return mb.get_next_table_index (obj, table, inc); + return mb.get_next_table_index (obj, table, count); } #endif throw new Exception ("Method is not a builder method"); diff --git a/mcs/class/corlib/ReferenceSources/RuntimeType.cs b/mcs/class/corlib/ReferenceSources/RuntimeType.cs index c080d4ed80..472d48e75a 100644 --- a/mcs/class/corlib/ReferenceSources/RuntimeType.cs +++ b/mcs/class/corlib/ReferenceSources/RuntimeType.cs @@ -138,7 +138,7 @@ namespace System return m_serializationCtor; } - internal Object CreateInstanceSlow(bool publicOnly, bool skipCheckThis, bool fillCache, ref StackCrawlMark stackMark) + internal Object CreateInstanceSlow(bool publicOnly, bool wrapExceptions, bool skipCheckThis, bool fillCache, ref StackCrawlMark stackMark) { //bool bNeedSecurityCheck = true; //bool bCanBeCached = false; @@ -150,10 +150,10 @@ namespace System //if (!fillCache) // bSecurityCheckOff = true; - return CreateInstanceMono (!publicOnly); + return CreateInstanceMono (!publicOnly, wrapExceptions); } - object CreateInstanceMono (bool nonPublic) + object CreateInstanceMono (bool nonPublic, bool wrapExceptions) { var ctor = GetDefaultConstructor (); if (!nonPublic && ctor != null && !ctor.IsPublic) { @@ -176,7 +176,7 @@ namespace System throw new MissingMethodException (Locale.GetText ("Cannot create an abstract class '{0}'.", FullName)); } - return ctor.InternalInvoke (null, null); + return ctor.InternalInvoke (null, null, wrapExceptions); } internal Object CheckValue (Object value, Binder binder, CultureInfo culture, BindingFlags invokeAttr) @@ -465,7 +465,7 @@ namespace System { var gt = (RuntimeType) MakeGenericType (genericType, new Type [] { genericArgument }); var ctor = gt.GetDefaultConstructor (); - return ctor.InternalInvoke (null, null); + return ctor.InternalInvoke (null, null, wrapExceptions: true); } [MethodImplAttribute(MethodImplOptions.InternalCall)] diff --git a/mcs/class/corlib/ReferenceSources/String.cs b/mcs/class/corlib/ReferenceSources/String.cs index bb6cad7429..149e5fcdb1 100644 --- a/mcs/class/corlib/ReferenceSources/String.cs +++ b/mcs/class/corlib/ReferenceSources/String.cs @@ -36,127 +36,40 @@ using System.Runtime.CompilerServices; using System.Text; +using System.Globalization; +using System.Collections; +using System.Collections.Generic; namespace System { partial class String { - [MethodImplAttribute (MethodImplOptions.InternalCall)] - public extern String (ReadOnlySpan value); + [NonSerialized] + int _stringLength; + [NonSerialized] + char _firstChar; - public int Length { - get { - return m_stringLength; - } - } + public static readonly String Empty; public unsafe static implicit operator ReadOnlySpan (String value) { if (value == null) return default; - fixed (void* start = &value.m_firstChar) + fixed (void* start = &value._firstChar) return new ReadOnlySpan (start, value.Length); } - - internal static unsafe int CompareOrdinalUnchecked (String strA, int indexA, int lenA, String strB, int indexB, int lenB) - { - if (strA == null) { - return strB == null ? 0 : -1; - } - if (strB == null) { - return 1; - } - int lengthA = Math.Min (lenA, strA.m_stringLength - indexA); - int lengthB = Math.Min (lenB, strB.m_stringLength - indexB); - - if (lengthA == lengthB && indexA == indexB && Object.ReferenceEquals (strA, strB)) - return 0; - - fixed (char* aptr = strA, bptr = strB) { - char* ap = aptr + indexA; - char* end = ap + Math.Min (lengthA, lengthB); - char* bp = bptr + indexB; - while (ap < end) { - if (*ap != *bp) - return *ap - *bp; - ap++; - bp++; - } - return lengthA - lengthB; - } - } - - public int IndexOf (char value, int startIndex, int count) - { - if (startIndex < 0 || startIndex > this.m_stringLength) - throw new ArgumentOutOfRangeException ("startIndex", "Cannot be negative and must be< 0"); - if (count < 0) - throw new ArgumentOutOfRangeException ("count", "< 0"); - if (startIndex > this.m_stringLength - count) - throw new ArgumentOutOfRangeException ("count", "startIndex + count > this.m_stringLength"); - - if ((startIndex == 0 && this.m_stringLength == 0) || (startIndex == this.m_stringLength) || (count == 0)) - return -1; - - return IndexOfUnchecked (value, startIndex, count); - } - - internal unsafe int IndexOfUnchecked (char value, int startIndex, int count) - { - // It helps JIT compiler to optimize comparison - int value_32 = (int)value; - - fixed (char* start = &m_firstChar) { - char* ptr = start + startIndex; - char* end_ptr = ptr + (count >> 3 << 3); - - while (ptr != end_ptr) { - if (*ptr == value_32) - return (int)(ptr - start); - if (ptr[1] == value_32) - return (int)(ptr - start + 1); - if (ptr[2] == value_32) - return (int)(ptr - start + 2); - if (ptr[3] == value_32) - return (int)(ptr - start + 3); - if (ptr[4] == value_32) - return (int)(ptr - start + 4); - if (ptr[5] == value_32) - return (int)(ptr - start + 5); - if (ptr[6] == value_32) - return (int)(ptr - start + 6); - if (ptr[7] == value_32) - return (int)(ptr - start + 7); - - ptr += 8; - } - - end_ptr += count & 0x07; - while (ptr != end_ptr) { - if (*ptr == value_32) - return (int)(ptr - start); - - ptr++; - } - return -1; - } - } - internal unsafe int IndexOfUnchecked (string value, int startIndex, int count) { int valueLen = value.Length; if (count < valueLen) return -1; - if (valueLen <= 1) { - if (valueLen == 1) - return IndexOfUnchecked (value[0], startIndex, count); + if (valueLen == 0) return startIndex; - } - fixed (char* thisptr = &m_firstChar, valueptr = value) { + fixed (char* thisptr = &_firstChar, valueptr = value) { char* ap = thisptr + startIndex; char* thisEnd = ap + count - valueLen + 1; while (ap != thisEnd) { @@ -174,372 +87,126 @@ namespace System return -1; } - public int IndexOfAny (char [] anyOf, int startIndex, int count) + internal unsafe int IndexOfUncheckedIgnoreCase (string value, int startIndex, int count) { - if (anyOf == null) - throw new ArgumentNullException (); - if (startIndex < 0 || startIndex > this.m_stringLength) - throw new ArgumentOutOfRangeException (); - if (count < 0 || startIndex > this.m_stringLength - count) - throw new ArgumentOutOfRangeException ("count", "Count cannot be negative, and startIndex + count must be less than m_stringLength of the string."); - - return IndexOfAnyUnchecked (anyOf, startIndex, count); - } - - unsafe int IndexOfAnyUnchecked (char[] anyOf, int startIndex, int count) - { - if (anyOf.Length == 0) + int valueLen = value.Length; + if (count < valueLen) return -1; - if (anyOf.Length == 1) - return IndexOfUnchecked (anyOf[0], startIndex, count); + if (valueLen == 0) + return startIndex; - fixed (char* any = anyOf) { - int highest = *any; - int lowest = *any; + var ti = CultureInfo.InvariantCulture.TextInfo; - char* end_any_ptr = any + anyOf.Length; - char* any_ptr = any; - while (++any_ptr != end_any_ptr) { - if (*any_ptr > highest) { - highest = *any_ptr; - continue; - } - - if (*any_ptr < lowest) - lowest = *any_ptr; - } - - fixed (char* start = &m_firstChar) { - char* ptr = start + startIndex; - char* end_ptr = ptr + count; - - while (ptr != end_ptr) { - if (*ptr > highest || *ptr < lowest) { - ptr++; - continue; + fixed (char* thisptr = &_firstChar, valueptr = value) { + char* ap = thisptr + startIndex; + char* thisEnd = ap + count - valueLen + 1; + char valueUpper = ti.ToUpper (*valueptr); + while (ap != thisEnd) { + if (ti.ToUpper (*ap) == valueUpper) { + for (int i = 1; i < valueLen; i++) { + if (ti.ToUpper (ap[i]) != ti.ToUpper (valueptr [i])) + goto NextVal; } - - if (*ptr == *any) - return (int)(ptr - start); - - any_ptr = any; - while (++any_ptr != end_any_ptr) { - if (*ptr == *any_ptr) - return (int)(ptr - start); - } - - ptr++; + return (int)(ap - thisptr); } + NextVal: + ap++; } } return -1; } - public int LastIndexOf (char value, int startIndex, int count) + internal unsafe int LastIndexOfUnchecked (string value, int startIndex, int count) { - if (this.m_stringLength == 0) - return -1; - - // >= for char (> for string) - if ((startIndex < 0) || (startIndex >= this.Length)) - throw new ArgumentOutOfRangeException ("startIndex", "< 0 || >= this.Length"); - if ((count < 0) || (count > this.Length)) - throw new ArgumentOutOfRangeException ("count", "< 0 || > this.Length"); - if (startIndex - count + 1 < 0) - throw new ArgumentOutOfRangeException ("startIndex - count + 1 < 0"); - - return LastIndexOfUnchecked (value, startIndex, count); - } - - internal unsafe int LastIndexOfUnchecked (char value, int startIndex, int count) - { - // It helps JIT compiler to optimize comparison - int value_32 = (int)value; - - fixed (char* start = &m_firstChar) { - char* ptr = start + startIndex; - char* end_ptr = ptr - (count >> 3 << 3); - - while (ptr != end_ptr) { - if (*ptr == value_32) - return (int)(ptr - start); - if (ptr[-1] == value_32) - return (int)(ptr - start) - 1; - if (ptr[-2] == value_32) - return (int)(ptr - start) - 2; - if (ptr[-3] == value_32) - return (int)(ptr - start) - 3; - if (ptr[-4] == value_32) - return (int)(ptr - start) - 4; - if (ptr[-5] == value_32) - return (int)(ptr - start) - 5; - if (ptr[-6] == value_32) - return (int)(ptr - start) - 6; - if (ptr[-7] == value_32) - return (int)(ptr - start) - 7; - - ptr -= 8; - } - - end_ptr -= count & 0x07; - while (ptr != end_ptr) { - if (*ptr == value_32) - return (int)(ptr - start); - - ptr--; - } - return -1; - } - } - - public int LastIndexOfAny (char [] anyOf, int startIndex, int count) - { - if (anyOf == null) - throw new ArgumentNullException (); - if (this.m_stringLength == 0) + int valueLen = value.Length; + if (count < valueLen) return -1; - if ((startIndex < 0) || (startIndex >= this.Length)) - throw new ArgumentOutOfRangeException ("startIndex", "< 0 || > this.Length"); - if ((count < 0) || (count > this.Length)) - throw new ArgumentOutOfRangeException ("count", "< 0 || > this.Length"); - if (startIndex - count + 1 < 0) - throw new ArgumentOutOfRangeException ("startIndex - count + 1 < 0"); + if (valueLen == 0) + return startIndex; - if (this.m_stringLength == 0) + fixed (char* thisptr = &_firstChar, valueptr = value) { + char* ap = thisptr + startIndex; + + char* thisEnd = ap - count + valueLen - 1; + char* valueEnd = valueptr + valueLen - 1; + + while (ap != thisEnd) { + if (*ap == *valueEnd) { + char* apEnd = ap; + while (valueptr != valueEnd) { + valueEnd--; + ap--; + if (*ap != *valueEnd) { + valueEnd = valueptr + valueLen - 1; + ap = apEnd; + goto NextVal; + } + } + + return (int)(ap - thisptr); + } + NextVal: + ap--; + } + } + + return -1; + } + + internal unsafe int LastIndexOfUncheckedIgnoreCase (string value, int startIndex, int count) + { + int valueLen = value.Length; + if (count < valueLen) return -1; - return LastIndexOfAnyUnchecked (anyOf, startIndex, count); - } + if (valueLen == 0) + return startIndex; - private unsafe int LastIndexOfAnyUnchecked (char [] anyOf, int startIndex, int count) - { - if (anyOf.Length == 1) - return LastIndexOfUnchecked (anyOf[0], startIndex, count); + var ti = CultureInfo.InvariantCulture.TextInfo; - fixed (char* start = &m_firstChar, testStart = anyOf) { - char* ptr = start + startIndex; - char* ptrEnd = ptr - count; - char* test; - char* testEnd = testStart + anyOf.Length; + fixed (char* thisptr = &_firstChar, valueptr = value) { + char* ap = thisptr + startIndex; - while (ptr != ptrEnd) { - test = testStart; - while (test != testEnd) { - if (*test == *ptr) - return (int)(ptr - start); - test++; + char* thisEnd = ap - count + valueLen - 1; + char* valueEnd = valueptr + valueLen - 1; + + var valueEndUpper = ti.ToUpper (*valueEnd); + + while (ap != thisEnd) { + if (ti.ToUpper (*ap) == valueEndUpper) { + char* apEnd = ap; + while (valueptr != valueEnd) { + valueEnd--; + ap--; + if (ti.ToUpper (*ap) != ti.ToUpper (*valueEnd)) { + valueEnd = valueptr + valueLen - 1; + ap = apEnd; + goto NextVal; + } + } + + return (int)(ap - thisptr); } - ptr--; - } - return -1; - } - } - - internal static int nativeCompareOrdinalEx (String strA, int indexA, String strB, int indexB, int count) - { - // - // .net does following checks in unmanaged land only which is quite - // wrong as it's not always necessary and argument names don't match - // but we are compatible - // - if (count < 0) - throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NegativeCount")); - - if (indexA < 0 || indexA > strA.Length) - throw new ArgumentOutOfRangeException("indexA", Environment.GetResourceString("ArgumentOutOfRange_Index")); - - if (indexB < 0 || indexB > strB.Length) - throw new ArgumentOutOfRangeException("indexB", Environment.GetResourceString("ArgumentOutOfRange_Index")); - - return CompareOrdinalUnchecked (strA, indexA, count, strB, indexB, count); - } - - unsafe String ReplaceInternal (char oldChar, char newChar) - { - if (this.m_stringLength == 0 || oldChar == newChar) - return this; - - int start_pos = IndexOfUnchecked (oldChar, 0, this.m_stringLength); - if (start_pos == -1) - return this; - - if (start_pos < 4) - start_pos = 0; - - string tmp = FastAllocateString (m_stringLength); - fixed (char* dest = tmp, src = &m_firstChar) { - if (start_pos != 0) - CharCopy (dest, src, start_pos); - - char* end_ptr = dest + m_stringLength; - char* dest_ptr = dest + start_pos; - char* src_ptr = src + start_pos; - - while (dest_ptr != end_ptr) { - if (*src_ptr == oldChar) - *dest_ptr = newChar; - else - *dest_ptr = *src_ptr; - - ++src_ptr; - ++dest_ptr; - } - } - return tmp; - } - - internal String ReplaceInternal (String oldValue, String newValue) - { - // LAMESPEC: According to MSDN the following method is culture-sensitive but this seems to be incorrect - // LAMESPEC: Result is undefined if result Length is longer than maximum string Length - - if (oldValue == null) - throw new ArgumentNullException ("oldValue"); - - if (oldValue.Length == 0) - throw new ArgumentException ("oldValue is the empty string."); - - if (this.Length == 0) - return this; - - if (newValue == null) - newValue = Empty; - - return ReplaceUnchecked (oldValue, newValue); - } - - private unsafe String ReplaceUnchecked (String oldValue, String newValue) - { - if (oldValue.m_stringLength > m_stringLength) - return this; - - if (oldValue.m_stringLength == 1 && newValue.m_stringLength == 1) { - return Replace (oldValue[0], newValue[0]); - // ENHANCE: It would be possible to special case oldValue.m_stringLength == newValue.m_stringLength - // because the m_stringLength of the result would be this.m_stringLength and m_stringLength calculation unneccesary - } - - const int maxValue = 200; // Allocate 800 byte maximum - int* dat = stackalloc int[maxValue]; - fixed (char* source = &m_firstChar, replace = newValue) { - int i = 0, count = 0; - while (i < m_stringLength) { - int found = IndexOfUnchecked (oldValue, i, m_stringLength - i); - if (found < 0) - break; - else { - if (count < maxValue) - dat[count++] = found; - else - return ReplaceFallback (oldValue, newValue, maxValue); - } - i = found + oldValue.m_stringLength; - } - if (count == 0) - return this; - - int nlen = 0; - checked { - try { - nlen = this.m_stringLength + ((newValue.m_stringLength - oldValue.m_stringLength) * count); - } catch (OverflowException) { - throw new OutOfMemoryException (); - } - } - String tmp = FastAllocateString (nlen); - - int curPos = 0, lastReadPos = 0; - fixed (char* dest = tmp) { - for (int j = 0; j < count; j++) { - int precopy = dat[j] - lastReadPos; - CharCopy (dest + curPos, source + lastReadPos, precopy); - curPos += precopy; - lastReadPos = dat[j] + oldValue.m_stringLength; - CharCopy (dest + curPos, replace, newValue.m_stringLength); - curPos += newValue.m_stringLength; - } - CharCopy (dest + curPos, source + lastReadPos, m_stringLength - lastReadPos); - } - return tmp; - } - } - - private String ReplaceFallback (String oldValue, String newValue, int testedCount) - { - int lengthEstimate = this.m_stringLength + ((newValue.m_stringLength - oldValue.m_stringLength) * testedCount); - StringBuilder sb = new StringBuilder (lengthEstimate); - for (int i = 0; i < m_stringLength;) { - int found = IndexOfUnchecked (oldValue, i, m_stringLength - i); - if (found < 0) { - sb.Append (InternalSubString (i, m_stringLength - i)); - break; - } - sb.Append (InternalSubString (i, found - i)); - sb.Append (newValue); - i = found + oldValue.m_stringLength; - } - return sb.ToString (); - - } - - unsafe String PadHelper (int totalWidth, char paddingChar, bool isRightPadded) - { - if (totalWidth < 0) - throw new ArgumentOutOfRangeException ("totalWidth", "Non-negative number required"); - if (totalWidth <= m_stringLength) - return this; - - string result = FastAllocateString (totalWidth); - - fixed (char *dest = result, src = &m_firstChar) { - if (isRightPadded) { - CharCopy (dest, src, m_stringLength); - char *end = dest + totalWidth; - char *p = dest + m_stringLength; - while (p < end) { - *p++ = paddingChar; - } - } else { - char *p = dest; - char *end = p + totalWidth - m_stringLength; - while (p < end) { - *p++ = paddingChar; - } - CharCopy (p, src, m_stringLength); + NextVal: + ap--; } } - return result; + return -1; } internal bool StartsWithOrdinalUnchecked (String value) { - return m_stringLength >= value.m_stringLength && CompareOrdinalUnchecked (this, 0, value.m_stringLength, value, 0, value.m_stringLength) == 0; + if (this.Length < value.Length || _firstChar != value._firstChar) + return false; + + return value.Length == 1 ? true : StartsWithOrdinalHelper (this, value); } - internal unsafe bool IsAscii () - { - fixed (char* src = &m_firstChar) { - char* end_ptr = src + m_stringLength; - char* str_ptr = src; - - while (str_ptr != end_ptr) { - if (*str_ptr >= 0x80) - return false; - - ++str_ptr; - } - } - - return true; - } - - internal bool IsFastSort () - { - return false; - } + [MethodImplAttribute (MethodImplOptions.InternalCall)] + internal extern static String FastAllocateString (int length); [MethodImplAttribute (MethodImplOptions.InternalCall)] private extern static string InternalIsInterned (string str); @@ -547,6 +214,21 @@ namespace System [MethodImplAttribute (MethodImplOptions.InternalCall)] private extern static string InternalIntern (string str); + static unsafe int FastCompareStringHelper (uint* strAChars, int countA, uint* strBChars, int countB) + { + // CoreRT implementation has alignment issues + char* ap = (char*) strAChars; + char* bp = (char*) strBChars; + char* end = ap + Math.Min (countA, countB); + while (ap < end) { + if (*ap != *bp) + return (int)*ap - (int)*bp; + ap++; + bp++; + } + return countA - countB; + } + internal static unsafe void CharCopy (char *dest, char *src, int count) { // Same rules as for memcpy, but with the premise that // chars can only be aligned to even addresses if their @@ -662,122 +344,100 @@ namespace System // Certain constructors are redirected to CreateString methods with // matching argument list. The this pointer should not be used. - private unsafe String CreateString (sbyte* value) + unsafe String CreateString (sbyte* value) { - if (value == null) - return Empty; - - byte* bytes = (byte*) value; - int length = 0; - - try { - while (bytes++ [0] != 0) - length++; - } catch (NullReferenceException) { - throw new ArgumentOutOfRangeException ("ptr", "Value does not refer to a valid string."); - } - - return CreateString (value, 0, length, null); + return Ctor (value); } unsafe String CreateString (sbyte* value, int startIndex, int length) { - return CreateString (value, startIndex, length, null); + return Ctor (value, startIndex, length); } - unsafe string CreateString (char *value) + unsafe string CreateString (char* value) { - return CtorCharPtr (value); + return Ctor (value); } - unsafe string CreateString (char *value, int startIndex, int length) + unsafe string CreateString (char* value, int startIndex, int length) { - return CtorCharPtrStartLength (value, startIndex, length); + return Ctor (value, startIndex, length); } string CreateString (char [] val, int startIndex, int length) { - return CtorCharArrayStartLength (val, startIndex, length); + return Ctor (val, startIndex, length); } string CreateString (char [] val) { - return CtorCharArray (val); + return Ctor (val); } - unsafe string CreateString (char c, int count) + string CreateString (char c, int count) { - if (count < 0) - throw new ArgumentOutOfRangeException ("count"); - if (count == 0) - return Empty; - string result = FastAllocateString (count); - fixed (char *dest = result) { - char *p = dest; - char *end = p + count; - while (p < end) { - *p = c; - p++; - } - } - return result; + return Ctor (c, count); } - private unsafe String CreateString (sbyte* value, int startIndex, int length, Encoding enc) + unsafe String CreateString (sbyte* value, int startIndex, int length, Encoding enc) { - if (length < 0) - throw new ArgumentOutOfRangeException ("length", "Non-negative number required."); - if (startIndex < 0) - throw new ArgumentOutOfRangeException ("startIndex", "Non-negative number required."); - if (value + startIndex < value) - throw new ArgumentOutOfRangeException ("startIndex", "Value, startIndex and length do not refer to a valid string."); - - if (enc == null) { - if (value == null) - throw new ArgumentNullException ("value"); - if (length == 0) - return Empty; - - enc = Encoding.Default; - } - - byte [] bytes = new byte [length]; - - if (length != 0) - fixed (byte* bytePtr = bytes) - try { - if (value == null) - throw new ArgumentOutOfRangeException ("ptr", "Value, startIndex and length do not refer to a valid string."); - memcpy (bytePtr, (byte*) (value + startIndex), length); - } catch (NullReferenceException) { - throw new ArgumentOutOfRangeException ("ptr", "Value, startIndex and length do not refer to a valid string."); - } - - // GetString () is called even when length == 0 - return enc.GetString (bytes); + return Ctor (value, startIndex, length, enc); } - unsafe String CreateString (ReadOnlySpan value) + String CreateString (ReadOnlySpan value) { - if (value.Length == 0) - return Empty; - - String result = FastAllocateString (value.Length); - fixed (char *dest = result, ptr = &value.DangerousGetPinnableReference ()) - wstrcpy (dest, ptr, value.Length); - - return result; + return Ctor (value); } [IndexerName ("Chars")] public char this [int index] { [IntrinsicAttribute] get { - if ((uint)index >= m_stringLength) + if ((uint)index >= _stringLength) ThrowHelper.ThrowIndexOutOfRangeException (); - return Unsafe.Add (ref m_firstChar, index); + return Unsafe.Add (ref _firstChar, index); } } + + public static String Intern (String str) + { + if (str == null) { + throw new ArgumentNullException ("str"); + } + + return InternalIntern (str); + } + + public static String IsInterned (String str) + { + if (str == null) + throw new ArgumentNullException ("str"); + + return InternalIsInterned (str); + } + + int LegacyStringGetHashCode () + { + int hash1 = 5381; + int hash2 = hash1; + + unsafe { + fixed (char *src = this) { + int c; + char *s = src; + while ((c = s[0]) != 0) { + hash1 = ((hash1 << 5) + hash1) ^ c; + c = s [1]; + if (c == 0) + break; + hash2 = ((hash2 << 5) + hash2) ^ c; + s += 2; + } + } + } + + return hash1 + (hash2 * 1566083941); + } } } \ No newline at end of file diff --git a/mcs/class/corlib/System.Globalization/CultureInfo.cs b/mcs/class/corlib/System.Globalization/CultureInfo.cs index 63c0c01597..e6a4fff119 100644 --- a/mcs/class/corlib/System.Globalization/CultureInfo.cs +++ b/mcs/class/corlib/System.Globalization/CultureInfo.cs @@ -115,6 +115,8 @@ namespace System.Globalization internal const int InvariantCultureId = 0x7F; const int CalendarTypeBits = 8; + internal const int LOCALE_INVARIANT = 0x007F; + const string MSG_READONLY = "This instance is read only"; static volatile CultureInfo s_DefaultThreadCurrentUICulture; @@ -180,6 +182,8 @@ namespace System.Globalization get { return territory; } } + internal string _name => m_name; + // FIXME: It is implemented, but would be hell slow. [ComVisible (false)] public CultureTypes CultureTypes { diff --git a/mcs/class/corlib/System.Reflection.Emit/ConstructorBuilder.cs b/mcs/class/corlib/System.Reflection.Emit/ConstructorBuilder.cs index 7b77a70194..89e83c7f50 100644 --- a/mcs/class/corlib/System.Reflection.Emit/ConstructorBuilder.cs +++ b/mcs/class/corlib/System.Reflection.Emit/ConstructorBuilder.cs @@ -81,7 +81,7 @@ namespace System.Reflection.Emit { type = tb; this.paramModReq = paramModReq; this.paramModOpt = paramModOpt; - table_idx = get_next_table_index (this, 0x06, true); + table_idx = get_next_table_index (this, 0x06, 1); ((ModuleBuilder) tb.Module).RegisterToken (this, GetToken ().Token); } @@ -396,9 +396,9 @@ namespace System.Reflection.Emit { } } - internal override int get_next_table_index (object obj, int table, bool inc) + internal override int get_next_table_index (object obj, int table, int count) { - return type.get_next_table_index (obj, table, inc); + return type.get_next_table_index (obj, table, count); } private void RejectIfCreated () diff --git a/mcs/class/corlib/System.Reflection.Emit/DynamicMethod.cs b/mcs/class/corlib/System.Reflection.Emit/DynamicMethod.cs index 82e099c4c4..c2a541976c 100644 --- a/mcs/class/corlib/System.Reflection.Emit/DynamicMethod.cs +++ b/mcs/class/corlib/System.Reflection.Emit/DynamicMethod.cs @@ -296,7 +296,7 @@ namespace System.Reflection.Emit { if (method == null) method = new MonoMethod (mhandle); - return method.Invoke (obj, parameters); + return method.Invoke (obj, invokeAttr, binder, parameters, culture); } catch (MethodAccessException mae) { throw new TargetInvocationException ("Method cannot be invoked.", mae); diff --git a/mcs/class/Facades/System.Reflection.Emit.Lightweight/DynamicMethod.cs b/mcs/class/corlib/System.Reflection.Emit/DynamicMethod.notsupported.cs similarity index 100% rename from mcs/class/Facades/System.Reflection.Emit.Lightweight/DynamicMethod.cs rename to mcs/class/corlib/System.Reflection.Emit/DynamicMethod.notsupported.cs diff --git a/mcs/class/corlib/System.Reflection.Emit/EventBuilder.cs b/mcs/class/corlib/System.Reflection.Emit/EventBuilder.cs index 2393e2abc9..77d3d7ac5c 100644 --- a/mcs/class/corlib/System.Reflection.Emit/EventBuilder.cs +++ b/mcs/class/corlib/System.Reflection.Emit/EventBuilder.cs @@ -63,11 +63,11 @@ namespace System.Reflection.Emit { attrs = eventAttrs; type = eventType; typeb = tb; - table_idx = get_next_table_index (this, 0x14, true); + table_idx = get_next_table_index (this, 0x14, 1); } - internal int get_next_table_index (object obj, int table, bool inc) { - return typeb.get_next_table_index (obj, table, inc); + internal int get_next_table_index (object obj, int table, int count) { + return typeb.get_next_table_index (obj, table, count); } public void AddOtherMethod( MethodBuilder mdBuilder) { diff --git a/mcs/class/corlib/System.Reflection.Emit/FieldBuilder.cs b/mcs/class/corlib/System.Reflection.Emit/FieldBuilder.cs index 23f27ca17c..a0a3a237bd 100644 --- a/mcs/class/corlib/System.Reflection.Emit/FieldBuilder.cs +++ b/mcs/class/corlib/System.Reflection.Emit/FieldBuilder.cs @@ -52,7 +52,6 @@ namespace System.Reflection.Emit { private String name; private object def_value; private int offset; - private int table_idx; internal TypeBuilder typeb; private byte[] rva_data; private CustomAttributeBuilder[] cattrs; @@ -74,7 +73,6 @@ namespace System.Reflection.Emit { this.modOpt = modOpt; offset = -1; typeb = tb; - table_idx = tb.get_next_table_index (this, 0x04, true); ((ModuleBuilder) tb.Module).RegisterToken (this, GetToken ().Token); } @@ -124,6 +122,8 @@ namespace System.Reflection.Emit { throw CreateNotSupportedException (); } + public override int MetadataToken { get { return ((ModuleBuilder) typeb.Module).GetToken (this); } } + public FieldToken GetToken() { return new FieldToken (MetadataToken); } diff --git a/mcs/class/corlib/System.Reflection.Emit/MethodBuilder.cs b/mcs/class/corlib/System.Reflection.Emit/MethodBuilder.cs index 8f09f0262b..38f81edca1 100644 --- a/mcs/class/corlib/System.Reflection.Emit/MethodBuilder.cs +++ b/mcs/class/corlib/System.Reflection.Emit/MethodBuilder.cs @@ -103,7 +103,7 @@ namespace System.Reflection.Emit System.Array.Copy (parameterTypes, this.parameters, parameterTypes.Length); } type = tb; - table_idx = get_next_table_index (this, 0x06, true); + table_idx = get_next_table_index (this, 0x06, 1); ((ModuleBuilder)tb.Module).RegisterToken (this, GetToken ().Token); } @@ -566,9 +566,9 @@ namespace System.Reflection.Emit return name.GetHashCode (); } - internal override int get_next_table_index (object obj, int table, bool inc) + internal override int get_next_table_index (object obj, int table, int count) { - return type.get_next_table_index (obj, table, inc); + return type.get_next_table_index (obj, table, count); } void ExtendArray (ref T[] array, T elem) { diff --git a/mcs/class/corlib/System.Reflection.Emit/ModuleBuilder.cs b/mcs/class/corlib/System.Reflection.Emit/ModuleBuilder.cs index 8744b4a458..ec3dbdb57f 100644 --- a/mcs/class/corlib/System.Reflection.Emit/ModuleBuilder.cs +++ b/mcs/class/corlib/System.Reflection.Emit/ModuleBuilder.cs @@ -63,6 +63,7 @@ namespace System.Reflection.Emit { bool is_main; private MonoResource[] resources; private IntPtr unparented_classes; + private int[] table_indexes; #endregion #pragma warning restore 169, 414 @@ -71,7 +72,6 @@ namespace System.Reflection.Emit { // name_cache keys are display names Dictionary name_cache; Dictionary us_string_cache; - private int[] table_indexes; bool transient; ModuleBuilderTokenGenerator token_gen; Hashtable resource_writers; @@ -93,7 +93,7 @@ namespace System.Reflection.Emit { // to keep mcs fast we do not want CryptoConfig wo be involved to create the RNG guid = Guid.FastNewGuidArray (); // guid = Guid.NewGuid().ToByteArray (); - table_idx = get_next_table_index (this, 0x00, true); + table_idx = get_next_table_index (this, 0x00, 1); name_cache = new Dictionary (); us_string_cache = new Dictionary (512); @@ -450,7 +450,7 @@ namespace System.Reflection.Emit { return result; } - internal int get_next_table_index (object obj, int table, bool inc) { + internal int get_next_table_index (object obj, int table, int count) { if (table_indexes == null) { table_indexes = new int [64]; for (int i=0; i < 64; ++i) @@ -459,9 +459,9 @@ namespace System.Reflection.Emit { table_indexes [0x02] = 2; } // Console.WriteLine ("getindex for table "+table.ToString()+" got "+table_indexes [table].ToString()); - if (inc) - return table_indexes [table]++; - return table_indexes [table]; + var index = table_indexes [table]; + table_indexes [table] += count; + return index; } public void SetCustomAttribute( CustomAttributeBuilder customBuilder) { @@ -786,7 +786,7 @@ namespace System.Reflection.Emit { } internal int GetToken (MemberInfo member) { - if (member is ConstructorBuilder || member is MethodBuilder) + if (member is ConstructorBuilder || member is MethodBuilder || member is FieldBuilder) return GetPseudoToken (member, false); return getToken (this, member, true); } diff --git a/mcs/class/corlib/System.Reflection.Emit/ParameterBuilder.cs b/mcs/class/corlib/System.Reflection.Emit/ParameterBuilder.cs index 97f9980513..5c75f0ed7f 100644 --- a/mcs/class/corlib/System.Reflection.Emit/ParameterBuilder.cs +++ b/mcs/class/corlib/System.Reflection.Emit/ParameterBuilder.cs @@ -66,7 +66,7 @@ namespace System.Reflection.Emit { if (mb is DynamicMethod) table_idx = 0; else - table_idx = mb.get_next_table_index (this, 0x08, true); + table_idx = mb.get_next_table_index (this, 0x08, 1); } public virtual int Attributes { diff --git a/mcs/class/corlib/System.Reflection.Emit/PropertyBuilder.cs b/mcs/class/corlib/System.Reflection.Emit/PropertyBuilder.cs index 8e53d04614..83ef86e7ea 100644 --- a/mcs/class/corlib/System.Reflection.Emit/PropertyBuilder.cs +++ b/mcs/class/corlib/System.Reflection.Emit/PropertyBuilder.cs @@ -80,7 +80,7 @@ namespace System.Reflection.Emit { System.Array.Copy (parameterTypes, this.parameters, this.parameters.Length); } typeb = tb; - table_idx = tb.get_next_table_index (this, 0x17, true); + table_idx = tb.get_next_table_index (this, 0x17, 1); } public override PropertyAttributes Attributes { diff --git a/mcs/class/corlib/System.Reflection.Emit/TypeBuilder.cs b/mcs/class/corlib/System.Reflection.Emit/TypeBuilder.cs index b1cc9727d5..31a06678e0 100644 --- a/mcs/class/corlib/System.Reflection.Emit/TypeBuilder.cs +++ b/mcs/class/corlib/System.Reflection.Emit/TypeBuilder.cs @@ -138,7 +138,7 @@ namespace System.Reflection.Emit this.parent = typeof (object); // skip . ? - table_idx = mb.get_next_table_index (this, 0x02, true); + table_idx = mb.get_next_table_index (this, 0x02, 1); fullname = GetFullName (); } @@ -1601,8 +1601,8 @@ namespace System.Reflection.Emit this.parent = ResolveUserType (this.parent); } - internal int get_next_table_index (object obj, int table, bool inc) { - return pmodule.get_next_table_index (obj, table, inc); + internal int get_next_table_index (object obj, int table, int count) { + return pmodule.get_next_table_index (obj, table, count); } [ComVisible (true)] diff --git a/mcs/class/corlib/System.Reflection/MonoMethod.cs b/mcs/class/corlib/System.Reflection/MonoMethod.cs index 9e5197df13..ce428e82e3 100644 --- a/mcs/class/corlib/System.Reflection/MonoMethod.cs +++ b/mcs/class/corlib/System.Reflection/MonoMethod.cs @@ -277,6 +277,8 @@ namespace System.Reflection { /* * InternalInvoke() receives the parameters correctly converted by the * binder to match the types of the method signature. + * The exc argument is used to capture exceptions thrown by the icall. + * Exceptions thrown by the called method propagate normally. */ [MethodImplAttribute(MethodImplOptions.InternalCall)] internal extern Object InternalInvoke (Object obj, Object[] parameters, out Exception exc); @@ -298,19 +300,22 @@ namespace System.Reflection { Exception exc; object o = null; - try { - // The ex argument is used to distinguish exceptions thrown by the icall - // from the exceptions thrown by the called method (which need to be - // wrapped in TargetInvocationException). - o = InternalInvoke (obj, parameters, out exc); - } catch (ThreadAbortException) { - throw; + if ((invokeAttr & BindingFlags.DoNotWrapExceptions) == 0) { + try { + o = InternalInvoke (obj, parameters, out exc); + } catch (ThreadAbortException) { + throw; #if MOBILE - } catch (MethodAccessException) { - throw; + } catch (MethodAccessException) { + throw; #endif - } catch (Exception e) { - throw new TargetInvocationException (e); + } catch (Exception e) { + throw new TargetInvocationException (e); + } + } + else + { + o = InternalInvoke (obj, parameters, out exc); } if (exc != null) @@ -649,22 +654,26 @@ namespace System.Reflection { throw new MemberAccessException (String.Format ("Cannot create an instance of {0} because it is an abstract class", DeclaringType)); } - return InternalInvoke (obj, parameters); + return InternalInvoke (obj, parameters, (invokeAttr & BindingFlags.DoNotWrapExceptions) == 0); } - public object InternalInvoke (object obj, object[] parameters) + public object InternalInvoke (object obj, object[] parameters, bool wrapExceptions) { Exception exc; object o = null; - try { - o = InternalInvoke (obj, parameters, out exc); + if (wrapExceptions) { + try { + o = InternalInvoke (obj, parameters, out exc); #if MOBILE - } catch (MethodAccessException) { - throw; + } catch (MethodAccessException) { + throw; #endif - } catch (Exception e) { - throw new TargetInvocationException (e); + } catch (Exception e) { + throw new TargetInvocationException (e); + } + } else { + o = InternalInvoke (obj, parameters, out exc); } if (exc != null) diff --git a/mcs/class/corlib/System.Runtime.CompilerServices/ConditionalWeakTable.cs b/mcs/class/corlib/System.Runtime.CompilerServices/ConditionalWeakTable.cs index bd5640ff8c..17474df4f9 100644 --- a/mcs/class/corlib/System.Runtime.CompilerServices/ConditionalWeakTable.cs +++ b/mcs/class/corlib/System.Runtime.CompilerServices/ConditionalWeakTable.cs @@ -49,7 +49,7 @@ namespace System.Runtime.CompilerServices Look into using quatratic probing/double hashing to reduce clustering problems. Make reads and non-expanding writes (add/remove) lock free. */ - public sealed class ConditionalWeakTable + public sealed class ConditionalWeakTable : IEnumerable> where TKey : class where TValue : class { @@ -374,5 +374,12 @@ namespace System.Runtime.CompilerServices return list; } } + + IEnumerator> IEnumerable>.GetEnumerator () + { + throw new NotImplementedException (); + } + + IEnumerator IEnumerable.GetEnumerator () => ((IEnumerable>)this).GetEnumerator (); } } diff --git a/mcs/class/corlib/System.Runtime.InteropServices.RuntimeInformation/RuntimeInformation.cs b/mcs/class/corlib/System.Runtime.InteropServices.RuntimeInformation/RuntimeInformation.cs index 922de4a22b..eda34460ff 100644 --- a/mcs/class/corlib/System.Runtime.InteropServices.RuntimeInformation/RuntimeInformation.cs +++ b/mcs/class/corlib/System.Runtime.InteropServices.RuntimeInformation/RuntimeInformation.cs @@ -43,6 +43,9 @@ namespace System.Runtime.InteropServices public static bool IsOSPlatform (OSPlatform osPlatform) { +#if WASM + return osPlatform == OSPlatform.Create ("WEBASSEMBLY"); +#else switch (Environment.Platform) { case PlatformID.Win32NT: return osPlatform == OSPlatform.Windows; @@ -53,13 +56,18 @@ namespace System.Runtime.InteropServices default: return false; } +#endif } public static string OSDescription { get { +#if WASM + return "web"; //yes, hardcoded as right now we don't really support other environments +#else return Environment.OSVersion.VersionString; +#endif } } diff --git a/mcs/class/corlib/System.Runtime.InteropServices/Marshal.cs b/mcs/class/corlib/System.Runtime.InteropServices/Marshal.cs index e94898a5c3..abbe07a747 100644 --- a/mcs/class/corlib/System.Runtime.InteropServices/Marshal.cs +++ b/mcs/class/corlib/System.Runtime.InteropServices/Marshal.cs @@ -1118,8 +1118,12 @@ namespace System.Runtime.InteropServices throw new OutOfMemoryException(); byte* pbMem = (byte*)pMem; - int nbWritten = s.GetBytesFromEncoding(pbMem, nb, Encoding.UTF8); - pbMem[nbWritten] = 0; + + fixed (char* pwzChar = s) + { + int nbWritten = Encoding.UTF8.GetBytes(pwzChar, s.Length, pbMem, nb); + pbMem[nbWritten] = 0; + } return pMem; } diff --git a/mcs/class/corlib/System.Runtime.Remoting/RemotingServices.cs b/mcs/class/corlib/System.Runtime.Remoting/RemotingServices.cs index 815c1ba7e7..422302eaf0 100644 --- a/mcs/class/corlib/System.Runtime.Remoting/RemotingServices.cs +++ b/mcs/class/corlib/System.Runtime.Remoting/RemotingServices.cs @@ -780,7 +780,9 @@ namespace System.Runtime.Remoting if (obj == null) return null; MemoryStream ms = new MemoryStream (); - _serializationFormatter.Serialize (ms, obj); + lock (_serializationFormatter) { + _serializationFormatter.Serialize (ms, obj); + } return ms.ToArray (); } @@ -791,7 +793,10 @@ namespace System.Runtime.Remoting if (array == null) return null; MemoryStream ms = new MemoryStream (array); - object obj = _deserializationFormatter.Deserialize (ms); + object obj; + lock (_deserializationFormatter) { + obj = _deserializationFormatter.Deserialize (ms); + } if (obj is CACD) { CACD cad = (CACD) obj; @@ -813,7 +818,9 @@ namespace System.Runtime.Remoting /* empty - we're only interested in the protected block */ } finally { MemoryStream ms = new MemoryStream (); - _serializationFormatter.Serialize (ms, ex); + lock (_serializationFormatter) { + _serializationFormatter.Serialize (ms, ex); + } result = ms.ToArray (); } return result; diff --git a/mcs/class/corlib/System.Threading/Thread.cs b/mcs/class/corlib/System.Threading/Thread.cs index 4cf9b0ede1..13731672a6 100644 --- a/mcs/class/corlib/System.Threading/Thread.cs +++ b/mcs/class/corlib/System.Threading/Thread.cs @@ -245,6 +245,10 @@ namespace System.Threading { get { Thread th = CurrentThread; + var logicalPrincipal = th.GetExecutionContextReader().LogicalCallContext.Principal; + if (logicalPrincipal != null) + return logicalPrincipal; + if (th.principal_version != th.Internal._serialized_principal_version) th.principal = null; @@ -266,6 +270,8 @@ namespace System.Threading { set { Thread th = CurrentThread; + th.GetMutableExecutionContext().LogicalCallContext.Principal = value; + if (value != GetDomain ().DefaultPrincipal) { ++th.Internal._serialized_principal_version; try { diff --git a/mcs/class/corlib/System.Threading/Timer.cs b/mcs/class/corlib/System.Threading/Timer.cs index 63026b42c7..25a446599d 100644 --- a/mcs/class/corlib/System.Threading/Timer.cs +++ b/mcs/class/corlib/System.Threading/Timer.cs @@ -33,8 +33,35 @@ using System.Collections.Generic; using System.Collections; using System.Runtime.CompilerServices; + namespace System.Threading { +#if WASM + internal static class WasmRuntime { + static Dictionary callbacks; + static int next_id; + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + static extern void SetTimeout (int timeout, int id); + + internal static void ScheduleTimeout (int timeout, Action action) { + if (callbacks == null) + callbacks = new Dictionary (); + int id = ++next_id; + callbacks [id] = action; + SetTimeout (timeout, id); + } + + //XXX Keep this in sync with mini-wasm.c:mono_set_timeout_exec + static void TimeoutCallback (int id) { + var cb = callbacks [id]; + callbacks.Remove (id); + cb (); + } + } +#endif + + [ComVisible (true)] public sealed class Timer : MarshalByRefObject, IDisposable @@ -198,8 +225,62 @@ namespace System.Threading sealed class Scheduler { static Scheduler instance; SortedList list; + +#if WASM + List cached_new_time; + bool scheduled_zero; + + void InitScheduler () { + cached_new_time = new List (512); + } + + void WakeupScheduler () { + if (!scheduled_zero) { + WasmRuntime.ScheduleTimeout (0, this.RunScheduler); + scheduled_zero = true; + } + } + + void RunScheduler() { + scheduled_zero = false; + int ms_wait = RunSchedulerLoop (cached_new_time); + if (ms_wait >= 0) { + WasmRuntime.ScheduleTimeout (ms_wait, this.RunScheduler); + if (ms_wait == 0) + scheduled_zero = true; + } + } +#else ManualResetEvent changed; + void InitScheduler () { + changed = new ManualResetEvent (false); + Thread thread = new Thread (SchedulerThread); + thread.IsBackground = true; + thread.Start (); + } + + void WakeupScheduler () { + changed.Set (); + } + + void SchedulerThread () + { + Thread.CurrentThread.Name = "Timer-Scheduler"; + var new_time = new List (512); + while (true) { + int ms_wait = -1; + lock (this) { + changed.Reset (); + ms_wait = RunSchedulerLoop (new_time); + } + // Wait until due time or a timer is changed and moves from/to the first place in the list. + changed.WaitOne (ms_wait); + } + } + +#endif + static Scheduler () { instance = new Scheduler (); @@ -211,11 +292,8 @@ namespace System.Threading private Scheduler () { - changed = new ManualResetEvent (false); list = new SortedList (new TimerComparer (), 1024); - Thread thread = new Thread (SchedulerThread); - thread.IsBackground = true; - thread.Start (); + InitScheduler (); } public void Remove (Timer timer) @@ -250,7 +328,7 @@ namespace System.Threading } } if (wake) - changed.Set (); + WakeupScheduler(); } // lock held by caller @@ -327,73 +405,64 @@ namespace System.Threading timer.callback (timer.state); } - void SchedulerThread () - { - Thread.CurrentThread.Name = "Timer-Scheduler"; - var new_time = new List (512); - while (true) { - int ms_wait = -1; - long ticks = GetTimeMonotonic (); - lock (this) { - changed.Reset (); - //PrintList (); - int i; - int count = list.Count; - for (i = 0; i < count; i++) { - Timer timer = (Timer) list.GetByIndex (i); - if (timer.next_run > ticks) - break; + int RunSchedulerLoop (List new_time) { + int ms_wait = -1; + int i; + int count = list.Count; + long ticks = GetTimeMonotonic (); - list.RemoveAt (i); - count--; - i--; - ThreadPool.UnsafeQueueUserWorkItem (TimerCB, timer); - long period = timer.period_ms; - long due_time = timer.due_time_ms; - bool no_more = (period == -1 || ((period == 0 || period == Timeout.Infinite) && due_time != Timeout.Infinite)); - if (no_more) { - timer.next_run = Int64.MaxValue; - } else { - timer.next_run = GetTimeMonotonic () + TimeSpan.TicksPerMillisecond * timer.period_ms; - new_time.Add (timer); - } - } + for (i = 0; i < count; i++) { + Timer timer = (Timer) list.GetByIndex (i); + if (timer.next_run > ticks) + break; - // Reschedule timers with a new due time - count = new_time.Count; - for (i = 0; i < count; i++) { - Timer timer = new_time [i]; - Add (timer); - } - new_time.Clear (); - ShrinkIfNeeded (new_time, 512); - - // Shrink the list - int capacity = list.Capacity; - count = list.Count; - if (capacity > 1024 && count > 0 && (capacity / count) > 3) - list.Capacity = count * 2; - - long min_next_run = Int64.MaxValue; - if (list.Count > 0) - min_next_run = ((Timer) list.GetByIndex (0)).next_run; - - //PrintList (); - ms_wait = -1; - if (min_next_run != Int64.MaxValue) { - long diff = (min_next_run - GetTimeMonotonic ()) / TimeSpan.TicksPerMillisecond; - if (diff > Int32.MaxValue) - ms_wait = Int32.MaxValue - 1; - else { - ms_wait = (int)(diff); - if (ms_wait < 0) - ms_wait = 0; - } - } + list.RemoveAt (i); + count--; + i--; + ThreadPool.UnsafeQueueUserWorkItem (TimerCB, timer); + long period = timer.period_ms; + long due_time = timer.due_time_ms; + bool no_more = (period == -1 || ((period == 0 || period == Timeout.Infinite) && due_time != Timeout.Infinite)); + if (no_more) { + timer.next_run = Int64.MaxValue; + } else { + timer.next_run = GetTimeMonotonic () + TimeSpan.TicksPerMillisecond * timer.period_ms; + new_time.Add (timer); } - // Wait until due time or a timer is changed and moves from/to the first place in the list. - changed.WaitOne (ms_wait); } + + // Reschedule timers with a new due time + count = new_time.Count; + for (i = 0; i < count; i++) { + Timer timer = new_time [i]; + Add (timer); + } + new_time.Clear (); + ShrinkIfNeeded (new_time, 512); + + // Shrink the list + int capacity = list.Capacity; + count = list.Count; + if (capacity > 1024 && count > 0 && (capacity / count) > 3) + list.Capacity = count * 2; + + long min_next_run = Int64.MaxValue; + if (list.Count > 0) + min_next_run = ((Timer) list.GetByIndex (0)).next_run; + + //PrintList (); + ms_wait = -1; + if (min_next_run != Int64.MaxValue) { + long diff = (min_next_run - GetTimeMonotonic ()) / TimeSpan.TicksPerMillisecond; + if (diff > Int32.MaxValue) + ms_wait = Int32.MaxValue - 1; + else { + ms_wait = (int)(diff); + if (ms_wait < 0) + ms_wait = 0; + } + } + return ms_wait; } void ShrinkIfNeeded (List list, int initial) diff --git a/mcs/class/corlib/System/Array.cs b/mcs/class/corlib/System/Array.cs index c3f04223d8..00433d8b68 100644 --- a/mcs/class/corlib/System/Array.cs +++ b/mcs/class/corlib/System/Array.cs @@ -49,7 +49,6 @@ namespace System private Array () { } - /* * These methods are used to implement the implicit generic interfaces * implemented by arrays in NET 2.0. diff --git a/mcs/class/corlib/System/Console.cs b/mcs/class/corlib/System/Console.cs index aa0d8fca91..eb3279e13d 100644 --- a/mcs/class/corlib/System/Console.cs +++ b/mcs/class/corlib/System/Console.cs @@ -596,7 +596,6 @@ namespace System get { return ConsoleDriver.LargestWindowWidth; } } - [MonoLimitation ("Only works on windows")] public static bool NumberLock { get { return ConsoleDriver.NumberLock; } } @@ -611,25 +610,21 @@ namespace System set { ConsoleDriver.TreatControlCAsInput = value; } } - [MonoLimitation ("Only works on windows")] public static int WindowHeight { get { return ConsoleDriver.WindowHeight; } set { ConsoleDriver.WindowHeight = value; } } - [MonoLimitation ("Only works on windows")] public static int WindowLeft { get { return ConsoleDriver.WindowLeft; } set { ConsoleDriver.WindowLeft = value; } } - [MonoLimitation ("Only works on windows")] public static int WindowTop { get { return ConsoleDriver.WindowTop; } set { ConsoleDriver.WindowTop = value; } } - [MonoLimitation ("Only works on windows")] public static int WindowWidth { get { return ConsoleDriver.WindowWidth; } set { ConsoleDriver.WindowWidth = value; } diff --git a/mcs/class/corlib/System/Delegate.cs b/mcs/class/corlib/System/Delegate.cs index 958b70ce81..8b28570782 100644 --- a/mcs/class/corlib/System/Delegate.cs +++ b/mcs/class/corlib/System/Delegate.cs @@ -115,6 +115,8 @@ namespace System } } + internal IntPtr GetNativeFunctionPointer () => method_ptr; + // // Methods // diff --git a/mcs/class/corlib/System/Nullable.cs b/mcs/class/corlib/System/Nullable.cs index 32c4aa0885..2d8a297e4c 100644 --- a/mcs/class/corlib/System/Nullable.cs +++ b/mcs/class/corlib/System/Nullable.cs @@ -186,6 +186,17 @@ namespace System return null; return (T) o; } + + static T? UnboxExact (object o) + { + if (o == null) + return null; + if (o.GetType() != typeof (T)) + throw new InvalidCastException(); + + return (T) o; + } + #pragma warning restore 169 } } diff --git a/mcs/class/corlib/System/TermInfoDriver.cs b/mcs/class/corlib/System/TermInfoDriver.cs index aa0eab7796..b8e0ba452f 100644 --- a/mcs/class/corlib/System/TermInfoDriver.cs +++ b/mcs/class/corlib/System/TermInfoDriver.cs @@ -391,6 +391,10 @@ namespace System { void ChangeColor (string format, ConsoleColor color) { + if (String.IsNullOrEmpty (format)) + // the terminal doesn't support colors + return; + int ccValue = (int)color; if ((ccValue & ~0xF) != 0) throw new ArgumentException("Invalid Console Color"); diff --git a/mcs/class/corlib/Test/System.Reflection.Emit/ModuleBuilderTest.cs b/mcs/class/corlib/Test/System.Reflection.Emit/ModuleBuilderTest.cs index 807a1dd3e9..5973108cb1 100644 --- a/mcs/class/corlib/Test/System.Reflection.Emit/ModuleBuilderTest.cs +++ b/mcs/class/corlib/Test/System.Reflection.Emit/ModuleBuilderTest.cs @@ -525,7 +525,7 @@ namespace MonoTests.System.Reflection.Emit var field = type.DefineField ("field", t, FieldAttributes.Public); - type.CreateType (); + var tc = type.CreateType (); var resolved_field = (FieldInfo) module.ResolveMember (0x04000001, new [] { typeof (string) }, Type.EmptyTypes); Assert.IsNotNull (resolved_field); @@ -1185,5 +1185,55 @@ namespace MonoTests.System.Reflection.Emit Assert.AreEqual ("17", s2); } + [Test] + public void FieldBuilder_DistinctTokens () + { + // Regression test for #33208 + // Fields of distinct classes in the same + // module should have distinct tokens. + + AssemblyBuilder ab = genAssembly (); + ModuleBuilder module = ab.DefineDynamicModule ("foo.dll", "foo.dll"); + + var tb1 = module.DefineType ("T1", TypeAttributes.Public); + + var tb2 = module.DefineType ("T2", TypeAttributes.Public); + + FieldBuilder fbX1 = tb1.DefineField ("X", typeof (Object), FieldAttributes.Public); + + FieldBuilder fbX2 = tb2.DefineField ("X", typeof (Object), FieldAttributes.Public); + + FieldBuilder fbY1 = tb1.DefineField ("Y", typeof (int), FieldAttributes.Public); + + Assert.AreNotEqual (fbX1.GetToken (), fbX2.GetToken (), "GetToken() T1.X != T2.X"); + Assert.AreNotEqual (fbX1.GetToken (), fbY1.GetToken (), "GetToken() T1.X != T1.Y"); + Assert.AreNotEqual (fbY1.GetToken (), fbX2.GetToken (), "GetToken() T1.Y != T2.X"); + + // .NET throws NotSupportedException for + // FieldBuilder.MetadataToken, Mono doesn't. + // We'll check that the metadata tokens are + // distinct, but it's also okay to take these + // assertions out if we start following .NET + // behavior. + Assert.AreNotEqual (fbX1.MetadataToken, fbX2.MetadataToken, "MetadataToken T1.X != T2.X"); + Assert.AreNotEqual (fbX1.MetadataToken, fbY1.MetadataToken, "MetadataToken T1.X != T1.Y"); + Assert.AreNotEqual (fbY1.MetadataToken, fbX2.MetadataToken, "MetadataToken T1.Y != T2.X"); + + var t1 = tb1.CreateType (); + var t2 = tb2.CreateType (); + + FieldInfo fX1 = t1.GetField ("X"); + FieldInfo fX2 = t2.GetField ("X"); + + FieldInfo fY1 = t1.GetField ("Y"); + + Assert.AreNotEqual (fX1.MetadataToken, fX2.MetadataToken, "T1.X != T2.X"); + Assert.AreNotEqual (fX1.MetadataToken, fY1.MetadataToken, "T1.X != T1.Y"); + Assert.AreNotEqual (fY1.MetadataToken, fX2.MetadataToken, "T1.Y != T2.X"); + + Assert.AreEqual (module.ResolveField (fX1.MetadataToken), fX1, "resolve T1.X"); + Assert.AreEqual (module.ResolveField (fX2.MetadataToken), fX2, "resolve T2.X"); + Assert.AreEqual (module.ResolveField (fY1.MetadataToken), fY1, "resolve T1.Y"); + } } } diff --git a/mcs/class/corlib/Test/System.Runtime.CompilerServices/TypeForwardedFromAttributeTest.cs b/mcs/class/corlib/Test/System.Runtime.CompilerServices/TypeForwardedFromAttributeTest.cs index d11fa7138a..3ebb1da285 100644 --- a/mcs/class/corlib/Test/System.Runtime.CompilerServices/TypeForwardedFromAttributeTest.cs +++ b/mcs/class/corlib/Test/System.Runtime.CompilerServices/TypeForwardedFromAttributeTest.cs @@ -43,7 +43,7 @@ namespace MonoTests.System.Runtime.CompilerServices { var a = new TypeForwardedFromAttribute ("System.Web, Version=2.0.0.0, Culture=Neutral, PublicKeyToken=b03f5f7f11d50a3a"); Assert.AreEqual ("System.Web, Version=2.0.0.0, Culture=Neutral, PublicKeyToken=b03f5f7f11d50a3a", a.AssemblyFullName); - Assert.Throws ( () => new TypeForwardedFromAttribute (null) ); + var nullArgumentDoesntThrowException = new TypeForwardedFromAttribute (null); } } } diff --git a/mcs/class/corlib/Test/System.Runtime.Remoting/RemotingServicesTest.cs b/mcs/class/corlib/Test/System.Runtime.Remoting/RemotingServicesTest.cs new file mode 100644 index 0000000000..8f01385fab --- /dev/null +++ b/mcs/class/corlib/Test/System.Runtime.Remoting/RemotingServicesTest.cs @@ -0,0 +1,60 @@ +// +// MonoTests.System.Runtime.Remoting.RemotingServicesTest.cs +// +// Author: Alexis Christoforides (alchri@microsoft.com) +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Reflection; +using System.Threading.Tasks; +using NUnit.Framework; + +namespace MonoTests.System.Runtime.Remoting +{ + [TestFixture] + public class RemotingServicesTest + { + public class AppDomainObject : MarshalByRefObject + { + public void Init(CrossDomainSerializedObject applicationDependencies) // racy exception here + { + + } + } + + public class CrossDomainSerializedObject : MarshalByRefObject + { + } + private static CrossDomainSerializedObject crossDomainSerializedObject; + + private static void AppDomainWithRemotingSerialization(Assembly assembly, string name) + { + var appDomain = AppDomain.CreateDomain(name); + var appDomainObject = (AppDomainObject)appDomain.CreateInstanceAndUnwrap(assembly.GetName().Name, typeof(AppDomainObject).FullName); + appDomainObject.Init(crossDomainSerializedObject); + } + + [Test] + public void Bug46473 () // concurrent serialization/deserialization + { + bool success = true; + crossDomainSerializedObject = new CrossDomainSerializedObject(); + Task[] tasks = new Task [20]; + for (int i = 0; i < tasks.Length; i++) + { + var assembly = Assembly.GetAssembly(typeof(AppDomainObject)); + var name = "AppDomainWithCall" + i; + tasks [i] = Task.Factory.StartNew(() => AppDomainWithRemotingSerialization(assembly, name)); + } + try { + Task.WaitAll (tasks); + } catch (AggregateException e) { + success = false; + Console.WriteLine ($"{e}, {e.InnerException}"); + } + Assert.IsTrue (success, "Bug46473 (exception during remoting call)"); + } + } +} diff --git a/mcs/class/corlib/Test/System.Threading.Tasks/TaskFactoryTest.cs b/mcs/class/corlib/Test/System.Threading.Tasks/TaskFactoryTest.cs index dd9edde9ad..973ec1ff46 100644 --- a/mcs/class/corlib/Test/System.Threading.Tasks/TaskFactoryTest.cs +++ b/mcs/class/corlib/Test/System.Threading.Tasks/TaskFactoryTest.cs @@ -569,7 +569,6 @@ namespace MonoTests.System.Threading.Tasks } [Test] - [Category ("MacNotWorking")] // Randomly fails - https://bugzilla.xamarin.com/show_bug.cgi?id=51255 public void FromAsync_BeginCallback () { bool called = false; @@ -586,8 +585,9 @@ namespace MonoTests.System.Threading.Tasks Assert.IsFalse (Thread.CurrentThread.IsThreadPoolThread, "#12"); called2 = true; - b.Invoke (null); - return null; + var ar = Task.CompletedTask; + b.Invoke (ar); + return ar; }, l => { called = true; diff --git a/mcs/class/corlib/Test/System.Threading/ThreadPrincipalTests.cs b/mcs/class/corlib/Test/System.Threading/ThreadPrincipalTests.cs new file mode 100644 index 0000000000..712814c137 --- /dev/null +++ b/mcs/class/corlib/Test/System.Threading/ThreadPrincipalTests.cs @@ -0,0 +1,76 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using NUnit.Framework; +using System.Security; +using System.Security.Permissions; +using System.Security.Principal; + +namespace MonoTests.System.Threading.Tasks +{ + [TestFixture] + public class ThreadPrincipalTests + { + [Test] + public void PrincipalFlowsToAsyncTask () + { + var t = _PrincipalFlowsToAsyncTask(); + t.GetAwaiter().GetResult(); + } + + public async Task _PrincipalFlowsToAsyncTask () + { + var mockIdentity = new MockIdentity { + AuthenticationType = "authtype", + IsAuthenticated = true, + Name = "name" + }; + var mockPrincipal = new MockPrincipal { + Identity = mockIdentity + }; + var oldPrincipal = Thread.CurrentPrincipal; + Thread.CurrentPrincipal = mockPrincipal; + + try { + await Task.Factory.StartNew(async () => + { + var newThreadId = Thread.CurrentThread.ManagedThreadId; // on different thread. + Assert.IsTrue(Thread.CurrentPrincipal.Identity.IsAuthenticated); + Assert.AreEqual(mockPrincipal, Thread.CurrentPrincipal); + + await Task.Factory.StartNew(() => + { + // still works even when nesting.. + newThreadId = Thread.CurrentThread.ManagedThreadId; + Assert.IsTrue(Thread.CurrentPrincipal.Identity.IsAuthenticated); + Assert.AreEqual(mockPrincipal, Thread.CurrentPrincipal); + + }, TaskCreationOptions.LongRunning); + }, TaskCreationOptions.LongRunning); + + await Task.Run(() => + { + // Following works on NET4.7 and fails under Xamarin.Android. + var newThreadId = Thread.CurrentThread.ManagedThreadId; + Assert.IsTrue(Thread.CurrentPrincipal.Identity.IsAuthenticated); + Assert.AreEqual(mockPrincipal, Thread.CurrentPrincipal); + }); + } finally { + Thread.CurrentPrincipal = oldPrincipal; + } + } + } + + public class MockPrincipal : IPrincipal { + public IIdentity Identity { get; set; } + public bool IsInRole (string role) { + return true; + } + } + + public class MockIdentity : IIdentity { + public string AuthenticationType { get; set; } + public bool IsAuthenticated { get; set; } + public string Name { get; set; } + } +} \ No newline at end of file diff --git a/mcs/class/corlib/Test/System.Threading/ThreadTest.cs b/mcs/class/corlib/Test/System.Threading/ThreadTest.cs index 8969ca9862..317cfe4da6 100644 --- a/mcs/class/corlib/Test/System.Threading/ThreadTest.cs +++ b/mcs/class/corlib/Test/System.Threading/ThreadTest.cs @@ -835,6 +835,7 @@ namespace MonoTests.System.Threading #endif [Test] + [Category ("NotWorkingRuntimeInterpreter")] public void Test_Interrupt () { ManualResetEvent mre = new ManualResetEvent (false); diff --git a/mcs/class/corlib/Test/System/StringTest.cs.REMOVED.git-id b/mcs/class/corlib/Test/System/StringTest.cs.REMOVED.git-id index f76ed8a99b..f3840e2db8 100644 --- a/mcs/class/corlib/Test/System/StringTest.cs.REMOVED.git-id +++ b/mcs/class/corlib/Test/System/StringTest.cs.REMOVED.git-id @@ -1 +1 @@ -be5e7984757b64a30bba3b7274a9f86edfab970f \ No newline at end of file +0be02f7a0bafa90f444ffe344ae9d4564513f5f1 \ No newline at end of file diff --git a/mcs/class/corlib/Test/System/TypeTest.cs.REMOVED.git-id b/mcs/class/corlib/Test/System/TypeTest.cs.REMOVED.git-id index ec38d11c01..842f2b4894 100644 --- a/mcs/class/corlib/Test/System/TypeTest.cs.REMOVED.git-id +++ b/mcs/class/corlib/Test/System/TypeTest.cs.REMOVED.git-id @@ -1 +1 @@ -9feda2ab31c0832aa8ddef3b30100db2246253e7 \ No newline at end of file +744f1a217a1af896659e714634a6b4c7b8a08b5a \ No newline at end of file diff --git a/mcs/class/corlib/corefx/AwaitTaskContinuation.cs b/mcs/class/corlib/corefx/AwaitTaskContinuation.cs new file mode 100644 index 0000000000..9d416a10b1 --- /dev/null +++ b/mcs/class/corlib/corefx/AwaitTaskContinuation.cs @@ -0,0 +1,12 @@ +namespace System.Threading.Tasks +{ + partial class AwaitTaskContinuation + { + public void MarkAborted (ThreadAbortException e) {} + } + + partial class CompletionActionInvoker + { + public void MarkAborted (ThreadAbortException e) {} + } +} \ No newline at end of file diff --git a/mcs/class/corlib/corefx/CompareInfo.cs b/mcs/class/corlib/corefx/CompareInfo.cs new file mode 100644 index 0000000000..78bce55087 --- /dev/null +++ b/mcs/class/corlib/corefx/CompareInfo.cs @@ -0,0 +1,149 @@ +// +// CompareInfo.cs +// +// Authors: +// Marek Safar +// +// Copyright (C) 2018 Microsoft Corporation +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace System.Globalization +{ + partial class CompareInfo + { + void InitSort (CultureInfo culture) + { + _sortName = culture.SortName; + } + + unsafe static int CompareStringOrdinalIgnoreCase (char* pString1, int length1, char* pString2, int length2) + { + var ti = CultureInfo.InvariantCulture.TextInfo; + + int index = 0; + while (index < length1 && index < length2 && ti.ToUpper (*pString1) == ti.ToUpper (*pString2)) { + ++index; + ++pString1; + ++pString2; + } + + if (index >= length1) { + if (index >= length2) + return 0; + + return -1; + } + + if (index >= length2) + return 1; + + return ti.ToUpper (*pString1) - ti.ToUpper (*pString2); + } + + internal static int IndexOfOrdinalCore (string source, string value, int startIndex, int count, bool ignoreCase) + { + if (!ignoreCase) + return source.IndexOfUnchecked (value, startIndex, count); + + return source.IndexOfUncheckedIgnoreCase (value, startIndex, count); + } + + internal static unsafe int LastIndexOfOrdinalCore (string source, string value, int startIndex, int count, bool ignoreCase) + { + if (!ignoreCase) + return source.LastIndexOfUnchecked (value, startIndex, count); + + return source.LastIndexOfUncheckedIgnoreCase (value, startIndex, count); + } + + int LastIndexOfCore (string source, string target, int startIndex, int count, CompareOptions options) + { + return internal_index_switch (source, startIndex, count, target, options, false); + } + + unsafe int IndexOfCore (string source, string target, int startIndex, int count, CompareOptions options, int* matchLengthPtr) + { + if (matchLengthPtr != null) + throw new NotImplementedException (); + + return internal_index_switch (source, startIndex, count, target, options, true); + } + + int CompareString (ReadOnlySpan string1, string string2, CompareOptions options) + { + throw new NotImplementedException (); + } + + int CompareString (ReadOnlySpan string1, ReadOnlySpan string2, CompareOptions options) + { + throw new NotImplementedException (); + } + + unsafe static bool IsSortable (char *text, int length) + { + return Mono.Globalization.Unicode.MSCompatUnicodeTable.IsSortable (new string (text, 0, length)); + } + + SortKey CreateSortKey (String source, CompareOptions options) + { + if (source == null) + throw new ArgumentNullException (nameof (source)); + + if ((options & ValidSortkeyCtorMaskOffFlags) != 0) + throw new ArgumentException (SR.Argument_InvalidFlag, nameof (options)); + + return CreateSortKeyCore (source, options); + } + + bool StartsWith (string source, string prefix, CompareOptions options) + { + if (UseManagedCollation) + return GetCollator ().IsPrefix (source, prefix, options); + + if (source.Length < prefix.Length) + return false; + + return Compare (source, 0, prefix.Length, prefix, 0, prefix.Length, options) == 0; + } + + bool EndsWith (string source, string suffix, CompareOptions options) + { + if (UseManagedCollation) + return GetCollator ().IsSuffix (source, suffix, options); + + if (source.Length < suffix.Length) + return false; + + return Compare (source, source.Length - suffix.Length, suffix.Length, suffix, 0, suffix.Length, options) == 0; + } + + internal int GetHashCodeOfStringCore (string source, CompareOptions options) + { + return GetSortKey (source, options).GetHashCode (); + } + + SortVersion GetSortVersion () + { + throw new NotImplementedException (); + } + } +} \ No newline at end of file diff --git a/mcs/class/corlib/corefx/GlobalizationMode.cs b/mcs/class/corlib/corefx/GlobalizationMode.cs new file mode 100644 index 0000000000..5fb83ac9b6 --- /dev/null +++ b/mcs/class/corlib/corefx/GlobalizationMode.cs @@ -0,0 +1,7 @@ +namespace System.Globalization +{ + partial class GlobalizationMode + { + private static bool GetGlobalizationInvariantMode () => false; + } +} diff --git a/mcs/class/corlib/corefx/MemoryExtensions.cs b/mcs/class/corlib/corefx/MemoryExtensions.cs new file mode 100644 index 0000000000..96a4495a1e --- /dev/null +++ b/mcs/class/corlib/corefx/MemoryExtensions.cs @@ -0,0 +1,15 @@ +using System.Runtime.CompilerServices; + +namespace System +{ + partial class MemoryExtensions + { + public static ReadOnlySpan AsSpan (this string text) + { + if (text == null) + return default; + + return new ReadOnlySpan (Unsafe.As> (text), StringAdjustment, text.Length); + } + } +} diff --git a/mcs/class/corlib/corefx/SR.cs.REMOVED.git-id b/mcs/class/corlib/corefx/SR.cs.REMOVED.git-id index baf66a0144..61cac8a7b9 100644 --- a/mcs/class/corlib/corefx/SR.cs.REMOVED.git-id +++ b/mcs/class/corlib/corefx/SR.cs.REMOVED.git-id @@ -1 +1 @@ -9ac00eca4c5e8b4a2e61d5826df2437d0ceb119b \ No newline at end of file +ec5b4344a30b08f8137db41ec67c1b34702c56b8 \ No newline at end of file diff --git a/mcs/class/corlib/corefx/SynchronizationContext.cs b/mcs/class/corlib/corefx/SynchronizationContext.cs new file mode 100644 index 0000000000..09952a9097 --- /dev/null +++ b/mcs/class/corlib/corefx/SynchronizationContext.cs @@ -0,0 +1,7 @@ +namespace System.Threading +{ + partial class SynchronizationContext + { + internal static SynchronizationContext CurrentExplicit => Current; + } +} \ No newline at end of file diff --git a/mcs/class/corlib/corert/Debug.cs b/mcs/class/corlib/corert/Debug.cs index 31959c1739..4a3f984f73 100644 --- a/mcs/class/corlib/corert/Debug.cs +++ b/mcs/class/corlib/corert/Debug.cs @@ -2,7 +2,7 @@ namespace System.Diagnostics.Private { static partial class Debug { - static void ShowAssertDialog (string stackTrace, string message, string detailMessage) + static void ShowDialog (string stackTrace, string message, string detailMessage, string errorSource) { // FIXME should we g_error in this case? } diff --git a/mcs/class/corlib/corert/DependencyReductionRootAttribute.cs b/mcs/class/corlib/corert/DependencyReductionRootAttribute.cs new file mode 100644 index 0000000000..34bb027866 --- /dev/null +++ b/mcs/class/corlib/corert/DependencyReductionRootAttribute.cs @@ -0,0 +1,9 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Runtime.CompilerServices +{ + [System.Diagnostics.Conditional("NOT_MONO")] + class DependencyReductionRootAttribute : Attribute {} +} diff --git a/mcs/class/corlib/corert/RuntimeAugments.cs b/mcs/class/corlib/corert/RuntimeAugments.cs new file mode 100644 index 0000000000..64d7fbb800 --- /dev/null +++ b/mcs/class/corlib/corert/RuntimeAugments.cs @@ -0,0 +1,12 @@ +using System; + +namespace Internal.Runtime.Augments +{ + partial class RuntimeAugments + { + public static void ReportUnhandledException (Exception exception) + { + throw exception; + } + } +} \ No newline at end of file diff --git a/mcs/class/corlib/corert/RuntimeThread.cs b/mcs/class/corlib/corert/RuntimeThread.cs index a296d8cbc2..ec594a264d 100644 --- a/mcs/class/corlib/corert/RuntimeThread.cs +++ b/mcs/class/corlib/corert/RuntimeThread.cs @@ -1,14 +1,37 @@ +using System; +using System.Threading; + namespace Internal.Runtime.Augments { class RuntimeThread { - public static RuntimeThread InitializeThreadPoolThread () + readonly Thread thread; + + RuntimeThread (Thread t) { thread = t; } + + public void ResetThreadPoolThread () {} + + public static RuntimeThread InitializeThreadPoolThread () => default; + + public static RuntimeThread Create (ParameterizedThreadStart start, int maxStackSize) + => new RuntimeThread (new Thread (start, maxStackSize)); + + public bool IsBackground { - return default; + get => thread.IsBackground; + set => thread.IsBackground = value; } - public void ResetThreadPoolThread () + public void Start () => thread.Start (); + + public void Start (object state) => thread.Start (state); + + public static bool Yield () => Thread.Yield (); + + public static bool SpinWait (int iterations) { + Thread.SpinWait (iterations); + return true; } } } \ No newline at end of file diff --git a/mcs/class/corlib/corert/Task.cs b/mcs/class/corlib/corert/Task.cs new file mode 100644 index 0000000000..61f0a1407d --- /dev/null +++ b/mcs/class/corlib/corert/Task.cs @@ -0,0 +1,87 @@ +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Diagnostics.Contracts; +using System.Security; +using System.Security.Permissions; + +namespace System.Threading.Tasks +{ + // these members were copied from https://github.com/mono/mono/blob/7b4dfeebc40cf8c027819b8b7bd85a4e7c87ad50/mcs/class/referencesource/mscorlib/system/threading/Tasks/Task.cs#L220-L246 + partial class Task + { + // This dictonary relates the task id, from an operation id located in the Async Causality log to the actual + // task. This is to be used by the debugger ONLY. Task in this dictionary represent current active tasks. + private static readonly Dictionary s_currentActiveTasks = new Dictionary (); + private static readonly Object s_activeTasksLock = new Object (); + + // These methods are a way to access the dictionary both from this class and for other classes that also + // activate dummy tasks. Specifically the AsyncTaskMethodBuilder and AsyncTaskMethodBuilder<> + [FriendAccessAllowed] + internal static bool AddToActiveTasks (Task task) + { + Contract.Requires (task != null, "Null Task objects can't be added to the ActiveTasks collection"); + lock (s_activeTasksLock) + { + s_currentActiveTasks[task.Id] = task; + } + //always return true to keep signature as bool for backwards compatibility + return true; + } + + [FriendAccessAllowed] + internal static void RemoveFromActiveTasks (int taskId) + { + lock (s_activeTasksLock) + { + s_currentActiveTasks.Remove (taskId); + } + } + + public void MarkAborted (ThreadAbortException e) {} + + // Copied from reference-sources + [SecurityCritical] + void ExecuteWithThreadLocal (ref Task currentTaskSlot) + { + // Remember the current task so we can restore it after running, and then + Task previousTask = currentTaskSlot; + try + { + // place the current task into TLS. + currentTaskSlot = this; + + ExecutionContext ec = CapturedContext; + if (ec == null) + { + // No context, just run the task directly. + Execute (); + } + else + { + // Run the task. We need a simple shim that converts the + // object back into a Task object, so that we can Execute it. + + // Lazily initialize the callback delegate; benign ---- + var callback = s_ecCallback; + if (callback == null) s_ecCallback = callback = new ContextCallback (ExecutionContextCallback); +#if PFX_LEGACY_3_5 + ExecutionContext.Run (ec, callback, this); +#else + ExecutionContext.Run (ec, callback, this, true); +#endif + } + + if (AsyncCausalityTracer.LoggingOn) + AsyncCausalityTracer.TraceSynchronousWorkCompletion (CausalityTraceLevel.Required, CausalitySynchronousWork.Execution); + + Finish (true); + } + finally + { + currentTaskSlot = previousTask; + } + } + } +} \ No newline at end of file diff --git a/mcs/class/corlib/corert/ThreadPool.cs b/mcs/class/corlib/corert/ThreadPool.cs new file mode 100644 index 0000000000..23fd6c065d --- /dev/null +++ b/mcs/class/corlib/corert/ThreadPool.cs @@ -0,0 +1,7 @@ +namespace System.Threading +{ + partial class ThreadPool + { + internal static bool IsThreadPoolThread => Thread.CurrentThread.IsThreadPoolThread; + } +} \ No newline at end of file diff --git a/mcs/class/corlib/corlib.dll.sources b/mcs/class/corlib/corlib.dll.sources index 43aae4cb05..096a3b395b 100644 --- a/mcs/class/corlib/corlib.dll.sources +++ b/mcs/class/corlib/corlib.dll.sources @@ -267,6 +267,7 @@ System.Reflection.Emit/CustomAttributeBuilder.cs System.Reflection.Emit/DerivedTypes.cs System.Reflection.Emit/DynamicILInfo.cs System.Reflection.Emit/DynamicMethod.cs +System.Reflection.Emit/DynamicMethod.notsupported.cs System.Reflection.Emit/EnumBuilder.cs System.Reflection.Emit/EventBuilder.cs System.Reflection.Emit/EventOnTypeBuilderInst.cs @@ -703,9 +704,9 @@ System.Security.Cryptography.X509Certificates/X509Certificate.cs System.Security.Cryptography.X509Certificates/X509Certificate20.cs System.Security.Cryptography.X509Certificates/X509CertificateImpl.cs System.Security.Cryptography.X509Certificates/X509CertificateImplMono.cs -../../../external/corefx/src/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/X509ContentType.cs System.Security.Cryptography.X509Certificates/X509Helper.cs -../../../external/corefx/src/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/X509KeyStorageFlags.cs +System.Security.Cryptography.X509Certificates/X509CertificateImplApple.cs +System.Security.Cryptography.X509Certificates/X509Helper.Apple.cs System.Security.Permissions/CodeAccessSecurityAttribute.cs System.Security.Permissions/EnvironmentPermission.cs System.Security.Permissions/EnvironmentPermissionAccess.cs @@ -852,6 +853,8 @@ System.Threading/WaitHandle.cs System.Threading.Tasks/DecoupledTask.cs ../Mono.Parallel/Mono.Threading/AtomicBoolean.cs +CoreFoundation/CFHelpers.cs + ReferenceSources/__ConsoleStream.cs ReferenceSources/Array.cs ReferenceSources/BCLDebug.cs @@ -1006,7 +1009,6 @@ ReferenceSources/Type.cs ../referencesource/mscorlib/system/sharedstatics.cs ../referencesource/mscorlib/system/stackoverflowexception.cs ../referencesource/mscorlib/system/single.cs -../referencesource/mscorlib/system/string.cs ../referencesource/mscorlib/system/stringcomparer.cs ../referencesource/mscorlib/system/stringfreezingattribute.cs ../referencesource/mscorlib/system/systemexception.cs @@ -1037,54 +1039,39 @@ ReferenceSources/Type.cs ../referencesource/mscorlib/system/AppContext/AppContextSwitches.cs ReferenceSources/AppContextDefaultValues.cs -../referencesource/mscorlib/system/collections/arraylist.cs -../referencesource/mscorlib/system/collections/bitarray.cs -../referencesource/mscorlib/system/collections/caseinsensitivecomparer.cs -../referencesource/mscorlib/system/collections/caseinsensitivehashcodeprovider.cs -../referencesource/mscorlib/system/collections/collectionbase.cs -../referencesource/mscorlib/system/collections/comparer.cs -../referencesource/mscorlib/system/collections/compatiblecomparer.cs -../referencesource/mscorlib/system/collections/dictionarybase.cs -../referencesource/mscorlib/system/collections/emptyreadonlydictionaryinternal.cs -../referencesource/mscorlib/system/collections/hashtable.cs -../referencesource/mscorlib/system/collections/icollection.cs -../referencesource/mscorlib/system/collections/icomparer.cs -../referencesource/mscorlib/system/collections/idictionary.cs -../referencesource/mscorlib/system/collections/idictionaryenumerator.cs -../referencesource/mscorlib/system/collections/ienumerable.cs -../referencesource/mscorlib/system/collections/ienumerator.cs -../referencesource/mscorlib/system/collections/iequalitycomparer.cs -../referencesource/mscorlib/system/collections/ihashcodeprovider.cs -../referencesource/mscorlib/system/collections/ilist.cs -../referencesource/mscorlib/system/collections/istructuralcomparable.cs -../referencesource/mscorlib/system/collections/istructuralequatable.cs -../referencesource/mscorlib/system/collections/keyvaluepairs.cs -../referencesource/mscorlib/system/collections/listdictionaryinternal.cs -../referencesource/mscorlib/system/collections/objectmodel/collection.cs -../referencesource/mscorlib/system/collections/objectmodel/keyedcollection.cs -../referencesource/mscorlib/system/collections/objectmodel/readonlycollection.cs -../referencesource/mscorlib/system/collections/objectmodel/readonlydictionary.cs -../referencesource/mscorlib/system/collections/queue.cs -../referencesource/mscorlib/system/collections/readonlycollectionbase.cs -../referencesource/mscorlib/system/collections/sortedlist.cs -../referencesource/mscorlib/system/collections/stack.cs -../referencesource/mscorlib/system/collections/structuralcomparisons.cs - +../../../external/corefx/src/System.Runtime.Extensions/src/System/Collections/ArrayList.cs +../../../external/corefx/src/System.Collections.NonGeneric/src/System/Collections/*.cs +../../../external/corefx/src/System.Collections/src/System/Collections/BitArray.cs +../../../external/corefx/src/System.Collections/src/System/Collections/StructuralComparisons.cs +../../../external/corefx/src/Common/src/CoreLib/System/Collections/Comparer.cs +../../../external/corefx/src/Common/src/CoreLib/System/Collections/DictionaryEntry.cs +../../../external/corefx/src/Common/src/CoreLib/System/Collections/ICollection.cs +../../../external/corefx/src/Common/src/CoreLib/System/Collections/IComparer.cs +../../../external/corefx/src/Common/src/CoreLib/System/Collections/IDictionary.cs +../../../external/corefx/src/Common/src/CoreLib/System/Collections/IDictionaryEnumerator.cs +../../../external/corefx/src/Common/src/CoreLib/System/Collections/IEnumerable.cs +../../../external/corefx/src/Common/src/CoreLib/System/Collections/IEnumerator.cs +../../../external/corefx/src/Common/src/CoreLib/System/Collections/IEqualityComparer.cs +../../../external/corefx/src/Common/src/CoreLib/System/Collections/IList.cs +../../../external/corefx/src/Common/src/CoreLib/System/Collections/IStructuralComparable.cs +../../../external/corefx/src/Common/src/CoreLib/System/Collections/IStructuralEquatable.cs +../../../external/corefx/src/Common/src/CoreLib/System/Collections/ListDictionaryInternal.cs +../../../external/corefx/src/Common/src/CoreLib/System/Collections/Generic/*.cs +../../../external/corefx/src/Common/src/CoreLib/System/Collections/ObjectModel/Collection.cs +../../../external/corefx/src/Common/src/CoreLib/System/Collections/ObjectModel/ReadOnlyCollection.cs +../../../external/corefx/src/Common/src/CoreLib/System/Collections/DictionaryEntry.cs +../../../external/corefx/src/Common/src/CoreLib/System/Collections/Generic/Dictionary.cs +../../../external/corefx/src/Common/src/CoreLib/System/Collections/Generic/IDictionaryDebugView.cs +../../../external/corefx/src/Common/src/CoreLib/System/Collections/Generic/KeyValuePair.cs +../../../external/corefx/src/Common/src/System/Collections/CompatibleComparer.cs +../../../external/corefx/src/System.Runtime.Extensions/src/System/Collections/Hashtable.cs +../../../external/corefx/src/System.Runtime.Extensions/src/System/Collections/IHashCodeProvider.cs +../../../external/corefx/src/System.ObjectModel/src/System/Collections/Generic/DebugView.cs +../../../external/corefx/src/System.ObjectModel/src/System/Collections/ObjectModel/KeyedCollection.cs +../../../external/corefx/src/System.ObjectModel/src/System/Collections/ObjectModel/ReadOnlyDictionary.cs ../referencesource/mscorlib/system/collections/generic/comparer.cs -../referencesource/mscorlib/system/collections/generic/debugview.cs ../referencesource/mscorlib/system/collections/generic/equalitycomparer.cs -../referencesource/mscorlib/system/collections/generic/icollection.cs -../referencesource/mscorlib/system/collections/generic/icomparer.cs -../referencesource/mscorlib/system/collections/generic/idictionary.cs -../referencesource/mscorlib/system/collections/generic/ienumerable.cs -../referencesource/mscorlib/system/collections/generic/ienumerator.cs -../referencesource/mscorlib/system/collections/generic/iequalitycomparer.cs -../referencesource/mscorlib/system/collections/generic/ilist.cs -../referencesource/mscorlib/system/collections/generic/ireadonlycollection.cs -../referencesource/mscorlib/system/collections/generic/ireadonlydictionary.cs -../referencesource/mscorlib/system/collections/generic/ireadonlylist.cs -../referencesource/mscorlib/system/collections/generic/keynotfoundexception.cs -../referencesource/mscorlib/system/collections/generic/list.cs +../referencesource/mscorlib/system/collections/emptyreadonlydictionaryinternal.cs ../referencesource/mscorlib/system/diagnostics/assert.cs ../referencesource/mscorlib/system/diagnostics/assertfilter.cs @@ -1112,7 +1099,7 @@ ReferenceSources/AppContextDefaultValues.cs ../referencesource/mscorlib/system/globalization/calendarweekrule.cs ../referencesource/mscorlib/system/globalization/charunicodeinfo.cs ../referencesource/mscorlib/system/globalization/chineselunisolarcalendar.cs -../referencesource/mscorlib/system/globalization/compareinfo.cs +#../referencesource/mscorlib/system/globalization/compareinfo.cs ../referencesource/mscorlib/system/globalization/culturenotfoundexception.cs ../referencesource/mscorlib/system/globalization/culturetypes.cs ../referencesource/mscorlib/system/globalization/daylighttime.cs @@ -1184,7 +1171,7 @@ ReferenceSources/AppContextDefaultValues.cs ../referencesource/mscorlib/system/reflection/assemblynameflags.cs ../referencesource/mscorlib/system/reflection/assemblynameproxy.cs ../referencesource/mscorlib/system/reflection/binder.cs -../referencesource/mscorlib/system/reflection/bindingflags.cs +../../../external/corefx/src/Common/src/CoreLib/System/Reflection/BindingFlags.cs ../referencesource/mscorlib/system/reflection/callingconventions.cs ../referencesource/mscorlib/system/reflection/CustomAttributeExtensions.cs ../referencesource/mscorlib/system/reflection/defaultmemberattribute.cs @@ -1252,6 +1239,7 @@ ReferenceSources/AppContextDefaultValues.cs ../referencesource/mscorlib/system/resources/ultimateresourcefallbacklocation.cs ../referencesource/mscorlib/system/runtime/NgenServicingAttributes.cs +../referencesource/mscorlib/system/runtime/ProfileOptimization.cs ../referencesource/mscorlib/system/runtime/exceptionservices/corruptingexceptioncommon.cs ../referencesource/mscorlib/system/runtime/exceptionservices/exceptionnotification.cs @@ -1325,38 +1313,38 @@ ReferenceSources/AppContextDefaultValues.cs ../referencesource/mscorlib//system/runtime/reliability/prepreparemethodattribute.cs ../referencesource/mscorlib//system/runtime/reliability/reliabilitycontractattribute.cs -../referencesource/mscorlib/system/runtime/compilerservices/accessedthroughpropertyattribute.cs +../../../external/corefx/src/Common/src/CoreLib/System/Runtime/CompilerServices/AccessedThroughPropertyAttribute.cs ../referencesource/mscorlib/system/runtime/compilerservices/assemblyattributesgohere.cs ../referencesource/mscorlib/system/runtime/compilerservices/assemblysettingattributes.cs +../../../external/corefx/src/Common/src/CoreLib/System/Runtime/CompilerServices/AsyncStateMachineAttribute.cs +../../../external/corefx/src/Common/src/CoreLib/System/Runtime/CompilerServices/CallerFilePathAttribute.cs +../../../external/corefx/src/Common/src/CoreLib/System/Runtime/CompilerServices/CallerLineNumberAttribute.cs +../../../external/corefx/src/Common/src/CoreLib/System/Runtime/CompilerServices/CallerMemberNameAttribute.cs ../referencesource/mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs -../referencesource/mscorlib/system/runtime/compilerservices/AsyncStateMachineAttribute.cs -../referencesource/mscorlib/system/runtime/compilerservices/CallerFilePathAttribute.cs -../referencesource/mscorlib/system/runtime/compilerservices/CallerLineNumberAttribute.cs -../referencesource/mscorlib/system/runtime/compilerservices/CallerMemberNameAttribute.cs ../referencesource/mscorlib/system/runtime/compilerservices/callingconvention.cs +../../../external/corefx/src/Common/src/CoreLib/System/Runtime/CompilerServices/CompilerGeneratedAttribute.cs +../../../external/corefx/src/Common/src/CoreLib/System/Runtime/CompilerServices/CompilerGlobalScopeAttribute.cs ../referencesource/mscorlib/system/runtime/compilerservices/compilationrelaxations.cs -../referencesource/mscorlib/system/runtime/compilerservices/compilergeneratedattribute.cs -../referencesource/mscorlib/system/runtime/compilerservices/compilerglobalscopeattribute.cs ../referencesource/mscorlib/system/runtime/compilerservices/compilermarshaloverride.cs -../referencesource/mscorlib/system/runtime/compilerservices/customconstantattribute.cs -../referencesource/mscorlib/system/runtime/compilerservices/datetimeconstantattribute.cs -../referencesource/mscorlib/system/runtime/compilerservices/decimalconstantattribute.cs +../../../external/corefx/src/Common/src/CoreLib/System/Runtime/CompilerServices/CustomConstantAttribute.cs +../../../external/corefx/src/Common/src/CoreLib/System/Runtime/CompilerServices/DateTimeConstantAttribute.cs +../../../external/corefx/src/Common/src/CoreLib/System/Runtime/CompilerServices/DecimalConstantAttribute.cs ../referencesource/mscorlib/system/runtime/compilerservices/decoratednameattribute.cs -../referencesource/mscorlib/system/runtime/compilerservices/disableprivatereflectionattribute.cs -../referencesource/mscorlib/system/runtime/compilerservices/discardableattribute.cs -../referencesource/mscorlib/system/runtime/compilerservices/extensionattribute.cs -../referencesource/mscorlib/system/runtime/compilerservices/fixedaddressvaluetypeattribute.cs -../referencesource/mscorlib/system/runtime/compilerservices/fixedbufferattribute.cs -../referencesource/mscorlib/system/runtime/compilerservices/FormattableStringFactory.cs +../../../external/corefx/src/Common/src/CoreLib/System/Runtime/CompilerServices/DisablePrivateReflectionAttribute.cs +../../../external/corefx/src/Common/src/CoreLib/System/Runtime/CompilerServices/DiscardableAttribute.cs +../../../external/corefx/src/Common/src/CoreLib/System/Runtime/CompilerServices/ExtensionAttribute.cs +../../../external/corefx/src/Common/src/CoreLib/System/Runtime/CompilerServices/FixedAddressValueTypeAttribute.cs +../../../external/corefx/src/Common/src/CoreLib/System/Runtime/CompilerServices/FixedBufferAttribute.cs +../../../external/corefx/src/Common/src/CoreLib/System/Runtime/CompilerServices/FormattableStringFactory.cs ../referencesource/mscorlib/system/runtime/compilerservices/hascopysemanticsattribute.cs -../referencesource/mscorlib/system/runtime/compilerservices/IAsyncStateMachine.cs +../../../external/corefx/src/Common/src/CoreLib/System/Runtime/CompilerServices/IAsyncStateMachine.cs ../referencesource/mscorlib/system/runtime/compilerservices/idispatchconstantattribute.cs -../referencesource/mscorlib/system/runtime/compilerservices/indexernameattribute.cs -../referencesource/mscorlib/system/runtime/compilerservices/INotifyCompletion.cs ../referencesource/mscorlib/system/runtime/compilerservices/internalsvisibletoattribute.cs +../../../external/corefx/src/Common/src/CoreLib/System/Runtime/CompilerServices/IndexerNameAttribute.cs +../../../external/corefx/src/Common/src/CoreLib/System/Runtime/CompilerServices/INotifyCompletion.cs ../referencesource/mscorlib/system/runtime/compilerservices/isboxed.cs ../referencesource/mscorlib/system/runtime/compilerservices/isbyvalue.cs -../referencesource/mscorlib/system/runtime/compilerservices/isconst.cs +../../../external/corefx/src/Common/src/CoreLib/System/Runtime/CompilerServices/IsConst.cs ../referencesource/mscorlib/system/runtime/compilerservices/iscopyconstructed.cs ../referencesource/mscorlib/system/runtime/compilerservices/isexplicitlydereferenced.cs ../referencesource/mscorlib/system/runtime/compilerservices/isimplicitlydereferenced.cs @@ -1365,25 +1353,26 @@ ReferenceSources/AppContextDefaultValues.cs ../referencesource/mscorlib/system/runtime/compilerservices/ispinned.cs ../referencesource/mscorlib/system/runtime/compilerservices/issignunspecifiedbyte.cs ../referencesource/mscorlib/system/runtime/compilerservices/isudtreturn.cs -../referencesource/mscorlib/system/runtime/compilerservices/isvolatile.cs -../referencesource/mscorlib/system/runtime/compilerservices/IteratorStateMachineAttribute.cs +../../../external/corefx/src/Common/src/CoreLib/System/Runtime/CompilerServices/IsVolatile.cs +../../../external/corefx/src/Common/src/CoreLib/System/Runtime/CompilerServices/IteratorStateMachineAttribute.cs ../referencesource/mscorlib/system/runtime/compilerservices/iunknownconstantattribute.cs ../referencesource/mscorlib/system/runtime/compilerservices/methodimplattribute.cs ../referencesource/mscorlib/system/runtime/compilerservices/nativecppclassattribute.cs -../referencesource/mscorlib/system/runtime/compilerservices/ReferenceAssemblyAttribute.cs +../../../external/corefx/src/Common/src/CoreLib/System/HResults.cs +../../../external/corefx/src/Common/src/CoreLib/System/Runtime/CompilerServices/ReferenceAssemblyAttribute.cs ../referencesource/mscorlib/system/runtime/compilerservices/requiredattributeattribute.cs -../referencesource/mscorlib/system/runtime/compilerservices/RuntimeCompatibilityAttribute.cs -../referencesource/mscorlib/system/runtime/compilerservices/RuntimeWrappedException.cs +../../../external/corefx/src/Common/src/CoreLib/System/Runtime/CompilerServices/RuntimeCompatibilityAttribute.cs +../../../external/corefx/src/Common/src/CoreLib/System/Runtime/CompilerServices/RuntimeWrappedException.cs ../referencesource/mscorlib/system/runtime/compilerservices/scopelessenumattribute.cs -../referencesource/mscorlib/system/runtime/compilerservices/specialnameattribute.cs -../referencesource/mscorlib/system/runtime/compilerservices/StateMachineAttribute.cs -../referencesource/mscorlib/system/runtime/compilerservices/suppressildasmattribute.cs +../../../external/corefx/src/Common/src/CoreLib/System/Runtime/CompilerServices/SpecialNameAttribute.cs +../../../external/corefx/src/Common/src/CoreLib/System/Runtime/CompilerServices/StateMachineAttribute.cs +../../../external/corefx/src/Common/src/CoreLib/System/Runtime/CompilerServices/SuppressIldasmAttribute.cs ../referencesource/mscorlib/system/runtime/compilerservices/suppressmergecheckattribute.cs -../referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs +../../../external/corert/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/TaskAwaiter.cs ../referencesource/mscorlib/system/runtime/compilerservices/typedependencyattribute.cs -../referencesource/mscorlib/system/runtime/compilerservices/TypeForwardedFromAttribute.cs -../referencesource/mscorlib/system/runtime/compilerservices/TypeForwardedToAttribute.cs -../referencesource/mscorlib/system/runtime/compilerservices/unsafevaluetypeattribute.cs +../../../external/corefx/src/Common/src/CoreLib/System/Runtime/CompilerServices/TypeForwardedFromAttribute.cs +../../../external/corefx/src/Common/src/CoreLib/System/Runtime/CompilerServices/TypeForwardedToAttribute.cs +../../../external/corefx/src/Common/src/CoreLib/System/Runtime/CompilerServices/UnsafeValueTypeAttribute.cs ../referencesource/mscorlib/system/runtime/compilerservices/YieldAwaitable.cs ../referencesource/mscorlib/system/security/attributes.cs @@ -1595,20 +1584,7 @@ ReferenceSources/AppContextDefaultValues.cs ../referencesource/mscorlib/system/threading/waithandleExtensions.cs ../referencesource/mscorlib/system/threading/Tasks/AsyncCausalityTracer.cs -../referencesource/mscorlib/system/threading/Tasks/BeginEndAwaitableAdapter.cs -../referencesource/mscorlib/system/threading/Tasks/TaskFactory.cs -../referencesource/mscorlib/system/threading/Tasks/FutureFactory.cs -../referencesource/mscorlib/system/threading/Tasks/TaskScheduler.cs -../referencesource/mscorlib/system/threading/Tasks/TaskCanceledException.cs -../referencesource/mscorlib/system/threading/Tasks/Task.cs -../referencesource/mscorlib/system/threading/Tasks/Future.cs -../referencesource/mscorlib/system/threading/Tasks/TaskCompletionSource.cs -../referencesource/mscorlib/system/threading/Tasks/TaskContinuation.cs -../referencesource/mscorlib/system/threading/Tasks/TaskSchedulerException.cs -../referencesource/mscorlib/system/threading/Tasks/Parallel.cs -../referencesource/mscorlib/system/threading/Tasks/ParallelLoopState.cs -../referencesource/mscorlib/system/threading/Tasks/ParallelRangeManager.cs -../referencesource/mscorlib/system/threading/Tasks/ThreadPoolTaskScheduler.cs + ../referencesource/mscorlib/system/threading/Tasks/TaskExceptionHolder.cs ../referencesource/mscorlib/system/threading/Tasks/ConcurrentExclusiveSchedulerPair.cs ../referencesource/mscorlib/system/threading/Tasks/ProducerConsumerQueues.cs @@ -1622,6 +1598,10 @@ ReferenceSources/AppContextDefaultValues.cs coreclr/SorterArray.cs +corefx/AwaitTaskContinuation.cs +corefx/SynchronizationContext.cs + +corert/DependencyReductionRootAttribute.cs corert/AddrofIntrinsics.cs corert/Debug.cs corert/EnvironmentAugments.cs @@ -1629,31 +1609,66 @@ corert/RelocatedTypeAttribute.cs corert/RuntimeThread.cs corert/Stream.cs corert/ThreadPoolBoundHandle.cs +corert/Task.cs +corert/ThreadPool.cs +corert/RuntimeAugments.cs ../../../external/corert/src/Common/src/Interop/Unix/Interop.Libraries.cs +../../../external/corert/src/Common/src/System/Collections/Generic/LowLevelList.cs + ../../../external/corert/src/Common/src/System/Numerics/Hashing/HashHelpers.cs ../../../external/corert/src/Runtime.Base/src/System/Runtime/InteropServices/NativeCallableAttribute.cs +../../../external/corert/src/System.Private.CoreLib/shared/System/String.Manipulation.cs +../../../external/corert/src/System.Private.CoreLib/shared/System/StringSpanHelpers.cs +../../../external/corert/src/System.Private.CoreLib/shared/System/Collections/Generic/ValueListBuilder.cs ../../../external/corert/src/System.Private.CoreLib/shared/System/Diagnostics/Debug.cs -../../../external/corert/src/System.Private.CoreLib/shared/System/Diagnostics/StackTraceHiddenAttribute.cs - ../../../external/corert/src/System.Private.CoreLib/shared/System/Threading/DeferredDisposableLifetime.cs -../../../external/corert/src/System.Private.CoreLib/src/System/Array.cs +../../../external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/AsyncCausalityTracer.cs +../../../external/corert/src/System.Private.CoreLib/src/Internal/Runtime/Augments/TaskTraceCallbacks.cs -../../../external/corert/src/System.Private.CoreLib/src/System/Collections/LowLevelComparer.cs +../../../external/corert/src/System.Private.CoreLib/src/System/Array.cs +# TODO: Should all come from shared +../../../external/corert/src/System.Private.CoreLib/src/System/String.cs +../../../external/corert/src/System.Private.CoreLib/src/System/String.Comparison.cs ../../../external/corert/src/System.Private.CoreLib/src/System/Collections/Generic/ArraySortHelper.cs +../../../external/corert/src/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.cs + +../../../external/corert/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/ReflectionBlockedAttribute.cs + +../../../external/corert/src/System.Private.CoreLib/src/System/Threading/LockHolder.cs + ../../../external/corert/src/System.Private.CoreLib/src/System/Threading/ThreadPoolCallbackWrapper.cs +../../../external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/DebuggerSupport.cs +../../../external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/DebuggerSupport.Dummy.cs +../../../external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/TaskFactory.cs +../../../external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/FutureFactory.cs +../../../external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/TaskScheduler.cs +../../../external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs +../../../external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/Future.cs +../../../external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/TaskContinuation.cs +../../../external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/ThreadPoolTaskScheduler.cs + +../../../external/corert/src/System.Private.CoreLib/src/Internal/Threading/Tasks/Tracing/TaskTrace.cs + +../../../external/corert/src/System.Private.Interop/src/InteropExtensions/Lock.cs + corefx/SR.cs +corefx/CompareInfo.cs +corefx/GlobalizationMode.cs +corefx/MemoryExtensions.cs ../../../external/corefx/src/Common/src/CoreLib/System/Memory.cs ../../../external/corefx/src/Common/src/CoreLib/System/MemoryDebugView.cs ../../../external/corefx/src/Common/src/CoreLib/System/ReadOnlyMemory.cs +../../../external/corefx/src/Common/src/CoreLib/System/String.Searching.cs +../../../external/corefx/src/Common/src/CoreLib/System/StringSplitOptions.cs ../../../external/corefx/src/Common/src/CoreLib/System/Tuple.cs ../../../external/corefx/src/Common/src/CoreLib/System/TupleExtensions.cs ../../../external/corefx/src/Common/src/CoreLib/System/ValueTuple.cs @@ -1662,10 +1677,11 @@ corefx/SR.cs ../../../external/corefx/src/Common/src/CoreLib/System/Buffers/MemoryHandle.cs ../../../external/corefx/src/Common/src/CoreLib/System/Buffers/OwnedMemory.cs -../../../external/corefx/src/Common/src/CoreLib/System/Collections/DictionaryEntry.cs -../../../external/corefx/src/Common/src/CoreLib/System/Collections/Generic/Dictionary.cs -../../../external/corefx/src/Common/src/CoreLib/System/Collections/Generic/IDictionaryDebugView.cs -../../../external/corefx/src/Common/src/CoreLib/System/Collections/Generic/KeyValuePair.cs + +../../../external/corefx/src/Common/src/CoreLib/System/Diagnostics/StackTraceHiddenAttribute.cs + +../../../external/corefx/src/Common/src/CoreLib/System/Globalization/CompareInfo.cs +../../../external/corefx/src/Common/src/CoreLib/System/Globalization/CompareInfo.Invariant.cs ../../../external/corefx/src/Common/src/CoreLib/System/Runtime/CompilerServices/IntrinsicAttribute.cs ../../../external/corefx/src/Common/src/CoreLib/System/Runtime/CompilerServices/IsReadOnlyAttribute.cs @@ -1676,8 +1692,22 @@ corefx/SR.cs ../../../external/corefx/src/Common/src/CoreLib/System/Runtime/InteropServices/MemoryMarshal.cs +../../../external/corefx/src/Common/src/CoreLib/System/Threading/Tasks/TaskCanceledException.cs +../../../external/corefx/src/Common/src/CoreLib/System/Threading/Tasks/TaskCompletionSource.cs +../../../external/corefx/src/Common/src/CoreLib/System/Threading/Tasks/TaskSchedulerException.cs + +../../../external/corefx/src/Common/src/System/Collections/Generic/LowLevelDictionary.cs ../../../external/corefx/src/Common/src/System/Collections/Generic/ReferenceEqualityComparer.cs +../../../external/corefx/src/Common/src/System/Threading/Tasks/BeginEndAwaitableAdapter.cs +../../../external/corefx/src/Common/src/System/Threading/Tasks/RendezvousAwaitable.cs + +../../../external/corefx/src/System.Buffers/src/System/Buffers/ArrayPool.cs +../../../external/corefx/src/System.Buffers/src/System/Buffers/ArrayPoolEventSource.cs +../../../external/corefx/src/System.Buffers/src/System/Buffers/DefaultArrayPool.cs +../../../external/corefx/src/System.Buffers/src/System/Buffers/DefaultArrayPoolBucket.cs +../../../external/corefx/src/System.Buffers/src/System/Buffers/Utilities.cs + ../../../external/corefx/src/System.Collections/src/System/Collections/Generic/CollectionExtensions.cs ../../../external/corefx/src/System.Collections.Concurrent/src/System/Collections/Concurrent/CDSCollectionETWBCLProvider.cs @@ -1707,9 +1737,12 @@ corefx/SR.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 +../../../external/corefx/src/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/X509ContentType.cs +../../../external/corefx/src/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/X509KeyStorageFlags.cs + ../../../external/corefx/src/System.Threading.Tasks.Extensions/src/System/Threading/Tasks/ValueTask.cs ../../../external/corefx/src/System.Threading.Tasks.Extensions/src/System/Runtime/CompilerServices/*.cs -System.Security.Cryptography.X509Certificates/X509CertificateImplApple.cs -System.Security.Cryptography.X509Certificates/X509Helper.Apple.cs -CoreFoundation/CFHelpers.cs +../../../external/corefx/src/System.Threading.Tasks.Parallel/src/System/Threading/Tasks/*.cs + +../../../external/corefx/src/System.Runtime.Extensions/src/System/Globalization/Extensions.cs diff --git a/mcs/class/corlib/corlib_test.dll.sources b/mcs/class/corlib/corlib_test.dll.sources index 507c39c4a7..aca4e90237 100644 --- a/mcs/class/corlib/corlib_test.dll.sources +++ b/mcs/class/corlib/corlib_test.dll.sources @@ -220,6 +220,7 @@ System.Runtime.InteropServices/StructLayoutAttributeTest.cs System.Runtime.Remoting/ContextTest.cs System.Runtime.Remoting/SoapServicesTest.cs System.Runtime.Remoting/SynchronizationAttributeTest.cs +System.Runtime.Remoting/RemotingServicesTest.cs System.Runtime.Remoting.Channels/ChannelServicesTest.cs System.Runtime.Remoting.Contexts/SynchronizationAttributeTest.cs System.Runtime.Remoting.Messaging/CallContextTest.cs @@ -544,3 +545,4 @@ System.Threading/ThreadLocalTests.cs System.Threading/SpinLockTests.cs ../../../../mono/mini/TestHelpers.cs ../../test-helpers/NunitHelpers.cs +System.Threading/ThreadPrincipalTests.cs diff --git a/mcs/class/lib/monolite-darwin/1051200002/Facades/System.Security.Cryptography.Algorithms.dll b/mcs/class/lib/monolite-darwin/1051200002/Facades/System.Security.Cryptography.Algorithms.dll deleted file mode 100644 index b3c7b85964..0000000000 Binary files a/mcs/class/lib/monolite-darwin/1051200002/Facades/System.Security.Cryptography.Algorithms.dll and /dev/null differ diff --git a/mcs/class/lib/monolite-darwin/1051200002/Mono.Security.dll.REMOVED.git-id b/mcs/class/lib/monolite-darwin/1051200002/Mono.Security.dll.REMOVED.git-id deleted file mode 100644 index 81aa843377..0000000000 --- a/mcs/class/lib/monolite-darwin/1051200002/Mono.Security.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -58e3afff30e9696cf624f871df55a0a07aac1134 \ No newline at end of file diff --git a/mcs/class/lib/monolite-darwin/1051200002/System.Configuration.dll.REMOVED.git-id b/mcs/class/lib/monolite-darwin/1051200002/System.Configuration.dll.REMOVED.git-id deleted file mode 100644 index c2422cc1d4..0000000000 --- a/mcs/class/lib/monolite-darwin/1051200002/System.Configuration.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -938c6b0afec364e19bd901d7f331d1a8600943d8 \ No newline at end of file diff --git a/mcs/class/lib/monolite-darwin/1051200002/System.Core.dll.REMOVED.git-id b/mcs/class/lib/monolite-darwin/1051200002/System.Core.dll.REMOVED.git-id deleted file mode 100644 index b85e324e6f..0000000000 --- a/mcs/class/lib/monolite-darwin/1051200002/System.Core.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -939005727764598d30ed961d7c64417144ed5273 \ No newline at end of file diff --git a/mcs/class/lib/monolite-darwin/1051200002/System.Numerics.dll.REMOVED.git-id b/mcs/class/lib/monolite-darwin/1051200002/System.Numerics.dll.REMOVED.git-id deleted file mode 100644 index 44729fc55d..0000000000 --- a/mcs/class/lib/monolite-darwin/1051200002/System.Numerics.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -fe58dbd6ced95901c047720893fed58b36f36eed \ No newline at end of file diff --git a/mcs/class/lib/monolite-darwin/1051200002/System.Security.dll.REMOVED.git-id b/mcs/class/lib/monolite-darwin/1051200002/System.Security.dll.REMOVED.git-id deleted file mode 100644 index de81787346..0000000000 --- a/mcs/class/lib/monolite-darwin/1051200002/System.Security.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -bd87e3386b025eec758cc37e9cbfa8800c5e0c4c \ No newline at end of file diff --git a/mcs/class/lib/monolite-darwin/1051200002/System.Xml.Linq.dll.REMOVED.git-id b/mcs/class/lib/monolite-darwin/1051200002/System.Xml.Linq.dll.REMOVED.git-id deleted file mode 100644 index 8838d85b5d..0000000000 --- a/mcs/class/lib/monolite-darwin/1051200002/System.Xml.Linq.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -e9329342179f8971d9fd7aa04251dcb17a2a6d9d \ No newline at end of file diff --git a/mcs/class/lib/monolite-darwin/1051200002/System.Xml.dll.REMOVED.git-id b/mcs/class/lib/monolite-darwin/1051200002/System.Xml.dll.REMOVED.git-id deleted file mode 100644 index e6fc2548fc..0000000000 --- a/mcs/class/lib/monolite-darwin/1051200002/System.Xml.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -770d3f5d4a965c6a3fd48e27a848ab233fb8a79f \ No newline at end of file diff --git a/mcs/class/lib/monolite-darwin/1051200002/System.dll.REMOVED.git-id b/mcs/class/lib/monolite-darwin/1051200002/System.dll.REMOVED.git-id deleted file mode 100644 index e362ce1b0d..0000000000 --- a/mcs/class/lib/monolite-darwin/1051200002/System.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -391ab530387c217aea71486f167301bf0e2b871e \ No newline at end of file diff --git a/mcs/class/lib/monolite-darwin/1051200002/mcs.exe.REMOVED.git-id b/mcs/class/lib/monolite-darwin/1051200002/mcs.exe.REMOVED.git-id deleted file mode 100644 index 6930835560..0000000000 --- a/mcs/class/lib/monolite-darwin/1051200002/mcs.exe.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -9d912b3cd815b8f94e4f5e81fef5df0c6d15eba5 \ No newline at end of file diff --git a/mcs/class/lib/monolite-darwin/1051200002/mscorlib.dll.REMOVED.git-id b/mcs/class/lib/monolite-darwin/1051200002/mscorlib.dll.REMOVED.git-id deleted file mode 100644 index 1beeb533cc..0000000000 --- a/mcs/class/lib/monolite-darwin/1051200002/mscorlib.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -71055ca5da1f426f38fd18c6bb4bc137f3391ab4 \ No newline at end of file diff --git a/mcs/class/lib/monolite-darwin/1051200002/Facades/System.Collections.Concurrent.dll b/mcs/class/lib/monolite-darwin/1051400003/Facades/System.Collections.Concurrent.dll similarity index 100% rename from mcs/class/lib/monolite-darwin/1051200002/Facades/System.Collections.Concurrent.dll rename to mcs/class/lib/monolite-darwin/1051400003/Facades/System.Collections.Concurrent.dll diff --git a/mcs/class/lib/monolite-darwin/1051200002/Facades/System.Collections.dll b/mcs/class/lib/monolite-darwin/1051400003/Facades/System.Collections.dll similarity index 52% rename from mcs/class/lib/monolite-darwin/1051200002/Facades/System.Collections.dll rename to mcs/class/lib/monolite-darwin/1051400003/Facades/System.Collections.dll index f05f9c22cb..9dcb3db6b9 100644 Binary files a/mcs/class/lib/monolite-darwin/1051200002/Facades/System.Collections.dll and b/mcs/class/lib/monolite-darwin/1051400003/Facades/System.Collections.dll differ diff --git a/mcs/class/lib/monolite-darwin/1051200002/Facades/System.Diagnostics.Debug.dll b/mcs/class/lib/monolite-darwin/1051400003/Facades/System.Diagnostics.Debug.dll similarity index 100% rename from mcs/class/lib/monolite-darwin/1051200002/Facades/System.Diagnostics.Debug.dll rename to mcs/class/lib/monolite-darwin/1051400003/Facades/System.Diagnostics.Debug.dll diff --git a/mcs/class/lib/monolite-darwin/1051200002/Facades/System.Diagnostics.FileVersionInfo.dll b/mcs/class/lib/monolite-darwin/1051400003/Facades/System.Diagnostics.FileVersionInfo.dll similarity index 100% rename from mcs/class/lib/monolite-darwin/1051200002/Facades/System.Diagnostics.FileVersionInfo.dll rename to mcs/class/lib/monolite-darwin/1051400003/Facades/System.Diagnostics.FileVersionInfo.dll diff --git a/mcs/class/lib/monolite-darwin/1051200002/Facades/System.Diagnostics.Tools.dll b/mcs/class/lib/monolite-darwin/1051400003/Facades/System.Diagnostics.Tools.dll similarity index 100% rename from mcs/class/lib/monolite-darwin/1051200002/Facades/System.Diagnostics.Tools.dll rename to mcs/class/lib/monolite-darwin/1051400003/Facades/System.Diagnostics.Tools.dll diff --git a/mcs/class/lib/monolite-darwin/1051200002/Facades/System.Dynamic.Runtime.dll b/mcs/class/lib/monolite-darwin/1051400003/Facades/System.Dynamic.Runtime.dll similarity index 100% rename from mcs/class/lib/monolite-darwin/1051200002/Facades/System.Dynamic.Runtime.dll rename to mcs/class/lib/monolite-darwin/1051400003/Facades/System.Dynamic.Runtime.dll diff --git a/mcs/class/lib/monolite-darwin/1051200002/Facades/System.Globalization.dll b/mcs/class/lib/monolite-darwin/1051400003/Facades/System.Globalization.dll similarity index 100% rename from mcs/class/lib/monolite-darwin/1051200002/Facades/System.Globalization.dll rename to mcs/class/lib/monolite-darwin/1051400003/Facades/System.Globalization.dll diff --git a/mcs/class/lib/monolite-darwin/1051200002/Facades/System.IO.FileSystem.Primitives.dll b/mcs/class/lib/monolite-darwin/1051400003/Facades/System.IO.FileSystem.Primitives.dll similarity index 100% rename from mcs/class/lib/monolite-darwin/1051200002/Facades/System.IO.FileSystem.Primitives.dll rename to mcs/class/lib/monolite-darwin/1051400003/Facades/System.IO.FileSystem.Primitives.dll diff --git a/mcs/class/lib/monolite-darwin/1051200002/Facades/System.IO.FileSystem.dll b/mcs/class/lib/monolite-darwin/1051400003/Facades/System.IO.FileSystem.dll similarity index 100% rename from mcs/class/lib/monolite-darwin/1051200002/Facades/System.IO.FileSystem.dll rename to mcs/class/lib/monolite-darwin/1051400003/Facades/System.IO.FileSystem.dll diff --git a/mcs/class/lib/monolite-darwin/1051200002/Facades/System.IO.dll b/mcs/class/lib/monolite-darwin/1051400003/Facades/System.IO.dll similarity index 100% rename from mcs/class/lib/monolite-darwin/1051200002/Facades/System.IO.dll rename to mcs/class/lib/monolite-darwin/1051400003/Facades/System.IO.dll diff --git a/mcs/class/lib/monolite-darwin/1051200002/Facades/System.Linq.Expressions.dll b/mcs/class/lib/monolite-darwin/1051400003/Facades/System.Linq.Expressions.dll similarity index 100% rename from mcs/class/lib/monolite-darwin/1051200002/Facades/System.Linq.Expressions.dll rename to mcs/class/lib/monolite-darwin/1051400003/Facades/System.Linq.Expressions.dll diff --git a/mcs/class/lib/monolite-darwin/1051200002/Facades/System.Linq.dll b/mcs/class/lib/monolite-darwin/1051400003/Facades/System.Linq.dll similarity index 100% rename from mcs/class/lib/monolite-darwin/1051200002/Facades/System.Linq.dll rename to mcs/class/lib/monolite-darwin/1051400003/Facades/System.Linq.dll diff --git a/mcs/class/lib/monolite-darwin/1051200002/Facades/System.Reflection.Extensions.dll b/mcs/class/lib/monolite-darwin/1051400003/Facades/System.Reflection.Extensions.dll similarity index 100% rename from mcs/class/lib/monolite-darwin/1051200002/Facades/System.Reflection.Extensions.dll rename to mcs/class/lib/monolite-darwin/1051400003/Facades/System.Reflection.Extensions.dll diff --git a/mcs/class/lib/monolite-darwin/1051200002/Facades/System.Reflection.Primitives.dll b/mcs/class/lib/monolite-darwin/1051400003/Facades/System.Reflection.Primitives.dll similarity index 100% rename from mcs/class/lib/monolite-darwin/1051200002/Facades/System.Reflection.Primitives.dll rename to mcs/class/lib/monolite-darwin/1051400003/Facades/System.Reflection.Primitives.dll diff --git a/mcs/class/lib/monolite-darwin/1051200002/Facades/System.Reflection.dll b/mcs/class/lib/monolite-darwin/1051400003/Facades/System.Reflection.dll similarity index 100% rename from mcs/class/lib/monolite-darwin/1051200002/Facades/System.Reflection.dll rename to mcs/class/lib/monolite-darwin/1051400003/Facades/System.Reflection.dll diff --git a/mcs/class/lib/monolite-darwin/1051200002/Facades/System.Resources.ResourceManager.dll b/mcs/class/lib/monolite-darwin/1051400003/Facades/System.Resources.ResourceManager.dll similarity index 100% rename from mcs/class/lib/monolite-darwin/1051200002/Facades/System.Resources.ResourceManager.dll rename to mcs/class/lib/monolite-darwin/1051400003/Facades/System.Resources.ResourceManager.dll diff --git a/mcs/class/lib/monolite-darwin/1051200002/Facades/System.Runtime.Extensions.dll b/mcs/class/lib/monolite-darwin/1051400003/Facades/System.Runtime.Extensions.dll similarity index 100% rename from mcs/class/lib/monolite-darwin/1051200002/Facades/System.Runtime.Extensions.dll rename to mcs/class/lib/monolite-darwin/1051400003/Facades/System.Runtime.Extensions.dll diff --git a/mcs/class/lib/monolite-darwin/1051200002/Facades/System.Runtime.InteropServices.dll b/mcs/class/lib/monolite-darwin/1051400003/Facades/System.Runtime.InteropServices.dll similarity index 100% rename from mcs/class/lib/monolite-darwin/1051200002/Facades/System.Runtime.InteropServices.dll rename to mcs/class/lib/monolite-darwin/1051400003/Facades/System.Runtime.InteropServices.dll diff --git a/mcs/class/lib/monolite-darwin/1051200002/Facades/System.Runtime.Numerics.dll b/mcs/class/lib/monolite-darwin/1051400003/Facades/System.Runtime.Numerics.dll similarity index 100% rename from mcs/class/lib/monolite-darwin/1051200002/Facades/System.Runtime.Numerics.dll rename to mcs/class/lib/monolite-darwin/1051400003/Facades/System.Runtime.Numerics.dll diff --git a/mcs/class/lib/monolite-darwin/1051200002/Facades/System.Runtime.dll b/mcs/class/lib/monolite-darwin/1051400003/Facades/System.Runtime.dll similarity index 100% rename from mcs/class/lib/monolite-darwin/1051200002/Facades/System.Runtime.dll rename to mcs/class/lib/monolite-darwin/1051400003/Facades/System.Runtime.dll diff --git a/mcs/class/lib/monolite-darwin/1051400003/Facades/System.Security.Cryptography.Algorithms.dll b/mcs/class/lib/monolite-darwin/1051400003/Facades/System.Security.Cryptography.Algorithms.dll new file mode 100644 index 0000000000..2035789f6c Binary files /dev/null and b/mcs/class/lib/monolite-darwin/1051400003/Facades/System.Security.Cryptography.Algorithms.dll differ diff --git a/mcs/class/lib/monolite-darwin/1051200002/Facades/System.Security.Cryptography.Primitives.dll b/mcs/class/lib/monolite-darwin/1051400003/Facades/System.Security.Cryptography.Primitives.dll similarity index 100% rename from mcs/class/lib/monolite-darwin/1051200002/Facades/System.Security.Cryptography.Primitives.dll rename to mcs/class/lib/monolite-darwin/1051400003/Facades/System.Security.Cryptography.Primitives.dll diff --git a/mcs/class/lib/monolite-darwin/1051200002/Facades/System.Text.Encoding.CodePages.dll b/mcs/class/lib/monolite-darwin/1051400003/Facades/System.Text.Encoding.CodePages.dll similarity index 100% rename from mcs/class/lib/monolite-darwin/1051200002/Facades/System.Text.Encoding.CodePages.dll rename to mcs/class/lib/monolite-darwin/1051400003/Facades/System.Text.Encoding.CodePages.dll diff --git a/mcs/class/lib/monolite-darwin/1051200002/Facades/System.Text.Encoding.Extensions.dll b/mcs/class/lib/monolite-darwin/1051400003/Facades/System.Text.Encoding.Extensions.dll similarity index 100% rename from mcs/class/lib/monolite-darwin/1051200002/Facades/System.Text.Encoding.Extensions.dll rename to mcs/class/lib/monolite-darwin/1051400003/Facades/System.Text.Encoding.Extensions.dll diff --git a/mcs/class/lib/monolite-darwin/1051200002/Facades/System.Text.Encoding.dll b/mcs/class/lib/monolite-darwin/1051400003/Facades/System.Text.Encoding.dll similarity index 100% rename from mcs/class/lib/monolite-darwin/1051200002/Facades/System.Text.Encoding.dll rename to mcs/class/lib/monolite-darwin/1051400003/Facades/System.Text.Encoding.dll diff --git a/mcs/class/lib/monolite-linux/1051200002/Facades/System.Threading.Tasks.Parallel.dll b/mcs/class/lib/monolite-darwin/1051400003/Facades/System.Threading.Tasks.Parallel.dll similarity index 57% rename from mcs/class/lib/monolite-linux/1051200002/Facades/System.Threading.Tasks.Parallel.dll rename to mcs/class/lib/monolite-darwin/1051400003/Facades/System.Threading.Tasks.Parallel.dll index 37e515669e..463e74e826 100644 Binary files a/mcs/class/lib/monolite-linux/1051200002/Facades/System.Threading.Tasks.Parallel.dll and b/mcs/class/lib/monolite-darwin/1051400003/Facades/System.Threading.Tasks.Parallel.dll differ diff --git a/mcs/class/lib/monolite-win32/1051200002/Facades/System.Threading.Tasks.dll b/mcs/class/lib/monolite-darwin/1051400003/Facades/System.Threading.Tasks.dll similarity index 52% rename from mcs/class/lib/monolite-win32/1051200002/Facades/System.Threading.Tasks.dll rename to mcs/class/lib/monolite-darwin/1051400003/Facades/System.Threading.Tasks.dll index 68d2b3ac14..bd94187f12 100644 Binary files a/mcs/class/lib/monolite-win32/1051200002/Facades/System.Threading.Tasks.dll and b/mcs/class/lib/monolite-darwin/1051400003/Facades/System.Threading.Tasks.dll differ diff --git a/mcs/class/lib/monolite-darwin/1051200002/Facades/System.Threading.dll b/mcs/class/lib/monolite-darwin/1051400003/Facades/System.Threading.dll similarity index 100% rename from mcs/class/lib/monolite-darwin/1051200002/Facades/System.Threading.dll rename to mcs/class/lib/monolite-darwin/1051400003/Facades/System.Threading.dll diff --git a/mcs/class/lib/monolite-win32/1051200002/Facades/System.ValueTuple.dll b/mcs/class/lib/monolite-darwin/1051400003/Facades/System.ValueTuple.dll similarity index 62% rename from mcs/class/lib/monolite-win32/1051200002/Facades/System.ValueTuple.dll rename to mcs/class/lib/monolite-darwin/1051400003/Facades/System.ValueTuple.dll index f30fc4503e..dc59301eb3 100644 Binary files a/mcs/class/lib/monolite-win32/1051200002/Facades/System.ValueTuple.dll and b/mcs/class/lib/monolite-darwin/1051400003/Facades/System.ValueTuple.dll differ diff --git a/mcs/class/lib/monolite-darwin/1051200002/Facades/System.Xml.ReaderWriter.dll b/mcs/class/lib/monolite-darwin/1051400003/Facades/System.Xml.ReaderWriter.dll similarity index 100% rename from mcs/class/lib/monolite-darwin/1051200002/Facades/System.Xml.ReaderWriter.dll rename to mcs/class/lib/monolite-darwin/1051400003/Facades/System.Xml.ReaderWriter.dll diff --git a/mcs/class/lib/monolite-darwin/1051200002/Facades/System.Xml.XDocument.dll b/mcs/class/lib/monolite-darwin/1051400003/Facades/System.Xml.XDocument.dll similarity index 100% rename from mcs/class/lib/monolite-darwin/1051200002/Facades/System.Xml.XDocument.dll rename to mcs/class/lib/monolite-darwin/1051400003/Facades/System.Xml.XDocument.dll diff --git a/mcs/class/lib/monolite-darwin/1051400003/Mono.Cecil.dll.REMOVED.git-id b/mcs/class/lib/monolite-darwin/1051400003/Mono.Cecil.dll.REMOVED.git-id new file mode 100644 index 0000000000..bd49a2076e --- /dev/null +++ b/mcs/class/lib/monolite-darwin/1051400003/Mono.Cecil.dll.REMOVED.git-id @@ -0,0 +1 @@ +d7eb5a10aae99a897f8c1b6f49f3df205695cbf3 \ No newline at end of file diff --git a/mcs/class/lib/monolite-darwin/1051400003/Mono.Security.dll.REMOVED.git-id b/mcs/class/lib/monolite-darwin/1051400003/Mono.Security.dll.REMOVED.git-id new file mode 100644 index 0000000000..969200f3b2 --- /dev/null +++ b/mcs/class/lib/monolite-darwin/1051400003/Mono.Security.dll.REMOVED.git-id @@ -0,0 +1 @@ +5bbdb28d177b6c7c5296146f8f6657911a17d9ff \ No newline at end of file diff --git a/mcs/class/lib/monolite-darwin/1051400003/System.Configuration.dll.REMOVED.git-id b/mcs/class/lib/monolite-darwin/1051400003/System.Configuration.dll.REMOVED.git-id new file mode 100644 index 0000000000..67743bc43d --- /dev/null +++ b/mcs/class/lib/monolite-darwin/1051400003/System.Configuration.dll.REMOVED.git-id @@ -0,0 +1 @@ +9084a538593186fa0b78b53c3f3c400a0b154888 \ No newline at end of file diff --git a/mcs/class/lib/monolite-darwin/1051400003/System.Core.dll.REMOVED.git-id b/mcs/class/lib/monolite-darwin/1051400003/System.Core.dll.REMOVED.git-id new file mode 100644 index 0000000000..4dbca2aa2b --- /dev/null +++ b/mcs/class/lib/monolite-darwin/1051400003/System.Core.dll.REMOVED.git-id @@ -0,0 +1 @@ +d238b88c1556bc3ce7dcfb3c9f9b05116a9109b0 \ No newline at end of file diff --git a/mcs/class/lib/monolite-darwin/1051400003/System.Numerics.dll.REMOVED.git-id b/mcs/class/lib/monolite-darwin/1051400003/System.Numerics.dll.REMOVED.git-id new file mode 100644 index 0000000000..0eb6d3820c --- /dev/null +++ b/mcs/class/lib/monolite-darwin/1051400003/System.Numerics.dll.REMOVED.git-id @@ -0,0 +1 @@ +4f982dd758484e7d9dedc80704686176254546fb \ No newline at end of file diff --git a/mcs/class/lib/monolite-darwin/1051400003/System.Security.dll.REMOVED.git-id b/mcs/class/lib/monolite-darwin/1051400003/System.Security.dll.REMOVED.git-id new file mode 100644 index 0000000000..a570b91ff3 --- /dev/null +++ b/mcs/class/lib/monolite-darwin/1051400003/System.Security.dll.REMOVED.git-id @@ -0,0 +1 @@ +a84f3a5098c1badfd3c220a431fd598cb265fa66 \ No newline at end of file diff --git a/mcs/class/lib/monolite-darwin/1051400003/System.Xml.Linq.dll.REMOVED.git-id b/mcs/class/lib/monolite-darwin/1051400003/System.Xml.Linq.dll.REMOVED.git-id new file mode 100644 index 0000000000..9748fb232f --- /dev/null +++ b/mcs/class/lib/monolite-darwin/1051400003/System.Xml.Linq.dll.REMOVED.git-id @@ -0,0 +1 @@ +81f7326b14a61c5a16b8d80fcfc8b91049041971 \ No newline at end of file diff --git a/mcs/class/lib/monolite-darwin/1051400003/System.Xml.dll.REMOVED.git-id b/mcs/class/lib/monolite-darwin/1051400003/System.Xml.dll.REMOVED.git-id new file mode 100644 index 0000000000..6955bfd05f --- /dev/null +++ b/mcs/class/lib/monolite-darwin/1051400003/System.Xml.dll.REMOVED.git-id @@ -0,0 +1 @@ +d9b67c8fe7d84716fdec7ad28c391b4622a68ee0 \ No newline at end of file diff --git a/mcs/class/lib/monolite-darwin/1051400003/System.dll.REMOVED.git-id b/mcs/class/lib/monolite-darwin/1051400003/System.dll.REMOVED.git-id new file mode 100644 index 0000000000..767782c288 --- /dev/null +++ b/mcs/class/lib/monolite-darwin/1051400003/System.dll.REMOVED.git-id @@ -0,0 +1 @@ +d256823b3e8007e1e37e92b2d0d8abb3a7ecc96c \ No newline at end of file diff --git a/mcs/class/lib/monolite-darwin/1051400003/mcs.exe.REMOVED.git-id b/mcs/class/lib/monolite-darwin/1051400003/mcs.exe.REMOVED.git-id new file mode 100644 index 0000000000..22c52d1eec --- /dev/null +++ b/mcs/class/lib/monolite-darwin/1051400003/mcs.exe.REMOVED.git-id @@ -0,0 +1 @@ +d933cd10fd0abc9546eb2002618bc2ad19f3e9cb \ No newline at end of file diff --git a/mcs/class/lib/monolite-darwin/1051400003/mscorlib.dll.REMOVED.git-id b/mcs/class/lib/monolite-darwin/1051400003/mscorlib.dll.REMOVED.git-id new file mode 100644 index 0000000000..4651af3350 --- /dev/null +++ b/mcs/class/lib/monolite-darwin/1051400003/mscorlib.dll.REMOVED.git-id @@ -0,0 +1 @@ +86cf695ef4ffb54b278a3115a93794a53a33607e \ No newline at end of file diff --git a/mcs/class/lib/monolite-linux/1051200002/Facades/System.Security.Cryptography.Algorithms.dll b/mcs/class/lib/monolite-linux/1051200002/Facades/System.Security.Cryptography.Algorithms.dll deleted file mode 100644 index b3c7b85964..0000000000 Binary files a/mcs/class/lib/monolite-linux/1051200002/Facades/System.Security.Cryptography.Algorithms.dll and /dev/null differ diff --git a/mcs/class/lib/monolite-linux/1051200002/Mono.Security.dll.REMOVED.git-id b/mcs/class/lib/monolite-linux/1051200002/Mono.Security.dll.REMOVED.git-id deleted file mode 100644 index 81aa843377..0000000000 --- a/mcs/class/lib/monolite-linux/1051200002/Mono.Security.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -58e3afff30e9696cf624f871df55a0a07aac1134 \ No newline at end of file diff --git a/mcs/class/lib/monolite-linux/1051200002/System.Configuration.dll.REMOVED.git-id b/mcs/class/lib/monolite-linux/1051200002/System.Configuration.dll.REMOVED.git-id deleted file mode 100644 index c2422cc1d4..0000000000 --- a/mcs/class/lib/monolite-linux/1051200002/System.Configuration.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -938c6b0afec364e19bd901d7f331d1a8600943d8 \ No newline at end of file diff --git a/mcs/class/lib/monolite-linux/1051200002/System.Core.dll.REMOVED.git-id b/mcs/class/lib/monolite-linux/1051200002/System.Core.dll.REMOVED.git-id deleted file mode 100644 index b85e324e6f..0000000000 --- a/mcs/class/lib/monolite-linux/1051200002/System.Core.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -939005727764598d30ed961d7c64417144ed5273 \ No newline at end of file diff --git a/mcs/class/lib/monolite-linux/1051200002/System.Numerics.dll.REMOVED.git-id b/mcs/class/lib/monolite-linux/1051200002/System.Numerics.dll.REMOVED.git-id deleted file mode 100644 index 44729fc55d..0000000000 --- a/mcs/class/lib/monolite-linux/1051200002/System.Numerics.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -fe58dbd6ced95901c047720893fed58b36f36eed \ No newline at end of file diff --git a/mcs/class/lib/monolite-linux/1051200002/System.Security.dll.REMOVED.git-id b/mcs/class/lib/monolite-linux/1051200002/System.Security.dll.REMOVED.git-id deleted file mode 100644 index de81787346..0000000000 --- a/mcs/class/lib/monolite-linux/1051200002/System.Security.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -bd87e3386b025eec758cc37e9cbfa8800c5e0c4c \ No newline at end of file diff --git a/mcs/class/lib/monolite-linux/1051200002/System.Xml.Linq.dll.REMOVED.git-id b/mcs/class/lib/monolite-linux/1051200002/System.Xml.Linq.dll.REMOVED.git-id deleted file mode 100644 index 8838d85b5d..0000000000 --- a/mcs/class/lib/monolite-linux/1051200002/System.Xml.Linq.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -e9329342179f8971d9fd7aa04251dcb17a2a6d9d \ No newline at end of file diff --git a/mcs/class/lib/monolite-linux/1051200002/System.Xml.dll.REMOVED.git-id b/mcs/class/lib/monolite-linux/1051200002/System.Xml.dll.REMOVED.git-id deleted file mode 100644 index e6fc2548fc..0000000000 --- a/mcs/class/lib/monolite-linux/1051200002/System.Xml.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -770d3f5d4a965c6a3fd48e27a848ab233fb8a79f \ No newline at end of file diff --git a/mcs/class/lib/monolite-linux/1051200002/System.dll.REMOVED.git-id b/mcs/class/lib/monolite-linux/1051200002/System.dll.REMOVED.git-id deleted file mode 100644 index e362ce1b0d..0000000000 --- a/mcs/class/lib/monolite-linux/1051200002/System.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -391ab530387c217aea71486f167301bf0e2b871e \ No newline at end of file diff --git a/mcs/class/lib/monolite-linux/1051200002/mcs.exe.REMOVED.git-id b/mcs/class/lib/monolite-linux/1051200002/mcs.exe.REMOVED.git-id deleted file mode 100644 index 6930835560..0000000000 --- a/mcs/class/lib/monolite-linux/1051200002/mcs.exe.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -9d912b3cd815b8f94e4f5e81fef5df0c6d15eba5 \ No newline at end of file diff --git a/mcs/class/lib/monolite-linux/1051200002/mscorlib.dll.REMOVED.git-id b/mcs/class/lib/monolite-linux/1051200002/mscorlib.dll.REMOVED.git-id deleted file mode 100644 index 1beeb533cc..0000000000 --- a/mcs/class/lib/monolite-linux/1051200002/mscorlib.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -71055ca5da1f426f38fd18c6bb4bc137f3391ab4 \ No newline at end of file diff --git a/mcs/class/lib/monolite-linux/1051200002/Facades/System.Collections.Concurrent.dll b/mcs/class/lib/monolite-linux/1051400003/Facades/System.Collections.Concurrent.dll similarity index 100% rename from mcs/class/lib/monolite-linux/1051200002/Facades/System.Collections.Concurrent.dll rename to mcs/class/lib/monolite-linux/1051400003/Facades/System.Collections.Concurrent.dll diff --git a/mcs/class/lib/monolite-win32/1051200002/Facades/System.Collections.dll b/mcs/class/lib/monolite-linux/1051400003/Facades/System.Collections.dll similarity index 52% rename from mcs/class/lib/monolite-win32/1051200002/Facades/System.Collections.dll rename to mcs/class/lib/monolite-linux/1051400003/Facades/System.Collections.dll index f05f9c22cb..9dcb3db6b9 100644 Binary files a/mcs/class/lib/monolite-win32/1051200002/Facades/System.Collections.dll and b/mcs/class/lib/monolite-linux/1051400003/Facades/System.Collections.dll differ diff --git a/mcs/class/lib/monolite-linux/1051200002/Facades/System.Diagnostics.Debug.dll b/mcs/class/lib/monolite-linux/1051400003/Facades/System.Diagnostics.Debug.dll similarity index 100% rename from mcs/class/lib/monolite-linux/1051200002/Facades/System.Diagnostics.Debug.dll rename to mcs/class/lib/monolite-linux/1051400003/Facades/System.Diagnostics.Debug.dll diff --git a/mcs/class/lib/monolite-linux/1051200002/Facades/System.Diagnostics.FileVersionInfo.dll b/mcs/class/lib/monolite-linux/1051400003/Facades/System.Diagnostics.FileVersionInfo.dll similarity index 100% rename from mcs/class/lib/monolite-linux/1051200002/Facades/System.Diagnostics.FileVersionInfo.dll rename to mcs/class/lib/monolite-linux/1051400003/Facades/System.Diagnostics.FileVersionInfo.dll diff --git a/mcs/class/lib/monolite-linux/1051200002/Facades/System.Diagnostics.Tools.dll b/mcs/class/lib/monolite-linux/1051400003/Facades/System.Diagnostics.Tools.dll similarity index 100% rename from mcs/class/lib/monolite-linux/1051200002/Facades/System.Diagnostics.Tools.dll rename to mcs/class/lib/monolite-linux/1051400003/Facades/System.Diagnostics.Tools.dll diff --git a/mcs/class/lib/monolite-linux/1051200002/Facades/System.Dynamic.Runtime.dll b/mcs/class/lib/monolite-linux/1051400003/Facades/System.Dynamic.Runtime.dll similarity index 100% rename from mcs/class/lib/monolite-linux/1051200002/Facades/System.Dynamic.Runtime.dll rename to mcs/class/lib/monolite-linux/1051400003/Facades/System.Dynamic.Runtime.dll diff --git a/mcs/class/lib/monolite-linux/1051200002/Facades/System.Globalization.dll b/mcs/class/lib/monolite-linux/1051400003/Facades/System.Globalization.dll similarity index 100% rename from mcs/class/lib/monolite-linux/1051200002/Facades/System.Globalization.dll rename to mcs/class/lib/monolite-linux/1051400003/Facades/System.Globalization.dll diff --git a/mcs/class/lib/monolite-linux/1051200002/Facades/System.IO.FileSystem.Primitives.dll b/mcs/class/lib/monolite-linux/1051400003/Facades/System.IO.FileSystem.Primitives.dll similarity index 100% rename from mcs/class/lib/monolite-linux/1051200002/Facades/System.IO.FileSystem.Primitives.dll rename to mcs/class/lib/monolite-linux/1051400003/Facades/System.IO.FileSystem.Primitives.dll diff --git a/mcs/class/lib/monolite-linux/1051200002/Facades/System.IO.FileSystem.dll b/mcs/class/lib/monolite-linux/1051400003/Facades/System.IO.FileSystem.dll similarity index 100% rename from mcs/class/lib/monolite-linux/1051200002/Facades/System.IO.FileSystem.dll rename to mcs/class/lib/monolite-linux/1051400003/Facades/System.IO.FileSystem.dll diff --git a/mcs/class/lib/monolite-linux/1051200002/Facades/System.IO.dll b/mcs/class/lib/monolite-linux/1051400003/Facades/System.IO.dll similarity index 100% rename from mcs/class/lib/monolite-linux/1051200002/Facades/System.IO.dll rename to mcs/class/lib/monolite-linux/1051400003/Facades/System.IO.dll diff --git a/mcs/class/lib/monolite-linux/1051200002/Facades/System.Linq.Expressions.dll b/mcs/class/lib/monolite-linux/1051400003/Facades/System.Linq.Expressions.dll similarity index 100% rename from mcs/class/lib/monolite-linux/1051200002/Facades/System.Linq.Expressions.dll rename to mcs/class/lib/monolite-linux/1051400003/Facades/System.Linq.Expressions.dll diff --git a/mcs/class/lib/monolite-linux/1051200002/Facades/System.Linq.dll b/mcs/class/lib/monolite-linux/1051400003/Facades/System.Linq.dll similarity index 100% rename from mcs/class/lib/monolite-linux/1051200002/Facades/System.Linq.dll rename to mcs/class/lib/monolite-linux/1051400003/Facades/System.Linq.dll diff --git a/mcs/class/lib/monolite-linux/1051200002/Facades/System.Reflection.Extensions.dll b/mcs/class/lib/monolite-linux/1051400003/Facades/System.Reflection.Extensions.dll similarity index 100% rename from mcs/class/lib/monolite-linux/1051200002/Facades/System.Reflection.Extensions.dll rename to mcs/class/lib/monolite-linux/1051400003/Facades/System.Reflection.Extensions.dll diff --git a/mcs/class/lib/monolite-linux/1051200002/Facades/System.Reflection.Primitives.dll b/mcs/class/lib/monolite-linux/1051400003/Facades/System.Reflection.Primitives.dll similarity index 100% rename from mcs/class/lib/monolite-linux/1051200002/Facades/System.Reflection.Primitives.dll rename to mcs/class/lib/monolite-linux/1051400003/Facades/System.Reflection.Primitives.dll diff --git a/mcs/class/lib/monolite-linux/1051200002/Facades/System.Reflection.dll b/mcs/class/lib/monolite-linux/1051400003/Facades/System.Reflection.dll similarity index 100% rename from mcs/class/lib/monolite-linux/1051200002/Facades/System.Reflection.dll rename to mcs/class/lib/monolite-linux/1051400003/Facades/System.Reflection.dll diff --git a/mcs/class/lib/monolite-linux/1051200002/Facades/System.Resources.ResourceManager.dll b/mcs/class/lib/monolite-linux/1051400003/Facades/System.Resources.ResourceManager.dll similarity index 100% rename from mcs/class/lib/monolite-linux/1051200002/Facades/System.Resources.ResourceManager.dll rename to mcs/class/lib/monolite-linux/1051400003/Facades/System.Resources.ResourceManager.dll diff --git a/mcs/class/lib/monolite-linux/1051200002/Facades/System.Runtime.Extensions.dll b/mcs/class/lib/monolite-linux/1051400003/Facades/System.Runtime.Extensions.dll similarity index 100% rename from mcs/class/lib/monolite-linux/1051200002/Facades/System.Runtime.Extensions.dll rename to mcs/class/lib/monolite-linux/1051400003/Facades/System.Runtime.Extensions.dll diff --git a/mcs/class/lib/monolite-linux/1051200002/Facades/System.Runtime.InteropServices.dll b/mcs/class/lib/monolite-linux/1051400003/Facades/System.Runtime.InteropServices.dll similarity index 100% rename from mcs/class/lib/monolite-linux/1051200002/Facades/System.Runtime.InteropServices.dll rename to mcs/class/lib/monolite-linux/1051400003/Facades/System.Runtime.InteropServices.dll diff --git a/mcs/class/lib/monolite-linux/1051200002/Facades/System.Runtime.Numerics.dll b/mcs/class/lib/monolite-linux/1051400003/Facades/System.Runtime.Numerics.dll similarity index 100% rename from mcs/class/lib/monolite-linux/1051200002/Facades/System.Runtime.Numerics.dll rename to mcs/class/lib/monolite-linux/1051400003/Facades/System.Runtime.Numerics.dll diff --git a/mcs/class/lib/monolite-linux/1051200002/Facades/System.Runtime.dll b/mcs/class/lib/monolite-linux/1051400003/Facades/System.Runtime.dll similarity index 100% rename from mcs/class/lib/monolite-linux/1051200002/Facades/System.Runtime.dll rename to mcs/class/lib/monolite-linux/1051400003/Facades/System.Runtime.dll diff --git a/mcs/class/lib/monolite-linux/1051400003/Facades/System.Security.Cryptography.Algorithms.dll b/mcs/class/lib/monolite-linux/1051400003/Facades/System.Security.Cryptography.Algorithms.dll new file mode 100644 index 0000000000..2035789f6c Binary files /dev/null and b/mcs/class/lib/monolite-linux/1051400003/Facades/System.Security.Cryptography.Algorithms.dll differ diff --git a/mcs/class/lib/monolite-linux/1051200002/Facades/System.Security.Cryptography.Primitives.dll b/mcs/class/lib/monolite-linux/1051400003/Facades/System.Security.Cryptography.Primitives.dll similarity index 100% rename from mcs/class/lib/monolite-linux/1051200002/Facades/System.Security.Cryptography.Primitives.dll rename to mcs/class/lib/monolite-linux/1051400003/Facades/System.Security.Cryptography.Primitives.dll diff --git a/mcs/class/lib/monolite-linux/1051200002/Facades/System.Text.Encoding.CodePages.dll b/mcs/class/lib/monolite-linux/1051400003/Facades/System.Text.Encoding.CodePages.dll similarity index 100% rename from mcs/class/lib/monolite-linux/1051200002/Facades/System.Text.Encoding.CodePages.dll rename to mcs/class/lib/monolite-linux/1051400003/Facades/System.Text.Encoding.CodePages.dll diff --git a/mcs/class/lib/monolite-linux/1051200002/Facades/System.Text.Encoding.Extensions.dll b/mcs/class/lib/monolite-linux/1051400003/Facades/System.Text.Encoding.Extensions.dll similarity index 100% rename from mcs/class/lib/monolite-linux/1051200002/Facades/System.Text.Encoding.Extensions.dll rename to mcs/class/lib/monolite-linux/1051400003/Facades/System.Text.Encoding.Extensions.dll diff --git a/mcs/class/lib/monolite-linux/1051200002/Facades/System.Text.Encoding.dll b/mcs/class/lib/monolite-linux/1051400003/Facades/System.Text.Encoding.dll similarity index 100% rename from mcs/class/lib/monolite-linux/1051200002/Facades/System.Text.Encoding.dll rename to mcs/class/lib/monolite-linux/1051400003/Facades/System.Text.Encoding.dll diff --git a/mcs/class/lib/monolite-darwin/1051200002/Facades/System.Threading.Tasks.Parallel.dll b/mcs/class/lib/monolite-linux/1051400003/Facades/System.Threading.Tasks.Parallel.dll similarity index 57% rename from mcs/class/lib/monolite-darwin/1051200002/Facades/System.Threading.Tasks.Parallel.dll rename to mcs/class/lib/monolite-linux/1051400003/Facades/System.Threading.Tasks.Parallel.dll index 37e515669e..463e74e826 100644 Binary files a/mcs/class/lib/monolite-darwin/1051200002/Facades/System.Threading.Tasks.Parallel.dll and b/mcs/class/lib/monolite-linux/1051400003/Facades/System.Threading.Tasks.Parallel.dll differ diff --git a/mcs/class/lib/monolite-linux/1051200002/Facades/System.Threading.Tasks.dll b/mcs/class/lib/monolite-linux/1051400003/Facades/System.Threading.Tasks.dll similarity index 52% rename from mcs/class/lib/monolite-linux/1051200002/Facades/System.Threading.Tasks.dll rename to mcs/class/lib/monolite-linux/1051400003/Facades/System.Threading.Tasks.dll index 68d2b3ac14..bd94187f12 100644 Binary files a/mcs/class/lib/monolite-linux/1051200002/Facades/System.Threading.Tasks.dll and b/mcs/class/lib/monolite-linux/1051400003/Facades/System.Threading.Tasks.dll differ diff --git a/mcs/class/lib/monolite-linux/1051200002/Facades/System.Threading.dll b/mcs/class/lib/monolite-linux/1051400003/Facades/System.Threading.dll similarity index 100% rename from mcs/class/lib/monolite-linux/1051200002/Facades/System.Threading.dll rename to mcs/class/lib/monolite-linux/1051400003/Facades/System.Threading.dll diff --git a/mcs/class/lib/monolite-linux/1051200002/Facades/System.ValueTuple.dll b/mcs/class/lib/monolite-linux/1051400003/Facades/System.ValueTuple.dll similarity index 62% rename from mcs/class/lib/monolite-linux/1051200002/Facades/System.ValueTuple.dll rename to mcs/class/lib/monolite-linux/1051400003/Facades/System.ValueTuple.dll index f30fc4503e..dc59301eb3 100644 Binary files a/mcs/class/lib/monolite-linux/1051200002/Facades/System.ValueTuple.dll and b/mcs/class/lib/monolite-linux/1051400003/Facades/System.ValueTuple.dll differ diff --git a/mcs/class/lib/monolite-linux/1051200002/Facades/System.Xml.ReaderWriter.dll b/mcs/class/lib/monolite-linux/1051400003/Facades/System.Xml.ReaderWriter.dll similarity index 100% rename from mcs/class/lib/monolite-linux/1051200002/Facades/System.Xml.ReaderWriter.dll rename to mcs/class/lib/monolite-linux/1051400003/Facades/System.Xml.ReaderWriter.dll diff --git a/mcs/class/lib/monolite-linux/1051200002/Facades/System.Xml.XDocument.dll b/mcs/class/lib/monolite-linux/1051400003/Facades/System.Xml.XDocument.dll similarity index 100% rename from mcs/class/lib/monolite-linux/1051200002/Facades/System.Xml.XDocument.dll rename to mcs/class/lib/monolite-linux/1051400003/Facades/System.Xml.XDocument.dll diff --git a/mcs/class/lib/monolite-linux/1051400003/Mono.Cecil.dll.REMOVED.git-id b/mcs/class/lib/monolite-linux/1051400003/Mono.Cecil.dll.REMOVED.git-id new file mode 100644 index 0000000000..bd49a2076e --- /dev/null +++ b/mcs/class/lib/monolite-linux/1051400003/Mono.Cecil.dll.REMOVED.git-id @@ -0,0 +1 @@ +d7eb5a10aae99a897f8c1b6f49f3df205695cbf3 \ No newline at end of file diff --git a/mcs/class/lib/monolite-linux/1051400003/Mono.Security.dll.REMOVED.git-id b/mcs/class/lib/monolite-linux/1051400003/Mono.Security.dll.REMOVED.git-id new file mode 100644 index 0000000000..969200f3b2 --- /dev/null +++ b/mcs/class/lib/monolite-linux/1051400003/Mono.Security.dll.REMOVED.git-id @@ -0,0 +1 @@ +5bbdb28d177b6c7c5296146f8f6657911a17d9ff \ No newline at end of file diff --git a/mcs/class/lib/monolite-linux/1051400003/System.Configuration.dll.REMOVED.git-id b/mcs/class/lib/monolite-linux/1051400003/System.Configuration.dll.REMOVED.git-id new file mode 100644 index 0000000000..67743bc43d --- /dev/null +++ b/mcs/class/lib/monolite-linux/1051400003/System.Configuration.dll.REMOVED.git-id @@ -0,0 +1 @@ +9084a538593186fa0b78b53c3f3c400a0b154888 \ No newline at end of file diff --git a/mcs/class/lib/monolite-linux/1051400003/System.Core.dll.REMOVED.git-id b/mcs/class/lib/monolite-linux/1051400003/System.Core.dll.REMOVED.git-id new file mode 100644 index 0000000000..4dbca2aa2b --- /dev/null +++ b/mcs/class/lib/monolite-linux/1051400003/System.Core.dll.REMOVED.git-id @@ -0,0 +1 @@ +d238b88c1556bc3ce7dcfb3c9f9b05116a9109b0 \ No newline at end of file diff --git a/mcs/class/lib/monolite-linux/1051400003/System.Numerics.dll.REMOVED.git-id b/mcs/class/lib/monolite-linux/1051400003/System.Numerics.dll.REMOVED.git-id new file mode 100644 index 0000000000..0eb6d3820c --- /dev/null +++ b/mcs/class/lib/monolite-linux/1051400003/System.Numerics.dll.REMOVED.git-id @@ -0,0 +1 @@ +4f982dd758484e7d9dedc80704686176254546fb \ No newline at end of file diff --git a/mcs/class/lib/monolite-linux/1051400003/System.Security.dll.REMOVED.git-id b/mcs/class/lib/monolite-linux/1051400003/System.Security.dll.REMOVED.git-id new file mode 100644 index 0000000000..a570b91ff3 --- /dev/null +++ b/mcs/class/lib/monolite-linux/1051400003/System.Security.dll.REMOVED.git-id @@ -0,0 +1 @@ +a84f3a5098c1badfd3c220a431fd598cb265fa66 \ No newline at end of file diff --git a/mcs/class/lib/monolite-linux/1051400003/System.Xml.Linq.dll.REMOVED.git-id b/mcs/class/lib/monolite-linux/1051400003/System.Xml.Linq.dll.REMOVED.git-id new file mode 100644 index 0000000000..9748fb232f --- /dev/null +++ b/mcs/class/lib/monolite-linux/1051400003/System.Xml.Linq.dll.REMOVED.git-id @@ -0,0 +1 @@ +81f7326b14a61c5a16b8d80fcfc8b91049041971 \ No newline at end of file diff --git a/mcs/class/lib/monolite-linux/1051400003/System.Xml.dll.REMOVED.git-id b/mcs/class/lib/monolite-linux/1051400003/System.Xml.dll.REMOVED.git-id new file mode 100644 index 0000000000..6955bfd05f --- /dev/null +++ b/mcs/class/lib/monolite-linux/1051400003/System.Xml.dll.REMOVED.git-id @@ -0,0 +1 @@ +d9b67c8fe7d84716fdec7ad28c391b4622a68ee0 \ No newline at end of file diff --git a/mcs/class/lib/monolite-linux/1051400003/System.dll.REMOVED.git-id b/mcs/class/lib/monolite-linux/1051400003/System.dll.REMOVED.git-id new file mode 100644 index 0000000000..767782c288 --- /dev/null +++ b/mcs/class/lib/monolite-linux/1051400003/System.dll.REMOVED.git-id @@ -0,0 +1 @@ +d256823b3e8007e1e37e92b2d0d8abb3a7ecc96c \ No newline at end of file diff --git a/mcs/class/lib/monolite-linux/1051400003/mcs.exe.REMOVED.git-id b/mcs/class/lib/monolite-linux/1051400003/mcs.exe.REMOVED.git-id new file mode 100644 index 0000000000..22c52d1eec --- /dev/null +++ b/mcs/class/lib/monolite-linux/1051400003/mcs.exe.REMOVED.git-id @@ -0,0 +1 @@ +d933cd10fd0abc9546eb2002618bc2ad19f3e9cb \ No newline at end of file diff --git a/mcs/class/lib/monolite-linux/1051400003/mscorlib.dll.REMOVED.git-id b/mcs/class/lib/monolite-linux/1051400003/mscorlib.dll.REMOVED.git-id new file mode 100644 index 0000000000..4651af3350 --- /dev/null +++ b/mcs/class/lib/monolite-linux/1051400003/mscorlib.dll.REMOVED.git-id @@ -0,0 +1 @@ +86cf695ef4ffb54b278a3115a93794a53a33607e \ No newline at end of file diff --git a/mcs/class/lib/monolite-win32/1051200002/Facades/System.Security.Cryptography.Algorithms.dll b/mcs/class/lib/monolite-win32/1051200002/Facades/System.Security.Cryptography.Algorithms.dll deleted file mode 100644 index b3c7b85964..0000000000 Binary files a/mcs/class/lib/monolite-win32/1051200002/Facades/System.Security.Cryptography.Algorithms.dll and /dev/null differ diff --git a/mcs/class/lib/monolite-win32/1051200002/Mono.Security.dll.REMOVED.git-id b/mcs/class/lib/monolite-win32/1051200002/Mono.Security.dll.REMOVED.git-id deleted file mode 100644 index 81aa843377..0000000000 --- a/mcs/class/lib/monolite-win32/1051200002/Mono.Security.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -58e3afff30e9696cf624f871df55a0a07aac1134 \ No newline at end of file diff --git a/mcs/class/lib/monolite-win32/1051200002/System.Configuration.dll.REMOVED.git-id b/mcs/class/lib/monolite-win32/1051200002/System.Configuration.dll.REMOVED.git-id deleted file mode 100644 index c2422cc1d4..0000000000 --- a/mcs/class/lib/monolite-win32/1051200002/System.Configuration.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -938c6b0afec364e19bd901d7f331d1a8600943d8 \ No newline at end of file diff --git a/mcs/class/lib/monolite-win32/1051200002/System.Core.dll.REMOVED.git-id b/mcs/class/lib/monolite-win32/1051200002/System.Core.dll.REMOVED.git-id deleted file mode 100644 index b85e324e6f..0000000000 --- a/mcs/class/lib/monolite-win32/1051200002/System.Core.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -939005727764598d30ed961d7c64417144ed5273 \ No newline at end of file diff --git a/mcs/class/lib/monolite-win32/1051200002/System.Numerics.dll.REMOVED.git-id b/mcs/class/lib/monolite-win32/1051200002/System.Numerics.dll.REMOVED.git-id deleted file mode 100644 index 44729fc55d..0000000000 --- a/mcs/class/lib/monolite-win32/1051200002/System.Numerics.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -fe58dbd6ced95901c047720893fed58b36f36eed \ No newline at end of file diff --git a/mcs/class/lib/monolite-win32/1051200002/System.Security.dll.REMOVED.git-id b/mcs/class/lib/monolite-win32/1051200002/System.Security.dll.REMOVED.git-id deleted file mode 100644 index de81787346..0000000000 --- a/mcs/class/lib/monolite-win32/1051200002/System.Security.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -bd87e3386b025eec758cc37e9cbfa8800c5e0c4c \ No newline at end of file diff --git a/mcs/class/lib/monolite-win32/1051200002/System.Xml.Linq.dll.REMOVED.git-id b/mcs/class/lib/monolite-win32/1051200002/System.Xml.Linq.dll.REMOVED.git-id deleted file mode 100644 index 8838d85b5d..0000000000 --- a/mcs/class/lib/monolite-win32/1051200002/System.Xml.Linq.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -e9329342179f8971d9fd7aa04251dcb17a2a6d9d \ No newline at end of file diff --git a/mcs/class/lib/monolite-win32/1051200002/System.Xml.dll.REMOVED.git-id b/mcs/class/lib/monolite-win32/1051200002/System.Xml.dll.REMOVED.git-id deleted file mode 100644 index e6fc2548fc..0000000000 --- a/mcs/class/lib/monolite-win32/1051200002/System.Xml.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -770d3f5d4a965c6a3fd48e27a848ab233fb8a79f \ No newline at end of file diff --git a/mcs/class/lib/monolite-win32/1051200002/System.dll.REMOVED.git-id b/mcs/class/lib/monolite-win32/1051200002/System.dll.REMOVED.git-id deleted file mode 100644 index e362ce1b0d..0000000000 --- a/mcs/class/lib/monolite-win32/1051200002/System.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -391ab530387c217aea71486f167301bf0e2b871e \ No newline at end of file diff --git a/mcs/class/lib/monolite-win32/1051200002/mcs.exe.REMOVED.git-id b/mcs/class/lib/monolite-win32/1051200002/mcs.exe.REMOVED.git-id deleted file mode 100644 index 6930835560..0000000000 --- a/mcs/class/lib/monolite-win32/1051200002/mcs.exe.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -9d912b3cd815b8f94e4f5e81fef5df0c6d15eba5 \ No newline at end of file diff --git a/mcs/class/lib/monolite-win32/1051200002/mscorlib.dll.REMOVED.git-id b/mcs/class/lib/monolite-win32/1051200002/mscorlib.dll.REMOVED.git-id deleted file mode 100644 index 1beeb533cc..0000000000 --- a/mcs/class/lib/monolite-win32/1051200002/mscorlib.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -71055ca5da1f426f38fd18c6bb4bc137f3391ab4 \ No newline at end of file diff --git a/mcs/class/lib/monolite-win32/1051200002/Facades/System.Collections.Concurrent.dll b/mcs/class/lib/monolite-win32/1051400003/Facades/System.Collections.Concurrent.dll similarity index 100% rename from mcs/class/lib/monolite-win32/1051200002/Facades/System.Collections.Concurrent.dll rename to mcs/class/lib/monolite-win32/1051400003/Facades/System.Collections.Concurrent.dll diff --git a/mcs/class/lib/monolite-linux/1051200002/Facades/System.Collections.dll b/mcs/class/lib/monolite-win32/1051400003/Facades/System.Collections.dll similarity index 52% rename from mcs/class/lib/monolite-linux/1051200002/Facades/System.Collections.dll rename to mcs/class/lib/monolite-win32/1051400003/Facades/System.Collections.dll index f05f9c22cb..9dcb3db6b9 100644 Binary files a/mcs/class/lib/monolite-linux/1051200002/Facades/System.Collections.dll and b/mcs/class/lib/monolite-win32/1051400003/Facades/System.Collections.dll differ diff --git a/mcs/class/lib/monolite-win32/1051200002/Facades/System.Diagnostics.Debug.dll b/mcs/class/lib/monolite-win32/1051400003/Facades/System.Diagnostics.Debug.dll similarity index 100% rename from mcs/class/lib/monolite-win32/1051200002/Facades/System.Diagnostics.Debug.dll rename to mcs/class/lib/monolite-win32/1051400003/Facades/System.Diagnostics.Debug.dll diff --git a/mcs/class/lib/monolite-win32/1051200002/Facades/System.Diagnostics.FileVersionInfo.dll b/mcs/class/lib/monolite-win32/1051400003/Facades/System.Diagnostics.FileVersionInfo.dll similarity index 100% rename from mcs/class/lib/monolite-win32/1051200002/Facades/System.Diagnostics.FileVersionInfo.dll rename to mcs/class/lib/monolite-win32/1051400003/Facades/System.Diagnostics.FileVersionInfo.dll diff --git a/mcs/class/lib/monolite-win32/1051200002/Facades/System.Diagnostics.Tools.dll b/mcs/class/lib/monolite-win32/1051400003/Facades/System.Diagnostics.Tools.dll similarity index 100% rename from mcs/class/lib/monolite-win32/1051200002/Facades/System.Diagnostics.Tools.dll rename to mcs/class/lib/monolite-win32/1051400003/Facades/System.Diagnostics.Tools.dll diff --git a/mcs/class/lib/monolite-win32/1051200002/Facades/System.Dynamic.Runtime.dll b/mcs/class/lib/monolite-win32/1051400003/Facades/System.Dynamic.Runtime.dll similarity index 100% rename from mcs/class/lib/monolite-win32/1051200002/Facades/System.Dynamic.Runtime.dll rename to mcs/class/lib/monolite-win32/1051400003/Facades/System.Dynamic.Runtime.dll diff --git a/mcs/class/lib/monolite-win32/1051200002/Facades/System.Globalization.dll b/mcs/class/lib/monolite-win32/1051400003/Facades/System.Globalization.dll similarity index 100% rename from mcs/class/lib/monolite-win32/1051200002/Facades/System.Globalization.dll rename to mcs/class/lib/monolite-win32/1051400003/Facades/System.Globalization.dll diff --git a/mcs/class/lib/monolite-win32/1051200002/Facades/System.IO.FileSystem.Primitives.dll b/mcs/class/lib/monolite-win32/1051400003/Facades/System.IO.FileSystem.Primitives.dll similarity index 100% rename from mcs/class/lib/monolite-win32/1051200002/Facades/System.IO.FileSystem.Primitives.dll rename to mcs/class/lib/monolite-win32/1051400003/Facades/System.IO.FileSystem.Primitives.dll diff --git a/mcs/class/lib/monolite-win32/1051200002/Facades/System.IO.FileSystem.dll b/mcs/class/lib/monolite-win32/1051400003/Facades/System.IO.FileSystem.dll similarity index 100% rename from mcs/class/lib/monolite-win32/1051200002/Facades/System.IO.FileSystem.dll rename to mcs/class/lib/monolite-win32/1051400003/Facades/System.IO.FileSystem.dll diff --git a/mcs/class/lib/monolite-win32/1051200002/Facades/System.IO.dll b/mcs/class/lib/monolite-win32/1051400003/Facades/System.IO.dll similarity index 100% rename from mcs/class/lib/monolite-win32/1051200002/Facades/System.IO.dll rename to mcs/class/lib/monolite-win32/1051400003/Facades/System.IO.dll diff --git a/mcs/class/lib/monolite-win32/1051200002/Facades/System.Linq.Expressions.dll b/mcs/class/lib/monolite-win32/1051400003/Facades/System.Linq.Expressions.dll similarity index 100% rename from mcs/class/lib/monolite-win32/1051200002/Facades/System.Linq.Expressions.dll rename to mcs/class/lib/monolite-win32/1051400003/Facades/System.Linq.Expressions.dll diff --git a/mcs/class/lib/monolite-win32/1051200002/Facades/System.Linq.dll b/mcs/class/lib/monolite-win32/1051400003/Facades/System.Linq.dll similarity index 100% rename from mcs/class/lib/monolite-win32/1051200002/Facades/System.Linq.dll rename to mcs/class/lib/monolite-win32/1051400003/Facades/System.Linq.dll diff --git a/mcs/class/lib/monolite-win32/1051200002/Facades/System.Reflection.Extensions.dll b/mcs/class/lib/monolite-win32/1051400003/Facades/System.Reflection.Extensions.dll similarity index 100% rename from mcs/class/lib/monolite-win32/1051200002/Facades/System.Reflection.Extensions.dll rename to mcs/class/lib/monolite-win32/1051400003/Facades/System.Reflection.Extensions.dll diff --git a/mcs/class/lib/monolite-win32/1051200002/Facades/System.Reflection.Primitives.dll b/mcs/class/lib/monolite-win32/1051400003/Facades/System.Reflection.Primitives.dll similarity index 100% rename from mcs/class/lib/monolite-win32/1051200002/Facades/System.Reflection.Primitives.dll rename to mcs/class/lib/monolite-win32/1051400003/Facades/System.Reflection.Primitives.dll diff --git a/mcs/class/lib/monolite-win32/1051200002/Facades/System.Reflection.dll b/mcs/class/lib/monolite-win32/1051400003/Facades/System.Reflection.dll similarity index 100% rename from mcs/class/lib/monolite-win32/1051200002/Facades/System.Reflection.dll rename to mcs/class/lib/monolite-win32/1051400003/Facades/System.Reflection.dll diff --git a/mcs/class/lib/monolite-win32/1051200002/Facades/System.Resources.ResourceManager.dll b/mcs/class/lib/monolite-win32/1051400003/Facades/System.Resources.ResourceManager.dll similarity index 100% rename from mcs/class/lib/monolite-win32/1051200002/Facades/System.Resources.ResourceManager.dll rename to mcs/class/lib/monolite-win32/1051400003/Facades/System.Resources.ResourceManager.dll diff --git a/mcs/class/lib/monolite-win32/1051200002/Facades/System.Runtime.Extensions.dll b/mcs/class/lib/monolite-win32/1051400003/Facades/System.Runtime.Extensions.dll similarity index 100% rename from mcs/class/lib/monolite-win32/1051200002/Facades/System.Runtime.Extensions.dll rename to mcs/class/lib/monolite-win32/1051400003/Facades/System.Runtime.Extensions.dll diff --git a/mcs/class/lib/monolite-win32/1051200002/Facades/System.Runtime.InteropServices.dll b/mcs/class/lib/monolite-win32/1051400003/Facades/System.Runtime.InteropServices.dll similarity index 100% rename from mcs/class/lib/monolite-win32/1051200002/Facades/System.Runtime.InteropServices.dll rename to mcs/class/lib/monolite-win32/1051400003/Facades/System.Runtime.InteropServices.dll diff --git a/mcs/class/lib/monolite-win32/1051200002/Facades/System.Runtime.Numerics.dll b/mcs/class/lib/monolite-win32/1051400003/Facades/System.Runtime.Numerics.dll similarity index 100% rename from mcs/class/lib/monolite-win32/1051200002/Facades/System.Runtime.Numerics.dll rename to mcs/class/lib/monolite-win32/1051400003/Facades/System.Runtime.Numerics.dll diff --git a/mcs/class/lib/monolite-win32/1051200002/Facades/System.Runtime.dll b/mcs/class/lib/monolite-win32/1051400003/Facades/System.Runtime.dll similarity index 100% rename from mcs/class/lib/monolite-win32/1051200002/Facades/System.Runtime.dll rename to mcs/class/lib/monolite-win32/1051400003/Facades/System.Runtime.dll diff --git a/mcs/class/lib/monolite-win32/1051400003/Facades/System.Security.Cryptography.Algorithms.dll b/mcs/class/lib/monolite-win32/1051400003/Facades/System.Security.Cryptography.Algorithms.dll new file mode 100644 index 0000000000..2035789f6c Binary files /dev/null and b/mcs/class/lib/monolite-win32/1051400003/Facades/System.Security.Cryptography.Algorithms.dll differ diff --git a/mcs/class/lib/monolite-win32/1051200002/Facades/System.Security.Cryptography.Primitives.dll b/mcs/class/lib/monolite-win32/1051400003/Facades/System.Security.Cryptography.Primitives.dll similarity index 100% rename from mcs/class/lib/monolite-win32/1051200002/Facades/System.Security.Cryptography.Primitives.dll rename to mcs/class/lib/monolite-win32/1051400003/Facades/System.Security.Cryptography.Primitives.dll diff --git a/mcs/class/lib/monolite-win32/1051200002/Facades/System.Text.Encoding.CodePages.dll b/mcs/class/lib/monolite-win32/1051400003/Facades/System.Text.Encoding.CodePages.dll similarity index 100% rename from mcs/class/lib/monolite-win32/1051200002/Facades/System.Text.Encoding.CodePages.dll rename to mcs/class/lib/monolite-win32/1051400003/Facades/System.Text.Encoding.CodePages.dll diff --git a/mcs/class/lib/monolite-win32/1051200002/Facades/System.Text.Encoding.Extensions.dll b/mcs/class/lib/monolite-win32/1051400003/Facades/System.Text.Encoding.Extensions.dll similarity index 100% rename from mcs/class/lib/monolite-win32/1051200002/Facades/System.Text.Encoding.Extensions.dll rename to mcs/class/lib/monolite-win32/1051400003/Facades/System.Text.Encoding.Extensions.dll diff --git a/mcs/class/lib/monolite-win32/1051200002/Facades/System.Text.Encoding.dll b/mcs/class/lib/monolite-win32/1051400003/Facades/System.Text.Encoding.dll similarity index 100% rename from mcs/class/lib/monolite-win32/1051200002/Facades/System.Text.Encoding.dll rename to mcs/class/lib/monolite-win32/1051400003/Facades/System.Text.Encoding.dll diff --git a/mcs/class/lib/monolite-win32/1051200002/Facades/System.Threading.Tasks.Parallel.dll b/mcs/class/lib/monolite-win32/1051400003/Facades/System.Threading.Tasks.Parallel.dll similarity index 57% rename from mcs/class/lib/monolite-win32/1051200002/Facades/System.Threading.Tasks.Parallel.dll rename to mcs/class/lib/monolite-win32/1051400003/Facades/System.Threading.Tasks.Parallel.dll index 37e515669e..463e74e826 100644 Binary files a/mcs/class/lib/monolite-win32/1051200002/Facades/System.Threading.Tasks.Parallel.dll and b/mcs/class/lib/monolite-win32/1051400003/Facades/System.Threading.Tasks.Parallel.dll differ diff --git a/mcs/class/lib/monolite-darwin/1051200002/Facades/System.Threading.Tasks.dll b/mcs/class/lib/monolite-win32/1051400003/Facades/System.Threading.Tasks.dll similarity index 52% rename from mcs/class/lib/monolite-darwin/1051200002/Facades/System.Threading.Tasks.dll rename to mcs/class/lib/monolite-win32/1051400003/Facades/System.Threading.Tasks.dll index 68d2b3ac14..bd94187f12 100644 Binary files a/mcs/class/lib/monolite-darwin/1051200002/Facades/System.Threading.Tasks.dll and b/mcs/class/lib/monolite-win32/1051400003/Facades/System.Threading.Tasks.dll differ diff --git a/mcs/class/lib/monolite-win32/1051200002/Facades/System.Threading.dll b/mcs/class/lib/monolite-win32/1051400003/Facades/System.Threading.dll similarity index 100% rename from mcs/class/lib/monolite-win32/1051200002/Facades/System.Threading.dll rename to mcs/class/lib/monolite-win32/1051400003/Facades/System.Threading.dll diff --git a/mcs/class/lib/monolite-darwin/1051200002/Facades/System.ValueTuple.dll b/mcs/class/lib/monolite-win32/1051400003/Facades/System.ValueTuple.dll similarity index 62% rename from mcs/class/lib/monolite-darwin/1051200002/Facades/System.ValueTuple.dll rename to mcs/class/lib/monolite-win32/1051400003/Facades/System.ValueTuple.dll index f30fc4503e..dc59301eb3 100644 Binary files a/mcs/class/lib/monolite-darwin/1051200002/Facades/System.ValueTuple.dll and b/mcs/class/lib/monolite-win32/1051400003/Facades/System.ValueTuple.dll differ diff --git a/mcs/class/lib/monolite-win32/1051200002/Facades/System.Xml.ReaderWriter.dll b/mcs/class/lib/monolite-win32/1051400003/Facades/System.Xml.ReaderWriter.dll similarity index 100% rename from mcs/class/lib/monolite-win32/1051200002/Facades/System.Xml.ReaderWriter.dll rename to mcs/class/lib/monolite-win32/1051400003/Facades/System.Xml.ReaderWriter.dll diff --git a/mcs/class/lib/monolite-win32/1051200002/Facades/System.Xml.XDocument.dll b/mcs/class/lib/monolite-win32/1051400003/Facades/System.Xml.XDocument.dll similarity index 100% rename from mcs/class/lib/monolite-win32/1051200002/Facades/System.Xml.XDocument.dll rename to mcs/class/lib/monolite-win32/1051400003/Facades/System.Xml.XDocument.dll diff --git a/mcs/class/lib/monolite-win32/1051400003/Mono.Cecil.dll.REMOVED.git-id b/mcs/class/lib/monolite-win32/1051400003/Mono.Cecil.dll.REMOVED.git-id new file mode 100644 index 0000000000..bd49a2076e --- /dev/null +++ b/mcs/class/lib/monolite-win32/1051400003/Mono.Cecil.dll.REMOVED.git-id @@ -0,0 +1 @@ +d7eb5a10aae99a897f8c1b6f49f3df205695cbf3 \ No newline at end of file diff --git a/mcs/class/lib/monolite-win32/1051400003/Mono.Security.dll.REMOVED.git-id b/mcs/class/lib/monolite-win32/1051400003/Mono.Security.dll.REMOVED.git-id new file mode 100644 index 0000000000..969200f3b2 --- /dev/null +++ b/mcs/class/lib/monolite-win32/1051400003/Mono.Security.dll.REMOVED.git-id @@ -0,0 +1 @@ +5bbdb28d177b6c7c5296146f8f6657911a17d9ff \ No newline at end of file diff --git a/mcs/class/lib/monolite-win32/1051400003/System.Configuration.dll.REMOVED.git-id b/mcs/class/lib/monolite-win32/1051400003/System.Configuration.dll.REMOVED.git-id new file mode 100644 index 0000000000..67743bc43d --- /dev/null +++ b/mcs/class/lib/monolite-win32/1051400003/System.Configuration.dll.REMOVED.git-id @@ -0,0 +1 @@ +9084a538593186fa0b78b53c3f3c400a0b154888 \ No newline at end of file diff --git a/mcs/class/lib/monolite-win32/1051400003/System.Core.dll.REMOVED.git-id b/mcs/class/lib/monolite-win32/1051400003/System.Core.dll.REMOVED.git-id new file mode 100644 index 0000000000..4dbca2aa2b --- /dev/null +++ b/mcs/class/lib/monolite-win32/1051400003/System.Core.dll.REMOVED.git-id @@ -0,0 +1 @@ +d238b88c1556bc3ce7dcfb3c9f9b05116a9109b0 \ No newline at end of file diff --git a/mcs/class/lib/monolite-win32/1051400003/System.Numerics.dll.REMOVED.git-id b/mcs/class/lib/monolite-win32/1051400003/System.Numerics.dll.REMOVED.git-id new file mode 100644 index 0000000000..0eb6d3820c --- /dev/null +++ b/mcs/class/lib/monolite-win32/1051400003/System.Numerics.dll.REMOVED.git-id @@ -0,0 +1 @@ +4f982dd758484e7d9dedc80704686176254546fb \ No newline at end of file diff --git a/mcs/class/lib/monolite-win32/1051400003/System.Security.dll.REMOVED.git-id b/mcs/class/lib/monolite-win32/1051400003/System.Security.dll.REMOVED.git-id new file mode 100644 index 0000000000..a570b91ff3 --- /dev/null +++ b/mcs/class/lib/monolite-win32/1051400003/System.Security.dll.REMOVED.git-id @@ -0,0 +1 @@ +a84f3a5098c1badfd3c220a431fd598cb265fa66 \ No newline at end of file diff --git a/mcs/class/lib/monolite-win32/1051400003/System.Xml.Linq.dll.REMOVED.git-id b/mcs/class/lib/monolite-win32/1051400003/System.Xml.Linq.dll.REMOVED.git-id new file mode 100644 index 0000000000..9748fb232f --- /dev/null +++ b/mcs/class/lib/monolite-win32/1051400003/System.Xml.Linq.dll.REMOVED.git-id @@ -0,0 +1 @@ +81f7326b14a61c5a16b8d80fcfc8b91049041971 \ No newline at end of file diff --git a/mcs/class/lib/monolite-win32/1051400003/System.Xml.dll.REMOVED.git-id b/mcs/class/lib/monolite-win32/1051400003/System.Xml.dll.REMOVED.git-id new file mode 100644 index 0000000000..6955bfd05f --- /dev/null +++ b/mcs/class/lib/monolite-win32/1051400003/System.Xml.dll.REMOVED.git-id @@ -0,0 +1 @@ +d9b67c8fe7d84716fdec7ad28c391b4622a68ee0 \ No newline at end of file diff --git a/mcs/class/lib/monolite-win32/1051400003/System.dll.REMOVED.git-id b/mcs/class/lib/monolite-win32/1051400003/System.dll.REMOVED.git-id new file mode 100644 index 0000000000..767782c288 --- /dev/null +++ b/mcs/class/lib/monolite-win32/1051400003/System.dll.REMOVED.git-id @@ -0,0 +1 @@ +d256823b3e8007e1e37e92b2d0d8abb3a7ecc96c \ No newline at end of file diff --git a/mcs/class/lib/monolite-win32/1051400003/mcs.exe.REMOVED.git-id b/mcs/class/lib/monolite-win32/1051400003/mcs.exe.REMOVED.git-id new file mode 100644 index 0000000000..22c52d1eec --- /dev/null +++ b/mcs/class/lib/monolite-win32/1051400003/mcs.exe.REMOVED.git-id @@ -0,0 +1 @@ +d933cd10fd0abc9546eb2002618bc2ad19f3e9cb \ No newline at end of file diff --git a/mcs/class/lib/monolite-win32/1051400003/mscorlib.dll.REMOVED.git-id b/mcs/class/lib/monolite-win32/1051400003/mscorlib.dll.REMOVED.git-id new file mode 100644 index 0000000000..4651af3350 --- /dev/null +++ b/mcs/class/lib/monolite-win32/1051400003/mscorlib.dll.REMOVED.git-id @@ -0,0 +1 @@ +86cf695ef4ffb54b278a3115a93794a53a33607e \ No newline at end of file diff --git a/mcs/class/referencesource/System/compmod/system/collections/specialized/stringdictionary.cs b/mcs/class/referencesource/System/compmod/system/collections/specialized/stringdictionary.cs index 88f41bd59e..90d5c9fdb0 100644 --- a/mcs/class/referencesource/System/compmod/system/collections/specialized/stringdictionary.cs +++ b/mcs/class/referencesource/System/compmod/system/collections/specialized/stringdictionary.cs @@ -15,6 +15,7 @@ namespace System.Collections.Specialized { using System.Globalization; using System.Collections.Generic; +#if !COREFX /// /// Implements a hashtable with the key strongly typed to be /// a string rather than an object. @@ -188,12 +189,13 @@ namespace System.Collections.Specialized { internal IDictionary AsGenericDictionary() { return new GenericAdapter(this); } +#endif #region GenericAdapter // // This class is used to make StringDictionary implement IDictionary indirectly. // This is done to prevent StringDictionary be serialized as IDictionary and break its serialization by DataContractSerializer due to a bug in the serialization code. - private class GenericAdapter : IDictionary + class GenericAdapter : IDictionary { StringDictionary m_stringDictionary; @@ -454,5 +456,7 @@ namespace System.Collections.Specialized { #endregion } #endregion +#if !COREFX } +#endif } diff --git a/mcs/class/referencesource/System/net/System/Net/Internal.cs b/mcs/class/referencesource/System/net/System/Net/Internal.cs index 9ca1b3527c..3700535c29 100644 --- a/mcs/class/referencesource/System/net/System/Net/Internal.cs +++ b/mcs/class/referencesource/System/net/System/Net/Internal.cs @@ -989,6 +989,10 @@ namespace System.Net { } } +#if MONO + internal static WebException TimeoutException => new WebException(SR.net_timeout); +#endif + internal static NotSupportedException MethodNotSupportedException { get { return new NotSupportedException(SR.GetString(SR.net_MethodNotSupportedException)); diff --git a/mcs/class/referencesource/System/net/System/Net/WebRequest.cs b/mcs/class/referencesource/System/net/System/Net/WebRequest.cs index 57b3274a09..079a624576 100644 --- a/mcs/class/referencesource/System/net/System/Net/WebRequest.cs +++ b/mcs/class/referencesource/System/net/System/Net/WebRequest.cs @@ -555,7 +555,7 @@ namespace System.Net { res.Add(new WebRequestPrefixElement("http", http)); res.Add(new WebRequestPrefixElement("https", http)); res.Add(new WebRequestPrefixElement("file", new FileWebRequestCreator ())); - res.Add(new WebRequestPrefixElement("ftp", new FtpRequestCreator ())); + res.Add(new WebRequestPrefixElement("ftp", new FtpWebRequestCreator ())); #else object cfg = ConfigurationManager.GetSection ("system.net/webRequestModules"); WebRequestModulesSection s = cfg as WebRequestModulesSection; diff --git a/mcs/class/referencesource/mscorlib/system/activator.cs b/mcs/class/referencesource/mscorlib/system/activator.cs index 0a1ffa93eb..67a42942d3 100644 --- a/mcs/class/referencesource/mscorlib/system/activator.cs +++ b/mcs/class/referencesource/mscorlib/system/activator.cs @@ -184,9 +184,14 @@ namespace System { null, ref stackMark); } - + + public static object CreateInstance(Type type, bool nonPublic) + { + return CreateInstance(type, nonPublic, wrapExceptions: true); + } + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable - static public Object CreateInstance(Type type, bool nonPublic) + internal static object CreateInstance(Type type, bool nonPublic, bool wrapExceptions) { if ((object)type == null) throw new ArgumentNullException("type"); @@ -198,7 +203,7 @@ namespace System { throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "type"); StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; - return rt.CreateInstanceDefaultCtor(!nonPublic, false, true, ref stackMark); + return rt.CreateInstanceDefaultCtor(!nonPublic, false, true, wrapExceptions, ref stackMark); } [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable @@ -228,7 +233,7 @@ namespace System { return (T)rt.CreateInstanceSlow(true /*publicOnly*/, true /*skipCheckThis*/, false /*fillCache*/, ref stackMark); else #endif // FEATURE_CORECLR - return (T)rt.CreateInstanceDefaultCtor(true /*publicOnly*/, true /*skipCheckThis*/, true /*fillCache*/, ref stackMark); + return (T)rt.CreateInstanceDefaultCtor(true /*publicOnly*/, true /*skipCheckThis*/, true /*fillCache*/, true /*wrapExceptions*/, ref stackMark); } [ResourceExposure(ResourceScope.Machine)] diff --git a/mcs/class/referencesource/mscorlib/system/globalization/textinfo.cs b/mcs/class/referencesource/mscorlib/system/globalization/textinfo.cs index e2d5391f97..4881335010 100644 --- a/mcs/class/referencesource/mscorlib/system/globalization/textinfo.cs +++ b/mcs/class/referencesource/mscorlib/system/globalization/textinfo.cs @@ -617,7 +617,7 @@ namespace System.Globalization { #endif } - static private Char ToUpperAsciiInvariant(Char c) + static internal Char ToUpperAsciiInvariant(Char c) { if ('a' <= c && c <= 'z') { diff --git a/mcs/class/referencesource/mscorlib/system/io/stream.cs b/mcs/class/referencesource/mscorlib/system/io/stream.cs index d830182a03..f1c73c6adb 100644 --- a/mcs/class/referencesource/mscorlib/system/io/stream.cs +++ b/mcs/class/referencesource/mscorlib/system/io/stream.cs @@ -518,14 +518,14 @@ namespace System.IO { // If the wait has already complete, run the task. if (asyncWaiter.IsCompleted) { - Contract.Assert(asyncWaiter.IsRanToCompletion, "The semaphore wait should always complete successfully."); + Contract.Assert(asyncWaiter.IsCompletedSuccessfully, "The semaphore wait should always complete successfully."); RunReadWriteTask(readWriteTask); } else // Otherwise, wait for our turn, and then run the task. { asyncWaiter.ContinueWith((t, state) => { - Contract.Assert(t.IsRanToCompletion, "The semaphore wait should always complete successfully."); + Contract.Assert(t.IsCompletedSuccessfully, "The semaphore wait should always complete successfully."); var tuple = (Tuple)state; tuple.Item1.RunReadWriteTask(tuple.Item2); // RunReadWriteTask(readWriteTask); }, Tuple.Create(this, readWriteTask), @@ -699,6 +699,8 @@ namespace System.IO { using(context) ExecutionContext.Run(context, invokeAsyncCallback, this, true); } } + + public bool InvokeMayRunArbitraryCode => true; } #endif diff --git a/mcs/class/referencesource/mscorlib/system/missingmemberexception.cs b/mcs/class/referencesource/mscorlib/system/missingmemberexception.cs index 7f2857d962..a2ddbf63b7 100644 --- a/mcs/class/referencesource/mscorlib/system/missingmemberexception.cs +++ b/mcs/class/referencesource/mscorlib/system/missingmemberexception.cs @@ -61,11 +61,12 @@ namespace System { } } } - + #if MONO - internal static String FormatSignature(byte [] signature) { - throw new NotImplementedException (); - } + internal static string FormatSignature(byte[] signature) + { + return ""; + } #else // Called to format signature [System.Security.SecurityCritical] // auto-generated diff --git a/mcs/class/referencesource/mscorlib/system/missingmethodexception.cs b/mcs/class/referencesource/mscorlib/system/missingmethodexception.cs index abea8212ed..bbc2521b85 100644 --- a/mcs/class/referencesource/mscorlib/system/missingmethodexception.cs +++ b/mcs/class/referencesource/mscorlib/system/missingmethodexception.cs @@ -48,19 +48,10 @@ namespace System { if (ClassName == null) { return base.Message; } else { -#if MONO - string res = ClassName + "." + MemberName; - if (!string.IsNullOrEmpty(signature)) - res = string.Format (CultureInfo.InvariantCulture, signature, res); - if (!string.IsNullOrEmpty(_message)) - res += " Due to: " + _message; - return res; -#else // do any desired fixups to classname here. return Environment.GetResourceString("MissingMethod_Name", ClassName + "." + MemberName + (Signature != null ? " " + FormatSignature(Signature) : "")); -#endif } } } @@ -82,17 +73,5 @@ namespace System { // If ClassName != null, Message will construct on the fly using it // and the other variables. This allows customization of the // format depending on the language environment. -#if MONO - // Called from the EE - private MissingMethodException(String className, String methodName, String signature, String message) : base (message) - { - ClassName = className; - MemberName = methodName; - this.signature = signature; - } - - [NonSerialized] - string signature; -#endif } } diff --git a/mcs/class/referencesource/mscorlib/system/rttype.cs.REMOVED.git-id b/mcs/class/referencesource/mscorlib/system/rttype.cs.REMOVED.git-id index cb1d6a5747..ea8b99c901 100644 --- a/mcs/class/referencesource/mscorlib/system/rttype.cs.REMOVED.git-id +++ b/mcs/class/referencesource/mscorlib/system/rttype.cs.REMOVED.git-id @@ -1 +1 @@ -61b46433b342f6950ce1bad97f235b6a47259f76 \ No newline at end of file +dc706570b91f215615b17e9753d2eb67144fe265 \ No newline at end of file diff --git a/mcs/class/referencesource/mscorlib/system/runtime/ProfileOptimization.cs b/mcs/class/referencesource/mscorlib/system/runtime/ProfileOptimization.cs index 09715de0e5..91e74afe23 100644 --- a/mcs/class/referencesource/mscorlib/system/runtime/ProfileOptimization.cs +++ b/mcs/class/referencesource/mscorlib/system/runtime/ProfileOptimization.cs @@ -25,10 +25,21 @@ namespace System.Runtime { using System.Runtime.Versioning; using System.Runtime.CompilerServices; -#if FEATURE_MULTICOREJIT +#if FEATURE_MULTICOREJIT || MONO public static class ProfileOptimization { +#if MONO + internal static void InternalSetProfileRoot(string directoryPath) + { + // ignore + } + + internal static void InternalStartProfile(string profile, IntPtr ptrNativeAssemblyLoadContext) + { + // ignore + } +#else [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] [SecurityCritical] [ResourceExposure(ResourceScope.None)] @@ -40,6 +51,7 @@ namespace System.Runtime { [ResourceExposure(ResourceScope.None)] [SuppressUnmanagedCodeSecurity] internal static extern void InternalStartProfile(string profile, IntPtr ptrNativeAssemblyLoadContext); +#endif [SecurityCritical] public static void SetProfileRoot(string directoryPath) diff --git a/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs b/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs index b2d762d0ca..3e7d5fb429 100644 --- a/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs +++ b/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs @@ -245,7 +245,7 @@ namespace System.Runtime.CompilerServices } // This property lazily instantiates the Task in a non-thread-safe manner. - private Task Task + internal Task Task { get { diff --git a/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs b/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs index 64327a99ea..cd16af0c3e 100644 --- a/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs +++ b/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs @@ -153,7 +153,7 @@ namespace System.Runtime.CompilerServices task.NotifyDebuggerOfWaitCompletionIfNecessary(); // And throw an exception if the task is faulted or canceled. - if (!task.IsRanToCompletion) ThrowForNonSuccess(task); + if (!task.IsCompletedSuccessfully) ThrowForNonSuccess(task); } /// Throws an exception to handle a task that completed in a state other than RanToCompletion. @@ -209,18 +209,18 @@ namespace System.Runtime.CompilerServices internal static void OnCompletedInternal(Task task, Action continuation, bool continueOnCapturedContext, bool flowExecutionContext) { if (continuation == null) throw new ArgumentNullException("continuation"); - StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; #if !MONO + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; // If TaskWait* ETW events are enabled, trace a beginning event for this await // and set up an ending event to be traced when the asynchronous await completes. if ( TplEtwProvider.Log.IsEnabled() || Task.s_asyncDebuggingEnabled) { continuation = OutputWaitEtwEvents(task, continuation); } -#endif - - // Set the continuation onto the awaited task. task.SetContinuationForAwait(continuation, continueOnCapturedContext, flowExecutionContext, ref stackMark); +#else + task.SetContinuationForAwait(continuation, continueOnCapturedContext, flowExecutionContext); +#endif } /// diff --git a/mcs/class/referencesource/mscorlib/system/stringcomparer.cs b/mcs/class/referencesource/mscorlib/system/stringcomparer.cs index 0de343b1a0..0b41a333e1 100644 --- a/mcs/class/referencesource/mscorlib/system/stringcomparer.cs +++ b/mcs/class/referencesource/mscorlib/system/stringcomparer.cs @@ -125,6 +125,30 @@ namespace System { public abstract int Compare(String x, String y); public abstract bool Equals(String x, String y); public abstract int GetHashCode(string obj); + +#if MONO + // Convert a StringComparison to a StringComparer + public static StringComparer FromComparison(StringComparison comparisonType) + { + switch (comparisonType) + { + case StringComparison.CurrentCulture: + return CurrentCulture; + case StringComparison.CurrentCultureIgnoreCase: + return CurrentCultureIgnoreCase; + case StringComparison.InvariantCulture: + return InvariantCulture; + case StringComparison.InvariantCultureIgnoreCase: + return InvariantCultureIgnoreCase; + case StringComparison.Ordinal: + return Ordinal; + case StringComparison.OrdinalIgnoreCase: + return OrdinalIgnoreCase; + default: + throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType)); + } + } +#endif } [Serializable] diff --git a/mcs/class/referencesource/mscorlib/system/threading/LazyInitializer.cs b/mcs/class/referencesource/mscorlib/system/threading/LazyInitializer.cs index f34e183d05..69b9a6f545 100644 --- a/mcs/class/referencesource/mscorlib/system/threading/LazyInitializer.cs +++ b/mcs/class/referencesource/mscorlib/system/threading/LazyInitializer.cs @@ -156,6 +156,40 @@ namespace System.Threading return target; } +#if MONO + public static T EnsureInitialized(ref T target, ref object syncLock, System.Func valueFactory) where T : class + => Volatile.Read(ref target) ?? EnsureInitializedCore(ref target, ref syncLock, valueFactory); + + private static T EnsureInitializedCore(ref T target, ref object syncLock, Func valueFactory) where T : class + { + // Lazily initialize the lock if necessary and then double check if initialization is still required. + lock (EnsureLockInitialized(ref syncLock)) + { + if (Volatile.Read(ref target) == null) + { + Volatile.Write(ref target, valueFactory()); + if (target == null) + { + throw new InvalidOperationException(SR.Lazy_StaticInit_InvalidOperation); + } + } + } + + return target; + } + + /// + /// Ensure the lock object is initialized. + /// + /// A reference to a location containing a mutual exclusive lock. If is null, + /// a new object will be instantiated. + /// Initialized lock object. + private static object EnsureLockInitialized(ref object syncLock) => + syncLock ?? + Interlocked.CompareExchange(ref syncLock, new object(), null) ?? + syncLock; +#endif + /// /// Initializes a target reference or value type with its default constructor if it has not already diff --git a/mcs/class/referencesource/mscorlib/system/threading/executioncontext.cs b/mcs/class/referencesource/mscorlib/system/threading/executioncontext.cs index fb7a53c429..6f5f609c55 100644 --- a/mcs/class/referencesource/mscorlib/system/threading/executioncontext.cs +++ b/mcs/class/referencesource/mscorlib/system/threading/executioncontext.cs @@ -576,6 +576,10 @@ namespace System.Threading } } +#if MONO + internal static readonly ExecutionContext Default = new ExecutionContext(); +#endif + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] internal ExecutionContext() { diff --git a/mcs/class/referencesource/mscorlib/system/threading/synchronizationcontext.cs b/mcs/class/referencesource/mscorlib/system/threading/synchronizationcontext.cs index 34bb037f2a..e1be5014b9 100644 --- a/mcs/class/referencesource/mscorlib/system/threading/synchronizationcontext.cs +++ b/mcs/class/referencesource/mscorlib/system/threading/synchronizationcontext.cs @@ -60,7 +60,7 @@ namespace System.Threading #if !FEATURE_CORECLR [SecurityPermissionAttribute(SecurityAction.InheritanceDemand, Flags =SecurityPermissionFlag.ControlPolicy|SecurityPermissionFlag.ControlEvidence)] #endif - public class SynchronizationContext + public partial class SynchronizationContext { #if FEATURE_SYNCHRONIZATIONCONTEXT_WAIT SynchronizationContextProperties _props = SynchronizationContextProperties.None; diff --git a/mcs/class/referencesource/mscorlib/system/threading/threadpool.cs b/mcs/class/referencesource/mscorlib/system/threading/threadpool.cs index 2db695c93e..aaa517a33e 100644 --- a/mcs/class/referencesource/mscorlib/system/threading/threadpool.cs +++ b/mcs/class/referencesource/mscorlib/system/threading/threadpool.cs @@ -1382,7 +1382,7 @@ namespace System.Threading } [HostProtection(Synchronization=true, ExternalThreading=true)] - public static class ThreadPool + public static partial class ThreadPool { #if FEATURE_CORECLR [System.Security.SecurityCritical] // auto-generated diff --git a/mcs/class/referencesource/mscorlib/system/throwhelper.cs b/mcs/class/referencesource/mscorlib/system/throwhelper.cs index 21ccab07c0..d4031a2e92 100644 --- a/mcs/class/referencesource/mscorlib/system/throwhelper.cs +++ b/mcs/class/referencesource/mscorlib/system/throwhelper.cs @@ -307,6 +307,23 @@ namespace System { return argumentName; } + private static ArgumentOutOfRangeException GetArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource) + { + return new ArgumentOutOfRangeException(GetArgumentName(argument), resource.ToString()); + } + + internal static void ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index() + { + throw GetArgumentOutOfRangeException(ExceptionArgument.startIndex, + ExceptionResource.ArgumentOutOfRange_Index); + } + + internal static void ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count() + { + throw GetArgumentOutOfRangeException(ExceptionArgument.count, + ExceptionResource.ArgumentOutOfRange_Count); + } + // // This function will convert an ExceptionResource enum value to the resource string. // @@ -545,7 +562,11 @@ namespace System { text, length, comparer, - comparable + comparable, + exceptions, + exception, + action, + comparison #endif } @@ -600,7 +621,10 @@ namespace System { ObjectDisposed_RegKeyClosed, NotSupported_InComparableType, Argument_InvalidRegistryOptionsCheck, - Argument_InvalidRegistryViewCheck + Argument_InvalidRegistryViewCheck, + TaskT_TransitionToFinal_AlreadyCompleted, + TaskCompletionSourceT_TrySetException_NullException, + TaskCompletionSourceT_TrySetException_NoExceptions, } } diff --git a/mcs/errors/Makefile b/mcs/errors/Makefile index 90e83ea515..b957556292 100644 --- a/mcs/errors/Makefile +++ b/mcs/errors/Makefile @@ -2,11 +2,6 @@ thisdir = errors SUBDIRS = include ../build/rules.make -with_mono_path = MONO_PATH="$(topdir)/class/lib/$(PROFILE)$(PLATFORM_PATH_SEPARATOR)$$MONO_PATH" - -ilasm = $(topdir)/class/lib/$(PROFILE)/ilasm.exe -ILASM = $(with_mono_path) $(RUNTIME) $(RUNTIME_FLAGS) $(ilasm) - DISTFILES = \ CONTRIBUTORS_README \ errors.txt \ @@ -84,52 +79,52 @@ dist-local: dist-default csproj-local install-local uninstall-local: CS0029-26-lib.dll : CS0029-26-lib.cs - $(CSCOMPILE) /target:library /publicsign /keyfile:key.snk /out:$@ $< + $(CSCOMPILE) /r:$(topdir)/class/lib/$(PROFILE_DIRECTORY)/mscorlib.dll /target:library /publicsign /keyfile:key.snk /out:$@ $< CS0266-25-lib.dll: CS0266-25-lib.cs - $(CSCOMPILE) /target:library /r:$(topdir)/class/lib/$(PROFILE)/System.Core.dll /out:$@ $< + $(CSCOMPILE) /r:$(topdir)/class/lib/$(PROFILE_DIRECTORY)/mscorlib.dll /target:library /r:$(topdir)/class/lib/$(PROFILE)/System.Core.dll /out:$@ $< dlls/first/CS1701-lib.dll: dlls/first/CS1701-lib.cs - $(CSCOMPILE) /target:library /warn:0 /publicsign /keyfile:key.snk /out:$@ $< + $(CSCOMPILE) /r:$(topdir)/class/lib/$(PROFILE_DIRECTORY)/mscorlib.dll /target:library /warn:0 /publicsign /keyfile:key.snk /out:$@ $< dlls/first/CS1702-lib.dll: dlls/first/CS1702-lib.cs - $(CSCOMPILE) /target:library /warn:0 /publicsign /keyfile:key.snk /out:$@ $< + $(CSCOMPILE) /r:$(topdir)/class/lib/$(PROFILE_DIRECTORY)/mscorlib.dll /target:library /warn:0 /publicsign /keyfile:key.snk /out:$@ $< dlls/first/CS1703-lib.dll: dlls/first/CS1703-lib.cs - $(CSCOMPILE) /target:library /warn:0 /publicsign /keyfile:key.snk /out:$@ $< + $(CSCOMPILE) /r:$(topdir)/class/lib/$(PROFILE_DIRECTORY)/mscorlib.dll /target:library /warn:0 /publicsign /keyfile:key.snk /out:$@ $< dlls/first/CS1705-lib.dll: dlls/first/CS1705-lib.cs - $(CSCOMPILE) /target:library /warn:0 /publicsign /keyfile:key.snk /out:$@ $< + $(CSCOMPILE) /r:$(topdir)/class/lib/$(PROFILE_DIRECTORY)/mscorlib.dll /target:library /warn:0 /publicsign /keyfile:key.snk /out:$@ $< dlls/second/CS1701-lib.dll: dlls/second/CS1701-lib.cs - $(CSCOMPILE) /target:library /warn:0 /publicsign /keyfile:key.snk /out:$@ $< + $(CSCOMPILE) /r:$(topdir)/class/lib/$(PROFILE_DIRECTORY)/mscorlib.dll /target:library /warn:0 /publicsign /keyfile:key.snk /out:$@ $< dlls/second/CS1702-lib.dll: dlls/second/CS1702-lib.cs - $(CSCOMPILE) /target:library /warn:0 /publicsign /keyfile:key.snk /out:$@ $< + $(CSCOMPILE) /r:$(topdir)/class/lib/$(PROFILE_DIRECTORY)/mscorlib.dll /target:library /warn:0 /publicsign /keyfile:key.snk /out:$@ $< dlls/second/CS1703-lib.dll: dlls/second/CS1703-lib.cs - $(CSCOMPILE) /target:library /warn:0 /publicsign /keyfile:key.snk /out:$@ $< + $(CSCOMPILE) /r:$(topdir)/class/lib/$(PROFILE_DIRECTORY)/mscorlib.dll /target:library /warn:0 /publicsign /keyfile:key.snk /out:$@ $< dlls/second/CS1705-lib.dll: dlls/second/CS1705-lib.cs - $(CSCOMPILE) /target:library /warn:0 /publicsign /keyfile:key.snk /out:$@ $< + $(CSCOMPILE) /r:$(topdir)/class/lib/$(PROFILE_DIRECTORY)/mscorlib.dll /target:library /warn:0 /publicsign /keyfile:key.snk /out:$@ $< CS1701-lib.dll : CS1701-lib.cs - $(CSCOMPILE) /target:library /warn:0 /r:dlls/first/CS1701-lib.dll /out:$@ $< + $(CSCOMPILE) /r:$(topdir)/class/lib/$(PROFILE_DIRECTORY)/mscorlib.dll /target:library /warn:0 /r:dlls/first/CS1701-lib.dll /out:$@ $< CS1702-lib.dll : CS1702-lib.cs - $(CSCOMPILE) /target:library /warn:0 /r:dlls/first/CS1702-lib.dll /out:$@ $< + $(CSCOMPILE) /r:$(topdir)/class/lib/$(PROFILE_DIRECTORY)/mscorlib.dll /target:library /warn:0 /r:dlls/first/CS1702-lib.dll /out:$@ $< CS1705-lib.dll : CS1705-lib.cs - $(CSCOMPILE) /target:library /warn:0 /r:dlls/first/CS1705-lib.dll /out:$@ $< + $(CSCOMPILE) /r:$(topdir)/class/lib/$(PROFILE_DIRECTORY)/mscorlib.dll /target:library /warn:0 /r:dlls/first/CS1705-lib.dll /out:$@ $< CSFriendAssembly-lib.dll : CSFriendAssembly-lib.cs - $(CSCOMPILE) /target:library /publicsign /keyfile:key.snk /warn:0 /out:$@ $< + $(CSCOMPILE) /r:$(topdir)/class/lib/$(PROFILE_DIRECTORY)/mscorlib.dll /target:library /publicsign /keyfile:key.snk /warn:0 /out:$@ $< %-lib.dll: %-lib.cs - $(CSCOMPILE) /target:library /warn:0 /out:$@ $< + $(CSCOMPILE) /r:$(topdir)/class/lib/$(PROFILE_DIRECTORY)/mscorlib.dll /target:library /warn:0 /out:$@ $< %-module.dll: %-module.cs - $(CSCOMPILE) /target:module /out:$@ $< + $(CSCOMPILE) /r:$(topdir)/class/lib/$(PROFILE_DIRECTORY)/mscorlib.dll /target:module /out:$@ $< %-lib.dll: %-lib.il $(ILASM) /dll /out:$@ $< diff --git a/mcs/errors/cs0419.cs b/mcs/errors/cs0419.cs index b8ef0bab15..7f25d80769 100644 --- a/mcs/errors/cs0419.cs +++ b/mcs/errors/cs0419.cs @@ -1,4 +1,4 @@ -// CS0419: Ambiguous reference in cref attribute `System.String.Replace'. Assuming `string.Replace(char, char)' but other overloads including `string.Replace(string, string)' have also matched +// CS0419: Ambiguous reference in cref attribute `System.String.Replace'. Assuming `string.Replace(string, string, bool, System.Globalization.CultureInfo)' but other overloads including `string.Replace(string, string, System.StringComparison)' have also matched // Line: 1 // Compiler options: -doc:dummy.xml -warn:3 -warnaserror /// diff --git a/mcs/errors/cs0826-9.cs b/mcs/errors/cs0826-9.cs deleted file mode 100644 index 4e098969b8..0000000000 --- a/mcs/errors/cs0826-9.cs +++ /dev/null @@ -1,16 +0,0 @@ -// CS0826: The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly -// Line: 8 - -class C -{ - static void Main() - { - object o = 1; - dynamic d = 1; - - var a = new[] { - new { X = o }, - new { X = d } - }; - } -} diff --git a/mcs/errors/cs1525-27.cs b/mcs/errors/cs1525-27.cs index dc18493166..d4c1f326be 100644 --- a/mcs/errors/cs1525-27.cs +++ b/mcs/errors/cs1525-27.cs @@ -1,4 +1,4 @@ -// CS1525: Unexpected symbol `fe', expecting `class', `delegate', `enum', `interface', `partial', or `struct' +// CS1525: Unexpected symbol `fe', expecting `class', `delegate', `enum', `interface', `partial', `ref', or `struct' // Line: 6 namespace X diff --git a/mcs/ilasm/Makefile b/mcs/ilasm/Makefile index 090d1cc323..4ca1154578 100644 --- a/mcs/ilasm/Makefile +++ b/mcs/ilasm/Makefile @@ -13,7 +13,7 @@ EXTRA_DISTFILES = \ $(wildcard tests/*.il) ILParser.cs: parser/ILParser.jay $(topdir)/jay/skeleton.cs - $(topdir)/jay/jay -ct < $(topdir)/jay/skeleton.cs $(CURDIR)/$< >$@ + $(topdir)/jay/jay -ct -o $@ $(CURDIR)/$< < $(topdir)/jay/skeleton.cs include ../build/executable.make diff --git a/mcs/jay/defs.h b/mcs/jay/defs.h index b5dfc4303b..fd9fc2348e 100644 --- a/mcs/jay/defs.h +++ b/mcs/jay/defs.h @@ -237,12 +237,14 @@ extern char *input_file_name; extern char *prolog_file_name; extern char *local_file_name; extern char *verbose_file_name; +extern char *output_file_name; extern FILE *action_file; extern FILE *input_file; extern FILE *prolog_file; extern FILE *local_file; extern FILE *verbose_file; +extern FILE *output_file; extern int nitems; extern int nrules; diff --git a/mcs/jay/main.c b/mcs/jay/main.c index e039763571..2dc3580bd1 100644 --- a/mcs/jay/main.c +++ b/mcs/jay/main.c @@ -70,6 +70,7 @@ char *input_file_name = (char*)""; char *prolog_file_name; char *local_file_name; char *verbose_file_name; +char *output_file_name = 0; FILE *action_file; /* a temp file, used to save actions associated */ /* with rules until the parser is written */ @@ -77,6 +78,7 @@ FILE *input_file; /* the input file */ FILE *prolog_file; /* temp files, used to save text until all */ FILE *local_file; /* symbols have been defined */ FILE *verbose_file; /* y.output */ +FILE *output_file; /* defaults to stdout */ int nitems; int nrules; @@ -113,6 +115,7 @@ done (int k) if (action_file) { fclose(action_file); unlink(action_file_name); } if (prolog_file) { fclose(prolog_file); unlink(prolog_file_name); } if (local_file) { fclose(local_file); unlink(local_file_name); } + if (output_file && (output_file != stdout)) { fclose(output_file); if (k != 0) unlink(output_file_name); } exit(k); } @@ -143,7 +146,7 @@ set_signals (void) static void usage (void) { - fprintf(stderr, "usage: %s [-tvcp] [-b file_prefix] filename\n", myname); + fprintf(stderr, "usage: %s [-tvcp] [-b file_prefix] [-o output_filename] input_filename\n", myname); exit(1); } @@ -172,9 +175,9 @@ getargs (int argc, char *argv[]) if (i + 1 < argc) usage(); return; - case '-': - ++i; - goto no_more_options; + case '-': + ++i; + goto no_more_options; case 'b': if (*++s) @@ -185,13 +188,22 @@ getargs (int argc, char *argv[]) usage(); continue; - case 't': - tflag = 1; - break; + case 'o': + if (*++s) + output_file_name = s; + else if (++i < argc) + output_file_name = argv[i]; + else + usage(); + continue; + + case 't': + tflag = 1; + break; case 'p': - print_skel_dir (); - break; + print_skel_dir (); + break; case 'c': csharp = 1; @@ -222,12 +234,12 @@ getargs (int argc, char *argv[]) vflag = 1; break; - case 'p': - print_skel_dir (); - break; + case 'p': + print_skel_dir (); + break; - case 'c': - csharp = 1; + case 'c': + csharp = 1; line_format = "#line %d \"%s\"\n"; default_line_format = "#line default\n"; @@ -359,6 +371,17 @@ open_files (void) if (verbose_file == 0) open_error(verbose_file_name); } + + if (output_file == 0) + { + if (output_file_name != 0) { + output_file = fopen(output_file_name, "w"); + if (output_file == 0) + open_error(output_file_name); + } else { + output_file = stdout; + } + } } diff --git a/mcs/jay/output.c b/mcs/jay/output.c index 9e883a7504..859415a69f 100644 --- a/mcs/jay/output.c +++ b/mcs/jay/output.c @@ -141,7 +141,7 @@ output (void) fprintf(stderr, "jay: line %d is too long\n", lno), done(1); switch (buf[0]) { case '#': continue; - case 't': if (!tflag) fputs("//t", stdout); + case 't': if (!tflag) fputs("//t", output_file); case '.': break; default: cp = strtok(buf, " \t\r\n"); @@ -162,7 +162,7 @@ output (void) } continue; } - fputs(buf+1, stdout), ++ outline; + fputs(buf+1, output_file), ++ outline; } free_parser(); } @@ -173,19 +173,19 @@ output_rule_data (void) register int i; register int j; - printf("/*\n All more than 3 lines long rules are wrapped into a method\n*/\n"); + fprintf(output_file, "/*\n All more than 3 lines long rules are wrapped into a method\n*/\n"); for (i = 0; i < nmethods; ++i) { - printf("%s", methods[i]); + fprintf(output_file, "%s", methods[i]); FREE(methods[i]); - printf("\n\n"); + fprintf(output_file, "\n\n"); } FREE(methods); - printf(default_line_format, ++outline + 1); + fprintf(output_file, default_line_format, ++outline + 1); - printf(" %s static %s short [] yyLhs = {%16d,", + fprintf(output_file, " %s static %s short [] yyLhs = {%16d,", csharp ? "" : " protected", csharp ? "readonly" : "final", symbol_value[start_symbol]); @@ -196,18 +196,18 @@ output_rule_data (void) if (j >= 10) { ++outline; - putchar('\n'); + putc('\n', output_file); j = 1; } else ++j; - printf("%5d,", symbol_value[rlhs[i]]); + fprintf(output_file, "%5d,", symbol_value[rlhs[i]]); } outline += 2; - printf("\n };\n"); + fprintf(output_file, "\n };\n"); - printf(" %s static %s short [] yyLen = {%12d,", + fprintf(output_file, " %s static %s short [] yyLen = {%12d,", csharp ? "" : "protected", csharp ? "readonly" : "final", 2); @@ -218,16 +218,16 @@ output_rule_data (void) if (j >= 10) { ++outline; - putchar('\n'); + putc('\n', output_file); j = 1; } else j++; - printf("%5d,", rrhs[i + 1] - rrhs[i] - 1); + fprintf(output_file, "%5d,", rrhs[i + 1] - rrhs[i] - 1); } outline += 2; - printf("\n };\n"); + fprintf(output_file, "\n };\n"); } static void @@ -235,7 +235,7 @@ output_yydefred (void) { register int i, j; - printf(" %s static %s short [] yyDefRed = {%13d,", + fprintf(output_file, " %s static %s short [] yyDefRed = {%13d,", csharp ? "" : "protected", csharp ? "readonly" : "final", (defred[0] ? defred[0] - 2 : 0)); @@ -248,15 +248,15 @@ output_yydefred (void) else { ++outline; - putchar('\n'); + putc('\n', output_file); j = 1; } - printf("%5d,", (defred[i] ? defred[i] - 2 : 0)); + fprintf(output_file, "%5d,", (defred[i] ? defred[i] - 2 : 0)); } outline += 2; - printf("\n };\n"); + fprintf(output_file, "\n };\n"); } static void @@ -380,7 +380,7 @@ goto_actions (void) state_count = NEW2(nstates, short); k = default_goto(start_symbol + 1); - printf(" protected static %s short [] yyDgoto = {%14d,", csharp ? "readonly" : "final", k); + fprintf(output_file, " protected static %s short [] yyDgoto = {%14d,", csharp ? "readonly" : "final", k); save_column(start_symbol + 1, k); j = 10; @@ -389,19 +389,19 @@ goto_actions (void) if (j >= 10) { ++outline; - putchar('\n'); + putc('\n', output_file); j = 1; } else ++j; k = default_goto(i); - printf("%5d,", k); + fprintf(output_file, "%5d,", k); save_column(i, k); } outline += 2; - printf("\n };\n"); + fprintf(output_file, "\n };\n"); FREE(state_count); } @@ -696,7 +696,7 @@ output_base (void) { register int i, j; - printf(" protected static %s short [] yySindex = {%13d,", csharp? "readonly":"final", base[0]); + fprintf(output_file, " protected static %s short [] yySindex = {%13d,", csharp? "readonly":"final", base[0]); j = 10; for (i = 1; i < nstates; i++) @@ -704,17 +704,17 @@ output_base (void) if (j >= 10) { ++outline; - putchar('\n'); + putc('\n', output_file); j = 1; } else ++j; - printf("%5d,", base[i]); + fprintf(output_file, "%5d,", base[i]); } outline += 2; - printf("\n };\n protected static %s short [] yyRindex = {%13d,", + fprintf(output_file, "\n };\n protected static %s short [] yyRindex = {%13d,", csharp ? "readonly" : "final", base[nstates]); @@ -724,17 +724,17 @@ output_base (void) if (j >= 10) { ++outline; - putchar('\n'); + putc('\n', output_file); j = 1; } else ++j; - printf("%5d,", base[i]); + fprintf(output_file, "%5d,", base[i]); } outline += 2; - printf("\n };\n protected static %s short [] yyGindex = {%13d,", + fprintf(output_file, "\n };\n protected static %s short [] yyGindex = {%13d,", csharp ? "readonly" : "final", base[2*nstates]); @@ -744,17 +744,17 @@ output_base (void) if (j >= 10) { ++outline; - putchar('\n'); + putc('\n', output_file); j = 1; } else ++j; - printf("%5d,", base[i]); + fprintf(output_file, "%5d,", base[i]); } outline += 2; - printf("\n };\n"); + fprintf(output_file, "\n };\n"); FREE(base); } @@ -764,7 +764,7 @@ output_table (void) register int i; register int j; - printf(" protected static %s short [] yyTable = {%14d,", csharp ? "readonly" : "final", table[0]); + fprintf(output_file, " protected static %s short [] yyTable = {%14d,", csharp ? "readonly" : "final", table[0]); j = 10; for (i = 1; i <= high; i++) @@ -772,17 +772,17 @@ output_table (void) if (j >= 10) { ++outline; - putchar('\n'); + putc('\n', output_file); j = 1; } else ++j; - printf("%5d,", table[i]); + fprintf(output_file, "%5d,", table[i]); } outline += 2; - printf("\n };\n"); + fprintf(output_file, "\n };\n"); FREE(table); } @@ -792,7 +792,7 @@ output_check (void) register int i; register int j; - printf(" protected static %s short [] yyCheck = {%14d,", + fprintf(output_file, " protected static %s short [] yyCheck = {%14d,", csharp ? "readonly" : "final", check[0]); @@ -802,17 +802,17 @@ output_check (void) if (j >= 10) { ++outline; - putchar('\n'); + putc('\n', output_file); j = 1; } else ++j; - printf("%5d,", check[i]); + fprintf(output_file, "%5d,", check[i]); } outline += 2; - printf("\n };\n"); + fprintf(output_file, "\n };\n"); FREE(check); } @@ -859,30 +859,30 @@ output_defines (const char *prefix) if (is_C_identifier(s)) { if (prefix) - printf(" %s ", prefix); + fprintf(output_file, " %s ", prefix); c = *s; if (c == '"') { while ((c = *++s) != '"') { - putchar(c); + putc(c, output_file); } } else { do { - putchar(c); + putc(c, output_file); } while ((c = *++s)); } ++outline; - printf(" = %d%s\n", symbol_value[i], csharp ? ";" : ";"); + fprintf(output_file, " = %d%s\n", symbol_value[i], csharp ? ";" : ";"); } } ++outline; - printf(" %s yyErrorCode = %d%s\n", prefix ? prefix : "", symbol_value[1], csharp ? ";" : ";"); + fprintf(output_file, " %s yyErrorCode = %d%s\n", prefix ? prefix : "", symbol_value[1], csharp ? ";" : ";"); } static void @@ -898,14 +898,14 @@ output_stored_text (FILE *file, const char *name) if ((c = getc(in)) != EOF) { if (c == '\n') ++outline; - putchar(c); + putc(c, output_file); while ((c = getc(in)) != EOF) { if (c == '\n') ++outline; - putchar(c); + putc(c, output_file); } - printf(default_line_format, ++outline + 1); + fprintf(output_file, default_line_format, ++outline + 1); } fclose(in); } @@ -918,67 +918,67 @@ output_debug (void) const char * prefix = tflag ? "" : "//t"; ++outline; - printf(" protected %s int yyFinal = %d;\n", csharp ? "const" : "static final", final_state); + fprintf(output_file, " protected %s int yyFinal = %d;\n", csharp ? "const" : "static final", final_state); ++outline; - printf ("%s // Put this array into a separate class so it is only initialized if debugging is actually used\n", prefix); - printf ("%s // Use MarshalByRefObject to disable inlining\n", prefix); - printf("%s class YYRules %s {\n", prefix, csharp ? ": MarshalByRefObject" : ""); - printf("%s public static %s string [] yyRule = {\n", prefix, csharp ? "readonly" : "final"); + fprintf(output_file, "%s // Put this array into a separate class so it is only initialized if debugging is actually used\n", prefix); + fprintf(output_file, "%s // Use MarshalByRefObject to disable inlining\n", prefix); + fprintf(output_file, "%s class YYRules %s {\n", prefix, csharp ? ": MarshalByRefObject" : ""); + fprintf(output_file, "%s public static %s string [] yyRule = {\n", prefix, csharp ? "readonly" : "final"); for (i = 2; i < nrules; ++i) { - printf("%s \"%s :", prefix, symbol_name[rlhs[i]]); + fprintf(output_file, "%s \"%s :", prefix, symbol_name[rlhs[i]]); for (j = rrhs[i]; ritem[j] > 0; ++j) { s = symbol_name[ritem[j]]; if (s[0] == '"') { - printf(" \\\""); + fprintf(output_file, " \\\""); while (*++s != '"') { if (*s == '\\') { if (s[1] == '\\') - printf("\\\\\\\\"); + fprintf(output_file, "\\\\\\\\"); else - printf("\\\\%c", s[1]); + fprintf(output_file, "\\\\%c", s[1]); ++s; } else - putchar(*s); + putc(*s, output_file); } - printf("\\\""); + fprintf(output_file, "\\\""); } else if (s[0] == '\'') { if (s[1] == '"') - printf(" '\\\"'"); + fprintf(output_file, " '\\\"'"); else if (s[1] == '\\') { if (s[2] == '\\') - printf(" '\\\\\\\\"); + fprintf(output_file, " '\\\\\\\\"); else - printf(" '\\\\%c", s[2]); + fprintf(output_file, " '\\\\%c", s[2]); s += 2; while (*++s != '\'') - putchar(*s); - putchar('\''); + putc(*s, output_file); + putc('\'', output_file); } else - printf(" '%c'", s[1]); + fprintf(output_file, " '%c'", s[1]); } else - printf(" %s", s); + fprintf(output_file, " %s", s); } ++outline; - printf("\",\n"); + fprintf(output_file, "\",\n"); } ++ outline; - printf("%s };\n", prefix); - printf ("%s public static string getRule (int index) {\n", prefix); - printf ("%s return yyRule [index];\n", prefix); - printf ("%s }\n", prefix); - printf ("%s}\n", prefix); + fprintf(output_file, "%s };\n", prefix); + fprintf(output_file, "%s public static string getRule (int index) {\n", prefix); + fprintf(output_file, "%s return yyRule [index];\n", prefix); + fprintf(output_file, "%s }\n", prefix); + fprintf(output_file, "%s}\n", prefix); max = 0; for (i = 2; i < ntokens; ++i) @@ -987,7 +987,7 @@ output_debug (void) /* need yyNames for yyExpecting() */ - printf(" protected static %s string [] yyNames = {", csharp ? "readonly" : "final"); + fprintf(output_file, " protected static %s string [] yyNames = {", csharp ? "readonly" : "final"); symnam = (char **) MALLOC((max+1)*sizeof(char *)); if (symnam == 0) no_space(); @@ -999,7 +999,7 @@ output_debug (void) symnam[symbol_value[i]] = symbol_name[i]; symnam[0] = (char*)"end-of-file"; - j = 70; fputs(" ", stdout); + j = 70; fputs(" ", output_file); for (i = 0; i <= max; ++i) { if ((s = symnam[i])) @@ -1021,25 +1021,25 @@ output_debug (void) if (j > 70) { ++outline; - printf("\n "); + fprintf(output_file, "\n "); j = k; } - printf("\"\\\""); + fprintf(output_file, "\"\\\""); s = symnam[i]; while (*++s != '"') { if (*s == '\\') { - printf("\\\\"); + fprintf(output_file, "\\\\"); if (*++s == '\\') - printf("\\\\"); + fprintf(output_file, "\\\\"); else - putchar(*s); + putc(*s, output_file); } else - putchar(*s); + putc(*s, output_file); } - printf("\\\"\","); + fprintf(output_file, "\\\"\","); } else if (s[0] == '\'') { @@ -1049,10 +1049,10 @@ output_debug (void) if (j > 70) { ++outline; - printf("\n "); + fprintf(output_file, "\n "); j = 7; } - printf("\"'\\\"'\","); + fprintf(output_file, "\"'\\\"'\","); } else { @@ -1071,25 +1071,25 @@ output_debug (void) if (j > 70) { ++outline; - printf("\n "); + fprintf(output_file, "\n "); j = k; } - printf("\"'"); + fprintf(output_file, "\"'"); s = symnam[i]; while (*++s != '\'') { if (*s == '\\') { - printf("\\\\"); + fprintf(output_file, "\\\\"); if (*++s == '\\') - printf("\\\\"); + fprintf(output_file, "\\\\"); else - putchar(*s); + putc(*s, output_file); } else - putchar(*s); + putc(*s, output_file); } - printf("'\","); + fprintf(output_file, "'\","); } } else @@ -1099,12 +1099,12 @@ output_debug (void) if (j > 70) { ++outline; - printf("\n "); + fprintf(output_file, "\n "); j = k; } - putchar('"'); - do { putchar(*s); } while (*++s); - printf("\","); + putc('"', output_file); + do { putc(*s, output_file); } while (*++s); + fprintf(output_file, "\","); } } else @@ -1113,14 +1113,14 @@ output_debug (void) if (j > 70) { ++outline; - printf("\n "); + fprintf(output_file, "\n "); j = 5; } - printf("null,"); + fprintf(output_file, "null,"); } } outline += 2; - printf("\n };\n"); + fprintf(output_file, "\n };\n"); FREE(symnam); } @@ -1141,19 +1141,19 @@ output_trailing_text (void) if ((c = getc(in)) == EOF) return; ++outline; - printf(line_format, lineno, input_file_name); + fprintf(output_file, line_format, lineno, input_file_name); if (c == '\n') ++outline; - putchar(c); + putc(c, output_file); last = c; } else { ++outline; - printf(line_format, lineno, input_file_name); - do { putchar(c); } while ((c = *++cptr) != '\n'); + fprintf(output_file, line_format, lineno, input_file_name); + do { putc(c, output_file); } while ((c = *++cptr) != '\n'); ++outline; - putchar('\n'); + putc('\n', output_file); last = '\n'; } @@ -1161,16 +1161,16 @@ output_trailing_text (void) { if (c == '\n') ++outline; - putchar(c); + putc(c, output_file); last = c; } if (last != '\n') { ++outline; - putchar('\n'); + putc('\n', output_file); } - printf(default_line_format, ++outline + 1); + fprintf(output_file, default_line_format, ++outline + 1); } static void @@ -1189,22 +1189,22 @@ output_semantic_actions (void) last = c; if (c == '\n') ++outline; - putchar(c); + putc(c, output_file); while ((c = getc(action_file)) != EOF) { if (c == '\n') ++outline; - putchar(c); + putc(c, output_file); last = c; } if (last != '\n') { ++outline; - putchar('\n'); + putc('\n', output_file); } - printf(default_line_format, ++outline + 1); + fprintf(output_file, default_line_format, ++outline + 1); } static void diff --git a/mcs/mcs/Makefile b/mcs/mcs/Makefile index dbd71a3d58..dbf040afdd 100644 --- a/mcs/mcs/Makefile +++ b/mcs/mcs/Makefile @@ -32,7 +32,7 @@ BUILT_SOURCES = cs-parser.cs CLEAN_FILES += y.output %-parser.cs: %-parser.jay $(topdir)/jay/skeleton.cs - $(topdir)/jay/jay $(JAY_FLAGS) < $(topdir)/jay/skeleton.cs $< > jay-tmp.out && mv jay-tmp.out $@ + $(topdir)/jay/jay $(JAY_FLAGS) -o jay-tmp.out $< < $(topdir)/jay/skeleton.cs && mv jay-tmp.out $@ KEEP_OUTPUT_FILE_COPY = yes diff --git a/mcs/mcs/cs-parser.jay.REMOVED.git-id b/mcs/mcs/cs-parser.jay.REMOVED.git-id index 25ad128cf9..37eed687a0 100644 --- a/mcs/mcs/cs-parser.jay.REMOVED.git-id +++ b/mcs/mcs/cs-parser.jay.REMOVED.git-id @@ -1 +1 @@ -7e78d41043314048b54c7e8ec54e14a9bc2944f0 \ No newline at end of file +29e041bd715e98996e4bfcea2ef89ec0acb0c466 \ No newline at end of file diff --git a/mcs/mcs/cs-tokenizer.cs.REMOVED.git-id b/mcs/mcs/cs-tokenizer.cs.REMOVED.git-id index c41c02cf8f..45821c0e46 100644 --- a/mcs/mcs/cs-tokenizer.cs.REMOVED.git-id +++ b/mcs/mcs/cs-tokenizer.cs.REMOVED.git-id @@ -1 +1 @@ -b4a6a6a1dd58a51dfde5b14b6b6e8af4566850c0 \ No newline at end of file +7b3cb46f2b8083c2b0c64084235e9d355426449a \ No newline at end of file diff --git a/mcs/mcs/generic.cs b/mcs/mcs/generic.cs index ec2965df63..0c7032b208 100644 --- a/mcs/mcs/generic.cs +++ b/mcs/mcs/generic.cs @@ -3381,7 +3381,7 @@ namespace Mono.CSharp { continue; var bound = candidates [ci]; - if (bound.Type == best_candidate) + if (TypeSpecComparer.IsEqual (bound.Type, best_candidate)) continue; int cii = 0; diff --git a/mcs/mcs/mcs.csproj b/mcs/mcs/mcs.csproj index de5655e7e4..b3755e6fd4 100644 --- a/mcs/mcs/mcs.csproj +++ b/mcs/mcs/mcs.csproj @@ -1,193 +1,126 @@  - + + Debug - AnyCPU - 8.0.30703 - 2.0 {D4A01C5B-A1B5-48F5-BB5B-D2E1BD236E56} Exe - Properties - Mono.CSharp + 1699 + latest + win32 + darwin + linux + false + False + True mcs - 512 - x86 + v4.6.2 - - True + + + false + + + ./../class/lib/net_4_x-$(HostPlatform) + ./../class/obj/$(AssemblyName)-net_4_x-$(HostPlatform) + STATIC;NO_SYMBOL_WRITER;NO_AUTHENTICODE;MONO_FEATURE_THREAD_ABORT;MONO_FEATURE_PROCESS_START;NET_4_0;NET_4_5;NET_4_6;MONO;WIN_PLATFORM;MULTIPLEX_OS + + + + true full - False - . - TRACE;DEBUG;NET_4_5;STATIC;NO_SYMBOL_WRITER;NO_AUTHENTICODE - prompt - 4 - false - + false + + TRACE;$(DefineConstants) - + pdbonly - True - TRACE;NET_4_0;STATIC;NO_SYMBOL_WRITER;NO_AUTHENTICODE - prompt - prompt - 4 - . + true - - True - . - TRACE;DEBUG;NET_4_0;STATIC;NO_SYMBOL_WRITER;NO_AUTHENTICODE;FULL_AST - full - mcs.exe.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - false - prompt - MinimumRecommendedRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - false - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - false - false - 4 - False - - - - - - - - - - CryptoConvert.cs - - - MonoSymbolFile.cs - - - MonoSymbolTable.cs - - - SourceMethodBuilder.cs - + + + + + + + + + + + + + + + + + - - - - - - + + - - - - - - - - + + + + - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - - - - + + + - - outline.cs - - - - - - - - - - - - - + + + + + - + - - - False - - - False - - - False - - - False - - - False - - - False - - - False - + + + + + + - - - + + + + $(ProjectDir)\..\jay\jay -ct < $(ProjectDir)\..\jay\skeleton.cs $(ProjectDir)\cs-parser.jay > $(ProjectDir)\cs-parser.cs + $(ProjectDir)\..\jay\jay.exe -ct < $(ProjectDir)\..\jay\skeleton.cs $(ProjectDir)\cs-parser.jay > $(ProjectDir)\cs-parser.cs + + \ No newline at end of file diff --git a/mcs/mcs/statement.cs.REMOVED.git-id b/mcs/mcs/statement.cs.REMOVED.git-id index b2740701fc..b2305f36a2 100644 --- a/mcs/mcs/statement.cs.REMOVED.git-id +++ b/mcs/mcs/statement.cs.REMOVED.git-id @@ -1 +1 @@ -9c51128548f7bf24c42648a23fef1bf5dbc67fa8 \ No newline at end of file +6c834a1b868a20e05cf71b90e656297e3cce7faf \ No newline at end of file diff --git a/mcs/mcs/tuples.cs b/mcs/mcs/tuples.cs index 15a2ca5b0d..5226b9843e 100644 --- a/mcs/mcs/tuples.cs +++ b/mcs/mcs/tuples.cs @@ -267,6 +267,11 @@ namespace Mono.CSharp this.Location = expr.Location; } + public TupleLiteralElement Clone (CloneContext clonectx) + { + return new TupleLiteralElement (Name, Expr.Clone (clonectx), Location); + } + public string Name { get; private set; } public Expression Expr { get; set; } public Location Location { get; private set; } @@ -288,6 +293,16 @@ namespace Mono.CSharp } } + protected override void CloneTo (CloneContext clonectx, Expression t) + { + var clone = new List (elements.Count); + foreach (var te in elements) + clone.Add (te.Clone (clonectx)); + + TupleLiteral target = (TupleLiteral)t; + target.elements = clone; + } + public static bool ContainsNoTypeElement (TypeSpec type) { var ta = type.TypeArguments; diff --git a/mcs/nunit24/ClientUtilities/util/AssemblyInfo.cs b/mcs/nunit24/ClientUtilities/util/AssemblyInfo.cs index 919ca07ace..6489c1b2a5 100644 --- a/mcs/nunit24/ClientUtilities/util/AssemblyInfo.cs +++ b/mcs/nunit24/ClientUtilities/util/AssemblyInfo.cs @@ -5,7 +5,3 @@ // **************************************************************** using System.Reflection; - -[assembly: AssemblyDelaySign(false)] -[assembly: AssemblyKeyFile("../../nunit.snk")] -[assembly: AssemblyKeyName("")] diff --git a/mcs/nunit24/ConsoleRunner/nunit-console/AssemblyInfo.cs b/mcs/nunit24/ConsoleRunner/nunit-console/AssemblyInfo.cs index 919ca07ace..6489c1b2a5 100644 --- a/mcs/nunit24/ConsoleRunner/nunit-console/AssemblyInfo.cs +++ b/mcs/nunit24/ConsoleRunner/nunit-console/AssemblyInfo.cs @@ -5,7 +5,3 @@ // **************************************************************** using System.Reflection; - -[assembly: AssemblyDelaySign(false)] -[assembly: AssemblyKeyFile("../../nunit.snk")] -[assembly: AssemblyKeyName("")] diff --git a/mcs/nunit24/NUnitCore/core/AssemblyInfo.cs b/mcs/nunit24/NUnitCore/core/AssemblyInfo.cs index 747032c7e6..2f66d80222 100644 --- a/mcs/nunit24/NUnitCore/core/AssemblyInfo.cs +++ b/mcs/nunit24/NUnitCore/core/AssemblyInfo.cs @@ -7,7 +7,3 @@ using System; using System.Reflection; [assembly: CLSCompliant(true)] - -[assembly: AssemblyDelaySign(false)] -[assembly: AssemblyKeyFile("../../nunit.snk")] -[assembly: AssemblyKeyName("")] diff --git a/mcs/nunit24/NUnitCore/interfaces/AssemblyInfo.cs b/mcs/nunit24/NUnitCore/interfaces/AssemblyInfo.cs index fa86732b3d..efeaecf198 100644 --- a/mcs/nunit24/NUnitCore/interfaces/AssemblyInfo.cs +++ b/mcs/nunit24/NUnitCore/interfaces/AssemblyInfo.cs @@ -8,7 +8,3 @@ using System; using System.Reflection; [assembly: CLSCompliant(true)] - -[assembly: AssemblyDelaySign(false)] -[assembly: AssemblyKeyFile("../../nunit.snk")] -[assembly: AssemblyKeyName("")] diff --git a/mcs/nunit24/NUnitExtensions/core/AssemblyInfo.cs b/mcs/nunit24/NUnitExtensions/core/AssemblyInfo.cs index fa86732b3d..efeaecf198 100644 --- a/mcs/nunit24/NUnitExtensions/core/AssemblyInfo.cs +++ b/mcs/nunit24/NUnitExtensions/core/AssemblyInfo.cs @@ -8,7 +8,3 @@ using System; using System.Reflection; [assembly: CLSCompliant(true)] - -[assembly: AssemblyDelaySign(false)] -[assembly: AssemblyKeyFile("../../nunit.snk")] -[assembly: AssemblyKeyName("")] diff --git a/mcs/nunit24/NUnitExtensions/framework/AssemblyInfo.cs b/mcs/nunit24/NUnitExtensions/framework/AssemblyInfo.cs index a9553f691c..2b4b5bfb34 100644 --- a/mcs/nunit24/NUnitExtensions/framework/AssemblyInfo.cs +++ b/mcs/nunit24/NUnitExtensions/framework/AssemblyInfo.cs @@ -8,7 +8,3 @@ using System; using System.Reflection; [assembly: CLSCompliant(true)] - -[assembly: AssemblyDelaySign(false)] -[assembly: AssemblyKeyFile("../../nunit.snk")] -[assembly: AssemblyKeyName("")] diff --git a/mcs/nunit24/NUnitFramework/framework/AssemblyInfo.cs b/mcs/nunit24/NUnitFramework/framework/AssemblyInfo.cs index fa86732b3d..efeaecf198 100644 --- a/mcs/nunit24/NUnitFramework/framework/AssemblyInfo.cs +++ b/mcs/nunit24/NUnitFramework/framework/AssemblyInfo.cs @@ -8,7 +8,3 @@ using System; using System.Reflection; [assembly: CLSCompliant(true)] - -[assembly: AssemblyDelaySign(false)] -[assembly: AssemblyKeyFile("../../nunit.snk")] -[assembly: AssemblyKeyName("")] diff --git a/mcs/nunit24/NUnitMocks/mocks/AssemblyInfo.cs b/mcs/nunit24/NUnitMocks/mocks/AssemblyInfo.cs index 599b04ce45..f87ae60281 100644 --- a/mcs/nunit24/NUnitMocks/mocks/AssemblyInfo.cs +++ b/mcs/nunit24/NUnitMocks/mocks/AssemblyInfo.cs @@ -6,7 +6,3 @@ using System; using System.Reflection; - -[assembly: AssemblyDelaySign(false)] -[assembly: AssemblyKeyFile("../../nunit.snk")] -[assembly: AssemblyKeyName("")] diff --git a/mcs/nunit24/NUnitMocks/mocks/nunit.mocks.csproj b/mcs/nunit24/NUnitMocks/mocks/nunit.mocks.csproj index 1f2943ce18..dc09a47dd1 100644 --- a/mcs/nunit24/NUnitMocks/mocks/nunit.mocks.csproj +++ b/mcs/nunit24/NUnitMocks/mocks/nunit.mocks.csproj @@ -1,161 +1,68 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + {94A88112-9E7E-45FA-A3FF-ACF8E1DF0FCB} + Library + 1699 + latest + win32 + darwin + linux + false + True + True + nunit.mocks + v4.6.2 + + + + false + + + ./../../../class/lib/net_4_x-$(HostPlatform) + ./../../../class/obj/$(AssemblyName)-net_4_x-$(HostPlatform) + StronglyNamedAssembly;NET_4_0;NET_4_5;NET_4_6;MONO;WIN_PLATFORM;MULTIPLEX_OS + + + + true + full + false + + TRACE;$(DefineConstants) + + + pdbonly + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/Microsoft.Build.Tasks.CodeAnalysis.dll.REMOVED.git-id b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/Microsoft.Build.Tasks.CodeAnalysis.dll.REMOVED.git-id deleted file mode 100644 index feeec9b327..0000000000 --- a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/Microsoft.Build.Tasks.CodeAnalysis.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -2b9dbef3a097e168e0d6b2155f0989858e48c44d \ No newline at end of file diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/Microsoft.CodeAnalysis.CSharp.dll.REMOVED.git-id b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/Microsoft.CodeAnalysis.CSharp.dll.REMOVED.git-id deleted file mode 100644 index 3bfc94de10..0000000000 --- a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/Microsoft.CodeAnalysis.CSharp.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -5a25fc2768e1fe23abedb3df3ba7a508bb87002e \ No newline at end of file diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/Microsoft.CodeAnalysis.Scripting.dll.REMOVED.git-id b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/Microsoft.CodeAnalysis.Scripting.dll.REMOVED.git-id deleted file mode 100644 index 7c305f7429..0000000000 --- a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/Microsoft.CodeAnalysis.Scripting.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -d699cf61fdea635ceeb0404c7bd5790bccea1271 \ No newline at end of file diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/Microsoft.CodeAnalysis.VisualBasic.dll.REMOVED.git-id b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/Microsoft.CodeAnalysis.VisualBasic.dll.REMOVED.git-id deleted file mode 100644 index cc9b095b24..0000000000 --- a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/Microsoft.CodeAnalysis.VisualBasic.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -0f170f3010532d234420542230b97f06d9cfce7a \ No newline at end of file diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/Microsoft.CodeAnalysis.dll.REMOVED.git-id b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/Microsoft.CodeAnalysis.dll.REMOVED.git-id deleted file mode 100644 index ca6d1adbb8..0000000000 --- a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/Microsoft.CodeAnalysis.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -94f1812d5acd37fde33bc1c3b8e99baafd1117b9 \ No newline at end of file diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/VBCSCompiler.exe b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/VBCSCompiler.exe deleted file mode 100644 index c894163913..0000000000 Binary files a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/VBCSCompiler.exe and /dev/null differ diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/csc.exe b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/csc.exe deleted file mode 100644 index 5081b38c0f..0000000000 Binary files a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/csc.exe and /dev/null differ diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/vbc.exe b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/vbc.exe deleted file mode 100644 index 7a74435709..0000000000 Binary files a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.6.0/tools/vbc.exe and /dev/null differ diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.Build.Tasks.CodeAnalysis.dll.REMOVED.git-id b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.Build.Tasks.CodeAnalysis.dll.REMOVED.git-id new file mode 100644 index 0000000000..e21cd9eb02 --- /dev/null +++ b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.Build.Tasks.CodeAnalysis.dll.REMOVED.git-id @@ -0,0 +1 @@ +f05efc1a893862b0f114a0a76620b8661272148a \ No newline at end of file diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.CSharp.Core.targets b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.CSharp.Core.targets new file mode 100755 index 0000000000..8c535b2e29 --- /dev/null +++ b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.CSharp.Core.targets @@ -0,0 +1,167 @@ + + + + + + + + + + + + + + $(NoWarn);1701;1702 + + + + + $(NoWarn);2008 + + + + + + + + + + + $(AppConfig) + + + $(IntermediateOutputPath)$(TargetName).compile.pdb + + + + + false + + + + + + + + + + true + + + + + + + + + <_CoreCompileResourceInputs Remove="@(_CoreCompileResourceInputs)" /> + + + + + \ No newline at end of file diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.CodeAnalysis.CSharp.Scripting.dll b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.CodeAnalysis.CSharp.Scripting.dll new file mode 100755 index 0000000000..bb720f0289 Binary files /dev/null and b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.CodeAnalysis.CSharp.Scripting.dll differ diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.CodeAnalysis.CSharp.dll.REMOVED.git-id b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.CodeAnalysis.CSharp.dll.REMOVED.git-id new file mode 100644 index 0000000000..99798e7956 --- /dev/null +++ b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.CodeAnalysis.CSharp.dll.REMOVED.git-id @@ -0,0 +1 @@ +2ad58e695999acab255b43212777276fccf98b8a \ No newline at end of file diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.CodeAnalysis.Scripting.dll.REMOVED.git-id b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.CodeAnalysis.Scripting.dll.REMOVED.git-id new file mode 100644 index 0000000000..2b5ab1250c --- /dev/null +++ b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.CodeAnalysis.Scripting.dll.REMOVED.git-id @@ -0,0 +1 @@ +b21fcbe9336c57e668847b417c21995036af1b62 \ No newline at end of file diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.CodeAnalysis.VisualBasic.dll.REMOVED.git-id b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.CodeAnalysis.VisualBasic.dll.REMOVED.git-id new file mode 100644 index 0000000000..cb85e1db0d --- /dev/null +++ b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.CodeAnalysis.VisualBasic.dll.REMOVED.git-id @@ -0,0 +1 @@ +a3985f27509c583bdab4fbd2e12b931c96885f1d \ No newline at end of file diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.CodeAnalysis.dll.REMOVED.git-id b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.CodeAnalysis.dll.REMOVED.git-id new file mode 100644 index 0000000000..f41349adf7 --- /dev/null +++ b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.CodeAnalysis.dll.REMOVED.git-id @@ -0,0 +1 @@ +270574d390a3ea048cafc086660206e2e9d17ab0 \ No newline at end of file diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.VisualBasic.Core.targets b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.VisualBasic.Core.targets new file mode 100755 index 0000000000..21099278f4 --- /dev/null +++ b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/Microsoft.VisualBasic.Core.targets @@ -0,0 +1,164 @@ + + + + + + + + + + + + + <_NoWarnings Condition="'$(WarningLevel)' == '0'">true + <_NoWarnings Condition="'$(WarningLevel)' == '1'">false + + + + + $(IntermediateOutputPath)$(TargetName).compile.pdb + + + + + + + + + + + false + + + + + + + + + + true + + + + + + + + <_CoreCompileResourceInputs Remove="@(_CoreCompileResourceInputs)" /> + + + + + \ No newline at end of file diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/System.Collections.Immutable.dll.REMOVED.git-id b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/System.Collections.Immutable.dll.REMOVED.git-id new file mode 100644 index 0000000000..f621878df3 --- /dev/null +++ b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/System.Collections.Immutable.dll.REMOVED.git-id @@ -0,0 +1 @@ +ce6fc0e8d0d43a3e824b4a844fe5eae4667dd428 \ No newline at end of file diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/System.Reflection.Metadata.dll.REMOVED.git-id b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/System.Reflection.Metadata.dll.REMOVED.git-id new file mode 100644 index 0000000000..469c933c5d --- /dev/null +++ b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/System.Reflection.Metadata.dll.REMOVED.git-id @@ -0,0 +1 @@ +ee68731c052c101cd85d9f4ec976628cf1e224b4 \ No newline at end of file diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/VBCSCompiler.exe b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/VBCSCompiler.exe new file mode 100755 index 0000000000..1d3856b685 Binary files /dev/null and b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/VBCSCompiler.exe differ diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/VBCSCompiler.exe.config b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/VBCSCompiler.exe.config new file mode 100755 index 0000000000..6f76c76d18 --- /dev/null +++ b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/VBCSCompiler.exe.config @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/csc.exe b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/csc.exe new file mode 100755 index 0000000000..0a80c14413 Binary files /dev/null and b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/csc.exe differ diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/csc.exe.config b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/csc.exe.config new file mode 100755 index 0000000000..ce5472c93a --- /dev/null +++ b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/csc.exe.config @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/csc.rsp b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/csc.rsp new file mode 100755 index 0000000000..be7661d074 --- /dev/null +++ b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/csc.rsp @@ -0,0 +1,46 @@ +# Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +# This file contains command-line options that the C# +# command line compiler (CSC) will process as part +# of every compilation, unless the "/noconfig" option +# is specified. + +# Reference the common Framework libraries +/r:Accessibility.dll +/r:Microsoft.CSharp.dll +/r:System.Configuration.dll +/r:System.Configuration.Install.dll +/r:System.Core.dll +/r:System.Data.dll +/r:System.Data.DataSetExtensions.dll +/r:System.Data.Linq.dll +/r:System.Data.OracleClient.dll +/r:System.Deployment.dll +/r:System.Design.dll +/r:System.DirectoryServices.dll +/r:System.dll +/r:System.Drawing.Design.dll +/r:System.Drawing.dll +/r:System.EnterpriseServices.dll +/r:System.Management.dll +/r:System.Messaging.dll +/r:System.Runtime.Remoting.dll +/r:System.Runtime.Serialization.dll +/r:System.Runtime.Serialization.Formatters.Soap.dll +/r:System.Security.dll +/r:System.ServiceModel.dll +/r:System.ServiceModel.Web.dll +/r:System.ServiceProcess.dll +/r:System.Transactions.dll +/r:System.Web.dll +/r:System.Web.Extensions.Design.dll +/r:System.Web.Extensions.dll +/r:System.Web.Mobile.dll +/r:System.Web.RegularExpressions.dll +/r:System.Web.Services.dll +/r:System.Windows.Forms.dll +/r:System.Workflow.Activities.dll +/r:System.Workflow.ComponentModel.dll +/r:System.Workflow.Runtime.dll +/r:System.Xml.dll +/r:System.Xml.Linq.dll diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/csi.exe b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/csi.exe new file mode 100755 index 0000000000..5fcd12bc1c Binary files /dev/null and b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/csi.exe differ diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/csi.exe.config b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/csi.exe.config new file mode 100755 index 0000000000..937789ca32 --- /dev/null +++ b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/csi.exe.config @@ -0,0 +1,159 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/csi.rsp b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/csi.rsp new file mode 100755 index 0000000000..492f239de8 --- /dev/null +++ b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/csi.rsp @@ -0,0 +1,14 @@ +/r:System.dll +/r:System.Core.dll +/r:Microsoft.CSharp.dll +/r:Facades/System.Runtime.dll +/u:System +/u:System.IO +/u:System.Collections.Generic +/u:System.Console +/u:System.Diagnostics +/u:System.Dynamic +/u:System.Linq +/u:System.Linq.Expressions +/u:System.Text +/u:System.Threading.Tasks \ No newline at end of file diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/vbc.exe b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/vbc.exe new file mode 100755 index 0000000000..24bb6aa7cc Binary files /dev/null and b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/vbc.exe differ diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/vbc.exe.config b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/vbc.exe.config new file mode 100755 index 0000000000..ce5472c93a --- /dev/null +++ b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/vbc.exe.config @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/vbc.rsp b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/vbc.rsp new file mode 100755 index 0000000000..52b4caceb9 --- /dev/null +++ b/mcs/packages/mnt/jenkins/workspace/release-tarball-mono/external/roslyn-binaries/Microsoft.Net.Compilers/Microsoft.Net.Compilers.2.7.0/tools/vbc.rsp @@ -0,0 +1,55 @@ +# Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +# This file contains command-line options that the VB +# command line compiler (VBC) will process as part +# of every compilation, unless the "/noconfig" option +# is specified. + +# Reference the common Framework libraries +/r:Accessibility.dll +/r:System.Configuration.dll +/r:System.Configuration.Install.dll +/r:System.Data.dll +/r:System.Data.OracleClient.dll +/r:System.Deployment.dll +/r:System.Design.dll +/r:System.DirectoryServices.dll +/r:System.dll +/r:System.Drawing.Design.dll +/r:System.Drawing.dll +/r:System.EnterpriseServices.dll +/r:System.Management.dll +/r:System.Messaging.dll +/r:System.Runtime.Remoting.dll +/r:System.Runtime.Serialization.Formatters.Soap.dll +/r:System.Security.dll +/r:System.ServiceProcess.dll +/r:System.Transactions.dll +/r:System.Web.dll +/r:System.Web.Mobile.dll +/r:System.Web.RegularExpressions.dll +/r:System.Web.Services.dll +/r:System.Windows.Forms.dll +/r:System.XML.dll + +/r:System.Workflow.Activities.dll +/r:System.Workflow.ComponentModel.dll +/r:System.Workflow.Runtime.dll +/r:System.Runtime.Serialization.dll +/r:System.ServiceModel.dll + +/r:System.Core.dll +/r:System.Xml.Linq.dll +/r:System.Data.Linq.dll +/r:System.Data.DataSetExtensions.dll +/r:System.Web.Extensions.dll +/r:System.Web.Extensions.Design.dll +/r:System.ServiceModel.Web.dll + +# Import System and Microsoft.VisualBasic +/imports:System +/imports:Microsoft.VisualBasic +/imports:System.Linq +/imports:System.Xml.Linq + +/optioninfer+ diff --git a/mcs/tests/dtest-066.cs b/mcs/tests/dtest-066.cs new file mode 100644 index 0000000000..893fb40dff --- /dev/null +++ b/mcs/tests/dtest-066.cs @@ -0,0 +1,13 @@ +class C +{ + static void Main() + { + object o = 1; + dynamic d = 1; + + var a = new[] { + new { X = o }, + new { X = d } + }; + } +} diff --git a/mcs/tests/known-issues-interp-net_4_x b/mcs/tests/known-issues-interp-net_4_x index d4a03dc968..7bd5ebbf4d 100644 --- a/mcs/tests/known-issues-interp-net_4_x +++ b/mcs/tests/known-issues-interp-net_4_x @@ -10,12 +10,5 @@ test-pattern-04.cs test-pattern-05.cs test-pattern-07.cs -gtest-etree-01.cs gtest-etree-09.cs -test-269.cs -test-270.cs -test-399.cs test-404.cs -test-704.cs -test-811.cs -test-async-17.cs diff --git a/mcs/tests/test-928.cs b/mcs/tests/test-928.cs index 9018013795..290ee4d1fb 100644 --- a/mcs/tests/test-928.cs +++ b/mcs/tests/test-928.cs @@ -15,6 +15,24 @@ unsafe class Program } } + public static bool StringNull (string s) + { + unsafe { + fixed (char *a = s) { + return a == null; + } + } + } + + public static bool ArrayNull (int[] a) + { + unsafe { + fixed (int *e = a) { + return e == null; + } + } + } + public static int Main () { Test (); @@ -24,6 +42,12 @@ unsafe class Program if (lv.IsPinned) return 1; + if (!StringNull (null)) + return 1; + + if (!ArrayNull (null)) + return 2; + return 0; } } diff --git a/mcs/tests/test-ref-07.cs b/mcs/tests/test-ref-07.cs index 4aa1657975..f17cfb443b 100644 --- a/mcs/tests/test-ref-07.cs +++ b/mcs/tests/test-ref-07.cs @@ -1,6 +1,6 @@ // Compiler options: -langversion:latest -public readonly partial ref struct Test +public readonly ref partial struct Test { public static void Main () { @@ -14,6 +14,11 @@ public readonly partial ref struct Test } } +ref partial struct Test +{ + +} + ref struct Second { Test field; diff --git a/mcs/tests/test-tuple-02.cs b/mcs/tests/test-tuple-02.cs index c049275945..ab722642ae 100644 --- a/mcs/tests/test-tuple-02.cs +++ b/mcs/tests/test-tuple-02.cs @@ -26,6 +26,11 @@ class TupleConversions (string v1, object v2) b = ("a", "b"); (int v1, long v2)? x = null; + + var array = new [] { + (name: "A", offset: 0), + (name: "B", size: 4) + }; } static void Foo (T arg) diff --git a/mcs/tests/test-tuple-10.cs b/mcs/tests/test-tuple-10.cs new file mode 100644 index 0000000000..82f4e01ec1 --- /dev/null +++ b/mcs/tests/test-tuple-10.cs @@ -0,0 +1,9 @@ +using System.Linq; + +class Program { + public static int Main () + { + var l = (from f in (typeof (Program)).GetFields() select (name: f.Name, offset: 0)).ToList(); + return 0; + } +} \ No newline at end of file diff --git a/mcs/tests/ver-il-net_4_x.xml.REMOVED.git-id b/mcs/tests/ver-il-net_4_x.xml.REMOVED.git-id index d655468296..31310c92e7 100644 --- a/mcs/tests/ver-il-net_4_x.xml.REMOVED.git-id +++ b/mcs/tests/ver-il-net_4_x.xml.REMOVED.git-id @@ -1 +1 @@ -b9f7e8f159b0400a597cc46e59c1ab2f32b9d4e8 \ No newline at end of file +4fc8adbf4abf604dc4d7d7c0c6b1bc707fcd6916 \ No newline at end of file diff --git a/mcs/tools/Makefile b/mcs/tools/Makefile index 5cf5013e8c..750da31d12 100644 --- a/mcs/tools/Makefile +++ b/mcs/tools/Makefile @@ -10,7 +10,6 @@ net_4_5_dirs := \ mono-service \ mono-xsd \ resgen \ - gacutil \ wsdl \ xbuild \ csharp \ diff --git a/mcs/tools/cil-stringreplacer/Makefile b/mcs/tools/cil-stringreplacer/Makefile index aad8dad1b0..2a684b606f 100644 --- a/mcs/tools/cil-stringreplacer/Makefile +++ b/mcs/tools/cil-stringreplacer/Makefile @@ -5,6 +5,14 @@ include ../../build/rules.make PROGRAM = cil-stringreplacer.exe NO_INSTALL = yes +ifeq ($(PROFILE),basic) +# It can be run using system .net during boostrap +TARGET_NET_REFERENCE = v4.6 +# Trick to make it work during boostrap where it has to run with system +# assemblies not the ones in lib/basic folder +PROGRAM_USE_INTERMEDIATE_FILE = 1 +endif + LIB_REFS = System Mono.Cecil ifdef MCS_MODE diff --git a/mcs/tools/linker/monolinker.exe.sources b/mcs/tools/linker/monolinker.exe.sources index c58f704930..6312a320c5 100644 --- a/mcs/tools/linker/monolinker.exe.sources +++ b/mcs/tools/linker/monolinker.exe.sources @@ -1,6 +1,7 @@ ../../../external/linker/linker/Linker/Pipeline.cs ../../../external/linker/linker/Linker/AssemblyInfo.cs ../../../external/linker/linker/Linker/AssemblyResolver.cs +../../../external/linker/linker/Linker/AssemblyUtilities.cs ../../../external/linker/linker/Linker/TypePreserve.cs ../../../external/linker/linker/Linker/TypeReferenceExtensions.cs ../../../external/linker/linker/Linker/Annotations.cs diff --git a/mcs/tools/mdoc/Makefile b/mcs/tools/mdoc/Makefile index e4bd162730..13ab373764 100644 --- a/mcs/tools/mdoc/Makefile +++ b/mcs/tools/mdoc/Makefile @@ -24,6 +24,8 @@ LIB_REFS = monodoc System System.Xml System.Core Mono.Cecil ICSharpCode.SharpZip LOCAL_MCS_FLAGS = $(MDOC_RESOURCES_COMMAND) $(MONODOC_RESOURCES_COMMAND) PROGRAM = $(topdir)/class/lib/$(PROFILE)/mdoc.exe PROGRAM_DEPS = $(topdir)/class/lib/$(PROFILE)/monodoc.dll +MSCORLIB = -r:$(topdir)/class/lib/$(PROFILE)/mscorlib.dll + MDOC_TEST_FILES = \ Test/CLILibraryTypes.dtd \ @@ -77,51 +79,51 @@ cleanup: -rm -f monodocer1.exe* Test/DocTest-addNonGeneric.dll: - $(CSCOMPILE) $(TEST_CSCFLAGS) -unsafe -target:library -out:$@ Test/DocTest-addNonGeneric.cs + $(CSCOMPILE) $(TEST_CSCFLAGS) $(MSCORLIB) -unsafe -target:library -out:$@ Test/DocTest-addNonGeneric.cs Test/DocTest-addNonGeneric-v2.dll: - $(CSCOMPILE) $(TEST_CSCFLAGS) -unsafe -target:library -out:$@ Test/DocTest-addNonGeneric.cs /define:V2 + $(CSCOMPILE) $(TEST_CSCFLAGS) $(MSCORLIB) -unsafe -target:library -out:$@ Test/DocTest-addNonGeneric.cs /define:V2 Test/DocTest-DropNS-classic-secondary.dll: @echo $(value @) - $(CSCOMPILE) $(TEST_CSCFLAGS) -unsafe -target:library -out:$@ Test/DocTest-DropNS-classic-secondary.cs + $(CSCOMPILE) $(TEST_CSCFLAGS) $(MSCORLIB) -unsafe -target:library -out:$@ Test/DocTest-DropNS-classic-secondary.cs Test/DocTest-DropNS-classic.dll: @echo $(value @) - $(CSCOMPILE) $(TEST_CSCFLAGS) -unsafe -target:library -out:$@ Test/DocTest-DropNS-classic.cs + $(CSCOMPILE) $(TEST_CSCFLAGS) $(MSCORLIB) -unsafe -target:library -out:$@ Test/DocTest-DropNS-classic.cs Test/DocTest-DropNS-unified.dll: - $(CSCOMPILE) $(TEST_CSCFLAGS) -unsafe -target:library -out:$@ Test/DocTest-DropNS-unified.cs + $(CSCOMPILE) $(TEST_CSCFLAGS) $(MSCORLIB) -unsafe -target:library -out:$@ Test/DocTest-DropNS-unified.cs Test/DocTest-DropNS-unified-multitest.dll: rm -f $@ - $(CSCOMPILE) $(TEST_CSCFLAGS) -unsafe -target:library -out:$@ Test/DocTest-DropNS-unified.cs /define:MULTITEST + $(CSCOMPILE) $(TEST_CSCFLAGS) $(MSCORLIB) -unsafe -target:library -out:$@ Test/DocTest-DropNS-unified.cs /define:MULTITEST Test/DocTest-DropNS-classic-multitest.dll: rm -f $@ - $(CSCOMPILE) $(TEST_CSCFLAGS) -unsafe -target:library -out:$@ Test/DocTest-DropNS-classic.cs /define:MULTITEST + $(CSCOMPILE) $(TEST_CSCFLAGS) $(MSCORLIB) -unsafe -target:library -out:$@ Test/DocTest-DropNS-classic.cs /define:MULTITEST Test/DocTest-DropNS-unified-deletetest.dll: rm -f Test/DocTest-DropNS-unified-deletetest.dll - $(CSCOMPILE) $(TEST_CSCFLAGS) -unsafe -target:library -out:$@ Test/DocTest-DropNS-unified.cs /define:DELETETEST + $(CSCOMPILE) $(TEST_CSCFLAGS) $(MSCORLIB) -unsafe -target:library -out:$@ Test/DocTest-DropNS-unified.cs /define:DELETETEST Test/DocTest-DropNS-unified-deletetest-V2.dll: rm -f Test/DocTest-DropNS-unified-deletetest.dll - $(CSCOMPILE) $(TEST_CSCFLAGS) -unsafe -target:library -out:Test/DocTest-DropNS-unified-deletetest.dll Test/DocTest-DropNS-unified.cs /define:DELETETEST,V2 + $(CSCOMPILE) $(TEST_CSCFLAGS) $(MSCORLIB) -unsafe -target:library -out:Test/DocTest-DropNS-unified-deletetest.dll Test/DocTest-DropNS-unified.cs /define:DELETETEST,V2 Test/DocTest-DropNS-classic-deletetest.dll: rm -f Test/DocTest-DropNS-classic-deletetest.dll - $(CSCOMPILE) $(TEST_CSCFLAGS) -unsafe -target:library -out:$@ Test/DocTest-DropNS-classic.cs /define:DELETETEST + $(CSCOMPILE) $(TEST_CSCFLAGS) $(MSCORLIB) -unsafe -target:library -out:$@ Test/DocTest-DropNS-classic.cs /define:DELETETEST Test/DocTest-DropNS-classic-deletetest-V2.dll: rm -f Test/DocTest-DropNS-classic-deletetest.dll - $(CSCOMPILE) $(TEST_CSCFLAGS) -unsafe -target:library -out:Test/DocTest-DropNS-classic-deletetest.dll Test/DocTest-DropNS-classic.cs /define:DELETETEST,V2 + $(CSCOMPILE) $(TEST_CSCFLAGS) $(MSCORLIB) -unsafe -target:library -out:Test/DocTest-DropNS-classic-deletetest.dll Test/DocTest-DropNS-classic.cs /define:DELETETEST,V2 Test/DocTest.dll: - $(CSCOMPILE) $(TEST_CSCFLAGS) -unsafe -target:library -out:$@ Test/DocTest.cs -r:$(topdir)/class/lib/$(PROFILE)/System.Core.dll -r:$(topdir)/class/lib/$(PROFILE)/Microsoft.CSharp.dll + $(CSCOMPILE) $(TEST_CSCFLAGS) $(MSCORLIB) -unsafe -target:library -out:$@ Test/DocTest.cs -r:$(topdir)/class/lib/$(PROFILE)/System.Core.dll -r:$(topdir)/class/lib/$(PROFILE)/Microsoft.CSharp.dll Test/DocTest-InternalInterface.dll: - $(CSCOMPILE) $(TEST_CSCFLAGS) -unsafe -target:library -out:$@ Test/DocTest-InternalInterface.cs + $(CSCOMPILE) $(TEST_CSCFLAGS) $(MSCORLIB) -unsafe -target:library -out:$@ Test/DocTest-InternalInterface.cs Test/DocTest.dll-v1: -rm -f Test/DocTest.cs @@ -137,7 +139,7 @@ Test/DocTest.dll-v2: $(MAKE) TEST_CSCFLAGS=$(TEST_CSCFLAGS) Test/DocTest.dll Test/DocTest-enumerations.dll: - $(CSCOMPILE) $(TEST_CSCFLAGS) -unsafe -target:library -out:$@ Test/DocTest-enumerations.cs + $(CSCOMPILE) $(TEST_CSCFLAGS) $(MSCORLIB) -unsafe -target:library -out:$@ Test/DocTest-enumerations.cs check-monodocer-addNonGeneric: $(PROGRAM) -rm -Rf Test/en.actual diff --git a/mcs/tools/mkbundle/mkbundle.cs b/mcs/tools/mkbundle/mkbundle.cs index 1fd9c97e03..25f644fc13 100755 --- a/mcs/tools/mkbundle/mkbundle.cs +++ b/mcs/tools/mkbundle/mkbundle.cs @@ -48,8 +48,19 @@ class MakeBundle { static bool keeptemp = false; static bool compile_only = false; static bool static_link = false; - static string config_file = null; + + // Points to the $sysconfig/mono/4.5/machine.config, which contains System.Configuration settings static string machine_config_file = null; + + // By default, we automatically bundle a machine-config, use this to turn off the behavior. + static bool no_machine_config = false; + + // Points to the $sysconfig/mono/config file, contains and others + static string config_file = null; + + // By default, we automatically bundle the above config file, use this to turn off the behavior. + static bool no_config = false; + static string config_dir = null; static string style = "linux"; static bool bundled_header = false; @@ -65,7 +76,7 @@ class MakeBundle { static string fetch_target = null; static bool custom_mode = true; static string embedded_options = null; - + static string runtime = null; static bool aot_compile = false; @@ -148,7 +159,7 @@ class MakeBundle { return 1; } if (sdk_path != null || runtime != null) - Error ("You can only specify one of --runtime, --sdk or --cross"); + Error ("You can only specify one of --runtime, --sdk or --cross {sdk_path}/{runtime}"); custom_mode = false; autodeps = true; cross_target = args [++i]; @@ -289,6 +300,12 @@ class MakeBundle { if (!quiet) Console.WriteLine ("WARNING:\n Check that the machine.config file you are bundling\n doesn't contain sensitive information specific to this machine."); break; + case "--no-machine-config": + no_machine_config = true; + break; + case "--no-config": + no_config = true; + break; case "--config-dir": if (i+1 == top) { Help (); @@ -523,6 +540,18 @@ class MakeBundle { if (!Directory.Exists (lib_path)) Error ($"The SDK location does not contain a {path}/lib/mono/4.5 directory"); link_paths.Add (lib_path); + if (machine_config_file == null && !no_machine_config) { + machine_config_file = Path.Combine (path, "etc", "mono", "4.5", "machine.config"); + if (!File.Exists (machine_config_file)){ + Error ($"Could not locate the file machine.config file at ${machine_config_file} use --machine-config FILE or --no-machine-config"); + } + } + if (config_file == null && !no_config) { + config_file = Path.Combine (path, "etc", "mono", "config"); + if (!File.Exists (config_file)){ + Error ($"Could not locate the file config file at ${config_file} use --config FILE or --no-config"); + } + } } static string targets_dir = Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.Personal), ".mono", "targets"); @@ -2463,7 +2492,15 @@ void mono_register_config_for_assembly (const char* assembly_name, cons static bool Target64BitApplication () { // Should probably handled the --cross and sdk parameters. - return Environment.Is64BitProcess; + string targetArchitecture = GetEnv ("VSCMD_ARG_TGT_ARCH", ""); + if (targetArchitecture.Length != 0) { + if (string.Compare (targetArchitecture, "x64", StringComparison.OrdinalIgnoreCase) == 0) + return true; + else + return false; + } else { + return Environment.Is64BitProcess; + } } static string GetMonoDir () @@ -2560,6 +2597,13 @@ void mono_register_config_for_assembly (const char* assembly_name, cons linkerArgs.Add ("oldnames.lib"); } + if (MakeBundle.compress) { + if (staticLinkMono) + linkerArgs.Add("zlibstatic.lib"); + else + linkerArgs.Add("zlib.lib"); + } + return; } diff --git a/mcs/tools/mono-service/Makefile b/mcs/tools/mono-service/Makefile index e27822addc..b1c6d2f32e 100644 --- a/mcs/tools/mono-service/Makefile +++ b/mcs/tools/mono-service/Makefile @@ -6,11 +6,11 @@ PROGRAM = mono-service.exe PROGRAM_SNK = ../../class/mono.snk -include ../../build/executable.make - LOCAL_MCS_FLAGS = -unsafe -publicsign -keyfile:../../class/mono.snk LIB_REFS = System.ServiceProcess Mono.Posix System +include ../../build/executable.make + # Copied from library.make # -- begin -- diff --git a/mcs/tools/mono-symbolicate/Makefile b/mcs/tools/mono-symbolicate/Makefile index 440dfe9f8e..38a345454e 100644 --- a/mcs/tools/mono-symbolicate/Makefile +++ b/mcs/tools/mono-symbolicate/Makefile @@ -45,7 +45,7 @@ PREPARE_OUTDIR = @\ mkdir -p $(MSYM_DIR); COMPILE = \ - $(CSCOMPILE) $(TEST_CS) -out:$(TEST_EXE); \ + $(CSCOMPILE) $(TEST_CS) -r:$(LIB_PATH)/mscorlib.dll -out:$(TEST_EXE); \ $(MONO) $(LIB_PATH)/$(PROGRAM) store-symbols $(MSYM_DIR) $(OUT_DIR); \ $(MONO) $(LIB_PATH)/$(PROGRAM) store-symbols $(MSYM_DIR) $(LIB_PATH); diff --git a/mcs/tools/security/Makefile b/mcs/tools/security/Makefile index be162957fa..b01c75796b 100644 --- a/mcs/tools/security/Makefile +++ b/mcs/tools/security/Makefile @@ -60,10 +60,10 @@ clean-local: dist-local: dist-default sn.exe $(topdir)/class/lib/$(PROFILE)/sn.exe: $(SN_SOURCES) - $(CSCOMPILE) -r:$(topdir)/class/lib/$(PROFILE)/Mono.Security.dll /out:$@ $(SN_SOURCES) + $(CSCOMPILE) -r:$(topdir)/class/lib/$(PROFILE)/mscorlib.dll -r:$(topdir)/class/lib/$(PROFILE)/Mono.Security.dll /out:$@ $(SN_SOURCES) permview.exe: permview.cs - $(CSCOMPILE) $^ $(HELPER_SOURCES) -r:$(topdir)/class/lib/$(PROFILE)/Mono.Cecil.dll + $(CSCOMPILE) $^ $(HELPER_SOURCES) -r:$(topdir)/class/lib/$(PROFILE)/mscorlib.dll -r:$(topdir)/class/lib/$(PROFILE)/Mono.Cecil.dll %.exe: %.cs $(HELPER_SOURCES) - $(CSCOMPILE) -r:$(topdir)/class/lib/$(PROFILE)/Mono.Security.dll -r:$(topdir)/class/lib/$(PROFILE)/System.dll $^ + $(CSCOMPILE) -r:$(topdir)/class/lib/$(PROFILE)/mscorlib.dll -r:$(topdir)/class/lib/$(PROFILE)/Mono.Security.dll -r:$(topdir)/class/lib/$(PROFILE)/System.dll $^ diff --git a/mono/Makefile.in b/mono/Makefile.in index 2c93073733..2e483aec1c 100644 --- a/mono/Makefile.in +++ b/mono/Makefile.in @@ -83,8 +83,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -252,6 +250,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -270,7 +269,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -284,7 +282,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -398,7 +395,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ diff --git a/mono/arch/Makefile.am b/mono/arch/Makefile.am index a5c81d135e..14352283f2 100644 --- a/mono/arch/Makefile.am +++ b/mono/arch/Makefile.am @@ -4,7 +4,7 @@ AM_CPPFLAGS = $(GLIB_CFLAGS) -I$(top_srcdir) if ARM # arm needs to build some stuff even in JIT mode -SUBDIRS = $(arch_target) +SUBDIRS = arm endif diff --git a/mono/arch/Makefile.in b/mono/arch/Makefile.in index da76877813..d8992a11ff 100644 --- a/mono/arch/Makefile.in +++ b/mono/arch/Makefile.in @@ -83,8 +83,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -252,6 +250,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -270,7 +269,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -284,7 +282,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -398,7 +395,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ @@ -422,7 +418,7 @@ DIST_SUBDIRS = x86 ppc sparc arm arm64 s390x amd64 mips AM_CPPFLAGS = $(GLIB_CFLAGS) -I$(top_srcdir) # arm needs to build some stuff even in JIT mode -@ARM_TRUE@SUBDIRS = $(arch_target) +@ARM_TRUE@SUBDIRS = arm all: all-recursive .SUFFIXES: diff --git a/mono/arch/amd64/Makefile.in b/mono/arch/amd64/Makefile.in index 67b8096b91..5f7c2bc66b 100644 --- a/mono/arch/amd64/Makefile.in +++ b/mono/arch/amd64/Makefile.in @@ -83,8 +83,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -193,6 +191,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -211,7 +210,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -225,7 +223,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -339,7 +336,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ diff --git a/mono/arch/arm/Makefile.in b/mono/arch/arm/Makefile.in index 7119466673..4e830baabb 100644 --- a/mono/arch/arm/Makefile.in +++ b/mono/arch/arm/Makefile.in @@ -83,8 +83,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -193,6 +191,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -211,7 +210,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -225,7 +223,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -339,7 +336,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ diff --git a/mono/arch/arm64/Makefile.in b/mono/arch/arm64/Makefile.in index 81ec285c45..b1e4c2f038 100644 --- a/mono/arch/arm64/Makefile.in +++ b/mono/arch/arm64/Makefile.in @@ -83,8 +83,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -193,6 +191,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -211,7 +210,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -225,7 +223,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -339,7 +336,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ diff --git a/mono/arch/mips/Makefile.in b/mono/arch/mips/Makefile.in index c768afbb45..73dadee12e 100644 --- a/mono/arch/mips/Makefile.in +++ b/mono/arch/mips/Makefile.in @@ -86,8 +86,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs $(top_srcdir)/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -244,6 +242,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -262,7 +261,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -276,7 +274,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -390,7 +387,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ diff --git a/mono/arch/ppc/Makefile.in b/mono/arch/ppc/Makefile.in index 7d10e063f3..baff7ab438 100644 --- a/mono/arch/ppc/Makefile.in +++ b/mono/arch/ppc/Makefile.in @@ -83,8 +83,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -193,6 +191,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -211,7 +210,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -225,7 +223,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -339,7 +336,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ diff --git a/mono/arch/s390x/Makefile.in b/mono/arch/s390x/Makefile.in index e8e23415f2..9f880cf9fe 100644 --- a/mono/arch/s390x/Makefile.in +++ b/mono/arch/s390x/Makefile.in @@ -84,8 +84,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs $(top_srcdir)/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -238,6 +236,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -256,7 +255,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -270,7 +268,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -384,7 +381,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ diff --git a/mono/arch/s390x/s390x-codegen.h b/mono/arch/s390x/s390x-codegen.h index 9c3750e213..49fc120f7d 100644 --- a/mono/arch/s390x/s390x-codegen.h +++ b/mono/arch/s390x/s390x-codegen.h @@ -1197,8 +1197,10 @@ typedef struct { #define s390_cebr(c, r1, r2) S390_RRE(c, 0xb309, r1, r2) #define s390_cegbr(c, r1, r2) S390_RRE(c, 0xb3a4, r1, r2) #define s390_cfdbr(c, r1, m, r2) S390_RRF_2(c, 0xb399, r1, m, r2) +#define s390_cfebr(c, r1, m, r2) S390_RRF_2(c, 0xb398, r1, m, r2) #define s390_cfi(c, r, v) S390_RIL_1(c, 0xc2d, r, v) #define s390_cgdbr(c, r1, m, r2) S390_RRF_2(c, 0xb3a9, r1, m, r2) +#define s390_cgebr(c, r1, m, r2) S390_RRF_2(c, 0xb3a8, r1, m, r2) #define s390_cg(c, r, x, b, d) S390_RXY(c, 0xe320, r, x, b, d) #define s390_cgfi(c, r, v) S390_RIL_1(c, 0xc2c, r, v) #define s390_cgfrl(c, r, v) S390_RIL_1(c, 0xc6c, r, v) @@ -1216,11 +1218,13 @@ typedef struct { #define s390_cit(c, r, i, m) S390_RIE_4(c, 0xec72, r, i m); #define s390_cl(c, r, x, b, d) S390_RX(c, 0x55, r, x, b, d) #define s390_clfdbr(c, r1, m3, r2, m4) S390_RRF_4(c, 0xb39d, r1, m3, r2, m4) +#define s390_clfebr(c, r1, m3, r2, m4) S390_RRF_4(c, 0xb39c, r1, m3, r2, m4) #define s390_clg(c, r, x, b, d) S390_RXY(c, 0xe321, r, x, b, d) #define s390_clgib(c, r, i, m, b, d) S390_RIS(c, 0xecfd, r, i, m, b, d) #define s390_clgij(c, r, i, b) S390_RIE_3(c, 0xec7d, r, i, m, d) #define s390_clgr(c, r1, r2) S390_RRE(c, 0xb921, r1, r2) #define s390_clgdbr(c, r1, m3, r2, m4) S390_RRF_4(c, 0xb3ad, r1, m3, r2, m4) +#define s390_clgebr(c, r1, m3, r2, m4) S390_RRF_4(c, 0xb39c, r1, m3, r2, m4) #define s390_clgrj(c, r1, r2, m, v) S390_RIE_2(c, 0xec65, r1, r2, m, v) #define s390_clgrb(c, r1, r2, m3, b, d) S390_RRS(c, 0xece5, r1, r2, m3, b, d) #define s390_cli(c, b, d, v) S390_SI(c, 0x95, b, d, v) @@ -1243,6 +1247,7 @@ typedef struct { #define s390_ddbr(c, r1, r2) S390_RRE(c, 0xb31d, r1, r2) #define s390_debr(c, r1, r2) S390_RRE(c, 0xb30d, r1, r2) #define s390_didbr(c, r1, r2, m, r3) S390_RRF_3(c, 0xb35b, r1, r2, m, r3) +#define s390_diebr(c, r1, r2, m, r3) S390_RRF_3(c, 0xb353, r1, r2, m, r3) #define s390_dlgr(c, r1, r2) S390_RRE(c, 0xb987, r1, r2) #define s390_dlr(c, r1, r2) S390_RRE(c, 0xb997, r1, r2) #define s390_dr(c, r1, r2) S390_RR(c, 0x1d, r1, r2) @@ -1310,6 +1315,7 @@ typedef struct { #define s390_lb(c, r, x, b, d) S390_RXY(c, 0xe376, r, x, b, d) #define s390_lbr(c, r1, r2) S390_RRE(c, 0xb926, r1, r2) #define s390_lcdbr(c, r1, r2) S390_RRE(c, 0xb313, r1, r2) +#define s390_lcebr(c, r1, r2) S390_RRE(c, 0xb303, r1, r2) #define s390_lcgr(c, r1, r2) S390_RRE(c, 0xb903, r1, r2) #define s390_lcr(c, r1, r2) S390_RR(c, 0x13, r1, r2) #define s390_ld(c, f, x, b, d) S390_RX(c, 0x68, f, x, b, d) @@ -1317,6 +1323,7 @@ typedef struct { #define s390_ldeb(c, r, x, b, d) S390_RXE(c, 0xed04, r, x, b, d) #define s390_ldebr(c, r1, r2) S390_RRE(c, 0xb304, r1, r2) #define s390_ldgr(c, r1, r2) S390_RRE(c, 0xb3c1, r1, r2) +#define s390_ldgr(c, r1, r2) S390_RRE(c, 0xb3c1, r1, r2) #define s390_ldxbr(c, r1, r2) S390_RRE(c, 0xb345, r1, r2) #define s390_ldr(c, r1, r2) S390_RR(c, 0x28, r1, r2) #define s390_le(c, f, x, b, d) S390_RX(c, 0x78, f, x, b, d) @@ -1377,7 +1384,7 @@ typedef struct { #define s390_lzer(c, r) S390_RRE(c, 0xb374, r, 0) #define s390_m(c, r, x, b, d) S390_RX(c, 0x5c, r, x, b, d) #define s390_mdbr(c, r1, r2) S390_RRE(c, 0xb31c, r1, r2) -#define s390_meebr(c, r1, r2) S390_RRE(c, 0xb317, r1, r2) +#define s390_meer(c, r1, r2) S390_RRE(c, 0xb317, r1, r2) #define s390_mg(c, r, x, b, d) S390_RXY(c, 0xe384, r, x, b, d) #define s390_mgh(c, r, x, b, d) S390_RXY(c, 0xe33c, r, x, b, d) #define s390_mgrk(c, r1, r2, r3) S390_RRF_1(c, 0xb9ec, r1, r2, r3) diff --git a/mono/arch/sparc/Makefile.in b/mono/arch/sparc/Makefile.in index 0ecc093ad6..6639824d6e 100644 --- a/mono/arch/sparc/Makefile.in +++ b/mono/arch/sparc/Makefile.in @@ -83,8 +83,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -193,6 +191,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -211,7 +210,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -225,7 +223,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -339,7 +336,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ diff --git a/mono/arch/x86/Makefile.in b/mono/arch/x86/Makefile.in index 4bb025053e..6fc1474ff2 100644 --- a/mono/arch/x86/Makefile.in +++ b/mono/arch/x86/Makefile.in @@ -83,8 +83,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -193,6 +191,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -211,7 +210,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -225,7 +223,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -339,7 +336,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ diff --git a/mono/benchmark/Makefile.in b/mono/benchmark/Makefile.in index cf7f697168..12a76ec42b 100644 --- a/mono/benchmark/Makefile.in +++ b/mono/benchmark/Makefile.in @@ -83,8 +83,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -193,6 +191,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -211,7 +210,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -225,7 +223,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -339,7 +336,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ diff --git a/mono/btls/Makefile.in b/mono/btls/Makefile.in index 84bb7502f1..e9cb713329 100644 --- a/mono/btls/Makefile.in +++ b/mono/btls/Makefile.in @@ -83,8 +83,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -193,6 +191,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -211,7 +210,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -225,7 +223,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -339,7 +336,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ diff --git a/mono/cil/Makefile.in b/mono/cil/Makefile.in index c66e4e7101..0873c7df89 100644 --- a/mono/cil/Makefile.in +++ b/mono/cil/Makefile.in @@ -84,8 +84,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs TODO ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -223,6 +221,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -241,7 +240,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -255,7 +253,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -369,7 +366,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ diff --git a/mono/dis/Makefile.am b/mono/dis/Makefile.am index c4327b6ce5..19890cf54b 100644 --- a/mono/dis/Makefile.am +++ b/mono/dis/Makefile.am @@ -16,7 +16,7 @@ runtime_lib= \ $(metadata_lib) \ $(gc_lib) \ $(top_builddir)/mono/utils/libmonoutils.la \ - $(GLIB_LIBS) $(LIBICONV) + $(GLIB_LIBS) if DISABLE_EXECUTABLES bin_PROGRAMS = @@ -51,8 +51,7 @@ monodis_LDADD = \ $(runtime_lib) \ $(LLVM_LIBS) \ $(LLVM_LDFLAGS) \ - $(GLIB_LIBS) \ - $(LIBICONV) + $(GLIB_LIBS) if HOST_DARWIN monodis_LDFLAGS=-framework CoreFoundation -framework Foundation diff --git a/mono/dis/Makefile.in b/mono/dis/Makefile.in index c933dc4de5..c95779d814 100644 --- a/mono/dis/Makefile.in +++ b/mono/dis/Makefile.in @@ -86,8 +86,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs $(top_srcdir)/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -120,10 +118,10 @@ am__DEPENDENCIES_1 = @SUPPORT_SGEN_TRUE@ $(top_builddir)/mono/sgen/libmonosgen.la am__DEPENDENCIES_3 = $(metadata_lib) $(am__DEPENDENCIES_2) \ $(top_builddir)/mono/utils/libmonoutils.la \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) + $(am__DEPENDENCIES_1) monodis_DEPENDENCIES = libmonodis.a $(am__DEPENDENCIES_3) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) + $(am__DEPENDENCIES_1) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent @@ -294,6 +292,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -312,7 +311,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -326,7 +324,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -440,7 +437,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ @@ -469,7 +465,7 @@ runtime_lib = \ $(metadata_lib) \ $(gc_lib) \ $(top_builddir)/mono/utils/libmonoutils.la \ - $(GLIB_LIBS) $(LIBICONV) + $(GLIB_LIBS) noinst_LIBRARIES = libmonodis.a libmonodis_a_SOURCES = \ @@ -493,8 +489,7 @@ monodis_LDADD = \ $(runtime_lib) \ $(LLVM_LIBS) \ $(LLVM_LDFLAGS) \ - $(GLIB_LIBS) \ - $(LIBICONV) + $(GLIB_LIBS) @HOST_DARWIN_TRUE@monodis_LDFLAGS = -framework CoreFoundation -framework Foundation man_MANS = monodis.1 diff --git a/mono/dis/dump.c b/mono/dis/dump.c index 4c2ba81e48..75042891ed 100755 --- a/mono/dis/dump.c +++ b/mono/dis/dump.c @@ -578,14 +578,14 @@ dump_table_method (MonoImage *m) mono_metadata_string_heap (m, mono_metadata_decode_row_col (td, current_type - 2, MONO_TYPEDEF_NAMESPACE)), mono_metadata_string_heap (m, mono_metadata_decode_row_col (td, current_type - 2, MONO_TYPEDEF_NAME))); first_m = last_m; - type_container = mono_metadata_load_generic_params (m, MONO_TOKEN_TYPE_DEF | (current_type - 1), NULL); + type_container = mono_metadata_load_generic_params (m, MONO_TOKEN_TYPE_DEF | (current_type - 1), NULL, NULL); if (type_container) { mono_metadata_load_generic_param_constraints_checked (m, MONO_TOKEN_TYPE_DEF | (current_type - 1), type_container, error); g_assert (mono_error_ok (error)); /*FIXME don't swallow the error message*/ } } - method_container = mono_metadata_load_generic_params (m, MONO_TOKEN_METHOD_DEF | i, type_container); + method_container = mono_metadata_load_generic_params (m, MONO_TOKEN_METHOD_DEF | i, type_container, NULL); if (method_container) { mono_metadata_load_generic_param_constraints_checked (m, MONO_TOKEN_METHOD_DEF | i, method_container, error); g_assert (mono_error_ok (error)); /*FIXME don't swallow the error message*/ diff --git a/mono/dis/get.c.REMOVED.git-id b/mono/dis/get.c.REMOVED.git-id index c5290b8409..ecbd45fc58 100644 --- a/mono/dis/get.c.REMOVED.git-id +++ b/mono/dis/get.c.REMOVED.git-id @@ -1 +1 @@ -f0247e05d9b430386d42086bb29a1d6b0a2cfa2d \ No newline at end of file +dfd5267f8314d8d180dde022fa54a6177f585b1d \ No newline at end of file diff --git a/mono/dis/main.c b/mono/dis/main.c index 972e156b6f..2fea57dc9e 100644 --- a/mono/dis/main.c +++ b/mono/dis/main.c @@ -858,7 +858,7 @@ dis_method_list (const char *klass_name, MonoImage *m, guint32 start, guint32 en sig = mono_metadata_blob_heap (m, cols [MONO_METHOD_SIGNATURE]); mono_metadata_decode_blob_size (sig, &sig); - container = mono_metadata_load_generic_params (m, MONO_TOKEN_METHOD_DEF | (i + 1), type_container); + container = mono_metadata_load_generic_params (m, MONO_TOKEN_METHOD_DEF | (i + 1), type_container, NULL); if (container) { ERROR_DECL (error); mono_metadata_load_generic_param_constraints_checked (m, MONO_TOKEN_METHOD_DEF | (i + 1), container, error); @@ -1201,7 +1201,7 @@ dis_type (MonoImage *m, int n, int is_nested, int forward) g_free (esnspace); } - container = mono_metadata_load_generic_params (m, MONO_TOKEN_TYPE_DEF | (n + 1), NULL); + container = mono_metadata_load_generic_params (m, MONO_TOKEN_TYPE_DEF | (n + 1), NULL, NULL); if (container) { ERROR_DECL (error); mono_metadata_load_generic_param_constraints_checked (m, MONO_TOKEN_TYPE_DEF | (n + 1), container, error); diff --git a/mono/eglib/Makefile.am b/mono/eglib/Makefile.am index 87051a6be1..1e5d2ca864 100644 --- a/mono/eglib/Makefile.am +++ b/mono/eglib/Makefile.am @@ -52,11 +52,13 @@ libeglib_la_CFLAGS = -g -Wall -D_FORTIFY_SOURCE=2 -D_GNU_SOURCE AM_CPPFLAGS = -I$(srcdir) -if HOST_WIN32 -libeglib_la_LIBADD = -lm $(LIBICONV) -lpsapi -else if HOST_ANDROID libeglib_la_LIBADD = -llog +else +if HOST_WIN32 +libeglib_la_LIBADD = -lm -lpsapi $(LTLIBICONV) +else +libeglib_la_LIBADD = $(LTLIBICONV) endif endif diff --git a/mono/eglib/Makefile.in b/mono/eglib/Makefile.in index 2e0c5da320..5f7e251f7b 100644 --- a/mono/eglib/Makefile.in +++ b/mono/eglib/Makefile.in @@ -85,8 +85,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -99,8 +97,7 @@ CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = eglib-config.h CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) -am__DEPENDENCIES_1 = -@HOST_WIN32_TRUE@libeglib_la_DEPENDENCIES = $(am__DEPENDENCIES_1) +libeglib_la_DEPENDENCIES = am__libeglib_la_SOURCES_DIST = eglib-remap.h sort.frag.h glib.h \ garray.c gbytearray.c gerror.c ghashtable.c giconv.c gmem.c \ gmodule.h goutput.c gqsort.c gstr.c gslist.c gstring.c \ @@ -273,6 +270,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -291,7 +289,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -305,7 +302,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -419,7 +415,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ @@ -485,8 +480,9 @@ libeglib_la_SOURCES = \ libeglib_la_CFLAGS = -g -Wall -D_FORTIFY_SOURCE=2 -D_GNU_SOURCE AM_CPPFLAGS = -I$(srcdir) -@HOST_ANDROID_TRUE@@HOST_WIN32_FALSE@libeglib_la_LIBADD = -llog -@HOST_WIN32_TRUE@libeglib_la_LIBADD = -lm $(LIBICONV) -lpsapi +@HOST_ANDROID_FALSE@@HOST_WIN32_FALSE@libeglib_la_LIBADD = $(LTLIBICONV) +@HOST_ANDROID_FALSE@@HOST_WIN32_TRUE@libeglib_la_LIBADD = -lm -lpsapi $(LTLIBICONV) +@HOST_ANDROID_TRUE@libeglib_la_LIBADD = -llog MAINTAINERCLEANFILES = Makefile.in EXTRA_DIST = eglib-config.h.in $(win_files) $(unix_files) all: all-am diff --git a/mono/eglib/eglib-remap.h b/mono/eglib/eglib-remap.h index 15dc4bb0bb..417a8c28dd 100644 --- a/mono/eglib/eglib-remap.h +++ b/mono/eglib/eglib-remap.h @@ -243,6 +243,9 @@ #define g_usleep monoeg_g_usleep #define g_utf16_to_ucs4 monoeg_g_utf16_to_ucs4 #define g_utf16_to_utf8 monoeg_g_utf16_to_utf8 +#define g_utf16_ascii_equal monoeg_g_utf16_ascii_equal +#define g_utf16_asciiz_equal monoeg_g_utf16_asciiz_equal +#define g_utf8_jump_table monoeg_g_utf8_jump_table #define g_utf8_get_char monoeg_g_utf8_get_char #define g_utf8_offset_to_pointer monoeg_g_utf8_offset_to_pointer #define g_utf8_pointer_to_offset monoeg_g_utf8_pointer_to_offset diff --git a/mono/eglib/gfile-unix.c b/mono/eglib/gfile-unix.c index a91a25f441..3aacf9fb44 100644 --- a/mono/eglib/gfile-unix.c +++ b/mono/eglib/gfile-unix.c @@ -79,27 +79,32 @@ g_file_test (const gchar *filename, GFileTest test) return FALSE; } -#ifdef _AIX -/* HACK: the preprocessor will not give us mkdtemp no matter - what and Mono (for good reason) does - "-Werror-implicit-function-declaration" so we error out; - instead declare mkdtemp here; the linker will find mkdtemp - anwyays. libuv has had similar issues, but they just ignore - the compiler warning instead of failing on it. - - See: github.com/libuv/libuv/pull/740 */ - -extern char *mkdtemp(char *); -#endif - gchar * g_mkdtemp (char *tmp_template) { -#ifdef HAVE_MKDTEMP +/* + * On systems without mkdtemp, use a reimplemented version + * adapted from the Win32 version of this file. AIX is an + * exception because i before version 7.2 lacks mkdtemp in + * libc, and GCC can "fix" system headers so that it isn't + * present without redefining it. + */ +#if defined(HAVE_MKDTEMP) && !defined(_AIX) char *template_copy = g_strdup (tmp_template); return mkdtemp (template_copy); #else - g_error("Function mkdtemp not supported"); + char *template = g_strdup (tmp_template); + + template = mktemp(template); + if (template && *template) { + /* 0700 is the mode specified in specs */ + if (mkdir (template, 0700) == 0){ + return template; + } + } + + g_free (template); + return NULL; #endif } diff --git a/mono/eglib/glib.h b/mono/eglib/glib.h index 46d01e4a23..a14c0b0231 100644 --- a/mono/eglib/glib.h +++ b/mono/eglib/glib.h @@ -107,6 +107,14 @@ typedef guint32 gunichar; #define ABS(a) ((a) > 0 ? (a) : -(a)) #endif +#ifndef ALIGN_TO +#define ALIGN_TO(val,align) ((((gssize)val) + ((align) - 1)) & ~((align) - 1)) +#endif + +#ifndef ALIGN_PTR_TO +#define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1))) +#endif + #define G_STRUCT_OFFSET(p_type,field) offsetof(p_type,field) #define EGLIB_STRINGIFY(x) #x @@ -721,12 +729,8 @@ GUnicodeBreakType g_unichar_break_type (gunichar c); #define eg_unreachable() #endif -/* Old version. Preserved for testing and history. */ - /* g_assert is a boolean expression; the precise value is not preserved, just true or false. */ -#define g_assert(x) \ - (G_LIKELY(x) ? 1 : (g_assertion_message ( \ - "* Assertion at %s:%d, condition `%s' not met\n", __FILE__, __LINE__, #x), 0)) +#define g_assert(x) (G_LIKELY((x)) ? 1 : (g_assertion_message ("* Assertion at %s:%d, condition `%s' not met\n", __FILE__, __LINE__, #x), 0)) #define g_assert_not_reached() G_STMT_START { g_assertion_message ("* Assertion: should not be reached at %s:%d\n", __FILE__, __LINE__); eg_unreachable(); } G_STMT_END @@ -747,10 +751,11 @@ GUnicodeBreakType g_unichar_break_type (gunichar c); * format must be a string literal, in order to be concatenated. * If this is too restrictive, g_error remains. */ -#define g_assertf(x, format, ...) \ - (G_LIKELY(x) ? 1 : (g_assertion_message ( \ - "* Assertion at %s:%d, condition `%s' not met, function:%s, " format "\n", \ - __FILE__, __LINE__, #x, __func__, __VA_ARGS__), 0)) +#if defined(_MSC_VER) && (_MSC_VER < 1910) +#define g_assertf(x, format, ...) (G_LIKELY((x)) ? 1 : (g_assertion_message ("* Assertion at %s:%d, condition `%s' not met, function:%s, " format "\n", __FILE__, __LINE__, #x, __func__, __VA_ARGS__), 0)) +#else +#define g_assertf(x, format, ...) (G_LIKELY((x)) ? 1 : (g_assertion_message ("* Assertion at %s:%d, condition `%s' not met, function:%s, " format "\n", __FILE__, __LINE__, #x, __func__, ##__VA_ARGS__), 0)) +#endif /* * Unicode conversion @@ -909,10 +914,33 @@ GFileError g_file_error_from_errno (gint err_no); gint g_file_open_tmp (const gchar *tmpl, gchar **name_used, GError **gerror); gboolean g_file_test (const gchar *filename, GFileTest test); +#ifdef G_OS_WIN32 +#define g_open _open +#else #define g_open open +#endif #define g_rename rename #define g_stat stat +#ifdef G_OS_WIN32 +#define g_access _access +#else +#define g_access access +#endif +#ifdef G_OS_WIN32 +#define g_mktemp _mktemp +#else +#define g_mktemp mktemp +#endif +#ifdef G_OS_WIN32 +#define g_unlink _unlink +#else #define g_unlink unlink +#endif +#ifdef G_OS_WIN32 +#define g_write _write +#else +#define g_write write +#endif #define g_fopen fopen #define g_lstat lstat #define g_rmdir rmdir diff --git a/mono/eglib/gpath.c b/mono/eglib/gpath.c index 21e7770460..aca33e45e9 100644 --- a/mono/eglib/gpath.c +++ b/mono/eglib/gpath.c @@ -251,11 +251,13 @@ g_find_program_in_path (const gchar *program) x = NULL; probe_path = g_build_path (G_DIR_SEPARATOR_S, l, program, NULL); - if (access (probe_path, X_OK) == 0){ /* FIXME: on windows this is just a read permissions test */ +#ifdef HAVE_ACCESS + if (g_access (probe_path, X_OK) == 0){ /* FIXME: on windows this is just a read permissions test */ g_free (curdir); g_free (p); return probe_path; } +#endif g_free (probe_path); #ifdef G_OS_WIN32 @@ -265,12 +267,14 @@ g_find_program_in_path (const gchar *program) while (suffix_list[listx]) { program_exe = g_strjoin(NULL,program,suffix_list[listx],NULL); probe_path = g_build_path (G_DIR_SEPARATOR_S, l, program_exe, NULL); - if (access (probe_path, X_OK) == 0){ /* FIXME: on windows this is just a read permissions test */ +#ifdef HAVE_ACCESS + if (g_access (probe_path, X_OK) == 0){ /* FIXME: on windows this is just a read permissions test */ g_free (curdir); g_free (p); g_free (program_exe); return probe_path; } +#endif listx++; g_free (probe_path); g_free (program_exe); diff --git a/mono/eglib/gunicode-win32.c b/mono/eglib/gunicode-win32.c index a35cfcd48c..c6033eae37 100644 --- a/mono/eglib/gunicode-win32.c +++ b/mono/eglib/gunicode-win32.c @@ -11,21 +11,21 @@ #define CODESET 1 #include -extern const char *my_charset; +extern const char *eg_my_charset; static gboolean is_utf8; gboolean g_get_charset (G_CONST_RETURN char **charset) { - if (my_charset == NULL) { + if (eg_my_charset == NULL) { static char buf [14]; sprintf (buf, "CP%u", GetACP ()); - my_charset = buf; + eg_my_charset = buf; is_utf8 = FALSE; } if (charset != NULL) - *charset = my_charset; + *charset = eg_my_charset; return is_utf8; } diff --git a/mono/eglib/gunicode.c b/mono/eglib/gunicode.c index 2c76c7c970..69d02cd963 100644 --- a/mono/eglib/gunicode.c +++ b/mono/eglib/gunicode.c @@ -45,7 +45,7 @@ # endif #endif -const char *my_charset; +const char *eg_my_charset; /* * Character set conversion @@ -206,18 +206,18 @@ static gboolean is_utf8; gboolean g_get_charset (G_CONST_RETURN char **charset) { - if (my_charset == NULL) { + if (eg_my_charset == NULL) { /* These shouldn't be heap allocated */ #if defined(HAVE_LOCALCHARSET_H) - my_charset = locale_charset (); + eg_my_charset = locale_charset (); #else - my_charset = "UTF-8"; + eg_my_charset = "UTF-8"; #endif - is_utf8 = strcmp (my_charset, "UTF-8") == 0; + is_utf8 = strcmp (eg_my_charset, "UTF-8") == 0; } if (charset != NULL) - *charset = my_charset; + *charset = eg_my_charset; return is_utf8; } @@ -228,7 +228,7 @@ g_locale_to_utf8 (const gchar *opsysstring, gssize len, gsize *bytes_read, gsize { g_get_charset (NULL); - return g_convert (opsysstring, len, "UTF-8", my_charset, bytes_read, bytes_written, gerror); + return g_convert (opsysstring, len, "UTF-8", eg_my_charset, bytes_read, bytes_written, gerror); } gchar * @@ -236,5 +236,5 @@ g_locale_from_utf8 (const gchar *utf8string, gssize len, gsize *bytes_read, gsiz { g_get_charset (NULL); - return g_convert (utf8string, len, my_charset, "UTF-8", bytes_read, bytes_written, gerror); + return g_convert (utf8string, len, eg_my_charset, "UTF-8", bytes_read, bytes_written, gerror); } diff --git a/mono/metadata/Makefile.am b/mono/metadata/Makefile.am index 6b17dee4dc..665b2cd230 100644 --- a/mono/metadata/Makefile.am +++ b/mono/metadata/Makefile.am @@ -182,8 +182,12 @@ common_sources = \ attach.c \ cil-coff.h \ class.c \ + class-getters.h \ + class-init.h \ + class-init.c \ class-internals.h \ class-inlines.h \ + class-private-definition.h \ class-accessors.c \ cominterop.c \ cominterop.h \ @@ -313,6 +317,7 @@ common_sources = \ file-mmap.h \ object-offsets.h \ abi-details.h \ + class-abi-details.h \ metadata-cross-helpers.c \ seq-points-data.h \ seq-points-data.c \ @@ -388,6 +393,7 @@ libmonoruntimeinclude_HEADERS = \ mono-debug.h \ mono-gc.h \ object.h \ + object-forward.h \ opcodes.h \ profiler.h \ profiler-events.h \ diff --git a/mono/metadata/Makefile.in.REMOVED.git-id b/mono/metadata/Makefile.in.REMOVED.git-id index c2bc050320..ab084894fc 100644 --- a/mono/metadata/Makefile.in.REMOVED.git-id +++ b/mono/metadata/Makefile.in.REMOVED.git-id @@ -1 +1 @@ -2d5717007116890444130260e939df68297131e2 \ No newline at end of file +751e5e26b200266ae8e9421e9c06178570254a22 \ No newline at end of file diff --git a/mono/metadata/appdomain.c b/mono/metadata/appdomain.c index dfb72166b3..8e98befc5c 100644 --- a/mono/metadata/appdomain.c +++ b/mono/metadata/appdomain.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include "mono/metadata/metadata-internals.h" #include @@ -234,7 +235,7 @@ create_domain_objects (MonoDomain *domain) * This class is used during exception handling, so initialize it here, to prevent * stack overflows while handling stack overflows. */ - mono_class_init (mono_array_class_get (mono_defaults.int_class, 1)); + mono_class_init (mono_class_create_array (mono_defaults.int_class, 1)); } /** @@ -490,7 +491,7 @@ mono_domain_create_appdomain_checked (char *friendly_name, char *configuration_f MonoDomain *result = NULL; MonoClass *klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup"); - MonoAppDomainSetupHandle setup = MONO_HANDLE_NEW (MonoAppDomainSetup, mono_object_new_checked (mono_domain_get (), klass, error)); + MonoAppDomainSetupHandle setup = (MonoAppDomainSetupHandle)mono_object_new_handle (mono_domain_get (), klass, error); goto_if_nok (error, leave); MonoStringHandle config_file; if (configuration_file != NULL) { @@ -559,7 +560,7 @@ copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetupHandle setup, MonoE caller_domain = mono_domain_get (); ads_class = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup"); - MonoAppDomainSetupHandle copy = MONO_HANDLE_NEW (MonoAppDomainSetup, mono_object_new_checked (domain, ads_class, error)); + MonoAppDomainSetupHandle copy = (MonoAppDomainSetupHandle)mono_object_new_handle(domain, ads_class, error); goto_if_nok (error, leave); mono_domain_set_internal (domain); @@ -623,7 +624,7 @@ mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetupHa /* FIXME: pin all those objects */ data = mono_domain_create(); - MonoAppDomainHandle ad = MONO_HANDLE_NEW (MonoAppDomain, mono_object_new_checked (data, adclass, error)); + MonoAppDomainHandle ad = (MonoAppDomainHandle)mono_object_new_handle (data, adclass, error); goto_if_nok (error, leave); MONO_HANDLE_SETVAL (ad, data, MonoDomain*, data); data->domain = MONO_HANDLE_RAW (ad); @@ -1229,7 +1230,7 @@ mono_try_assembly_resolve_handle (MonoDomain *domain, MonoStringHandle fname, Mo if (ret && !refonly && ret->ref_only) { /* .NET Framework throws System.IO.FileNotFoundException in this case */ - mono_error_set_file_not_found (error, "AssemblyResolveEvent handlers cannot return Assemblies loaded for reflection only"); + mono_error_set_file_not_found (error, NULL, "AssemblyResolveEvent handlers cannot return Assemblies loaded for reflection only"); ret = NULL; goto leave; } @@ -2204,9 +2205,9 @@ ves_icall_System_Reflection_Assembly_LoadFrom (MonoStringHandle fname, MonoBoole if (!ass) { if (status == MONO_IMAGE_IMAGE_INVALID) - mono_error_set_bad_image_name (error, g_strdup (name), ""); + mono_error_set_bad_image_by_name (error, name, "Invalid Image"); else - mono_error_set_assembly_load (error, g_strdup (name), "%s", ""); + mono_error_set_file_not_found (error, name, "Invalid Image"); goto leave; } @@ -2246,7 +2247,7 @@ ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomainHandle ad, MonoImage *image = mono_image_open_from_data_full (assembly_data, raw_assembly_len, FALSE, NULL, refonly); if (!image) { - mono_error_set_bad_image_name (error, g_strdup (""), "%s", ""); + mono_error_set_bad_image_by_name (error, "In memory assembly", "0x%p", raw_data); return refass; } @@ -2263,7 +2264,7 @@ ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomainHandle ad, if (!ass) { mono_image_close (image); - mono_error_set_bad_image_name (error, g_strdup (""), "%s", ""); + mono_error_set_bad_image_by_name (error, "In Memory assembly", "0x%p", assembly_data); return refass; } @@ -2539,10 +2540,10 @@ clear_cached_vtable (MonoVTable *vtable) MonoClassRuntimeInfo *runtime_info; void *data; - runtime_info = klass->runtime_info; + runtime_info = m_class_get_runtime_info (klass); if (runtime_info && runtime_info->max_domain >= domain->domain_id) runtime_info->domain_vtables [domain->domain_id] = NULL; - if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable))) + if (m_class_has_static_refs (klass) && (data = mono_vtable_get_static_field_data (vtable))) mono_gc_free_fixed (data); } @@ -2552,7 +2553,7 @@ zero_static_data (MonoVTable *vtable) MonoClass *klass = vtable->klass; void *data; - if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable))) + if (m_class_has_static_refs (klass) && (data = mono_vtable_get_static_field_data (vtable))) mono_gc_bzero_aligned (data, mono_class_data_size (klass)); } diff --git a/mono/metadata/appdomain.h b/mono/metadata/appdomain.h index 9d42bdda49..99227f0f7e 100644 --- a/mono/metadata/appdomain.h +++ b/mono/metadata/appdomain.h @@ -145,7 +145,7 @@ MONO_API int32_t mono_context_get_domain_id (MonoAppContext *context); MONO_API MonoJitInfo * -mono_jit_info_table_find (MonoDomain *domain, char *addr); +mono_jit_info_table_find (MonoDomain *domain, void* addr); /* MonoJitInfo accessors */ diff --git a/mono/metadata/assembly.c.REMOVED.git-id b/mono/metadata/assembly.c.REMOVED.git-id index b77ca01749..32fb4d5366 100644 --- a/mono/metadata/assembly.c.REMOVED.git-id +++ b/mono/metadata/assembly.c.REMOVED.git-id @@ -1 +1 @@ -c77f190da2f5f4cbd04a2d9208da50400ec851d7 \ No newline at end of file +9f49eda52fe1c7559833769a8e1bfc7ebc7fa5dd \ No newline at end of file diff --git a/mono/metadata/boehm-gc.c b/mono/metadata/boehm-gc.c index f8c945a709..2169b55f65 100644 --- a/mono/metadata/boehm-gc.c +++ b/mono/metadata/boehm-gc.c @@ -40,6 +40,7 @@ #include #include + #if HAVE_BOEHM_GC #undef TRUE @@ -194,7 +195,7 @@ mono_gc_base_init (void) if (!strcmp (opt, "do-not-finalize")) { mono_do_not_finalize = 1; } else if (!strcmp (opt, "log-finalizers")) { - log_finalizers = 1; + mono_log_finalizers = 1; } } g_free (env); @@ -462,7 +463,7 @@ on_gc_notification (GC_EventType event) if (mono_perfcounters) mono_atomic_inc_i32 (&mono_perfcounters->gc_collections0); #endif - mono_atomic_inc_i32 (&gc_stats.major_gc_count); + mono_atomic_inc_i32 (&mono_gc_stats.major_gc_count); gc_start_time = mono_100ns_ticks (); break; @@ -487,7 +488,7 @@ on_gc_notification (GC_EventType event) UnlockedWrite64 (&mono_perfcounters->gc_gen0size, heap_size); } #endif - UnlockedAdd64 (&gc_stats.major_gc_time, mono_100ns_ticks () - gc_start_time); + UnlockedAdd64 (&mono_gc_stats.major_gc_time, mono_100ns_ticks () - gc_start_time); mono_trace_message (MONO_TRACE_GC, "gc took %" G_GINT64_FORMAT " usecs", (mono_100ns_ticks () - gc_start_time) / 10); break; default: @@ -613,7 +614,7 @@ static void mono_push_other_roots (void) { g_hash_table_foreach (roots, push_root, NULL); - FOREACH_THREAD (info) { + FOREACH_THREAD_EXCLUDE (info, MONO_THREAD_INFO_FLAGS_NO_GC) { HandleStack* stack = (HandleStack*)info->handle_stack; if (stack) push_handle_stack (stack); @@ -720,7 +721,7 @@ mono_gc_alloc_obj (MonoVTable *vtable, size_t size) { MonoObject *obj; - if (!vtable->klass->has_references) { + if (!m_class_has_references (vtable->klass)) { obj = (MonoObject *)GC_MALLOC_ATOMIC (size); if (G_UNLIKELY (!obj)) return NULL; @@ -752,7 +753,7 @@ mono_gc_alloc_vector (MonoVTable *vtable, size_t size, uintptr_t max_length) { MonoArray *obj; - if (!vtable->klass->has_references) { + if (!m_class_has_references (vtable->klass)) { obj = (MonoArray *)GC_MALLOC_ATOMIC (size); if (G_UNLIKELY (!obj)) return NULL; @@ -786,7 +787,7 @@ mono_gc_alloc_array (MonoVTable *vtable, size_t size, uintptr_t max_length, uint { MonoArray *obj; - if (!vtable->klass->has_references) { + if (!m_class_has_references (vtable->klass)) { obj = (MonoArray *)GC_MALLOC_ATOMIC (size); if (G_UNLIKELY (!obj)) return NULL; @@ -913,7 +914,7 @@ mono_gc_wbarrier_object_copy (MonoObject* obj, MonoObject *src) { /* do not copy the sync state */ mono_gc_memmove_aligned ((char*)obj + sizeof (MonoObject), (char*)src + sizeof (MonoObject), - mono_object_class (obj)->instance_size - sizeof (MonoObject)); + m_class_get_instance_size (mono_object_class (obj)) - sizeof (MonoObject)); } void @@ -991,13 +992,13 @@ create_allocator (int atype, int tls_key, gboolean slowpath) csig = mono_metadata_signature_alloc (mono_defaults.corlib, 2); if (atype == ATYPE_STRING) { - csig->ret = &mono_defaults.string_class->byval_arg; - csig->params [0] = &mono_defaults.int_class->byval_arg; - csig->params [1] = &mono_defaults.int32_class->byval_arg; + csig->ret = m_class_get_byval_arg (mono_defaults.string_class); + csig->params [0] = m_class_get_byval_arg (mono_defaults.int_class); + csig->params [1] = m_class_get_byval_arg (mono_defaults.int32_class); } else { - csig->ret = &mono_defaults.object_class->byval_arg; - csig->params [0] = &mono_defaults.int_class->byval_arg; - csig->params [1] = &mono_defaults.int32_class->byval_arg; + csig->ret = m_class_get_byval_arg (mono_defaults.object_class); + csig->params [0] = m_class_get_byval_arg (mono_defaults.int_class); + csig->params [1] = m_class_get_byval_arg (mono_defaults.int32_class); } mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_ALLOC); @@ -1005,7 +1006,7 @@ create_allocator (int atype, int tls_key, gboolean slowpath) if (slowpath) goto always_slowpath; - bytes_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg); + bytes_var = mono_mb_add_local (mb, m_class_get_byval_arg (mono_defaults.int32_class)); if (atype == ATYPE_STRING) { /* a string alloator method takes the args: (vtable, len) */ /* bytes = (offsetof (MonoString, chars) + ((len + 1) * 2)); */ @@ -1037,7 +1038,7 @@ create_allocator (int atype, int tls_key, gboolean slowpath) } /* int index = INDEX_FROM_BYTES(bytes); */ - index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg); + index_var = mono_mb_add_local (mb, m_class_get_byval_arg (mono_defaults.int32_class)); mono_mb_emit_ldloc (mb, bytes_var); mono_mb_emit_icon (mb, GRANULARITY - 1); @@ -1049,8 +1050,8 @@ create_allocator (int atype, int tls_key, gboolean slowpath) /* index var is already adjusted into bytes */ mono_mb_emit_stloc (mb, index_var); - my_fl_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); - my_entry_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); + my_fl_var = mono_mb_add_local (mb, m_class_get_byval_arg (mono_defaults.int_class)); + my_entry_var = mono_mb_add_local (mb, m_class_get_byval_arg (mono_defaults.int_class)); /* my_fl = ((GC_thread)tsd) -> ptrfree_freelists + index; */ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); mono_mb_emit_byte (mb, 0x0D); /* CEE_MONO_TLS */ @@ -1099,8 +1100,8 @@ create_allocator (int atype, int tls_key, gboolean slowpath) int start_var, end_var, start_loop; /* end = my_entry + bytes; start = my_entry + sizeof (gpointer); */ - start_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); - end_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); + start_var = mono_mb_add_local (mb, m_class_get_byval_arg (mono_defaults.int_class)); + end_var = mono_mb_add_local (mb, m_class_get_byval_arg (mono_defaults.int_class)); mono_mb_emit_ldloc (mb, my_entry_var); mono_mb_emit_ldloc (mb, bytes_var); mono_mb_emit_byte (mb, MONO_CEE_ADD); @@ -1220,21 +1221,21 @@ mono_gc_get_managed_allocator (MonoClass *klass, gboolean for_box, gboolean know */ return NULL; - if (!SMALL_ENOUGH (klass->instance_size)) + if (!SMALL_ENOUGH (m_class_get_instance_size (klass))) return NULL; if (mono_class_has_finalizer (klass) || mono_class_is_marshalbyref (klass)) return NULL; if (G_UNLIKELY (mono_profiler_allocations_enabled ())) return NULL; - if (klass->rank) + if (m_class_get_rank (klass)) return NULL; - if (mono_class_is_open_constructed_type (&klass->byval_arg)) + if (mono_class_is_open_constructed_type (m_class_get_byval_arg (klass))) return NULL; - if (klass->byval_arg.type == MONO_TYPE_STRING) { + if (m_class_get_byval_arg (klass)->type == MONO_TYPE_STRING) { atype = ATYPE_STRING; } else if (!known_instance_size) { return NULL; - } else if (!klass->has_references) { + } else if (!m_class_has_references (klass)) { if (for_box) atype = ATYPE_FREEPTR_FOR_BOX; else @@ -1480,12 +1481,27 @@ mono_gc_set_stack_end (void *stack_end) { } -void mono_gc_set_skip_thread (gboolean value) +void +mono_gc_skip_thread_changing (gboolean skip) +{ + /* + * Unlike SGen, Boehm doesn't respect our thread info flags. We need to + * inform Boehm manually to skip/not skip the current thread. + */ + + if (skip) + GC_start_blocking (); + else + GC_end_blocking (); +} + +void +mono_gc_skip_thread_changed (gboolean skip) { } void -mono_gc_register_for_finalization (MonoObject *obj, void *user_data) +mono_gc_register_for_finalization (MonoObject *obj, MonoFinalizationProc user_data) { guint offset = 0; diff --git a/mono/metadata/callspec.c b/mono/metadata/callspec.c index f2301e2c38..91937af926 100644 --- a/mono/metadata/callspec.c +++ b/mono/metadata/callspec.c @@ -39,8 +39,8 @@ mono_callspec_eval_exception (MonoClass *klass, MonoCallSpec *spec) strcmp ("all", op->data2) == 0) inc = 1; else if (strcmp ("", op->data) == 0 || - strcmp (klass->name_space, op->data) == 0) - if (strcmp (klass->name, op->data2) == 0) + strcmp (m_class_get_name_space (klass), op->data) == 0) + if (strcmp (m_class_get_name (klass), op->data2) == 0) inc = 1; break; default: @@ -73,7 +73,7 @@ gboolean mono_callspec_eval (MonoMethod *method, const MonoCallSpec *spec) break; case MONO_TRACEOP_PROGRAM: if (prog_assembly && - (method->klass->image == + (m_class_get_image (method->klass) == mono_assembly_get_image (prog_assembly))) inc = 1; break; @@ -94,18 +94,18 @@ gboolean mono_callspec_eval (MonoMethod *method, const MonoCallSpec *spec) inc = 1; break; case MONO_TRACEOP_CLASS: - if (strcmp (method->klass->name_space, op->data) == 0) - if (strcmp (method->klass->name, op->data2) == + if (strcmp (m_class_get_name_space (method->klass), op->data) == 0) + if (strcmp (m_class_get_name (method->klass), op->data2) == 0) inc = 1; break; case MONO_TRACEOP_ASSEMBLY: - if (strcmp (mono_image_get_name (method->klass->image), + if (strcmp (mono_image_get_name (m_class_get_image (method->klass)), op->data) == 0) inc = 1; break; case MONO_TRACEOP_NAMESPACE: - if (strcmp (method->klass->name_space, op->data) == 0) + if (strcmp (m_class_get_name_space (method->klass), op->data) == 0) inc = 1; break; case MONO_TRACEOP_EXCEPTION: diff --git a/mono/metadata/class-abi-details.h b/mono/metadata/class-abi-details.h new file mode 100644 index 0000000000..495f00f6e0 --- /dev/null +++ b/mono/metadata/class-abi-details.h @@ -0,0 +1,23 @@ +/** + * \file Declarations of MonoClass field offset functions + * Copyright 2018 Microsoft + * Licensed under the MIT license. See LICENSE file in the project root for full license information. + */ +#ifndef __MONO_METADATA_CLASS_ABI_DETAILS_H__ +#define __MONO_METADATA_CLASS_ABI_DETAILS_H__ + +#include +#include + +#define MONO_CLASS_GETTER(funcname, rettype, optref, argtype, fieldname) /*nothing*/ +#ifdef MONO_CLASS_DEF_PRIVATE +#define MONO_CLASS_OFFSET(funcname, argtype, fieldname) intptr_t funcname (void); +#else +#define MONO_CLASS_OFFSET(funcname, argtype, fieldname) static inline intptr_t funcname (void) { return MONO_STRUCT_OFFSET (argtype, fieldname); } +#endif +#include "class-getters.h" +#undef MONO_CLASS_GETTER +#undef MONO_CLASS_OFFSET + +#endif /* __MONO_METADATA_CLASS_ABI_DETAILS_H__ */ + diff --git a/mono/metadata/class-accessors.c b/mono/metadata/class-accessors.c index 189cfbba3f..ad3ec667bc 100644 --- a/mono/metadata/class-accessors.c +++ b/mono/metadata/class-accessors.c @@ -5,8 +5,15 @@ */ #include #include +#include #include - +#include +#ifdef MONO_CLASS_DEF_PRIVATE +#include +#define REALLY_INCLUDE_CLASS_DEF 1 +#include +#undef REALLY_INCLUDE_CLASS_DEF +#endif typedef enum { PROP_MARSHAL_INFO = 1, /* MonoMarshalType */ @@ -17,7 +24,8 @@ typedef enum { PROP_EVENT_INFO = 6, /* MonoClassEventInfo* */ PROP_FIELD_DEF_VALUES = 7, /* MonoFieldDefaultValue* */ PROP_DECLSEC_FLAGS = 8, /* guint32 */ - PROP_WEAK_BITMAP = 9 + PROP_WEAK_BITMAP = 9, + PROP_DIM_CONFLICTS = 10 /* GSList of MonoMethod* */ } InfrequentDataKind; /* Accessors based on class kind*/ @@ -31,7 +39,7 @@ MonoGenericClass* mono_class_get_generic_class (MonoClass *klass) { g_assert (mono_class_is_ginst (klass)); - return ((MonoClassGenericInst*)klass)->generic_class; + return m_classgenericinst_get_generic_class ((MonoClassGenericInst*)klass); } /* @@ -43,7 +51,7 @@ MonoGenericClass* mono_class_try_get_generic_class (MonoClass *klass) { if (mono_class_is_ginst (klass)) - return ((MonoClassGenericInst*)klass)->generic_class; + return m_classgenericinst_get_generic_class ((MonoClassGenericInst*)klass); return NULL; } @@ -56,19 +64,19 @@ mono_class_try_get_generic_class (MonoClass *klass) guint32 mono_class_get_flags (MonoClass *klass) { - switch (klass->class_kind) { + switch (m_class_get_class_kind (klass)) { case MONO_CLASS_DEF: case MONO_CLASS_GTD: - return ((MonoClassDef*)klass)->flags; + return m_classdef_get_flags ((MonoClassDef*)klass); case MONO_CLASS_GINST: - return mono_class_get_flags (((MonoClassGenericInst*)klass)->generic_class->container_class); + return mono_class_get_flags (m_classgenericinst_get_generic_class ((MonoClassGenericInst*)klass)->container_class); case MONO_CLASS_GPARAM: return TYPE_ATTRIBUTE_PUBLIC; case MONO_CLASS_ARRAY: /* all arrays are marked serializable and sealed, bug #42779 */ return TYPE_ATTRIBUTE_CLASS | TYPE_ATTRIBUTE_SERIALIZABLE | TYPE_ATTRIBUTE_SEALED | TYPE_ATTRIBUTE_PUBLIC; case MONO_CLASS_POINTER: - return TYPE_ATTRIBUTE_CLASS | (mono_class_get_flags (klass->element_class) & TYPE_ATTRIBUTE_VISIBILITY_MASK); + return TYPE_ATTRIBUTE_CLASS | (mono_class_get_flags (m_class_get_element_class (klass)) & TYPE_ATTRIBUTE_VISIBILITY_MASK); } g_assert_not_reached (); } @@ -76,7 +84,7 @@ mono_class_get_flags (MonoClass *klass) void mono_class_set_flags (MonoClass *klass, guint32 flags) { - g_assert (klass->class_kind == MONO_CLASS_DEF || klass->class_kind == MONO_CLASS_GTD); + g_assert (m_class_get_class_kind (klass) == MONO_CLASS_DEF || m_class_get_class_kind (klass) == MONO_CLASS_GTD); ((MonoClassDef*)klass)->flags = flags; } @@ -90,18 +98,17 @@ mono_class_get_generic_container (MonoClass *klass) { g_assert (mono_class_is_gtd (klass)); - return ((MonoClassGtd*)klass)->generic_container; + return m_classgtd_get_generic_container ((MonoClassGtd*)klass); } MonoGenericContainer* mono_class_try_get_generic_container (MonoClass *klass) { if (mono_class_is_gtd (klass)) - return ((MonoClassGtd*)klass)->generic_container; + return m_classgtd_get_generic_container ((MonoClassGtd*)klass); return NULL; } - void mono_class_set_generic_container (MonoClass *klass, MonoGenericContainer *container) { @@ -120,7 +127,7 @@ mono_class_get_first_method_idx (MonoClass *klass) { g_assert (mono_class_has_static_metadata (klass)); - return ((MonoClassDef*)klass)->first_method_idx; + return m_classdef_get_first_method_idx ((MonoClassDef*)klass); } void @@ -137,15 +144,15 @@ mono_class_get_first_field_idx (MonoClass *klass) if (mono_class_is_ginst (klass)) return mono_class_get_first_field_idx (mono_class_get_generic_class (klass)->container_class); - g_assert (mono_class_has_static_metadata (klass)); + g_assert (klass->type_token && !mono_class_is_ginst (klass)); - return ((MonoClassDef*)klass)->first_field_idx; + return m_classdef_get_first_field_idx ((MonoClassDef*)klass); } void mono_class_set_first_field_idx (MonoClass *klass, guint32 idx) { - g_assert (mono_class_has_static_metadata (klass)); + g_assert (klass->type_token && !mono_class_is_ginst (klass)); ((MonoClassDef*)klass)->first_field_idx = idx; } @@ -153,16 +160,16 @@ mono_class_set_first_field_idx (MonoClass *klass, guint32 idx) guint32 mono_class_get_method_count (MonoClass *klass) { - switch (klass->class_kind) { + switch (m_class_get_class_kind (klass)) { case MONO_CLASS_DEF: case MONO_CLASS_GTD: - return ((MonoClassDef*)klass)->method_count; + return m_classdef_get_method_count ((MonoClassDef*)klass); case MONO_CLASS_GINST: - return mono_class_get_method_count (((MonoClassGenericInst*)klass)->generic_class->container_class); + return mono_class_get_method_count (m_classgenericinst_get_generic_class ((MonoClassGenericInst*)klass)->container_class); case MONO_CLASS_GPARAM: return 0; case MONO_CLASS_ARRAY: - return ((MonoClassArray*)klass)->method_count; + return m_classarray_get_method_count ((MonoClassArray*)klass); case MONO_CLASS_POINTER: return 0; default: @@ -174,7 +181,7 @@ mono_class_get_method_count (MonoClass *klass) void mono_class_set_method_count (MonoClass *klass, guint32 count) { - switch (klass->class_kind) { + switch (m_class_get_class_kind (klass)) { case MONO_CLASS_DEF: case MONO_CLASS_GTD: ((MonoClassDef*)klass)->method_count = count; @@ -197,12 +204,12 @@ mono_class_set_method_count (MonoClass *klass, guint32 count) guint32 mono_class_get_field_count (MonoClass *klass) { - switch (klass->class_kind) { + switch (m_class_get_class_kind (klass)) { case MONO_CLASS_DEF: case MONO_CLASS_GTD: - return ((MonoClassDef*)klass)->field_count; + return m_classdef_get_field_count ((MonoClassDef*)klass); case MONO_CLASS_GINST: - return mono_class_get_field_count (((MonoClassGenericInst*)klass)->generic_class->container_class); + return mono_class_get_field_count (m_classgenericinst_get_generic_class ((MonoClassGenericInst*)klass)->container_class); case MONO_CLASS_GPARAM: case MONO_CLASS_ARRAY: case MONO_CLASS_POINTER: @@ -216,7 +223,7 @@ mono_class_get_field_count (MonoClass *klass) void mono_class_set_field_count (MonoClass *klass, guint32 count) { - switch (klass->class_kind) { + switch (m_class_get_class_kind (klass)) { case MONO_CLASS_DEF: case MONO_CLASS_GTD: ((MonoClassDef*)klass)->field_count = count; @@ -237,14 +244,14 @@ mono_class_set_field_count (MonoClass *klass, guint32 count) MonoMarshalType* mono_class_get_marshal_info (MonoClass *klass) { - return mono_property_bag_get (&klass->infrequent_data, PROP_MARSHAL_INFO); + return mono_property_bag_get (m_class_get_infrequent_data (klass), PROP_MARSHAL_INFO); } void mono_class_set_marshal_info (MonoClass *klass, MonoMarshalType *marshal_info) { marshal_info->head.tag = PROP_MARSHAL_INFO; - mono_property_bag_add (&klass->infrequent_data, marshal_info); + mono_property_bag_add (m_class_get_infrequent_data (klass), marshal_info); } typedef struct { @@ -255,7 +262,7 @@ typedef struct { guint32 mono_class_get_ref_info_handle (MonoClass *klass) { - Uint32Property *prop = mono_property_bag_get (&klass->infrequent_data, PROP_REF_INFO_HANDLE); + Uint32Property *prop = mono_property_bag_get (m_class_get_infrequent_data (klass), PROP_REF_INFO_HANDLE); return prop ? prop->value : 0; } @@ -263,7 +270,7 @@ guint32 mono_class_set_ref_info_handle (MonoClass *klass, guint32 value) { if (!value) { - Uint32Property *prop = mono_property_bag_get (&klass->infrequent_data, PROP_REF_INFO_HANDLE); + Uint32Property *prop = mono_property_bag_get (m_class_get_infrequent_data (klass), PROP_REF_INFO_HANDLE); if (prop) prop->value = 0; return 0; @@ -272,7 +279,7 @@ mono_class_set_ref_info_handle (MonoClass *klass, guint32 value) Uint32Property *prop = mono_class_alloc (klass, sizeof (Uint32Property)); prop->head.tag = PROP_REF_INFO_HANDLE; prop->value = value; - prop = mono_property_bag_add (&klass->infrequent_data, prop); + prop = mono_property_bag_add (m_class_get_infrequent_data (klass), prop); return prop->value; } @@ -287,13 +294,13 @@ set_pointer_property (MonoClass *klass, InfrequentDataKind property, gpointer va PointerProperty *prop = mono_class_alloc (klass, sizeof (PointerProperty)); prop->head.tag = property; prop->value = value; - mono_property_bag_add (&klass->infrequent_data, prop); + mono_property_bag_add (m_class_get_infrequent_data (klass), prop); } static gpointer get_pointer_property (MonoClass *klass, InfrequentDataKind property) { - PointerProperty *prop = (PointerProperty*)mono_property_bag_get (&klass->infrequent_data, property); + PointerProperty *prop = (PointerProperty*)mono_property_bag_get (m_class_get_infrequent_data (klass), property); return prop ? prop->value : NULL; } @@ -324,27 +331,27 @@ mono_class_set_nested_classes_property (MonoClass *klass, GList *value) MonoClassPropertyInfo* mono_class_get_property_info (MonoClass *klass) { - return mono_property_bag_get (&klass->infrequent_data, PROP_PROPERTY_INFO); + return mono_property_bag_get (m_class_get_infrequent_data (klass), PROP_PROPERTY_INFO); } void mono_class_set_property_info (MonoClass *klass, MonoClassPropertyInfo *info) { info->head.tag = PROP_PROPERTY_INFO; - mono_property_bag_add (&klass->infrequent_data, info); + mono_property_bag_add (m_class_get_infrequent_data (klass), info); } MonoClassEventInfo* mono_class_get_event_info (MonoClass *klass) { - return mono_property_bag_get (&klass->infrequent_data, PROP_EVENT_INFO); + return mono_property_bag_get (m_class_get_infrequent_data (klass), PROP_EVENT_INFO); } void mono_class_set_event_info (MonoClass *klass, MonoClassEventInfo *info) { info->head.tag = PROP_EVENT_INFO; - mono_property_bag_add (&klass->infrequent_data, info); + mono_property_bag_add (m_class_get_infrequent_data (klass), info); } MonoFieldDefaultValue* @@ -362,7 +369,7 @@ mono_class_set_field_def_values (MonoClass *klass, MonoFieldDefaultValue *values guint32 mono_class_get_declsec_flags (MonoClass *klass) { - Uint32Property *prop = mono_property_bag_get (&klass->infrequent_data, PROP_DECLSEC_FLAGS); + Uint32Property *prop = mono_property_bag_get (m_class_get_infrequent_data (klass), PROP_DECLSEC_FLAGS); return prop ? prop->value : 0; } @@ -372,7 +379,7 @@ mono_class_set_declsec_flags (MonoClass *klass, guint32 value) Uint32Property *prop = mono_class_alloc (klass, sizeof (Uint32Property)); prop->head.tag = PROP_DECLSEC_FLAGS; prop->value = value; - mono_property_bag_add (&klass->infrequent_data, prop); + mono_property_bag_add (m_class_get_infrequent_data (klass), prop); } void @@ -389,7 +396,7 @@ MonoType* mono_class_gtd_get_canonical_inst (MonoClass *klass) { g_assert (mono_class_is_gtd (klass)); - return &((MonoClassGtd*)klass)->canonical_inst; + return m_classgtd_get_canonical_inst ((MonoClassGtd*)klass); } typedef struct { @@ -407,15 +414,140 @@ mono_class_set_weak_bitmap (MonoClass *klass, int nbits, gsize *bits) info->bits = bits; info->head.tag = PROP_WEAK_BITMAP; - mono_property_bag_add (&klass->infrequent_data, info); + mono_property_bag_add (m_class_get_infrequent_data (klass), info); } gsize* mono_class_get_weak_bitmap (MonoClass *klass, int *nbits) { - WeakBitmapData *prop = mono_property_bag_get (&klass->infrequent_data, PROP_WEAK_BITMAP); + WeakBitmapData *prop = mono_property_bag_get (m_class_get_infrequent_data (klass), PROP_WEAK_BITMAP); g_assert (prop); *nbits = prop->nbits; return prop->bits; } + +gboolean +mono_class_has_dim_conflicts (MonoClass *klass) +{ + if (klass->has_dim_conflicts) + return TRUE; + + if (mono_class_is_ginst (klass)) { + MonoClass *gklass = mono_class_get_generic_class (klass)->container_class; + + return gklass->has_dim_conflicts; + } + + return FALSE; +} + +typedef struct { + MonoPropertyBagItem head; + + GSList *data; +} DimConflictData; + +void +mono_class_set_dim_conflicts (MonoClass *klass, GSList *conflicts) +{ + DimConflictData *info = mono_class_alloc (klass, sizeof (DimConflictData)); + info->data = conflicts; + + g_assert (!mono_class_is_ginst (klass)); + + info->head.tag = PROP_DIM_CONFLICTS; + mono_property_bag_add (&klass->infrequent_data, info); +} + +GSList* +mono_class_get_dim_conflicts (MonoClass *klass) +{ + if (mono_class_is_ginst (klass)) + return mono_class_get_dim_conflicts (mono_class_get_generic_class (klass)->container_class); + + DimConflictData *info = mono_property_bag_get (&klass->infrequent_data, PROP_DIM_CONFLICTS); + + g_assert (info); + return info->data; +} + +/** + * mono_class_set_failure: + * \param klass class in which the failure was detected + * \param ex_type the kind of exception/error to be thrown (later) + * \param ex_data exception data (specific to each type of exception/error) + * + * Keep a detected failure informations in the class for later processing. + * Note that only the first failure is kept. + * + * LOCKING: Acquires the loader lock. + */ +gboolean +mono_class_set_failure (MonoClass *klass, MonoErrorBoxed *boxed_error) +{ + g_assert (boxed_error != NULL); + + if (mono_class_has_failure (klass)) + return FALSE; + + mono_loader_lock (); + klass->has_failure = 1; + mono_class_set_exception_data (klass, boxed_error); + mono_loader_unlock (); + + return TRUE; +} + +/** + * mono_class_set_nonblittable: + * \param klass class which will be marked as not blittable. + * + * Mark \c klass as not blittable. + * + * LOCKING: Acquires the loader lock. + */ +void +mono_class_set_nonblittable (MonoClass *klass) { + mono_loader_lock (); + klass->blittable = FALSE; + mono_loader_unlock (); +} + +#ifndef DISABLE_REMOTING +void +mono_class_contextbound_bit_offset (int* byte_offset_out, guint8* mask_out) { + mono_marshal_find_bitfield_offset (MonoClass, contextbound, byte_offset_out, mask_out); +} +#endif + +/** + * mono_class_publish_gc_descriptor: + * \param klass the \c MonoClass whose GC descriptor is to be set + * \param gc_descr the GC descriptor for \p klass + * + * Sets the \c gc_descr_inited and \c gc_descr fields of \p klass. + * \returns previous value of \c klass->gc_descr_inited + * + * LOCKING: Acquires the loader lock. + */ +gboolean +mono_class_publish_gc_descriptor (MonoClass *klass, MonoGCDescriptor gc_descr) +{ + gboolean ret; + mono_loader_lock (); + ret = klass->gc_descr_inited; + klass->gc_descr = gc_descr; + mono_memory_barrier (); + klass->gc_descr_inited = TRUE; + mono_loader_unlock (); + return ret; +} + +#ifdef MONO_CLASS_DEF_PRIVATE +#define MONO_CLASS_GETTER(funcname, rettype, optref, argtype, fieldname) rettype funcname (argtype *klass) { return optref klass-> fieldname ; } +#define MONO_CLASS_OFFSET(funcname, argtype, fieldname) intptr_t funcname (void) { return MONO_STRUCT_OFFSET (argtype, fieldname); } +#include "class-getters.h" +#undef MONO_CLASS_GETTER +#undef MONO_CLASS_OFFSET +#endif /* MONO_CLASS_DEF_PRIVATE */ diff --git a/mono/metadata/class-getters.h b/mono/metadata/class-getters.h new file mode 100644 index 0000000000..72abeb609b --- /dev/null +++ b/mono/metadata/class-getters.h @@ -0,0 +1,118 @@ +/* + * \file Definitions of getters for the fields of struct _MonoClass + * + * Copyright 2018 Microsoft + * Licensed under the MIT license. See LICENSE file in the project root for full license information. + */ + +/* No include guards - this file is meant to be included multiple times. + * Before including the file define the following macros: + * MONO_CLASS_GETTER(funcname, rettype, optref, argtype, fieldname) + * + * MONO_CLASS_OFFSET(funcname, argtype, fieldname) + */ + +/* Accessors for _MonoClass fields. */ +MONO_CLASS_GETTER(m_class_get_element_class, MonoClass *, , MonoClass, element_class) +MONO_CLASS_GETTER(m_class_get_cast_class, MonoClass *, , MonoClass, cast_class) +MONO_CLASS_GETTER(m_class_get_supertypes, MonoClass **, , MonoClass, supertypes) +MONO_CLASS_GETTER(m_class_get_idepth, guint16, , MonoClass, idepth) +MONO_CLASS_GETTER(m_class_get_rank, guint8, , MonoClass, rank) +MONO_CLASS_GETTER(m_class_get_instance_size, int, , MonoClass, instance_size) +MONO_CLASS_GETTER(m_class_is_inited, gboolean, , MonoClass, inited) +MONO_CLASS_GETTER(m_class_is_size_inited, gboolean, , MonoClass, size_inited) +MONO_CLASS_GETTER(m_class_is_valuetype, gboolean, , MonoClass, valuetype) +MONO_CLASS_GETTER(m_class_is_enumtype, gboolean, , MonoClass, enumtype) +MONO_CLASS_GETTER(m_class_is_blittable, gboolean, , MonoClass, blittable) +MONO_CLASS_GETTER(m_class_is_unicode, gboolean, , MonoClass, unicode) +MONO_CLASS_GETTER(m_class_was_typebuilder, gboolean, , MonoClass, wastypebuilder) +MONO_CLASS_GETTER(m_class_is_array_special_interface, gboolean, , MonoClass, is_array_special_interface) +MONO_CLASS_GETTER(m_class_get_min_align, guint8, , MonoClass, min_align) +MONO_CLASS_GETTER(m_class_get_packing_size, guint, , MonoClass, packing_size) +MONO_CLASS_GETTER(m_class_is_ghcimpl, gboolean, , MonoClass, ghcimpl) +MONO_CLASS_GETTER(m_class_has_finalize, gboolean, , MonoClass, has_finalize) +#ifndef DISABLE_REMOTING +MONO_CLASS_GETTER(m_class_get_marshalbyref, guint, , MonoClass, marshalbyref) +MONO_CLASS_GETTER(m_class_get_contextbound, guint, , MonoClass, contextbound) +#endif +MONO_CLASS_GETTER(m_class_is_delegate, gboolean, , MonoClass, delegate) +MONO_CLASS_GETTER(m_class_is_gc_descr_inited, gboolean, , MonoClass, gc_descr_inited) +MONO_CLASS_GETTER(m_class_has_cctor, gboolean, , MonoClass, has_cctor) +MONO_CLASS_GETTER(m_class_has_references, gboolean, , MonoClass, has_references) +MONO_CLASS_GETTER(m_class_has_static_refs, gboolean, , MonoClass, has_static_refs) +MONO_CLASS_GETTER(m_class_has_no_special_static_fields, gboolean, , MonoClass, no_special_static_fields) +MONO_CLASS_GETTER(m_class_is_com_object, gboolean, , MonoClass, is_com_object) +MONO_CLASS_GETTER(m_class_is_nested_classes_inited, gboolean, , MonoClass, nested_classes_inited) +MONO_CLASS_GETTER(m_class_get_class_kind, guint, , MonoClass, class_kind) +MONO_CLASS_GETTER(m_class_is_interfaces_inited, gboolean, , MonoClass, interfaces_inited) +MONO_CLASS_GETTER(m_class_is_simd_type, gboolean, , MonoClass, simd_type) +MONO_CLASS_GETTER(m_class_is_has_finalize_inited, gboolean, , MonoClass, has_finalize_inited) +MONO_CLASS_GETTER(m_class_is_fields_inited, gboolean, , MonoClass, fields_inited) +MONO_CLASS_GETTER(m_class_has_failure, gboolean, , MonoClass, has_failure) +MONO_CLASS_GETTER(m_class_has_weak_fields, gboolean, , MonoClass, has_weak_fields) +MONO_CLASS_GETTER(m_class_has_dim_conflicts, gboolean, , MonoClass, has_dim_conflicts) +MONO_CLASS_GETTER(m_class_get_parent, MonoClass *, , MonoClass, parent) +MONO_CLASS_GETTER(m_class_get_nested_in, MonoClass *, , MonoClass, nested_in) +MONO_CLASS_GETTER(m_class_get_image, MonoImage *, , MonoClass, image) +MONO_CLASS_GETTER(m_class_get_name, const char *, , MonoClass, name) +MONO_CLASS_GETTER(m_class_get_name_space, const char *, , MonoClass, name_space) +MONO_CLASS_GETTER(m_class_get_type_token, guint32, , MonoClass, type_token) +MONO_CLASS_GETTER(m_class_get_vtable_size, int, , MonoClass, vtable_size) +MONO_CLASS_GETTER(m_class_get_interface_count, guint16, , MonoClass, interface_count) +MONO_CLASS_GETTER(m_class_get_interface_id, guint32, , MonoClass, interface_id) +MONO_CLASS_GETTER(m_class_get_max_interface_id, guint32, , MonoClass, max_interface_id) +MONO_CLASS_GETTER(m_class_get_interface_offsets_count, guint16, , MonoClass, interface_offsets_count) +MONO_CLASS_GETTER(m_class_get_interfaces_packed, MonoClass **, , MonoClass, interfaces_packed) +MONO_CLASS_GETTER(m_class_get_interface_offsets_packed, guint16 *, , MonoClass, interface_offsets_packed) +MONO_CLASS_GETTER(m_class_get_interface_bitmap, guint8 *, , MonoClass, interface_bitmap) +MONO_CLASS_GETTER(m_class_get_interfaces, MonoClass **, , MonoClass, interfaces) +MONO_CLASS_GETTER(m_class_get_sizes, union _MonoClassSizes, , MonoClass, sizes) +MONO_CLASS_GETTER(m_class_get_fields, MonoClassField *, , MonoClass, fields) +MONO_CLASS_GETTER(m_class_get_methods, MonoMethod **, , MonoClass, methods) +MONO_CLASS_GETTER(m_class_get_this_arg, MonoType*, &, MonoClass, this_arg) +MONO_CLASS_GETTER(m_class_get_byval_arg, MonoType*, &, MonoClass, byval_arg) +MONO_CLASS_GETTER(m_class_get_gc_descr, MonoGCDescriptor, , MonoClass, gc_descr) +MONO_CLASS_GETTER(m_class_get_runtime_info, MonoClassRuntimeInfo *, , MonoClass, runtime_info) +MONO_CLASS_GETTER(m_class_get_vtable, MonoMethod **, , MonoClass, vtable) +MONO_CLASS_GETTER(m_class_get_infrequent_data, MonoPropertyBag*, &, MonoClass, infrequent_data) + +/* Accessors for _MonoClassDef fields. */ +MONO_CLASS_GETTER(m_classdef_get_klass, MonoClass*, &, MonoClassDef, klass) +MONO_CLASS_GETTER(m_classdef_get_flags, guint32, , MonoClassDef, flags) +MONO_CLASS_GETTER(m_classdef_get_first_method_idx, guint32, , MonoClassDef, first_method_idx) +MONO_CLASS_GETTER(m_classdef_get_first_field_idx, guint32, , MonoClassDef, first_field_idx) +MONO_CLASS_GETTER(m_classdef_get_method_count, guint32, , MonoClassDef, method_count) +MONO_CLASS_GETTER(m_classdef_get_field_count, guint32, , MonoClassDef, field_count) +MONO_CLASS_GETTER(m_classdef_get_next_class_cache, MonoClass **, &, MonoClassDef, next_class_cache) + +/* Accessors for _MonoClassGtd fields. */ +MONO_CLASS_GETTER(m_classgtd_get_klass, MonoClassDef*, &, MonoClassGtd, klass) +MONO_CLASS_GETTER(m_classgtd_get_generic_container, MonoGenericContainer*, , MonoClassGtd, generic_container) +MONO_CLASS_GETTER(m_classgtd_get_canonical_inst, MonoType*, &, MonoClassGtd, canonical_inst) + +/* Accessors for _MonoClassGenericInst fields. */ +MONO_CLASS_GETTER(m_classgenericinst_get_klass, MonoClass*, &, MonoClassGenericInst, klass) +MONO_CLASS_GETTER(m_classgenericinst_get_generic_class, MonoGenericClass*, , MonoClassGenericInst, generic_class) + +/* Accessors for _MonoClassGenericParam fields. */ +MONO_CLASS_GETTER(m_classgenericparam_get_klass, MonoClass*, &, MonoClassGenericParam, klass) + +/* Accessors for _MonoClassArray fields. */ +MONO_CLASS_GETTER(m_classarray_get_klass, MonoClass*, &, MonoClassArray, klass) +MONO_CLASS_GETTER(m_classarray_get_method_count, guint32, , MonoClassArray, method_count) + +/* Accessors for _MonoClassPointer fields. */ +MONO_CLASS_GETTER(m_classpointer_get_klass, MonoClass*, &, MonoClassPointer, klass) + +MONO_CLASS_OFFSET(m_class_offsetof_interface_bitmap, MonoClass, interface_bitmap) +MONO_CLASS_OFFSET(m_class_offsetof_byval_arg, MonoClass, byval_arg) +MONO_CLASS_OFFSET(m_class_offsetof_cast_class, MonoClass, cast_class) +MONO_CLASS_OFFSET(m_class_offsetof_element_class, MonoClass, element_class) +MONO_CLASS_OFFSET(m_class_offsetof_idepth, MonoClass, idepth) +MONO_CLASS_OFFSET(m_class_offsetof_instance_size, MonoClass, instance_size) +MONO_CLASS_OFFSET(m_class_offsetof_interface_id, MonoClass, interface_id) +MONO_CLASS_OFFSET(m_class_offsetof_max_interface_id, MonoClass, max_interface_id) +MONO_CLASS_OFFSET(m_class_offsetof_parent, MonoClass, parent) +MONO_CLASS_OFFSET(m_class_offsetof_rank, MonoClass, rank) +MONO_CLASS_OFFSET(m_class_offsetof_sizes, MonoClass, sizes) +MONO_CLASS_OFFSET(m_class_offsetof_supertypes, MonoClass, supertypes) diff --git a/mono/metadata/class-init.c.REMOVED.git-id b/mono/metadata/class-init.c.REMOVED.git-id new file mode 100644 index 0000000000..13fb29269b --- /dev/null +++ b/mono/metadata/class-init.c.REMOVED.git-id @@ -0,0 +1 @@ +bc29775573a3734622f6f328342e8639438e8f61 \ No newline at end of file diff --git a/mono/metadata/class-init.h b/mono/metadata/class-init.h new file mode 100644 index 0000000000..075fdfe76d --- /dev/null +++ b/mono/metadata/class-init.h @@ -0,0 +1,92 @@ +/** + * \file + * Copyright 2018 Microsoft + * Licensed under the MIT license. See LICENSE file in the project root for full license information. + */ +#ifndef __MONO_METADATA_CLASS_INIT_H__ +#define __MONO_METADATA_CLASS_INIT_H__ + +#include +#include +#include + +MONO_BEGIN_DECLS + +void +mono_classes_init (void); + +void +mono_classes_cleanup (void); + +MonoClass * +mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError *error); + +MonoClass* +mono_class_create_generic_inst (MonoGenericClass *gclass); + +MonoClass * +mono_class_create_bounded_array (MonoClass *element_class, uint32_t rank, mono_bool bounded); + +MonoClass * +mono_class_create_array (MonoClass *element_class, uint32_t rank); + +MonoClass * +mono_class_create_generic_parameter (MonoGenericParam *param); + +MonoClass * +mono_class_create_ptr (MonoType *type); + +MonoClass * +mono_class_create_fnptr (MonoMethodSignature *sig); + +void +mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int onum, GList *in_setup); + +void +mono_class_init_sizes (MonoClass *klass); + +void +mono_class_setup_basic_field_info (MonoClass *klass); + +void +mono_class_setup_fields (MonoClass *klass); + +void +mono_class_setup_methods (MonoClass *klass); + +void +mono_class_setup_properties (MonoClass *klass); + +void +mono_class_setup_events (MonoClass *klass); + +void +mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_size, int real_size, gboolean sre); + +void +mono_class_setup_interface_offsets (MonoClass *klass); + +void +mono_class_setup_vtable (MonoClass *klass); + +void +mono_class_setup_parent (MonoClass *klass, MonoClass *parent); + +void +mono_class_setup_mono_type (MonoClass *klass); + +void +mono_class_setup_has_finalizer (MonoClass *klass); + +void +mono_class_setup_nested_types (MonoClass *klass); + +void +mono_class_setup_runtime_info (MonoClass *klass, MonoDomain *domain, MonoVTable *vtable); + +MonoClass * +mono_class_create_array_fill_type (void); + +MONO_END_DECLS + +#endif diff --git a/mono/metadata/class-inlines.h b/mono/metadata/class-inlines.h index d57d5310cc..44f128bef8 100644 --- a/mono/metadata/class-inlines.h +++ b/mono/metadata/class-inlines.h @@ -12,37 +12,37 @@ static inline gboolean mono_class_is_def (MonoClass *klass) { - return klass->class_kind == MONO_CLASS_DEF; + return m_class_get_class_kind (klass) == MONO_CLASS_DEF; } static inline gboolean mono_class_is_gtd (MonoClass *klass) { - return klass->class_kind == MONO_CLASS_GTD; + return m_class_get_class_kind (klass) == MONO_CLASS_GTD; } static inline gboolean mono_class_is_ginst (MonoClass *klass) { - return klass->class_kind == MONO_CLASS_GINST; + return m_class_get_class_kind (klass) == MONO_CLASS_GINST; } static inline gboolean mono_class_is_gparam (MonoClass *klass) { - return klass->class_kind == MONO_CLASS_GPARAM; + return m_class_get_class_kind (klass) == MONO_CLASS_GPARAM; } static inline gboolean mono_class_is_array (MonoClass *klass) { - return klass->class_kind == MONO_CLASS_ARRAY; + return m_class_get_class_kind (klass) == MONO_CLASS_ARRAY; } static inline gboolean mono_class_is_pointer (MonoClass *klass) { - return klass->class_kind == MONO_CLASS_POINTER; + return m_class_get_class_kind (klass) == MONO_CLASS_POINTER; } static inline gboolean @@ -90,7 +90,7 @@ mono_class_is_public (MonoClass *klass) static inline gboolean mono_class_has_static_metadata (MonoClass *klass) { - return klass->type_token && !klass->image->dynamic && !mono_class_is_ginst (klass); + return m_class_get_type_token (klass) && !m_class_get_image (klass)->dynamic && !mono_class_is_ginst (klass); } #endif diff --git a/mono/metadata/class-internals.h b/mono/metadata/class-internals.h index dc27745aef..4270eecb06 100644 --- a/mono/metadata/class-internals.h +++ b/mono/metadata/class-internals.h @@ -15,9 +15,9 @@ #include "mono/utils/mono-error.h" #include "mono/sgen/gc-internal-agnostic.h" -#define MONO_CLASS_IS_ARRAY(c) ((c)->rank) +#define MONO_CLASS_IS_ARRAY(c) (m_class_get_rank (c)) -#define MONO_CLASS_HAS_STATIC_METADATA(klass) ((klass)->type_token && !(klass)->image->dynamic && !mono_class_is_ginst (klass)) +#define MONO_CLASS_HAS_STATIC_METADATA(klass) (m_class_get_type_token (klass) && !m_class_get_image (klass)->dynamic && !mono_class_is_ginst (klass)) #define MONO_DEFAULT_SUPERTABLE_SIZE 6 @@ -261,167 +261,48 @@ typedef enum { MONO_CLASS_POINTER, /* pointer of function pointer*/ } MonoTypeKind; -struct _MonoClass { - /* element class for arrays and enum basetype for enums */ - MonoClass *element_class; - /* used for subtype checks */ - MonoClass *cast_class; +typedef struct _MonoClassDef MonoClassDef; +typedef struct _MonoClassGtd MonoClassGtd; +typedef struct _MonoClassGenericInst MonoClassGenericInst; +typedef struct _MonoClassGenericParam MonoClassGenericParam; +typedef struct _MonoClassArray MonoClassArray; +typedef struct _MonoClassPointer MonoClassPointer; - /* for fast subtype checks */ - MonoClass **supertypes; - guint16 idepth; +union _MonoClassSizes { + int class_size; /* size of area for static fields */ + int element_size; /* for array types */ + int generic_param_token; /* for generic param types, both var and mvar */ +}; - /* array dimension */ - guint8 rank; - - int instance_size; /* object instance size */ - - guint inited : 1; - - /* A class contains static and non static data. Static data can be - * of the same type as the class itselfs, but it does not influence - * the instance size of the class. To avoid cyclic calls to - * mono_class_init (from mono_class_instance_size ()) we first - * initialise all non static fields. After that we set size_inited - * to 1, because we know the instance size now. After that we - * initialise all static fields. - */ - - /* ALL BITFIELDS SHOULD BE WRITTEN WHILE HOLDING THE LOADER LOCK */ - guint size_inited : 1; - guint valuetype : 1; /* derives from System.ValueType */ - guint enumtype : 1; /* derives from System.Enum */ - guint blittable : 1; /* class is blittable */ - guint unicode : 1; /* class uses unicode char when marshalled */ - guint wastypebuilder : 1; /* class was created at runtime from a TypeBuilder */ - guint is_array_special_interface : 1; /* gtd or ginst of once of the magic interfaces that arrays implement */ - - /* next byte */ - guint8 min_align; - - /* next byte */ - guint packing_size : 4; - guint ghcimpl : 1; /* class has its own GetHashCode impl */ - guint has_finalize : 1; /* class has its own Finalize impl */ -#ifndef DISABLE_REMOTING - guint marshalbyref : 1; /* class is a MarshalByRefObject */ - guint contextbound : 1; /* class is a ContextBoundObject */ -#endif - /* next byte */ - guint delegate : 1; /* class is a Delegate */ - guint gc_descr_inited : 1; /* gc_descr is initialized */ - guint has_cctor : 1; /* class has a cctor */ - guint has_references : 1; /* it has GC-tracked references in the instance */ - guint has_static_refs : 1; /* it has static fields that are GC-tracked */ - guint no_special_static_fields : 1; /* has no thread/context static fields */ - /* directly or indirectly derives from ComImport attributed class. - * this means we need to create a proxy for instances of this class - * for COM Interop. set this flag on loading so all we need is a quick check - * during object creation rather than having to traverse supertypes - */ - guint is_com_object : 1; - guint nested_classes_inited : 1; /* Whenever nested_class is initialized */ - - /* next byte*/ - guint class_kind : 3; /* One of the values from MonoTypeKind */ - guint interfaces_inited : 1; /* interfaces is initialized */ - guint simd_type : 1; /* class is a simd intrinsic type */ - 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; - - MonoImage *image; - const char *name; - const char *name_space; - - guint32 type_token; - int vtable_size; /* number of slots */ - - guint16 interface_count; - guint32 interface_id; /* unique inderface id (for interfaces) */ - guint32 max_interface_id; - - guint16 interface_offsets_count; - MonoClass **interfaces_packed; - guint16 *interface_offsets_packed; /* enabled only with small config for now: we might want to do it unconditionally */ #ifdef MONO_SMALL_CONFIG #define COMPRESSED_INTERFACE_BITMAP 1 #endif - guint8 *interface_bitmap; - MonoClass **interfaces; - union { - int class_size; /* size of area for static fields */ - int element_size; /* for array types */ - int generic_param_token; /* for generic param types, both var and mvar */ - } sizes; +#ifdef ENABLE_CHECKED_BUILD_PRIVATE_TYPES +#define MONO_CLASS_DEF_PRIVATE 1 +#endif - /* - * Field information: Type and location from object base - */ - MonoClassField *fields; +/* Hide _MonoClass definition in checked build mode to ensure that + * it is only accessed via getter and setter methods. + */ +#ifndef MONO_CLASS_DEF_PRIVATE +#include "class-private-definition.h" +#endif - MonoMethod **methods; - - /* used as the type of the this argument and when passing the arg by value */ - MonoType this_arg; - MonoType byval_arg; - - MonoGCDescriptor gc_descr; - - MonoClassRuntimeInfo *runtime_info; - - /* Generic vtable. Initialized by a call to mono_class_setup_vtable () */ - MonoMethod **vtable; - - /* Infrequently used items. See class-accessors.c: InfrequentDataKind for what goes into here. */ - MonoPropertyBag infrequent_data; -}; - -typedef struct { - MonoClass klass; - guint32 flags; - /* - * From the TypeDef table - */ - guint32 first_method_idx; - guint32 first_field_idx; - guint32 method_count, field_count; - /* next element in the class_cache hash list (in MonoImage) */ - MonoClass *next_class_cache; -} MonoClassDef; - -typedef struct { - MonoClassDef klass; - MonoGenericContainer *generic_container; - /* The canonical GENERICINST where we instantiate a generic type definition with its own generic parameters.*/ - /* Suppose we have class T`2 {...}. canonical_inst is the GTD T`2 applied to A and B. */ - MonoType canonical_inst; -} MonoClassGtd; - -typedef struct { - MonoClass klass; - MonoGenericClass *generic_class; -} MonoClassGenericInst; - -typedef struct { - MonoClass klass; -} MonoClassGenericParam; - -typedef struct { - MonoClass klass; - guint32 method_count; -} MonoClassArray; - -typedef struct { - MonoClass klass; -} MonoClassPointer; +/* If MonoClass definition is hidden, just declare the getters. + * Otherwise, define them as static inline functions. + */ +#ifdef MONO_CLASS_DEF_PRIVATE +#define MONO_CLASS_GETTER(funcname, rettype, optref, argtype, fieldname) rettype funcname (argtype *klass); +#else +#define MONO_CLASS_GETTER(funcname, rettype, optref, argtype, fieldname) static inline rettype funcname (argtype *klass) { return optref klass-> fieldname ; } +#endif +#define MONO_CLASS_OFFSET(funcname, argtype, fieldname) /*nothing*/ +#include "class-getters.h" +#undef MONO_CLASS_GETTER +#undef MONO_CLASS_OFFSET #ifdef COMPRESSED_INTERFACE_BITMAP int mono_compress_bitmap (uint8_t *dest, const uint8_t *bitmap, int size); @@ -430,7 +311,7 @@ int mono_class_interface_match (const uint8_t *bitmap, int id); #define mono_class_interface_match(bmap,uiid) ((bmap) [(uiid) >> 3] & (1 << ((uiid)&7))) #endif -#define MONO_CLASS_IMPLEMENTS_INTERFACE(k,uiid) (((uiid) <= (k)->max_interface_id) && mono_class_interface_match ((k)->interface_bitmap, (uiid))) +#define MONO_CLASS_IMPLEMENTS_INTERFACE(k,uiid) (((uiid) <= m_class_get_max_interface_id (k)) && mono_class_interface_match (m_class_get_interface_bitmap (k), (uiid))) #define MONO_VTABLE_AVAILABLE_GC_BITS 4 @@ -440,8 +321,8 @@ int mono_class_interface_match (const uint8_t *bitmap, int id); #define mono_vtable_is_remote(vtable) (FALSE) #define mono_vtable_set_is_remote(vtable,enable) do {} while (0) #else -#define mono_class_is_marshalbyref(klass) ((klass)->marshalbyref) -#define mono_class_is_contextbound(klass) ((klass)->contextbound) +#define mono_class_is_marshalbyref(klass) (m_class_get_marshalbyref (klass)) +#define mono_class_is_contextbound(klass) (m_class_get_contextbound (klass)) #define mono_vtable_is_remote(vtable) ((vtable)->remote) #define mono_vtable_set_is_remote(vtable,enable) do { (vtable)->remote = enable ? 1 : 0; } while (0) #endif @@ -449,7 +330,7 @@ int mono_class_interface_match (const uint8_t *bitmap, int id); #ifdef DISABLE_COM #define mono_class_is_com_object(klass) (FALSE) #else -#define mono_class_is_com_object(klass) ((klass)->is_com_object) +#define mono_class_is_com_object(klass) (m_class_is_com_object (klass)) #endif @@ -556,22 +437,6 @@ struct _MonoGenericClass { MonoImageSet *owner; }; -/* - * A type parameter. - */ -struct _MonoGenericParam { - /* - * Type or method this parameter was defined in. - */ - MonoGenericContainer *owner; - guint16 num; - /* - * If != NULL, this is a generated generic param used by the JIT to implement generic - * sharing. - */ - MonoType *gshared_constraint; -}; - /* Additional details about a MonoGenericParam */ /* Keep in sync with managed Mono.RuntimeStructs.GenericParamInfo */ typedef struct { @@ -587,10 +452,25 @@ typedef struct { MonoClass** constraints; /* NULL means end of list */ } MonoGenericParamInfo; -typedef struct { - MonoGenericParam param; +/* + * A type parameter. + */ +struct _MonoGenericParam { + /* + * Type or method this parameter was defined in. + */ + MonoGenericContainer *owner; + guint16 num; + /* + * If != NULL, this is a generated generic param used by the JIT to implement generic + * sharing. + */ + MonoType *gshared_constraint; + MonoGenericParamInfo info; -} MonoGenericParamFull; +}; + +typedef MonoGenericParam MonoGenericParamFull; /* * The generic container. @@ -615,15 +495,9 @@ struct _MonoGenericContainer { int is_method : 1; /* If true, this container has no associated class/method and only the image is known. This can happen: 1. For the special anonymous containers kept by MonoImage. - 2. During container creation via the mono_metadata_load_generic_params path-- in this case the caller - sets the owner, so temporarily while load_generic_params is completing the container is anonymous. - 3. When user code creates a generic parameter via SRE, but has not yet set an owner. */ + 2. When user code creates a generic parameter via SRE, but has not yet set an owner. */ int is_anonymous : 1; - /* If false, all params in this container are full-size. If true, all params are just param structs. */ - /* This field is always == to the is_anonymous field, except in "temporary" cases (2) and (3) above. */ - /* TODO: Merge GenericParam and GenericParamFull, remove this field. Benefit is marginal. */ - int is_small_param : 1; - /* Our type parameters. */ + /* Our type parameters. If this is a special anonymous container (case 1, above), this field is not valid, use mono_metadata_create_anon_gparam () */ MonoGenericParamFull *type_params; }; @@ -651,26 +525,16 @@ mono_generic_param_num (MonoGenericParam *p) return p->num; } -static inline gboolean -mono_generic_param_is_fullsize (MonoGenericParam *p) -{ - return !mono_generic_param_owner (p)->is_small_param; -} - static inline MonoGenericParamInfo * mono_generic_param_info (MonoGenericParam *p) { - if (mono_generic_param_is_fullsize (p)) - return &((MonoGenericParamFull *) p)->info; - return NULL; + return &((MonoGenericParamFull *) p)->info; } static inline const char * mono_generic_param_name (MonoGenericParam *p) { - if (mono_generic_param_is_fullsize (p)) - return ((MonoGenericParamFull *) p)->info.name; - return NULL; + return ((MonoGenericParamFull *) p)->info.name; } static inline MonoGenericContainer * @@ -725,9 +589,6 @@ typedef struct { void mono_class_setup_supertypes (MonoClass *klass); -void -mono_class_setup_fields (MonoClass *klass); - /* WARNING * Only call this function if you can ensure both @klass and @parent * have supertype information initialized. @@ -737,16 +598,16 @@ mono_class_setup_fields (MonoClass *klass); static inline gboolean mono_class_has_parent_fast (MonoClass *klass, MonoClass *parent) { - return (klass->idepth >= parent->idepth) && (klass->supertypes [parent->idepth - 1] == parent); + return (m_class_get_idepth (klass) >= m_class_get_idepth (parent)) && (m_class_get_supertypes (klass) [m_class_get_idepth (parent) - 1] == parent); } static inline gboolean mono_class_has_parent (MonoClass *klass, MonoClass *parent) { - if (G_UNLIKELY (!klass->supertypes)) + if (G_UNLIKELY (!m_class_get_supertypes (klass))) mono_class_setup_supertypes (klass); - if (G_UNLIKELY (!parent->supertypes)) + if (G_UNLIKELY (!m_class_get_supertypes (parent))) mono_class_setup_supertypes (parent); return mono_class_has_parent_fast (klass, parent); @@ -912,33 +773,6 @@ method_is_dynamic (MonoMethod *method) #endif } -void -mono_classes_init (void); - -void -mono_classes_cleanup (void); - -void -mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_size, int real_size, gboolean sre); - -void -mono_class_setup_interface_offsets (MonoClass *klass); - -void -mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int onum, GList *in_setup); - -void -mono_class_setup_vtable (MonoClass *klass); - -void -mono_class_setup_methods (MonoClass *klass); - -void -mono_class_setup_mono_type (MonoClass *klass); - -void -mono_class_setup_parent (MonoClass *klass, MonoClass *parent); - MonoMethod* mono_class_get_method_by_index (MonoClass *klass, int index); @@ -1021,9 +855,6 @@ mono_method_get_generic_container (MonoMethod *method); MonoGenericContext* mono_generic_class_get_context (MonoGenericClass *gclass); -MonoClass* -mono_generic_class_get_class (MonoGenericClass *gclass); - void mono_method_set_generic_container (MonoMethod *method, MonoGenericContainer* container); @@ -1224,7 +1055,8 @@ mono_metadata_has_generic_params (MonoImage *image, guint32 token); MONO_API MonoGenericContainer * mono_metadata_load_generic_params (MonoImage *image, guint32 token, - MonoGenericContainer *parent_container); + MonoGenericContainer *parent_container, + gpointer real_owner); MONO_API gboolean mono_metadata_load_generic_param_constraints_checked (MonoImage *image, guint32 token, @@ -1412,14 +1244,11 @@ mono_field_from_token_checked (MonoImage *image, uint32_t token, MonoClass **ret gpointer mono_ldtoken_checked (MonoImage *image, guint32 token, MonoClass **handle_class, MonoGenericContext *context, MonoError *error); -MonoClass * -mono_class_from_generic_parameter_internal (MonoGenericParam *param); - MonoImage * -get_image_for_generic_param (MonoGenericParam *param); +mono_get_image_for_generic_param (MonoGenericParam *param); char * -make_generic_name_string (MonoImage *image, int num); +mono_make_generic_name_string (MonoImage *image, int num); MonoClass * mono_class_load_from_name (MonoImage *image, const char* name_space, const char *name) MONO_LLVM_INTERNAL; @@ -1533,6 +1362,15 @@ mono_class_set_weak_bitmap (MonoClass *klass, int nbits, gsize *bits); gsize* mono_class_get_weak_bitmap (MonoClass *klass, int *nbits); +gboolean +mono_class_has_dim_conflicts (MonoClass *klass); + +void +mono_class_set_dim_conflicts (MonoClass *klass, GSList *conflicts); + +GSList* +mono_class_get_dim_conflicts (MonoClass *klass); + MonoMethod * mono_class_get_method_from_name_checked (MonoClass *klass, const char *name, int param_count, int flags, MonoError *error); @@ -1548,6 +1386,45 @@ mono_method_has_no_body (MonoMethod *method); MonoMethodHeader* mono_method_get_header_internal (MonoMethod *method, MonoError *error); +MonoType* +mono_class_find_enum_basetype (MonoClass *klass, MonoError *error); + +gboolean +mono_class_set_failure (MonoClass *klass, MonoErrorBoxed *boxed_error); + +gboolean +mono_class_set_type_load_failure_causedby_class (MonoClass *klass, const MonoClass *caused_by, const gchar* msg); + +gboolean mono_class_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res); + +MonoMethod* mono_find_method_in_metadata (MonoClass *klass, const char *name, int param_count, int flags); + +int +mono_class_get_object_finalize_slot (void); + +MonoMethod * +mono_class_get_default_finalize_method (void); + +void +mono_field_resolve_type (MonoClassField *field, MonoError *error); + +gboolean +mono_type_has_exceptions (MonoType *type); + +void +mono_class_set_nonblittable (MonoClass *klass); + +gboolean +mono_class_publish_gc_descriptor (MonoClass *klass, MonoGCDescriptor gc_descr); + +void +mono_class_compute_gc_descriptor (MonoClass *klass); + +#ifndef DISABLE_REMOTING +void +mono_class_contextbound_bit_offset (int* byte_offset_out, guint8* mask_out); +#endif + /*Now that everything has been defined, let's include the inline functions */ #include diff --git a/mono/metadata/class-private-definition.h b/mono/metadata/class-private-definition.h new file mode 100644 index 0000000000..e539019b73 --- /dev/null +++ b/mono/metadata/class-private-definition.h @@ -0,0 +1,170 @@ +/** + * \file Definitions of struct _MonoClass members + * + * NOTE: This file should NOT be included directly. + */ + +#if defined(MONO_CLASS_DEF_PRIVATE) && !defined(REALLY_INCLUDE_CLASS_DEF) +#error struct _MonoClass definition should not be accessed directly +#endif + +#ifndef __MONO_METADATA_CLASS_PRIVATE_DEFINITION_H__ +#define __MONO_METADATA_CLASS_PRIVATE_DEFINITION_H__ + +struct _MonoClass { + /* element class for arrays and enum basetype for enums */ + MonoClass *element_class; + /* used for subtype checks */ + MonoClass *cast_class; + + /* for fast subtype checks */ + MonoClass **supertypes; + guint16 idepth; + + /* array dimension */ + guint8 rank; + + int instance_size; /* object instance size */ + + guint inited : 1; + + /* A class contains static and non static data. Static data can be + * of the same type as the class itselfs, but it does not influence + * the instance size of the class. To avoid cyclic calls to + * mono_class_init (from mono_class_instance_size ()) we first + * initialise all non static fields. After that we set size_inited + * to 1, because we know the instance size now. After that we + * initialise all static fields. + */ + + /* ALL BITFIELDS SHOULD BE WRITTEN WHILE HOLDING THE LOADER LOCK */ + guint size_inited : 1; + guint valuetype : 1; /* derives from System.ValueType */ + guint enumtype : 1; /* derives from System.Enum */ + guint blittable : 1; /* class is blittable */ + guint unicode : 1; /* class uses unicode char when marshalled */ + guint wastypebuilder : 1; /* class was created at runtime from a TypeBuilder */ + guint is_array_special_interface : 1; /* gtd or ginst of once of the magic interfaces that arrays implement */ + + /* next byte */ + guint8 min_align; + + /* next byte */ + guint packing_size : 4; + guint ghcimpl : 1; /* class has its own GetHashCode impl */ + guint has_finalize : 1; /* class has its own Finalize impl */ +#ifndef DISABLE_REMOTING + guint marshalbyref : 1; /* class is a MarshalByRefObject */ + guint contextbound : 1; /* class is a ContextBoundObject */ +#endif + /* next byte */ + guint delegate : 1; /* class is a Delegate */ + guint gc_descr_inited : 1; /* gc_descr is initialized */ + guint has_cctor : 1; /* class has a cctor */ + guint has_references : 1; /* it has GC-tracked references in the instance */ + guint has_static_refs : 1; /* it has static fields that are GC-tracked */ + guint no_special_static_fields : 1; /* has no thread/context static fields */ + /* directly or indirectly derives from ComImport attributed class. + * this means we need to create a proxy for instances of this class + * for COM Interop. set this flag on loading so all we need is a quick check + * during object creation rather than having to traverse supertypes + */ + guint is_com_object : 1; + guint nested_classes_inited : 1; /* Whenever nested_class is initialized */ + + /* next byte*/ + guint class_kind : 3; /* One of the values from MonoTypeKind */ + guint interfaces_inited : 1; /* interfaces is initialized */ + guint simd_type : 1; /* class is a simd intrinsic type */ + 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 */ + guint has_dim_conflicts : 1; /* Class has conflicting default interface methods */ + + MonoClass *parent; + MonoClass *nested_in; + + MonoImage *image; + const char *name; + const char *name_space; + + guint32 type_token; + int vtable_size; /* number of slots */ + + guint16 interface_count; + guint32 interface_id; /* unique inderface id (for interfaces) */ + guint32 max_interface_id; + + guint16 interface_offsets_count; + MonoClass **interfaces_packed; + guint16 *interface_offsets_packed; + guint8 *interface_bitmap; + + MonoClass **interfaces; + + union _MonoClassSizes sizes; + + /* + * Field information: Type and location from object base + */ + MonoClassField *fields; + + MonoMethod **methods; + + /* used as the type of the this argument and when passing the arg by value */ + MonoType this_arg; + MonoType byval_arg; + + MonoGCDescriptor gc_descr; + + MonoClassRuntimeInfo *runtime_info; + + /* Generic vtable. Initialized by a call to mono_class_setup_vtable () */ + MonoMethod **vtable; + + /* Infrequently used items. See class-accessors.c: InfrequentDataKind for what goes into here. */ + MonoPropertyBag infrequent_data; +}; + +struct _MonoClassDef { + MonoClass klass; + guint32 flags; + /* + * From the TypeDef table + */ + guint32 first_method_idx; + guint32 first_field_idx; + guint32 method_count, field_count; + /* next element in the class_cache hash list (in MonoImage) */ + MonoClass *next_class_cache; +}; + +struct _MonoClassGtd { + MonoClassDef klass; + MonoGenericContainer *generic_container; + /* The canonical GENERICINST where we instantiate a generic type definition with its own generic parameters.*/ + /* Suppose we have class T`2 {...}. canonical_inst is the GTD T`2 applied to A and B. */ + MonoType canonical_inst; +}; + +struct _MonoClassGenericInst { + MonoClass klass; + MonoGenericClass *generic_class; +}; + +struct _MonoClassGenericParam { + MonoClass klass; +}; + +struct _MonoClassArray { + MonoClass klass; + guint32 method_count; +}; + +struct _MonoClassPointer { + MonoClass klass; +}; + + +#endif diff --git a/mono/metadata/class.c.REMOVED.git-id b/mono/metadata/class.c.REMOVED.git-id index 203aeff68b..66a2d50ab6 100644 --- a/mono/metadata/class.c.REMOVED.git-id +++ b/mono/metadata/class.c.REMOVED.git-id @@ -1 +1 @@ -d9d2bd488056924f2ffe4218405597e4f4206565 \ No newline at end of file +a4565929b9db58ea5a4791fa633ba3584e78a368 \ No newline at end of file diff --git a/mono/metadata/class.h b/mono/metadata/class.h index 877379fc00..5d7bf80d9c 100644 --- a/mono/metadata/class.h +++ b/mono/metadata/class.h @@ -68,12 +68,15 @@ MONO_RT_EXTERNAL_ONLY MONO_API MonoClassField* mono_field_from_token (MonoImage *image, uint32_t token, MonoClass **retklass, MonoGenericContext *context); +MONO_RT_EXTERNAL_ONLY MONO_API MonoClass * mono_bounded_array_class_get (MonoClass *element_class, uint32_t rank, mono_bool bounded); +MONO_RT_EXTERNAL_ONLY MONO_API MonoClass * mono_array_class_get (MonoClass *element_class, uint32_t rank); +MONO_RT_EXTERNAL_ONLY MONO_API MonoClass * mono_ptr_class_get (MonoType *type); diff --git a/mono/metadata/cominterop.c.REMOVED.git-id b/mono/metadata/cominterop.c.REMOVED.git-id index bb1684cb2e..a7b733b54d 100644 --- a/mono/metadata/cominterop.c.REMOVED.git-id +++ b/mono/metadata/cominterop.c.REMOVED.git-id @@ -1 +1 @@ -fad0d1a534f8c784caf07437b80b3be076be8eed \ No newline at end of file +5db5f906000448cc0a0e1754ab4e67a04effe6a5 \ No newline at end of file diff --git a/mono/metadata/console-io.h b/mono/metadata/console-io.h index c5c572e58a..851b82c96e 100644 --- a/mono/metadata/console-io.h +++ b/mono/metadata/console-io.h @@ -22,14 +22,25 @@ G_BEGIN_DECLS void mono_console_init (void); void mono_console_handle_async_ops (void); -MonoBoolean ves_icall_System_ConsoleDriver_Isatty (gpointer handle); -gint32 ves_icall_System_ConsoleDriver_InternalKeyAvailable (gint32 timeout); -MonoBoolean ves_icall_System_ConsoleDriver_SetEcho (MonoBoolean echo); -MonoBoolean ves_icall_System_ConsoleDriver_SetBreak (MonoBoolean want_break); -MonoBoolean ves_icall_System_ConsoleDriver_TtySetup (MonoString *keypad, MonoString *teardown, MonoArray **control_characters, int **size); -void ves_icall_System_ConsoleDriver_Suspend (void); + +MonoBoolean +ves_icall_System_ConsoleDriver_Isatty (gpointer handle, MonoError* error); + +gint32 +ves_icall_System_ConsoleDriver_InternalKeyAvailable (gint32 timeout, MonoError* error); + +MonoBoolean +ves_icall_System_ConsoleDriver_SetEcho (MonoBoolean echo, MonoError* error); + +MonoBoolean +ves_icall_System_ConsoleDriver_SetBreak (MonoBoolean want_break, MonoError* error); + +MonoBoolean +ves_icall_System_ConsoleDriver_TtySetup (MonoStringHandle keypad, MonoStringHandle teardown, MonoArrayHandleOut control_chars, int **size, MonoError* error); + +void +ves_icall_System_ConsoleDriver_Suspend (MonoError* error); G_END_DECLS #endif /* _MONO_METADATA_CONSOLEIO_H */ - diff --git a/mono/metadata/console-null.c b/mono/metadata/console-null.c index 749a43452d..79ba30668f 100644 --- a/mono/metadata/console-null.c +++ b/mono/metadata/console-null.c @@ -31,31 +31,31 @@ mono_console_handle_async_ops (void) } MonoBoolean -ves_icall_System_ConsoleDriver_Isatty (HANDLE handle) +ves_icall_System_ConsoleDriver_Isatty (HANDLE handle, MonoError* error) { return mono_w32file_get_type (handle) == FILE_TYPE_CHAR; } MonoBoolean -ves_icall_System_ConsoleDriver_SetEcho (MonoBoolean want_echo) +ves_icall_System_ConsoleDriver_SetEcho (MonoBoolean want_echo, MonoError* error) { return FALSE; } MonoBoolean -ves_icall_System_ConsoleDriver_SetBreak (MonoBoolean want_break) +ves_icall_System_ConsoleDriver_SetBreak (MonoBoolean want_break, MonoError* error) { return FALSE; } gint32 -ves_icall_System_ConsoleDriver_InternalKeyAvailable (gint32 timeout) +ves_icall_System_ConsoleDriver_InternalKeyAvailable (gint32 timeout, MonoError* error) { return FALSE; } MonoBoolean -ves_icall_System_ConsoleDriver_TtySetup (MonoString *keypad, MonoString *teardown, MonoArray **control_chars, int **size) +ves_icall_System_ConsoleDriver_TtySetup (MonoStringHandle keypad, MonoStringHandle teardown, MonoArrayHandleOut control_chars, int **size, MonoError* error) { return FALSE; } diff --git a/mono/metadata/console-unix.c b/mono/metadata/console-unix.c index d14c52c0c8..d29b3ebe68 100644 --- a/mono/metadata/console-unix.c +++ b/mono/metadata/console-unix.c @@ -91,7 +91,7 @@ mono_console_init (void) static struct termios initial_attr; MonoBoolean -ves_icall_System_ConsoleDriver_Isatty (HANDLE handle) +ves_icall_System_ConsoleDriver_Isatty (HANDLE handle, MonoError* error) { return isatty (GPOINTER_TO_INT (handle)); } @@ -126,20 +126,19 @@ set_property (gint property, gboolean value) } MonoBoolean -ves_icall_System_ConsoleDriver_SetEcho (MonoBoolean want_echo) +ves_icall_System_ConsoleDriver_SetEcho (MonoBoolean want_echo, MonoError* error) { - return set_property (ECHO, want_echo); } MonoBoolean -ves_icall_System_ConsoleDriver_SetBreak (MonoBoolean want_break) +ves_icall_System_ConsoleDriver_SetBreak (MonoBoolean want_break, MonoError* error) { return set_property (IGNBRK, !want_break); } gint32 -ves_icall_System_ConsoleDriver_InternalKeyAvailable (gint32 timeout) +ves_icall_System_ConsoleDriver_InternalKeyAvailable (gint32 timeout, MonoError* error) { fd_set rfds; struct timeval tv; @@ -358,66 +357,66 @@ console_restore_signal_handlers () #endif static void -set_control_chars (MonoArray *control_chars, const guchar *cc) +set_control_chars (gchar *control_chars, const guchar *cc) { /* The index into the array comes from corlib/System/ControlCharacters.cs */ #ifdef VINTR - mono_array_set (control_chars, gchar, 0, cc [VINTR]); + control_chars [0] = cc [VINTR]; #endif #ifdef VQUIT - mono_array_set (control_chars, gchar, 1, cc [VQUIT]); + control_chars [1] = cc [VQUIT]; #endif #ifdef VERASE - mono_array_set (control_chars, gchar, 2, cc [VERASE]); + control_chars [2] = cc [VERASE]; #endif #ifdef VKILL - mono_array_set (control_chars, gchar, 3, cc [VKILL]); + control_chars [3] = cc [VKILL]; #endif #ifdef VEOF - mono_array_set (control_chars, gchar, 4, cc [VEOF]); + control_chars [4] = cc [VEOF]; #endif #ifdef VTIME - mono_array_set (control_chars, gchar, 5, cc [VTIME]); + control_chars [5] = cc [VTIME]; #endif #ifdef VMIN - mono_array_set (control_chars, gchar, 6, cc [VMIN]); + control_chars [6] = cc [VMIN]; #endif #ifdef VSWTC - mono_array_set (control_chars, gchar, 7, cc [VSWTC]); + control_chars [7] = cc [VSWTC]; #endif #ifdef VSTART - mono_array_set (control_chars, gchar, 8, cc [VSTART]); + control_chars [8] = cc [VSTART]; #endif #ifdef VSTOP - mono_array_set (control_chars, gchar, 9, cc [VSTOP]); + control_chars [9] = cc [VSTOP]; #endif #ifdef VSUSP - mono_array_set (control_chars, gchar, 10, cc [VSUSP]); + control_chars [10] = cc [VSUSP]; #endif #ifdef VEOL - mono_array_set (control_chars, gchar, 11, cc [VEOL]); + control_chars [11] = cc [VEOL]; #endif #ifdef VREPRINT - mono_array_set (control_chars, gchar, 12, cc [VREPRINT]); + control_chars [12] = cc [VREPRINT]; #endif #ifdef VDISCARD - mono_array_set (control_chars, gchar, 13, cc [VDISCARD]); + control_chars [13] = cc [VDISCARD]; #endif #ifdef VWERASE - mono_array_set (control_chars, gchar, 14, cc [VWERASE]); + control_chars [14] = cc [VWERASE]; #endif #ifdef VLNEXT - mono_array_set (control_chars, gchar, 15, cc [VLNEXT]); + control_chars [15] = cc [VLNEXT]; #endif #ifdef VEOL2 - mono_array_set (control_chars, gchar, 16, cc [VEOL2]); + control_chars [16] = cc [VEOL2]; #endif } MonoBoolean -ves_icall_System_ConsoleDriver_TtySetup (MonoString *keypad, MonoString *teardown, MonoArray **control_chars, int **size) +ves_icall_System_ConsoleDriver_TtySetup (MonoStringHandle keypad, MonoStringHandle teardown, MonoArrayHandleOut control_chars, int **size, MonoError* error) { - ERROR_DECL (error); + // FIXME Lock around the globals? int dims; @@ -448,10 +447,10 @@ ves_icall_System_ConsoleDriver_TtySetup (MonoString *keypad, MonoString *teardow /* 17 is the number of entries set in set_control_chars() above. * NCCS is the total size, but, by now, we only care about those 17 values*/ - MonoArray *control_chars_arr = mono_array_new_checked (mono_domain_get (), mono_defaults.byte_class, 17, error); - if (mono_error_set_pending_exception (error)) - return FALSE; - mono_gc_wbarrier_generic_store (control_chars, (MonoObject*) control_chars_arr); + MonoArrayHandle control_chars_arr = mono_array_new_handle (mono_domain_get (), mono_defaults.byte_class, 17, error); + return_val_if_nok (error, FALSE); + + MONO_HANDLE_ASSIGN (control_chars, control_chars_arr); if (tcgetattr (STDIN_FILENO, &initial_attr) == -1) return FALSE; @@ -467,25 +466,25 @@ ves_icall_System_ConsoleDriver_TtySetup (MonoString *keypad, MonoString *teardow if (tcsetattr (STDIN_FILENO, TCSANOW, &mono_attr) == -1) return FALSE; - set_control_chars (*control_chars, mono_attr.c_cc); + uint32_t h; + set_control_chars (MONO_ARRAY_HANDLE_PIN (control_chars_arr, gchar, 0, &h), mono_attr.c_cc); + mono_gchandle_free (h); /* If initialized from another appdomain... */ if (setup_finished) return TRUE; keypad_xmit_str = NULL; - if (keypad != NULL) { - keypad_xmit_str = mono_string_to_utf8_checked (keypad, error); - if (mono_error_set_pending_exception (error)) - return FALSE; + if (!MONO_HANDLE_IS_NULL (keypad)) { + keypad_xmit_str = mono_string_handle_to_utf8 (keypad, error); + return_val_if_nok (error, FALSE); } console_set_signal_handlers (); setup_finished = TRUE; if (!atexit_called) { - if (teardown != NULL) { - teardown_str = mono_string_to_utf8_checked (teardown, error); - if (mono_error_set_pending_exception (error)) - return FALSE; + if (!MONO_HANDLE_IS_NULL (teardown)) { + teardown_str = mono_string_handle_to_utf8 (teardown, error); + return_val_if_nok (error, FALSE); } mono_atexit (tty_teardown); diff --git a/mono/metadata/console-win32.c b/mono/metadata/console-win32.c index ab856f6449..98e3be680c 100644 --- a/mono/metadata/console-win32.c +++ b/mono/metadata/console-win32.c @@ -44,32 +44,32 @@ mono_console_handle_async_ops (void) #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) MonoBoolean -ves_icall_System_ConsoleDriver_Isatty (HANDLE handle) +ves_icall_System_ConsoleDriver_Isatty (HANDLE handle, MonoError* error) { DWORD mode; return GetConsoleMode (handle, &mode) != 0; } MonoBoolean -ves_icall_System_ConsoleDriver_SetEcho (MonoBoolean want_echo) +ves_icall_System_ConsoleDriver_SetEcho (MonoBoolean want_echo, MonoError* error) { return FALSE; } MonoBoolean -ves_icall_System_ConsoleDriver_SetBreak (MonoBoolean want_break) +ves_icall_System_ConsoleDriver_SetBreak (MonoBoolean want_break, MonoError* error) { return FALSE; } gint32 -ves_icall_System_ConsoleDriver_InternalKeyAvailable (gint32 timeout) +ves_icall_System_ConsoleDriver_InternalKeyAvailable (gint32 timeout, MonoError* error) { return FALSE; } MonoBoolean -ves_icall_System_ConsoleDriver_TtySetup (MonoString *keypad, MonoString *teardown, MonoArray **control_chars, int **size) +ves_icall_System_ConsoleDriver_TtySetup (MonoStringHandle keypad, MonoStringHandle teardown, MonoArrayHandleOut control_chars, int **size, MonoError* error) { return FALSE; } diff --git a/mono/metadata/custom-attrs.c b/mono/metadata/custom-attrs.c index 4d85ef9423..72e4705d53 100644 --- a/mono/metadata/custom-attrs.c +++ b/mono/metadata/custom-attrs.c @@ -14,6 +14,7 @@ */ #include #include "mono/metadata/assembly.h" +#include "mono/metadata/class-init.h" #include "mono/metadata/gc-internals.h" #include "mono/metadata/mono-endian.h" #include "mono/metadata/object-internals.h" @@ -38,6 +39,11 @@ #define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b)) #define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b)) +#define CATTR_TYPE_SYSTEM_TYPE 0x50 +#define CATTR_BOXED_VALUETYPE_PREFIX 0x51 +#define CATTR_TYPE_FIELD 0x53 +#define CATTR_TYPE_PROPERTY 0x54 + static gboolean type_is_reference (MonoType *type); static GENERATE_GET_CLASS_WITH_CACHE (custom_attribute_typed_argument, "System.Reflection", "CustomAttributeTypedArgument"); @@ -78,7 +84,7 @@ custom_attr_visible (MonoImage *image, MonoReflectionCustomAttr *cattr) MONO_REQ_GC_UNSAFE_MODE; /* FIXME: Need to do more checks */ - if (cattr->ctor->method && (cattr->ctor->method->klass->image != image)) { + if (cattr->ctor->method && (m_class_get_image (cattr->ctor->method->klass) != image)) { int visibility = mono_class_get_flags (cattr->ctor->method->klass) & TYPE_ATTRIBUTE_VISIBILITY_MASK; if ((visibility != TYPE_ATTRIBUTE_PUBLIC) && (visibility != TYPE_ATTRIBUTE_NESTED_PUBLIC)) @@ -130,8 +136,9 @@ find_field_index (MonoClass *klass, MonoClassField *field) { int i; int fcount = mono_class_get_field_count (klass); + MonoClassField *klass_fields = m_class_get_fields (klass); for (i = 0; i < fcount; ++i) { - if (field == &klass->fields [i]) + if (field == &klass_fields [i]) return mono_class_get_first_field_idx (klass) + 1 + i; } return 0; @@ -213,6 +220,44 @@ load_cattr_enum_type (MonoImage *image, const char *p, const char *boundp, const return mono_class_from_mono_type (t); } +static MonoReflectionType* +load_cattr_type_object (MonoImage *image, MonoType *t, const char *p, const char *boundp, const char **end, MonoError *error, guint32 *slen) +{ + MonoReflectionType *rt; + char *n; + + if (!decode_blob_value_checked (p, boundp, slen, &p, error)) + return NULL; + if (*slen > 0 && !bcheck_blob (p, *slen - 1, boundp, error)) + return NULL; + n = (char *)g_memdup (p, *slen + 1); + n [*slen] = 0; + t = cattr_type_from_name (n, image, FALSE, error); + g_free (n); + return_val_if_nok (error, NULL); + + rt = mono_type_get_object_checked (mono_domain_get (), t, error); + if (!is_ok (error)) + return NULL; + + *end = p + *slen; + + return rt; +} + +static MonoReflectionType* +load_cattr_type_object_with_header (MonoImage *image, MonoType *t, const char *p, const char *boundp, const char **end, MonoError *error, guint32 *slen) +{ + if (!bcheck_blob (p, 0, boundp, error)) + return NULL; + if (*p == (char)0xFF) { + *end = p + 1; + return NULL; + } + + return load_cattr_type_object (image, t, p, boundp, end, error, slen); +} + static void* load_cattr_value (MonoImage *image, MonoType *t, const char *p, const char *boundp, const char **end, MonoError *error) { @@ -223,6 +268,18 @@ load_cattr_value (MonoImage *image, MonoType *t, const char *p, const char *boun g_assert (boundp); error_init (error); + if (type == MONO_TYPE_GENERICINST) { + MonoGenericClass * mgc = t->data.generic_class; + MonoClass * cc = mgc->container_class; + if (m_class_is_enumtype (cc)) { + tklass = m_class_get_element_class (cc); + t = m_class_get_byval_arg (tklass); + type = t->type; + } else { + g_error ("Unhandled type of generic instance in load_cattr_value: %s", m_class_get_name (cc)); + } + } + handle_enum: switch (type) { case MONO_TYPE_U1: @@ -281,13 +338,13 @@ handle_enum: return val; } case MONO_TYPE_VALUETYPE: - if (t->data.klass->enumtype) { + if (m_class_is_enumtype (t->data.klass)) { type = mono_class_enum_basetype (t->data.klass)->type; goto handle_enum; } else { MonoClass *k = t->data.klass; - if (mono_is_corlib_image (k->image) && strcmp (k->name_space, "System") == 0 && strcmp (k->name, "DateTime") == 0){ + if (mono_is_corlib_image (m_class_get_image (k)) && strcmp (m_class_get_name_space (k), "System") == 0 && strcmp (m_class_get_name (k), "DateTime") == 0){ guint64 *val = (guint64 *)g_malloc (sizeof (guint64)); if (!bcheck_blob (p, 7, boundp, error)) return NULL; @@ -296,7 +353,7 @@ handle_enum: return val; } } - g_error ("generic valutype %s not handled in custom attr value decoding", t->data.klass->name); + g_error ("generic valutype %s not handled in custom attr value decoding", m_class_get_name (t->data.klass)); break; case MONO_TYPE_STRING: @@ -319,32 +376,7 @@ handle_enum: // See https://simonsapin.github.io/wtf-8/ for a description of wtf-8. return mono_string_new_wtf8_len_checked (mono_domain_get (), p, slen, error); case MONO_TYPE_CLASS: { - MonoReflectionType *rt; - char *n; - MonoType *t; - if (!bcheck_blob (p, 0, boundp, error)) - return NULL; - if (*p == (char)0xFF) { - *end = p + 1; - return NULL; - } -handle_type: - if (!decode_blob_value_checked (p, boundp, &slen, &p, error)) - return NULL; - if (slen > 0 && !bcheck_blob (p, slen - 1, boundp, error)) - return NULL; - n = (char *)g_memdup (p, slen + 1); - n [slen] = 0; - t = cattr_type_from_name (n, image, FALSE, error); - g_free (n); - return_val_if_nok (error, NULL); - *end = p + slen; - - rt = mono_type_get_object_checked (mono_domain_get (), t, error); - if (!mono_error_ok (error)) - return NULL; - - return rt; + return load_cattr_type_object_with_header (image, t, p, boundp, end, error, &slen); } case MONO_TYPE_OBJECT: { if (!bcheck_blob (p, 0, boundp, error)) @@ -354,8 +386,8 @@ handle_type: MonoClass *subc = NULL; void *val; - if (subt == 0x50) { - goto handle_type; + if (subt == CATTR_TYPE_SYSTEM_TYPE) { + return load_cattr_type_object (image, t, p, boundp, end, error, &slen); } else if (subt == 0x0E) { type = MONO_TYPE_STRING; goto handle_enum; @@ -367,21 +399,21 @@ handle_type: p ++; type = MONO_TYPE_SZARRAY; - if (etype == 0x50) { + if (etype == CATTR_TYPE_SYSTEM_TYPE) { tklass = mono_defaults.systemtype_class; - } else if (etype == 0x55) { + } else if (etype == MONO_TYPE_ENUM) { tklass = load_cattr_enum_type (image, p, boundp, &p, error); if (!is_ok (error)) return NULL; } else { - if (etype == 0x51) + if (etype == CATTR_BOXED_VALUETYPE_PREFIX) /* See Partition II, Appendix B3 */ etype = MONO_TYPE_OBJECT; simple_type.type = (MonoTypeEnum)etype; tklass = mono_class_from_mono_type (&simple_type); } goto handle_enum; - } else if (subt == 0x55) { + } else if (subt == MONO_TYPE_ENUM) { char *n; MonoType *t; if (!decode_blob_value_checked (p, boundp, &slen, &p, error)) @@ -402,11 +434,11 @@ handle_type: } else { g_error ("Unknown type 0x%02x for object type encoding in custom attr", subt); } - val = load_cattr_value (image, &subc->byval_arg, p, boundp, end, error); + val = load_cattr_value (image, m_class_get_byval_arg (subc), p, boundp, end, error); obj = NULL; if (is_ok (error)) { obj = mono_object_new_checked (mono_domain_get (), subc, error); - g_assert (!subc->has_references); + g_assert (!m_class_has_references (subc)); if (is_ok (error)) mono_gc_memmove_atomic ((char*)obj + sizeof (MonoObject), val, mono_class_value_size (subc, NULL)); } @@ -427,9 +459,20 @@ handle_type: } arr = mono_array_new_checked (mono_domain_get(), tklass, alen, error); return_val_if_nok (error, NULL); - basetype = tklass->byval_arg.type; - if (basetype == MONO_TYPE_VALUETYPE && tklass->enumtype) + basetype = m_class_get_byval_arg (tklass)->type; + if (basetype == MONO_TYPE_VALUETYPE && m_class_is_enumtype (tklass)) basetype = mono_class_enum_basetype (tklass)->type; + + if (basetype == MONO_TYPE_GENERICINST) { + MonoGenericClass * mgc = m_class_get_byval_arg (tklass)->data.generic_class; + MonoClass * cc = mgc->container_class; + if (m_class_is_enumtype (cc)) { + basetype = m_class_get_byval_arg (m_class_get_element_class (cc))->type; + } else { + g_error ("Unhandled type of generic instance in load_cattr_value: %s[]", m_class_get_name (cc)); + } + } + switch (basetype) { case MONO_TYPE_U1: @@ -489,7 +532,7 @@ handle_type: case MONO_TYPE_STRING: case MONO_TYPE_SZARRAY: for (i = 0; i < alen; i++) { - MonoObject *item = (MonoObject *)load_cattr_value (image, &tklass->byval_arg, p, boundp, &p, error); + MonoObject *item = (MonoObject *)load_cattr_value (image, m_class_get_byval_arg (tklass), p, boundp, &p, error); if (!is_ok (error)) return NULL; mono_array_setref (arr, i, item); @@ -836,7 +879,7 @@ create_custom_attr (MonoImage *image, MonoMethod *method, const guchar *data, gu memcpy (name, named, name_len); name [name_len] = 0; named += name_len; - if (named_type == 0x53) { + if (named_type == CATTR_TYPE_FIELD) { MonoClassField *field; void *val; @@ -859,7 +902,7 @@ create_custom_attr (MonoImage *image, MonoMethod *method, const guchar *data, gu mono_field_set_value (attr, field, val); if (!type_is_reference (field->type)) g_free (val); - } else if (named_type == 0x54) { + } else if (named_type == CATTR_TYPE_PROPERTY) { MonoProperty *prop; void *pparams [1]; MonoType *prop_type; @@ -1020,7 +1063,7 @@ mono_reflection_create_custom_attr_data_args (MonoImage *image, MonoMethod *meth memcpy (name, named, name_len); name [name_len] = 0; named += name_len; - if (named_type == 0x53) { + if (named_type == CATTR_TYPE_FIELD) { /* Named arg is a field. */ MonoObject *obj; MonoClassField *field = mono_class_get_field_from_name (attrklass, name); @@ -1040,7 +1083,7 @@ mono_reflection_create_custom_attr_data_args (MonoImage *image, MonoMethod *meth } mono_array_setref (namedargs, j, obj); - } else if (named_type == 0x54) { + } else if (named_type == CATTR_TYPE_PROPERTY) { /* Named arg is a property */ MonoObject *obj; MonoType *prop_type; @@ -1172,7 +1215,7 @@ create_custom_attr_data_handle (MonoImage *image, MonoCustomAttrEntry *cattr, Mo domain = mono_domain_get (); - MonoObjectHandle attr = MONO_HANDLE_NEW (MonoObject, mono_object_new_checked (domain, mono_defaults.customattribute_data_class, error)); + MonoObjectHandle attr = mono_object_new_handle (domain, mono_defaults.customattribute_data_class, error); goto_if_nok (error, fail); MonoReflectionMethod *ctor_obj = mono_method_get_object_checked (domain, cattr->ctor, NULL, error); @@ -1396,8 +1439,8 @@ mono_custom_attrs_from_method_checked (MonoMethod *method, MonoError *error) if (method->is_inflated) method = ((MonoMethodInflated *) method)->declaring; - if (method_is_dynamic (method) || image_is_dynamic (method->klass->image)) - return lookup_custom_attr (method->klass->image, method); + if (method_is_dynamic (method) || image_is_dynamic (m_class_get_image (method->klass))) + return lookup_custom_attr (m_class_get_image (method->klass), method); if (!method->token) /* Synthetic methods */ @@ -1406,7 +1449,7 @@ mono_custom_attrs_from_method_checked (MonoMethod *method, MonoError *error) idx = mono_method_get_index (method); idx <<= MONO_CUSTOM_ATTR_BITS; idx |= MONO_CUSTOM_ATTR_METHODDEF; - return mono_custom_attrs_from_index_checked (method->klass->image, idx, FALSE, error); + return mono_custom_attrs_from_index_checked (m_class_get_image (method->klass), idx, FALSE, error); } /** @@ -1431,19 +1474,19 @@ mono_custom_attrs_from_class_checked (MonoClass *klass, MonoError *error) if (mono_class_is_ginst (klass)) klass = mono_class_get_generic_class (klass)->container_class; - if (image_is_dynamic (klass->image)) - return lookup_custom_attr (klass->image, klass); + if (image_is_dynamic (m_class_get_image (klass))) + return lookup_custom_attr (m_class_get_image (klass), klass); - if (klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR) { - idx = mono_metadata_token_index (klass->sizes.generic_param_token); + if (m_class_get_byval_arg (klass)->type == MONO_TYPE_VAR || m_class_get_byval_arg (klass)->type == MONO_TYPE_MVAR) { + idx = mono_metadata_token_index (m_class_get_sizes (klass).generic_param_token); idx <<= MONO_CUSTOM_ATTR_BITS; idx |= MONO_CUSTOM_ATTR_GENERICPAR; } else { - idx = mono_metadata_token_index (klass->type_token); + idx = mono_metadata_token_index (m_class_get_type_token (klass)); idx <<= MONO_CUSTOM_ATTR_BITS; idx |= MONO_CUSTOM_ATTR_TYPEDEF; } - return mono_custom_attrs_from_index_checked (klass->image, idx, FALSE, error); + return mono_custom_attrs_from_index_checked (m_class_get_image (klass), idx, FALSE, error); } /** @@ -1507,14 +1550,14 @@ mono_custom_attrs_from_property_checked (MonoClass *klass, MonoProperty *propert error_init (error); - if (image_is_dynamic (klass->image)) { + if (image_is_dynamic (m_class_get_image (klass))) { property = mono_metadata_get_corresponding_property_from_generic_type_definition (property); - return lookup_custom_attr (klass->image, property); + return lookup_custom_attr (m_class_get_image (klass), property); } idx = find_property_index (klass, property); idx <<= MONO_CUSTOM_ATTR_BITS; idx |= MONO_CUSTOM_ATTR_PROPERTY; - return mono_custom_attrs_from_index_checked (klass->image, idx, FALSE, error); + return mono_custom_attrs_from_index_checked (m_class_get_image (klass), idx, FALSE, error); } /** @@ -1536,14 +1579,14 @@ mono_custom_attrs_from_event_checked (MonoClass *klass, MonoEvent *event, MonoEr error_init (error); - if (image_is_dynamic (klass->image)) { + if (image_is_dynamic (m_class_get_image (klass))) { event = mono_metadata_get_corresponding_event_from_generic_type_definition (event); - return lookup_custom_attr (klass->image, event); + return lookup_custom_attr (m_class_get_image (klass), event); } idx = find_event_index (klass, event); idx <<= MONO_CUSTOM_ATTR_BITS; idx |= MONO_CUSTOM_ATTR_EVENT; - return mono_custom_attrs_from_index_checked (klass->image, idx, FALSE, error); + return mono_custom_attrs_from_index_checked (m_class_get_image (klass), idx, FALSE, error); } /** @@ -1564,14 +1607,14 @@ mono_custom_attrs_from_field_checked (MonoClass *klass, MonoClassField *field, M guint32 idx; error_init (error); - if (image_is_dynamic (klass->image)) { + if (image_is_dynamic (m_class_get_image (klass))) { field = mono_metadata_get_corresponding_field_from_generic_type_definition (field); - return lookup_custom_attr (klass->image, field); + return lookup_custom_attr (m_class_get_image (klass), field); } idx = find_field_index (klass, field); idx <<= MONO_CUSTOM_ATTR_BITS; idx |= MONO_CUSTOM_ATTR_FIELDDEF; - return mono_custom_attrs_from_index_checked (klass->image, idx, FALSE, error); + return mono_custom_attrs_from_index_checked (m_class_get_image (klass), idx, FALSE, error); } /** @@ -1622,11 +1665,11 @@ mono_custom_attrs_from_param_checked (MonoMethod *method, guint32 param, MonoErr if (method->is_inflated) method = ((MonoMethodInflated *) method)->declaring; - if (image_is_dynamic (method->klass->image)) { + if (image_is_dynamic (m_class_get_image (method->klass))) { MonoCustomAttrInfo *res, *ainfo; int size; - aux = (MonoReflectionMethodAux *)g_hash_table_lookup (((MonoDynamicImage*)method->klass->image)->method_aux_hash, method); + aux = (MonoReflectionMethodAux *)g_hash_table_lookup (((MonoDynamicImage*)m_class_get_image (method->klass))->method_aux_hash, method); if (!aux || !aux->param_cattr) return NULL; @@ -1640,7 +1683,7 @@ mono_custom_attrs_from_param_checked (MonoMethod *method, guint32 param, MonoErr return res; } - image = method->klass->image; + image = m_class_get_image (method->klass); method_index = mono_method_get_index (method); if (!method_index) return NULL; @@ -1764,6 +1807,7 @@ mono_reflection_get_custom_attrs_info_checked (MonoObjectHandle obj, MonoError * error_init (error); klass = mono_handle_class (obj); + const char *klass_name = m_class_get_name (klass); if (klass == mono_defaults.runtimetype_class) { MonoType *type = mono_reflection_type_handle_mono_type (MONO_HANDLE_CAST(MonoReflectionType, obj), error); goto_if_nok (error, leave); @@ -1771,34 +1815,34 @@ mono_reflection_get_custom_attrs_info_checked (MonoObjectHandle obj, MonoError * /*We cannot mono_class_init the class from which we'll load the custom attributes since this must work with broken types.*/ cinfo = mono_custom_attrs_from_class_checked (klass, error); goto_if_nok (error, leave); - } else if (strcmp ("Assembly", klass->name) == 0 || strcmp ("MonoAssembly", klass->name) == 0) { + } else if (strcmp ("Assembly", klass_name) == 0 || strcmp ("MonoAssembly", klass_name) == 0) { MonoReflectionAssemblyHandle rassembly = MONO_HANDLE_CAST (MonoReflectionAssembly, obj); cinfo = mono_custom_attrs_from_assembly_checked (MONO_HANDLE_GETVAL (rassembly, assembly), FALSE, error); goto_if_nok (error, leave); - } else if (strcmp ("Module", klass->name) == 0 || strcmp ("MonoModule", klass->name) == 0) { + } else if (strcmp ("Module", klass_name) == 0 || strcmp ("MonoModule", klass_name) == 0) { MonoReflectionModuleHandle module = MONO_HANDLE_CAST (MonoReflectionModule, obj); cinfo = mono_custom_attrs_from_module (MONO_HANDLE_GETVAL (module, image), error); goto_if_nok (error, leave); - } else if (strcmp ("MonoProperty", klass->name) == 0) { + } else if (strcmp ("MonoProperty", klass_name) == 0) { MonoReflectionPropertyHandle rprop = MONO_HANDLE_CAST (MonoReflectionProperty, obj); MonoProperty *property = MONO_HANDLE_GETVAL (rprop, property); cinfo = mono_custom_attrs_from_property_checked (property->parent, property, error); goto_if_nok (error, leave); - } else if (strcmp ("MonoEvent", klass->name) == 0) { + } else if (strcmp ("MonoEvent", klass_name) == 0) { MonoReflectionMonoEventHandle revent = MONO_HANDLE_CAST (MonoReflectionMonoEvent, obj); MonoEvent *event = MONO_HANDLE_GETVAL (revent, event); cinfo = mono_custom_attrs_from_event_checked (event->parent, event, error); goto_if_nok (error, leave); - } else if (strcmp ("MonoField", klass->name) == 0) { + } else if (strcmp ("MonoField", klass_name) == 0) { MonoReflectionFieldHandle rfield = MONO_HANDLE_CAST (MonoReflectionField, obj); MonoClassField *field = MONO_HANDLE_GETVAL (rfield, field); cinfo = mono_custom_attrs_from_field_checked (field->parent, field, error); goto_if_nok (error, leave); - } else if ((strcmp ("MonoMethod", klass->name) == 0) || (strcmp ("MonoCMethod", klass->name) == 0)) { + } else if ((strcmp ("MonoMethod", klass_name) == 0) || (strcmp ("MonoCMethod", klass_name) == 0)) { MonoReflectionMethodHandle rmethod = MONO_HANDLE_CAST (MonoReflectionMethod, obj); cinfo = mono_custom_attrs_from_method_checked (MONO_HANDLE_GETVAL (rmethod, method), error); goto_if_nok (error, leave); - } else if (strcmp ("ParameterInfo", klass->name) == 0 || strcmp ("MonoParameterInfo", klass->name) == 0) { + } else if (strcmp ("ParameterInfo", klass_name) == 0 || strcmp ("MonoParameterInfo", klass_name) == 0) { MonoReflectionParameterHandle param = MONO_HANDLE_CAST (MonoReflectionParameter, obj); MonoObjectHandle member_impl = MONO_HANDLE_NEW_GET (MonoObject, param, MemberImpl); MonoClass *member_class = mono_handle_class (member_impl); @@ -1834,48 +1878,48 @@ mono_reflection_get_custom_attrs_info_checked (MonoObjectHandle obj, MonoError * g_free (type_name); goto leave; } - } else if (strcmp ("AssemblyBuilder", klass->name) == 0) { + } else if (strcmp ("AssemblyBuilder", klass_name) == 0) { MonoReflectionAssemblyBuilderHandle assemblyb = MONO_HANDLE_CAST (MonoReflectionAssemblyBuilder, obj); MonoReflectionAssemblyHandle assembly = MONO_HANDLE_CAST (MonoReflectionAssembly, assemblyb); MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, assemblyb, cattrs); MonoImage * image = MONO_HANDLE_GETVAL (assembly, assembly)->image; g_assert (image); cinfo = mono_custom_attrs_from_builders_handle (NULL, image, cattrs); - } else if (strcmp ("TypeBuilder", klass->name) == 0) { + } else if (strcmp ("TypeBuilder", klass_name) == 0) { MonoReflectionTypeBuilderHandle tb = MONO_HANDLE_CAST (MonoReflectionTypeBuilder, obj); MonoReflectionModuleBuilderHandle module = MONO_HANDLE_NEW_GET (MonoReflectionModuleBuilder, tb, module); MonoDynamicImage *dynamic_image = MONO_HANDLE_GETVAL (module, dynamic_image); MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, tb, cattrs); cinfo = mono_custom_attrs_from_builders_handle (NULL, &dynamic_image->image, cattrs); - } else if (strcmp ("ModuleBuilder", klass->name) == 0) { + } else if (strcmp ("ModuleBuilder", klass_name) == 0) { MonoReflectionModuleBuilderHandle mb = MONO_HANDLE_CAST (MonoReflectionModuleBuilder, obj); MonoDynamicImage *dynamic_image = MONO_HANDLE_GETVAL (mb, dynamic_image); MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, mb, cattrs); cinfo = mono_custom_attrs_from_builders_handle (NULL, &dynamic_image->image, cattrs); - } else if (strcmp ("ConstructorBuilder", klass->name) == 0) { + } else if (strcmp ("ConstructorBuilder", klass_name) == 0) { MonoReflectionCtorBuilderHandle cb = MONO_HANDLE_CAST (MonoReflectionCtorBuilder, obj); MonoMethod *mhandle = MONO_HANDLE_GETVAL (cb, mhandle); MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, cb, cattrs); - cinfo = mono_custom_attrs_from_builders_handle (NULL, mhandle->klass->image, cattrs); - } else if (strcmp ("MethodBuilder", klass->name) == 0) { + cinfo = mono_custom_attrs_from_builders_handle (NULL, m_class_get_image (mhandle->klass), cattrs); + } else if (strcmp ("MethodBuilder", klass_name) == 0) { MonoReflectionMethodBuilderHandle mb = MONO_HANDLE_CAST (MonoReflectionMethodBuilder, obj); MonoMethod *mhandle = MONO_HANDLE_GETVAL (mb, mhandle); MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, mb, cattrs); - cinfo = mono_custom_attrs_from_builders_handle (NULL, mhandle->klass->image, cattrs); - } else if (strcmp ("FieldBuilder", klass->name) == 0) { + cinfo = mono_custom_attrs_from_builders_handle (NULL, m_class_get_image (mhandle->klass), cattrs); + } else if (strcmp ("FieldBuilder", klass_name) == 0) { MonoReflectionFieldBuilderHandle fb = MONO_HANDLE_CAST (MonoReflectionFieldBuilder, obj); MonoReflectionTypeBuilderHandle tb = MONO_HANDLE_NEW_GET (MonoReflectionTypeBuilder, fb, typeb); MonoReflectionModuleBuilderHandle mb = MONO_HANDLE_NEW_GET (MonoReflectionModuleBuilder, tb, module); MonoDynamicImage *dynamic_image = MONO_HANDLE_GETVAL (mb, dynamic_image); MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, fb, cattrs); cinfo = mono_custom_attrs_from_builders_handle (NULL, &dynamic_image->image, cattrs); - } else if (strcmp ("MonoGenericClass", klass->name) == 0) { + } else if (strcmp ("MonoGenericClass", klass_name) == 0) { MonoReflectionGenericClassHandle gclass = MONO_HANDLE_CAST (MonoReflectionGenericClass, obj); MonoReflectionTypeHandle generic_type = MONO_HANDLE_NEW_GET (MonoReflectionType, gclass, generic_type); cinfo = mono_reflection_get_custom_attrs_info_checked (MONO_HANDLE_CAST (MonoObject, generic_type), error); goto_if_nok (error, leave); } else { /* handle other types here... */ - g_error ("get custom attrs not yet supported for %s", klass->name); + g_error ("get custom attrs not yet supported for %s", m_class_get_name (klass)); } leave: @@ -2249,9 +2293,9 @@ init_weak_fields_inner (MonoImage *image, GHashTable *indexes) mono_error_cleanup (error); return; } - g_assert (!strcmp (klass->name, "WeakAttribute")); + g_assert (!strcmp (m_class_get_name (klass), "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"))) { + if (klass && (m_class_get_image (klass) == mono_get_corlib () || strstr (m_class_get_image (klass)->name, "Mono.Runtime.Testing"))) { /* Sanity check that it only has 1 ctor */ gpointer iter = NULL; int count = 0; diff --git a/mono/metadata/debug-helpers.c b/mono/metadata/debug-helpers.c index 3742175728..4811d07998 100644 --- a/mono/metadata/debug-helpers.c +++ b/mono/metadata/debug-helpers.c @@ -19,6 +19,17 @@ #include "mono/metadata/debug-helpers.h" #include "mono/metadata/tabledefs.h" #include "mono/metadata/appdomain.h" +#ifdef MONO_CLASS_DEF_PRIVATE +/* Rationale: we want the functions in this file to work even when everything + * is broken. They may be called from a debugger session, for example. If + * MonoClass getters include assertions or trigger class loading, we don't want + * that kicked off by a call to one of the functions in here. + */ +#define REALLY_INCLUDE_CLASS_DEF 1 +#include +#undef REALLY_INCLUDE_CLASS_DEF +#endif + struct MonoMethodDesc { char *name_space; @@ -287,49 +298,6 @@ mono_signature_full_name (MonoMethodSignature *sig) return result; } -/* - * Returns a string ready to be consumed by managed code when formating a string to include class + method name. - * IE, say you have void Foo:Bar(int). It will return "void {0}(int)". - * The reason for this is that managed exception constructors for missing members require a both class and member names to be provided independently of the signature. - */ -char* -mono_signature_get_managed_fmt_string (MonoMethodSignature *sig) -{ - int i; - char *result; - GString *res; - - if (!sig) - return g_strdup (""); - - res = g_string_new (""); - - mono_type_get_desc (res, sig->ret, TRUE); - - g_string_append (res, " {0}"); - - if (sig->generic_param_count) { - g_string_append_c (res, '<'); - for (i = 0; i < sig->generic_param_count; ++i) { - if (i > 0) - g_string_append (res, ","); - g_string_append_printf (res, "!%d", i); - } - g_string_append_c (res, '>'); - } - - g_string_append_c (res, '('); - for (i = 0; i < sig->param_count; ++i) { - if (i > 0) - g_string_append_c (res, ','); - mono_type_get_desc (res, sig->params [i], TRUE); - } - g_string_append_c (res, ')'); - result = res->str; - g_string_free (res, FALSE); - return result; -} - void mono_ginst_get_desc (GString *str, MonoGenericInst *ginst) { diff --git a/mono/metadata/debug-mono-ppdb.c b/mono/metadata/debug-mono-ppdb.c index 4d61efe345..fb209dc41a 100644 --- a/mono/metadata/debug-mono-ppdb.c +++ b/mono/metadata/debug-mono-ppdb.c @@ -370,6 +370,7 @@ mono_ppdb_lookup_location (MonoDebugMethodInfo *minfo, uint32_t offset) location = g_new0 (MonoDebugSourceLocation, 1); location->source_file = docname; location->row = start_line; + location->column = start_col; location->il_offset = iloffset; return location; diff --git a/mono/metadata/decimal-ms.c b/mono/metadata/decimal-ms.c index fe1c04ab7c..1ba9fb3a34 100644 --- a/mono/metadata/decimal-ms.c +++ b/mono/metadata/decimal-ms.c @@ -96,7 +96,7 @@ typedef union { static const SPLIT64 ten_to_eighteen = { 1000000000000000000ULL }; -const MonoDouble_double ds2to64 = { .s = { .sign = 0, .exp = MONO_DOUBLE_BIAS + 65, .mantHi = 0, .mantLo = 0 } }; +static const MonoDouble_double ds2to64 = { .s = { .sign = 0, .exp = MONO_DOUBLE_BIAS + 65, .mantHi = 0, .mantLo = 0 } }; // // Data tables @@ -118,7 +118,7 @@ static const double double_power10[] = { 1e70, 1e71, 1e72, 1e73, 1e74, 1e75, 1e76, 1e77, 1e78, 1e79, 1e80 }; -const SPLIT64 sdl_power10[] = { {10000000000ULL}, // 1E10 +static const SPLIT64 sdl_power10[] = { {10000000000ULL}, // 1E10 {100000000000ULL}, // 1E11 {1000000000000ULL}, // 1E12 {10000000000000ULL}, // 1E13 @@ -150,7 +150,7 @@ typedef struct { uint32_t Hi, Mid, Lo; } DECOVFL; -const DECOVFL power_overflow[] = { +static const DECOVFL power_overflow[] = { // This is a table of the largest values that can be in the upper two // ULONGs of a 96-bit number that will not overflow when multiplied // by a given power. For the upper word, this is a table of diff --git a/mono/metadata/domain-internals.h b/mono/metadata/domain-internals.h index ba58b3e7e1..97e41a59a5 100644 --- a/mono/metadata/domain-internals.h +++ b/mono/metadata/domain-internals.h @@ -391,8 +391,6 @@ struct _MonoDomain { /* Used when accessing 'domain_assemblies' */ mono_mutex_t assemblies_lock; - GHashTable *method_rgctx_hash; - GHashTable *generic_virtual_cases; /* Information maintained by the JIT engine */ @@ -604,7 +602,7 @@ void mono_reflection_cleanup_domain (MonoDomain *domain); void mono_assembly_cleanup_domain_bindings (guint32 domain_id); -MonoJitInfo* mono_jit_info_table_find_internal (MonoDomain *domain, char *addr, gboolean try_aot, gboolean allow_trampolines); +MonoJitInfo* mono_jit_info_table_find_internal (MonoDomain *domain, gpointer addr, gboolean try_aot, gboolean allow_trampolines); void mono_enable_debug_domain_unload (gboolean enable); diff --git a/mono/metadata/domain.c b/mono/metadata/domain.c index 88f3f3f9fa..a4a1726fce 100644 --- a/mono/metadata/domain.c +++ b/mono/metadata/domain.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -123,9 +124,6 @@ get_runtimes_from_exe (const char *exe_file, MonoImage **exe_image, const MonoRu static const MonoRuntimeInfo* get_runtime_by_version (const char *version); -#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1)) -#define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1))) - static LockFreeMempool* lock_free_mempool_new (void) { @@ -441,8 +439,6 @@ mono_domain_create (void) mono_os_mutex_init_recursive (&domain->jit_code_hash_lock); mono_os_mutex_init_recursive (&domain->finalizable_objects_hash_lock); - domain->method_rgctx_hash = NULL; - mono_appdomains_lock (); domain_id_alloc (domain); mono_appdomains_unlock (); @@ -1207,10 +1203,6 @@ mono_domain_free (MonoDomain *domain, gboolean force) g_hash_table_destroy (domain->finalizable_objects_hash); domain->finalizable_objects_hash = NULL; - if (domain->method_rgctx_hash) { - g_hash_table_destroy (domain->method_rgctx_hash); - domain->method_rgctx_hash = NULL; - } if (domain->generic_virtual_cases) { g_hash_table_destroy (domain->generic_virtual_cases); domain->generic_virtual_cases = NULL; diff --git a/mono/metadata/dynamic-image.c b/mono/metadata/dynamic-image.c index e386fbbe73..c9f35d461d 100644 --- a/mono/metadata/dynamic-image.c +++ b/mono/metadata/dynamic-image.c @@ -28,7 +28,7 @@ #include "mono/utils/mono-error-internals.h" #include "mono/utils/mono-os-mutex.h" -const unsigned char table_sizes [MONO_TABLE_NUM] = { +static const unsigned char table_sizes [MONO_TABLE_NUM] = { MONO_MODULE_SIZE, MONO_TYPEREF_SIZE, MONO_TYPEDEF_SIZE, @@ -198,7 +198,7 @@ mono_dynamic_image_register_token (MonoDynamicImage *assembly, guint32 token, Mo MONO_REQ_GC_UNSAFE_MODE; g_assert (!MONO_HANDLE_IS_NULL (obj)); - g_assert (strcmp (mono_handle_class (obj)->name, "EnumBuilder")); + g_assert (strcmp (m_class_get_name (mono_handle_class (obj)), "EnumBuilder")); dynamic_image_lock (assembly); MonoObject *prev = (MonoObject *)mono_g_hash_table_lookup (assembly->tokens, GUINT_TO_POINTER (token)); if (prev) { diff --git a/mono/metadata/environment.c b/mono/metadata/environment.c index b7001b57ac..d002777bfd 100644 --- a/mono/metadata/environment.c +++ b/mono/metadata/environment.c @@ -67,9 +67,24 @@ ves_icall_System_Environment_GetOSVersionString (MonoError *error) verinfo.wServicePackMajor << 16); return mono_string_new_handle (mono_domain_get (), version, error); } +#elif defined(HAVE_SYS_UTSNAME_H) && defined(_AIX) + /* + * AIX puts the major version number in .version and minor in .release; so make a + * version string based on that; other Unices seem to cram everything in .release + * and .version is for things like kernel variants. + */ + struct utsname name; + char version [sizeof(name)]; + + if (uname (&name) >= 0) { + sprintf (version, "%s.%s", name.version, name.release); + return mono_string_new_handle (mono_domain_get (), version, error); + } #elif defined(HAVE_SYS_UTSNAME_H) struct utsname name; + memset (&name, 0, sizeof (name)); // WSL does not always nul terminate. + if (uname (&name) >= 0) { return mono_string_new_handle (mono_domain_get (), name.release, error); } diff --git a/mono/metadata/exception-internals.h b/mono/metadata/exception-internals.h index 2b567e3fd2..ee19d921c4 100644 --- a/mono/metadata/exception-internals.h +++ b/mono/metadata/exception-internals.h @@ -30,15 +30,39 @@ mono_exception_from_token_two_strings_checked (MonoImage *image, uint32_t token, MonoString *a1, MonoString *a2, MonoError *error); -MonoException * -mono_exception_from_name_four_strings_checked (MonoImage *image, const char *name_space, - const char *name, MonoString *a1, MonoString *a2, MonoString *a3, MonoString *a4, - MonoError *error); - - typedef int (*MonoGetSeqPointFunc) (MonoDomain *domain, MonoMethod *method, gint32 native_offset); void mono_install_get_seq_point (MonoGetSeqPointFunc func); +void +mono_error_set_method_missing (MonoError *error, MonoClass *klass, const char *method_name, MonoMethodSignature *sig, const char *reason, ...) MONO_ATTR_FORMAT_PRINTF(5,6); + +void +mono_error_set_field_missing (MonoError *oerror, MonoClass *klass, const char *field_name, MonoType *sig, const char *reason, ...) MONO_ATTR_FORMAT_PRINTF(5,6); + +void +mono_error_set_bad_image (MonoError *error, MonoImage *image, const char *msg_format, ...) MONO_ATTR_FORMAT_PRINTF(3,4); + +void +mono_error_set_bad_image_by_name (MonoError *error, const char *image_name, const char *msg_format, ...) MONO_ATTR_FORMAT_PRINTF(3,4); + +void +mono_error_set_file_not_found (MonoError *oerror, const char *file_name, const char *msg_format, ...) MONO_ATTR_FORMAT_PRINTF(3,4); + +void +mono_error_set_simple_file_not_found (MonoError *oerror, const char *assembly_name, gboolean refection_only); + +MonoException * +mono_corlib_exception_new_with_args (const char *name_space, const char *name, const char *arg_0, const char *arg_1, MonoError *error); + +MonoExceptionHandle +mono_exception_new_argument (const char *arg, const char *msg, MonoError *error); + +MonoExceptionHandle +mono_exception_new_thread_abort (MonoError *error); + +MonoExceptionHandle +mono_exception_new_thread_interrupted (MonoError *error); + #endif diff --git a/mono/metadata/exception.c b/mono/metadata/exception.c index d7aee9e1fd..404fbc6d44 100644 --- a/mono/metadata/exception.c +++ b/mono/metadata/exception.c @@ -34,6 +34,27 @@ static MonoUnhandledExceptionFunc unhandled_exception_hook = NULL; static gpointer unhandled_exception_hook_data = NULL; +static MonoExceptionHandle +mono_exception_new_by_name_domain (MonoDomain *domain, MonoImage *image, + const char* name_space, const char *name, MonoError *error); + +/** + * mono_exception_new_by_name: + * \param image the Mono image where to look for the class + * \param name_space the namespace for the class + * \param name class name + * + * Creates an exception of the given namespace/name class in the + * current domain. + * + * \returns the initialized exception instance. + */ +static MonoExceptionHandle +mono_exception_new_by_name (MonoImage *image, const char *name_space, const char *name, MonoError *error) +{ + return mono_exception_new_by_name_domain (mono_domain_get (), image, name_space, name, error); +} + /** * mono_exception_from_name: * \param image the Mono image where to look for the class @@ -52,6 +73,48 @@ mono_exception_from_name (MonoImage *image, const char *name_space, return mono_exception_from_name_domain (mono_domain_get (), image, name_space, name); } +/** + * mono_exception_new_by_name_domain: + * \param domain Domain where the return object will be created. + * \param image the Mono image where to look for the class + * \param name_space the namespace for the class + * \param name class name + * + * Creates an exception object of the given namespace/name class on + * the given domain. + * + * \returns the initialized exception instance. + */ +static MonoExceptionHandle +mono_exception_new_by_name_domain (MonoDomain *domain, MonoImage *image, + const char* name_space, const char *name, MonoError *error) +{ + HANDLE_FUNCTION_ENTER () + + MonoDomain * const caller_domain = mono_domain_get (); + + MonoClass * const klass = mono_class_load_from_name (image, name_space, name); + + MonoObjectHandle o = mono_object_new_handle (domain, klass, error); + goto_if_nok (error, return_null); + + if (domain != caller_domain) + mono_domain_set_internal (domain); + + mono_runtime_object_init_handle (o, error); + mono_error_assert_ok (error); + + // Restore domain in success and error path. + if (domain != caller_domain) + mono_domain_set_internal (caller_domain); + + goto_if_ok (error, exit); +return_null: + MONO_HANDLE_ASSIGN (o, NULL); +exit: + HANDLE_FUNCTION_RETURN_REF (MonoException, o); +} + /** * mono_exception_from_name_domain: * \param domain Domain where the return object will be created. @@ -215,6 +278,40 @@ mono_exception_from_name_two_strings_checked (MonoImage *image, const char *name return create_exception_two_strings (klass, a1, a2, error); } +/** + * mono_exception_new_by_name_msg: + * \param image the Mono image where to look for the class + * \param name_space the namespace for the class + * \param name class name + * \param msg the message to embed inside the exception + * + * Creates an exception and initializes its message field. + * + * \returns the initialized exception instance. + */ +static MonoExceptionHandle +mono_exception_new_by_name_msg (MonoImage *image, const char *name_space, + const char *name, const char *msg, MonoError *error) +{ + HANDLE_FUNCTION_ENTER () + + MonoExceptionHandle ex = mono_exception_new_by_name (image, name_space, name, error); + goto_if_nok (error, return_null); + + if (msg) { + MonoStringHandle msg_str = mono_string_new_handle (MONO_HANDLE_DOMAIN (ex), msg, error); + // FIXME? Maybe just ignore this error, the exception is close to correct. + goto_if_nok (error, return_null); + // ex->message = msg_str; + MONO_HANDLE_SET (ex, message, msg_str); + } + goto exit; +return_null: + MONO_HANDLE_ASSIGN (ex, NULL); +exit: + HANDLE_FUNCTION_RETURN_REF (MonoException, ex) +} + /** * mono_exception_from_name_msg: * \param image the Mono image where to look for the class @@ -304,6 +401,16 @@ mono_get_exception_security () "SecurityException"); } +/** + * mono_exception_new_thread_abort: + * \returns a new instance of the \c System.Threading.ThreadAbortException + */ +MonoExceptionHandle +mono_exception_new_thread_abort (MonoError *error) +{ + return mono_exception_new_by_name (mono_get_corlib (), "System.Threading", "ThreadAbortException", error); +} + /** * mono_get_exception_thread_abort: * \returns a new instance of the \c System.Threading.ThreadAbortException @@ -315,6 +422,16 @@ mono_get_exception_thread_abort () "ThreadAbortException"); } +/** + * mono_exception_new_thread_interrupted: + * \returns a new instance of the \c System.Threading.ThreadInterruptedException + */ +MonoExceptionHandle +mono_exception_new_thread_interrupted (MonoError *error) +{ + return mono_exception_new_by_name (mono_get_corlib (), "System.Threading", "ThreadInterruptedException", error); +} + /** * mono_get_exception_thread_interrupted: * \returns a new instance of the \c System.Threading.ThreadInterruptedException @@ -560,6 +677,23 @@ mono_get_exception_argument (const char *arg, const char *msg) return ex; } +TYPED_HANDLE_DECL (MonoArgumentException); + +MonoExceptionHandle +mono_exception_new_argument (const char *arg, const char *msg, MonoError *error) +{ + MonoExceptionHandle ex; + ex = mono_exception_new_by_name_msg (mono_get_corlib (), "System", "ArgumentException", msg, error); + + if (arg && !MONO_HANDLE_IS_NULL (ex)) { + MonoArgumentExceptionHandle argex = (MonoArgumentExceptionHandle)ex; + MonoStringHandle arg_str = mono_string_new_handle (MONO_HANDLE_DOMAIN (ex), arg, error); + MONO_HANDLE_SET (argex, param_name, arg_str); + } + + return ex; +} + /** * mono_get_exception_argument_out_of_range: * \param arg the name of the out of range argument. @@ -850,10 +984,7 @@ mono_get_exception_reflection_type_load (MonoArray *types_raw, MonoArray *except if (is_ok (error)) { mono_error_cleanup (error); ret = MONO_HANDLE_CAST (MonoException, NULL_HANDLE); - goto leave; } - -leave: HANDLE_FUNCTION_RETURN_OBJ (ret); } @@ -920,7 +1051,6 @@ mono_get_exception_runtime_wrapped_checked (MonoObject *wrapped_exception, MonoE MonoObject *o; MonoMethod *method; MonoDomain *domain = mono_domain_get (); - gpointer params [16]; klass = mono_class_load_from_name (mono_get_corlib (), "System.Runtime.CompilerServices", "RuntimeWrappedException"); @@ -931,9 +1061,7 @@ mono_get_exception_runtime_wrapped_checked (MonoObject *wrapped_exception, MonoE method = mono_class_get_method_from_name (klass, ".ctor", 1); g_assert (method); - params [0] = wrapped_exception; - - mono_runtime_invoke_checked (method, o, params, error); + mono_runtime_invoke_checked (method, o, (gpointer*)&wrapped_exception, error); return_val_if_nok (error, NULL); return (MonoException *)o; @@ -996,7 +1124,7 @@ mono_exception_handle_get_native_backtrace (MonoExceptionHandle exc) for (i = 0; i < len; ++i) { gpointer ip; MONO_HANDLE_ARRAY_GETVAL (ip, arr, gpointer, i); - MonoJitInfo *ji = mono_jit_info_table_find (mono_domain_get (), (char *)ip); + MonoJitInfo *ji = mono_jit_info_table_find (mono_domain_get (), ip); if (ji) { char *msg = mono_debug_print_stack_frame (mono_jit_info_get_method (ji), (char*)ip - (char*)ji->code_start, domain); g_string_append_printf (text, "%s\n", msg); @@ -1119,67 +1247,186 @@ mono_invoke_unhandled_exception_hook (MonoObject *exc) g_assert_not_reached (); } - -static MonoException * -create_exception_four_strings (MonoClass *klass, MonoString *a1, MonoString *a2, MonoString *a3, MonoString *a4, MonoError *error) +MonoException * +mono_corlib_exception_new_with_args (const char *name_space, const char *name, const char *arg_0, const char *arg_1, MonoError *error) { MonoDomain *domain = mono_domain_get (); - MonoMethod *method = NULL; - MonoObject *o; - int count = 4; - gpointer args [4]; - gpointer iter; - MonoMethod *m; + MonoString *str_0, *str_1; + error_init (error); - o = mono_object_new_checked (domain, klass, error); - mono_error_assert_ok (error); - - iter = NULL; - while ((m = mono_class_get_methods (klass, &iter))) { - MonoMethodSignature *sig; - - if (strcmp (".ctor", mono_method_get_name (m))) - continue; - sig = mono_method_signature (m); - if (sig->param_count != count) - continue; - - int i; - gboolean good = TRUE; - for (i = 0; i < count; ++i) { - if (sig->params [i]->type != MONO_TYPE_STRING) { - good = FALSE; - break; - } - } - if (good) { - method = m; - break; - } - } - - g_assert (method); - - args [0] = a1; - args [1] = a2; - args [2] = a3; - args [3] = a4; - - mono_runtime_invoke_checked (method, o, args, error); + str_0 = arg_0 ? mono_string_new_checked (domain, arg_0, error) : NULL; return_val_if_nok (error, NULL); - return (MonoException *) o; + str_1 = arg_1 ? mono_string_new_checked (domain, arg_1, error) : NULL; + return_val_if_nok (error, NULL); + + return mono_exception_from_name_two_strings_checked (mono_defaults.corlib, name_space, name, str_0, str_1, error); } -MonoException * -mono_exception_from_name_four_strings_checked (MonoImage *image, const char *name_space, - const char *name, MonoString *a1, MonoString *a2, MonoString *a3, MonoString *a4, - MonoError *error) +void +mono_error_set_field_missing (MonoError *error, MonoClass *klass, const char *field_name, MonoType *sig, const char *reason, ...) { - MonoClass *klass; + char *result; + GString *res; - error_init (error); - klass = mono_class_load_from_name (image, name_space, name); + res = g_string_new ("Field not found: "); - return create_exception_four_strings (klass, a1, a2, a3, a4, error); + + if (sig) { + mono_type_get_desc (res, sig, TRUE); + g_string_append_c (res, ' '); + } + + if (klass) { + if (m_class_get_name_space (klass)) { + g_string_append (res, m_class_get_name_space (klass)); + g_string_append_c (res, '.'); + } + g_string_append (res, m_class_get_name (klass)); + } + else { + g_string_append (res, ""); + } + + g_string_append_c (res, '.'); + + if (field_name) + g_string_append (res, field_name); + else + g_string_append (res, ""); + + if (reason && *reason) { + va_list args; + va_start (args, reason); + + g_string_append (res, " Due to: "); + g_string_append_vprintf (res, reason, args); + va_end (args); + } + result = res->str; + g_string_free (res, FALSE); + + mono_error_set_specific (error, MONO_ERROR_MISSING_FIELD, result); +} + +/* + * Sets @error to a method missing error. + */ +void +mono_error_set_method_missing (MonoError *error, MonoClass *klass, const char *method_name, MonoMethodSignature *sig, const char *reason, ...) +{ + int i; + char *result; + GString *res; + + res = g_string_new ("Method not found: "); + + if (sig) { + mono_type_get_desc (res, sig->ret, TRUE); + + g_string_append_c (res, ' '); + } + + if (klass) { + if (m_class_get_name_space (klass)) { + g_string_append (res, m_class_get_name_space (klass)); + g_string_append_c (res, '.'); + } + g_string_append (res, m_class_get_name (klass)); + } + else { + g_string_append (res, ""); + } + + g_string_append_c (res, '.'); + + if (method_name) + g_string_append (res, method_name); + else + g_string_append (res, ""); + + if (sig) { + if (sig->generic_param_count) { + g_string_append_c (res, '<'); + for (i = 0; i < sig->generic_param_count; ++i) { + if (i > 0) + g_string_append (res, ","); + g_string_append_printf (res, "!%d", i); + } + g_string_append_c (res, '>'); + } + + g_string_append_c (res, '('); + for (i = 0; i < sig->param_count; ++i) { + if (i > 0) + g_string_append_c (res, ','); + mono_type_get_desc (res, sig->params [i], TRUE); + } + g_string_append_c (res, ')'); + } + + if (reason && *reason) { + va_list args; + va_start (args, reason); + + g_string_append (res, " Due to: "); + g_string_append_vprintf (res, reason, args); + va_end (args); + } + result = res->str; + g_string_free (res, FALSE); + + mono_error_set_specific (error, MONO_ERROR_MISSING_METHOD, result); +} + +#define SET_ERROR_MSG(STR_VAR, FMT_STR) do { \ + va_list __args; \ + va_start (__args, FMT_STR); \ + STR_VAR = g_strdup_vprintf (FMT_STR, __args); \ + va_end(__args); \ +} while (0); + +/** + * \p image_name argument will be g_strdup'd. Called must free passed value + */ +void +mono_error_set_bad_image_by_name (MonoError *error, const char *image_name, const char *msg_format, ...) +{ + char *str; + SET_ERROR_MSG (str, msg_format); + + mono_error_set_specific (error, MONO_ERROR_BAD_IMAGE, str); + if (image_name) + mono_error_set_first_argument (error, image_name); +} + +void +mono_error_set_bad_image (MonoError *error, MonoImage *image, const char *msg_format, ...) +{ + char *str; + SET_ERROR_MSG (str, msg_format); + + mono_error_set_specific (error, MONO_ERROR_BAD_IMAGE, str); + if (image) + mono_error_set_first_argument (error, mono_image_get_name (image)); +} + +void +mono_error_set_file_not_found (MonoError *error, const char *file_name, const char *msg_format, ...) +{ + char *str; + SET_ERROR_MSG (str, msg_format); + + mono_error_set_specific (error, MONO_ERROR_FILE_NOT_FOUND, str); + if (file_name) + mono_error_set_first_argument (error, file_name); +} + +void +mono_error_set_simple_file_not_found (MonoError *error, const char *file_name, gboolean refection_only) +{ + if (refection_only) + mono_error_set_file_not_found (error, file_name, "Cannot resolve dependency to assembly because it has not been preloaded. When using the ReflectionOnly APIs, dependent assemblies must be pre-loaded or loaded on demand through the ReflectionOnlyAssemblyResolve event."); + else + mono_error_set_file_not_found (error, file_name, "Could not load file or assembly '%s' or one of its dependencies.", file_name); } diff --git a/mono/metadata/exception.h b/mono/metadata/exception.h index 6575694c7c..95b2521fda 100644 --- a/mono/metadata/exception.h +++ b/mono/metadata/exception.h @@ -5,6 +5,7 @@ #ifndef _MONO_METADATA_EXCEPTION_H_ #define _MONO_METADATA_EXCEPTION_H_ +#include #include #include diff --git a/mono/metadata/file-mmap-posix.c b/mono/metadata/file-mmap-posix.c index b936caa0fa..32618afd8f 100644 --- a/mono/metadata/file-mmap-posix.c +++ b/mono/metadata/file-mmap-posix.c @@ -379,24 +379,21 @@ done: /* This is an icall */ void * -mono_mmap_open_file (MonoString *path, int mode, MonoString *mapName, gint64 *capacity, int access, int options, int *ioerror) +mono_mmap_open_file (const gunichar2 *path, gint path_length, int mode, const gunichar2 *mapName, gint mapName_length, gint64 *capacity, int access, int options, int *ioerror, MonoError *error) { - ERROR_DECL (error); MmapHandle *handle = NULL; g_assert (path || mapName); if (!mapName) { - char * c_path = mono_string_to_utf8_checked (path, error); - if (mono_error_set_pending_exception (error)) - return NULL; + char * c_path = mono_utf16_to_utf8 (path, path_length, error); + return_val_if_nok (error, NULL); handle = open_file_map (c_path, -1, mode, capacity, access, options, ioerror); g_free (c_path); return handle; } - char *c_mapName = mono_string_to_utf8_checked (mapName, error); - if (mono_error_set_pending_exception (error)) - return NULL; + char *c_mapName = mono_utf16_to_utf8 (mapName, mapName_length, error); + return_val_if_nok (error, NULL); if (path) { named_regions_lock (); @@ -405,7 +402,7 @@ mono_mmap_open_file (MonoString *path, int mode, MonoString *mapName, gint64 *ca *ioerror = FILE_ALREADY_EXISTS; handle = NULL; } else { - char *c_path = mono_string_to_utf8_checked (path, error); + char *c_path = mono_utf16_to_utf8 (path, path_length, error); if (is_ok (error)) { handle = (MmapHandle *)open_file_map (c_path, -1, mode, capacity, access, options, ioerror); if (handle) { @@ -427,16 +424,14 @@ mono_mmap_open_file (MonoString *path, int mode, MonoString *mapName, gint64 *ca /* this is an icall */ void * -mono_mmap_open_handle (void *input_fd, MonoString *mapName, gint64 *capacity, int access, int options, int *ioerror) +mono_mmap_open_handle (void *input_fd, const mono_unichar2 *mapName, gint mapName_length, gint64 *capacity, int access, int options, int *ioerror, MonoError *error) { - ERROR_DECL (error); MmapHandle *handle; if (!mapName) { handle = (MmapHandle *)open_file_map (NULL, GPOINTER_TO_INT (input_fd), FILE_MODE_OPEN, capacity, access, options, ioerror); } else { - char *c_mapName = mono_string_to_utf8_checked (mapName, error); - if (mono_error_set_pending_exception (error)) - return NULL; + char *c_mapName = mono_utf16_to_utf8 (mapName, mapName_length, error); + return_val_if_nok (error, NULL); named_regions_lock (); handle = (MmapHandle*)g_hash_table_lookup (named_regions, c_mapName); @@ -457,7 +452,7 @@ mono_mmap_open_handle (void *input_fd, MonoString *mapName, gint64 *capacity, in } void -mono_mmap_close (void *mmap_handle) +mono_mmap_close (void *mmap_handle, MonoError *error) { MmapHandle *handle = (MmapHandle *)mmap_handle; @@ -475,7 +470,7 @@ mono_mmap_close (void *mmap_handle) } void -mono_mmap_configure_inheritability (void *mmap_handle, gboolean inheritability) +mono_mmap_configure_inheritability (void *mmap_handle, gboolean inheritability, MonoError *error) { MmapHandle *h = (MmapHandle *)mmap_handle; int fd, flags; @@ -490,7 +485,7 @@ mono_mmap_configure_inheritability (void *mmap_handle, gboolean inheritability) } void -mono_mmap_flush (void *mmap_handle) +mono_mmap_flush (void *mmap_handle, MonoError *error) { MmapInstance *h = (MmapInstance *)mmap_handle; @@ -499,7 +494,7 @@ mono_mmap_flush (void *mmap_handle) } int -mono_mmap_map (void *handle, gint64 offset, gint64 *size, int access, void **mmap_handle, void **base_address) +mono_mmap_map (void *handle, gint64 offset, gint64 *size, int access, void **mmap_handle, void **base_address, MonoError *error) { gint64 mmap_offset = 0; MmapHandle *fh = (MmapHandle *)handle; @@ -538,7 +533,7 @@ mono_mmap_map (void *handle, gint64 offset, gint64 *size, int access, void **mma } gboolean -mono_mmap_unmap (void *mmap_handle) +mono_mmap_unmap (void *mmap_handle, MonoError *error) { int res = 0; MmapInstance *h = (MmapInstance *)mmap_handle; diff --git a/mono/metadata/file-mmap-windows.c b/mono/metadata/file-mmap-windows.c index d5178b096c..2cb918779b 100644 --- a/mono/metadata/file-mmap-windows.c +++ b/mono/metadata/file-mmap-windows.c @@ -118,9 +118,9 @@ static int get_file_map_access (int access) } } -static int convert_win32_error (int error, int def) +static int convert_win32_error (int win32error, int default_) { - switch (error) { + switch (win32error) { case ERROR_FILE_NOT_FOUND: return FILE_NOT_FOUND; case ERROR_FILE_EXISTS: @@ -129,69 +129,67 @@ static int convert_win32_error (int error, int def) case ERROR_ACCESS_DENIED: return ACCESS_DENIED; } - return def; + return default_; } -static void *open_handle (void *handle, MonoString *mapName, int mode, gint64 *capacity, int access, int options, int *error) +static void* +open_handle (void *handle, const gunichar2 *mapName, gint mapName_length, int mode, gint64 *capacity, int access, int options, int *ioerror, MonoError *error) { g_assert (handle != NULL); - wchar_t *w_mapName = NULL; - HANDLE result = NULL; - // INVALID_HANDLE_VALUE (-1) is valid, to make named shared memory, // backed by physical memory / pagefile. if (handle == INVALID_HANDLE_VALUE) { if (*capacity <= 0 && mode != FILE_MODE_OPEN) { - *error = CAPACITY_MUST_BE_POSITIVE; + *ioerror = CAPACITY_MUST_BE_POSITIVE; return NULL; } #if SIZEOF_VOID_P == 4 if (*capacity > UINT32_MAX) { - *error = CAPACITY_LARGER_THAN_LOGICAL_ADDRESS_SPACE; + *ioerror = CAPACITY_LARGER_THAN_LOGICAL_ADDRESS_SPACE; return NULL; } #endif if (!(mode == FILE_MODE_CREATE_NEW || mode == FILE_MODE_OPEN_OR_CREATE || mode == FILE_MODE_OPEN)) { - *error = INVALID_FILE_MODE; + *ioerror = INVALID_FILE_MODE; return NULL; } } else { FILE_STANDARD_INFO info; if (!GetFileInformationByHandleEx (handle, FileStandardInfo, &info, sizeof (FILE_STANDARD_INFO))) { - *error = convert_win32_error (GetLastError (), COULD_NOT_OPEN); + *ioerror = convert_win32_error (GetLastError (), COULD_NOT_OPEN); return NULL; } if (*capacity == 0) { if (info.EndOfFile.QuadPart == 0) { - *error = CAPACITY_SMALLER_THAN_FILE_SIZE; + *ioerror = CAPACITY_SMALLER_THAN_FILE_SIZE; return NULL; } } else if (*capacity < info.EndOfFile.QuadPart) { - *error = CAPACITY_SMALLER_THAN_FILE_SIZE; + *ioerror = CAPACITY_SMALLER_THAN_FILE_SIZE; return NULL; } } - w_mapName = mapName ? mono_string_chars (mapName) : NULL; + HANDLE result = NULL; if (mode == FILE_MODE_CREATE_NEW || handle != INVALID_HANDLE_VALUE) { - result = CreateFileMappingW (handle, NULL, get_page_access (access) | options, (DWORD)(((guint64)*capacity) >> 32), (DWORD)*capacity, w_mapName); + result = CreateFileMappingW (handle, NULL, get_page_access (access) | options, (DWORD)(((guint64)*capacity) >> 32), (DWORD)*capacity, mapName); if (result && GetLastError () == ERROR_ALREADY_EXISTS) { CloseHandle (result); result = NULL; - *error = FILE_ALREADY_EXISTS; + *ioerror = FILE_ALREADY_EXISTS; } else if (!result && GetLastError () != NO_ERROR) { - *error = convert_win32_error (GetLastError (), COULD_NOT_OPEN); + *ioerror = convert_win32_error (GetLastError (), COULD_NOT_OPEN); } } else if (mode == FILE_MODE_OPEN || mode == FILE_MODE_OPEN_OR_CREATE && access == MMAP_FILE_ACCESS_WRITE) { - result = OpenFileMappingW (get_file_map_access (access), FALSE, w_mapName); + result = OpenFileMappingW (get_file_map_access (access), FALSE, mapName); if (!result) { if (mode == FILE_MODE_OPEN_OR_CREATE && GetLastError () == ERROR_FILE_NOT_FOUND) { - *error = INVALID_FILE_MODE; + *ioerror = INVALID_FILE_MODE; } else { - *error = convert_win32_error (GetLastError (), COULD_NOT_OPEN); + *ioerror = convert_win32_error (GetLastError (), COULD_NOT_OPEN); } } } else if (mode == FILE_MODE_OPEN_OR_CREATE) { @@ -212,18 +210,18 @@ static void *open_handle (void *handle, MonoString *mapName, int mode, gint64 *c guint32 waitSleep = 0; while (waitRetries > 0) { - result = CreateFileMappingW (handle, NULL, get_page_access (access) | options, (DWORD)(((guint64)*capacity) >> 32), (DWORD)*capacity, w_mapName); + result = CreateFileMappingW (handle, NULL, get_page_access (access) | options, (DWORD)(((guint64)*capacity) >> 32), (DWORD)*capacity, mapName); if (result) break; if (GetLastError() != ERROR_ACCESS_DENIED) { - *error = convert_win32_error (GetLastError (), COULD_NOT_OPEN); + *ioerror = convert_win32_error (GetLastError (), COULD_NOT_OPEN); break; } - result = OpenFileMappingW (get_file_map_access (access), FALSE, w_mapName); + result = OpenFileMappingW (get_file_map_access (access), FALSE, mapName); if (result) break; if (GetLastError () != ERROR_FILE_NOT_FOUND) { - *error = convert_win32_error (GetLastError (), COULD_NOT_OPEN); + *ioerror = convert_win32_error (GetLastError (), COULD_NOT_OPEN); break; } // increase wait time @@ -237,33 +235,32 @@ static void *open_handle (void *handle, MonoString *mapName, int mode, gint64 *c } if (!result) { - *error = COULD_NOT_OPEN; + *ioerror = COULD_NOT_OPEN; } } return result; } -void *mono_mmap_open_file (MonoString *path, int mode, MonoString *mapName, gint64 *capacity, int access, int options, int *error) +void* +mono_mmap_open_file (const gunichar2 *path, gint path_length, int mode, const gunichar2 *mapName, gint mapName_length, gint64 *capacity, int access, int options, int *ioerror, MonoError *error) { g_assert (path != NULL || mapName != NULL); - wchar_t *w_path = NULL; HANDLE hFile = INVALID_HANDLE_VALUE; HANDLE result = NULL; gboolean delete_on_error = FALSE; if (path) { - w_path = mono_string_chars (path); WIN32_FILE_ATTRIBUTE_DATA file_attrs; - gboolean existed = GetFileAttributesExW (w_path, GetFileExInfoStandard, &file_attrs); + gboolean existed = GetFileAttributesExW (path, GetFileExInfoStandard, &file_attrs); if (!existed && mode == FILE_MODE_CREATE_NEW && *capacity == 0) { - *error = CAPACITY_SMALLER_THAN_FILE_SIZE; + *ioerror = CAPACITY_SMALLER_THAN_FILE_SIZE; goto done; } - hFile = CreateFileW (w_path, get_file_access (access), FILE_SHARE_READ, NULL, mode, FILE_ATTRIBUTE_NORMAL, NULL); + hFile = CreateFileW (path, get_file_access (access), FILE_SHARE_READ, NULL, mode, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { - *error = convert_win32_error (GetLastError (), COULD_NOT_OPEN); + *ioerror = convert_win32_error (GetLastError (), COULD_NOT_OPEN); goto done; } delete_on_error = !existed; @@ -272,31 +269,34 @@ void *mono_mmap_open_file (MonoString *path, int mode, MonoString *mapName, gint // backed by physical memory / pagefile. } - result = open_handle (hFile, mapName, mode, capacity, access, options, error); + result = open_handle (hFile, mapName, mapName_length, mode, capacity, access, options, ioerror, error); done: if (hFile != INVALID_HANDLE_VALUE) CloseHandle (hFile); if (!result && delete_on_error) - DeleteFileW (w_path); + DeleteFileW (path); return result; } -void *mono_mmap_open_handle (void *handle, MonoString *mapName, gint64 *capacity, int access, int options, int *error) +void* +mono_mmap_open_handle (void *handle, const gunichar2 *mapName, gint mapName_length, gint64 *capacity, int access, int options, int *ioerror, MonoError *error) { g_assert (handle != NULL); - return open_handle (handle, mapName, FILE_MODE_OPEN, capacity, access, options, error); + return open_handle (handle, mapName, mapName_length, FILE_MODE_OPEN, capacity, access, options, ioerror, error); } -void mono_mmap_close (void *mmap_handle) +void +mono_mmap_close (void *mmap_handle, MonoError *error) { g_assert (mmap_handle); CloseHandle (mmap_handle); } -void mono_mmap_configure_inheritability (void *mmap_handle, gboolean inheritability) +void +mono_mmap_configure_inheritability (void *mmap_handle, gboolean inheritability, MonoError *error) { g_assert (mmap_handle); if (!SetHandleInformation (mmap_handle, HANDLE_FLAG_INHERIT, inheritability ? HANDLE_FLAG_INHERIT : 0)) { @@ -304,7 +304,8 @@ void mono_mmap_configure_inheritability (void *mmap_handle, gboolean inheritabil } } -void mono_mmap_flush (void *mmap_handle) +void +mono_mmap_flush (void *mmap_handle, MonoError *error) { g_assert (mmap_handle); MmapInstance *h = (MmapInstance *)mmap_handle; @@ -345,7 +346,8 @@ void mono_mmap_flush (void *mmap_handle) // TODO: Propagate error to caller } -int mono_mmap_map (void *handle, gint64 offset, gint64 *size, int access, void **mmap_handle, void **base_address) +int +mono_mmap_map (void *handle, gint64 offset, gint64 *size, int access, void **mmap_handle, void **base_address, MonoError *error) { static DWORD allocationGranularity = 0; if (allocationGranularity == 0) { @@ -404,7 +406,8 @@ int mono_mmap_map (void *handle, gint64 offset, gint64 *size, int access, void * return 0; } -gboolean mono_mmap_unmap (void *mmap_handle) +gboolean +mono_mmap_unmap (void *mmap_handle, MonoError *error) { g_assert (mmap_handle); diff --git a/mono/metadata/file-mmap.h b/mono/metadata/file-mmap.h index 93d1f05afa..2a79e8474e 100644 --- a/mono/metadata/file-mmap.h +++ b/mono/metadata/file-mmap.h @@ -18,18 +18,25 @@ #include #include -extern void mono_mmap_close (void *mmap_handle); +void +mono_mmap_close (void *mmap_handle, MonoError *error); -extern void mono_mmap_configure_inheritability (void *mmap_handle, gboolean inheritability); +void +mono_mmap_configure_inheritability (void *mmap_handle, gboolean inheritability, MonoError *error); -extern void mono_mmap_flush (void *mmap_handle); +void +mono_mmap_flush (void *mmap_handle, MonoError *error); -extern void *mono_mmap_open_file (MonoString *string, int mode, MonoString *mapName, gint64 *capacity, int access, int options, int *error); +void* +mono_mmap_open_file (const gunichar2 *path, gint path_length, int mode, const gunichar2 *mapName, gint mapName_length, gint64 *capacity, int access, int options, int *win32error, MonoError *error); -extern void *mono_mmap_open_handle (void *handle, MonoString *mapName, gint64 *capacity, int access, int options, int *error); +void* +mono_mmap_open_handle (void *handle, const gunichar2 *mapName, gint mapName_length, gint64 *capacity, int access, int options, int *win32error, MonoError *error); -extern int mono_mmap_map (void *handle, gint64 offset, gint64 *size, int access, void **mmap_handle, void **base_address); +int +mono_mmap_map (void *handle, gint64 offset, gint64 *size, int access, void **mmap_handle, void **base_address, MonoError *error); -extern gboolean mono_mmap_unmap (void *base_address); +gboolean +mono_mmap_unmap (void *base_address, MonoError *error); #endif /* _MONO_METADATA_FILE_MMAP_H_ */ diff --git a/mono/metadata/filewatcher.c b/mono/metadata/filewatcher.c index f0b8b14800..b5d642ee8f 100644 --- a/mono/metadata/filewatcher.c +++ b/mono/metadata/filewatcher.c @@ -59,8 +59,13 @@ static int (*FAMNextEvent) (gpointer, gpointer); gint ves_icall_System_IO_FSW_SupportsFSW (void) { -#if HAVE_KQUEUE - return 3; +#if defined(__APPLE__) + if (getenv ("MONO_DARWIN_USE_KQUEUE_FSW")) + return 3; /* kqueue */ + else + return 6; /* FSEvent */ +#elif HAVE_KQUEUE + return 3; /* kqueue */ #else MonoDl *fam_module; int lib_used = 4; /* gamin */ @@ -260,3 +265,42 @@ ves_icall_System_IO_KqueueMonitor_kevent_notimeout (int *kq_ptr, gpointer change #endif /* #if HAVE_KQUEUE */ +#if defined(__APPLE__) + +#include + +static void +interrupt_CFRunLoop (gpointer data) +{ + g_assert (data); + CFRunLoopStop(data); +} + +void +ves_icall_CoreFX_Interop_RunLoop_CFRunLoopRun (void) +{ + gpointer runloop_ref = CFRunLoopGetCurrent(); + gboolean interrupted; + mono_thread_info_install_interrupt (interrupt_CFRunLoop, runloop_ref, &interrupted); + + if (interrupted) + return; + + MONO_ENTER_GC_SAFE; + CFRunLoopRun(); + MONO_EXIT_GC_SAFE; + + mono_thread_info_uninstall_interrupt (&interrupted); +} + +MONO_API char* SystemNative_RealPath(const char* path) +{ + g_assert(path != NULL); + return realpath(path, NULL); +} + +MONO_API void SystemNative_Sync(void) +{ + sync(); +} +#endif /* #if defined(__APPLE__) */ diff --git a/mono/metadata/filewatcher.h b/mono/metadata/filewatcher.h index 2a0f8b0e62..65f68473e3 100644 --- a/mono/metadata/filewatcher.h +++ b/mono/metadata/filewatcher.h @@ -34,6 +34,12 @@ int ves_icall_System_IO_InotifyWatcher_RemoveWatch (int fd, gint32 watch_descrip int ves_icall_System_IO_KqueueMonitor_kevent_notimeout (int *kq, gpointer changelist, int nchanges, gpointer eventlist, int nevents); +#if defined(__APPLE__) +void ves_icall_CoreFX_Interop_RunLoop_CFRunLoopRun (void); +MONO_API char* SystemNative_RealPath(const char* path); +MONO_API void SystemNative_Sync (void); +#endif + G_END_DECLS #endif diff --git a/mono/metadata/gc-internals.h b/mono/metadata/gc-internals.h index 7c3cb01466..4867847af0 100644 --- a/mono/metadata/gc-internals.h +++ b/mono/metadata/gc-internals.h @@ -57,6 +57,9 @@ #define IS_GC_REFERENCE(class,t) (mono_gc_is_moving () ? FALSE : ((t)->type == MONO_TYPE_U && (class)->image == mono_defaults.corlib)) void mono_object_register_finalizer (MonoObject *obj); +void +mono_object_register_finalizer_handle (MonoObjectHandle obj); + void ves_icall_System_GC_InternalCollect (int generation); gint64 ves_icall_System_GC_GetTotalMemory (MonoBoolean forceCollection); void ves_icall_System_GC_KeepAlive (MonoObject *obj); @@ -131,16 +134,43 @@ void mono_gchandle_free_domain (MonoDomain *domain); typedef void (*FinalizerThreadCallback) (gpointer user_data); void* mono_gc_alloc_pinned_obj (MonoVTable *vtable, size_t size); + +MonoObjectHandle +mono_gc_alloc_handle_pinned_obj (MonoVTable *vtable, gsize size); + void* mono_gc_alloc_obj (MonoVTable *vtable, size_t size); + +MonoObjectHandle +mono_gc_alloc_handle_obj (MonoVTable *vtable, gsize size); + void* mono_gc_alloc_vector (MonoVTable *vtable, size_t size, uintptr_t max_length); + +MonoArrayHandle +mono_gc_alloc_handle_vector (MonoVTable *vtable, gsize size, gsize max_length); + void* mono_gc_alloc_array (MonoVTable *vtable, size_t size, uintptr_t max_length, uintptr_t bounds_size); + +MonoArrayHandle +mono_gc_alloc_handle_array (MonoVTable *vtable, gsize size, gsize max_length, gsize bounds_size); + void* mono_gc_alloc_string (MonoVTable *vtable, size_t size, gint32 len); + +MonoStringHandle +mono_gc_alloc_handle_string (MonoVTable *vtable, gsize 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); +MonoObjectHandle +mono_gc_alloc_handle_mature (MonoVTable *vtable, gsize size); -void mono_gc_register_for_finalization (MonoObject *obj, void *user_data); +void mono_gc_register_obj_with_weak_fields (void *obj); +void +mono_gc_register_object_with_weak_fields (MonoObjectHandle obj); + +typedef void (*MonoFinalizationProc)(gpointer, gpointer); // same as SGenFinalizationProc, GC_finalization_proc + +void mono_gc_register_for_finalization (MonoObject *obj, MonoFinalizationProc 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, void *key, const char *msg); void mono_gc_deregister_root (char* addr); @@ -289,7 +319,9 @@ gboolean mono_gc_card_table_nursery_check (void); void* mono_gc_get_nursery (int *shift_bits, size_t *size); -void mono_gc_set_skip_thread (gboolean skip); +// Don't use directly; set/unset MONO_THREAD_INFO_FLAGS_NO_GC instead. +void mono_gc_skip_thread_changing (gboolean skip); +void mono_gc_skip_thread_changed (gboolean skip); #ifndef HOST_WIN32 int mono_gc_pthread_create (pthread_t *new_thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg); @@ -363,7 +395,7 @@ void mono_gc_thread_detach_with_lock (THREAD_INFO_TYPE *info); gboolean mono_gc_thread_in_critical_region (THREAD_INFO_TYPE *info); /* If set, print debugging messages around finalizers. */ -extern gboolean log_finalizers; +extern gboolean mono_log_finalizers; /* If set, do not run finalizers. */ extern gboolean mono_do_not_finalize; diff --git a/mono/metadata/gc-stats.c b/mono/metadata/gc-stats.c index 908efed7d6..5bd61a766d 100644 --- a/mono/metadata/gc-stats.c +++ b/mono/metadata/gc-stats.c @@ -14,7 +14,7 @@ * "undefined symbol" errors. */ #if defined(__APPLE__) -GCStats gc_stats = {}; +GCStats mono_gc_stats = {}; #else -GCStats gc_stats; +GCStats mono_gc_stats; #endif diff --git a/mono/metadata/gc.c b/mono/metadata/gc.c index 06dd41c35c..2d5eb39958 100644 --- a/mono/metadata/gc.c +++ b/mono/metadata/gc.c @@ -61,9 +61,9 @@ static gboolean gc_disabled; static gboolean finalizing_root_domain; -gboolean log_finalizers; +gboolean mono_log_finalizers; gboolean mono_do_not_finalize; -volatile gboolean suspend_finalizers; +static volatile gboolean suspend_finalizers; gchar **mono_do_not_finalize_class_names ; #define mono_finalizer_lock() mono_coop_mutex_lock (&finalizer_mutex) @@ -183,25 +183,28 @@ mono_gc_run_finalize (void *obj, void *data) o = (MonoObject*)((char*)obj + GPOINTER_TO_UINT (data)); + const char *o_ns = m_class_get_name_space (mono_object_class (o)); + const char *o_name = m_class_get_name (mono_object_class (o)); + if (mono_do_not_finalize) { if (!mono_do_not_finalize_class_names) return; - size_t namespace_len = strlen (o->vtable->klass->name_space); + size_t namespace_len = strlen (o_ns); for (int i = 0; mono_do_not_finalize_class_names [i]; ++i) { const char *name = mono_do_not_finalize_class_names [i]; - if (strncmp (name, o->vtable->klass->name_space, namespace_len)) + if (strncmp (name, o_ns, namespace_len)) break; if (name [namespace_len] != '.') break; - if (strcmp (name + namespace_len + 1, o->vtable->klass->name)) + if (strcmp (name + namespace_len + 1, o_name)) break; return; } } - if (log_finalizers) - g_log ("mono-gc-finalizers", G_LOG_LEVEL_DEBUG, "<%s at %p> Starting finalizer checks.", o->vtable->klass->name, o); + if (mono_log_finalizers) + g_log ("mono-gc-finalizers", G_LOG_LEVEL_DEBUG, "<%s at %p> Starting finalizer checks.", o_name, o); if (suspend_finalizers) return; @@ -223,8 +226,8 @@ mono_gc_run_finalize (void *obj, void *data) /* make sure the finalizer is not called again if the object is resurrected */ object_register_finalizer ((MonoObject *)obj, NULL); - if (log_finalizers) - g_log ("mono-gc-finalizers", G_LOG_LEVEL_MESSAGE, "<%s at %p> Registered finalizer as processed.", o->vtable->klass->name, o); + if (mono_log_finalizers) + g_log ("mono-gc-finalizers", G_LOG_LEVEL_MESSAGE, "<%s at %p> Registered finalizer as processed.", o_name, o); if (o->vtable->klass == mono_defaults.internal_thread_class) { MonoInternalThread *t = (MonoInternalThread*)o; @@ -234,7 +237,7 @@ mono_gc_run_finalize (void *obj, void *data) return; } - if (o->vtable->klass->image == mono_defaults.corlib && !strcmp (o->vtable->klass->name, "DynamicMethod") && finalizing_root_domain) { + if (m_class_get_image (mono_object_class (o)) == mono_defaults.corlib && !strcmp (o_name, "DynamicMethod") && finalizing_root_domain) { /* * These can't be finalized during unloading/shutdown, since that would * free the native code which can still be referenced by other @@ -258,7 +261,7 @@ mono_gc_run_finalize (void *obj, void *data) * registered for finalization, but they don't have a Finalize * method, because in most cases it's not needed and it's just a waste. */ - if (o->vtable->klass->delegate) { + if (m_class_is_delegate (mono_object_class (o))) { MonoDelegate* del = (MonoDelegate*)o; if (del->delegate_trampoline) mono_delegate_free_ftnptr ((MonoDelegate*)o); @@ -284,8 +287,8 @@ mono_gc_run_finalize (void *obj, void *data) * create and precompile a wrapper which calls the finalize method using * a CALLVIRT. */ - if (log_finalizers) - g_log ("mono-gc-finalizers", G_LOG_LEVEL_MESSAGE, "<%s at %p> Compiling finalizer.", o->vtable->klass->name, o); + if (mono_log_finalizers) + g_log ("mono-gc-finalizers", G_LOG_LEVEL_MESSAGE, "<%s at %p> Compiling finalizer.", o_name, o); #ifndef HOST_WASM if (!domain->finalize_runtime_invoke) { @@ -303,11 +306,11 @@ mono_gc_run_finalize (void *obj, void *data) if (G_UNLIKELY (MONO_GC_FINALIZE_INVOKE_ENABLED ())) { MONO_GC_FINALIZE_INVOKE ((unsigned long)o, mono_object_get_size (o), - o->vtable->klass->name_space, o->vtable->klass->name); + o_ns, o_name); } - if (log_finalizers) - g_log ("mono-gc-finalizers", G_LOG_LEVEL_MESSAGE, "<%s at %p> Calling finalizer.", o->vtable->klass->name, o); + if (mono_log_finalizers) + g_log ("mono-gc-finalizers", G_LOG_LEVEL_MESSAGE, "<%s at %p> Calling finalizer.", o_name, o); MONO_PROFILER_RAISE (gc_finalizing_object, (o)); @@ -320,8 +323,8 @@ mono_gc_run_finalize (void *obj, void *data) MONO_PROFILER_RAISE (gc_finalized_object, (o)); - if (log_finalizers) - g_log ("mono-gc-finalizers", G_LOG_LEVEL_MESSAGE, "<%s at %p> Returned from finalizer.", o->vtable->klass->name, o); + if (mono_log_finalizers) + g_log ("mono-gc-finalizers", G_LOG_LEVEL_MESSAGE, "<%s at %p> Returned from finalizer.", o_name, o); unhandled_error: if (!is_ok (error)) @@ -386,6 +389,13 @@ object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*)) * Finalize method when the garbage collector disposes the object. * */ +void +mono_object_register_finalizer_handle (MonoObjectHandle obj) +{ + /* g_print ("Registered finalizer on %p %s.%s\n", obj, mono_object_class (obj)->name_space, mono_object_class (obj)->name); */ + object_register_finalizer (MONO_HANDLE_RAW (obj), mono_gc_run_finalize); +} + void mono_object_register_finalizer (MonoObject *obj) { @@ -557,7 +567,7 @@ ves_icall_System_GC_SuppressFinalize (MonoObject *obj) * unmanaged->managed trampoline. We don't let the user suppress it * otherwise we'd leak it. */ - if (obj->vtable->klass->delegate) + if (m_class_is_delegate (mono_object_class (obj))) return; /* FIXME: Need to handle case where obj has COM Callable Wrapper @@ -676,7 +686,7 @@ ves_icall_System_GCHandle_GetAddrOfPinnedObject (guint32 handle) MonoClass *klass = mono_object_class (obj); if (klass == mono_defaults.string_class) { return mono_string_chars ((MonoString*)obj); - } else if (klass->rank) { + } else if (m_class_get_rank (klass)) { return mono_array_addr ((MonoArray*)obj, char, 0); } else { /* the C# code will check and throw the exception */ @@ -886,7 +896,7 @@ finalizer_thread (gpointer unused) */ g_assert (mono_domain_get () == mono_get_root_domain ()); - mono_gc_set_skip_thread (TRUE); + mono_thread_info_set_flags (MONO_THREAD_INFO_FLAGS_NO_GC); if (wait) { /* An alertable wait is required so this thread can be suspended on windows */ @@ -894,7 +904,7 @@ finalizer_thread (gpointer unused) } wait = TRUE; - mono_gc_set_skip_thread (FALSE); + mono_thread_info_set_flags (MONO_THREAD_INFO_FLAGS_NONE); mono_runtime_do_background_work (); @@ -939,11 +949,11 @@ mono_gc_init (void) mono_coop_mutex_init_recursive (&finalizer_mutex); mono_coop_mutex_init_recursive (&reference_queue_mutex); - mono_counters_register ("Minor GC collections", MONO_COUNTER_GC | MONO_COUNTER_INT, &gc_stats.minor_gc_count); - mono_counters_register ("Major GC collections", MONO_COUNTER_GC | MONO_COUNTER_INT, &gc_stats.major_gc_count); - mono_counters_register ("Minor GC time", MONO_COUNTER_GC | MONO_COUNTER_ULONG | MONO_COUNTER_TIME, &gc_stats.minor_gc_time); - mono_counters_register ("Major GC time", MONO_COUNTER_GC | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &gc_stats.major_gc_time); - mono_counters_register ("Major GC time concurrent", MONO_COUNTER_GC | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &gc_stats.major_gc_time_concurrent); + mono_counters_register ("Minor GC collections", MONO_COUNTER_GC | MONO_COUNTER_INT, &mono_gc_stats.minor_gc_count); + mono_counters_register ("Major GC collections", MONO_COUNTER_GC | MONO_COUNTER_INT, &mono_gc_stats.major_gc_count); + mono_counters_register ("Minor GC time", MONO_COUNTER_GC | MONO_COUNTER_ULONG | MONO_COUNTER_TIME, &mono_gc_stats.minor_gc_time); + mono_counters_register ("Major GC time", MONO_COUNTER_GC | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_gc_stats.major_gc_time); + mono_counters_register ("Major GC time concurrent", MONO_COUNTER_GC | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &mono_gc_stats.major_gc_time_concurrent); mono_gc_base_init (); @@ -1257,3 +1267,56 @@ mono_gc_reference_queue_free (MonoReferenceQueue *queue) { queue->should_be_deleted = TRUE; } + +MonoObjectHandle +mono_gc_alloc_handle_pinned_obj (MonoVTable *vtable, gsize size) +{ + return MONO_HANDLE_NEW (MonoObject, mono_gc_alloc_pinned_obj (vtable, size)); +} + +MonoObjectHandle +mono_gc_alloc_handle_obj (MonoVTable *vtable, gsize size) +{ + return MONO_HANDLE_NEW (MonoObject, mono_gc_alloc_obj (vtable, size)); +} + +MonoArrayHandle +mono_gc_alloc_handle_vector (MonoVTable *vtable, gsize size, gsize max_length) +{ + return MONO_HANDLE_NEW (MonoArray, mono_gc_alloc_vector (vtable, size, max_length)); +} + +MonoArrayHandle +mono_gc_alloc_handle_array (MonoVTable *vtable, gsize size, gsize max_length, gsize bounds_size) +{ + return MONO_HANDLE_NEW (MonoArray, mono_gc_alloc_array (vtable, size, max_length, bounds_size)); +} + +MonoStringHandle +mono_gc_alloc_handle_string (MonoVTable *vtable, gsize size, gint32 len) +{ + return MONO_HANDLE_NEW (MonoString, mono_gc_alloc_string (vtable, size, len)); +} + +MonoObjectHandle +mono_gc_alloc_handle_mature (MonoVTable *vtable, gsize size) +{ + return MONO_HANDLE_NEW (MonoObject, mono_gc_alloc_mature (vtable, size)); +} + +void +mono_gc_register_object_with_weak_fields (MonoObjectHandle obj) +{ + mono_gc_register_obj_with_weak_fields (MONO_HANDLE_RAW (obj)); +} + +/** + * mono_gc_wbarrier_object_copy_handle: + * + * Write barrier to call when \p obj is the result of a clone or copy of an object. + */ +void +mono_gc_wbarrier_object_copy_handle (MonoObjectHandle obj, MonoObjectHandle src) +{ + mono_gc_wbarrier_object_copy (MONO_HANDLE_RAW (obj), MONO_HANDLE_RAW (src)); +} diff --git a/mono/metadata/handle.c b/mono/metadata/handle.c index ad47303d02..4bc8b32985 100644 --- a/mono/metadata/handle.c +++ b/mono/metadata/handle.c @@ -538,7 +538,7 @@ mono_object_handle_pin_unbox (MonoObjectHandle obj, uint32_t *gchandle) { g_assert (!MONO_HANDLE_IS_NULL (obj)); MonoClass *klass = mono_handle_class (obj); - g_assert (klass->valuetype); + g_assert (m_class_is_valuetype (klass)); *gchandle = mono_gchandle_from_handle (obj, TRUE); return mono_object_unbox (MONO_HANDLE_RAW (obj)); } diff --git a/mono/metadata/handle.h b/mono/metadata/handle.h index 8328eee0e2..9ccb65cae5 100644 --- a/mono/metadata/handle.h +++ b/mono/metadata/handle.h @@ -22,6 +22,7 @@ #include #include #include +#include G_BEGIN_DECLS @@ -208,18 +209,21 @@ Icall macros CLEAR_ICALL_FRAME; \ } while (0) +// Return a non-pointer or non-managed pointer, e.g. gboolean. #define HANDLE_FUNCTION_RETURN_VAL(VAL) \ CLEAR_ICALL_FRAME; \ return (VAL); \ } while (0) +// Return a raw pointer from coop handle. #define HANDLE_FUNCTION_RETURN_OBJ(HANDLE) \ do { \ - void* __result = (MONO_HANDLE_RAW (HANDLE)); \ + void* __result = MONO_HANDLE_RAW (HANDLE); \ CLEAR_ICALL_FRAME; \ return __result; \ } while (0); } while (0); +// Return a coop handle from coop handle. #define HANDLE_FUNCTION_RETURN_REF(TYPE, HANDLE) \ do { \ MonoRawHandle __result; \ @@ -385,7 +389,7 @@ This is why we evaluate index and value before any call to MONO_HANDLE_RAW or ot /* N.B. RESULT is evaluated before HANDLE */ #define MONO_HANDLE_GET(RESULT, HANDLE, FIELD) do { \ MonoObjectHandle __dest = MONO_HANDLE_CAST(MonoObject, RESULT); \ - MONO_HANDLE_SUPPRESS (mono_gc_wbarrier_generic_store (&__dest->__raw, (MonoObject*)(MONO_HANDLE_RAW(MONO_HANDLE_UNSUPPRESS (HANDLE))->FIELD))); \ + MONO_HANDLE_SUPPRESS (*(gpointer*)&__dest->__raw = (gpointer)MONO_HANDLE_RAW (MONO_HANDLE_UNSUPPRESS (HANDLE))->FIELD); \ } while (0) #define MONO_HANDLE_NEW_GET(TYPE,HANDLE,FIELD) (MONO_HANDLE_NEW(TYPE,MONO_HANDLE_SUPPRESS (MONO_HANDLE_RAW (MONO_HANDLE_UNSUPPRESS (HANDLE))->FIELD))) @@ -399,26 +403,28 @@ This is why we evaluate index and value before any call to MONO_HANDLE_RAW or ot } while (0) #define MONO_HANDLE_ARRAY_SETREF(HANDLE, IDX, VALUE) do { \ - int __idx = (IDX); \ + uintptr_t __idx = (IDX); \ MonoObjectHandle __val = MONO_HANDLE_CAST (MonoObject, VALUE); \ - do { \ + { /* FIXME scope needed by Centrinel */ \ + /* FIXME mono_array_setref_fast is not an expression. */ \ MONO_HANDLE_SUPPRESS_SCOPE(1); \ mono_array_setref_fast (MONO_HANDLE_RAW (MONO_HANDLE_UNSUPPRESS (HANDLE)), __idx, MONO_HANDLE_RAW (__val)); \ - } while (0); \ + } \ } while (0) #define MONO_HANDLE_ARRAY_SETVAL(HANDLE, TYPE, IDX, VALUE) do { \ - int __idx = (IDX); \ + uintptr_t __idx = (IDX); \ TYPE __val = (VALUE); \ - do { \ + { /* FIXME scope needed by Centrinel */ \ + /* FIXME mono_array_set is not an expression. */ \ MONO_HANDLE_SUPPRESS_SCOPE(1); \ mono_array_set (MONO_HANDLE_RAW (MONO_HANDLE_UNSUPPRESS (HANDLE)), TYPE, __idx, __val); \ - } while (0); \ + } \ } while (0) #define MONO_HANDLE_ARRAY_SETRAW(HANDLE, IDX, VALUE) do { \ MONO_HANDLE_SUPPRESS_SCOPE(1); \ - int __idx = MONO_HANDLE_UNSUPPRESS(IDX); \ + uintptr_t __idx = MONO_HANDLE_UNSUPPRESS(IDX); \ MonoObject *__val = (MonoObject*)(VALUE); \ mono_array_setref_fast (MONO_HANDLE_RAW (MONO_HANDLE_UNSUPPRESS (HANDLE)), __idx, __val); \ } while (0) @@ -426,7 +432,7 @@ This is why we evaluate index and value before any call to MONO_HANDLE_RAW or ot /* N.B. DEST is evaluated AFTER all the other arguments */ #define MONO_HANDLE_ARRAY_GETVAL(DEST, HANDLE, TYPE, IDX) do { \ MonoArrayHandle __arr = (HANDLE); \ - int __idx = (IDX); \ + uintptr_t __idx = (IDX); \ TYPE __result = MONO_HANDLE_SUPPRESS (mono_array_get (MONO_HANDLE_RAW(__arr), TYPE, __idx)); \ (DEST) = __result; \ } while (0) @@ -443,7 +449,7 @@ This is why we evaluate index and value before any call to MONO_HANDLE_RAW or ot /* Given an object and a MonoClassField, return the value (must be non-object) * of the field. It's the caller's responsibility to check that the object is * of the correct class. */ -#define MONO_HANDLE_GET_FIELD_VAL(HANDLE,TYPE,FIELD) *(TYPE *)(mono_handle_unsafe_field_addr (MONO_HANDLE_CAST (MonoObject, (HANDLE)), (FIELD))) +#define MONO_HANDLE_GET_FIELD_VAL(HANDLE,TYPE,FIELD) (*(TYPE *)(mono_handle_unsafe_field_addr (MONO_HANDLE_CAST (MonoObject, (HANDLE)), (FIELD)))) #define MONO_HANDLE_NEW_GET_FIELD(HANDLE,TYPE,FIELD) MONO_HANDLE_NEW (TYPE, MONO_HANDLE_SUPPRESS (*(TYPE**)(mono_handle_unsafe_field_addr (MONO_HANDLE_CAST (MonoObject, MONO_HANDLE_UNSUPPRESS (HANDLE)), (FIELD))))) @@ -485,11 +491,11 @@ extern const MonoObjectHandle mono_null_value_handle; static inline void mono_handle_assign (MonoObjectHandleOut dest, MonoObjectHandle src) { - MONO_HANDLE_SUPPRESS (mono_gc_wbarrier_generic_store (&dest->__raw, src ? MONO_HANDLE_RAW(src) : NULL)); + MONO_HANDLE_SUPPRESS (dest->__raw = (gpointer)(src ? MONO_HANDLE_RAW (src) : NULL)); } /* It is unsafe to call this function directly - it does not pin the handle! Use MONO_HANDLE_GET_FIELD_VAL(). */ -static inline gchar* +static inline gpointer mono_handle_unsafe_field_addr (MonoObjectHandle h, MonoClassField *field) { return MONO_HANDLE_SUPPRESS (((gchar *)MONO_HANDLE_RAW (h)) + field->offset); @@ -507,7 +513,7 @@ uintptr_t mono_array_handle_length (MonoArrayHandle arr); static inline void mono_handle_array_getref (MonoObjectHandleOut dest, MonoArrayHandle array, uintptr_t index) { - MONO_HANDLE_SUPPRESS (mono_gc_wbarrier_generic_store (&dest->__raw, mono_array_get (MONO_HANDLE_RAW (array),gpointer, index))); + MONO_HANDLE_SUPPRESS (dest->__raw = (gpointer)mono_array_get(MONO_HANDLE_RAW (array), gpointer, index)); } #define mono_handle_class(o) MONO_HANDLE_SUPPRESS (mono_object_class (MONO_HANDLE_RAW (MONO_HANDLE_UNSUPPRESS (o)))) @@ -538,6 +544,13 @@ mono_string_handle_pin_chars (MonoStringHandle s, uint32_t *gchandle_out); gpointer mono_object_handle_pin_unbox (MonoObjectHandle boxed_valuetype_obj, uint32_t *gchandle_out); +static inline gpointer +mono_handle_unbox_unsafe (MonoObjectHandle handle) +{ + g_assert (m_class_is_valuetype (MONO_HANDLE_GETVAL (handle, vtable)->klass)); + return MONO_HANDLE_SUPPRESS (MONO_HANDLE_RAW (handle) + 1); +} + void mono_error_set_exception_handle (MonoError *error, MonoExceptionHandle exc); diff --git a/mono/metadata/icall-def.h b/mono/metadata/icall-def.h index 58416155ce..be9d1f64e4 100644 --- a/mono/metadata/icall-def.h +++ b/mono/metadata/icall-def.h @@ -64,6 +64,11 @@ * Limitations: "out" and "ref" arguments are not supported yet. */ + #if defined(__APPLE__) +ICALL_TYPE(CLR_INTEROP, "Interop/RunLoop", CLR_INTEROP_1) +ICALL(CLR_INTEROP_1, "CFRunLoopRun", ves_icall_CoreFX_Interop_RunLoop_CFRunLoopRun) +#endif + ICALL_TYPE(NATIVEMETHODS, "Microsoft.Win32.NativeMethods", NATIVEMETHODS_1) ICALL(NATIVEMETHODS_1, "CloseProcess", ves_icall_Microsoft_Win32_NativeMethods_CloseProcess) ICALL(NATIVEMETHODS_2, "GetCurrentProcess", ves_icall_Microsoft_Win32_NativeMethods_GetCurrentProcess) @@ -180,11 +185,11 @@ HANDLES(ICALL(INTCFGHOST_1, "get_bundled_app_config", ves_icall_System_Configura HANDLES(ICALL(INTCFGHOST_2, "get_bundled_machine_config", ves_icall_System_Configuration_InternalConfigurationHost_get_bundled_machine_config)) ICALL_TYPE(CONSOLE, "System.ConsoleDriver", CONSOLE_1) -ICALL(CONSOLE_1, "InternalKeyAvailable", ves_icall_System_ConsoleDriver_InternalKeyAvailable ) -ICALL(CONSOLE_2, "Isatty", ves_icall_System_ConsoleDriver_Isatty ) -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 ) +HANDLES(ICALL(CONSOLE_1, "InternalKeyAvailable", ves_icall_System_ConsoleDriver_InternalKeyAvailable)) +HANDLES(ICALL(CONSOLE_2, "Isatty", ves_icall_System_ConsoleDriver_Isatty)) +HANDLES(ICALL(CONSOLE_3, "SetBreak", ves_icall_System_ConsoleDriver_SetBreak)) +HANDLES(ICALL(CONSOLE_4, "SetEcho", ves_icall_System_ConsoleDriver_SetEcho)) +HANDLES(ICALL(CONSOLE_5, "TtySetup", ves_icall_System_ConsoleDriver_TtySetup)) ICALL_TYPE(DTIME, "System.DateTime", DTIME_1) ICALL(DTIME_1, "GetSystemTimeAsFileTime", mono_100ns_datetime) @@ -252,12 +257,12 @@ ICALL(STOPWATCH_1, "GetTimestamp", mono_100ns_ticks) ICALL_TYPE(ENUM, "System.Enum", ENUM_1) HANDLES(ICALL(ENUM_1, "GetEnumValuesAndNames", ves_icall_System_Enum_GetEnumValuesAndNames)) -ICALL(ENUM_2, "InternalBoxEnum", ves_icall_System_Enum_ToObject) -ICALL(ENUM_3, "InternalCompareTo", ves_icall_System_Enum_compare_value_to) -ICALL(ENUM_4, "InternalGetUnderlyingType", ves_icall_System_Enum_get_underlying_type) -ICALL(ENUM_5, "InternalHasFlag", ves_icall_System_Enum_InternalHasFlag) -ICALL(ENUM_6, "get_hashcode", ves_icall_System_Enum_get_hashcode) -ICALL(ENUM_7, "get_value", ves_icall_System_Enum_get_value) +HANDLES(ICALL(ENUM_2, "InternalBoxEnum", ves_icall_System_Enum_ToObject)) +HANDLES(ICALL(ENUM_3, "InternalCompareTo", ves_icall_System_Enum_compare_value_to)) +HANDLES(ICALL(ENUM_4, "InternalGetUnderlyingType", ves_icall_System_Enum_get_underlying_type)) +HANDLES(ICALL(ENUM_5, "InternalHasFlag", ves_icall_System_Enum_InternalHasFlag)) +HANDLES(ICALL(ENUM_6, "get_hashcode", ves_icall_System_Enum_get_hashcode)) +HANDLES(ICALL(ENUM_7, "get_value", ves_icall_System_Enum_get_value)) ICALL_TYPE(ENV, "System.Environment", ENV_1) ICALL(ENV_1, "Exit", ves_icall_System_Environment_Exit) @@ -348,13 +353,14 @@ ICALL_TYPE(LOGCATEXTWRITER, "System.IO.LogcatTextWriter", LOGCATEXTWRITER_1) HANDLES(ICALL(LOGCATEXTWRITER_1, "Log", ves_icall_System_IO_LogcatTextWriter_Log)) ICALL_TYPE(MMAPIMPL, "System.IO.MemoryMappedFiles.MemoryMapImpl", MMAPIMPL_1) -ICALL(MMAPIMPL_1, "CloseMapping", mono_mmap_close) -ICALL(MMAPIMPL_2, "ConfigureHandleInheritability", mono_mmap_configure_inheritability) -ICALL(MMAPIMPL_3, "Flush", mono_mmap_flush) -ICALL(MMAPIMPL_4, "MapInternal", mono_mmap_map) -ICALL(MMAPIMPL_5, "OpenFileInternal", mono_mmap_open_file) -ICALL(MMAPIMPL_6, "OpenHandleInternal", mono_mmap_open_handle) -ICALL(MMAPIMPL_7, "Unmap", mono_mmap_unmap) +// FIXME rename to ves_icall... +HANDLES(ICALL(MMAPIMPL_1, "CloseMapping", mono_mmap_close)) +HANDLES(ICALL(MMAPIMPL_2, "ConfigureHandleInheritability", mono_mmap_configure_inheritability)) +HANDLES(ICALL(MMAPIMPL_3, "Flush", mono_mmap_flush)) +HANDLES(ICALL(MMAPIMPL_4, "MapInternal", mono_mmap_map)) +HANDLES(ICALL(MMAPIMPL_5, "OpenFileInternal", mono_mmap_open_file)) +HANDLES(ICALL(MMAPIMPL_6, "OpenHandleInternal", mono_mmap_open_handle)) +HANDLES(ICALL(MMAPIMPL_7, "Unmap", mono_mmap_unmap)) ICALL_TYPE(MONOIO, "System.IO.MonoIO", MONOIO_1) ICALL(MONOIO_1, "Close(intptr,System.IO.MonoIOError&)", ves_icall_System_IO_MonoIO_Close) @@ -477,7 +483,7 @@ HANDLES(ICALL(SOCK_18, "SetSocketOption_internal(intptr,System.Net.Sockets.Socke HANDLES(ICALL(SOCK_19, "Shutdown_internal(intptr,System.Net.Sockets.SocketShutdown,int&)", ves_icall_System_Net_Sockets_Socket_Shutdown_internal)) HANDLES(ICALL(SOCK_20, "Socket_internal(System.Net.Sockets.AddressFamily,System.Net.Sockets.SocketType,System.Net.Sockets.ProtocolType,int&)", ves_icall_System_Net_Sockets_Socket_Socket_internal)) HANDLES(ICALL(SOCK_20a, "SupportsPortReuse", ves_icall_System_Net_Sockets_Socket_SupportPortReuse)) -HANDLES(ICALL(SOCK_21a, "cancel_blocking_socket_operation", icall_cancel_blocking_socket_operation)) +HANDLES(ICALL(SOCK_21a, "cancel_blocking_socket_operation", ves_icall_cancel_blocking_socket_operation)) ICALL_TYPE(SOCKEX, "System.Net.Sockets.SocketException", SOCKEX_1) ICALL(SOCKEX_1, "WSAGetLastError_internal", ves_icall_System_Net_Sockets_SocketException_WSAGetLastError_internal) @@ -627,14 +633,14 @@ HANDLES(ICALL(MMETH_10, "get_core_clr_security_level", ves_icall_MonoMethod_get_ HANDLES(ICALL(MMETH_9, "get_name", ves_icall_MonoMethod_get_name)) ICALL_TYPE(MMETHI, "System.Reflection.MonoMethodInfo", MMETHI_4) -ICALL(MMETHI_4, "get_method_attributes", vell_icall_get_method_attributes) +ICALL(MMETHI_4, "get_method_attributes", ves_icall_get_method_attributes) HANDLES(ICALL(MMETHI_1, "get_method_info", ves_icall_get_method_info)) HANDLES(ICALL(MMETHI_2, "get_parameter_info", ves_icall_System_Reflection_MonoMethodInfo_get_parameter_info)) HANDLES(ICALL(MMETHI_3, "get_retval_marshal", ves_icall_System_MonoMethodInfo_get_retval_marshal)) ICALL_TYPE(MPROPI, "System.Reflection.MonoPropertyInfo", MPROPI_1) HANDLES(ICALL(MPROPI_1, "GetTypeModifiers", ves_icall_MonoPropertyInfo_GetTypeModifiers)) -ICALL(MPROPI_3, "get_default_value", property_info_get_default_value) +ICALL(MPROPI_3, "get_default_value", ves_icall_property_info_get_default_value) HANDLES(ICALL(MPROPI_2, "get_property_info", ves_icall_MonoPropertyInfo_get_property_info)) ICALL_TYPE(PARAMI, "System.Reflection.ParameterInfo", PARAMI_1) @@ -792,7 +798,7 @@ HANDLES(ICALL(RT_21, "get_DeclaringMethod", ves_icall_RuntimeType_get_DeclaringM HANDLES(ICALL(RT_22, "get_DeclaringType", ves_icall_RuntimeType_get_DeclaringType)) HANDLES(ICALL(RT_23, "get_Name", ves_icall_RuntimeType_get_Name)) HANDLES(ICALL(RT_24, "get_Namespace", ves_icall_RuntimeType_get_Namespace)) -HANDLES(ICALL(RT_25, "get_core_clr_security_level", vell_icall_RuntimeType_get_core_clr_security_level)) +HANDLES(ICALL(RT_25, "get_core_clr_security_level", ves_icall_RuntimeType_get_core_clr_security_level)) HANDLES(ICALL(RT_26, "make_array_type", ves_icall_RuntimeType_make_array_type)) HANDLES(ICALL(RT_27, "make_byref_type", ves_icall_RuntimeType_make_byref_type)) @@ -899,7 +905,7 @@ ICALL(ILOCK_21, "Increment(long&)", ves_icall_System_Threading_Interlocked_Incre ICALL(ILOCK_22, "Read(long&)", ves_icall_System_Threading_Interlocked_Read_Long) ICALL_TYPE(ITHREAD, "System.Threading.InternalThread", ITHREAD_1) -ICALL(ITHREAD_1, "Thread_free_internal", ves_icall_System_Threading_InternalThread_Thread_free_internal) +HANDLES(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", ves_icall_System_Threading_Monitor_Monitor_Enter) @@ -930,13 +936,13 @@ ICALL(SEMA_3, "ReleaseSemaphore_internal(intptr,int,int&)", ves_icall_System_Thr ICALL_TYPE(THREAD, "System.Threading.Thread", THREAD_1) ICALL(THREAD_1, "Abort_internal(System.Threading.InternalThread,object)", ves_icall_System_Threading_Thread_Abort) -ICALL(THREAD_1a, "ByteArrayToCurrentDomain(byte[])", ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain) -ICALL(THREAD_1b, "ByteArrayToRootDomain(byte[])", ves_icall_System_Threading_Thread_ByteArrayToRootDomain) +HANDLES(ICALL(THREAD_1a, "ByteArrayToCurrentDomain(byte[])", ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain)) +HANDLES(ICALL(THREAD_1b, "ByteArrayToRootDomain(byte[])", ves_icall_System_Threading_Thread_ByteArrayToRootDomain)) HANDLES(ICALL(THREAD_2, "ClrState(System.Threading.InternalThread,System.Threading.ThreadState)", ves_icall_System_Threading_Thread_ClrState)) -ICALL(THREAD_2a, "ConstructInternalThread", ves_icall_System_Threading_Thread_ConstructInternalThread) +HANDLES(ICALL(THREAD_2a, "ConstructInternalThread", ves_icall_System_Threading_Thread_ConstructInternalThread)) ICALL(THREAD_55, "GetAbortExceptionState", ves_icall_System_Threading_Thread_GetAbortExceptionState) HANDLES(ICALL(THREAD_60, "GetCurrentThread", ves_icall_System_Threading_Thread_GetCurrentThread)) -ICALL(THREAD_7, "GetDomainID", ves_icall_System_Threading_Thread_GetDomainID) +HANDLES(ICALL(THREAD_7, "GetDomainID", ves_icall_System_Threading_Thread_GetDomainID)) HANDLES(ICALL(THREAD_8, "GetName_internal(System.Threading.InternalThread)", ves_icall_System_Threading_Thread_GetName_internal)) HANDLES(ICALL(THREAD_57, "GetPriorityNative", ves_icall_System_Threading_Thread_GetPriority)) ICALL(THREAD_59, "GetStackTraces", ves_icall_System_Threading_Thread_GetStackTraces) @@ -950,10 +956,11 @@ ICALL(THREAD_18, "SetName_internal(System.Threading.InternalThread,string)", ves HANDLES(ICALL(THREAD_58, "SetPriorityNative", ves_icall_System_Threading_Thread_SetPriority)) HANDLES(ICALL(THREAD_21, "SetState(System.Threading.InternalThread,System.Threading.ThreadState)", ves_icall_System_Threading_Thread_SetState)) ICALL(THREAD_22, "SleepInternal", ves_icall_System_Threading_Thread_Sleep_internal) -ICALL(THREAD_54, "SpinWait_nop", ves_icall_System_Threading_Thread_SpinWait_nop) -ICALL(THREAD_23, "SuspendInternal", ves_icall_System_Threading_Thread_Suspend) -ICALL(THREAD_56, "SystemMaxStackStize", mono_threads_get_max_stack_size) -ICALL(THREAD_25, "Thread_internal", ves_icall_System_Threading_Thread_Thread_internal) +HANDLES(ICALL(THREAD_54, "SpinWait_nop", ves_icall_System_Threading_Thread_SpinWait_nop)) +HANDLES(ICALL(THREAD_23, "SuspendInternal", ves_icall_System_Threading_Thread_Suspend)) +// FIXME SystemMaxStackStize should be SystemMaxStackSize +HANDLES(ICALL(THREAD_56, "SystemMaxStackStize", ves_icall_System_Threading_Thread_SystemMaxStackSize)) +HANDLES(ICALL(THREAD_25, "Thread_internal", ves_icall_System_Threading_Thread_Thread_internal)) ICALL(THREAD_26, "VolatileRead(byte&)", ves_icall_System_Threading_Thread_VolatileRead1) ICALL(THREAD_27, "VolatileRead(double&)", ves_icall_System_Threading_Thread_VolatileReadDouble) ICALL(THREAD_28, "VolatileRead(int&)", ves_icall_System_Threading_Thread_VolatileRead4) @@ -980,24 +987,24 @@ ICALL(THREAD_48, "VolatileWrite(uint&,uint)", ves_icall_System_Threading_Thread_ ICALL(THREAD_49, "VolatileWrite(uint16&,uint16)", ves_icall_System_Threading_Thread_VolatileWrite2) ICALL(THREAD_50, "VolatileWrite(uintptr&,uintptr)", ves_icall_System_Threading_Thread_VolatileWriteIntPtr) ICALL(THREAD_51, "VolatileWrite(ulong&,ulong)", ves_icall_System_Threading_Thread_VolatileWrite8) -ICALL(THREAD_9, "YieldInternal", ves_icall_System_Threading_Thread_Yield) -ICALL(THREAD_52, "current_lcid()", ves_icall_System_Threading_Thread_current_lcid) +HANDLES(ICALL(THREAD_9, "YieldInternal", ves_icall_System_Threading_Thread_Yield)) +HANDLES(ICALL(THREAD_52, "current_lcid()", ves_icall_System_Threading_Thread_current_lcid)) ICALL_TYPE(THREADP, "System.Threading.ThreadPool", THREADP_1) -ICALL(THREADP_1, "BindIOCompletionCallbackNative", ves_icall_System_Threading_ThreadPool_BindIOCompletionCallbackNative) -ICALL(THREADP_2, "GetAvailableThreadsNative", ves_icall_System_Threading_ThreadPool_GetAvailableThreadsNative) -ICALL(THREADP_3, "GetMaxThreadsNative", ves_icall_System_Threading_ThreadPool_GetMaxThreadsNative) -ICALL(THREADP_4, "GetMinThreadsNative", ves_icall_System_Threading_ThreadPool_GetMinThreadsNative) -ICALL(THREADP_5, "InitializeVMTp", ves_icall_System_Threading_ThreadPool_InitializeVMTp) -ICALL(THREADP_6, "IsThreadPoolHosted", ves_icall_System_Threading_ThreadPool_IsThreadPoolHosted) -ICALL(THREADP_7, "NotifyWorkItemComplete", ves_icall_System_Threading_ThreadPool_NotifyWorkItemComplete) -ICALL(THREADP_8, "NotifyWorkItemProgressNative", ves_icall_System_Threading_ThreadPool_NotifyWorkItemProgressNative) -ICALL(THREADP_8m, "NotifyWorkItemQueued", ves_icall_System_Threading_ThreadPool_NotifyWorkItemQueued) -ICALL(THREADP_9, "PostQueuedCompletionStatus", ves_icall_System_Threading_ThreadPool_PostQueuedCompletionStatus) -ICALL(THREADP_11, "ReportThreadStatus", ves_icall_System_Threading_ThreadPool_ReportThreadStatus) -ICALL(THREADP_12, "RequestWorkerThread", ves_icall_System_Threading_ThreadPool_RequestWorkerThread) -ICALL(THREADP_13, "SetMaxThreadsNative", ves_icall_System_Threading_ThreadPool_SetMaxThreadsNative) -ICALL(THREADP_14, "SetMinThreadsNative", ves_icall_System_Threading_ThreadPool_SetMinThreadsNative) +HANDLES(ICALL(THREADP_1, "BindIOCompletionCallbackNative", ves_icall_System_Threading_ThreadPool_BindIOCompletionCallbackNative)) +HANDLES(ICALL(THREADP_2, "GetAvailableThreadsNative", ves_icall_System_Threading_ThreadPool_GetAvailableThreadsNative)) +HANDLES(ICALL(THREADP_3, "GetMaxThreadsNative", ves_icall_System_Threading_ThreadPool_GetMaxThreadsNative)) +HANDLES(ICALL(THREADP_4, "GetMinThreadsNative", ves_icall_System_Threading_ThreadPool_GetMinThreadsNative)) +HANDLES(ICALL(THREADP_5, "InitializeVMTp", ves_icall_System_Threading_ThreadPool_InitializeVMTp)) +HANDLES(ICALL(THREADP_6, "IsThreadPoolHosted", ves_icall_System_Threading_ThreadPool_IsThreadPoolHosted)) +HANDLES(ICALL(THREADP_7, "NotifyWorkItemComplete", ves_icall_System_Threading_ThreadPool_NotifyWorkItemComplete)) +HANDLES(ICALL(THREADP_8, "NotifyWorkItemProgressNative", ves_icall_System_Threading_ThreadPool_NotifyWorkItemProgressNative)) +HANDLES(ICALL(THREADP_8m, "NotifyWorkItemQueued", ves_icall_System_Threading_ThreadPool_NotifyWorkItemQueued)) +HANDLES(ICALL(THREADP_9, "PostQueuedCompletionStatus", ves_icall_System_Threading_ThreadPool_PostQueuedCompletionStatus)) +HANDLES(ICALL(THREADP_11, "ReportThreadStatus", ves_icall_System_Threading_ThreadPool_ReportThreadStatus)) +HANDLES(ICALL(THREADP_12, "RequestWorkerThread", ves_icall_System_Threading_ThreadPool_RequestWorkerThread)) +HANDLES(ICALL(THREADP_13, "SetMaxThreadsNative", ves_icall_System_Threading_ThreadPool_SetMaxThreadsNative)) +HANDLES(ICALL(THREADP_14, "SetMinThreadsNative", ves_icall_System_Threading_ThreadPool_SetMinThreadsNative)) ICALL_TYPE(TTIMER, "System.Threading.Timer", TTIMER_1) ICALL(TTIMER_1, "GetTimeMonotonic", mono_100ns_ticks) diff --git a/mono/metadata/icall-table.c b/mono/metadata/icall-table.c index 93e26114ae..af632d0d7a 100644 --- a/mono/metadata/icall-table.c +++ b/mono/metadata/icall-table.c @@ -379,6 +379,7 @@ lookup_icall_symbol (gpointer func) } } } + inited = TRUE; } slot = mono_binary_search (func, functions_sorted, G_N_ELEMENTS (icall_functions), sizeof (gpointer), func_cmp); diff --git a/mono/metadata/icall.c.REMOVED.git-id b/mono/metadata/icall.c.REMOVED.git-id index d2940e9cd4..49035d98c9 100644 --- a/mono/metadata/icall.c.REMOVED.git-id +++ b/mono/metadata/icall.c.REMOVED.git-id @@ -1 +1 @@ -f12673d460431ee88ea05490d8e88073f9caa651 \ No newline at end of file +30544e52d5413d159ebfc887c18c8ca57dc512a2 \ No newline at end of file diff --git a/mono/metadata/image.c b/mono/metadata/image.c index 3cd12d868c..0947ec4fef 100644 --- a/mono/metadata/image.c +++ b/mono/metadata/image.c @@ -28,6 +28,7 @@ #include "loader.h" #include "marshal.h" #include "coree.h" +#include #include #include #include @@ -776,7 +777,7 @@ class_key_extract (gpointer value) { MonoClass *klass = (MonoClass *)value; - return GUINT_TO_POINTER (klass->type_token); + return GUINT_TO_POINTER (m_class_get_type_token (klass)); } static gpointer* @@ -784,7 +785,7 @@ class_next_value (gpointer value) { MonoClassDef *klass = (MonoClassDef *)value; - return (gpointer*)&klass->next_class_cache; + return (gpointer*)m_classdef_get_next_class_cache (klass); } /** @@ -1140,7 +1141,7 @@ typedef struct { guint16 major, minor, build, revision; } IgnoredAssemblyVersion; -const char *ignored_assemblies_file_names[] = { +static const char *ignored_assemblies_file_names[] = { "System.Runtime.InteropServices.RuntimeInformation.dll", "System.Globalization.Extensions.dll", "System.IO.Compression.dll", @@ -1210,7 +1211,7 @@ static const IgnoredAssembly ignored_assemblies [] = { }; -const char *ignored_assemblies_names[] = { +static const char *ignored_assemblies_names[] = { "System.Runtime.InteropServices.RuntimeInformation", "System.Globalization.Extensions", "System.IO.Compression", @@ -2117,10 +2118,10 @@ mono_image_close_except_pools (MonoImage *image) free_hash (image->castclass_cache); free_hash (image->icall_wrapper_cache); free_hash (image->proxy_isinst_cache); - free_hash (image->var_cache_slow); - free_hash (image->mvar_cache_slow); - free_hash (image->var_cache_constrained); - free_hash (image->mvar_cache_constrained); + if (image->var_gparam_cache) + mono_conc_hashtable_destroy (image->var_gparam_cache); + if (image->mvar_gparam_cache) + mono_conc_hashtable_destroy (image->mvar_gparam_cache); free_hash (image->wrapper_param_names); free_hash (image->pinvoke_scopes); free_hash (image->pinvoke_scope_filenames); @@ -2817,7 +2818,7 @@ mono_image_strdup_printf (MonoImage *image, const char *format, ...) } GList* -g_list_prepend_image (MonoImage *image, GList *list, gpointer data) +mono_g_list_prepend_image (MonoImage *image, GList *list, gpointer data) { GList *new_list; @@ -2835,7 +2836,7 @@ g_list_prepend_image (MonoImage *image, GList *list, gpointer data) } GSList* -g_slist_append_image (MonoImage *image, GSList *list, gpointer data) +mono_g_slist_append_image (MonoImage *image, GSList *list, gpointer data) { GSList *new_list; @@ -2910,7 +2911,7 @@ mono_image_property_remove (MonoImage *image, gpointer subject) void mono_image_append_class_to_reflection_info_set (MonoClass *klass) { - MonoImage *image = klass->image; + MonoImage *image = m_class_get_image (klass); g_assert (image_is_dynamic (image)); mono_image_lock (image); image->reflection_info_unregister_classes = g_slist_prepend_mempool (image->mempool, image->reflection_info_unregister_classes, klass); diff --git a/mono/metadata/image.h b/mono/metadata/image.h index 72836fddb0..b71217ab6d 100644 --- a/mono/metadata/image.h +++ b/mono/metadata/image.h @@ -8,10 +8,10 @@ #include #include #include +#include MONO_BEGIN_DECLS -typedef struct _MonoImage MonoImage; typedef struct _MonoAssembly MonoAssembly; typedef struct _MonoAssemblyName MonoAssemblyName; typedef struct _MonoTableInfo MonoTableInfo; diff --git a/mono/metadata/jit-info.c b/mono/metadata/jit-info.c index 76d272ad44..2ad7d2c9f4 100644 --- a/mono/metadata/jit-info.c +++ b/mono/metadata/jit-info.c @@ -272,7 +272,7 @@ jit_info_table_find (MonoJitInfoTable *table, MonoThreadHazardPointers *hp, gint * mono_jit_info_get_method () could fail. */ MonoJitInfo* -mono_jit_info_table_find_internal (MonoDomain *domain, char *addr, gboolean try_aot, gboolean allow_trampolines) +mono_jit_info_table_find_internal (MonoDomain *domain, gpointer addr, gboolean try_aot, gboolean allow_trampolines) { MonoJitInfoTable *table; MonoJitInfo *ji, *module_ji; @@ -330,7 +330,7 @@ mono_jit_info_table_find_internal (MonoDomain *domain, char *addr, gboolean try_ * code or a trampoline) or a valid pointer to a \c MonoJitInfo* . */ MonoJitInfo* -mono_jit_info_table_find (MonoDomain *domain, char *addr) +mono_jit_info_table_find (MonoDomain *domain, gpointer addr) { return mono_jit_info_table_find_internal (domain, addr, TRUE, FALSE); } diff --git a/mono/metadata/loader.c b/mono/metadata/loader.c index 811ae8a016..3c9ff06693 100644 --- a/mono/metadata/loader.c +++ b/mono/metadata/loader.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -40,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -71,7 +73,7 @@ static gint32 signatures_size; * This TLS variable holds how many times the current thread has acquired the loader * lock. */ -MonoNativeTlsKey loader_lock_nest_id; +static MonoNativeTlsKey loader_lock_nest_id; static void dllmap_cleanup (void); static void cached_module_cleanup(void); @@ -224,7 +226,7 @@ field_from_memberref (MonoImage *image, guint32 token, MonoClass **retklass, /* we may want to check the signature here... */ if (*ptr++ != 0x6) { - mono_error_set_field_load (error, klass, fname, "Bad field signature class token %08x field name %s token %08x", class_index, fname, token); + mono_error_set_field_missing (error, klass, fname, NULL, "Bad field signature class token %08x field token %08x", class_index, token); return NULL; } @@ -238,7 +240,7 @@ field_from_memberref (MonoImage *image, guint32 token, MonoClass **retklass, ERROR_DECL_VALUE (inner_error); sig_type = mono_metadata_parse_type_checked (image, NULL, 0, FALSE, ptr, &ptr, &inner_error); if (sig_type == NULL) { - mono_error_set_field_load (error, klass, fname, "Could not parse field '%s' signature %08x due to: %s", fname, token, mono_error_get_message (&inner_error)); + mono_error_set_field_missing (error, klass, fname, NULL, "Could not parse field signature %08x due to: %s", token, mono_error_get_message (&inner_error)); mono_error_cleanup (&inner_error); return NULL; } @@ -251,7 +253,7 @@ field_from_memberref (MonoImage *image, guint32 token, MonoClass **retklass, field = mono_class_get_field_from_name_full (klass, fname, sig_type); if (!field) { - mono_error_set_field_load (error, klass, fname, "Could not find field '%s'", fname); + mono_error_set_field_missing (error, klass, fname, sig_type, "Could not find field in class"); } return field; @@ -374,8 +376,9 @@ find_method_in_class (MonoClass *klass, const char *name, const char *qname, con /* Search directly in the metadata to avoid calling setup_methods () */ error_init (error); + MonoImage *klass_image = m_class_get_image (klass); /* FIXME: !mono_class_is_ginst (from_class) condition causes test failures. */ - if (klass->type_token && !image_is_dynamic (klass->image) && !klass->methods && !klass->rank && klass == from_class && !mono_class_is_ginst (from_class)) { + if (m_class_get_type_token (klass) && !image_is_dynamic (klass_image) && !m_class_get_methods (klass) && !m_class_get_rank (klass) && klass == from_class && !mono_class_is_ginst (from_class)) { int first_idx = mono_class_get_first_method_idx (klass); int mcount = mono_class_get_method_count (klass); for (i = 0; i < mcount; ++i) { @@ -384,16 +387,16 @@ find_method_in_class (MonoClass *klass, const char *name, const char *qname, con const char *m_name; MonoMethodSignature *other_sig; - mono_metadata_decode_table_row (klass->image, MONO_TABLE_METHOD, first_idx + i, cols, MONO_METHOD_SIZE); + mono_metadata_decode_table_row (klass_image, MONO_TABLE_METHOD, first_idx + i, cols, MONO_METHOD_SIZE); - m_name = mono_metadata_string_heap (klass->image, cols [MONO_METHOD_NAME]); + m_name = mono_metadata_string_heap (klass_image, cols [MONO_METHOD_NAME]); if (!((fqname && !strcmp (m_name, fqname)) || (qname && !strcmp (m_name, qname)) || (name && !strcmp (m_name, name)))) continue; - method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (first_idx + i + 1), klass, NULL, error); + method = mono_get_method_checked (klass_image, MONO_TOKEN_METHOD_DEF | (first_idx + i + 1), klass, NULL, error); if (!mono_error_ok (error)) //bail out if we hit a loader error return NULL; if (method) { @@ -412,14 +415,15 @@ find_method_in_class (MonoClass *klass, const char *name, const char *qname, con See mono/tests/generic-type-load-exception.2.il FIXME we should better report this error to the caller */ - if (!klass->methods || mono_class_has_failure (klass)) { + if (!m_class_get_methods (klass) || mono_class_has_failure (klass)) { mono_error_set_type_load_class (error, klass, "Could not find method due to a type load error"); //FIXME get the error from the class return NULL; } int mcount = mono_class_get_method_count (klass); + MonoMethod **klass_methods = m_class_get_methods (klass); for (i = 0; i < mcount; ++i) { - MonoMethod *m = klass->methods [i]; + MonoMethod *m = klass_methods [i]; MonoMethodSignature *msig; /* We must cope with failing to load some of the types. */ @@ -431,7 +435,7 @@ find_method_in_class (MonoClass *klass, const char *name, const char *qname, con (name && !strcmp (m->name, name)))) continue; msig = mono_method_signature_checked (m, error); - if (!mono_error_ok (error)) //bail out if we hit a loader error + if (!mono_error_ok (error)) //bail out if we hit a loader error return NULL; if (!msig) @@ -464,11 +468,12 @@ find_method (MonoClass *in_class, MonoClass *ic, const char* name, MonoMethodSig is_interface = MONO_CLASS_IS_INTERFACE (in_class); if (ic) { - class_name = mono_type_get_name_full (&ic->byval_arg, MONO_TYPE_NAME_FORMAT_IL); + class_name = mono_type_get_name_full (m_class_get_byval_arg (ic), MONO_TYPE_NAME_FORMAT_IL); - qname = g_strconcat (class_name, ".", name, NULL); - if (ic->name_space && ic->name_space [0]) - fqname = g_strconcat (ic->name_space, ".", class_name, ".", name, NULL); + qname = g_strconcat (class_name, ".", name, NULL); + const char *ic_name_space = m_class_get_name_space (ic); + if (ic_name_space && ic_name_space [0]) + fqname = g_strconcat (ic_name_space, ".", class_name, ".", name, NULL); else fqname = NULL; } else @@ -487,21 +492,25 @@ find_method (MonoClass *in_class, MonoClass *ic, const char* name, MonoMethodSig * This happens when we fail to lazily load the interfaces of one of the types. * On such case we can't just bail out since user code depends on us trying harder. */ - if (from_class->interface_offsets_count != in_class->interface_offsets_count) { - in_class = in_class->parent; - from_class = from_class->parent; + if (m_class_get_interface_offsets_count (from_class) != m_class_get_interface_offsets_count (in_class)) { + in_class = m_class_get_parent (in_class); + from_class = m_class_get_parent (from_class); continue; } - for (i = 0; i < in_class->interface_offsets_count; i++) { - MonoClass *in_ic = in_class->interfaces_packed [i]; - MonoClass *from_ic = from_class->interfaces_packed [i]; + int in_class_interface_offsets_count = m_class_get_interface_offsets_count (in_class); + MonoClass **in_class_interfaces_packed = m_class_get_interfaces_packed (in_class); + MonoClass **from_class_interfaces_packed = m_class_get_interfaces_packed (from_class); + for (i = 0; i < in_class_interface_offsets_count; i++) { + MonoClass *in_ic = in_class_interfaces_packed [i]; + MonoClass *from_ic = from_class_interfaces_packed [i]; char *ic_qname, *ic_fqname, *ic_class_name; - ic_class_name = mono_type_get_name_full (&in_ic->byval_arg, MONO_TYPE_NAME_FORMAT_IL); + ic_class_name = mono_type_get_name_full (m_class_get_byval_arg (in_ic), MONO_TYPE_NAME_FORMAT_IL); ic_qname = g_strconcat (ic_class_name, ".", name, NULL); - if (in_ic->name_space && in_ic->name_space [0]) - ic_fqname = g_strconcat (in_ic->name_space, ".", ic_class_name, ".", name, NULL); + const char *in_ic_name_space = m_class_get_name_space (in_ic); + if (in_ic_name_space && in_ic_name_space [0]) + ic_fqname = g_strconcat (in_ic_name_space, ".", ic_class_name, ".", name, NULL); else ic_fqname = NULL; @@ -513,8 +522,8 @@ find_method (MonoClass *in_class, MonoClass *ic, const char* name, MonoMethodSig goto out; } - in_class = in_class->parent; - from_class = from_class->parent; + in_class = m_class_get_parent (in_class); + from_class = m_class_get_parent (from_class); } g_assert (!in_class == !from_class); @@ -522,10 +531,8 @@ find_method (MonoClass *in_class, MonoClass *ic, const char* name, MonoMethodSig result = find_method_in_class (mono_defaults.object_class, name, qname, fqname, sig, mono_defaults.object_class, error); //we did not find the method - if (!result && mono_error_ok (error)) { - char *desc = mono_signature_get_managed_fmt_string (sig); - mono_error_set_method_load (error, initial_class, g_strdup (name), desc, ""); - } + if (!result && mono_error_ok (error)) + mono_error_set_method_missing (error, initial_class, name, sig, NULL); out: g_free (class_name); @@ -766,8 +773,9 @@ mono_method_search_in_array_class (MonoClass *klass, const char *name, MonoMetho mono_class_setup_methods (klass); g_assert (!mono_class_has_failure (klass)); /*FIXME this should not fail, right?*/ int mcount = mono_class_get_method_count (klass); + MonoMethod **klass_methods = m_class_get_methods (klass); for (i = 0; i < mcount; ++i) { - MonoMethod *method = klass->methods [i]; + MonoMethod *method = klass_methods [i]; if (strcmp (method->name, name) == 0 && sig->param_count == method->signature->param_count) return method; } @@ -841,7 +849,7 @@ method_from_memberref (MonoImage *image, guint32 idx, MonoGenericContext *typesp sig_idx = cols [MONO_MEMBERREF_SIGNATURE]; if (!mono_verifier_verify_memberref_method_signature (image, sig_idx, NULL)) { - mono_error_set_method_load (error, klass, g_strdup (mname), NULL, "Verifier rejected method signature"); + mono_error_set_method_missing (error, klass, mname, NULL, "Verifier rejected method signature"); goto fail; } @@ -866,7 +874,7 @@ method_from_memberref (MonoImage *image, guint32 idx, MonoGenericContext *typesp case MONO_MEMBERREF_PARENT_TYPESPEC: { MonoType *type; - type = &klass->byval_arg; + type = m_class_get_byval_arg (klass); if (type->type != MONO_TYPE_ARRAY && type->type != MONO_TYPE_SZARRAY) { MonoClass *in_class = mono_class_is_ginst (klass) ? mono_class_get_generic_class (klass)->container_class : klass; @@ -883,12 +891,8 @@ method_from_memberref (MonoImage *image, guint32 idx, MonoGenericContext *typesp goto fail; } - if (!method && mono_error_ok (error)) { - - char *desc = mono_signature_get_managed_fmt_string (sig); - - mono_error_set_method_load (error, klass, g_strdup (mname), desc, "Failed to load due to unknown reasons"); - } + if (!method && mono_error_ok (error)) + mono_error_set_method_missing (error, klass, mname, sig, "Failed to load due to unknown reasons"); return method; @@ -1176,7 +1180,7 @@ is_absolute_path (const char *path) gpointer mono_lookup_pinvoke_call (MonoMethod *method, const char **exc_class, const char **exc_arg) { - MonoImage *image = method->klass->image; + MonoImage *image = m_class_get_image (method->klass); MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)method; MonoTableInfo *tables = image->tables; MonoTableInfo *im = &tables [MONO_TABLE_IMPLMAP]; @@ -1203,10 +1207,10 @@ mono_lookup_pinvoke_call (MonoMethod *method, const char **exc_class, const char if (piinfo->addr) return piinfo->addr; - if (image_is_dynamic (method->klass->image)) { + if (image_is_dynamic (m_class_get_image (method->klass))) { MonoReflectionMethodAux *method_aux = (MonoReflectionMethodAux *)g_hash_table_lookup ( - ((MonoDynamicImage*)method->klass->image)->method_aux_hash, method); + ((MonoDynamicImage*)m_class_get_image (method->klass))->method_aux_hash, method); if (!method_aux) return NULL; @@ -1697,12 +1701,10 @@ mono_get_method_from_token (MonoImage *image, guint32 token, MonoClass *klass, * is generic. */ if (*sig & 0x10) { - generic_container = mono_metadata_load_generic_params (image, token, container); + generic_container = mono_metadata_load_generic_params (image, token, container, result); } if (generic_container) { result->is_generic = TRUE; - generic_container->owner.method = result; - generic_container->is_anonymous = FALSE; // Method is now known, container is no longer anonymous /*FIXME put this before the image alloc*/ if (!mono_metadata_load_generic_param_constraints_checked (image, token, generic_container, error)) return NULL; @@ -1973,7 +1975,7 @@ mono_free_method (MonoMethod *method) mono_marshal_free_dynamic_wrappers (method); - mono_image_property_remove (method->klass->image, method); + mono_image_property_remove (m_class_get_image (method->klass), method); g_free ((char*)method->name); if (mw->header) { @@ -2018,15 +2020,16 @@ mono_method_get_param_names (MonoMethod *method, const char **names) names [i] = ""; klass = method->klass; - if (klass->rank) + if (m_class_get_rank (klass)) return; mono_class_init (klass); - if (image_is_dynamic (klass->image)) { + MonoImage *klass_image = m_class_get_image (klass); + if (image_is_dynamic (klass_image)) { MonoReflectionMethodAux *method_aux = (MonoReflectionMethodAux *)g_hash_table_lookup ( - ((MonoDynamicImage*)method->klass->image)->method_aux_hash, method); + ((MonoDynamicImage*)m_class_get_image (method->klass))->method_aux_hash, method); if (method_aux && method_aux->param_names) { for (i = 0; i < mono_method_signature (method)->param_count; ++i) if (method_aux->param_names [i + 1]) @@ -2038,10 +2041,10 @@ mono_method_get_param_names (MonoMethod *method, const char **names) if (method->wrapper_type) { char **pnames = NULL; - mono_image_lock (klass->image); - if (klass->image->wrapper_param_names) - pnames = (char **)g_hash_table_lookup (klass->image->wrapper_param_names, method); - mono_image_unlock (klass->image); + mono_image_lock (klass_image); + if (klass_image->wrapper_param_names) + pnames = (char **)g_hash_table_lookup (klass_image->wrapper_param_names, method); + mono_image_unlock (klass_image); if (pnames) { for (i = 0; i < signature->param_count; ++i) @@ -2050,8 +2053,8 @@ mono_method_get_param_names (MonoMethod *method, const char **names) return; } - methodt = &klass->image->tables [MONO_TABLE_METHOD]; - paramt = &klass->image->tables [MONO_TABLE_PARAM]; + methodt = &klass_image->tables [MONO_TABLE_METHOD]; + paramt = &klass_image->tables [MONO_TABLE_PARAM]; idx = mono_method_get_index (method); if (idx > 0) { guint32 cols [MONO_PARAM_SIZE]; @@ -2066,7 +2069,7 @@ mono_method_get_param_names (MonoMethod *method, const char **names) for (i = param_index; i < lastp; ++i) { mono_metadata_decode_row (paramt, i -1, cols, MONO_PARAM_SIZE); if (cols [MONO_PARAM_SEQUENCE] && cols [MONO_PARAM_SEQUENCE] <= signature->param_count) /* skip return param spec and bounds check*/ - names [cols [MONO_PARAM_SEQUENCE] - 1] = mono_metadata_string_heap (klass->image, cols [MONO_PARAM_NAME]); + names [cols [MONO_PARAM_SEQUENCE] - 1] = mono_metadata_string_heap (klass_image, cols [MONO_PARAM_NAME]); } } } @@ -2083,10 +2086,10 @@ mono_method_get_param_token (MonoMethod *method, int index) mono_class_init (klass); - if (image_is_dynamic (klass->image)) - g_assert_not_reached (); + MonoImage *klass_image = m_class_get_image (klass); + g_assert (!image_is_dynamic (klass_image)); - methodt = &klass->image->tables [MONO_TABLE_METHOD]; + methodt = &klass_image->tables [MONO_TABLE_METHOD]; idx = mono_method_get_index (method); if (idx > 0) { guint param_index = mono_metadata_decode_row_col (methodt, idx - 1, MONO_METHOD_PARAMLIST); @@ -2120,10 +2123,10 @@ mono_method_get_marshal_info (MonoMethod *method, MonoMarshalSpec **mspecs) for (i = 0; i < signature->param_count + 1; ++i) mspecs [i] = NULL; - if (image_is_dynamic (method->klass->image)) { + if (image_is_dynamic (m_class_get_image (method->klass))) { MonoReflectionMethodAux *method_aux = (MonoReflectionMethodAux *)g_hash_table_lookup ( - ((MonoDynamicImage*)method->klass->image)->method_aux_hash, method); + ((MonoDynamicImage*)m_class_get_image (method->klass))->method_aux_hash, method); if (method_aux && method_aux->param_marshall) { MonoMarshalSpec **dyn_specs = method_aux->param_marshall; for (i = 0; i < signature->param_count + 1; ++i) @@ -2139,8 +2142,9 @@ mono_method_get_marshal_info (MonoMethod *method, MonoMarshalSpec **mspecs) mono_class_init (klass); - methodt = &klass->image->tables [MONO_TABLE_METHOD]; - paramt = &klass->image->tables [MONO_TABLE_PARAM]; + MonoImage *klass_image = m_class_get_image (klass); + methodt = &klass_image->tables [MONO_TABLE_METHOD]; + paramt = &klass_image->tables [MONO_TABLE_PARAM]; idx = mono_method_get_index (method); if (idx > 0) { guint32 cols [MONO_PARAM_SIZE]; @@ -2156,9 +2160,9 @@ mono_method_get_marshal_info (MonoMethod *method, MonoMarshalSpec **mspecs) if (cols [MONO_PARAM_FLAGS] & PARAM_ATTRIBUTE_HAS_FIELD_MARSHAL && cols [MONO_PARAM_SEQUENCE] <= signature->param_count) { const char *tp; - tp = mono_metadata_get_marshal_info (klass->image, i - 1, FALSE); + tp = mono_metadata_get_marshal_info (klass_image, i - 1, FALSE); g_assert (tp); - mspecs [cols [MONO_PARAM_SEQUENCE]]= mono_metadata_parse_marshal_spec (klass->image, tp); + mspecs [cols [MONO_PARAM_SEQUENCE]]= mono_metadata_parse_marshal_spec (klass_image, tp); } } @@ -2178,10 +2182,10 @@ mono_method_has_marshal_info (MonoMethod *method) MonoTableInfo *paramt; guint32 idx; - if (image_is_dynamic (method->klass->image)) { + if (image_is_dynamic (m_class_get_image (method->klass))) { MonoReflectionMethodAux *method_aux = (MonoReflectionMethodAux *)g_hash_table_lookup ( - ((MonoDynamicImage*)method->klass->image)->method_aux_hash, method); + ((MonoDynamicImage*)m_class_get_image (method->klass))->method_aux_hash, method); MonoMarshalSpec **dyn_specs = method_aux->param_marshall; if (dyn_specs) { for (i = 0; i < mono_method_signature (method)->param_count + 1; ++i) @@ -2193,8 +2197,8 @@ mono_method_has_marshal_info (MonoMethod *method) mono_class_init (klass); - methodt = &klass->image->tables [MONO_TABLE_METHOD]; - paramt = &klass->image->tables [MONO_TABLE_PARAM]; + methodt = &m_class_get_image (klass)->tables [MONO_TABLE_METHOD]; + paramt = &m_class_get_image (klass)->tables [MONO_TABLE_PARAM]; idx = mono_method_get_index (method); if (idx > 0) { guint32 cols [MONO_PARAM_SIZE]; @@ -2243,8 +2247,10 @@ stack_walk_adapter (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data) case FRAME_TYPE_DEBUGGER_INVOKE: case FRAME_TYPE_MANAGED_TO_NATIVE: case FRAME_TYPE_TRAMPOLINE: + case FRAME_TYPE_INTERP_TO_MANAGED: return FALSE; case FRAME_TYPE_MANAGED: + case FRAME_TYPE_INTERP: g_assert (frame->ji); return d->func (frame->actual_method, frame->native_offset, frame->il_offset, frame->managed, d->user_data); break; @@ -2436,13 +2442,13 @@ mono_method_signature_checked (MonoMethod *m, MonoError *error) if (m->signature) return m->signature; - img = m->klass->image; + img = m_class_get_image (m->klass); if (m->is_inflated) { MonoMethodInflated *imethod = (MonoMethodInflated *) m; /* the lock is recursive */ signature = mono_method_signature (imethod->declaring); - signature = inflate_generic_signature_checked (imethod->declaring->klass->image, signature, mono_method_get_context (m), error); + signature = inflate_generic_signature_checked (m_class_get_image (imethod->declaring->klass), signature, mono_method_get_context (m), error); if (!mono_error_ok (error)) return NULL; @@ -2509,15 +2515,15 @@ mono_method_signature_checked (MonoMethod *m, MonoError *error) /* Verify metadata consistency */ if (signature->generic_param_count) { if (!container || !container->is_method) { - mono_error_set_method_load (error, m->klass, g_strdup (m->name), mono_signature_get_managed_fmt_string (signature), "Signature claims method has generic parameters, but generic_params table says it doesn't for method 0x%08x from image %s", idx, img->name); + mono_error_set_method_missing (error, m->klass, m->name, signature, "Signature claims method has generic parameters, but generic_params table says it doesn't for method 0x%08x from image %s", idx, img->name); return NULL; } if (container->type_argc != signature->generic_param_count) { - mono_error_set_method_load (error, m->klass, g_strdup (m->name), mono_signature_get_managed_fmt_string (signature), "Inconsistent generic parameter count. Signature says %d, generic_params table says %d for method 0x%08x from image %s", signature->generic_param_count, container->type_argc, idx, img->name); + mono_error_set_method_missing (error, m->klass, m->name, signature, "Inconsistent generic parameter count. Signature says %d, generic_params table says %d for method 0x%08x from image %s", signature->generic_param_count, container->type_argc, idx, img->name); return NULL; } } else if (container && container->is_method && container->type_argc) { - mono_error_set_method_load (error, m->klass, g_strdup (m->name), mono_signature_get_managed_fmt_string (signature), "generic_params table claims method has generic parameters, but signature says it doesn't for method 0x%08x from image %s", idx, img->name); + mono_error_set_method_missing (error, m->klass, m->name, signature, "generic_params table claims method has generic parameters, but signature says it doesn't for method 0x%08x from image %s", idx, img->name); return NULL; } if (m->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) { @@ -2554,7 +2560,7 @@ mono_method_signature_checked (MonoMethod *m, MonoError *error) case PINVOKE_ATTRIBUTE_CALL_CONV_GENERIC: case PINVOKE_ATTRIBUTE_CALL_CONV_GENERICINST: default: { - mono_error_set_method_load (error, m->klass, g_strdup (m->name), mono_signature_get_managed_fmt_string (signature), "unsupported calling convention : 0x%04x for method 0x%08x from image %s", piinfo->piflags, idx, img->name); + mono_error_set_method_missing (error, m->klass, m->name, signature, "Unsupported calling convention : 0x%04x for method 0x%08x from image %s", piinfo->piflags, idx, img->name); } return NULL; } @@ -2641,7 +2647,7 @@ mono_method_get_header_internal (MonoMethod *method, MonoError *error) MonoGenericContainer *container; error_init (error); - img = method->klass->image; + img = m_class_get_image (method->klass); // FIXME: for internal callers maybe it makes sense to do this check at the call site, not // here? @@ -2743,7 +2749,7 @@ mono_method_get_index (MonoMethod *method) MonoClass *klass = method->klass; int i; - if (klass->rank) + if (m_class_get_rank (klass)) /* constructed array methods are not in the MethodDef table */ return 0; @@ -2755,10 +2761,11 @@ mono_method_get_index (MonoMethod *method) return 0; int first_idx = mono_class_get_first_method_idx (klass); int mcount = mono_class_get_method_count (klass); + MonoMethod **klass_methods = m_class_get_methods (klass); for (i = 0; i < mcount; ++i) { - if (method == klass->methods [i]) { - if (klass->image->uncompressed_metadata) - return mono_metadata_translate_token_index (klass->image, MONO_TABLE_METHOD, first_idx + i + 1); + if (method == klass_methods [i]) { + if (m_class_get_image (klass)->uncompressed_metadata) + return mono_metadata_translate_token_index (m_class_get_image (klass), MONO_TABLE_METHOD, first_idx + i + 1); else return first_idx + i + 1; } diff --git a/mono/metadata/locales.c b/mono/metadata/locales.c index e9937a199c..3575098d85 100644 --- a/mono/metadata/locales.c +++ b/mono/metadata/locales.c @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -806,7 +807,8 @@ int ves_icall_System_Globalization_CompareInfo_internal_index_char (MonoCompareI first)); } -int ves_icall_System_Threading_Thread_current_lcid (void) +int +ves_icall_System_Threading_Thread_current_lcid (MonoError *error) { /* Invariant */ return(0x007F); diff --git a/mono/metadata/locales.h b/mono/metadata/locales.h index 0faee51a15..8059491d28 100644 --- a/mono/metadata/locales.h +++ b/mono/metadata/locales.h @@ -46,7 +46,8 @@ ves_icall_System_Globalization_RegionInfo_construct_internal_region_from_name (M extern void ves_icall_System_Globalization_CompareInfo_assign_sortkey (MonoCompareInfo *this_obj, MonoSortKey *key, MonoString *source, gint32 options); extern int ves_icall_System_Globalization_CompareInfo_internal_index (MonoCompareInfo *this_obj, MonoString *source, gint32 sindex, gint32 count, MonoString *value, gint32 options, MonoBoolean first); extern int ves_icall_System_Globalization_CompareInfo_internal_index_char (MonoCompareInfo *this_obj, MonoString *source, gint32 sindex, gint32 count, gunichar2 value, gint32 options, MonoBoolean first); -extern int ves_icall_System_Threading_Thread_current_lcid (void); +int +ves_icall_System_Threading_Thread_current_lcid (MonoError *error); extern MonoString *ves_icall_System_String_InternalToLower_Comp (MonoString *this_obj, MonoCultureInfo *cult); extern MonoString *ves_icall_System_String_InternalToUpper_Comp (MonoString *this_obj, MonoCultureInfo *cult); extern gunichar2 ves_icall_System_Char_InternalToUpper_Comp (gunichar2 c, MonoCultureInfo *cult); diff --git a/mono/metadata/lock-tracer.c b/mono/metadata/lock-tracer.c index bda05487d5..302c29f2c9 100644 --- a/mono/metadata/lock-tracer.c +++ b/mono/metadata/lock-tracer.c @@ -22,6 +22,7 @@ #endif #include +#include #include "lock-tracer.h" diff --git a/mono/metadata/marshal-ilgen.c.REMOVED.git-id b/mono/metadata/marshal-ilgen.c.REMOVED.git-id index a6c9574ced..6c138e3f7f 100644 --- a/mono/metadata/marshal-ilgen.c.REMOVED.git-id +++ b/mono/metadata/marshal-ilgen.c.REMOVED.git-id @@ -1 +1 @@ -c2da6ef0e94ea5a9ea6bdc979530087eda13ec75 \ No newline at end of file +18bf6a78880a7daf012ef4980fccad0a409c471d \ No newline at end of file diff --git a/mono/metadata/marshal.c.REMOVED.git-id b/mono/metadata/marshal.c.REMOVED.git-id index 808c19a196..54b3c228c9 100644 --- a/mono/metadata/marshal.c.REMOVED.git-id +++ b/mono/metadata/marshal.c.REMOVED.git-id @@ -1 +1 @@ -22678e56be344e2fbbf617928164c2acae66abb4 \ No newline at end of file +a5f2c5be6b97caa936f1ae9260c68558f2bac520 \ No newline at end of file diff --git a/mono/metadata/marshal.h b/mono/metadata/marshal.h index 9981ec9f2e..ba6ebfdb81 100644 --- a/mono/metadata/marshal.h +++ b/mono/metadata/marshal.h @@ -248,7 +248,7 @@ typedef struct { } d; } WrapperInfo; -enum { +typedef enum { STELEMREF_OBJECT, /*no check at all*/ STELEMREF_SEALED_CLASS, /*check vtable->klass->element_type */ STELEMREF_CLASS, /*only the klass->parents check*/ @@ -256,14 +256,10 @@ enum { STELEMREF_INTERFACE, /*interfaces without variant generic arguments. */ STELEMREF_COMPLEX, /*arrays, MBR or types with variant generic args - go straight to icalls*/ STELEMREF_KIND_COUNT -}; - -static const char *strelemref_wrapper_name[] = { - "object", "sealed_class", "class", "class_small_idepth", "interface", "complex" -}; +} MonoStelemrefKind; -#define MONO_MARSHAL_CALLBACKS_VERSION 1 +#define MONO_MARSHAL_CALLBACKS_VERSION 2 typedef struct { int version; @@ -285,7 +281,7 @@ typedef struct { void (*emit_struct_to_ptr) (MonoMethodBuilder *mb, MonoClass *klass); void (*emit_ptr_to_struct) (MonoMethodBuilder *mb, MonoClass *klass); void (*emit_isinst) (MonoMethodBuilder *mb); - void (*emit_virtual_stelemref) (MonoMethodBuilder *mb, const char **param_names, int kind); + void (*emit_virtual_stelemref) (MonoMethodBuilder *mb, const char **param_names, MonoStelemrefKind kind); void (*emit_stelemref) (MonoMethodBuilder *mb); void (*emit_array_address) (MonoMethodBuilder *mb, int rank, int elem_size); void (*emit_native_wrapper) (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func, gboolean aot, gboolean check_exceptions, gboolean func_param); @@ -516,7 +512,7 @@ gboolean mono_marshal_free_ccw (MonoObject* obj); void -cominterop_release_all_rcws (void); +mono_cominterop_release_all_rcws (void); MonoString* ves_icall_mono_string_from_utf16 (gunichar2 *data); @@ -622,10 +618,10 @@ MonoMarshalConv mono_marshal_get_ptr_to_string_conv (MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec, gboolean *need_free); MonoType* -marshal_boolean_conv_in_get_local_type (MonoMarshalSpec *spec, guint8 *ldc_op /*out*/); +mono_marshal_boolean_conv_in_get_local_type (MonoMarshalSpec *spec, guint8 *ldc_op /*out*/); MonoClass* -marshal_boolean_managed_conv_in_get_conv_arg_class (MonoMarshalSpec *spec, guint8 *ldop/*out*/); +mono_marshal_boolean_managed_conv_in_get_conv_arg_class (MonoMarshalSpec *spec, guint8 *ldop/*out*/); gboolean mono_pinvoke_is_unicode (MonoMethodPInvoke *piinfo); @@ -848,11 +844,6 @@ mono_mb_create_and_cache_full (GHashTable *cache, gpointer key, MonoMethodBuilder *mb, MonoMethodSignature *sig, int max_stack, WrapperInfo *info, gboolean *out_found); -typedef void (*MonoFtnPtrEHCallback) (guint32 gchandle); - -MONO_API void -mono_install_ftnptr_eh_callback (MonoFtnPtrEHCallback callback); - G_END_DECLS #endif /* __MONO_MARSHAL_H__ */ diff --git a/mono/metadata/metadata-cross-helpers.c b/mono/metadata/metadata-cross-helpers.c index c4c81eaf32..003c888b67 100644 --- a/mono/metadata/metadata-cross-helpers.c +++ b/mono/metadata/metadata-cross-helpers.c @@ -15,6 +15,13 @@ #ifdef HAVE_SGEN_GC #include #endif +#ifdef MONO_CLASS_DEF_PRIVATE +/* Rationale: MonoClass field offsets are computed here. Need to see the definition. + */ +#define REALLY_INCLUDE_CLASS_DEF 1 +#include +#undef REALLY_INCLUDE_CLASS_DEF +#endif static int dump_arch (void) diff --git a/mono/metadata/metadata-internals.h b/mono/metadata/metadata-internals.h index cd657d7441..b75d8bc829 100644 --- a/mono/metadata/metadata-internals.h +++ b/mono/metadata/metadata-internals.h @@ -384,13 +384,13 @@ struct _MonoImage { /* arguments */ MonoWrapperCaches wrapper_caches; - /* Caches for MonoClass-es representing anon generic params */ - MonoClass **var_cache_fast; - MonoClass **mvar_cache_fast; - GHashTable *var_cache_slow; - GHashTable *mvar_cache_slow; - GHashTable *var_cache_constrained; - GHashTable *mvar_cache_constrained; + /* Pre-allocated anon generic params for the first N generic + * parameters, for a small N */ + MonoGenericParam *var_gparam_cache_fast; + MonoGenericParam *mvar_gparam_cache_fast; + /* Anon generic parameters past N, if needed */ + MonoConcurrentHashTable *var_gparam_cache; + MonoConcurrentHashTable *mvar_gparam_cache; /* Maps malloc-ed char* pinvoke scope -> MonoDl* */ GHashTable *pinvoke_scopes; @@ -665,10 +665,10 @@ char* mono_image_strdup_printf (MonoImage *image, const char *format, ...) MONO_ATTR_FORMAT_PRINTF(2,3);; GList* -g_list_prepend_image (MonoImage *image, GList *list, gpointer data); +mono_g_list_prepend_image (MonoImage *image, GList *list, gpointer data); GSList* -g_slist_append_image (MonoImage *image, GSList *list, gpointer data); +mono_g_slist_append_image (MonoImage *image, GSList *list, gpointer data); void mono_image_lock (MonoImage *image); @@ -840,6 +840,9 @@ mono_assembly_fill_assembly_name_full (MonoImage *image, MonoAssemblyName *aname MONO_API guint32 mono_metadata_get_generic_param_row (MonoImage *image, guint32 token, guint32 *owner); +MonoGenericParam* +mono_metadata_create_anon_gparam (MonoImage *image, gint32 param_num, gboolean is_mvar); + void mono_unload_interface_ids (MonoBitSet *bitset); @@ -903,7 +906,7 @@ MonoException *mono_get_exception_field_access_msg (const char *msg); MonoException *mono_get_exception_method_access_msg (const char *msg); -MonoMethod* method_from_method_def_or_ref (MonoImage *m, guint32 tok, MonoGenericContext *context, MonoError *error); +MonoMethod* mono_method_from_method_def_or_ref (MonoImage *m, guint32 tok, MonoGenericContext *context, MonoError *error); MonoMethod *mono_get_method_constrained_with_method (MonoImage *image, MonoMethod *method, MonoClass *constrained_class, MonoGenericContext *context, MonoError *error); MonoMethod *mono_get_method_constrained_checked (MonoImage *image, guint32 token, MonoClass *constrained_class, MonoGenericContext *context, MonoMethod **cil_method, MonoError *error); @@ -936,7 +939,7 @@ MonoType* mono_metadata_parse_type_checked (MonoImage *m, MonoGenericContainer *container, short opt_attrs, gboolean transient, const char *ptr, const char **rptr, MonoError *error); MonoGenericContainer * -get_anonymous_container_for_image (MonoImage *image, gboolean is_mvar); +mono_get_anonymous_container_for_image (MonoImage *image, gboolean is_mvar); char * mono_image_set_description (MonoImageSet *); diff --git a/mono/metadata/metadata-verify.c.REMOVED.git-id b/mono/metadata/metadata-verify.c.REMOVED.git-id index df7685374e..31a87941a7 100644 --- a/mono/metadata/metadata-verify.c.REMOVED.git-id +++ b/mono/metadata/metadata-verify.c.REMOVED.git-id @@ -1 +1 @@ -b67ba57936ed2679c070422c049e1941c157e356 \ No newline at end of file +3760416954e4caa56acaf7af53c6de2d8dca1039 \ No newline at end of file diff --git a/mono/metadata/metadata.c.REMOVED.git-id b/mono/metadata/metadata.c.REMOVED.git-id index 6b2eba77df..5462538e34 100644 --- a/mono/metadata/metadata.c.REMOVED.git-id +++ b/mono/metadata/metadata.c.REMOVED.git-id @@ -1 +1 @@ -1b63db3224cc82da59241df8f6c0aaa4288472e4 \ No newline at end of file +55a9b5d3018e09df08f5d955f6b601d5ea98d9f0 \ No newline at end of file diff --git a/mono/metadata/metadata.h b/mono/metadata/metadata.h index 6f7131303c..b78b54be5c 100644 --- a/mono/metadata/metadata.h +++ b/mono/metadata/metadata.h @@ -10,6 +10,7 @@ #include #include #include +#include MONO_BEGIN_DECLS @@ -18,13 +19,11 @@ MONO_BEGIN_DECLS #define MONO_TYPE_IS_POINTER(t) mono_type_is_pointer (t) #define MONO_TYPE_IS_REFERENCE(t) mono_type_is_reference (t) -#define MONO_CLASS_IS_INTERFACE(c) ((mono_class_get_flags (c) & TYPE_ATTRIBUTE_INTERFACE) || (c->byval_arg.type == MONO_TYPE_VAR) || (c->byval_arg.type == MONO_TYPE_MVAR)) +#define MONO_CLASS_IS_INTERFACE(c) ((mono_class_get_flags (c) & TYPE_ATTRIBUTE_INTERFACE) || mono_type_is_generic_parameter (mono_class_get_type (c))) #define MONO_CLASS_IS_IMPORT(c) ((mono_class_get_flags (c) & TYPE_ATTRIBUTE_IMPORT)) -typedef struct _MonoClass MonoClass; typedef struct _MonoDomain MonoDomain; -typedef struct _MonoMethod MonoMethod; typedef enum { MONO_EXCEPTION_CLAUSE_NONE, diff --git a/mono/metadata/method-builder-ilgen-internals.h b/mono/metadata/method-builder-ilgen-internals.h index 86c4b01f22..5c15a08938 100644 --- a/mono/metadata/method-builder-ilgen-internals.h +++ b/mono/metadata/method-builder-ilgen-internals.h @@ -17,17 +17,17 @@ /* ilgen version */ struct _MonoMethodBuilder { MonoMethod *method; - char *name; + gchar *name; gboolean no_dup_name; GList *locals_list; - int locals; + gint locals; gboolean dynamic; gboolean skip_visibility, init_locals; guint32 code_size, pos; - unsigned char *code; - int num_clauses; + guchar *code; + gint num_clauses; MonoExceptionClause *clauses; - const char **param_names; + const gchar **param_names; }; #endif diff --git a/mono/metadata/method-builder-ilgen.c b/mono/metadata/method-builder-ilgen.c index 457845e3f6..52cb0c5148 100644 --- a/mono/metadata/method-builder-ilgen.c +++ b/mono/metadata/method-builder-ilgen.c @@ -84,7 +84,7 @@ create_method_ilgen (MonoMethodBuilder *mb, MonoMethodSignature *signature, int g_assert (mb != NULL); - image = mb->method->klass->image; + image = m_class_get_image (mb->method->klass); if (mb->dynamic) { method = mb->method; diff --git a/mono/metadata/method-builder-internals.h b/mono/metadata/method-builder-internals.h index 48466e262e..c18c81f153 100644 --- a/mono/metadata/method-builder-internals.h +++ b/mono/metadata/method-builder-internals.h @@ -17,7 +17,7 @@ /* noilgen version */ struct _MonoMethodBuilder { MonoMethod *method; - char *name; + gchar *name; gboolean no_dup_name; }; diff --git a/mono/metadata/method-builder.c b/mono/metadata/method-builder.c index c9e40d6c95..f45bce6298 100644 --- a/mono/metadata/method-builder.c +++ b/mono/metadata/method-builder.c @@ -98,7 +98,7 @@ create_method_noilgen (MonoMethodBuilder *mb, MonoMethodSignature *signature, in g_assert (mb != NULL); - image = mb->method->klass->image; + image = m_class_get_image (mb->method->klass); { /* Realloc the method info into a mempool */ diff --git a/mono/metadata/mono-debug.c b/mono/metadata/mono-debug.c index 4230399ec1..1b0f618b5e 100644 --- a/mono/metadata/mono-debug.c +++ b/mono/metadata/mono-debug.c @@ -27,8 +27,6 @@ #include #include -#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1)) - #if NO_UNALIGNED_ACCESS #define WRITE_UNALIGNED(type, addr, val) \ memcpy(addr, &val, sizeof(type)) @@ -996,7 +994,7 @@ mono_debug_print_stack_frame (MonoMethod *method, guint32 native_offset, MonoDom if (offset < 0) res = g_strdup_printf ("at %s <0x%05x>", fname, native_offset); else { - char *mvid = mono_guid_to_string_minimal ((uint8_t*)method->klass->image->heap_guid.data); + char *mvid = mono_guid_to_string_minimal ((uint8_t*)m_class_get_image (method->klass)->heap_guid.data); char *aotid = mono_runtime_get_aotid (); if (aotid) res = g_strdup_printf ("at %s [0x%05x] in <%s#%s>:0" , fname, offset, mvid, aotid); diff --git a/mono/metadata/mono-hash.c b/mono/metadata/mono-hash.c index a8a2d9b1e1..f58738bf8c 100644 --- a/mono/metadata/mono-hash.c +++ b/mono/metadata/mono-hash.c @@ -227,7 +227,7 @@ rehash (MonoGHashTable *hash) 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->key, hash->msg); - if (!mono_threads_is_coop_enabled ()) { + if (!mono_threads_are_safepoints_enabled ()) { mono_gc_invoke_with_gc_lock (do_rehash, &data); } else { /* We cannot be preempted */ diff --git a/mono/metadata/mono-perfcounters.c b/mono/metadata/mono-perfcounters.c index 7a6df9921f..f283a70c6a 100644 --- a/mono/metadata/mono-perfcounters.c +++ b/mono/metadata/mono-perfcounters.c @@ -688,26 +688,29 @@ get_custom_categories (void) { return list; } -static char* +static SharedCounter* custom_category_counters (SharedCategory* cat) { - char *p = cat->name + strlen (cat->name) + 1; - p += strlen (p) + 1; /* skip category help */ - return p; + char *help = cat->name + strlen (cat->name) + 1; + return (SharedCounter*)(help + strlen (help) + 1); +} + +static SharedCounter* +next_custom_category_counter (SharedCounter* counter) +{ + char *help = counter->name + strlen (counter->name) + 1; + return (SharedCounter*)(help + strlen (help) + 1); } static SharedCounter* find_custom_counter (SharedCategory* cat, MonoString *name) { int i; - char *p = custom_category_counters (cat); + SharedCounter *counter = custom_category_counters (cat); for (i = 0; i < cat->num_counters; ++i) { - SharedCounter *counter = (SharedCounter*)p; if (mono_string_compare_ascii (name, counter->name) == 0) return counter; - p += 2; /* skip counter type */ - p += strlen (p) + 1; /* skip counter name */ - p += strlen (p) + 1; /* skip counter help */ + counter = next_custom_category_counter (counter); } return NULL; } @@ -1650,7 +1653,7 @@ mono_perfcounter_counter_names (MonoString *category) perfctr_lock (); scat = find_custom_category (category); if (scat) { - char *p = custom_category_counters (scat); + SharedCounter *counter = custom_category_counters (scat); int i; res = mono_array_new_checked (domain, mono_get_string_class (), scat->num_counters, error); if (mono_error_set_pending_exception (error)) { @@ -1659,12 +1662,10 @@ mono_perfcounter_counter_names (MonoString *category) } for (i = 0; i < scat->num_counters; ++i) { - MonoString *str = mono_string_new_checked (domain, p + 1, error); + MonoString *str = mono_string_new_checked (domain, counter->name, error); goto_if_nok (error, leave); mono_array_setref (res, i, str); - p += 2; /* skip counter type */ - p += strlen (p) + 1; /* skip counter name */ - p += strlen (p) + 1; /* skip counter help */ + counter = next_custom_category_counter (counter); } } else res = mono_array_new_checked (domain, mono_get_string_class (), 0, error); @@ -1859,8 +1860,6 @@ static gboolean mono_perfcounter_foreach_shared_item (SharedHeader *header, gpointer data) { int i; - char *p, *name; - unsigned char type; void *addr; SharedCategory *cat; SharedCounter *counter; @@ -1869,26 +1868,15 @@ mono_perfcounter_foreach_shared_item (SharedHeader *header, gpointer data) if (header->ftype == FTYPE_CATEGORY) { cat = (SharedCategory*)header; - - p = cat->name; - p += strlen (p) + 1; /* skip category name */ - p += strlen (p) + 1; /* skip category help */ - + counter = custom_category_counters (cat); for (i = 0; i < cat->num_counters; ++i) { - counter = (SharedCounter*) p; - type = (unsigned char)*p++; - /* seq_num = (int)* */ p++; - name = p; - p += strlen (p) + 1; - /* help = p; */ - p += strlen (p) + 1; - - inst = custom_get_instance (cat, counter, name); + inst = custom_get_instance (cat, counter, counter->name); if (!inst) return FALSE; addr = custom_get_value_address (counter, inst); - if (!foreach_data->cb (cat->name, name, type, addr ? *(gint64*)addr : 0, foreach_data->data)) + if (!foreach_data->cb (cat->name, counter->name, counter->type, addr ? *(gint64*)addr : 0, foreach_data->data)) return FALSE; + counter = next_custom_category_counter (counter); } } diff --git a/mono/metadata/mono-security.c b/mono/metadata/mono-security.c index ce62effea9..182a22e82c 100644 --- a/mono/metadata/mono-security.c +++ b/mono/metadata/mono-security.c @@ -610,18 +610,18 @@ void ves_icall_System_Security_SecureString_DecryptInternal (MonoArray *data, MonoObject *scope) { ERROR_DECL (error); - invoke_protected_memory_method (data, scope, FALSE, error); + mono_invoke_protected_memory_method (data, scope, FALSE, error); mono_error_set_pending_exception (error); } void ves_icall_System_Security_SecureString_EncryptInternal (MonoArray* data, MonoObject *scope) { ERROR_DECL (error); - invoke_protected_memory_method (data, scope, TRUE, error); + mono_invoke_protected_memory_method (data, scope, TRUE, error); mono_error_set_pending_exception (error); } -void invoke_protected_memory_method (MonoArray *data, MonoObject *scope, gboolean encrypt, MonoError *error) +void mono_invoke_protected_memory_method (MonoArray *data, MonoObject *scope, gboolean encrypt, MonoError *error) { MonoClass *klass; MonoMethod *method; diff --git a/mono/metadata/null-gc.c b/mono/metadata/null-gc.c index 6e35625cbe..20f3441bdf 100644 --- a/mono/metadata/null-gc.c +++ b/mono/metadata/null-gc.c @@ -520,7 +520,14 @@ mono_gc_pthread_create (pthread_t *new_thread, const pthread_attr_t *attr, void } #endif -void mono_gc_set_skip_thread (gboolean value) +void +mono_gc_skip_thread_changing (gboolean skip) +{ + // No STW, nothing needs to be done. +} + +void +mono_gc_skip_thread_changed (gboolean skip) { } diff --git a/mono/metadata/object-forward.h b/mono/metadata/object-forward.h index be15a1fbe7..2688c87767 100644 --- a/mono/metadata/object-forward.h +++ b/mono/metadata/object-forward.h @@ -8,6 +8,13 @@ #ifndef __MONO_OBJECT_FORWARD_H__ #define __MONO_OBJECT_FORWARD_H__ +#include + typedef struct _MonoReflectionTypeBuilder MonoReflectionTypeBuilder; +typedef struct _MonoException MONO_RT_MANAGED_ATTR MonoException; +typedef struct _MonoClass MonoClass; +typedef struct _MonoImage MonoImage; +typedef struct _MonoMethod MonoMethod; + #endif /* __MONO_OBJECT_FORWARD_H__ */ diff --git a/mono/metadata/object-internals.h b/mono/metadata/object-internals.h index 30ad967764..d37102a7dd 100644 --- a/mono/metadata/object-internals.h +++ b/mono/metadata/object-internals.h @@ -80,7 +80,7 @@ #define mono_array_class_get_cached(eclass,rank) ({ \ static MonoClass *tmp_klass; \ if (!tmp_klass) { \ - tmp_klass = mono_array_class_get ((eclass), (rank)); \ + tmp_klass = mono_class_create_array ((eclass), (rank)); \ g_assert (tmp_klass); \ }; \ tmp_klass; }) @@ -95,7 +95,7 @@ #else #define mono_class_get_field_from_name_cached(klass,name) mono_class_get_field_from_name ((klass), (name)) -#define mono_array_class_get_cached(eclass,rank) mono_array_class_get ((eclass), (rank)) +#define mono_array_class_get_cached(eclass,rank) mono_class_create_array ((eclass), (rank)) #define mono_array_new_cached(domain, eclass, size, error) mono_array_new_checked ((domain), (eclass), (size), (error)) #endif @@ -127,7 +127,7 @@ struct _MonoArray { mono_64bitaligned_t vector [MONO_ZERO_LEN_ARRAY]; }; -#define MONO_SIZEOF_MONO_ARRAY (sizeof (MonoArray) - MONO_ZERO_LEN_ARRAY * sizeof (double)) +#define MONO_SIZEOF_MONO_ARRAY (sizeof (MonoArray) - MONO_ZERO_LEN_ARRAY * sizeof (mono_64bitaligned_t)) struct _MonoString { MonoObject object; @@ -642,6 +642,7 @@ typedef struct { void (*mono_raise_exception_with_ctx) (MonoException *ex, MonoContext *ctx); gboolean (*mono_exception_walk_trace) (MonoException *ex, MonoInternalExceptionFrameWalk func, gpointer user_data); gboolean (*mono_install_handler_block_guard) (MonoThreadUnwindState *unwind_state); + void (*mono_uninstall_current_handler_block_guard) (void); gboolean (*mono_current_thread_has_handle_block_guard) (void); gboolean (*mono_above_abort_threshold) (void); void (*mono_clear_abort_threshold) (void); @@ -650,6 +651,9 @@ typedef struct { MONO_COLD void mono_set_pending_exception (MonoException *exc); +MONO_COLD void +mono_set_pending_exception_handle (MonoExceptionHandle exc); + /* remoting and async support */ MonoAsyncResult * @@ -742,7 +746,7 @@ mono_domain_get_tls_offset (void); * encountering instances of user defined subclasses of System.Type. */ -#define IS_MONOTYPE(obj) (!(obj) || (((MonoObject*)(obj))->vtable->klass->image == mono_defaults.corlib && ((MonoReflectionType*)(obj))->type != NULL)) +#define IS_MONOTYPE(obj) (!(obj) || (m_class_get_image (mono_object_class ((obj))) == mono_defaults.corlib && ((MonoReflectionType*)(obj))->type != NULL)) #define IS_MONOTYPE_HANDLE(obj) IS_MONOTYPE (MONO_HANDLE_RAW (obj)) @@ -1162,7 +1166,6 @@ typedef struct { MonoString *name; MonoObject *def_value; gint32 offset; - gint32 table_idx; MonoReflectionType *typeb; MonoArray *rva_data; MonoArray *cattrs; @@ -1222,6 +1225,7 @@ typedef struct { gboolean is_main; MonoArray *resources; GHashTable *unparented_classes; + MonoArray *table_indexes; } MonoReflectionModuleBuilder; /* Safely acess System.Reflection.Emit.ModuleBuidler from native code */ @@ -1623,8 +1627,14 @@ mono_nullable_init_from_handle (guint8 *buf, MonoObjectHandle value, MonoClass * MonoObject * mono_value_box_checked (MonoDomain *domain, MonoClass *klass, void* val, MonoError *error); +MonoObjectHandle +mono_value_box_handle (MonoDomain *domain, MonoClass *klass, gpointer val, MonoError *error); + MonoObject* -mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error); +mono_nullable_box (gpointer buf, MonoClass *klass, MonoError *error); + +MonoObjectHandle +mono_nullable_box_handle (gpointer buf, MonoClass *klass, MonoError *error); #ifdef MONO_SMALL_CONFIG #define MONO_IMT_SIZE 9 @@ -1705,9 +1715,6 @@ mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error); void mono_method_clear_object (MonoDomain *domain, MonoMethod *method); -void -mono_class_compute_gc_descriptor (MonoClass *klass); - gsize* mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields); @@ -1811,15 +1818,21 @@ mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error); MonoObject * mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error); +MonoObjectHandle +mono_object_new_handle (MonoDomain *domain, MonoClass *klass, MonoError *error); + MonoObject* mono_object_new_mature (MonoVTable *vtable, MonoError *error); -MonoObject* -mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error); +MonoObjectHandle +mono_object_new_handle_mature (MonoVTable *vtable, MonoError *error); MonoObject * mono_object_clone_checked (MonoObject *obj, MonoError *error); +MonoObjectHandle +mono_object_clone_handle (MonoObjectHandle obj, MonoError *error); + MonoObject * mono_object_isinst_checked (MonoObject *obj, MonoClass *klass, MonoError *error); @@ -1838,7 +1851,7 @@ mono_ldstr_checked (MonoDomain *domain, MonoImage *image, uint32_t str_index, Mo MonoString* mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error); -MonoString* +MONO_PROFILER_API MonoString* mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *merror); MonoString* @@ -1859,6 +1872,9 @@ mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error); char* mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error); +char* +mono_utf16_to_utf8 (const mono_unichar2 *s, gsize slength, MonoError *error); + gboolean mono_runtime_object_init_checked (MonoObject *this_obj, MonoError *error); @@ -1960,4 +1976,11 @@ ves_icall_ModuleBuilder_set_wrappers_type (MonoReflectionModuleBuilderHandle mod MonoAssembly* mono_try_assembly_resolve_handle (MonoDomain *domain, MonoStringHandle fname, MonoAssembly *requesting, gboolean refonly, MonoError *error); +gboolean +mono_runtime_object_init_handle (MonoObjectHandle this_obj, MonoError *error); + +/* GC write barriers support */ +void +mono_gc_wbarrier_object_copy_handle (MonoObjectHandle obj, MonoObjectHandle src); + #endif /* __MONO_OBJECT_INTERNALS_H__ */ diff --git a/mono/metadata/object-offsets.h b/mono/metadata/object-offsets.h index 72d0a0ded6..371c277083 100644 --- a/mono/metadata/object-offsets.h +++ b/mono/metadata/object-offsets.h @@ -183,7 +183,6 @@ DECL_OFFSET(MonoContext, wasm_bp) DECL_OFFSET(MonoContext, wasm_sp) DECL_OFFSET(MonoContext, llvm_exc_reg) -DECL_OFFSET(MonoLMF, method) DECL_OFFSET(MonoLMF, lmf_addr) #elif defined(TARGET_X86) diff --git a/mono/metadata/object.c.REMOVED.git-id b/mono/metadata/object.c.REMOVED.git-id index a4ee0409c1..e0b0ee7267 100644 --- a/mono/metadata/object.c.REMOVED.git-id +++ b/mono/metadata/object.c.REMOVED.git-id @@ -1 +1 @@ -df97ddd7a540f619e38bb477346042e39ce3481a \ No newline at end of file +1f9e58e3fa710f5b551ddbed82833a226e508c0a \ No newline at end of file diff --git a/mono/metadata/object.h b/mono/metadata/object.h index 77f4adb88f..53cd548a60 100644 --- a/mono/metadata/object.h +++ b/mono/metadata/object.h @@ -5,6 +5,7 @@ #ifndef _MONO_CLI_OBJECT_H_ #define _MONO_CLI_OBJECT_H_ +#include #include #include @@ -22,7 +23,6 @@ typedef struct _MonoReflectionProperty MONO_RT_MANAGED_ATTR MonoReflectionProper typedef struct _MonoReflectionEvent MONO_RT_MANAGED_ATTR MonoReflectionEvent; typedef struct _MonoReflectionType MONO_RT_MANAGED_ATTR MonoReflectionType; typedef struct _MonoDelegate MONO_RT_MANAGED_ATTR MonoDelegate; -typedef struct _MonoException MONO_RT_MANAGED_ATTR MonoException; typedef struct _MonoThreadsSync MonoThreadsSync; typedef struct _MonoThread MONO_RT_MANAGED_ATTR MonoThread; typedef struct _MonoDynamicAssembly MonoDynamicAssembly; @@ -296,6 +296,7 @@ MONO_API MonoObject* mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params, MonoObject **exc); +MONO_RT_EXTERNAL_ONLY MONO_API void* mono_method_get_unmanaged_thunk (MonoMethod *method); diff --git a/mono/metadata/profiler-private.h b/mono/metadata/profiler-private.h index 3c0fe896c4..6967de483b 100644 --- a/mono/metadata/profiler-private.h +++ b/mono/metadata/profiler-private.h @@ -111,6 +111,7 @@ mono_profiler_installed (void) return !!mono_profiler_state.profilers; } +gboolean mono_profiler_coverage_instrumentation_enabled (MonoMethod *method); MonoProfilerCoverageInfo *mono_profiler_coverage_alloc (MonoMethod *method, guint32 entries); struct _MonoProfilerCallContext { diff --git a/mono/metadata/profiler.c b/mono/metadata/profiler.c index c1850434cc..f8e25322c7 100644 --- a/mono/metadata/profiler.c +++ b/mono/metadata/profiler.c @@ -399,15 +399,9 @@ mono_profiler_get_coverage_data (MonoProfilerHandle handle, MonoMethod *method, return TRUE; } -MonoProfilerCoverageInfo * -mono_profiler_coverage_alloc (MonoMethod *method, guint32 entries) +gboolean +mono_profiler_coverage_instrumentation_enabled (MonoMethod *method) { - if (!mono_profiler_state.code_coverage) - return FALSE; - - if (method->wrapper_type) - return FALSE; - gboolean cover = FALSE; for (MonoProfilerHandle handle = mono_profiler_state.profilers; handle; handle = handle->next) { @@ -417,7 +411,19 @@ mono_profiler_coverage_alloc (MonoMethod *method, guint32 entries) cover |= cb (handle->prof, method); } - if (!cover) + return cover; +} + +MonoProfilerCoverageInfo * +mono_profiler_coverage_alloc (MonoMethod *method, guint32 entries) +{ + if (!mono_profiler_state.code_coverage) + return FALSE; + + if (method->wrapper_type) + return FALSE; + + if (!mono_profiler_coverage_instrumentation_enabled (method)) return NULL; coverage_lock (); @@ -562,7 +568,7 @@ mono_profiler_enable_allocations (void) * filter functions from all installed profilers. If any of them return flags * other than \c MONO_PROFILER_CALL_INSTRUMENTATION_NONE, then the given method * will be instrumented as requested. All filters are guaranteed to be called - * exactly once per method, even if earlier filters have already specified all + * at least once per method, even if earlier filters have already specified all * flags. * * Note that filter functions must be installed before a method is compiled in diff --git a/mono/metadata/reflection-cache.h b/mono/metadata/reflection-cache.h index 9fd05486f2..8d76b16275 100644 --- a/mono/metadata/reflection-cache.h +++ b/mono/metadata/reflection-cache.h @@ -25,10 +25,10 @@ typedef struct { } ReflectedEntry; gboolean -reflected_equal (gconstpointer a, gconstpointer b); +mono_reflected_equal (gconstpointer a, gconstpointer b); guint -reflected_hash (gconstpointer a); +mono_reflected_hash (gconstpointer a); static inline ReflectedEntry* alloc_reflected_entry (MonoDomain *domain) @@ -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, "Domain Reflection Object Table"); + domain->refobject_hash = mono_conc_g_hash_table_new_type (mono_reflected_hash, mono_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, "Domain Reflection Object Table"); + domain->refobject_hash = mono_conc_g_hash_table_new_type (mono_reflected_hash, mono_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 77b6940382..5c2d4febe3 100644 --- a/mono/metadata/reflection.c +++ b/mono/metadata/reflection.c @@ -19,6 +19,7 @@ #include "mono/metadata/metadata-internals.h" #include #include "mono/metadata/class-internals.h" +#include "mono/metadata/class-init.h" #include "mono/metadata/gc-internals.h" #include "mono/metadata/domain-internals.h" #include "mono/metadata/opcodes.h" @@ -156,7 +157,7 @@ mono_custom_attrs_free (MonoCustomAttrInfo *ainfo) } gboolean -reflected_equal (gconstpointer a, gconstpointer b) +mono_reflected_equal (gconstpointer a, gconstpointer b) { const ReflectedEntry *ea = (const ReflectedEntry *)a; const ReflectedEntry *eb = (const ReflectedEntry *)b; @@ -165,7 +166,7 @@ reflected_equal (gconstpointer a, gconstpointer b) } guint -reflected_hash (gconstpointer a) { +mono_reflected_hash (gconstpointer a) { const ReflectedEntry *ea = (const ReflectedEntry *)a; /* Combine hashes for item and refclass. Identical to boost's hash_combine */ guint seed = mono_aligned_addr_hash (ea->item) + 0x9e3779b9; @@ -228,7 +229,7 @@ static MonoReflectionAssemblyHandle assembly_object_construct (MonoDomain *domain, MonoClass *unused_klass, MonoAssembly *assembly, gpointer user_data, MonoError *error) { error_init (error); - MonoReflectionAssemblyHandle res = MONO_HANDLE_NEW (MonoReflectionAssembly, mono_object_new_checked (domain, mono_class_get_mono_assembly_class (), error)); + MonoReflectionAssemblyHandle res = (MonoReflectionAssemblyHandle) mono_object_new_handle (domain, mono_class_get_mono_assembly_class (), error); return_val_if_nok (error, MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE)); MONO_HANDLE_SETVAL (res, assembly, MonoAssembly*, assembly); return res; @@ -267,7 +268,7 @@ module_object_construct (MonoDomain *domain, MonoClass *unused_klass, MonoImage char* basename; error_init (error); - MonoReflectionModuleHandle res = MONO_HANDLE_NEW (MonoReflectionModule, mono_object_new_checked (domain, mono_class_get_mono_module_class (), error)); + MonoReflectionModuleHandle res = (MonoReflectionModuleHandle)mono_object_new_handle (domain, mono_class_get_mono_module_class (), error); goto_if_nok (error, fail); MONO_HANDLE_SETVAL (res, image, MonoImage *, image); @@ -336,7 +337,7 @@ mono_module_file_get_object_handle (MonoDomain *domain, MonoImage *image, int ta error_init (error); - MonoReflectionModuleHandle res = MONO_HANDLE_NEW (MonoReflectionModule, mono_object_new_checked (domain, mono_class_get_mono_module_class (), error)); + MonoReflectionModuleHandle res = (MonoReflectionModuleHandle)mono_object_new_handle (domain, mono_class_get_mono_module_class (), error); goto_if_nok (error, fail); table = &image->tables [MONO_TABLE_FILE]; @@ -406,11 +407,11 @@ mono_type_normalize (MonoType *type) } if (is_denorm_gtd) - return type->byref == gtd->byval_arg.byref ? >d->byval_arg : >d->this_arg; + return type->byref == m_class_get_byval_arg (gtd)->byref ? m_class_get_byval_arg (gtd) : m_class_get_this_arg (gtd); if (requires_rebind) { MonoClass *klass = mono_class_bind_generic_parameters (gtd, ginst->type_argc, argv, gclass->is_dynamic); - return type->byref == klass->byval_arg.byref ? &klass->byval_arg : &klass->this_arg; + return type->byref == m_class_get_byval_arg (klass)->byref ? m_class_get_byval_arg (klass) : m_class_get_this_arg (klass); } return type; @@ -449,7 +450,7 @@ mono_type_get_object_checked (MonoDomain *domain, MonoType *type, MonoError *err * expects that is can be freed. * Using the right type from */ - type = klass->byval_arg.byref == type->byref ? &klass->byval_arg : &klass->this_arg; + type = m_class_get_byval_arg (klass)->byref == type->byref ? m_class_get_byval_arg (klass) : m_class_get_this_arg (klass); /* void is very common */ if (type->type == MONO_TYPE_VOID && domain->typeof_void) @@ -462,7 +463,7 @@ mono_type_get_object_checked (MonoDomain *domain, MonoType *type, MonoError *err * We cannot do this for TypeBuilders as mono_reflection_create_runtime_class expects * that the resulting object is different. */ - if (type == &klass->byval_arg && !image_is_dynamic (klass->image)) { + if (type == m_class_get_byval_arg (klass) && !image_is_dynamic (m_class_get_image (klass))) { MonoVTable *vtable = mono_class_try_get_vtable (domain, klass); if (vtable && vtable->type) return (MonoReflectionType *)vtable->type; @@ -500,7 +501,7 @@ mono_type_get_object_checked (MonoDomain *domain, MonoType *type, MonoError *err return res; } - if ((type->type == MONO_TYPE_GENERICINST) && type->data.generic_class->is_dynamic && !type->data.generic_class->container_class->wastypebuilder) { + if ((type->type == MONO_TYPE_GENERICINST) && type->data.generic_class->is_dynamic && !m_class_was_typebuilder (type->data.generic_class->container_class)) { /* This can happen if a TypeBuilder for a generic class K * had reflection_create_generic_class) called on it, but not * ves_icall_TypeBuilder_create_runtime_class. This can happen @@ -523,7 +524,7 @@ mono_type_get_object_checked (MonoDomain *domain, MonoType *type, MonoError *err return NULL; } - if (mono_class_has_ref_info (klass) && !klass->wastypebuilder && !type->byref) { + if (mono_class_has_ref_info (klass) && !m_class_was_typebuilder (klass) && !type->byref) { mono_domain_unlock (domain); mono_loader_unlock (); return (MonoReflectionType *)mono_class_get_ref_info_raw (klass); /* FIXME use handles */ @@ -594,11 +595,11 @@ method_object_construct (MonoDomain *domain, MonoClass *refclass, MonoMethod *me else { klass = mono_class_get_mono_method_class (); } - MonoReflectionMethodHandle ret = MONO_HANDLE_NEW (MonoReflectionMethod, mono_object_new_checked (domain, klass, error)); + MonoReflectionMethodHandle ret = (MonoReflectionMethodHandle)mono_object_new_handle (domain, klass, error); goto_if_nok (error, fail); MONO_HANDLE_SETVAL (ret, method, MonoMethod*, method); - MonoReflectionTypeHandle rt = mono_type_get_object_handle (domain, &refclass->byval_arg, error); + MonoReflectionTypeHandle rt = mono_type_get_object_handle (domain, m_class_get_byval_arg (refclass), error); goto_if_nok (error, fail); MONO_HANDLE_SET (ret, reftype, rt); @@ -660,14 +661,14 @@ mono_method_clear_object (MonoDomain *domain, MonoMethod *method) klass = method->klass; while (klass) { clear_cached_object (domain, method, klass); - klass = klass->parent; + klass = m_class_get_parent (klass); } /* Added by mono_param_get_objects () */ clear_cached_object (domain, &(method->signature), NULL); klass = method->klass; while (klass) { clear_cached_object (domain, &(method->signature), klass); - klass = klass->parent; + klass = m_class_get_parent (klass); } } @@ -694,7 +695,7 @@ field_object_construct (MonoDomain *domain, MonoClass *klass, MonoClassField *fi { error_init (error); - MonoReflectionFieldHandle res = MONO_HANDLE_NEW (MonoReflectionField, mono_object_new_checked (domain, mono_class_get_mono_field_class (), error)); + MonoReflectionFieldHandle res = (MonoReflectionFieldHandle)mono_object_new_handle (domain, mono_class_get_mono_field_class (), error); goto_if_nok (error, fail); MONO_HANDLE_SETVAL (res, klass, MonoClass *, klass); MONO_HANDLE_SETVAL (res, field, MonoClassField *, field); @@ -774,7 +775,7 @@ property_object_construct (MonoDomain *domain, MonoClass *klass, MonoProperty *p { error_init (error); - MonoReflectionPropertyHandle res = MONO_HANDLE_NEW (MonoReflectionProperty, mono_object_new_checked (domain, mono_class_get_mono_property_class (), error)); + MonoReflectionPropertyHandle res = (MonoReflectionPropertyHandle)mono_object_new_handle (domain, mono_class_get_mono_property_class (), error); goto_if_nok (error, fail); MONO_HANDLE_SETVAL (res, klass, MonoClass *, klass); MONO_HANDLE_SETVAL (res, property, MonoProperty *, property); @@ -839,7 +840,7 @@ event_object_construct (MonoDomain *domain, MonoClass *klass, MonoEvent *event, { error_init (error); - MonoReflectionMonoEventHandle mono_event = MONO_HANDLE_NEW (MonoReflectionMonoEvent, mono_object_new_checked (domain, mono_class_get_mono_event_class (), error)); + MonoReflectionMonoEventHandle mono_event = (MonoReflectionMonoEventHandle)mono_object_new_handle (domain, mono_class_get_mono_event_class (), error); if (!is_ok (error)) return MONO_HANDLE_CAST (MonoReflectionEvent, NULL_HANDLE); MONO_HANDLE_SETVAL (mono_event, klass, MonoClass* , klass); @@ -933,7 +934,7 @@ add_parameter_object_to_array (MonoDomain *domain, MonoMethod *method, MonoObjec { HANDLE_FUNCTION_ENTER (); error_init (error); - MonoReflectionParameterHandle param = MONO_HANDLE_NEW (MonoReflectionParameter, mono_object_new_checked (domain, mono_class_get_mono_parameter_info_class (), error)); + MonoReflectionParameterHandle param = (MonoReflectionParameterHandle)mono_object_new_handle (domain, mono_class_get_mono_parameter_info_class (), error); goto_if_nok (error, leave); MonoReflectionTypeHandle rt = mono_type_get_object_handle (domain, sig_param, error); @@ -966,7 +967,7 @@ add_parameter_object_to_array (MonoDomain *domain, MonoMethod *method, MonoObjec blob_type.data.klass = NULL; if (blob_type_enum == MONO_TYPE_CLASS) blob_type.data.klass = mono_defaults.object_class; - else if ((sig_param->type == MONO_TYPE_VALUETYPE) && sig_param->data.klass->enumtype) { + else if ((sig_param->type == MONO_TYPE_VALUETYPE) && m_class_is_enumtype (sig_param->data.klass)) { /* For enums, types [i] contains the base type */ blob_type.type = MONO_TYPE_VALUETYPE; @@ -1116,7 +1117,7 @@ add_local_var_info_to_array (MonoDomain *domain, MonoMethodHeader *header, int i { HANDLE_FUNCTION_ENTER (); error_init (error); - MonoReflectionLocalVariableInfoHandle info = MONO_HANDLE_NEW (MonoReflectionLocalVariableInfo, mono_object_new_checked (domain, mono_class_get_local_variable_info_class (), error)); + MonoReflectionLocalVariableInfoHandle info = (MonoReflectionLocalVariableInfoHandle)mono_object_new_handle (domain, mono_class_get_local_variable_info_class (), error); goto_if_nok (error, leave); MonoReflectionTypeHandle rt = mono_type_get_object_handle (domain, header->locals [idx], error); @@ -1138,7 +1139,7 @@ add_exception_handling_clause_to_array (MonoDomain *domain, MonoMethodHeader *he { HANDLE_FUNCTION_ENTER (); error_init (error); - MonoReflectionExceptionHandlingClauseHandle info = MONO_HANDLE_NEW (MonoReflectionExceptionHandlingClause, mono_object_new_checked (domain, mono_class_get_exception_handling_clause_class (), error)); + MonoReflectionExceptionHandlingClauseHandle info = (MonoReflectionExceptionHandlingClauseHandle)mono_object_new_handle (domain, mono_class_get_exception_handling_clause_class (), error); goto_if_nok (error, leave); MonoExceptionClause *clause = &header->clauses [idx]; @@ -1150,7 +1151,7 @@ add_exception_handling_clause_to_array (MonoDomain *domain, MonoMethodHeader *he if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) MONO_HANDLE_SETVAL (info, filter_offset, gint32, clause->data.filter_offset); else if (clause->data.catch_class) { - MonoReflectionTypeHandle rt = mono_type_get_object_handle (mono_domain_get (), &clause->data.catch_class->byval_arg, error); + MonoReflectionTypeHandle rt = mono_type_get_object_handle (mono_domain_get (), m_class_get_byval_arg (clause->data.catch_class), error); goto_if_nok (error, leave); MONO_HANDLE_SET (info, catch_type, rt); @@ -1196,14 +1197,14 @@ method_body_object_construct (MonoDomain *domain, MonoClass *unused_class, MonoM goto fail; } + image = m_class_get_image (method->klass); if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || (method->flags & METHOD_ATTRIBUTE_ABSTRACT) || (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || - (method->klass->image->raw_data && method->klass->image->raw_data [1] != 'Z') || + (image->raw_data && image->raw_data [1] != 'Z') || (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) return MONO_HANDLE_CAST (MonoReflectionMethodBody, NULL_HANDLE); - image = method->klass->image; header = mono_method_get_header_checked (method, error); goto_if_nok (error, fail); @@ -1229,7 +1230,7 @@ method_body_object_construct (MonoDomain *domain, MonoClass *unused_class, MonoM } else local_var_sig_token = 0; //FIXME - MonoReflectionMethodBodyHandle ret = MONO_HANDLE_NEW (MonoReflectionMethodBody, mono_object_new_checked (domain, mono_class_get_method_body_class (), error)); + MonoReflectionMethodBodyHandle ret = (MonoReflectionMethodBodyHandle)mono_object_new_handle (domain, mono_class_get_method_body_class (), error); goto_if_nok (error, fail); MONO_HANDLE_SETVAL (ret, init_locals, MonoBoolean, header->init_locals); @@ -1309,7 +1310,7 @@ get_default_param_value_blobs (MonoMethod *method, char **blobs, guint32 *types) gint32 idx; MonoClass *klass = method->klass; - MonoImage *image = klass->image; + MonoImage *image = m_class_get_image (klass); MonoMethodSignature *methodsig = mono_method_signature (method); MonoTableInfo *constt; @@ -1321,11 +1322,11 @@ get_default_param_value_blobs (MonoMethod *method, char **blobs, guint32 *types) mono_class_init (klass); - if (image_is_dynamic (klass->image)) { + if (image_is_dynamic (image)) { MonoReflectionMethodAux *aux; if (method->is_inflated) method = ((MonoMethodInflated*)method)->declaring; - aux = (MonoReflectionMethodAux *)g_hash_table_lookup (((MonoDynamicImage*)method->klass->image)->method_aux_hash, method); + aux = (MonoReflectionMethodAux *)g_hash_table_lookup (((MonoDynamicImage*)m_class_get_image (method->klass))->method_aux_hash, method); if (aux && aux->param_defaults) { memcpy (blobs, &(aux->param_defaults [1]), methodsig->param_count * sizeof (char*)); memcpy (types, &(aux->param_default_types [1]), methodsig->param_count * sizeof (guint32)); @@ -1333,8 +1334,8 @@ get_default_param_value_blobs (MonoMethod *method, char **blobs, guint32 *types) return; } - methodt = &klass->image->tables [MONO_TABLE_METHOD]; - paramt = &klass->image->tables [MONO_TABLE_PARAM]; + methodt = &image->tables [MONO_TABLE_METHOD]; + paramt = &image->tables [MONO_TABLE_PARAM]; constt = &image->tables [MONO_TABLE_CONSTANT]; idx = mono_method_get_index (method) - 1; @@ -1382,11 +1383,11 @@ mono_get_object_from_blob (MonoDomain *domain, MonoType *type, const char *blob, return NULL; klass = mono_class_from_mono_type (type); - if (klass->valuetype) { + if (m_class_is_valuetype (klass)) { object = mono_object_new_checked (domain, klass, error); return_val_if_nok (error, NULL); retval = ((gchar *) object + sizeof (MonoObject)); - if (klass->enumtype) + if (m_class_is_enumtype (klass)) basetype = mono_class_enum_basetype (klass); } else { retval = &object; @@ -1923,20 +1924,22 @@ mono_reflection_get_type_internal (MonoImage *rootimage, MonoImage* image, MonoT } if (nested_nspace) { + const char *klass_name_space = m_class_get_name_space (klass); if (ignorecase) { - if (!(klass->name_space && mono_utf8_strcasecmp (klass->name_space, nested_nspace) == 0)) + if (!(klass_name_space && mono_utf8_strcasecmp (klass_name_space, nested_nspace) == 0)) match = FALSE; } else { - if (!(klass->name_space && strcmp (klass->name_space, nested_nspace) == 0)) + if (!(klass_name_space && strcmp (klass_name_space, nested_nspace) == 0)) match = FALSE; } } if (match) { + const char *klass_name = m_class_get_name (klass); if (ignorecase) { - if (mono_utf8_strcasecmp (klass->name, nested_name) != 0) + if (mono_utf8_strcasecmp (klass_name, nested_name) != 0) match = FALSE; } else { - if (strcmp (klass->name, nested_name) != 0) + if (strcmp (klass_name, nested_name) != 0) match = FALSE; } } @@ -1970,7 +1973,7 @@ mono_reflection_get_type_internal (MonoImage *rootimage, MonoImage* image, MonoT } } - the_type = mono_type_get_object_handle (mono_domain_get (), &klass->byval_arg, error); + the_type = mono_type_get_object_handle (mono_domain_get (), m_class_get_byval_arg (klass), error); if (!is_ok (error) || MONO_HANDLE_IS_NULL (the_type)) goto leave; @@ -1987,18 +1990,18 @@ mono_reflection_get_type_internal (MonoImage *rootimage, MonoImage* image, MonoT for (mod = info->modifiers; mod; mod = mod->next) { modval = GPOINTER_TO_UINT (mod->data); if (!modval) { /* byref: must be last modifier */ - type = &klass->this_arg; + type = m_class_get_this_arg (klass); goto leave; } else if (modval == -1) { - klass = mono_ptr_class_get (&klass->byval_arg); + klass = mono_class_create_ptr (m_class_get_byval_arg (klass)); } else if (modval == -2) { bounded = TRUE; } else { /* array rank */ - klass = mono_bounded_array_class_get (klass, modval, bounded); + klass = mono_class_create_bounded_array (klass, modval, bounded); } } - type = &klass->byval_arg; + type = m_class_get_byval_arg (klass); leave: HANDLE_FUNCTION_RETURN_VAL (type); @@ -2275,22 +2278,21 @@ mono_reflection_get_token_checked (MonoObjectHandle obj, MonoError *error) MonoClass *klass = mono_handle_class (obj); - if (strcmp (klass->name, "MethodBuilder") == 0) { + const char *klass_name = m_class_get_name (klass); + if (strcmp (klass_name, "MethodBuilder") == 0) { MonoReflectionMethodBuilderHandle mb = MONO_HANDLE_CAST (MonoReflectionMethodBuilder, obj); token = MONO_HANDLE_GETVAL (mb, table_idx) | MONO_TOKEN_METHOD_DEF; - } else if (strcmp (klass->name, "ConstructorBuilder") == 0) { + } else if (strcmp (klass_name, "ConstructorBuilder") == 0) { MonoReflectionCtorBuilderHandle mb = MONO_HANDLE_CAST (MonoReflectionCtorBuilder, obj); token = MONO_HANDLE_GETVAL (mb, table_idx) | MONO_TOKEN_METHOD_DEF; - } else if (strcmp (klass->name, "FieldBuilder") == 0) { - MonoReflectionFieldBuilderHandle fb = MONO_HANDLE_CAST (MonoReflectionFieldBuilder, obj); - - token = MONO_HANDLE_GETVAL (fb, table_idx) | MONO_TOKEN_FIELD_DEF; - } else if (strcmp (klass->name, "TypeBuilder") == 0) { + } else if (strcmp (klass_name, "FieldBuilder") == 0) { + g_assert_not_reached (); + } else if (strcmp (klass_name, "TypeBuilder") == 0) { MonoReflectionTypeBuilderHandle tb = MONO_HANDLE_CAST (MonoReflectionTypeBuilder, obj); token = MONO_HANDLE_GETVAL (tb, table_idx) | MONO_TOKEN_TYPE_DEF; - } else if (strcmp (klass->name, "RuntimeType") == 0) { + } else if (strcmp (klass_name, "RuntimeType") == 0) { MonoType *type = mono_reflection_type_handle_mono_type (MONO_HANDLE_CAST (MonoReflectionType, obj), error); return_val_if_nok (error, 0); MonoClass *mc = mono_class_from_mono_type (type); @@ -2299,9 +2301,9 @@ mono_reflection_get_token_checked (MonoObjectHandle obj, MonoError *error) return 0; } - token = mc->type_token; - } else if (strcmp (klass->name, "MonoCMethod") == 0 || - strcmp (klass->name, "MonoMethod") == 0) { + token = m_class_get_type_token (mc); + } else if (strcmp (klass_name, "MonoCMethod") == 0 || + strcmp (klass_name, "MonoMethod") == 0) { MonoReflectionMethodHandle m = MONO_HANDLE_CAST (MonoReflectionMethod, obj); MonoMethod *method = MONO_HANDLE_GETVAL (m, method); if (method->is_inflated) { @@ -2310,19 +2312,19 @@ mono_reflection_get_token_checked (MonoObjectHandle obj, MonoError *error) } else { token = method->token; } - } else if (strcmp (klass->name, "MonoField") == 0) { + } else if (strcmp (klass_name, "MonoField") == 0) { MonoReflectionFieldHandle f = MONO_HANDLE_CAST (MonoReflectionField, obj); token = mono_class_get_field_token (MONO_HANDLE_GETVAL (f, field)); - } else if (strcmp (klass->name, "MonoProperty") == 0) { + } else if (strcmp (klass_name, "MonoProperty") == 0) { MonoReflectionPropertyHandle p = MONO_HANDLE_CAST (MonoReflectionProperty, obj); token = mono_class_get_property_token (MONO_HANDLE_GETVAL (p, property)); - } else if (strcmp (klass->name, "MonoEvent") == 0) { + } else if (strcmp (klass_name, "MonoEvent") == 0) { MonoReflectionMonoEventHandle p = MONO_HANDLE_CAST (MonoReflectionMonoEvent, obj); token = mono_class_get_event_token (MONO_HANDLE_GETVAL (p, event)); - } else if (strcmp (klass->name, "ParameterInfo") == 0 || strcmp (klass->name, "MonoParameterInfo") == 0) { + } else if (strcmp (klass_name, "ParameterInfo") == 0 || strcmp (klass_name, "MonoParameterInfo") == 0) { MonoReflectionParameterHandle p = MONO_HANDLE_CAST (MonoReflectionParameter, obj); MonoObjectHandle member_impl = MONO_HANDLE_NEW (MonoObject, NULL); MONO_HANDLE_GET (member_impl, p, MemberImpl); @@ -2331,15 +2333,15 @@ 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 || strcmp (klass->name, "ModuleBuilder") == 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); - } else if (strcmp (klass->name, "Assembly") == 0 || strcmp (klass->name, "MonoAssembly") == 0) { + } else if (strcmp (klass_name, "Assembly") == 0 || strcmp (klass_name, "MonoAssembly") == 0) { token = mono_metadata_make_token (MONO_TABLE_ASSEMBLY, 1); } else { mono_error_set_not_implemented (error, "MetadataToken is not supported for type '%s.%s'", - klass->name_space, klass->name); + m_class_get_name_space (klass), klass_name); return 0; } @@ -2351,7 +2353,7 @@ gboolean mono_reflection_is_usertype (MonoReflectionTypeHandle ref) { MonoClass *klass = mono_handle_class (ref); - return klass->image != mono_defaults.corlib || strcmp ("TypeDelegator", klass->name) == 0; + return m_class_get_image (klass) != mono_defaults.corlib || strcmp ("TypeDelegator", m_class_get_name (klass)) == 0; } /** @@ -2407,14 +2409,14 @@ mono_reflection_bind_generic_parameters (MonoReflectionTypeHandle reftype, int t } - if (klass->wastypebuilder) + if (m_class_was_typebuilder (klass)) is_dynamic = TRUE; mono_loader_unlock (); geninst = mono_class_bind_generic_parameters (klass, type_argc, types, is_dynamic); - return &geninst->byval_arg; + return m_class_get_byval_arg (geninst); } MonoClass* @@ -2428,7 +2430,7 @@ mono_class_bind_generic_parameters (MonoClass *klass, int type_argc, MonoType ** inst = mono_metadata_get_generic_inst (type_argc, types); gclass = mono_metadata_lookup_generic_class (klass, inst, is_dynamic); - return mono_generic_class_get_class (gclass); + return mono_class_create_generic_inst (gclass); } static MonoGenericInst* @@ -2493,15 +2495,15 @@ MonoReflectionMethodHandle ves_icall_MonoMethod_MakeGenericMethod_impl (MonoReflectionMethodHandle rmethod, MonoArrayHandle types, MonoError *error) { error_init (error); - g_assert (0 != strcmp (mono_handle_class (rmethod)->name, "MethodBuilder")); + g_assert (0 != strcmp (m_class_get_name (mono_handle_class (rmethod)), "MethodBuilder")); MonoMethod *method = MONO_HANDLE_GETVAL (rmethod, method); MonoMethod *imethod = reflection_bind_generic_method_parameters (method, types, error); return_val_if_nok (error, MONO_HANDLE_CAST (MonoReflectionMethod, NULL_HANDLE)); /*FIXME but I think this is no longer necessary*/ - if (image_is_dynamic (method->klass->image)) { - MonoDynamicImage *image = (MonoDynamicImage*)method->klass->image; + if (image_is_dynamic (m_class_get_image (method->klass))) { + MonoDynamicImage *image = (MonoDynamicImage*)m_class_get_image (method->klass); /* * This table maps metadata structures representing inflated methods/fields * to the reflection objects representing their generic definitions. @@ -2590,7 +2592,7 @@ mono_declsec_flags_from_method (MonoMethod *method) guint32 idx = mono_method_get_index (method); idx <<= MONO_HAS_DECL_SECURITY_BITS; idx |= MONO_HAS_DECL_SECURITY_METHODDEF; - return mono_declsec_get_flags (method->klass->image, idx); + return mono_declsec_get_flags (m_class_get_image (method->klass), idx); } return 0; } @@ -2612,10 +2614,10 @@ mono_declsec_flags_from_class (MonoClass *klass) if (!flags) { guint32 idx; - idx = mono_metadata_token_index (klass->type_token); + idx = mono_metadata_token_index (m_class_get_type_token (klass)); idx <<= MONO_HAS_DECL_SECURITY_BITS; idx |= MONO_HAS_DECL_SECURITY_TYPEDEF; - flags = mono_declsec_get_flags (klass->image, idx); + flags = mono_declsec_get_flags (m_class_get_image (klass), idx); /* we cache the flags on classes */ mono_class_set_declsec_flags (klass, flags); } @@ -2698,10 +2700,10 @@ static MonoBoolean mono_declsec_get_class_demands_params (MonoClass *klass, MonoDeclSecurityActions* demands, guint32 id_std, guint32 id_noncas, guint32 id_choice) { - guint32 idx = mono_metadata_token_index (klass->type_token); + guint32 idx = mono_metadata_token_index (m_class_get_type_token (klass)); idx <<= MONO_HAS_DECL_SECURITY_BITS; idx |= MONO_HAS_DECL_SECURITY_TYPEDEF; - return fill_actions_from_index (klass->image, idx, demands, id_std, id_noncas, id_choice); + return fill_actions_from_index (m_class_get_image (klass), idx, demands, id_std, id_noncas, id_choice); } static MonoBoolean @@ -2711,7 +2713,7 @@ mono_declsec_get_method_demands_params (MonoMethod *method, MonoDeclSecurityActi guint32 idx = mono_method_get_index (method); idx <<= MONO_HAS_DECL_SECURITY_BITS; idx |= MONO_HAS_DECL_SECURITY_METHODDEF; - return fill_actions_from_index (method->klass->image, idx, demands, id_std, id_noncas, id_choice); + return fill_actions_from_index (m_class_get_image (method->klass), idx, demands, id_std, id_noncas, id_choice); } /** @@ -2729,7 +2731,7 @@ mono_declsec_get_demands (MonoMethod *method, MonoDeclSecurityActions* demands) guint32 flags; /* quick exit if no declarative security is present in the metadata */ - if (!method->klass->image->tables [MONO_TABLE_DECLSECURITY].rows) + if (!m_class_get_image (method->klass)->tables [MONO_TABLE_DECLSECURITY].rows) return FALSE; /* we want the original as the wrapper is "free" of the security informations */ @@ -2777,7 +2779,7 @@ mono_declsec_get_linkdemands (MonoMethod *method, MonoDeclSecurityActions* klass guint32 flags; /* quick exit if no declarative security is present in the metadata */ - if (!method->klass->image->tables [MONO_TABLE_DECLSECURITY].rows) + if (!m_class_get_image (method->klass)->tables [MONO_TABLE_DECLSECURITY].rows) return FALSE; /* we want the original as the wrapper is "free" of the security informations */ @@ -2826,7 +2828,7 @@ mono_declsec_get_inheritdemands_class (MonoClass *klass, MonoDeclSecurityActions guint32 flags; /* quick exit if no declarative security is present in the metadata */ - if (!klass->image->tables [MONO_TABLE_DECLSECURITY].rows) + if (!m_class_get_image (klass)->tables [MONO_TABLE_DECLSECURITY].rows) return FALSE; /* Here we use (or create) the class declarative cache to look for demands */ @@ -2851,7 +2853,7 @@ MonoBoolean mono_declsec_get_inheritdemands_method (MonoMethod *method, MonoDeclSecurityActions* demands) { /* quick exit if no declarative security is present in the metadata */ - if (!method->klass->image->tables [MONO_TABLE_DECLSECURITY].rows) + if (!m_class_get_image (method->klass)->tables [MONO_TABLE_DECLSECURITY].rows) return FALSE; /* we want the original as the wrapper is "free" of the security informations */ @@ -2909,7 +2911,7 @@ mono_declsec_get_method_action (MonoMethod *method, guint32 action, MonoDeclSecu guint32 idx = mono_method_get_index (method); idx <<= MONO_HAS_DECL_SECURITY_BITS; idx |= MONO_HAS_DECL_SECURITY_METHODDEF; - return get_declsec_action (method->klass->image, idx, action, entry); + return get_declsec_action (m_class_get_image (method->klass), idx, action, entry); } return FALSE; } @@ -2923,10 +2925,10 @@ mono_declsec_get_class_action (MonoClass *klass, guint32 action, MonoDeclSecurit /* use cache */ guint32 flags = mono_declsec_flags_from_class (klass); if (declsec_flags_map [action] & flags) { - guint32 idx = mono_metadata_token_index (klass->type_token); + guint32 idx = mono_metadata_token_index (m_class_get_type_token (klass)); idx <<= MONO_HAS_DECL_SECURITY_BITS; idx |= MONO_HAS_DECL_SECURITY_TYPEDEF; - return get_declsec_action (klass->image, idx, action, entry); + return get_declsec_action (m_class_get_image (klass), idx, action, entry); } return FALSE; } @@ -2963,9 +2965,9 @@ mono_reflection_call_is_assignable_to (MonoClass *klass, MonoClass *oklass, Mono * need a TypeBuilder so use mono_class_get_ref_info (klass). */ g_assert (mono_class_has_ref_info (klass)); - g_assert (!strcmp (mono_object_class (mono_class_get_ref_info_raw (klass))->name, "TypeBuilder")); /* FIXME use handles */ + g_assert (!strcmp (m_class_get_name (mono_object_class (mono_class_get_ref_info_raw (klass))), "TypeBuilder")); /* FIXME use handles */ - params [0] = mono_type_get_object_checked (mono_domain_get (), &oklass->byval_arg, error); + params [0] = mono_type_get_object_checked (mono_domain_get (), m_class_get_byval_arg (oklass), error); return_val_if_nok (error, FALSE); ERROR_DECL_VALUE (inner_error); diff --git a/mono/metadata/remoting.c b/mono/metadata/remoting.c index 65bca8cc8d..33d0b85efd 100644 --- a/mono/metadata/remoting.c +++ b/mono/metadata/remoting.c @@ -17,6 +17,7 @@ #include "mono/metadata/marshal.h" #include "mono/metadata/marshal-internals.h" #include "mono/metadata/abi-details.h" +#include "mono/metadata/class-init.h" #include "mono/metadata/cominterop.h" #include "mono/metadata/tabledefs.h" #include "mono/metadata/exception.h" @@ -174,7 +175,7 @@ mono_remoting_marshal_init (void) if (module_initialized) return; - byte_array_class = mono_array_class_get (mono_defaults.byte_class, 1); + byte_array_class = mono_class_create_array (mono_defaults.byte_class, 1); #ifndef DISABLE_JIT klass = mono_class_get_remoting_services_class (); @@ -284,7 +285,7 @@ mono_mb_emit_contextbound_check (MonoMethodBuilder *mb, int branch_code) static guint8 mask; if (offset < 0) - mono_marshal_find_bitfield_offset (MonoClass, contextbound, &offset, &mask); + mono_class_contextbound_bit_offset (&offset, &mask); mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class)); mono_mb_emit_byte (mb, CEE_LDIND_REF); @@ -397,7 +398,7 @@ mono_remoting_wrapper (MonoMethod *method, gpointer *params) for (i=0; iparams [i]); - if (klass->valuetype) { + if (m_class_is_valuetype (klass)) { if (sig->params [i]->byref) { mparams[i] = *((gpointer *)params [i]); } else { @@ -413,7 +414,7 @@ mono_remoting_wrapper (MonoMethod *method, gpointer *params) } } - res = mono_runtime_invoke_checked (method, method->klass->valuetype? mono_object_unbox ((MonoObject*)this_obj): this_obj, mparams, error); + res = mono_runtime_invoke_checked (method, m_class_is_valuetype (method->klass)? mono_object_unbox ((MonoObject*)this_obj): this_obj, mparams, error); goto_if_nok (error, fail); return res; @@ -455,8 +456,8 @@ mono_remoting_update_exception (MonoException *exc) /* Serialization error can only happen when still in the target appdomain */ if (!(mono_class_get_flags (klass) & TYPE_ATTRIBUTE_SERIALIZABLE)) { MonoException *ret; - char *aname = mono_stringify_assembly_name (&klass->image->assembly->aname); - char *message = g_strdup_printf ("Type '%s' in Assembly '%s' is not marked as serializable", klass->name, aname); + char *aname = mono_stringify_assembly_name (&m_class_get_image (klass)->assembly->aname); + char *message = g_strdup_printf ("Type '%s' in Assembly '%s' is not marked as serializable", m_class_get_name (klass), aname); ret = mono_get_exception_serialization (message); g_free (aname); g_free (message); @@ -561,10 +562,10 @@ mono_marshal_xdomain_copy_out_value (MonoObject *src, MonoObject *dst) g_assert (mono_object_class (src) == mono_object_class (dst)); - switch (mono_object_class (src)->byval_arg.type) { + switch (m_class_get_byval_arg (mono_object_class (src))->type) { case MONO_TYPE_ARRAY: case MONO_TYPE_SZARRAY: { - int mt = mono_get_xdomain_marshal_type (&(mono_object_class (src)->element_class->byval_arg)); + int mt = mono_get_xdomain_marshal_type (m_class_get_byval_arg (m_class_get_element_class (mono_object_class (src)))); if (mt == MONO_MARSHAL_SERIALIZE) return; if (mt == MONO_MARSHAL_COPY) { int i, len = mono_array_length ((MonoArray *)dst); @@ -713,9 +714,9 @@ mono_marshal_get_xappdomain_dispatch (MonoMethod *method, int *marshal_types, in j = 0; csig = mono_metadata_signature_alloc (mono_defaults.corlib, 3 + sig->param_count - complex_count); - csig->params [j++] = &mono_defaults.object_class->byval_arg; - csig->params [j++] = &byte_array_class->this_arg; - csig->params [j++] = &byte_array_class->this_arg; + csig->params [j++] = m_class_get_byval_arg (mono_defaults.object_class); + csig->params [j++] = m_class_get_this_arg (byte_array_class); + csig->params [j++] = m_class_get_this_arg (byte_array_class); for (i = 0; i < sig->param_count; i++) { if (marshal_types [i] != MONO_MARSHAL_SERIALIZE) csig->params [j++] = sig->params [i]; @@ -723,7 +724,7 @@ mono_marshal_get_xappdomain_dispatch (MonoMethod *method, int *marshal_types, in if (copy_return) csig->ret = sig->ret; else - csig->ret = &mono_defaults.void_class->byval_arg; + csig->ret = m_class_get_byval_arg (mono_defaults.void_class); csig->pinvoke = 1; csig->hasthis = FALSE; @@ -733,9 +734,9 @@ mono_marshal_get_xappdomain_dispatch (MonoMethod *method, int *marshal_types, in #ifndef DISABLE_JIT /* Locals */ - loc_serialized_exc = mono_mb_add_local (mb, &byte_array_class->byval_arg); + loc_serialized_exc = mono_mb_add_local (mb, m_class_get_byval_arg (byte_array_class)); if (complex_count > 0) - loc_array = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg); + loc_array = mono_mb_add_local (mb, m_class_get_byval_arg (mono_defaults.object_class)); if (sig->ret->type != MONO_TYPE_VOID) { loc_return = mono_mb_add_local (mb, sig->ret); ret_class = mono_class_from_mono_type (sig->ret); @@ -743,7 +744,7 @@ mono_marshal_get_xappdomain_dispatch (MonoMethod *method, int *marshal_types, in /* try */ - main_clause = (MonoExceptionClause *)mono_image_alloc0 (method->klass->image, sizeof (MonoExceptionClause)); + main_clause = (MonoExceptionClause *)mono_image_alloc0 (m_class_get_image (method->klass), sizeof (MonoExceptionClause)); main_clause->try_offset = mono_mb_get_label (mb); /* Clean the call context */ @@ -788,14 +789,14 @@ mono_marshal_get_xappdomain_dispatch (MonoMethod *method, int *marshal_types, in mono_mb_emit_ldloc (mb, loc_array); mono_mb_emit_icon (mb, j++); if (pt->byref) { - if (pclass->valuetype) { + if (m_class_is_valuetype (pclass)) { mono_mb_emit_byte (mb, CEE_LDELEM_REF); mono_mb_emit_op (mb, CEE_UNBOX, pclass); } else { mono_mb_emit_op (mb, CEE_LDELEMA, pclass); } } else { - if (pclass->valuetype) { + if (m_class_is_valuetype (pclass)) { mono_mb_emit_byte (mb, CEE_LDELEM_REF); mono_mb_emit_op (mb, CEE_UNBOX, pclass); mono_mb_emit_op (mb, CEE_LDOBJ, pclass); @@ -810,7 +811,7 @@ mono_marshal_get_xappdomain_dispatch (MonoMethod *method, int *marshal_types, in } case MONO_MARSHAL_COPY_OUT: { /* Keep a local copy of the value since we need to copy it back after the call */ - int copy_local = mono_mb_add_local (mb, &(pclass->byval_arg)); + int copy_local = mono_mb_add_local (mb, m_class_get_byval_arg (pclass)); mono_mb_emit_ldarg (mb, param_index++); mono_marshal_emit_xdomain_copy_value (mb, pclass); mono_mb_emit_byte (mb, CEE_DUP); @@ -884,7 +885,7 @@ mono_marshal_get_xappdomain_dispatch (MonoMethod *method, int *marshal_types, in mono_mb_emit_ldloc (mb, loc_return); g_assert (ret_class); /*FIXME properly fail here*/ - if (ret_class->valuetype) { + if (m_class_is_valuetype (ret_class)) { mono_mb_emit_op (mb, CEE_BOX, ret_class); } mono_mb_emit_byte (mb, CEE_STELEM_REF); @@ -899,7 +900,7 @@ mono_marshal_get_xappdomain_dispatch (MonoMethod *method, int *marshal_types, in } else if (ret_marshal_type == MONO_MARSHAL_SERIALIZE) { mono_mb_emit_ldarg (mb, 1); mono_mb_emit_ldloc (mb, loc_return); - if (ret_class->valuetype) { + if (m_class_is_valuetype (ret_class)) { mono_mb_emit_op (mb, CEE_BOX, ret_class); } mono_mb_emit_managed_call (mb, method_rs_serialize, NULL); @@ -1026,16 +1027,19 @@ mono_marshal_get_xappdomain_invoke (MonoMethod *method, MonoError *error) /* Locals */ #ifndef DISABLE_JIT + MonoType *object_type = m_class_get_byval_arg (mono_defaults.object_class); + MonoType *byte_array_type = m_class_get_byval_arg (byte_array_class); + MonoType *int32_type = m_class_get_byval_arg (mono_defaults.int32_class); if (complex_count > 0) - loc_array = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg); - loc_serialized_data = mono_mb_add_local (mb, &byte_array_class->byval_arg); - loc_real_proxy = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg); + loc_array = mono_mb_add_local (mb, object_type); + loc_serialized_data = mono_mb_add_local (mb, byte_array_type); + loc_real_proxy = mono_mb_add_local (mb, object_type); if (copy_return) loc_return = mono_mb_add_local (mb, sig->ret); - loc_old_domainid = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg); - loc_domainid = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg); - loc_serialized_exc = mono_mb_add_local (mb, &byte_array_class->byval_arg); - loc_context = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg); + loc_old_domainid = mono_mb_add_local (mb, int32_type); + loc_domainid = mono_mb_add_local (mb, int32_type); + loc_serialized_exc = mono_mb_add_local (mb, byte_array_type); + loc_context = mono_mb_add_local (mb, object_type); /* Save thread domain data */ @@ -1068,7 +1072,7 @@ mono_marshal_get_xappdomain_invoke (MonoMethod *method, MonoError *error) /* Check if the target domain has the same image for the required assembly */ mono_mb_emit_ldloc (mb, loc_domainid); - mono_mb_emit_ptr (mb, method->klass->image); + mono_mb_emit_ptr (mb, m_class_get_image (method->klass)); mono_mb_emit_icall (mb, mono_marshal_check_domain_image); pos_dispatch = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S); @@ -1104,12 +1108,12 @@ mono_marshal_get_xappdomain_invoke (MonoMethod *method, MonoError *error) mono_mb_emit_icon (mb, j); mono_mb_emit_ldarg (mb, i + 1); /* 0=this */ if (sig->params[i]->byref) { - if (pclass->valuetype) + if (m_class_is_valuetype (pclass)) mono_mb_emit_op (mb, CEE_LDOBJ, pclass); else mono_mb_emit_byte (mb, CEE_LDIND_REF); } - if (pclass->valuetype) + if (m_class_is_valuetype (pclass)) mono_mb_emit_op (mb, CEE_BOX, pclass); mono_mb_emit_byte (mb, CEE_STELEM_REF); j++; @@ -1152,7 +1156,7 @@ mono_marshal_get_xappdomain_invoke (MonoMethod *method, MonoError *error) * will be updated after the xdomain call */ MonoClass *pclass = mono_class_from_mono_type (sig->params [i]); - int copy_local = mono_mb_add_local (mb, &(pclass->byval_arg)); + int copy_local = mono_mb_add_local (mb, m_class_get_byval_arg (pclass)); mono_mb_emit_byte (mb, CEE_LDIND_REF); mono_mb_emit_stloc (mb, copy_local); mono_mb_emit_ldloc_addr (mb, copy_local); @@ -1230,7 +1234,7 @@ mono_marshal_get_xappdomain_invoke (MonoMethod *method, MonoError *error) mono_mb_emit_ldloc (mb, loc_array); mono_mb_emit_icon (mb, j); mono_mb_emit_byte (mb, CEE_LDELEM_REF); - if (pclass->valuetype) { + if (m_class_is_valuetype (pclass)) { mono_mb_emit_op (mb, CEE_UNBOX, pclass); mono_mb_emit_op (mb, CEE_LDOBJ, pclass); mono_mb_emit_op (mb, CEE_STOBJ, pclass); @@ -1247,7 +1251,7 @@ mono_marshal_get_xappdomain_invoke (MonoMethod *method, MonoError *error) mono_mb_emit_ldloc (mb, loc_array); mono_mb_emit_icon (mb, complex_count); mono_mb_emit_byte (mb, CEE_LDELEM_REF); - if (ret_class->valuetype) { + if (m_class_is_valuetype (ret_class)) { mono_mb_emit_op (mb, CEE_UNBOX, ret_class); mono_mb_emit_op (mb, CEE_LDOBJ, ret_class); } @@ -1256,7 +1260,7 @@ mono_marshal_get_xappdomain_invoke (MonoMethod *method, MonoError *error) mono_mb_emit_ldloc (mb, loc_serialized_data); mono_marshal_emit_xdomain_copy_value (mb, byte_array_class); mono_mb_emit_managed_call (mb, method_rs_deserialize, NULL); - if (ret_class->valuetype) { + if (m_class_is_valuetype (ret_class)) { mono_mb_emit_op (mb, CEE_UNBOX, ret_class); mono_mb_emit_op (mb, CEE_LDOBJ, ret_class); } else if (ret_class != mono_defaults.object_class) { @@ -1447,7 +1451,7 @@ mono_marshal_get_ldfld_wrapper (MonoType *type) klass = mono_defaults.int_class; } - cache = get_cache (&klass->image->ldfld_wrapper_cache, mono_aligned_addr_hash, NULL); + cache = get_cache (&m_class_get_image (klass)->ldfld_wrapper_cache, mono_aligned_addr_hash, NULL); if ((res = mono_marshal_find_in_cache (cache, klass))) return res; @@ -1459,16 +1463,18 @@ mono_marshal_get_ldfld_wrapper (MonoType *type) #endif /* we add the %p pointer value of klass because class names are not unique */ - name = g_strdup_printf ("__ldfld_wrapper_%p_%s.%s", klass, klass->name_space, klass->name); + name = g_strdup_printf ("__ldfld_wrapper_%p_%s.%s", klass, m_class_get_name_space (klass), m_class_get_name (klass)); mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_LDFLD); g_free (name); + MonoType *object_type = m_class_get_byval_arg (mono_defaults.object_class); + MonoType *int_type = m_class_get_byval_arg (mono_defaults.int_class); sig = mono_metadata_signature_alloc (mono_defaults.corlib, 4); - sig->params [0] = &mono_defaults.object_class->byval_arg; - sig->params [1] = &mono_defaults.int_class->byval_arg; - sig->params [2] = &mono_defaults.int_class->byval_arg; - sig->params [3] = &mono_defaults.int_class->byval_arg; - sig->ret = &klass->byval_arg; + sig->params [0] = object_type; + sig->params [1] = int_type; + sig->params [2] = int_type; + sig->params [3] = int_type; + sig->ret = m_class_get_byval_arg (klass); #ifndef DISABLE_JIT mono_mb_emit_ldarg (mb, 0); @@ -1493,7 +1499,7 @@ mono_marshal_get_ldfld_wrapper (MonoType *type) mono_marshal_emit_thread_interrupt_checkpoint (mb); */ - if (klass->valuetype) { + if (m_class_is_valuetype (klass)) { mono_mb_emit_op (mb, CEE_UNBOX, klass); pos1 = mono_mb_emit_branch (mb, CEE_BR); } else { @@ -1509,7 +1515,7 @@ mono_marshal_get_ldfld_wrapper (MonoType *type) mono_mb_emit_ldarg (mb, 3); mono_mb_emit_byte (mb, CEE_ADD); - if (klass->valuetype) + if (m_class_is_valuetype (klass)) mono_mb_patch_branch (mb, pos1); switch (t) { @@ -1537,7 +1543,7 @@ mono_marshal_get_ldfld_wrapper (MonoType *type) mono_mb_emit_byte (mb, mono_type_to_ldind (type)); break; case MONO_TYPE_VALUETYPE: - g_assert (!klass->enumtype); + g_assert (!m_class_is_enumtype (klass)); mono_mb_emit_op (mb, CEE_LDOBJ, klass); break; case MONO_TYPE_GENERICINST: @@ -1612,23 +1618,25 @@ mono_marshal_get_ldflda_wrapper (MonoType *type) klass = mono_defaults.int_class; } - cache = get_cache (&klass->image->ldflda_wrapper_cache, mono_aligned_addr_hash, NULL); + cache = get_cache (&m_class_get_image (klass)->ldflda_wrapper_cache, mono_aligned_addr_hash, NULL); if ((res = mono_marshal_find_in_cache (cache, klass))) return res; mono_remoting_marshal_init (); /* we add the %p pointer value of klass because class names are not unique */ - name = g_strdup_printf ("__ldflda_wrapper_%p_%s.%s", klass, klass->name_space, klass->name); + name = g_strdup_printf ("__ldflda_wrapper_%p_%s.%s", klass, m_class_get_name_space (klass), m_class_get_name (klass)); mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_LDFLDA); g_free (name); + MonoType *object_type = m_class_get_byval_arg (mono_defaults.object_class); + MonoType *int_type = m_class_get_byval_arg (mono_defaults.int_class); sig = mono_metadata_signature_alloc (mono_defaults.corlib, 4); - sig->params [0] = &mono_defaults.object_class->byval_arg; - sig->params [1] = &mono_defaults.int_class->byval_arg; - sig->params [2] = &mono_defaults.int_class->byval_arg; - sig->params [3] = &mono_defaults.int_class->byval_arg; - sig->ret = &mono_defaults.int_class->byval_arg; + sig->params [0] = object_type; + sig->params [1] = int_type; + sig->params [2] = int_type; + sig->params [3] = int_type; + sig->ret = int_type; #ifndef DISABLE_JIT /* if typeof (this) != transparent_proxy goto pos0 */ @@ -1743,7 +1751,7 @@ mono_marshal_get_stfld_wrapper (MonoType *type) klass = mono_defaults.int_class; } - cache = get_cache (&klass->image->stfld_wrapper_cache, mono_aligned_addr_hash, NULL); + cache = get_cache (&m_class_get_image (klass)->stfld_wrapper_cache, mono_aligned_addr_hash, NULL); if ((res = mono_marshal_find_in_cache (cache, klass))) return res; @@ -1755,17 +1763,21 @@ mono_marshal_get_stfld_wrapper (MonoType *type) #endif /* we add the %p pointer value of klass because class names are not unique */ - name = g_strdup_printf ("__stfld_wrapper_%p_%s.%s", klass, klass->name_space, klass->name); + name = g_strdup_printf ("__stfld_wrapper_%p_%s.%s", klass, m_class_get_name_space (klass), m_class_get_name (klass)); mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_STFLD); g_free (name); + + MonoType *object_type = m_class_get_byval_arg (mono_defaults.object_class); + MonoType *int_type = m_class_get_byval_arg (mono_defaults.int_class); + MonoType *void_type = m_class_get_byval_arg (mono_defaults.void_class); sig = mono_metadata_signature_alloc (mono_defaults.corlib, 5); - sig->params [0] = &mono_defaults.object_class->byval_arg; - sig->params [1] = &mono_defaults.int_class->byval_arg; - sig->params [2] = &mono_defaults.int_class->byval_arg; - sig->params [3] = &mono_defaults.int_class->byval_arg; - sig->params [4] = &klass->byval_arg; - sig->ret = &mono_defaults.void_class->byval_arg; + sig->params [0] = object_type; + sig->params [1] = int_type; + sig->params [2] = int_type; + sig->params [3] = int_type; + sig->params [4] = m_class_get_byval_arg (klass); + sig->ret = void_type; #ifndef DISABLE_JIT mono_mb_emit_ldarg (mb, 0); @@ -1776,7 +1788,7 @@ mono_marshal_get_stfld_wrapper (MonoType *type) mono_mb_emit_ldarg (mb, 1); mono_mb_emit_ldarg (mb, 2); mono_mb_emit_ldarg (mb, 4); - if (klass->valuetype) + if (m_class_is_valuetype (klass)) mono_mb_emit_op (mb, CEE_BOX, klass); mono_mb_emit_managed_call (mb, tp_store, NULL); @@ -1818,7 +1830,7 @@ mono_marshal_get_stfld_wrapper (MonoType *type) mono_mb_emit_byte (mb, mono_type_to_stind (type)); break; case MONO_TYPE_VALUETYPE: - g_assert (!klass->enumtype); + g_assert (!m_class_is_enumtype (klass)); mono_mb_emit_op (mb, CEE_STOBJ, klass); break; case MONO_TYPE_GENERICINST: @@ -1860,18 +1872,18 @@ mono_marshal_get_proxy_cancast (MonoClass *klass) MonoMethodDesc *desc; MonoMethodBuilder *mb; - cache = get_cache (&klass->image->proxy_isinst_cache, mono_aligned_addr_hash, NULL); + cache = get_cache (&m_class_get_image (klass)->proxy_isinst_cache, mono_aligned_addr_hash, NULL); if ((res = mono_marshal_find_in_cache (cache, klass))) return res; if (!isint_sig) { isint_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1); - isint_sig->params [0] = &mono_defaults.object_class->byval_arg; - isint_sig->ret = &mono_defaults.object_class->byval_arg; + isint_sig->params [0] = m_class_get_byval_arg (mono_defaults.object_class); + isint_sig->ret = m_class_get_byval_arg (mono_defaults.object_class); isint_sig->pinvoke = 0; } - klass_name = mono_type_full_name (&klass->byval_arg); + klass_name = mono_type_full_name (m_class_get_byval_arg (klass)); name = g_strdup_printf ("__proxy_isinst_wrapper_%s", klass_name); mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_PROXY_ISINST); g_free (klass_name); @@ -1886,7 +1898,7 @@ mono_marshal_get_proxy_cancast (MonoClass *klass) mono_mb_emit_byte (mb, CEE_LDIND_REF); /* get the reflection type from the type handle */ - mono_mb_emit_ptr (mb, &klass->byval_arg); + mono_mb_emit_ptr (mb, m_class_get_byval_arg (klass)); mono_mb_emit_icall (mb, type_from_handle); mono_mb_emit_ldarg (mb, 0); @@ -1901,7 +1913,7 @@ mono_marshal_get_proxy_cancast (MonoClass *klass) pos_failed = mono_mb_emit_branch (mb, CEE_BRFALSE); /* Upgrade the proxy vtable by calling: mono_upgrade_remote_class_wrapper (type, ob)*/ - mono_mb_emit_ptr (mb, &klass->byval_arg); + mono_mb_emit_ptr (mb, m_class_get_byval_arg (klass)); mono_mb_emit_icall (mb, type_from_handle); mono_mb_emit_ldarg (mb, 0); @@ -1978,8 +1990,8 @@ mono_get_xdomain_marshal_type (MonoType *t) return MONO_MARSHAL_COPY; case MONO_TYPE_ARRAY: case MONO_TYPE_SZARRAY: { - MonoClass *elem_class = mono_class_from_mono_type (t)->element_class; - if (mono_get_xdomain_marshal_type (&(elem_class->byval_arg)) != MONO_MARSHAL_SERIALIZE) + MonoClass *elem_class = m_class_get_element_class (mono_class_from_mono_type (t)); + if (mono_get_xdomain_marshal_type (m_class_get_byval_arg (elem_class)) != MONO_MARSHAL_SERIALIZE) return MONO_MARSHAL_COPY; break; } @@ -2024,7 +2036,7 @@ mono_marshal_xdomain_copy_value_handle (MonoObjectHandle val, MonoError *error) MonoClass *klass = mono_handle_class (val); - switch (klass->byval_arg.type) { + switch (m_class_get_byval_arg (klass)->type) { case MONO_TYPE_VOID: g_assert_not_reached (); break; @@ -2059,7 +2071,7 @@ mono_marshal_xdomain_copy_value_handle (MonoObjectHandle val, MonoError *error) case MONO_TYPE_ARRAY: case MONO_TYPE_SZARRAY: { MonoArrayHandle arr = MONO_HANDLE_CAST (MonoArray, val); - MonoXDomainMarshalType mt = mono_get_xdomain_marshal_type (&klass->element_class->byval_arg); + MonoXDomainMarshalType mt = mono_get_xdomain_marshal_type (m_class_get_byval_arg (m_class_get_element_class (klass))); if (mt == MONO_MARSHAL_SERIALIZE) goto leave; MonoArrayHandle acopy = mono_array_clone_in_domain (domain, arr, error); diff --git a/mono/metadata/runtime.h b/mono/metadata/runtime.h index ddd6d5deb5..d9a8f5cba9 100644 --- a/mono/metadata/runtime.h +++ b/mono/metadata/runtime.h @@ -22,7 +22,8 @@ gboolean mono_runtime_try_shutdown (void); void mono_runtime_init_tls (void); -char* mono_runtime_get_aotid (void); +MONO_PROFILER_API char* mono_runtime_get_aotid (void); + MONO_END_DECLS #endif /* _MONO_METADATA_RUNTIME_H_ */ diff --git a/mono/metadata/security-core-clr.c b/mono/metadata/security-core-clr.c index e81cadc460..676d978575 100644 --- a/mono/metadata/security-core-clr.c +++ b/mono/metadata/security-core-clr.c @@ -11,6 +11,7 @@ */ #include +#include #include #include #include @@ -162,8 +163,8 @@ static void set_type_load_exception_type (const char *format, MonoClass *klass) { char *type_name = mono_type_get_full_name (klass); - char *parent_name = mono_type_get_full_name (klass->parent); - char *message = mono_image_strdup_printf (klass->image, format, type_name, parent_name); + char *parent_name = mono_type_get_full_name (m_class_get_parent (klass)); + char *message = mono_image_strdup_printf (m_class_get_image (klass), format, type_name, parent_name); g_free (parent_name); g_free (type_name); @@ -186,7 +187,7 @@ set_type_load_exception_methods (const char *format, MonoMethod *override, MonoM { char *method_name = get_method_full_name (override); char *base_name = get_method_full_name (base); - char *message = mono_image_strdup_printf (override->klass->image, format, method_name, base_name); + char *message = mono_image_strdup_printf (m_class_get_image (override->klass), format, method_name, base_name); g_free (base_name); g_free (method_name); @@ -206,13 +207,14 @@ get_default_ctor (MonoClass *klass) int i; mono_class_setup_methods (klass); - if (!klass->methods) + if (!m_class_get_methods (klass)) return NULL; int mcount = mono_class_get_method_count (klass); + MonoMethod **klass_methods = m_class_get_methods (klass); for (i = 0; i < mcount; ++i) { MonoMethodSignature *sig; - MonoMethod *method = klass->methods [i]; + MonoMethod *method = klass_methods [i]; if (!method) continue; @@ -254,7 +256,7 @@ void mono_security_core_clr_check_inheritance (MonoClass *klass) { MonoSecurityCoreCLRLevel class_level, parent_level; - MonoClass *parent = klass->parent; + MonoClass *parent = m_class_get_parent (klass); if (!parent) return; @@ -339,14 +341,14 @@ get_caller_no_reflection_related (MonoMethod *m, gint32 no, gint32 ilo, gboolean return FALSE; /* quick out (any namespace not starting with an 'S' */ - ns = m->klass->name_space; + ns = m_class_get_name_space (m->klass); if (!ns || (*ns != 'S')) { *dest = m; return TRUE; } /* stop if the method is not part of platform code */ - if (!mono_security_core_clr_is_platform_image (m->klass->image)) { + if (!mono_security_core_clr_is_platform_image (m_class_get_image (m->klass))) { *dest = m; return TRUE; } @@ -361,7 +363,7 @@ get_caller_no_reflection_related (MonoMethod *m, gint32 no, gint32 ilo, gboolean /* calls from System.Delegate are also possible and allowed */ if (strcmp (ns, "System") == 0) { - const char *kname = m->klass->name; + const char *kname = m_class_get_name (m->klass); if ((*kname == 'A') && (strcmp (kname, "Activator") == 0)) return FALSE; @@ -439,7 +441,7 @@ get_caller_of_elevated_trust_code (MonoMethod *m, gint32 no, gint32 ilo, gboolea return FALSE; /* end stack walk if we find ourselves outside platform code (we won't find critical code anymore) */ - if (!mono_security_core_clr_is_platform_image (m->klass->image)) { + if (!mono_security_core_clr_is_platform_image (m_class_get_image (m->klass))) { cookie->caller = m; return TRUE; } @@ -447,9 +449,9 @@ get_caller_of_elevated_trust_code (MonoMethod *m, gint32 no, gint32 ilo, gboolea switch (cookie->depth) { /* while depth == 0 look for SecurityManager::[Check|Ensure]ElevatedPermissions */ case 0: - if (strcmp (m->klass->name_space, "System.Security")) + if (strcmp (m_class_get_name_space (m->klass), "System.Security")) return FALSE; - if (strcmp (m->klass->name, "SecurityManager")) + if (strcmp (m_class_get_name (m->klass), "SecurityManager")) return FALSE; if ((strcmp (m->name, "EnsureElevatedPermissions")) && strcmp (m->name, "CheckElevatedPermissions")) return FALSE; @@ -641,7 +643,7 @@ mono_security_core_clr_ensure_reflection_access_field (MonoClassField *field, Mo return TRUE; if (mono_security_core_clr_get_options () & MONO_SECURITY_CORE_CLR_OPTIONS_RELAX_REFLECTION) { - if (!mono_security_core_clr_is_platform_image (mono_field_get_parent(field)->image)) + if (!mono_security_core_clr_is_platform_image (m_class_get_image (mono_field_get_parent(field)))) return TRUE; } @@ -682,7 +684,7 @@ mono_security_core_clr_ensure_reflection_access_method (MonoMethod *method, Mono return TRUE; if (mono_security_core_clr_get_options () & MONO_SECURITY_CORE_CLR_OPTIONS_RELAX_REFLECTION) { - if (!mono_security_core_clr_is_platform_image (method->klass->image)) + if (!mono_security_core_clr_is_platform_image (m_class_get_image (method->klass))) return TRUE; } @@ -719,16 +721,16 @@ mono_security_core_clr_ensure_reflection_access_method (MonoMethod *method, Mono static gboolean can_avoid_corlib_reflection_delegate_optimization (MonoMethod *method) { - if (!mono_security_core_clr_is_platform_image (method->klass->image)) + if (!mono_security_core_clr_is_platform_image (m_class_get_image (method->klass))) return FALSE; - if (strcmp (method->klass->name_space, "System.Reflection") != 0) + if (strcmp (m_class_get_name_space (method->klass), "System.Reflection") != 0) return FALSE; - if (strcmp (method->klass->name, "MonoProperty") == 0) { + if (strcmp (m_class_get_name (method->klass), "MonoProperty") == 0) { if ((strcmp (method->name, "GetterAdapterFrame") == 0) || strcmp (method->name, "StaticGetterAdapterFrame") == 0) return TRUE; - } else if (strcmp (method->klass->name, "EventInfo") == 0) { + } else if (strcmp (m_class_get_name (method->klass), "EventInfo") == 0) { if ((strcmp (method->name, "AddEventFrame") == 0) || strcmp (method->name, "StaticAddEventAdapterFrame") == 0) return TRUE; } @@ -771,7 +773,7 @@ mono_security_core_clr_ensure_delegate_creation (MonoMethod *method, MonoError * } if (mono_security_core_clr_get_options () & MONO_SECURITY_CORE_CLR_OPTIONS_RELAX_DELEGATE) { - if (!mono_security_core_clr_is_platform_image (method->klass->image)) + if (!mono_security_core_clr_is_platform_image (m_class_get_image (method->klass))) return TRUE; } @@ -802,7 +804,7 @@ mono_security_core_clr_ensure_dynamic_method_resolved_object (gpointer ref, Mono MonoClassField *field = (MonoClassField*) ref; MonoClass *klass = mono_field_get_parent (field); /* fields coming from platform code have extra protection (accessibility check) */ - if (mono_security_core_clr_is_platform_image (klass->image)) { + if (mono_security_core_clr_is_platform_image (m_class_get_image (klass))) { MonoMethod *caller = get_reflection_caller (); /* XXX Critical code probably can do this / need some test cases (safer off otherwise) XXX */ if (!check_field_access (caller, field)) { @@ -814,7 +816,7 @@ mono_security_core_clr_ensure_dynamic_method_resolved_object (gpointer ref, Mono } else if (handle_class == mono_defaults.methodhandle_class) { MonoMethod *method = (MonoMethod*) ref; /* methods coming from platform code have extra protection (accessibility check) */ - if (mono_security_core_clr_is_platform_image (method->klass->image)) { + if (mono_security_core_clr_is_platform_image (m_class_get_image (method->klass))) { MonoMethod *caller = get_reflection_caller (); /* XXX Critical code probably can do this / need some test cases (safer off otherwise) XXX */ if (!check_method_access (caller, method)) { @@ -940,12 +942,12 @@ mono_security_core_clr_class_level_no_platform_check (MonoClass *klass) MonoCustomAttrInfo *cinfo = mono_custom_attrs_from_class_checked (klass, error); mono_error_cleanup (error); if (cinfo) { - level = mono_security_core_clr_level_from_cinfo (cinfo, klass->image); + level = mono_security_core_clr_level_from_cinfo (cinfo, m_class_get_image (klass)); mono_custom_attrs_free (cinfo); } - if (level == MONO_SECURITY_CORE_CLR_TRANSPARENT && klass->nested_in) - level = mono_security_core_clr_class_level_no_platform_check (klass->nested_in); + if (level == MONO_SECURITY_CORE_CLR_TRANSPARENT && m_class_get_nested_in (klass)) + level = mono_security_core_clr_class_level_no_platform_check (m_class_get_nested_in (klass)); return level; } @@ -959,7 +961,7 @@ MonoSecurityCoreCLRLevel mono_security_core_clr_class_level (MonoClass *klass) { /* non-platform code is always Transparent - whatever the attributes says */ - if (!mono_security_core_clr_test && !mono_security_core_clr_is_platform_image (klass->image)) + if (!mono_security_core_clr_test && !mono_security_core_clr_is_platform_image (m_class_get_image (klass))) return MONO_SECURITY_CORE_CLR_TRANSPARENT; return mono_security_core_clr_class_level_no_platform_check (klass); @@ -985,13 +987,13 @@ mono_security_core_clr_field_level (MonoClassField *field, gboolean with_class_l return level; /* non-platform code is always Transparent - whatever the attributes says */ - if (!mono_security_core_clr_test && !mono_security_core_clr_is_platform_image (field->parent->image)) + if (!mono_security_core_clr_test && !mono_security_core_clr_is_platform_image (m_class_get_image (field->parent))) return level; cinfo = mono_custom_attrs_from_field_checked (field->parent, field, error); mono_error_cleanup (error); if (cinfo) { - level = mono_security_core_clr_level_from_cinfo (cinfo, field->parent->image); + level = mono_security_core_clr_level_from_cinfo (cinfo, m_class_get_image (field->parent)); mono_custom_attrs_free (cinfo); } @@ -1021,13 +1023,13 @@ mono_security_core_clr_method_level (MonoMethod *method, gboolean with_class_lev return level; /* non-platform code is always Transparent - whatever the attributes says */ - if (!mono_security_core_clr_test && !mono_security_core_clr_is_platform_image (method->klass->image)) + if (!mono_security_core_clr_test && !mono_security_core_clr_is_platform_image (m_class_get_image (method->klass))) return level; cinfo = mono_custom_attrs_from_method_checked (method, error); mono_error_cleanup (error); if (cinfo) { - level = mono_security_core_clr_level_from_cinfo (cinfo, method->klass->image); + level = mono_security_core_clr_level_from_cinfo (cinfo, m_class_get_image (method->klass)); mono_custom_attrs_free (cinfo); } diff --git a/mono/metadata/security-manager.c b/mono/metadata/security-manager.c index eba523cfaf..64d03261dd 100644 --- a/mono/metadata/security-manager.c +++ b/mono/metadata/security-manager.c @@ -43,7 +43,7 @@ mono_security_manager_get_methods (void) /* Initialize */ secman.securitymanager = mono_class_get_security_manager_class (); - if (!secman.securitymanager->inited) + if (!m_class_is_inited (secman.securitymanager)) mono_class_init (secman.securitymanager); return &secman; diff --git a/mono/metadata/security.h b/mono/metadata/security.h index e6d57cff5d..4d64d670d2 100644 --- a/mono/metadata/security.h +++ b/mono/metadata/security.h @@ -59,7 +59,7 @@ MonoBoolean ves_icall_System_Security_Policy_Evidence_IsAuthenticodePresent (Mon /* System.Security.SecureString */ extern void ves_icall_System_Security_SecureString_DecryptInternal (MonoArray *data, MonoObject *scope); extern void ves_icall_System_Security_SecureString_EncryptInternal (MonoArray *data, MonoObject *scope); -void invoke_protected_memory_method (MonoArray *data, MonoObject *scope, gboolean encrypt, MonoError *error); +void mono_invoke_protected_memory_method (MonoArray *data, MonoObject *scope, gboolean encrypt, MonoError *error); G_END_DECLS diff --git a/mono/metadata/sgen-bridge-internals.h b/mono/metadata/sgen-bridge-internals.h index cf987d045d..e66455b16f 100644 --- a/mono/metadata/sgen-bridge-internals.h +++ b/mono/metadata/sgen-bridge-internals.h @@ -19,8 +19,8 @@ #include "mono/sgen/sgen-gc.h" #include "mono/metadata/sgen-bridge.h" -extern volatile gboolean bridge_processing_in_progress; -extern MonoGCBridgeCallbacks bridge_callbacks; +extern volatile gboolean mono_bridge_processing_in_progress; +extern MonoGCBridgeCallbacks mono_bridge_callbacks; gboolean sgen_need_bridge_processing (void); void sgen_bridge_reset_data (void); diff --git a/mono/metadata/sgen-bridge.c b/mono/metadata/sgen-bridge.c index 9d7809a211..4d51102ea6 100644 --- a/mono/metadata/sgen-bridge.c +++ b/mono/metadata/sgen-bridge.c @@ -22,6 +22,8 @@ #include "sgen/sgen-qsort.h" #include "utils/mono-logger-internals.h" +#ifndef DISABLE_SGEN_GC_BRIDGE + typedef enum { BRIDGE_PROCESSOR_INVALID, BRIDGE_PROCESSOR_OLD, @@ -37,14 +39,14 @@ static MonoGCBridgeCallbacks pending_bridge_callbacks; // Configuration to be passed to bridge processor after init static SgenBridgeProcessorConfig bridge_processor_config; // Currently-in-use callbacks -MonoGCBridgeCallbacks bridge_callbacks; +MonoGCBridgeCallbacks mono_bridge_callbacks; // Bridge processor state static SgenBridgeProcessor bridge_processor; // This is used for a special debug feature static SgenBridgeProcessor compare_to_bridge_processor; -volatile gboolean bridge_processing_in_progress = FALSE; +volatile gboolean mono_bridge_processing_in_progress = FALSE; // FIXME: The current usage pattern for this function is unsafe. Bridge processing could start immediately after unlock /** @@ -53,7 +55,7 @@ volatile gboolean bridge_processing_in_progress = FALSE; void mono_gc_wait_for_bridge_processing (void) { - if (!bridge_processing_in_progress) + if (!mono_bridge_processing_in_progress) return; mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_GC, "GC_BRIDGE waiting for bridge processing to finish"); @@ -145,10 +147,10 @@ sgen_init_bridge (void) // This lock is not initialized until the GC is sgen_gc_lock (); - bridge_callbacks = pending_bridge_callbacks; + mono_bridge_callbacks = pending_bridge_callbacks; // If a bridge was registered but there is no bridge processor yet - if (bridge_callbacks.cross_references && !bridge_processor_started ()) { + if (mono_bridge_callbacks.cross_references && !bridge_processor_started ()) { init_bridge_processor (&bridge_processor, bridge_processor_selection); if (bridge_processor.set_config) @@ -181,13 +183,13 @@ sgen_is_bridge_object (GCObject *obj) { if ((obj->vtable->gc_bits & SGEN_GC_BIT_BRIDGE_OBJECT) != SGEN_GC_BIT_BRIDGE_OBJECT) return FALSE; - return bridge_callbacks.is_bridge_object (obj); + return mono_bridge_callbacks.is_bridge_object (obj); } gboolean sgen_need_bridge_processing (void) { - return bridge_callbacks.cross_references != NULL; + return mono_bridge_callbacks.cross_references != NULL; } static gboolean @@ -209,10 +211,10 @@ void sgen_bridge_processing_stw_step (void) { /* - * bridge_processing_in_progress must be set with the world + * mono_bridge_processing_in_progress must be set with the world * stopped. If not there would be race conditions. */ - bridge_processing_in_progress = TRUE; + mono_bridge_processing_in_progress = TRUE; bridge_processor.processing_stw_step (); if (compare_bridge_processors ()) @@ -457,7 +459,7 @@ sgen_bridge_processing_finish (int generation) goto after_callback; } - bridge_callbacks.cross_references (bridge_processor.num_sccs, bridge_processor.api_sccs, + mono_bridge_callbacks.cross_references (bridge_processor.num_sccs, bridge_processor.api_sccs, bridge_processor.num_xrefs, bridge_processor.api_xrefs); if (compare_bridge_processors ()) @@ -476,7 +478,7 @@ sgen_bridge_processing_finish (int generation) mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_GC, "GC_BRIDGE: Complete, was running for %.2fms", mono_time_since_last_stw () / 10000.0f); - bridge_processing_in_progress = FALSE; + mono_bridge_processing_in_progress = FALSE; } MonoGCBridgeObjectKind @@ -514,7 +516,7 @@ static const char *bridge_class; static MonoGCBridgeObjectKind bridge_test_bridge_class_kind (MonoClass *klass) { - if (!strcmp (bridge_class, klass->name)) + if (!strcmp (bridge_class, m_class_get_name (klass))) return GC_BRIDGE_TRANSPARENT_BRIDGE_CLASS; return GC_BRIDGE_TRANSPARENT_CLASS; } @@ -724,4 +726,87 @@ sgen_bridge_print_gc_debug_usage (void) fprintf (stderr, " bridge-compare-to=\n"); } +#else + +//UG +volatile gboolean mono_bridge_processing_in_progress = FALSE; + +void +mono_gc_wait_for_bridge_processing (void) +{ +} + +MonoGCBridgeObjectKind +sgen_bridge_class_kind (MonoClass *klass) +{ + return GC_BRIDGE_TRANSPARENT_CLASS; +} + +void +sgen_bridge_describe_pointer (GCObject *obj) +{ +} + +gboolean +sgen_bridge_handle_gc_debug (const char *opt) +{ + return FALSE; +} + +gboolean +sgen_bridge_handle_gc_param (const char *opt) +{ + return FALSE; +} + +void +sgen_bridge_print_gc_debug_usage (void) +{ +} + +void +sgen_bridge_processing_finish (int generation) +{ +} + +void +sgen_bridge_processing_stw_step (void) +{ +} + +void +sgen_bridge_register_finalized_object (GCObject *obj) +{ +} + +void +sgen_bridge_reset_data (void) +{ +} + +void +sgen_init_bridge (void) +{ +} + +gboolean +sgen_is_bridge_object (GCObject *obj) +{ + return FALSE; +} + +gboolean +sgen_need_bridge_processing (void) +{ + return FALSE; +} + +void +sgen_set_bridge_implementation (const char *name) +{ + g_error ("Sgen bridge disabled"); +} + +#endif + #endif diff --git a/mono/metadata/sgen-client-mono.h b/mono/metadata/sgen-client-mono.h index a5af82696c..e200225799 100644 --- a/mono/metadata/sgen-client-mono.h +++ b/mono/metadata/sgen-client-mono.h @@ -40,15 +40,6 @@ struct _SgenClientThreadInfo { gboolean skip, suspend_done; volatile int in_critical_region; - /* - This is set the argument of mono_gc_set_skip_thread. - - A thread that knowingly holds no managed state can call this - function around blocking loops to reduce the GC burden by not - been scanned. - */ - gboolean gc_disabled; - #ifdef SGEN_POSIX_STW /* This is -1 until the first suspend. */ int signal; @@ -96,14 +87,14 @@ sgen_mono_array_size (GCVTable vtable, MonoArray *array, mword *bounds_size, mwo if ((descr & DESC_TYPE_MASK) == DESC_TYPE_VECTOR) element_size = ((descr) >> VECTOR_ELSIZE_SHIFT) & MAX_ELEMENT_SIZE; else - element_size = vtable->klass->sizes.element_size; + element_size = m_class_get_sizes (vtable->klass).element_size; size_without_bounds = size = MONO_SIZEOF_MONO_ARRAY + (mword)element_size * mono_array_length_fast (array); if (G_UNLIKELY (array->bounds)) { size += sizeof (mono_array_size_t) - 1; size &= ~(sizeof (mono_array_size_t) - 1); - size += sizeof (MonoArrayBounds) * vtable->klass->rank; + size += sizeof (MonoArrayBounds) * m_class_get_rank (vtable->klass); } if (bounds_size) @@ -125,11 +116,11 @@ sgen_client_slow_object_get_size (GCVTable vtable, GCObject* o) */ if (klass == mono_defaults.string_class) { return G_STRUCT_OFFSET (MonoString, chars) + 2 * mono_string_length_fast ((MonoString*) o) + 2; - } else if (klass->rank) { + } else if (m_class_get_rank (klass)) { return sgen_mono_array_size (vtable, (MonoArray*)o, NULL, 0); } else { /* from a created object: the class must be inited already */ - return klass->instance_size; + return m_class_get_instance_size (klass); } } @@ -186,7 +177,7 @@ static MONO_ALWAYS_INLINE void G_GNUC_UNUSED sgen_client_pre_copy_checks (char *destination, GCVTable gc_vtable, void *obj, mword objsize) { MonoVTable *vt = (MonoVTable*)gc_vtable; - SGEN_ASSERT (9, vt->klass->inited, "vtable %p for class %s:%s was not initialized", vt, vt->klass->name_space, vt->klass->name); + SGEN_ASSERT (9, m_class_is_inited (vt->klass), "vtable %p for class %s:%s was not initialized", vt, m_class_get_name_space (vt->klass), m_class_get_name (vt->klass)); } static MONO_ALWAYS_INLINE void G_GNUC_UNUSED diff --git a/mono/metadata/sgen-mono-ilgen.c b/mono/metadata/sgen-mono-ilgen.c index fd0712cfca..3f547ff9ac 100644 --- a/mono/metadata/sgen-mono-ilgen.c +++ b/mono/metadata/sgen-mono-ilgen.c @@ -17,8 +17,10 @@ #include "sgen/sgen-cardtable.h" #include "sgen/sgen-pinning.h" #include "sgen/sgen-workers.h" +#include "metadata/class-init.h" #include "metadata/marshal.h" #include "metadata/abi-details.h" +#include "metadata/class-abi-details.h" #include "metadata/mono-gc.h" #include "metadata/runtime.h" #include "metadata/sgen-bridge-internals.h" @@ -46,7 +48,7 @@ enum { // Cache the SgenThreadInfo pointer in a local 'var'. #define EMIT_TLS_ACCESS_VAR(mb, var) \ do { \ - var = mono_mb_add_local ((mb), &mono_defaults.int_class->byval_arg); \ + var = mono_mb_add_local ((mb), m_class_get_byval_arg (mono_defaults.int_class)); \ mono_mb_emit_byte ((mb), MONO_CUSTOM_PREFIX); \ mono_mb_emit_byte ((mb), CEE_MONO_TLS); \ mono_mb_emit_i4 ((mb), TLS_KEY_SGEN_THREAD_INFO); \ @@ -77,7 +79,7 @@ enum { static void emit_nursery_check (MonoMethodBuilder *mb, int *nursery_check_return_labels, gboolean is_concurrent) { - int shifted_nursery_start = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); + int shifted_nursery_start = mono_mb_add_local (mb, m_class_get_byval_arg (mono_defaults.int_class)); memset (nursery_check_return_labels, 0, sizeof (int) * 2); // if (ptr_in_nursery (ptr)) return; @@ -198,13 +200,14 @@ emit_managed_allocater_ilgen (MonoMethodBuilder *mb, gboolean slowpath, gboolean goto done; } + MonoType *int_type = m_class_get_byval_arg (mono_defaults.int_class); /* * Tls access might call foreign code or code without jinfo. This can * only happen if we are outside of the critical region. */ EMIT_TLS_ACCESS_VAR (mb, thread_var); - size_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); + size_var = mono_mb_add_local (mb, int_type); if (atype == ATYPE_SMALL) { /* size_var = size_arg */ mono_mb_emit_ldarg (mb, 1); @@ -215,7 +218,7 @@ emit_managed_allocater_ilgen (MonoMethodBuilder *mb, gboolean slowpath, gboolean mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoVTable, klass)); mono_mb_emit_byte (mb, CEE_ADD); mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoClass, instance_size)); + mono_mb_emit_icon (mb, m_class_offsetof_instance_size ()); mono_mb_emit_byte (mb, CEE_ADD); /* FIXME: assert instance_size stays a 4 byte integer */ mono_mb_emit_byte (mb, CEE_LDIND_U4); @@ -258,7 +261,7 @@ emit_managed_allocater_ilgen (MonoMethodBuilder *mb, gboolean slowpath, gboolean mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoVTable, klass)); mono_mb_emit_byte (mb, CEE_ADD); mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoClass, sizes)); + mono_mb_emit_icon (mb, m_class_offsetof_sizes ()); mono_mb_emit_byte (mb, CEE_ADD); mono_mb_emit_byte (mb, CEE_LDIND_U4); mono_mb_emit_byte (mb, CEE_CONV_I); @@ -338,8 +341,8 @@ emit_managed_allocater_ilgen (MonoMethodBuilder *mb, gboolean slowpath, gboolean mono_mb_emit_i4 (mb, MONO_MEMORY_BARRIER_NONE); #endif - if (nursery_canaries_enabled ()) { - real_size_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); + if (sgen_nursery_canaries_enabled ()) { + real_size_var = mono_mb_add_local (mb, int_type); mono_mb_emit_ldloc (mb, size_var); mono_mb_emit_stloc(mb, real_size_var); } @@ -368,24 +371,24 @@ emit_managed_allocater_ilgen (MonoMethodBuilder *mb, gboolean slowpath, gboolean */ /* tlab_next_addr (local) = tlab_next_addr (TLS var) */ - tlab_next_addr_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); + tlab_next_addr_var = mono_mb_add_local (mb, int_type); EMIT_TLS_ACCESS_NEXT_ADDR (mb, thread_var); mono_mb_emit_stloc (mb, tlab_next_addr_var); /* p = (void**)tlab_next; */ - p_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); + p_var = mono_mb_add_local (mb, int_type); mono_mb_emit_ldloc (mb, tlab_next_addr_var); mono_mb_emit_byte (mb, CEE_LDIND_I); mono_mb_emit_stloc (mb, p_var); /* new_next = (char*)p + size; */ - new_next_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); + new_next_var = mono_mb_add_local (mb, int_type); mono_mb_emit_ldloc (mb, p_var); mono_mb_emit_ldloc (mb, size_var); mono_mb_emit_byte (mb, CEE_CONV_I); mono_mb_emit_byte (mb, CEE_ADD); - if (nursery_canaries_enabled ()) { + if (sgen_nursery_canaries_enabled ()) { mono_mb_emit_icon (mb, CANARY_SIZE); mono_mb_emit_byte (mb, CEE_ADD); } @@ -454,7 +457,7 @@ emit_managed_allocater_ilgen (MonoMethodBuilder *mb, gboolean slowpath, gboolean mono_mb_emit_byte (mb, CEE_STIND_I); /* mark object end with nursery word */ - if (nursery_canaries_enabled ()) { + if (sgen_nursery_canaries_enabled ()) { mono_mb_emit_ldloc (mb, p_var); mono_mb_emit_ldloc (mb, real_size_var); mono_mb_emit_byte (mb, MONO_CEE_ADD); diff --git a/mono/metadata/sgen-mono.c b/mono/metadata/sgen-mono.c index 732078718b..8baded3a26 100644 --- a/mono/metadata/sgen-mono.c +++ b/mono/metadata/sgen-mono.c @@ -18,9 +18,11 @@ #include "sgen/sgen-cardtable.h" #include "sgen/sgen-pinning.h" #include "sgen/sgen-workers.h" +#include "metadata/class-init.h" #include "metadata/marshal.h" #include "metadata/method-builder.h" #include "metadata/abi-details.h" +#include "metadata/class-abi-details.h" #include "metadata/mono-gc.h" #include "metadata/runtime.h" #include "metadata/sgen-bridge-internals.h" @@ -52,7 +54,15 @@ gboolean sgen_mono_xdomain_checks = FALSE; /* Functions supplied by the runtime to be called by the GC */ static MonoGCCallbacks gc_callbacks; -#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1)) +#define OPDEF(a,b,c,d,e,f,g,h,i,j) \ + a = i, + +enum { +#include "mono/cil/opcode.def" + CEE_LAST +}; + +#undef OPDEF /* * Write barriers @@ -75,7 +85,7 @@ ptr_on_stack (void *ptr) gpointer o = *(gpointer*)(ptr); \ if ((o)) { \ gpointer d = ((char*)dest) + ((char*)(ptr) - (char*)(obj)); \ - binary_protocol_wbarrier (d, o, (gpointer) SGEN_LOAD_VTABLE (o)); \ + sgen_binary_protocol_wbarrier (d, o, (gpointer) SGEN_LOAD_VTABLE (o)); \ } \ } while (0) @@ -91,11 +101,11 @@ void mono_gc_wbarrier_value_copy (gpointer dest, gpointer src, int count, MonoClass *klass) { HEAVY_STAT (++stat_wbarrier_value_copy); - g_assert (klass->valuetype); + g_assert (m_class_is_valuetype (klass)); - SGEN_LOG (8, "Adding value remset at %p, count %d, descr %p for class %s (%p)", dest, count, (gpointer)klass->gc_descr, klass->name, klass); + SGEN_LOG (8, "Adding value remset at %p, count %d, descr %p for class %s (%p)", dest, count, (gpointer)m_class_get_gc_descr (klass), m_class_get_name (klass), klass); - if (sgen_ptr_in_nursery (dest) || ptr_on_stack (dest) || !sgen_gc_descr_has_references ((mword)klass->gc_descr)) { + if (sgen_ptr_in_nursery (dest) || ptr_on_stack (dest) || !sgen_gc_descr_has_references ((mword)m_class_get_gc_descr (klass))) { size_t element_size = mono_class_value_size (klass, NULL); size_t size = count * element_size; mono_gc_memmove_atomic (dest, src, size); @@ -103,7 +113,7 @@ mono_gc_wbarrier_value_copy (gpointer dest, gpointer src, int count, MonoClass * } #ifdef SGEN_HEAVY_BINARY_PROTOCOL - if (binary_protocol_is_heavy_enabled ()) { + if (sgen_binary_protocol_is_heavy_enabled ()) { size_t element_size = mono_class_value_size (klass, NULL); int i; for (i = 0; i < count; ++i) { @@ -131,14 +141,14 @@ mono_gc_wbarrier_object_copy (MonoObject* obj, MonoObject *src) SGEN_ASSERT (6, !ptr_on_stack (obj), "Why is this called for a non-reference type?"); if (sgen_ptr_in_nursery (obj) || !SGEN_OBJECT_HAS_REFERENCES (src)) { - size = mono_object_class (obj)->instance_size; + size = m_class_get_instance_size (mono_object_class (obj)); mono_gc_memmove_aligned ((char*)obj + sizeof (MonoObject), (char*)src + sizeof (MonoObject), size - sizeof (MonoObject)); return; } #ifdef SGEN_HEAVY_BINARY_PROTOCOL - if (binary_protocol_is_heavy_enabled ()) + if (sgen_binary_protocol_is_heavy_enabled ()) scan_object_for_binary_protocol_copy_wbarrier (obj, (char*)src, (mword) src->vtable->gc_descr); #endif @@ -158,7 +168,7 @@ mono_gc_wbarrier_set_arrayref (MonoArray *arr, gpointer slot_ptr, MonoObject* va } SGEN_LOG (8, "Adding remset at %p", slot_ptr); if (value) - binary_protocol_wbarrier (slot_ptr, value, value->vtable); + sgen_binary_protocol_wbarrier (slot_ptr, value, value->vtable); sgen_get_remset ()->wbarrier_set_field ((GCObject*)arr, slot_ptr, value); } @@ -282,8 +292,8 @@ mono_gc_get_specific_write_barrier (gboolean is_concurrent) /* Create the IL version of mono_gc_barrier_generic_store () */ sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1); - sig->ret = &mono_defaults.void_class->byval_arg; - sig->params [0] = &mono_defaults.int_class->byval_arg; + sig->ret = m_class_get_byval_arg (mono_defaults.void_class); + sig->params [0] = m_class_get_byval_arg (mono_defaults.int_class); if (is_concurrent) mb = mono_mb_new (mono_defaults.object_class, "wbarrier_conc", MONO_WRAPPER_WRITE_BARRIER); @@ -314,7 +324,7 @@ mono_gc_get_specific_write_barrier (gboolean is_concurrent) MonoMethod* mono_gc_get_write_barrier (void) { - return mono_gc_get_specific_write_barrier (major_collector.is_concurrent); + return mono_gc_get_specific_write_barrier (sgen_major_collector.is_concurrent); } /* @@ -328,22 +338,15 @@ static GCVTable get_array_fill_vtable (void) { if (!array_fill_vtable) { - static MonoClass klass; static char _vtable[sizeof(MonoVTable)+8]; MonoVTable* vtable = (MonoVTable*) ALIGN_TO((mword)_vtable, 8); gsize bmap; + MonoClass *klass = mono_class_create_array_fill_type (); MonoDomain *domain = mono_get_root_domain (); g_assert (domain); - klass.element_class = mono_defaults.byte_class; - klass.rank = 1; - klass.instance_size = MONO_SIZEOF_MONO_ARRAY; - klass.sizes.element_size = 1; - klass.size_inited = 1; - klass.name = "array_filler_type"; - - vtable->klass = &klass; + vtable->klass = klass; bmap = 0; vtable->gc_descr = mono_gc_make_descr_for_array (TRUE, &bmap, 0, 1); vtable->rank = 1; @@ -487,7 +490,7 @@ sgen_client_finalize_notify (void) } void -mono_gc_register_for_finalization (MonoObject *obj, void *user_data) +mono_gc_register_for_finalization (MonoObject *obj, MonoFinalizationProc user_data) { sgen_object_register_for_finalization (obj, user_data); } @@ -718,7 +721,7 @@ need_remove_object_for_domain (GCObject *start, MonoDomain *domain) { if (mono_object_domain (start) == domain) { SGEN_LOG (4, "Need to cleanup object %p", start); - binary_protocol_cleanup (start, (gpointer)SGEN_LOAD_VTABLE (start), sgen_safe_object_get_size ((GCObject*)start)); + sgen_binary_protocol_cleanup (start, (gpointer)SGEN_LOAD_VTABLE (start), sgen_safe_object_get_size ((GCObject*)start)); return TRUE; } return FALSE; @@ -733,7 +736,7 @@ process_object_for_domain_clearing (GCObject *start, MonoDomain *domain) /* The object could be a proxy for an object in the domain we're deleting. */ #ifndef DISABLE_REMOTING - if (mono_defaults.real_proxy_class->supertypes && mono_class_has_parent_fast (vt->klass, mono_defaults.real_proxy_class)) { + if (m_class_get_supertypes (mono_defaults.real_proxy_class) && mono_class_has_parent_fast (vt->klass, mono_defaults.real_proxy_class)) { MonoObject *server = ((MonoRealProxy*)start)->unwrapped_server; /* The server could already have been zeroed out, so @@ -782,14 +785,24 @@ static void clear_domain_free_major_non_pinned_object_callback (GCObject *obj, size_t size, MonoDomain *domain) { if (need_remove_object_for_domain (obj, domain)) - major_collector.free_non_pinned_object (obj, size); + sgen_major_collector.free_non_pinned_object (obj, size); } static void clear_domain_free_major_pinned_object_callback (GCObject *obj, size_t size, MonoDomain *domain) { if (need_remove_object_for_domain (obj, domain)) - major_collector.free_pinned_object (obj, size); + sgen_major_collector.free_pinned_object (obj, size); +} + +static void +sgen_finish_concurrent_work (const char *reason, gboolean stw) +{ + if (sgen_get_concurrent_collection_in_progress ()) + sgen_perform_collection (0, GENERATION_OLD, reason, TRUE, stw); + SGEN_ASSERT (0, !sgen_get_concurrent_collection_in_progress (), "We just ordered a synchronous collection. Why are we collecting concurrently?"); + + sgen_major_collector.finish_sweeping (); } /* @@ -809,21 +822,17 @@ mono_gc_clear_domain (MonoDomain * domain) LOCK_GC; - binary_protocol_domain_unload_begin (domain); + sgen_binary_protocol_domain_unload_begin (domain); sgen_stop_world (0, FALSE); - if (sgen_concurrent_collection_in_progress ()) - sgen_perform_collection (0, GENERATION_OLD, "clear domain", TRUE, FALSE); - SGEN_ASSERT (0, !sgen_concurrent_collection_in_progress (), "We just ordered a synchronous collection. Why are we collecting concurrently?"); - - major_collector.finish_sweeping (); + sgen_finish_concurrent_work ("clear domain", FALSE); sgen_process_fin_stage_entries (); sgen_clear_nursery_fragments (); - FOREACH_THREAD (info) { + FOREACH_THREAD_ALL (info) { mono_handle_stack_free_domain ((HandleStack*)info->client_info.info.handle_stack, domain); } FOREACH_THREAD_END @@ -841,7 +850,7 @@ mono_gc_clear_domain (MonoDomain * domain) for (i = GENERATION_NURSERY; i < GENERATION_MAX; ++i) sgen_remove_finalizers_if (object_in_domain_predicate, domain, i); - sgen_scan_area_with_callback (nursery_section->data, nursery_section->end_data, + sgen_scan_area_with_callback (sgen_nursery_section->data, sgen_nursery_section->end_data, (IterateObjectCallbackFunc)clear_domain_process_minor_object_callback, domain, FALSE, TRUE); /* We need two passes over major and large objects because @@ -851,18 +860,18 @@ mono_gc_clear_domain (MonoDomain * domain) objects with major-mark&sweep), but we might need to dereference a pointer from an object to another object if the first object is a proxy. */ - major_collector.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL, (IterateObjectCallbackFunc)clear_domain_process_major_object_callback, domain); - for (bigobj = los_object_list; bigobj; bigobj = bigobj->next) + sgen_major_collector.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL, (IterateObjectCallbackFunc)clear_domain_process_major_object_callback, domain); + for (bigobj = sgen_los_object_list; bigobj; bigobj = bigobj->next) clear_domain_process_object ((GCObject*)bigobj->data, domain); prev = NULL; - for (bigobj = los_object_list; bigobj;) { + for (bigobj = sgen_los_object_list; bigobj;) { if (need_remove_object_for_domain ((GCObject*)bigobj->data, domain)) { LOSObject *to_free = bigobj; if (prev) prev->next = bigobj->next; else - los_object_list = bigobj->next; + sgen_los_object_list = bigobj->next; bigobj = bigobj->next; SGEN_LOG (4, "Freeing large object %p", bigobj->data); sgen_los_free_object (to_free); @@ -871,8 +880,8 @@ mono_gc_clear_domain (MonoDomain * domain) prev = bigobj; bigobj = bigobj->next; } - major_collector.iterate_objects (ITERATE_OBJECTS_SWEEP_NON_PINNED, (IterateObjectCallbackFunc)clear_domain_free_major_non_pinned_object_callback, domain); - major_collector.iterate_objects (ITERATE_OBJECTS_SWEEP_PINNED, (IterateObjectCallbackFunc)clear_domain_free_major_pinned_object_callback, domain); + sgen_major_collector.iterate_objects (ITERATE_OBJECTS_SWEEP_NON_PINNED, (IterateObjectCallbackFunc)clear_domain_free_major_non_pinned_object_callback, domain); + sgen_major_collector.iterate_objects (ITERATE_OBJECTS_SWEEP_PINNED, (IterateObjectCallbackFunc)clear_domain_free_major_pinned_object_callback, domain); if (domain == mono_get_root_domain ()) { sgen_pin_stats_report (); @@ -881,8 +890,8 @@ mono_gc_clear_domain (MonoDomain * domain) sgen_restart_world (0, FALSE); - binary_protocol_domain_unload_end (domain); - binary_protocol_flush_buffers (FALSE); + sgen_binary_protocol_domain_unload_end (domain); + sgen_binary_protocol_flush_buffers (FALSE); UNLOCK_GC; } @@ -1007,15 +1016,16 @@ create_allocator (int atype, ManagedAllocatorVariant variant) else num_params = 2; + MonoType *int_type = m_class_get_byval_arg (mono_defaults.int_class); csig = mono_metadata_signature_alloc (mono_defaults.corlib, num_params); if (atype == ATYPE_STRING) { - csig->ret = &mono_defaults.string_class->byval_arg; - csig->params [0] = &mono_defaults.int_class->byval_arg; - csig->params [1] = &mono_defaults.int32_class->byval_arg; + csig->ret = m_class_get_byval_arg (mono_defaults.string_class); + csig->params [0] = int_type; + csig->params [1] = m_class_get_byval_arg (mono_defaults.int32_class); } else { - csig->ret = &mono_defaults.object_class->byval_arg; + csig->ret = m_class_get_byval_arg (mono_defaults.object_class); for (i = 0; i < num_params; i++) - csig->params [i] = &mono_defaults.int_class->byval_arg; + csig->params [i] = int_type; } mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_ALLOC); @@ -1051,17 +1061,17 @@ mono_gc_get_managed_allocator (MonoClass *klass, gboolean for_box, gboolean know ManagedAllocatorVariant variant = mono_profiler_allocations_enabled () ? MANAGED_ALLOCATOR_PROFILER : MANAGED_ALLOCATOR_REGULAR; - if (collect_before_allocs) + if (sgen_collect_before_allocs) return NULL; - if (klass->instance_size > tlab_size) + if (m_class_get_instance_size (klass) > sgen_tlab_size) return NULL; - if (known_instance_size && ALIGN_TO (klass->instance_size, SGEN_ALLOC_ALIGN) >= SGEN_MAX_SMALL_OBJ_SIZE) + if (known_instance_size && ALIGN_TO (m_class_get_instance_size (klass), SGEN_ALLOC_ALIGN) >= SGEN_MAX_SMALL_OBJ_SIZE) return NULL; - if (mono_class_has_finalizer (klass) || mono_class_is_marshalbyref (klass) || klass->has_weak_fields) + if (mono_class_has_finalizer (klass) || mono_class_is_marshalbyref (klass) || m_class_has_weak_fields (klass)) return NULL; - if (klass->rank) + if (m_class_get_rank (klass)) return NULL; - if (klass->byval_arg.type == MONO_TYPE_STRING) + if (m_class_get_byval_arg (klass)->type == MONO_TYPE_STRING) return mono_gc_get_managed_allocator_by_type (ATYPE_STRING, variant); /* Generic classes have dynamic field and can go above MAX_SMALL_OBJ_SIZE. */ if (known_instance_size) @@ -1077,9 +1087,9 @@ MonoMethod* mono_gc_get_managed_array_allocator (MonoClass *klass) { #ifdef MANAGED_ALLOCATION - if (klass->rank != 1) + if (m_class_get_rank (klass) != 1) return NULL; - if (has_per_allocation_action) + if (sgen_has_per_allocation_action) return NULL; g_assert (!mono_class_has_finalizer (klass) && !mono_class_is_marshalbyref (klass)); @@ -1184,15 +1194,11 @@ sgen_client_cardtable_scan_object (GCObject *obj, guint8 *cards, ScanCopyContext size_t card_count; size_t extra_idx = 0; - mword desc = (mword)klass->element_class->gc_descr; + mword desc = (mword)m_class_get_gc_descr (m_class_get_element_class (klass)); int elem_size = mono_array_element_size (klass); -#ifdef SGEN_HAVE_OVERLAPPING_CARDS - guint8 *overflow_scan_end = NULL; -#endif - #ifdef SGEN_OBJECT_LAYOUT_STATISTICS - if (klass->element_class->valuetype) + if (m_class_is_valuetype (m_class_get_element_class (klass))) sgen_object_layout_scanned_vtype_array (); else sgen_object_layout_scanned_ref_array (); @@ -1205,17 +1211,22 @@ sgen_client_cardtable_scan_object (GCObject *obj, guint8 *cards, ScanCopyContext card_base = card_data; card_count = sgen_card_table_number_of_cards_in_range ((mword)obj, obj_size); - card_data_end = card_data + card_count; - #ifdef SGEN_HAVE_OVERLAPPING_CARDS - /*Check for overflow and if so, setup to scan in two steps*/ +LOOP_HEAD: + card_data_end = card_base + card_count; + + /* + * Check for overflow and if so, scan only until the end of the shadow + * card table, leaving the rest for next iterations. + */ if (!cards && card_data_end >= SGEN_SHADOW_CARDTABLE_END) { - overflow_scan_end = sgen_shadow_cardtable + (card_data_end - SGEN_SHADOW_CARDTABLE_END); card_data_end = SGEN_SHADOW_CARDTABLE_END; } + card_count -= (card_data_end - card_base); -LOOP_HEAD: +#else + card_data_end = card_data + card_count; #endif card_data = sgen_find_next_card (card_data, card_data_end); @@ -1239,7 +1250,7 @@ LOOP_HEAD: index = ARRAY_OBJ_INDEX (start, obj, elem_size); elem = first_elem = (char*)mono_array_addr_with_size_fast ((MonoArray*)obj, elem_size, index); - if (klass->element_class->valuetype) { + if (m_class_is_valuetype (m_class_get_element_class (klass))) { ScanVTypeFunc scan_vtype_func = ctx.ops->scan_vtype; for (; elem < card_end; elem += elem_size) @@ -1252,15 +1263,14 @@ LOOP_HEAD: scan_ptr_field_func (obj, (GCObject**)elem, ctx.queue); } - binary_protocol_card_scan (first_elem, elem - first_elem); + sgen_binary_protocol_card_scan (first_elem, elem - first_elem); } #ifdef SGEN_HAVE_OVERLAPPING_CARDS - if (overflow_scan_end) { - extra_idx = card_data - card_base; + if (card_count > 0) { + SGEN_ASSERT (0, card_data == SGEN_SHADOW_CARDTABLE_END, "Why we didn't stop at shadow cardtable end ?"); + extra_idx += card_data - card_base; card_base = card_data = sgen_shadow_cardtable; - card_data_end = overflow_scan_end; - overflow_scan_end = NULL; goto LOOP_HEAD; } #endif @@ -1415,7 +1425,7 @@ mono_gc_set_string_length (MonoString *str, gint32 new_length) /* zero the discarded string. This null-delimits the string and allows * the space to be reclaimed by SGen. */ - if (nursery_canaries_enabled () && sgen_ptr_in_nursery (str)) { + if (sgen_nursery_canaries_enabled () && sgen_ptr_in_nursery (str)) { CHECK_CANARY_FOR_OBJECT ((GCObject*)str, TRUE); memset (new_end, 0, (str->length - new_length + 1) * sizeof (mono_unichar2) + CANARY_SIZE); memcpy (new_end + 1 , CANARY_STRING, CANARY_SIZE); @@ -1625,13 +1635,11 @@ static void report_stack_roots (void) { GCRootReport report = {0}; - FOREACH_THREAD (info) { + FOREACH_THREAD_EXCLUDE (info, MONO_THREAD_INFO_FLAGS_NO_GC) { 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) { @@ -1715,7 +1723,7 @@ report_registered_roots_by_type (int root_type) void **start_root; RootRecord *root; report.count = 0; - SGEN_HASH_TABLE_FOREACH (&roots_hash [root_type], void **, start_root, RootRecord *, root) { + SGEN_HASH_TABLE_FOREACH (&sgen_roots_hash [root_type], void **, start_root, RootRecord *, root) { 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); @@ -1966,9 +1974,9 @@ mono_gc_walk_heap (int flags, MonoGCReferences callback, void *data) hwi.data = data; sgen_clear_nursery_fragments (); - sgen_scan_area_with_callback (nursery_section->data, nursery_section->end_data, walk_references, &hwi, FALSE, TRUE); + sgen_scan_area_with_callback (sgen_nursery_section->data, sgen_nursery_section->end_data, walk_references, &hwi, FALSE, TRUE); - major_collector.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL, walk_references, &hwi); + sgen_major_collector.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL, walk_references, &hwi); sgen_los_iterate_objects (walk_references, &hwi); return 0; @@ -2001,7 +2009,7 @@ sgen_client_thread_attach (SgenThreadInfo* info) { mono_tls_set_sgen_thread_info (info); - info->client_info.skip = 0; + info->client_info.skip = FALSE; info->client_info.stack_start = NULL; @@ -2015,7 +2023,7 @@ sgen_client_thread_attach (SgenThreadInfo* info) if (mono_gc_get_gc_callbacks ()->thread_attach_func) info->client_info.runtime_data = mono_gc_get_gc_callbacks ()->thread_attach_func (); - binary_protocol_thread_register ((gpointer)mono_thread_info_get_tid (info)); + sgen_binary_protocol_thread_register ((gpointer)mono_thread_info_get_tid (info)); SGEN_LOG (3, "registered thread %p (%p) stack end %p", info, (gpointer)mono_thread_info_get_tid (info), info->client_info.info.stack_end); @@ -2044,7 +2052,7 @@ sgen_client_thread_detach_with_lock (SgenThreadInfo *p) p->client_info.runtime_data = NULL; } - binary_protocol_thread_unregister ((gpointer)tid); + sgen_binary_protocol_thread_unregister ((gpointer)tid); SGEN_LOG (3, "unregister thread %p (%p)", p, (gpointer)tid); HandleStack *handles = (HandleStack*) p->client_info.info.handle_stack; @@ -2053,23 +2061,32 @@ sgen_client_thread_detach_with_lock (SgenThreadInfo *p) } void -mono_gc_set_skip_thread (gboolean skip) +mono_gc_skip_thread_changing (gboolean skip) { - SgenThreadInfo *info = mono_thread_info_current (); - + /* + * SGen's STW will respect the thread info flags, but we do need to take + * the GC lock when changing them. If we don't do this, SGen might end up + * trying to resume a thread that wasn't suspended because it had + * MONO_THREAD_INFO_FLAGS_NO_GC set when STW began. + */ LOCK_GC; - info->client_info.gc_disabled = skip; - UNLOCK_GC; if (skip) { - /* If we skip scanning a thread with a non-empty handle stack, we may move an + /* + * If we skip scanning a thread with a non-empty handle stack, we may move an * object but fail to update the reference in the handle. */ - HandleStack *stack = info->client_info.info.handle_stack; + HandleStack *stack = mono_thread_info_current ()->client_info.info.handle_stack; g_assert (stack == NULL || mono_handle_stack_is_empty (stack)); } } +void +mono_gc_skip_thread_changed (gboolean skip) +{ + UNLOCK_GC; +} + gboolean mono_gc_thread_in_critical_region (SgenThreadInfo *info) { @@ -2142,16 +2159,13 @@ sgen_client_scan_thread_data (void *start_nursery, void *end_nursery, gboolean p return; #endif - FOREACH_THREAD (info) { + FOREACH_THREAD_EXCLUDE (info, MONO_THREAD_INFO_FLAGS_NO_GC) { int skip_reason = 0; void *aligned_stack_start; if (info->client_info.skip) { SGEN_LOG (3, "Skipping dead thread %p, range: %p-%p, size: %zd", info, info->client_info.stack_start, info->client_info.info.stack_end, (char*)info->client_info.info.stack_end - (char*)info->client_info.stack_start); skip_reason = 1; - } else if (info->client_info.gc_disabled) { - SGEN_LOG (3, "GC disabled for thread %p, range: %p-%p, size: %zd", info, info->client_info.stack_start, info->client_info.info.stack_end, (char*)info->client_info.info.stack_end - (char*)info->client_info.stack_start); - skip_reason = 2; } else if (!mono_thread_info_is_live (info)) { SGEN_LOG (3, "Skipping non-running thread %p, range: %p-%p, size: %zd (state %x)", info, info->client_info.stack_start, info->client_info.info.stack_end, (char*)info->client_info.info.stack_end - (char*)info->client_info.stack_start, info->client_info.info.thread_state); skip_reason = 3; @@ -2160,7 +2174,7 @@ sgen_client_scan_thread_data (void *start_nursery, void *end_nursery, gboolean p skip_reason = 4; } - binary_protocol_scan_stack ((gpointer)mono_thread_info_get_tid (info), info->client_info.stack_start, info->client_info.info.stack_end, skip_reason); + sgen_binary_protocol_scan_stack ((gpointer)mono_thread_info_get_tid (info), info->client_info.stack_start, info->client_info.info.stack_end, skip_reason); if (skip_reason) { if (precise) { @@ -2639,7 +2653,7 @@ sgen_client_ensure_weak_gchandles_accessible (void) /* FIXME: A GC can occur after this check fails, in which case we * should wait for bridge processing but would fail to do so. */ - if (G_UNLIKELY (bridge_processing_in_progress)) + if (G_UNLIKELY (mono_bridge_processing_in_progress)) mono_gc_wait_for_bridge_processing (); } @@ -2688,15 +2702,19 @@ sgen_client_degraded_allocation (void) static gint32 last_major_gc_warned = -1; static gint32 num_degraded = 0; - gint32 major_gc_count = mono_atomic_load_i32 (&gc_stats.major_gc_count); + gint32 major_gc_count = mono_atomic_load_i32 (&mono_gc_stats.major_gc_count); + //The WASM target aways triggers degrated allocation before collecting. So no point in printing the warning as it will just confuse users +#if !defined (TARGET_WASM) if (mono_atomic_load_i32 (&last_major_gc_warned) < major_gc_count) { gint32 num = mono_atomic_inc_i32 (&num_degraded); if (num == 1 || num == 3) mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_GC, "Warning: Degraded allocation. Consider increasing nursery-size if the warning persists."); else if (num == 10) mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_GC, "Warning: Repeated degraded allocation. Consider increasing nursery-size."); + mono_atomic_store_i32 (&last_major_gc_warned, major_gc_count); } +#endif } /* @@ -2726,19 +2744,19 @@ sgen_client_pre_collection_checks (void) gboolean sgen_client_vtable_is_inited (MonoVTable *vt) { - return vt->klass->inited; + return m_class_is_inited (vt->klass); } const char* sgen_client_vtable_get_namespace (MonoVTable *vt) { - return vt->klass->name_space; + return m_class_get_name_space (vt->klass); } const char* sgen_client_vtable_get_name (MonoVTable *vt) { - return vt->klass->name; + return m_class_get_name (vt->klass); } /* @@ -2807,7 +2825,7 @@ sgen_client_handle_gc_debug (const char *opt) mono_do_not_finalize = TRUE; mono_do_not_finalize_class_names = g_strsplit (opt, ",", 0); } else if (!strcmp (opt, "log-finalizers")) { - log_finalizers = TRUE; + mono_log_finalizers = TRUE; } else if (!strcmp (opt, "no-managed-allocator")) { sgen_set_use_managed_allocator (FALSE); } else if (!sgen_bridge_handle_gc_debug (opt)) { @@ -2885,6 +2903,15 @@ mono_gc_base_init (void) void mono_gc_base_cleanup (void) { + /* + * Note we don't fully cleanup the GC here, but the threads mainly. + * + * We need to finish any work on the sgen threads before shutting down + * the sgen threadpool. After this point we can still trigger GCs as + * part of domain free, but they should all be forced and not use the + * threadpool. + */ + sgen_finish_concurrent_work ("cleanup", TRUE); sgen_thread_pool_shutdown (); // We should have consumed any outstanding moves. @@ -2913,7 +2940,7 @@ 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)); - MONO_PROFILER_RAISE (gc_event2, (MONO_GC_EVENT_START, generation, generation == GENERATION_OLD && concurrent_collection_in_progress)); + MONO_PROFILER_RAISE (gc_event2, (MONO_GC_EVENT_START, generation, generation == GENERATION_OLD && sgen_concurrent_collection_in_progress)); if (!pseudo_roots_registered) { pseudo_roots_registered = TRUE; @@ -2936,7 +2963,7 @@ sgen_client_binary_protocol_collection_end (int minor_gc_count, int generation, MONO_GC_END (generation); MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_END, generation)); - MONO_PROFILER_RAISE (gc_event2, (MONO_GC_EVENT_END, generation, generation == GENERATION_OLD && concurrent_collection_in_progress)); + MONO_PROFILER_RAISE (gc_event2, (MONO_GC_EVENT_END, generation, generation == GENERATION_OLD && sgen_concurrent_collection_in_progress)); } #ifdef HOST_WASM diff --git a/mono/metadata/sgen-new-bridge.c b/mono/metadata/sgen-new-bridge.c index 21a90e8b78..321c4a6ed6 100644 --- a/mono/metadata/sgen-new-bridge.c +++ b/mono/metadata/sgen-new-bridge.c @@ -12,7 +12,7 @@ #include "config.h" -#ifdef HAVE_SGEN_GC +#if defined (HAVE_SGEN_GC) && !defined (DISABLE_SGEN_GC_BRIDGE) #include #include @@ -179,26 +179,26 @@ set_config (const SgenBridgeProcessorConfig *config) static MonoGCBridgeObjectKind class_kind (MonoClass *klass) { - MonoGCBridgeObjectKind res = bridge_callbacks.bridge_class_kind (klass); + MonoGCBridgeObjectKind res = mono_bridge_callbacks.bridge_class_kind (klass); /* If it's a bridge, nothing we can do about it. */ if (res == GC_BRIDGE_TRANSPARENT_BRIDGE_CLASS || res == GC_BRIDGE_OPAQUE_BRIDGE_CLASS) return res; /* Non bridge classes with no pointers will never point to a bridge, so we can savely ignore them. */ - if (!klass->has_references) { - SGEN_LOG (6, "class %s is opaque\n", klass->name); + if (!m_class_has_references (klass)) { + SGEN_LOG (6, "class %s is opaque\n", m_class_get_name (klass)); return GC_BRIDGE_OPAQUE_CLASS; } /* Some arrays can be ignored */ - if (klass->rank == 1) { - MonoClass *elem_class = klass->element_class; + if (m_class_get_rank (klass) == 1) { + MonoClass *elem_class = m_class_get_element_class (klass); /* FIXME the bridge check can be quite expensive, cache it at the class level. */ /* An array of a sealed type that is not a bridge will never get to a bridge */ - if ((mono_class_get_flags (elem_class) & TYPE_ATTRIBUTE_SEALED) && !elem_class->has_references && !bridge_callbacks.bridge_class_kind (elem_class)) { - SGEN_LOG (6, "class %s is opaque\n", klass->name); + if ((mono_class_get_flags (elem_class) & TYPE_ATTRIBUTE_SEALED) && !m_class_has_references (elem_class) && !mono_bridge_callbacks.bridge_class_kind (elem_class)) { + SGEN_LOG (6, "class %s is opaque\n", m_class_get_name (klass)); return GC_BRIDGE_OPAQUE_CLASS; } } @@ -281,7 +281,7 @@ static gboolean is_opaque_object (MonoObject *obj) { if ((obj->vtable->gc_bits & SGEN_GC_BIT_BRIDGE_OPAQUE_OBJECT) == SGEN_GC_BIT_BRIDGE_OPAQUE_OBJECT) { - SGEN_LOG (6, "ignoring %s\n", obj->vtable->klass->name); + SGEN_LOG (6, "ignoring %s\n", m_class_get_name (mono_object_class (obj))); ++ignored_objects; return TRUE; } @@ -644,7 +644,7 @@ dump_graph (void) SGEN_HASH_TABLE_FOREACH (&hash_table, MonoObject *, obj, HashEntry *, entry) { MonoVTable *vt = SGEN_LOAD_VTABLE (obj); fprintf (file, "\n", - obj, vt->klass->name_space, vt->klass->name, entry->is_bridge ? "true" : "false"); + obj, m_class_get_name_space (vt->klass), m_class_get_name (vt->klass), entry->is_bridge ? "true" : "false"); } SGEN_HASH_TABLE_FOREACH_END; fprintf (file, "\n"); @@ -764,7 +764,7 @@ processing_build_callback_data (int generation) if (!dyn_array_ptr_size (®istered_bridges)) return; - g_assert (bridge_processing_in_progress); + g_assert (mono_bridge_processing_in_progress); SGEN_TV_GETTIME (atv); @@ -906,7 +906,7 @@ processing_build_callback_data (int generation) if (entry->entry.is_bridge) { MonoObject *obj = sgen_hash_table_key_for_value_pointer (entry); MonoClass *klass = SGEN_LOAD_VTABLE (obj)->klass; - mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_GC, "OBJECT %s::%s (%p) weight %f", klass->name_space, klass->name, obj, entry->weight); + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_GC, "OBJECT %s::%s (%p) weight %f", m_class_get_name_space (klass), m_class_get_name (klass), obj, entry->weight); } } } diff --git a/mono/metadata/sgen-old-bridge.c b/mono/metadata/sgen-old-bridge.c index 12f82b07f7..fdad9102c2 100644 --- a/mono/metadata/sgen-old-bridge.c +++ b/mono/metadata/sgen-old-bridge.c @@ -11,7 +11,7 @@ #include "config.h" -#ifdef HAVE_SGEN_GC +#if defined (HAVE_SGEN_GC) && !defined (DISABLE_SGEN_GC_BRIDGE) #include @@ -385,7 +385,7 @@ set_config (const SgenBridgeProcessorConfig *config) static MonoGCBridgeObjectKind class_kind (MonoClass *klass) { - return bridge_callbacks.bridge_class_kind (klass); + return mono_bridge_callbacks.bridge_class_kind (klass); } static HashEntry* @@ -677,7 +677,7 @@ processing_build_callback_data (int generation) if (!dyn_array_ptr_size (®istered_bridges)) return; - g_assert (bridge_processing_in_progress); + g_assert (mono_bridge_processing_in_progress); SGEN_TV_GETTIME (atv); @@ -749,7 +749,7 @@ processing_build_callback_data (int generation) HashEntryWithAccounting *entry = (HashEntryWithAccounting*)all_entries [i]; if (entry->entry.is_bridge) { MonoClass *klass = SGEN_LOAD_VTABLE (entry->entry.obj)->klass; - mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_GC, "OBJECT %s::%s (%p) weight %f", klass->name_space, klass->name, entry->entry.obj, entry->weight); + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_GC, "OBJECT %s::%s (%p) weight %f", m_class_get_name_space (klass), m_class_get_name (klass), entry->entry.obj, entry->weight); } } } diff --git a/mono/metadata/sgen-stw.c b/mono/metadata/sgen-stw.c index 14eedd7496..3bd49b25ed 100644 --- a/mono/metadata/sgen-stw.c +++ b/mono/metadata/sgen-stw.c @@ -157,7 +157,7 @@ sgen_client_restart_world (int generation, gboolean serial_collection, gint64 *s MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_PRE_START_WORLD, generation)); MONO_PROFILER_RAISE (gc_event2, (MONO_GC_EVENT_PRE_START_WORLD, generation, serial_collection)); - FOREACH_THREAD (info) { + FOREACH_THREAD_ALL (info) { info->client_info.stack_start = NULL; memset (&info->client_info.ctx, 0, sizeof (MonoContext)); } FOREACH_THREAD_END @@ -208,15 +208,9 @@ static gboolean sgen_is_thread_in_current_stw (SgenThreadInfo *info, int *reason) { /* - A thread explicitly asked to be skiped because it holds no managed state. - This is used by TP and finalizer threads. - FIXME Use an atomic variable for this to avoid everyone taking the GC LOCK. - */ - if (info->client_info.gc_disabled) { - if (reason) - *reason = 1; - return FALSE; - } + * No need to check MONO_THREAD_INFO_FLAGS_NO_GC here as we rely on the + * FOREACH_THREAD_EXCLUDE macro to skip such threads for us. + */ /* We have detected that this thread is failing/dying, ignore it. @@ -268,7 +262,7 @@ sgen_unified_suspend_stop_world (void) mono_threads_begin_global_suspend (); THREADS_STW_DEBUG ("[GC-STW-BEGIN][%p] *** BEGIN SUSPEND *** \n", mono_thread_info_get_tid (mono_thread_info_current ())); - FOREACH_THREAD (info) { + FOREACH_THREAD_EXCLUDE (info, MONO_THREAD_INFO_FLAGS_NO_GC) { info->client_info.skip = FALSE; info->client_info.suspend_done = FALSE; @@ -289,7 +283,7 @@ sgen_unified_suspend_stop_world (void) for (;;) { gint restart_counter = 0; - FOREACH_THREAD (info) { + FOREACH_THREAD_EXCLUDE (info, MONO_THREAD_INFO_FLAGS_NO_GC) { gint suspend_count; int reason = 0; @@ -335,7 +329,7 @@ sgen_unified_suspend_stop_world (void) sleep_duration += 10; } - FOREACH_THREAD (info) { + FOREACH_THREAD_EXCLUDE (info, MONO_THREAD_INFO_FLAGS_NO_GC) { int reason = 0; if (info->client_info.suspend_done || !sgen_is_thread_in_current_stw (info, &reason)) { THREADS_STW_DEBUG ("[GC-STW-RESTART] IGNORE SUSPEND thread %p not been processed done %d current %d reason %d\n", mono_thread_info_get_tid (info), info->client_info.suspend_done, !sgen_is_thread_in_current_stw (info, NULL), reason); @@ -355,7 +349,7 @@ sgen_unified_suspend_stop_world (void) mono_threads_wait_pending_operations (); } - FOREACH_THREAD (info) { + FOREACH_THREAD_EXCLUDE (info, MONO_THREAD_INFO_FLAGS_NO_GC) { gpointer stopped_ip; int reason = 0; @@ -385,7 +379,7 @@ sgen_unified_suspend_stop_world (void) stopped_ip = (gpointer) (MONO_CONTEXT_GET_IP (&info->client_info.ctx)); - binary_protocol_thread_suspend ((gpointer) mono_thread_info_get_tid (info), stopped_ip); + sgen_binary_protocol_thread_suspend ((gpointer) mono_thread_info_get_tid (info), stopped_ip); THREADS_STW_DEBUG ("[GC-STW-SUSPEND-END] thread %p is suspended, stopped_ip = %p, stack = %p -> %p\n", mono_thread_info_get_tid (info), stopped_ip, info->client_info.stack_start, info->client_info.stack_start ? info->client_info.info.stack_end : NULL); @@ -396,13 +390,13 @@ static void sgen_unified_suspend_restart_world (void) { THREADS_STW_DEBUG ("[GC-STW-END] *** BEGIN RESUME ***\n"); - FOREACH_THREAD (info) { + FOREACH_THREAD_EXCLUDE (info, MONO_THREAD_INFO_FLAGS_NO_GC) { int reason = 0; if (sgen_is_thread_in_current_stw (info, &reason)) { g_assert (mono_thread_info_begin_resume (info)); THREADS_STW_DEBUG ("[GC-STW-RESUME-WORLD] RESUME thread %p\n", mono_thread_info_get_tid (info)); - binary_protocol_thread_restart ((gpointer) mono_thread_info_get_tid (info)); + sgen_binary_protocol_thread_restart ((gpointer) mono_thread_info_get_tid (info)); } else { THREADS_STW_DEBUG ("[GC-STW-RESUME-WORLD] IGNORE thread %p, reason %d\n", mono_thread_info_get_tid (info), reason); } diff --git a/mono/metadata/sgen-tarjan-bridge.c b/mono/metadata/sgen-tarjan-bridge.c index 77ea9f8a70..6cf7ce50b1 100644 --- a/mono/metadata/sgen-tarjan-bridge.c +++ b/mono/metadata/sgen-tarjan-bridge.c @@ -14,7 +14,7 @@ #include "config.h" -#ifdef HAVE_SGEN_GC +#if defined (HAVE_SGEN_GC) && !defined (DISABLE_SGEN_GC_BRIDGE) #include @@ -45,26 +45,26 @@ static MonoGCBridgeObjectKind class_kind (MonoClass *klass) { - MonoGCBridgeObjectKind res = bridge_callbacks.bridge_class_kind (klass); + MonoGCBridgeObjectKind res = mono_bridge_callbacks.bridge_class_kind (klass); /* If it's a bridge, nothing we can do about it. */ if (res == GC_BRIDGE_TRANSPARENT_BRIDGE_CLASS || res == GC_BRIDGE_OPAQUE_BRIDGE_CLASS) return res; /* Non bridge classes with no pointers will never point to a bridge, so we can savely ignore them. */ - if (!klass->has_references) { - SGEN_LOG (6, "class %s is opaque\n", klass->name); + if (!m_class_has_references (klass)) { + SGEN_LOG (6, "class %s is opaque\n", m_class_get_name (klass)); return GC_BRIDGE_OPAQUE_CLASS; } /* Some arrays can be ignored */ - if (klass->rank == 1) { - MonoClass *elem_class = klass->element_class; + if (m_class_get_rank (klass) == 1) { + MonoClass *elem_class = m_class_get_element_class (klass); /* FIXME the bridge check can be quite expensive, cache it at the class level. */ /* An array of a sealed type that is not a bridge will never get to a bridge */ - if ((mono_class_get_flags (elem_class) & TYPE_ATTRIBUTE_SEALED) && !elem_class->has_references && !bridge_callbacks.bridge_class_kind (elem_class)) { - SGEN_LOG (6, "class %s is opaque\n", klass->name); + if ((mono_class_get_flags (elem_class) & TYPE_ATTRIBUTE_SEALED) && !m_class_has_references (elem_class) && !mono_bridge_callbacks.bridge_class_kind (elem_class)) { + SGEN_LOG (6, "class %s is opaque\n", m_class_get_name (klass)); return GC_BRIDGE_OPAQUE_CLASS; } } @@ -596,7 +596,7 @@ is_opaque_object (GCObject *obj) { MonoVTable *vt = SGEN_LOAD_VTABLE (obj); if ((vt->gc_bits & SGEN_GC_BIT_BRIDGE_OPAQUE_OBJECT) == SGEN_GC_BIT_BRIDGE_OPAQUE_OBJECT) { - SGEN_LOG (6, "ignoring %s\n", vt->klass->name); + SGEN_LOG (6, "ignoring %s\n", m_class_get_name (vt->klass)); ++ignored_objects; return TRUE; } diff --git a/mono/metadata/sre-encode.c b/mono/metadata/sre-encode.c index f4afc9c752..151b43ff06 100644 --- a/mono/metadata/sre-encode.c +++ b/mono/metadata/sre-encode.c @@ -140,8 +140,8 @@ encode_generic_class (MonoDynamicImage *assembly, MonoGenericClass *gclass, SigB sigbuffer_add_value (buf, MONO_TYPE_GENERICINST); klass = gclass->container_class; - sigbuffer_add_value (buf, klass->byval_arg.type); - sigbuffer_add_value (buf, mono_dynimage_encode_typedef_or_ref_full (assembly, &klass->byval_arg, FALSE)); + sigbuffer_add_value (buf, m_class_get_byval_arg (klass)->type); + sigbuffer_add_value (buf, mono_dynimage_encode_typedef_or_ref_full (assembly, m_class_get_byval_arg (klass), FALSE)); sigbuffer_add_value (buf, class_inst->type_argc); for (i = 0; i < class_inst->type_argc; ++i) @@ -189,7 +189,7 @@ encode_type (MonoDynamicImage *assembly, MonoType *type, SigBuffer *buf) break; case MONO_TYPE_SZARRAY: sigbuffer_add_value (buf, type->type); - encode_type (assembly, &type->data.klass->byval_arg, buf); + encode_type (assembly, m_class_get_byval_arg (type->data.klass), buf); break; case MONO_TYPE_VALUETYPE: case MONO_TYPE_CLASS: { @@ -202,19 +202,19 @@ encode_type (MonoDynamicImage *assembly, MonoType *type, SigBuffer *buf) /* * Make sure we use the correct type. */ - sigbuffer_add_value (buf, k->byval_arg.type); + sigbuffer_add_value (buf, m_class_get_byval_arg (k)->type); /* * ensure only non-byref gets passed to mono_image_typedef_or_ref(), * otherwise two typerefs could point to the same type, leading to * verification errors. */ - sigbuffer_add_value (buf, mono_image_typedef_or_ref (assembly, &k->byval_arg)); + sigbuffer_add_value (buf, mono_image_typedef_or_ref (assembly, m_class_get_byval_arg (k))); } break; } case MONO_TYPE_ARRAY: sigbuffer_add_value (buf, type->type); - encode_type (assembly, &type->data.array->eklass->byval_arg, buf); + encode_type (assembly, m_class_get_byval_arg (type->data.array->eklass), buf); sigbuffer_add_value (buf, type->data.array->rank); sigbuffer_add_value (buf, 0); /* FIXME: set to 0 for now */ sigbuffer_add_value (buf, 0); @@ -530,7 +530,7 @@ mono_dynimage_encode_constant (MonoDynamicImage *assembly, MonoObject *val, Mono box_val = (char*)&dummy; } else { box_val = ((char*)val) + sizeof (MonoObject); - *ret_type = val->vtable->klass->byval_arg.type; + *ret_type = m_class_get_byval_arg (val->vtable->klass)->type; } handle_enum: switch (*ret_type) { @@ -559,10 +559,10 @@ handle_enum: case MONO_TYPE_VALUETYPE: { MonoClass *klass = val->vtable->klass; - if (klass->enumtype) { + if (m_class_is_enumtype (klass)) { *ret_type = mono_class_enum_basetype (klass)->type; goto handle_enum; - } else if (mono_is_corlib_image (klass->image) && strcmp (klass->name_space, "System") == 0 && strcmp (klass->name, "DateTime") == 0) { + } else if (mono_is_corlib_image (m_class_get_image (klass)) && strcmp (m_class_get_name_space (klass), "System") == 0 && strcmp (m_class_get_name (klass), "DateTime") == 0) { len = 8; } else g_error ("we can't encode valuetypes, we should have never reached this line"); @@ -592,7 +592,7 @@ handle_enum: return idx; } case MONO_TYPE_GENERICINST: - *ret_type = mono_class_get_generic_class (val->vtable->klass)->container_class->byval_arg.type; + *ret_type = m_class_get_byval_arg (mono_class_get_generic_class (val->vtable->klass)->container_class)->type; goto handle_enum; default: g_error ("we don't encode constant type 0x%02x yet", *ret_type); @@ -678,7 +678,7 @@ mono_dynimage_encode_fieldref_signature (MonoDynamicImage *assembly, MonoImage * MonoClass *klass = mono_class_get_checked (field_image, type->modifiers [i].token, error); g_assert (mono_error_ok (error)); /* FIXME don't swallow the error */ - token = mono_image_typedef_or_ref (assembly, &klass->byval_arg); + token = mono_image_typedef_or_ref (assembly, m_class_get_byval_arg (klass)); } else { token = type->modifiers [i].token; } @@ -782,7 +782,7 @@ mono_dynimage_encode_typedef_or_ref_full (MonoDynamicImage *assembly, MonoType * /* * If it's in the same module and not a generic type parameter: */ - if ((klass->image == &assembly->image) && (type->type != MONO_TYPE_VAR) && + if ((m_class_get_image (klass) == &assembly->image) && (type->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR)) { token = MONO_TYPEDEFORREF_TYPEDEF | (MONO_HANDLE_GETVAL (tb, table_idx) << MONO_TYPEDEFORREF_BITS); /* This function is called multiple times from sre and sre-save, so same object is okay */ @@ -790,21 +790,21 @@ mono_dynimage_encode_typedef_or_ref_full (MonoDynamicImage *assembly, MonoType * goto leave; } - if (klass->nested_in) { - enclosing = mono_dynimage_encode_typedef_or_ref_full (assembly, &klass->nested_in->byval_arg, FALSE); + if (m_class_get_nested_in (klass)) { + enclosing = mono_dynimage_encode_typedef_or_ref_full (assembly, m_class_get_byval_arg (m_class_get_nested_in (klass)), FALSE); /* get the typeref idx of the enclosing type */ enclosing >>= MONO_TYPEDEFORREF_BITS; scope = (enclosing << MONO_RESOLUTION_SCOPE_BITS) | MONO_RESOLUTION_SCOPE_TYPEREF; } else { - scope = mono_reflection_resolution_scope_from_image (assembly, klass->image); + scope = mono_reflection_resolution_scope_from_image (assembly, m_class_get_image (klass)); } table = &assembly->tables [MONO_TABLE_TYPEREF]; if (assembly->save) { alloc_table (table, table->rows + 1); values = table->values + table->next_idx * MONO_TYPEREF_SIZE; values [MONO_TYPEREF_SCOPE] = scope; - values [MONO_TYPEREF_NAME] = mono_dynstream_insert_string (&assembly->sheap, klass->name); - values [MONO_TYPEREF_NAMESPACE] = mono_dynstream_insert_string (&assembly->sheap, klass->name_space); + values [MONO_TYPEREF_NAME] = mono_dynstream_insert_string (&assembly->sheap, m_class_get_name (klass)); + values [MONO_TYPEREF_NAMESPACE] = mono_dynstream_insert_string (&assembly->sheap, m_class_get_name_space (klass)); } token = MONO_TYPEDEFORREF_TYPEREF | (table->next_idx << MONO_TYPEDEFORREF_BITS); /* typeref */ g_hash_table_insert (assembly->typeref, type, GUINT_TO_POINTER(token)); diff --git a/mono/metadata/sre-save.c.REMOVED.git-id b/mono/metadata/sre-save.c.REMOVED.git-id index 0b7d6b445a..049e2afab3 100644 --- a/mono/metadata/sre-save.c.REMOVED.git-id +++ b/mono/metadata/sre-save.c.REMOVED.git-id @@ -1 +1 @@ -9aea70328b683631954aba3c0a997f6b5f267d00 \ No newline at end of file +fea48cf8c7bc5fa4f359239c84d890797a2e36cb \ No newline at end of file diff --git a/mono/metadata/sre.c.REMOVED.git-id b/mono/metadata/sre.c.REMOVED.git-id index 41d691b83f..1a10f82a8a 100644 --- a/mono/metadata/sre.c.REMOVED.git-id +++ b/mono/metadata/sre.c.REMOVED.git-id @@ -1 +1 @@ -1b2eaa34de14e975711936cb42c318551e3ab9f1 \ No newline at end of file +6bd114c78bf80380e514efbb2dbf6ab56612459d \ No newline at end of file diff --git a/mono/metadata/threadpool-io-epoll.c b/mono/metadata/threadpool-io-epoll.c index 67d555707a..40efee6b42 100644 --- a/mono/metadata/threadpool-io-epoll.c +++ b/mono/metadata/threadpool-io-epoll.c @@ -85,13 +85,13 @@ epoll_event_wait (void (*callback) (gint fd, gint events, gpointer user_data), g memset (epoll_events, 0, sizeof (struct epoll_event) * EPOLL_NEVENTS); - mono_gc_set_skip_thread (TRUE); + mono_thread_info_set_flags (MONO_THREAD_INFO_FLAGS_NO_GC); MONO_ENTER_GC_SAFE; ready = epoll_wait (epoll_fd, epoll_events, EPOLL_NEVENTS, -1); MONO_EXIT_GC_SAFE; - mono_gc_set_skip_thread (FALSE); + mono_thread_info_set_flags (MONO_THREAD_INFO_FLAGS_NONE); if (ready == -1) { switch (errno) { diff --git a/mono/metadata/threadpool-io-kqueue.c b/mono/metadata/threadpool-io-kqueue.c index 657fad7e35..89d46ae405 100644 --- a/mono/metadata/threadpool-io-kqueue.c +++ b/mono/metadata/threadpool-io-kqueue.c @@ -82,13 +82,13 @@ kqueue_event_wait (void (*callback) (gint fd, gint events, gpointer user_data), memset (kqueue_events, 0, sizeof (struct kevent) * KQUEUE_NEVENTS); - mono_gc_set_skip_thread (TRUE); + mono_thread_info_set_flags (MONO_THREAD_INFO_FLAGS_NO_GC); MONO_ENTER_GC_SAFE; ready = kevent (kqueue_fd, NULL, 0, kqueue_events, KQUEUE_NEVENTS, NULL); MONO_EXIT_GC_SAFE; - mono_gc_set_skip_thread (FALSE); + mono_thread_info_set_flags (MONO_THREAD_INFO_FLAGS_NONE); if (ready == -1) { switch (errno) { diff --git a/mono/metadata/threadpool-io-poll.c b/mono/metadata/threadpool-io-poll.c index 8ff6b13c69..e086835577 100644 --- a/mono/metadata/threadpool-io-poll.c +++ b/mono/metadata/threadpool-io-poll.c @@ -140,13 +140,13 @@ poll_event_wait (void (*callback) (gint fd, gint events, gpointer user_data), gp for (i = 0; i < poll_fds_size; ++i) poll_fds [i].revents = 0; - mono_gc_set_skip_thread (TRUE); + mono_thread_info_set_flags (MONO_THREAD_INFO_FLAGS_NO_GC); MONO_ENTER_GC_SAFE; ready = mono_poll (poll_fds, poll_fds_size, -1); MONO_EXIT_GC_SAFE; - mono_gc_set_skip_thread (FALSE); + mono_thread_info_set_flags (MONO_THREAD_INFO_FLAGS_NONE); if (ready == -1) { /* diff --git a/mono/metadata/threadpool.c b/mono/metadata/threadpool.c index acf07d6765..2f7be0c7d2 100644 --- a/mono/metadata/threadpool.c +++ b/mono/metadata/threadpool.c @@ -608,7 +608,7 @@ mono_threadpool_resume (void) } void -ves_icall_System_Threading_ThreadPool_GetAvailableThreadsNative (gint32 *worker_threads, gint32 *completion_port_threads) +ves_icall_System_Threading_ThreadPool_GetAvailableThreadsNative (gint32 *worker_threads, gint32 *completion_port_threads, MonoError *error) { ThreadPoolCounter counter; @@ -630,7 +630,7 @@ ves_icall_System_Threading_ThreadPool_GetAvailableThreadsNative (gint32 *worker_ } void -ves_icall_System_Threading_ThreadPool_GetMinThreadsNative (gint32 *worker_threads, gint32 *completion_port_threads) +ves_icall_System_Threading_ThreadPool_GetMinThreadsNative (gint32 *worker_threads, gint32 *completion_port_threads, MonoError *error) { if (!worker_threads || !completion_port_threads) return; @@ -648,7 +648,7 @@ ves_icall_System_Threading_ThreadPool_GetMinThreadsNative (gint32 *worker_thread } void -ves_icall_System_Threading_ThreadPool_GetMaxThreadsNative (gint32 *worker_threads, gint32 *completion_port_threads) +ves_icall_System_Threading_ThreadPool_GetMaxThreadsNative (gint32 *worker_threads, gint32 *completion_port_threads, MonoError *error) { if (!worker_threads || !completion_port_threads) return; @@ -666,7 +666,7 @@ ves_icall_System_Threading_ThreadPool_GetMaxThreadsNative (gint32 *worker_thread } MonoBoolean -ves_icall_System_Threading_ThreadPool_SetMinThreadsNative (gint32 worker_threads, gint32 completion_port_threads) +ves_icall_System_Threading_ThreadPool_SetMinThreadsNative (gint32 worker_threads, gint32 completion_port_threads, MonoError *error) { if (completion_port_threads <= 0 || completion_port_threads > threadpool.limit_io_max) return FALSE; @@ -686,7 +686,7 @@ ves_icall_System_Threading_ThreadPool_SetMinThreadsNative (gint32 worker_threads } MonoBoolean -ves_icall_System_Threading_ThreadPool_SetMaxThreadsNative (gint32 worker_threads, gint32 completion_port_threads) +ves_icall_System_Threading_ThreadPool_SetMaxThreadsNative (gint32 worker_threads, gint32 completion_port_threads, MonoError *error) { worker_threads = MIN (worker_threads, MAX_POSSIBLE_THREADS); completion_port_threads = MIN (completion_port_threads, MAX_POSSIBLE_THREADS); @@ -711,7 +711,7 @@ ves_icall_System_Threading_ThreadPool_SetMaxThreadsNative (gint32 worker_threads } void -ves_icall_System_Threading_ThreadPool_InitializeVMTp (MonoBoolean *enable_worker_tracking) +ves_icall_System_Threading_ThreadPool_InitializeVMTp (MonoBoolean *enable_worker_tracking, MonoError *error) { if (enable_worker_tracking) { // TODO implement some kind of switch to have the possibily to use it @@ -722,7 +722,7 @@ ves_icall_System_Threading_ThreadPool_InitializeVMTp (MonoBoolean *enable_worker } MonoBoolean -ves_icall_System_Threading_ThreadPool_NotifyWorkItemComplete (void) +ves_icall_System_Threading_ThreadPool_NotifyWorkItemComplete (MonoError *error) { if (mono_domain_is_unloading (mono_domain_get ()) || mono_runtime_is_shutting_down ()) return FALSE; @@ -731,13 +731,14 @@ ves_icall_System_Threading_ThreadPool_NotifyWorkItemComplete (void) } void -ves_icall_System_Threading_ThreadPool_NotifyWorkItemProgressNative (void) +ves_icall_System_Threading_ThreadPool_NotifyWorkItemProgressNative (MonoError *error) { mono_threadpool_worker_notify_completed (); } void -ves_icall_System_Threading_ThreadPool_NotifyWorkItemQueued (void) +ves_icall_System_Threading_ThreadPool_NotifyWorkItemQueued (MonoError *error) +// FIXME Move to managed. { #ifndef DISABLE_PERFCOUNTERS mono_atomic_inc_i64 (&mono_perfcounters->threadpool_workitems); @@ -745,16 +746,14 @@ ves_icall_System_Threading_ThreadPool_NotifyWorkItemQueued (void) } void -ves_icall_System_Threading_ThreadPool_ReportThreadStatus (MonoBoolean is_working) +ves_icall_System_Threading_ThreadPool_ReportThreadStatus (MonoBoolean is_working, MonoError *error) { // TODO - ERROR_DECL (error); mono_error_set_not_implemented (error, ""); - mono_error_set_pending_exception (error); } MonoBoolean -ves_icall_System_Threading_ThreadPool_RequestWorkerThread (void) +ves_icall_System_Threading_ThreadPool_RequestWorkerThread (MonoError *error) { MonoDomain *domain; ThreadPoolDomain *tpdomain; @@ -806,24 +805,22 @@ ves_icall_System_Threading_ThreadPool_RequestWorkerThread (void) } MonoBoolean G_GNUC_UNUSED -ves_icall_System_Threading_ThreadPool_PostQueuedCompletionStatus (MonoNativeOverlapped *native_overlapped) +ves_icall_System_Threading_ThreadPool_PostQueuedCompletionStatus (MonoNativeOverlapped *native_overlapped, MonoError *error) { /* This copy the behavior of the current Mono implementation */ - ERROR_DECL (error); mono_error_set_not_implemented (error, ""); - mono_error_set_pending_exception (error); return FALSE; } MonoBoolean G_GNUC_UNUSED -ves_icall_System_Threading_ThreadPool_BindIOCompletionCallbackNative (gpointer file_handle) +ves_icall_System_Threading_ThreadPool_BindIOCompletionCallbackNative (gpointer file_handle, MonoError *error) { /* This copy the behavior of the current Mono implementation */ return TRUE; } MonoBoolean G_GNUC_UNUSED -ves_icall_System_Threading_ThreadPool_IsThreadPoolHosted (void) +ves_icall_System_Threading_ThreadPool_IsThreadPoolHosted (MonoError *error) { return FALSE; } diff --git a/mono/metadata/threadpool.h b/mono/metadata/threadpool.h index efe0ced567..912e033bda 100644 --- a/mono/metadata/threadpool.h +++ b/mono/metadata/threadpool.h @@ -30,36 +30,36 @@ void mono_threadpool_resume (void); void -ves_icall_System_Threading_ThreadPool_GetAvailableThreadsNative (gint32 *worker_threads, gint32 *completion_port_threads); +ves_icall_System_Threading_ThreadPool_GetAvailableThreadsNative (gint32 *worker_threads, gint32 *completion_port_threads, MonoError *error); void -ves_icall_System_Threading_ThreadPool_GetMinThreadsNative (gint32 *worker_threads, gint32 *completion_port_threads); +ves_icall_System_Threading_ThreadPool_GetMinThreadsNative (gint32 *worker_threads, gint32 *completion_port_threads, MonoError *error); void -ves_icall_System_Threading_ThreadPool_GetMaxThreadsNative (gint32 *worker_threads, gint32 *completion_port_threads); +ves_icall_System_Threading_ThreadPool_GetMaxThreadsNative (gint32 *worker_threads, gint32 *completion_port_threads, MonoError *error); MonoBoolean -ves_icall_System_Threading_ThreadPool_SetMinThreadsNative (gint32 worker_threads, gint32 completion_port_threads); +ves_icall_System_Threading_ThreadPool_SetMinThreadsNative (gint32 worker_threads, gint32 completion_port_threads, MonoError *error); MonoBoolean -ves_icall_System_Threading_ThreadPool_SetMaxThreadsNative (gint32 worker_threads, gint32 completion_port_threads); +ves_icall_System_Threading_ThreadPool_SetMaxThreadsNative (gint32 worker_threads, gint32 completion_port_threads, MonoError *error); void -ves_icall_System_Threading_ThreadPool_InitializeVMTp (MonoBoolean *enable_worker_tracking); +ves_icall_System_Threading_ThreadPool_InitializeVMTp (MonoBoolean *enable_worker_tracking, MonoError *error); MonoBoolean -ves_icall_System_Threading_ThreadPool_NotifyWorkItemComplete (void); +ves_icall_System_Threading_ThreadPool_NotifyWorkItemComplete (MonoError *error); void -ves_icall_System_Threading_ThreadPool_NotifyWorkItemProgressNative (void); +ves_icall_System_Threading_ThreadPool_NotifyWorkItemProgressNative (MonoError *error); void -ves_icall_System_Threading_ThreadPool_NotifyWorkItemQueued (void); +ves_icall_System_Threading_ThreadPool_NotifyWorkItemQueued (MonoError *error); void -ves_icall_System_Threading_ThreadPool_ReportThreadStatus (MonoBoolean is_working); +ves_icall_System_Threading_ThreadPool_ReportThreadStatus (MonoBoolean is_working, MonoError *error); MonoBoolean -ves_icall_System_Threading_ThreadPool_RequestWorkerThread (void); +ves_icall_System_Threading_ThreadPool_RequestWorkerThread (MonoError *error); MonoBoolean -ves_icall_System_Threading_ThreadPool_PostQueuedCompletionStatus (MonoNativeOverlapped *native_overlapped); +ves_icall_System_Threading_ThreadPool_PostQueuedCompletionStatus (MonoNativeOverlapped *native_overlapped, MonoError *error); MonoBoolean -ves_icall_System_Threading_ThreadPool_BindIOCompletionCallbackNative (gpointer file_handle); +ves_icall_System_Threading_ThreadPool_BindIOCompletionCallbackNative (gpointer file_handle, MonoError *error); MonoBoolean -ves_icall_System_Threading_ThreadPool_IsThreadPoolHosted (void); +ves_icall_System_Threading_ThreadPool_IsThreadPoolHosted (MonoError *error); /* Internals */ diff --git a/mono/metadata/threads-types.h b/mono/metadata/threads-types.h index 2814818714..194d928e4f 100644 --- a/mono/metadata/threads-types.h +++ b/mono/metadata/threads-types.h @@ -20,6 +20,7 @@ #include "mono/utils/mono-compiler.h" #include "mono/utils/mono-membar.h" #include "mono/utils/mono-threads.h" +#include "mono/metadata/class-internals.h" /* This is a copy of System.Threading.ThreadState */ typedef enum { @@ -81,14 +82,24 @@ mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, Mo void mono_threads_install_cleanup (MonoThreadCleanupFunc func); -void ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj); +void +ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThreadObjectHandle this_obj, MonoError *error); + MonoBoolean -ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj, MonoObject *start); -void ves_icall_System_Threading_InternalThread_Thread_free_internal(MonoInternalThread *this_obj); +ves_icall_System_Threading_Thread_Thread_internal (MonoThreadObjectHandle this_obj, MonoObjectHandle start, MonoError *error); + +void +ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThreadHandle this_obj, MonoError *error); + void ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms); gboolean ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms); -gint32 ves_icall_System_Threading_Thread_GetDomainID (void); -gboolean ves_icall_System_Threading_Thread_Yield (void); + +gint32 +ves_icall_System_Threading_Thread_GetDomainID (MonoError *error); + +gboolean +ves_icall_System_Threading_Thread_Yield (MonoError *error); + MonoStringHandle ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThreadHandle this_obj, MonoError *error); void ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name); int ves_icall_System_Threading_Thread_GetPriority (MonoThreadObjectHandle this_obj, MonoError *error); @@ -102,8 +113,8 @@ MonoThreadObjectHandle ves_icall_System_Threading_Thread_GetCurrentThread (MonoE gint32 ves_icall_System_Threading_WaitHandle_Wait_internal(gpointer *handles, gint32 numhandles, MonoBoolean waitall, gint32 ms, MonoError *error); gint32 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (gpointer toSignal, gpointer toWait, gint32 ms, MonoError *error); -MonoArray* ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr); -MonoArray* ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr); +MonoArrayHandle ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArrayHandle arr, MonoError *error); +MonoArrayHandle ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArrayHandle arr, MonoError *error); gint32 ves_icall_System_Threading_Interlocked_Increment_Int(gint32 *location); gint64 ves_icall_System_Threading_Interlocked_Increment_Long(gint64 *location); @@ -140,7 +151,10 @@ gint64 ves_icall_System_Threading_Interlocked_Decrement_Long(gint64 * location); void ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state); void ves_icall_System_Threading_Thread_ResetAbort (MonoThread *this_obj); MonoObject* ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *thread); -void ves_icall_System_Threading_Thread_Suspend (MonoThread *this_obj); + +void +ves_icall_System_Threading_Thread_Suspend (MonoThreadObjectHandle this_obj, MonoError *error); + void ves_icall_System_Threading_Thread_Resume (MonoThread *thread); void ves_icall_System_Threading_Thread_ClrState (MonoInternalThreadHandle thread, guint32 state, MonoError *error); void ves_icall_System_Threading_Thread_SetState (MonoInternalThreadHandle thread_handle, guint32 state, MonoError *error); @@ -184,7 +198,9 @@ void ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value); void ves_icall_System_Threading_Thread_MemoryBarrier (void); void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this_obj); -void ves_icall_System_Threading_Thread_SpinWait_nop (void); + +void +ves_icall_System_Threading_Thread_SpinWait_nop (MonoError *error); void mono_threads_register_app_context (MonoAppContext* ctx, MonoError *error); @@ -194,7 +210,7 @@ mono_threads_release_app_context (MonoAppContext* ctx, MonoError *error); void ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContextHandle ctx, MonoError *error); void ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContextHandle ctx, MonoError *error); -MonoInternalThread *mono_thread_internal_current (void); +MONO_PROFILER_API MonoInternalThread *mono_thread_internal_current (void); void mono_thread_internal_abort (MonoInternalThread *thread, gboolean appdomain_unload); void mono_thread_internal_suspend_for_shutdown (MonoInternalThread *thread); @@ -222,9 +238,9 @@ void mono_threads_set_shutting_down (void); gunichar2* mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len); MONO_API MonoException* mono_thread_get_undeniable_exception (void); -void mono_thread_self_abort (void); +void ves_icall_thread_finish_async_abort (void); -void mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean permanent, gboolean reset, MonoError *error); +MONO_PROFILER_API void mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean permanent, gboolean reset, MonoError *error); void mono_thread_suspend_all_other_threads (void); gboolean mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout); @@ -243,7 +259,8 @@ uint32_t mono_alloc_special_static_data (uint32_t static_type, uint32_t size, ui void* mono_get_special_static_data (uint32_t offset); gpointer mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset); -MonoException* mono_thread_resume_interruption (gboolean exec); +void +mono_thread_resume_interruption (gboolean exec); void mono_threads_perform_thread_dump (void); gboolean diff --git a/mono/metadata/threads.c.REMOVED.git-id b/mono/metadata/threads.c.REMOVED.git-id index d8f14ab5aa..3be0087d70 100644 --- a/mono/metadata/threads.c.REMOVED.git-id +++ b/mono/metadata/threads.c.REMOVED.git-id @@ -1 +1 @@ -7fe367ede840af0a8a635e62ec4c21df49278b84 \ No newline at end of file +4221a74721ce7abdb902b7a2e9a0ebd03a18b626 \ No newline at end of file diff --git a/mono/metadata/verify.c.REMOVED.git-id b/mono/metadata/verify.c.REMOVED.git-id index 54d2a5eaa8..fb4e56f93a 100644 --- a/mono/metadata/verify.c.REMOVED.git-id +++ b/mono/metadata/verify.c.REMOVED.git-id @@ -1 +1 @@ -6fda18789202511c5496ed7280a140609a9101ac \ No newline at end of file +f8bc9652f645248e37316f5116c077fbf1838b7d \ No newline at end of file diff --git a/mono/metadata/w32file-unix.c.REMOVED.git-id b/mono/metadata/w32file-unix.c.REMOVED.git-id index c605e88f85..9199247802 100644 --- a/mono/metadata/w32file-unix.c.REMOVED.git-id +++ b/mono/metadata/w32file-unix.c.REMOVED.git-id @@ -1 +1 @@ -435b5915c1cf7c6e5e50d5a865a4269cdc6eb0b9 \ No newline at end of file +d20571cbe9063f14ee5081788efab0cfbaea42d9 \ No newline at end of file diff --git a/mono/metadata/w32process.c b/mono/metadata/w32process.c index 13b60cb876..9bca41ee5b 100644 --- a/mono/metadata/w32process.c +++ b/mono/metadata/w32process.c @@ -430,7 +430,7 @@ ves_icall_System_Diagnostics_FileVersionInfo_GetVersionInfo_internal (MonoObject { ERROR_DECL (error); - stash_system_image (mono_object_class (this_obj)->image); + stash_system_image (m_class_get_image (mono_object_class (this_obj))); mono_w32process_get_fileversion (this_obj, mono_string_chars (filename), error); if (!mono_error_ok (error)) { @@ -573,7 +573,7 @@ ves_icall_System_Diagnostics_Process_GetModules_internal (MonoObject *this_obj, guint32 i, num_added = 0; GPtrArray *assemblies = NULL; - stash_system_image (mono_object_class (this_obj)->image); + stash_system_image (m_class_get_image (mono_object_class (this_obj))); if (mono_w32process_get_pid (process) == mono_process_current_pid ()) { assemblies = get_domain_assemblies (mono_domain_get ()); diff --git a/mono/metadata/w32socket-win32.c b/mono/metadata/w32socket-win32.c index 75d0dad27c..6ef4d3618a 100644 --- a/mono/metadata/w32socket-win32.c +++ b/mono/metadata/w32socket-win32.c @@ -331,8 +331,10 @@ gint mono_w32socket_get_available (SOCKET sock, guint64 *amount) { gint ret; + u_long amount_long = 0; MONO_ENTER_GC_SAFE; - ret = ioctlsocket (sock, FIONREAD, (int*) amount); + ret = ioctlsocket (sock, FIONREAD, &amount_long); + *amount = amount_long; MONO_EXIT_GC_SAFE; return ret; } diff --git a/mono/metadata/w32socket.c b/mono/metadata/w32socket.c index 8fab506185..007f3edaa1 100644 --- a/mono/metadata/w32socket.c +++ b/mono/metadata/w32socket.c @@ -902,7 +902,7 @@ create_object_handle_from_sockaddr (struct sockaddr *saddr, int sa_size, gint32 /* Build a System.Net.SocketAddress object instance */ if (!domain->sockaddr_class) domain->sockaddr_class = mono_class_load_from_name (get_socket_assembly (), "System.Net", "SocketAddress"); - MonoObjectHandle sockaddr_obj = MONO_HANDLE_NEW (MonoObject, mono_object_new_checked (domain, domain->sockaddr_class, error)); + MonoObjectHandle sockaddr_obj = mono_object_new_handle (domain, domain->sockaddr_class, error); return_val_if_nok (error, MONO_HANDLE_NEW (MonoObject, NULL)); /* Locate the SocketAddress data buffer in the object */ @@ -1957,7 +1957,7 @@ ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal (gsize sock, gi obj_class = mono_class_load_from_name (get_socket_assembly (), "System.Net.Sockets", "LingerOption"); - MonoObjectHandle obj = MONO_HANDLE_NEW (MonoObject, mono_object_new_checked (domain, obj_class, error)); + MonoObjectHandle obj = mono_object_new_handle (domain, obj_class, error); return_if_nok (error); /* Locate and set the fields "bool enabled" and "int @@ -2013,7 +2013,7 @@ ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal (gsize sock, gi obj_class = mono_class_load_from_name (mono_posix_image, "Mono.Posix", "PeerCredData"); - MonoPeerCredDataHandle cred_data = MONO_HANDLE_NEW (MonoPeerCredData, mono_object_new_checked (domain, obj_class, error)); + MonoPeerCredDataHandle cred_data = (MonoPeerCredDataHandle)mono_object_new_handle (domain, obj_class, error); return_if_nok (error); MONO_HANDLE_SETVAL (cred_data, pid, gint, cred.pid); @@ -2813,7 +2813,7 @@ mono_network_cleanup (void) } void -icall_cancel_blocking_socket_operation (MonoThreadObjectHandle thread, MonoError *error) +ves_icall_cancel_blocking_socket_operation (MonoThreadObjectHandle thread, MonoError *error) { error_init (error); MonoInternalThreadHandle internal = MONO_HANDLE_NEW_GET (MonoInternalThread, thread, internal_thread); diff --git a/mono/metadata/w32socket.h b/mono/metadata/w32socket.h index b03ac93673..9a8928191c 100644 --- a/mono/metadata/w32socket.h +++ b/mono/metadata/w32socket.h @@ -288,7 +288,7 @@ ves_icall_System_Net_Sockets_Socket_SendFile_internal (gsize sock, MonoStringHan gint flags, gint32 *werror, gboolean blocking, MonoError *error); void -icall_cancel_blocking_socket_operation (MonoThreadObjectHandle thread, MonoError *error); +ves_icall_cancel_blocking_socket_operation (MonoThreadObjectHandle thread, MonoError *error); gboolean ves_icall_System_Net_Sockets_Socket_SupportPortReuse (MonoProtocolType proto, MonoError *error); diff --git a/mono/mini/Makefile.am b/mono/mini/Makefile.am index 8059fde3c9..ddfd7cf7de 100644 --- a/mono/mini/Makefile.am +++ b/mono/mini/Makefile.am @@ -21,14 +21,14 @@ endif boehm_libs= \ $(monodir)/mono/metadata/libmonoruntime.la \ $(monodir)/mono/utils/libmonoutils.la \ - $(GLIB_LIBS) $(LIBICONV) \ + $(GLIB_LIBS) \ $(libgc_libs) sgen_libs = \ $(monodir)/mono/metadata/libmonoruntimesgen.la \ $(monodir)/mono/sgen/libmonosgen.la \ $(monodir)/mono/utils/libmonoutils.la \ - $(GLIB_LIBS) $(LIBICONV) + $(GLIB_LIBS) if FULL_AOT_TESTS # if the tests are going to run with framework assemblies compiled with @@ -223,7 +223,6 @@ mono_boehm_LDADD = \ $(MONO_LIB) \ $(GLIB_LIBS) \ $(LLVMMONOF) \ - $(LIBICONV) \ -lm \ $(MONO_DTRACE_OBJECT) @@ -234,7 +233,6 @@ mono_sgen_LDADD = \ $(MONO_SGEN_LIB) \ $(GLIB_LIBS) \ $(LLVMMONOF) \ - $(LIBICONV) \ -lm \ $(MONO_DTRACE_OBJECT) @@ -691,34 +689,34 @@ GENMDESC_OPTS= GENMDESC_PRG=python $(srcdir)/genmdesc.py $(target_define) $(srcdir) -cpu-wasm.h: cpu-wasm.md +cpu-wasm.h: mini-ops.h cpu-wasm.md $(GENMDESC_PRG) cpu-wasm.h wasm_desc $(srcdir)/cpu-wasm.md -cpu-x86.h: cpu-x86.md +cpu-x86.h: mini-ops.h cpu-x86.md $(GENMDESC_PRG) cpu-x86.h x86_desc $(srcdir)/cpu-x86.md -cpu-amd64.h: cpu-amd64.md +cpu-amd64.h: mini-ops.h cpu-amd64.md $(GENMDESC_PRG) cpu-amd64.h amd64_desc $(srcdir)/cpu-amd64.md -cpu-ppc.h: cpu-ppc.md +cpu-ppc.h: mini-ops.h cpu-ppc.md $(GENMDESC_PRG) cpu-ppc.h ppcg4 $(srcdir)/cpu-ppc.md -cpu-ppc64.h: cpu-ppc64.md +cpu-ppc64.h: mini-ops.h cpu-ppc64.md $(GENMDESC_PRG) cpu-ppc64.h ppc64_cpu_desc $(srcdir)/cpu-ppc64.md -cpu-arm.h: cpu-arm.md +cpu-arm.h: mini-ops.h cpu-arm.md $(GENMDESC_PRG) cpu-arm.h arm_cpu_desc $(srcdir)/cpu-arm.md -cpu-arm64.h: cpu-arm64.md +cpu-arm64.h: mini-ops.h cpu-arm64.md $(GENMDESC_PRG) cpu-arm64.h arm64_cpu_desc $(srcdir)/cpu-arm64.md -cpu-sparc.h: cpu-sparc.md +cpu-sparc.h: mini-ops.h cpu-sparc.md $(GENMDESC_PRG) cpu-sparc.h sparc_desc $(srcdir)/cpu-sparc.md -cpu-s390x.h: cpu-s390x.md +cpu-s390x.h: mini-ops.h cpu-s390x.md $(GENMDESC_PRG) cpu-s390x.h s390x_cpu_desc $(srcdir)/cpu-s390x.md -cpu-mips.h: cpu-mips.md +cpu-mips.h: mini-ops.h cpu-mips.md $(GENMDESC_PRG) cpu-mips.h mips_desc $(srcdir)/cpu-mips.md testi: mono test.exe @@ -907,11 +905,11 @@ EXTRA_DIST = TestDriver.cs \ Makefile.am.in version.h: Makefile - if test -d $(top_srcdir)/.git; then \ + if test -e $(top_srcdir)/.git; then \ (cd $(top_srcdir); \ LANG=C; export LANG; \ if test -z "$$ghprbPullId"; then \ - branch=`git branch | grep '^\*' | sed 's/(detached from .*/explicit/' | cut -d ' ' -f 2`; \ + branch=`git branch | grep '^\*' | sed 's/.*detached .*/explicit/' | cut -d ' ' -f 2`; \ else \ branch="pull-request-$$ghprbPullId"; \ fi; \ diff --git a/mono/mini/Makefile.am.in b/mono/mini/Makefile.am.in index 8059fde3c9..ddfd7cf7de 100755 --- a/mono/mini/Makefile.am.in +++ b/mono/mini/Makefile.am.in @@ -21,14 +21,14 @@ endif boehm_libs= \ $(monodir)/mono/metadata/libmonoruntime.la \ $(monodir)/mono/utils/libmonoutils.la \ - $(GLIB_LIBS) $(LIBICONV) \ + $(GLIB_LIBS) \ $(libgc_libs) sgen_libs = \ $(monodir)/mono/metadata/libmonoruntimesgen.la \ $(monodir)/mono/sgen/libmonosgen.la \ $(monodir)/mono/utils/libmonoutils.la \ - $(GLIB_LIBS) $(LIBICONV) + $(GLIB_LIBS) if FULL_AOT_TESTS # if the tests are going to run with framework assemblies compiled with @@ -223,7 +223,6 @@ mono_boehm_LDADD = \ $(MONO_LIB) \ $(GLIB_LIBS) \ $(LLVMMONOF) \ - $(LIBICONV) \ -lm \ $(MONO_DTRACE_OBJECT) @@ -234,7 +233,6 @@ mono_sgen_LDADD = \ $(MONO_SGEN_LIB) \ $(GLIB_LIBS) \ $(LLVMMONOF) \ - $(LIBICONV) \ -lm \ $(MONO_DTRACE_OBJECT) @@ -691,34 +689,34 @@ GENMDESC_OPTS= GENMDESC_PRG=python $(srcdir)/genmdesc.py $(target_define) $(srcdir) -cpu-wasm.h: cpu-wasm.md +cpu-wasm.h: mini-ops.h cpu-wasm.md $(GENMDESC_PRG) cpu-wasm.h wasm_desc $(srcdir)/cpu-wasm.md -cpu-x86.h: cpu-x86.md +cpu-x86.h: mini-ops.h cpu-x86.md $(GENMDESC_PRG) cpu-x86.h x86_desc $(srcdir)/cpu-x86.md -cpu-amd64.h: cpu-amd64.md +cpu-amd64.h: mini-ops.h cpu-amd64.md $(GENMDESC_PRG) cpu-amd64.h amd64_desc $(srcdir)/cpu-amd64.md -cpu-ppc.h: cpu-ppc.md +cpu-ppc.h: mini-ops.h cpu-ppc.md $(GENMDESC_PRG) cpu-ppc.h ppcg4 $(srcdir)/cpu-ppc.md -cpu-ppc64.h: cpu-ppc64.md +cpu-ppc64.h: mini-ops.h cpu-ppc64.md $(GENMDESC_PRG) cpu-ppc64.h ppc64_cpu_desc $(srcdir)/cpu-ppc64.md -cpu-arm.h: cpu-arm.md +cpu-arm.h: mini-ops.h cpu-arm.md $(GENMDESC_PRG) cpu-arm.h arm_cpu_desc $(srcdir)/cpu-arm.md -cpu-arm64.h: cpu-arm64.md +cpu-arm64.h: mini-ops.h cpu-arm64.md $(GENMDESC_PRG) cpu-arm64.h arm64_cpu_desc $(srcdir)/cpu-arm64.md -cpu-sparc.h: cpu-sparc.md +cpu-sparc.h: mini-ops.h cpu-sparc.md $(GENMDESC_PRG) cpu-sparc.h sparc_desc $(srcdir)/cpu-sparc.md -cpu-s390x.h: cpu-s390x.md +cpu-s390x.h: mini-ops.h cpu-s390x.md $(GENMDESC_PRG) cpu-s390x.h s390x_cpu_desc $(srcdir)/cpu-s390x.md -cpu-mips.h: cpu-mips.md +cpu-mips.h: mini-ops.h cpu-mips.md $(GENMDESC_PRG) cpu-mips.h mips_desc $(srcdir)/cpu-mips.md testi: mono test.exe @@ -907,11 +905,11 @@ EXTRA_DIST = TestDriver.cs \ Makefile.am.in version.h: Makefile - if test -d $(top_srcdir)/.git; then \ + if test -e $(top_srcdir)/.git; then \ (cd $(top_srcdir); \ LANG=C; export LANG; \ if test -z "$$ghprbPullId"; then \ - branch=`git branch | grep '^\*' | sed 's/(detached from .*/explicit/' | cut -d ' ' -f 2`; \ + branch=`git branch | grep '^\*' | sed 's/.*detached .*/explicit/' | cut -d ' ' -f 2`; \ else \ branch="pull-request-$$ghprbPullId"; \ fi; \ diff --git a/mono/mini/Makefile.in.REMOVED.git-id b/mono/mini/Makefile.in.REMOVED.git-id index 6e3351c8a9..aa8d0aa560 100644 --- a/mono/mini/Makefile.in.REMOVED.git-id +++ b/mono/mini/Makefile.in.REMOVED.git-id @@ -1 +1 @@ -65b252a2198ccae81c9cbabed24fcb6a69d4ddd8 \ No newline at end of file +54e4339677ecb142c140d7363fcab31f908f9a43 \ No newline at end of file diff --git a/mono/mini/TestHelpers.cs b/mono/mini/TestHelpers.cs index 26f8d1276d..798ecfc99c 100644 --- a/mono/mini/TestHelpers.cs +++ b/mono/mini/TestHelpers.cs @@ -13,10 +13,21 @@ namespace MonoTests.Helpers { int* values = stackalloc int [20]; aptr = new IntPtr (values); - if (depth <= 0) + if (depth <= 0) { + // + // When the action is called, this new thread might have not allocated + // anything yet in the nursery. This means that the address of the first + // object that would be allocated would be at the start of the tlab and + // implicitly the end of the previous tlab (address which can be in use + // when allocating on another thread, at checking if an object fits in + // this other tlab). We allocate a new dummy object to avoid this type + // of false pinning for most common cases. + // + new object (); act (); - else + } else { NoPinActionHelper (depth - 1, act); + } } public static void PerformNoPinAction (Action act) diff --git a/mono/mini/alias-analysis.c b/mono/mini/alias-analysis.c index 4c204f683c..b6d57d3fa8 100644 --- a/mono/mini/alias-analysis.c +++ b/mono/mini/alias-analysis.c @@ -43,12 +43,12 @@ static gboolean lower_load (MonoCompile *cfg, MonoInst *load, MonoInst *ldaddr) { MonoInst *var = (MonoInst *)ldaddr->inst_p0; - MonoType *type = &var->klass->byval_arg; + MonoType *type = m_class_get_byval_arg (var->klass); int replaced_op = mono_type_to_load_membase (cfg, type); if (load->opcode == OP_LOADV_MEMBASE && load->klass != var->klass) { if (cfg->verbose_level > 2) - printf ("Incompatible load_vtype classes %s x %s\n", load->klass->name, var->klass->name); + printf ("Incompatible load_vtype classes %s x %s\n", m_class_get_name (load->klass), m_class_get_name (var->klass)); return FALSE; } @@ -63,7 +63,7 @@ lower_load (MonoCompile *cfg, MonoInst *load, MonoInst *ldaddr) } load->opcode = mono_type_to_regmove (cfg, type); - type_to_eval_stack_type (cfg, type, load); + mini_type_to_eval_stack_type (cfg, type, load); load->sreg1 = var->dreg; mono_atomic_inc_i32 (&mono_jit_stats.loads_eliminated); return TRUE; @@ -73,12 +73,12 @@ static gboolean lower_store (MonoCompile *cfg, MonoInst *store, MonoInst *ldaddr) { MonoInst *var = (MonoInst *)ldaddr->inst_p0; - MonoType *type = &var->klass->byval_arg; + MonoType *type = m_class_get_byval_arg (var->klass); int replaced_op = mono_type_to_store_membase (cfg, type); if (store->opcode == OP_STOREV_MEMBASE && store->klass != var->klass) { if (cfg->verbose_level > 2) - printf ("Incompatible store_vtype classes %s x %s\n", store->klass->name, store->klass->name); + printf ("Incompatible store_vtype classes %s x %s\n", m_class_get_name (store->klass), m_class_get_name (store->klass)); return FALSE; } @@ -98,7 +98,7 @@ lower_store (MonoCompile *cfg, MonoInst *store, MonoInst *ldaddr) store->opcode = coerce_op; else store->opcode = mono_type_to_regmove (cfg, type); - type_to_eval_stack_type (cfg, type, store); + mini_type_to_eval_stack_type (cfg, type, store); store->dreg = var->dreg; mono_atomic_inc_i32 (&mono_jit_stats.stores_eliminated); return TRUE; @@ -108,7 +108,7 @@ static gboolean lower_store_imm (MonoCompile *cfg, MonoInst *store, MonoInst *ldaddr) { MonoInst *var = (MonoInst *)ldaddr->inst_p0; - MonoType *type = &var->klass->byval_arg; + MonoType *type = m_class_get_byval_arg (var->klass); int store_op = mono_type_to_store_membase (cfg, type); if (store_op == OP_STOREV_MEMBASE || store_op == OP_STOREX_MEMBASE) return FALSE; diff --git a/mono/mini/aot-compiler.c.REMOVED.git-id b/mono/mini/aot-compiler.c.REMOVED.git-id index 17138aa7b7..de810c26d1 100644 --- a/mono/mini/aot-compiler.c.REMOVED.git-id +++ b/mono/mini/aot-compiler.c.REMOVED.git-id @@ -1 +1 @@ -dc6ccdd9e32db46edaceb26fd359a8890e0a4244 \ No newline at end of file +a2fecb56cbbd9529af21138df34d26377b8b5aef \ No newline at end of file diff --git a/mono/mini/aot-runtime-wasm.c b/mono/mini/aot-runtime-wasm.c index 4541b6d99d..9a6b800213 100644 --- a/mono/mini/aot-runtime-wasm.c +++ b/mono/mini/aot-runtime-wasm.c @@ -77,14 +77,14 @@ handle_enum: case MONO_TYPE_VOID: return 'V'; case MONO_TYPE_VALUETYPE: - if (t->data.klass->enumtype) { + if (m_class_is_enumtype (t->data.klass)) { t = mono_class_enum_basetype (t->data.klass); goto handle_enum; } return 'I'; case MONO_TYPE_GENERICINST: - if (t->data.klass->valuetype) + if (m_class_is_valuetype (t->data.klass)) return 'S'; return 'I'; default: @@ -159,8 +159,11 @@ mono_aot_get_trampoline_full (const char *name, MonoTrampInfo **out_tinfo) code = wasm_throw_corlib_exception; else if (!strcmp (name, "interp_to_native_trampoline")) code = wasm_interp_to_native_trampoline; + else if (!strcmp (name, "sdb_breakpoint_trampoline")) + code = mono_wasm_breakpoint_hit; - g_assert (code); + if (!code) + g_error ("could not find trampoline for %s\n", name); if (out_tinfo) { MonoTrampInfo *tinfo = g_new0 (MonoTrampInfo, 1); diff --git a/mono/mini/aot-runtime.c.REMOVED.git-id b/mono/mini/aot-runtime.c.REMOVED.git-id index abc4652099..ece26a9bac 100644 --- a/mono/mini/aot-runtime.c.REMOVED.git-id +++ b/mono/mini/aot-runtime.c.REMOVED.git-id @@ -1 +1 @@ -50774d9173c34a2729f12201de0a24fba264f540 \ No newline at end of file +39ef7bb08b9c216488e36ca08d0473eadea0fe17 \ No newline at end of file diff --git a/mono/mini/aot-runtime.h b/mono/mini/aot-runtime.h index f0a8843f6f..def9aac418 100644 --- a/mono/mini/aot-runtime.h +++ b/mono/mini/aot-runtime.h @@ -210,7 +210,7 @@ typedef struct MonoAotFileInfo void mono_aot_init (void); void mono_aot_cleanup (void); -gpointer mono_aot_get_method_checked (MonoDomain *domain, +gpointer mono_aot_get_method (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); diff --git a/mono/mini/aot-tests.cs b/mono/mini/aot-tests.cs index 5d749c10ac..e111f52918 100644 --- a/mono/mini/aot-tests.cs +++ b/mono/mini/aot-tests.cs @@ -216,7 +216,6 @@ class Tests return 0; } - [Category ("!INTERPRETER")] static int test_42_arm64_dyncall_vtypebyval () { var method = typeof (Foo5).GetMethod ("vtype_by_val").MakeGenericMethod (new Type [] { typeof (int), typeof (long?), typeof (long?), typeof (long?), typeof (long?) }); long res = (long)method.Invoke (null, new object [] { 1, 2L, 3L, 4L, 42L }); diff --git a/mono/mini/arch-stubs.c b/mono/mini/arch-stubs.c index 6f918c5d0d..6427bb77cd 100644 --- a/mono/mini/arch-stubs.c +++ b/mono/mini/arch-stubs.c @@ -66,3 +66,36 @@ mono_arch_tail_call_supported (MonoCompile *cfg, MonoMethodSignature *caller_sig return mono_metadata_signature_equal (caller_sig, callee_sig) && !MONO_TYPE_ISSTRUCT (callee_sig->ret); } #endif + +#ifndef MONO_ARCH_INTERPRETER_SUPPORTED + +gpointer +mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) +{ + g_assert_not_reached (); + return NULL; +} + +gpointer +mono_arch_get_native_to_interp_trampoline (MonoTrampInfo **info) +{ + g_assert_not_reached (); + return NULL; +} + +void +mono_arch_undo_ip_adjustment (MonoContext *context) +{ + g_assert_not_reached (); +} + +#endif + +#ifndef MONO_ARCH_HAVE_EXCEPTIONS_INIT + +void +mono_arch_exceptions_init (void) +{ +} + +#endif diff --git a/mono/mini/basic-simd.cs b/mono/mini/basic-simd.cs index f8fdcebaf9..bbef558ccb 100644 --- a/mono/mini/basic-simd.cs +++ b/mono/mini/basic-simd.cs @@ -2940,6 +2940,8 @@ public class SimdTests { return 0; } +#if FALSE + // Fails with -O=float32 public static int test_0_regs_pressure_fp_and_simd_share_bank_2 () { Vector4f a = new Vector4f (4, 3, 2, 1); float aF = 10f; @@ -2990,7 +2992,7 @@ public class SimdTests { return 0; } - +#endif public static void call_simd_fp () { Vector4f a = new Vector4f (20f, 22f, 23f, 24f); diff --git a/mono/mini/branch-opts.c b/mono/mini/branch-opts.c index 4280c595ef..0ac008af4d 100644 --- a/mono/mini/branch-opts.c +++ b/mono/mini/branch-opts.c @@ -94,7 +94,7 @@ mono_branch_optimize_exception_target (MonoCompile *cfg, MonoBasicBlock *bb, con jump->inst_true_bb = targetbb; if (cfg->verbose_level > 2) - g_print ("found exception to optimize - returning branch to BB%d (%s) (instead of throw) for method %s:%s\n", targetbb->block_num, clause->data.catch_class->name, cfg->method->klass->name, cfg->method->name); + g_print ("found exception to optimize - returning branch to BB%d (%s) (instead of throw) for method %s:%s\n", targetbb->block_num, m_class_get_name (clause->data.catch_class), m_class_get_name (cfg->method->klass), cfg->method->name); return jump; } diff --git a/mono/mini/cfgdump.c b/mono/mini/cfgdump.c index 36c9ffac87..3cd62c5afb 100644 --- a/mono/mini/cfgdump.c +++ b/mono/mini/cfgdump.c @@ -137,7 +137,7 @@ add_pool_entry (MonoCompile *cfg, ConstantPoolEntry *entry) case PT_KLASS: { MonoClass *klass = (MonoClass *) entry->data; write_byte (cfg, POOL_KLASS); - write_string (cfg, klass->name); + write_string (cfg, m_class_get_name (klass)); write_byte (cfg, KLASS); break; } @@ -242,7 +242,7 @@ mono_cfg_dump_begin_group (MonoCompile *cfg) return; write_byte (cfg, BEGIN_GROUP); char *title = (char *) mono_mempool_alloc0 (cfg->mempool, 0x2000); - sprintf (title, "%s::%s", cfg->method->klass->name, cfg->method->name); + sprintf (title, "%s::%s", m_class_get_name (cfg->method->klass), cfg->method->name); write_pool (cfg, create_cp_entry (cfg, (void *) title, PT_STRING)); write_pool (cfg, create_cp_entry (cfg, (void *) cfg->method->name, PT_STRING)); write_pool (cfg, create_cp_entry (cfg, (void *) cfg->method, PT_METHOD)); @@ -433,7 +433,7 @@ constant_pool_hash (ConstantPoolEntry *entry) return g_str_hash (method->name) ^ g_str_hash (method->klass); } case PT_KLASS: - return g_str_hash (((MonoClass *) entry->data)->name); + return g_str_hash (m_class_get_name ((MonoClass *) entry->data)); case PT_OPTYPE: return instruction_hash ((MonoInst *) entry->data); case PT_SIGNATURE: { @@ -503,7 +503,7 @@ void mono_cfg_dump_create_context (MonoCompile *cfg) if (strcmp (cfg->method->name, name) != 0) return; - g_debug ("cfg_dump: create context for \"%s::%s\"", cfg->method->klass->name, cfg->method->name); + g_debug ("cfg_dump: create context for \"%s::%s\"", m_class_get_name (cfg->method->klass), cfg->method->name); int fd = create_socket (DEFAULT_HOST, DEFAULT_PORT); if (fd < 0) { g_warning ("cfg_dump: couldn't create socket: %s::%d", DEFAULT_HOST, DEFAULT_PORT); diff --git a/mono/mini/cpu-amd64.md b/mono/mini/cpu-amd64.md index b2354f1762..9298ef1423 100755 --- a/mono/mini/cpu-amd64.md +++ b/mono/mini/cpu-amd64.md @@ -1,4 +1,4 @@ - +# -*- mode:text; -*- # x86-class cpu description file # this file is read by genmdesc to pruduce a table with all the relevant information # about the cpu instructions that may be used by the regsiter allocator, the scheduler @@ -58,6 +58,7 @@ break: len:2 tailcall: len:120 clob:c +tailcall_membase: src1:b len:120 clob:c # FIXME len? br: len:6 label: len:0 seq_point: len:46 clob:c @@ -266,6 +267,7 @@ r4_conv_to_u2: dest:i src1:f len:32 r4_conv_to_i4: dest:i src1:f len:16 r4_conv_to_u4: dest:i src1:f len:32 r4_conv_to_i8: dest:i src1:f len:32 +r4_conv_to_i: dest:i src1:f len:32 r4_conv_to_r8: dest:f src1:f len:17 r4_conv_to_r4: dest:f src1:f len:17 r4_add: dest:f src1:f src2:f clob:1 len:5 @@ -448,9 +450,10 @@ hard_nop: len:1 # Linear IR opcodes nop: len:0 dummy_use: src1:i len:0 -dummy_store: len:0 dummy_iconst: dest:i len:0 +dummy_i8const: dest:i len:0 dummy_r8const: dest:f len:0 +dummy_r4const: dest:f len:0 not_reached: len:0 not_null: src1:i len:0 diff --git a/mono/mini/cpu-arm.md b/mono/mini/cpu-arm.md index e6a91fc176..21fd8a1e8c 100644 --- a/mono/mini/cpu-arm.md +++ b/mono/mini/cpu-arm.md @@ -298,9 +298,9 @@ arm_rsc_imm: dest:i src1:i len:4 # Linear IR opcodes dummy_use: src1:i len:0 -dummy_store: len:0 dummy_iconst: dest:i len:0 dummy_r8const: dest:f len:0 +dummy_r4const: dest:f len:0 not_reached: len:0 not_null: src1:i len:0 diff --git a/mono/mini/cpu-arm64.md b/mono/mini/cpu-arm64.md index 840d26067a..4d975168db 100644 --- a/mono/mini/cpu-arm64.md +++ b/mono/mini/cpu-arm64.md @@ -300,7 +300,10 @@ arm_rsc_imm: dest:i src1:i len:4 # Linear IR opcodes dummy_use: src1:i len:0 -dummy_store: len:0 +dummy_iconst: dest:i len:0 +dummy_i8const: dest:i len:0 +dummy_r8const: dest:f len:0 +dummy_r4const: dest:f len:0 not_reached: len:0 not_null: src1:i len:0 diff --git a/mono/mini/cpu-mips.md b/mono/mini/cpu-mips.md index 85c3476ee3..cc088474bc 100644 --- a/mono/mini/cpu-mips.md +++ b/mono/mini/cpu-mips.md @@ -172,7 +172,10 @@ shr_un_imm: dest:i src1:i len:8 # Linear IR opcodes dummy_use: src1:i len:0 -dummy_store: len:0 +dummy_iconst: dest:i len:0 +dummy_i8const: dest:i len:0 +dummy_r8const: dest:f len:0 +dummy_r4const: dest:f len:0 not_reached: len:0 not_null: src1:i len:0 @@ -455,4 +458,6 @@ mips_cond_exc_ino: src1:i src2:i len:44 mips_cond_exc_ic: src1:i src2:i len:44 mips_cond_exc_inc: src1:i src2:i len:44 +liverange_start: len:0 +liverange_end: len:0 gc_safe_point: len:0 diff --git a/mono/mini/cpu-ppc.md b/mono/mini/cpu-ppc.md index 0baa0fe3c9..f495ab940e 100644 --- a/mono/mini/cpu-ppc.md +++ b/mono/mini/cpu-ppc.md @@ -220,7 +220,9 @@ bigmul_un: len:12 dest:l src1:i src2:i # Linear IR opcodes dummy_use: src1:i len:0 -dummy_store: len:0 +dummy_iconst: dest:i len:0 +dummy_r8const: dest:f len:0 +dummy_r4const: dest:f len:0 not_reached: len:0 not_null: src1:i len:0 @@ -327,4 +329,6 @@ jump_table: dest:i len:8 atomic_add_i4: src1:b src2:i dest:i len:28 atomic_cas_i4: src1:b src2:i src3:i dest:i len:38 +liverange_start: len:0 +liverange_end: len:0 gc_safe_point: len:0 diff --git a/mono/mini/cpu-ppc64.md b/mono/mini/cpu-ppc64.md index 2c28e7dca7..1969ddad41 100644 --- a/mono/mini/cpu-ppc64.md +++ b/mono/mini/cpu-ppc64.md @@ -223,7 +223,10 @@ bigmul_un: len:12 dest:i src1:i src2:i # Linear IR opcodes dummy_use: src1:i len:0 -dummy_store: len:0 +dummy_iconst: dest:i len:0 +dummy_i8const: dest:i len:0 +dummy_r8const: dest:f len:0 +dummy_r4const: dest:f len:0 not_reached: len:0 not_null: src1:i len:0 @@ -395,4 +398,6 @@ atomic_add_i8: src1:b src2:i dest:i len:28 atomic_cas_i4: src1:b src2:i src3:i dest:i len:38 atomic_cas_i8: src1:b src2:i src3:i dest:i len:38 +liverange_start: len:0 +liverange_end: len:0 gc_safe_point: len:0 diff --git a/mono/mini/cpu-s390x.md b/mono/mini/cpu-s390x.md index f0a89c6fc3..51d902bc96 100644 --- a/mono/mini/cpu-s390x.md +++ b/mono/mini/cpu-s390x.md @@ -95,6 +95,7 @@ fcall: dest:g len:26 clob:c fcall_membase: dest:g src1:b len:14 clob:c fcall_reg: dest:g src1:i len:10 clob:c fcompare: src1:f src2:f len:14 +rcompare: src1:f src2:f len:14 float_add: dest:f src1:f src2:f len:6 float_beq: len:10 @@ -136,6 +137,31 @@ float_not: dest:f src1:f len:6 float_rem: dest:f src1:f src2:f len:16 float_rem_un: dest:f src1:f src2:f len:16 float_sub: dest:f src1:f src2:f len:6 + +# R4 opcodes +r4_conv_to_i1: dest:i src1:f len:32 +r4_conv_to_u1: dest:i src1:f len:32 +r4_conv_to_i2: dest:i src1:f len:32 +r4_conv_to_u2: dest:i src1:f len:32 +r4_conv_to_i4: dest:i src1:f len:16 +r4_conv_to_u4: dest:i src1:f len:32 +r4_conv_to_i8: dest:i src1:f len:32 +r4_conv_to_r8: dest:f src1:f len:17 +r4_conv_to_r4: dest:f src1:f len:17 +r4_add: dest:f src1:f src2:f clob:1 len:5 +r4_sub: dest:f src1:f src2:f clob:1 len:5 +r4_mul: dest:f src1:f src2:f clob:1 len:5 +r4_div: dest:f src1:f src2:f clob:1 len:5 +r4_neg: dest:f src1:f clob:1 len:23 +r4_ceq: dest:i src1:f src2:f len:35 +r4_cgt: dest:i src1:f src2:f len:35 +r4_cgt_un: dest:i src1:f src2:f len:48 +r4_clt: dest:i src1:f src2:f len:35 +r4_clt_un: dest:i src1:f src2:f len:42 +r4_cneq: dest:i src1:f src2:f len:42 +r4_cge: dest:i src1:f src2:f len:35 +r4_cle: dest:i src1:f src2:f len:35 + fmove: dest:f src1:f len:4 move_f_to_i4: dest:i src1:f len:14 move_i4_to_f: dest:f src1:i len:14 @@ -145,7 +171,6 @@ i8const: dest:i len:20 icompare: src1:i src2:i len:4 icompare_imm: src1:i len:18 iconst: dest:i len:40 -jmp: len:50 label: len:0 lcall: dest:o len:22 clob:c lcall_membase: dest:o src1:b len:12 clob:c @@ -177,6 +202,9 @@ or_imm: dest:i src1:i len:24 r4const: dest:f len:26 r8const: dest:f len:24 rem_imm: dest:i src1:i len:24 +rcall: dest:f len:26 clob:c +rcall_reg: dest:f src1:i len:8 clob:c +rcall_membase: dest:f src1:b len:12 clob:c 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 @@ -208,6 +236,7 @@ sub_imm: dest:i src1:i len:18 sub_ovf_carry: dest:i src1:1 src2:i len:28 sub_ovf_un_carry: dest:i src1:1 src2:i len:12 subcc: dest:i src1:i src2:i len:12 +tailcall: len:120 clob:c throw: src1:i len:26 tls_get: dest:1 len:32 tls_set: src1:1 len:32 @@ -346,7 +375,10 @@ long_bne_un: len:8 # Linear IR opcodes dummy_use: src1:i len:0 -dummy_store: len:0 +dummy_iconst: dest:i len:0 +dummy_i8const: dest:i len:0 +dummy_r8const: dest:f len:0 +dummy_r4const: dest:f len:0 not_reached: len:0 not_null: src1:i len:0 @@ -400,6 +432,8 @@ s390_long_add_ovf_un: dest:i src1:i src2:i len:32 s390_long_sub_ovf: dest:i src1:i src2:i len:32 s390_long_sub_ovf_un: dest:i src1:i src2:i len:32 +liverange_start: len:0 +liverange_end: len:0 gc_liveness_def: len:0 gc_liveness_use: len:0 gc_spill_slot_liveness_def: len:0 diff --git a/mono/mini/cpu-sparc.md b/mono/mini/cpu-sparc.md index d3409bc1d9..f0392aa4ab 100644 --- a/mono/mini/cpu-sparc.md +++ b/mono/mini/cpu-sparc.md @@ -290,7 +290,10 @@ relaxed_nop: len:0 # Linear IR opcodes nop: len:0 dummy_use: src1:i len:0 -dummy_store: len:0 +dummy_iconst: dest:i len:0 +dummy_i8const: dest:i len:0 +dummy_r8const: dest:f len:0 +dummy_r4const: dest:f len:0 not_reached: len:0 not_null: src1:i len:0 @@ -317,4 +320,6 @@ vcall2: len:40 clob:c vcall2_reg: src1:i len:64 clob:c vcall2_membase: src1:b len:64 clob:c +liverange_start: len:0 +liverange_end: len:0 gc_safe_point: len:0 diff --git a/mono/mini/cpu-x86.md b/mono/mini/cpu-x86.md index e0c9625f78..e7c1fb211f 100644 --- a/mono/mini/cpu-x86.md +++ b/mono/mini/cpu-x86.md @@ -334,9 +334,9 @@ hard_nop: len:1 # Linear IR opcodes nop: len:0 dummy_use: src1:i len:0 -dummy_store: len:0 dummy_iconst: dest:i len:0 dummy_r8const: dest:f len:0 +dummy_r4const: dest:f len:0 not_reached: len:0 not_null: src1:i len:0 diff --git a/mono/mini/debug-mini.c b/mono/mini/debug-mini.c index fb49311687..0f2de0be78 100644 --- a/mono/mini/debug-mini.c +++ b/mono/mini/debug-mini.c @@ -242,7 +242,7 @@ mono_debug_close_method (MonoCompile *cfg) jit->code_start = cfg->native_code; jit->epilogue_begin = cfg->epilog_begin; jit->code_size = cfg->code_len; - jit->has_var_info = debug_options.mdb_optimizations || MONO_CFG_PROFILE_CALL_CONTEXT (cfg); + jit->has_var_info = mini_debug_options.mdb_optimizations || MONO_CFG_PROFILE_CALL_CONTEXT (cfg); if (jit->epilogue_begin) record_line_number (info, jit->epilogue_begin, header->code_size); @@ -665,7 +665,7 @@ void mono_debug_print_vars (gpointer ip, gboolean only_arguments) { MonoDomain *domain = mono_domain_get (); - MonoJitInfo *ji = mono_jit_info_table_find (domain, (char *)ip); + MonoJitInfo *ji = mono_jit_info_table_find (domain, ip); MonoDebugMethodJitInfo *jit; int i; diff --git a/mono/mini/debugger-agent.c.REMOVED.git-id b/mono/mini/debugger-agent.c.REMOVED.git-id index 32f59be555..da2a7aecbc 100644 --- a/mono/mini/debugger-agent.c.REMOVED.git-id +++ b/mono/mini/debugger-agent.c.REMOVED.git-id @@ -1 +1 @@ -95715e6783b065dfdef915e1121847560e674f5b \ No newline at end of file +5af3c5156272f2514967cfc39847525b1645ccd6 \ No newline at end of file diff --git a/mono/mini/debugger-agent.h b/mono/mini/debugger-agent.h index 1ff9de11db..86c8f85217 100644 --- a/mono/mini/debugger-agent.h +++ b/mono/mini/debugger-agent.h @@ -21,10 +21,10 @@ void mono_debugger_agent_single_step_event (void *sigctx); void -debugger_agent_single_step_from_context (MonoContext *ctx); +mono_debugger_agent_single_step_from_context (MonoContext *ctx); void -debugger_agent_breakpoint_from_context (MonoContext *ctx); +mono_debugger_agent_breakpoint_from_context (MonoContext *ctx); void mono_debugger_agent_free_domain_info (MonoDomain *domain); diff --git a/mono/mini/decompose.c b/mono/mini/decompose.c index 1d8e45f718..bd2a3e954d 100644 --- a/mono/mini/decompose.c +++ b/mono/mini/decompose.c @@ -531,7 +531,12 @@ mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins) emulate = TRUE; } break; - + case OP_ICONV_TO_R_UN: +#ifdef MONO_ARCH_EMULATE_CONV_R8_UN + if (!COMPILE_LLVM (cfg)) + emulate = TRUE; +#endif + break; default: emulate = TRUE; break; @@ -1217,10 +1222,10 @@ mono_decompose_vtype_opts (MonoCompile *cfg) dest_var = get_vreg_to_inst (cfg, ins->dreg); if (!src_var) - src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg); + src_var = mono_compile_create_var_for_vreg (cfg, m_class_get_byval_arg (ins->klass), OP_LOCAL, ins->dreg); if (!dest_var) - dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg); + dest_var = mono_compile_create_var_for_vreg (cfg, m_class_get_byval_arg (ins->klass), OP_LOCAL, ins->dreg); // FIXME: if (src_var->backend.is_pinvoke) @@ -1238,7 +1243,7 @@ mono_decompose_vtype_opts (MonoCompile *cfg) g_assert (ins->klass); - EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg); + EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, m_class_get_byval_arg (ins->klass)); mini_emit_initobj (cfg, dest, NULL, ins->klass); if (cfg->compute_gc_maps) { @@ -1267,10 +1272,10 @@ mono_decompose_vtype_opts (MonoCompile *cfg) if (!src_var) { g_assert (ins->klass); - src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1); + src_var = mono_compile_create_var_for_vreg (cfg, m_class_get_byval_arg (ins->klass), OP_LOCAL, ins->sreg1); } - EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg); + EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, m_class_get_byval_arg (ins->klass)); dreg = alloc_preg (cfg); EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset); @@ -1286,7 +1291,7 @@ mono_decompose_vtype_opts (MonoCompile *cfg) // FIXME-VT: // FIXME: if (!dest_var) - dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg); + dest_var = mono_compile_create_var_for_vreg (cfg, m_class_get_byval_arg (ins->klass), OP_LOCAL, ins->dreg); dreg = alloc_preg (cfg); EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset); @@ -1302,7 +1307,7 @@ mono_decompose_vtype_opts (MonoCompile *cfg) src_var = get_vreg_to_inst (cfg, ins->sreg1); if (!src_var) - src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1); + src_var = mono_compile_create_var_for_vreg (cfg, m_class_get_byval_arg (ins->klass), OP_LOCAL, ins->sreg1); EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype); mono_arch_emit_outarg_vt (cfg, ins, src); @@ -1456,7 +1461,7 @@ inline static MonoInst * mono_get_domainvar (MonoCompile *cfg) { if (!cfg->domainvar) - cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL); + cfg->domainvar = mono_compile_create_var (cfg, m_class_get_byval_arg (mono_defaults.int_class), OP_LOCAL); return cfg->domainvar; } @@ -1527,7 +1532,7 @@ mono_decompose_array_access_opts (MonoCompile *cfg) dest = mono_emit_jit_icall (cfg, ves_icall_array_new, iargs); dest->dreg = ins->dreg; } else { - MonoClass *array_class = mono_array_class_get (ins->inst_newa_class, 1); + MonoClass *array_class = mono_class_create_array (ins->inst_newa_class, 1); ERROR_DECL_VALUE (vt_error); MonoVTable *vtable = mono_class_vtable_checked (cfg->domain, array_class, &vt_error); MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class); diff --git a/mono/mini/driver.c b/mono/mini/driver.c index 8444991055..dc01173e43 100644 --- a/mono/mini/driver.c +++ b/mono/mini/driver.c @@ -140,9 +140,10 @@ opt_names [] = { MONO_OPT_GSHARED | \ MONO_OPT_SIMD | \ MONO_OPT_ALIAS_ANALYSIS | \ - MONO_OPT_AOT) + MONO_OPT_AOT | \ + MONO_OPT_FLOAT32) -#define EXCLUDED_FROM_ALL (MONO_OPT_SHARED | MONO_OPT_PRECOMP | MONO_OPT_UNSAFE | MONO_OPT_GSHAREDVT | MONO_OPT_FLOAT32) +#define EXCLUDED_FROM_ALL (MONO_OPT_SHARED | MONO_OPT_PRECOMP | MONO_OPT_UNSAFE | MONO_OPT_GSHAREDVT) static guint32 parse_optimizations (guint32 opt, const char* p, gboolean cpu_opts) @@ -393,7 +394,7 @@ mini_regression_step (MonoImage *image, int verbose, int *total_run, int *total, g_print ("Running '%s' ...\n", method->name); #ifdef MONO_USE_AOT_COMPILER ERROR_DECL (error); - func = (TestMethod)mono_aot_get_method_checked (mono_get_root_domain (), method, error); + func = (TestMethod)mono_aot_get_method (mono_get_root_domain (), method, error); mono_error_cleanup (error); if (!func) func = (TestMethod)(gpointer)cfg->native_code; @@ -616,7 +617,7 @@ interp_regression_step (MonoImage *image, int verbose, int *total_run, int *tota continue; MonoClass *klass = centry->ctor->klass; - if (strcmp (klass->name, "CategoryAttribute")) + if (strcmp (m_class_get_name (klass), "CategoryAttribute")) continue; MonoObject *obj = mono_custom_attrs_get_attr_checked (ainfo, klass, error); @@ -928,7 +929,7 @@ test_thread_func (ThreadData *td) guint pos = (*data)->start + random () % (*data)->length; MonoJitInfo *ji; - ji = mono_jit_info_table_find (domain, (char*)(gulong) pos); + ji = mono_jit_info_table_find (domain, (char*)(gsize)pos); g_assert (ji->cas_inited); g_assert ((*data)->ji == ji); @@ -1764,7 +1765,7 @@ mono_enable_interp (const char *opts) g_error ("--interpreter on cross-compile runtimes not supported\n"); #endif -#if !defined(TARGET_AMD64) && !defined(TARGET_ARM) && !defined(TARGET_ARM64) +#ifndef MONO_ARCH_INTERPRETER_SUPPORTED g_error ("--interpreter not supported on this architecture.\n"); #endif } diff --git a/mono/mini/dwarfwriter.c b/mono/mini/dwarfwriter.c index 9d4a591f48..8cc4eae355 100644 --- a/mono/mini/dwarfwriter.c +++ b/mono/mini/dwarfwriter.c @@ -931,8 +931,8 @@ emit_class_dwarf_info (MonoDwarfWriter *w, MonoClass *klass, gboolean vtype) if (die) return die; - if (!((klass->byval_arg.type == MONO_TYPE_CLASS) || (klass->byval_arg.type == MONO_TYPE_OBJECT) || klass->byval_arg.type == MONO_TYPE_GENERICINST || klass->enumtype || (klass->byval_arg.type == MONO_TYPE_VALUETYPE && vtype) || - (klass->byval_arg.type >= MONO_TYPE_BOOLEAN && klass->byval_arg.type <= MONO_TYPE_R8 && !vtype))) + if (!((m_class_get_byval_arg (klass)->type == MONO_TYPE_CLASS) || (m_class_get_byval_arg (klass)->type == MONO_TYPE_OBJECT) || m_class_get_byval_arg (klass)->type == MONO_TYPE_GENERICINST || m_class_is_enumtype (klass) || (m_class_get_byval_arg (klass)->type == MONO_TYPE_VALUETYPE && vtype) || + (m_class_get_byval_arg (klass)->type >= MONO_TYPE_BOOLEAN && m_class_get_byval_arg (klass)->type <= MONO_TYPE_R8 && !vtype))) return NULL; /* @@ -944,10 +944,10 @@ emit_class_dwarf_info (MonoDwarfWriter *w, MonoClass *klass, gboolean vtype) */ if (emit_namespace) { emit_uleb128 (w, ABBREV_NAMESPACE); - emit_string (w, klass->name_space); + emit_string (w, m_class_get_name_space (klass)); } - full_name = g_strdup_printf ("%s%s%s", klass->name_space, klass->name_space ? "." : "", klass->name); + full_name = g_strdup_printf ("%s%s%s", m_class_get_name_space (klass), m_class_get_name_space (klass) ? "." : "", m_class_get_name (klass)); /* * gdb doesn't support namespaces for non-C++ dwarf objects, so use _ * to separate components. @@ -965,7 +965,7 @@ emit_class_dwarf_info (MonoDwarfWriter *w, MonoClass *klass, gboolean vtype) g_hash_table_insert (w->class_to_reference_die, klass, reference_die); g_hash_table_insert (cache, klass, die); - if (klass->enumtype) { + if (m_class_is_enumtype (klass)) { int size = mono_class_value_size (mono_class_from_mono_type (mono_class_enum_basetype (klass)), NULL); emit_label (w, die); @@ -1033,8 +1033,8 @@ emit_class_dwarf_info (MonoDwarfWriter *w, MonoClass *klass, gboolean vtype) guint8 *p; char *parent_die; - if (klass->parent) - parent_die = emit_class_dwarf_info (w, klass->parent, FALSE); + if (m_class_get_parent (klass)) + parent_die = emit_class_dwarf_info (w, m_class_get_parent (klass), FALSE); else parent_die = NULL; @@ -1054,7 +1054,7 @@ emit_class_dwarf_info (MonoDwarfWriter *w, MonoClass *klass, gboolean vtype) emit_uleb128 (w, has_children ? ABBREV_STRUCT_TYPE : ABBREV_STRUCT_TYPE_NOCHILDREN); emit_string (w, full_name); - emit_uleb128 (w, klass->instance_size); + emit_uleb128 (w, m_class_get_instance_size (klass)); if (parent_die) { emit_uleb128 (w, ABBREV_INHERITANCE); @@ -1081,7 +1081,7 @@ emit_class_dwarf_info (MonoDwarfWriter *w, MonoClass *klass, gboolean vtype) /* location */ p = buf; *p ++= DW_OP_plus_uconst; - if (klass->valuetype && vtype) + if (m_class_is_valuetype (klass) && vtype) encode_uleb128 (field->offset - sizeof (MonoObject), p, &p); else encode_uleb128 (field->offset, p, &p); @@ -1141,7 +1141,7 @@ get_type_die (MonoDwarfWriter *w, MonoType *t) /* Should return a pointer type to a reference */ } // FIXME: - t = &mono_defaults.int_class->byval_arg; + t = m_class_get_byval_arg (mono_defaults.int_class); } for (j = 0; j < G_N_ELEMENTS (basic_types); ++j) if (basic_types [j].type == t->type) @@ -1158,7 +1158,7 @@ get_type_die (MonoDwarfWriter *w, MonoType *t) tdie = ".LDIE_OBJECT"; break; case MONO_TYPE_VALUETYPE: - if (klass->enumtype) + if (m_class_is_enumtype (klass)) tdie = get_class_die (w, klass, FALSE); else tdie = ".LDIE_I4"; @@ -1201,7 +1201,7 @@ emit_type (MonoDwarfWriter *w, MonoType *t) emit_class_dwarf_info (w, klass, FALSE); } // FIXME: - t = &mono_defaults.int_class->byval_arg; + t = m_class_get_byval_arg (mono_defaults.int_class); } for (j = 0; j < G_N_ELEMENTS (basic_types); ++j) if (basic_types [j].type == t->type) @@ -1220,7 +1220,7 @@ emit_type (MonoDwarfWriter *w, MonoType *t) case MONO_TYPE_ARRAY: break; case MONO_TYPE_VALUETYPE: - if (klass->enumtype) + if (m_class_is_enumtype (klass)) emit_class_dwarf_info (w, klass, FALSE); break; case MONO_TYPE_GENERICINST: @@ -1316,10 +1316,10 @@ token_handler (MonoDisHelper *dh, MonoMethod *method, guint32 token) if (method->wrapper_type) { klass = (MonoClass *)data; } else { - klass = mono_class_get_checked (method->klass->image, token, error); + klass = mono_class_get_checked (m_class_get_image (method->klass), token, error); g_assert (mono_error_ok (error)); /* FIXME error handling */ } - res = g_strdup_printf ("<%s>", klass->name); + res = g_strdup_printf ("<%s>", m_class_get_name (klass)); break; case CEE_NEWOBJ: case CEE_CALL: @@ -1328,7 +1328,7 @@ token_handler (MonoDisHelper *dh, MonoMethod *method, guint32 token) cmethod = (MonoMethod *)data; } else { ERROR_DECL (error); - cmethod = mono_get_method_checked (method->klass->image, token, NULL, NULL, error); + cmethod = mono_get_method_checked (m_class_get_image (method->klass), token, NULL, NULL, error); if (!cmethod) g_error ("Could not load method due to %s", mono_error_get_message (error)); /* FIXME don't swallow the error */ } @@ -1352,7 +1352,7 @@ token_handler (MonoDisHelper *dh, MonoMethod *method, guint32 token) if (method->wrapper_type) { field = (MonoClassField *)data; } else { - field = mono_field_from_token_checked (method->klass->image, token, &klass, NULL, error); + field = mono_field_from_token_checked (m_class_get_image (method->klass), token, &klass, NULL, error); g_assert (mono_error_ok (error)); /* FIXME error handling */ } desc = mono_field_full_name (field); @@ -1411,7 +1411,7 @@ disasm_ins (MonoMethod *method, const guchar *ip, const guint8 **endip) token = read32 (ip + 2); data = mono_method_get_wrapper_data (method, token); - dis = g_strdup_printf ("IL_%04x: mono_classconst <%s>", (int)(ip - header->code), ((MonoClass*)data)->name); + dis = g_strdup_printf ("IL_%04x: mono_classconst <%s>", (int)(ip - header->code), m_class_get_name ((MonoClass*)data)); ip += 6; break; } @@ -1778,10 +1778,10 @@ mono_dwarf_writer_emit_method (MonoDwarfWriter *w, MonoCompile *cfg, MonoMethod MonoType *t; if (i == 0 && sig->hasthis) { - if (method->klass->valuetype) - t = &method->klass->this_arg; + if (m_class_is_valuetype (method->klass)) + t = m_class_get_this_arg (method->klass); else - t = &method->klass->byval_arg; + t = m_class_get_byval_arg (method->klass); } else { t = sig->params [i - sig->hasthis]; } @@ -1854,10 +1854,10 @@ mono_dwarf_writer_emit_method (MonoDwarfWriter *w, MonoCompile *cfg, MonoMethod need_loclist = TRUE; if (i == 0 && sig->hasthis) { - if (method->klass->valuetype) - t = &method->klass->this_arg; + if (m_class_is_valuetype (method->klass)) + t = m_class_get_this_arg (method->klass); else - t = &method->klass->byval_arg; + t = m_class_get_byval_arg (method->klass); pname = "this"; } else { t = sig->params [i - sig->hasthis]; @@ -1873,7 +1873,7 @@ mono_dwarf_writer_emit_method (MonoDwarfWriter *w, MonoCompile *cfg, MonoMethod emit_string (w, pname); /* type */ if (!arg || arg->flags & MONO_INST_IS_DEAD) - emit_var_type (w, &mono_defaults.int32_class->byval_arg); + emit_var_type (w, m_class_get_byval_arg (mono_defaults.int32_class)); else emit_var_type (w, t); @@ -1930,7 +1930,7 @@ mono_dwarf_writer_emit_method (MonoDwarfWriter *w, MonoCompile *cfg, MonoMethod } /* type */ if (!ins || ins->flags & MONO_INST_IS_DEAD) - emit_var_type (w, &mono_defaults.int32_class->byval_arg); + emit_var_type (w, m_class_get_byval_arg (mono_defaults.int32_class)); else emit_var_type (w, header->locals [i]); diff --git a/mono/mini/ee.h b/mono/mini/ee.h index c65ea5a28d..05db8b6d19 100644 --- a/mono/mini/ee.h +++ b/mono/mini/ee.h @@ -33,7 +33,6 @@ struct _MonoEECallbacks { void (*init_delegate) (MonoDelegate *del); gpointer (*get_remoting_invoke) (gpointer imethod, MonoError *error); 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); diff --git a/mono/mini/exceptions-amd64.c b/mono/mini/exceptions-amd64.c index 90423fad0a..66a0bcd051 100644 --- a/mono/mini/exceptions-amd64.c +++ b/mono/mini/exceptions-amd64.c @@ -46,8 +46,6 @@ #include "aot-runtime.h" #include "tasklets.h" -#define ALIGN_TO(val,align) (((val) + ((align) - 1)) & ~((align) - 1)) - #ifdef TARGET_WIN32 static void (*restore_stack) (void); static MonoW32ExceptionHandler fpe_handler; @@ -413,7 +411,7 @@ mono_amd64_throw_corlib_exception (guint64 dummy1, guint64 dummy2, guint64 dummy guint32 ex_token = MONO_TOKEN_TYPE_DEF | ex_token_index; MonoException *ex; - ex = mono_exception_from_token (mono_defaults.exception_class->image, ex_token); + ex = mono_exception_from_token (m_class_get_image (mono_defaults.exception_class), ex_token); mctx->gregs [AMD64_RIP] -= pc_offset; @@ -1964,3 +1962,9 @@ mono_tasklets_arch_restore (void) return NULL; } #endif /* !MONO_SUPPORT_TASKLETS || defined(DISABLE_JIT) */ + +void +mono_arch_undo_ip_adjustment (MonoContext *ctx) +{ + ctx->gregs [AMD64_RIP]++; +} diff --git a/mono/mini/exceptions-arm.c b/mono/mini/exceptions-arm.c index d2df1efb7e..6e3a4930b2 100644 --- a/mono/mini/exceptions-arm.c +++ b/mono/mini/exceptions-arm.c @@ -627,3 +627,12 @@ mono_arch_setup_resume_sighandler_ctx (MonoContext *ctx, gpointer func) /* Transition to ARM */ ctx->cpsr &= ~(1 << 5); } + +void +mono_arch_undo_ip_adjustment (MonoContext *ctx) +{ + ctx->pc++; + + if (mono_arm_thumb_supported ()) + ctx->pc |= 1; +} diff --git a/mono/mini/exceptions-arm64.c b/mono/mini/exceptions-arm64.c index 0e4a5ee0f4..945bc91ef3 100644 --- a/mono/mini/exceptions-arm64.c +++ b/mono/mini/exceptions-arm64.c @@ -21,8 +21,6 @@ #include #include -#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1)) - #ifndef DISABLE_JIT gpointer @@ -601,3 +599,9 @@ mono_arch_setup_resume_sighandler_ctx (MonoContext *ctx, gpointer func) { MONO_CONTEXT_SET_IP (ctx,func); } + +void +mono_arch_undo_ip_adjustment (MonoContext *ctx) +{ + ctx->pc++; +} diff --git a/mono/mini/exceptions-ppc.c b/mono/mini/exceptions-ppc.c index 4101eaf3e9..3483ba835d 100644 --- a/mono/mini/exceptions-ppc.c +++ b/mono/mini/exceptions-ppc.c @@ -618,22 +618,6 @@ mono_arch_ip_from_context (void *sigctx) #endif } -void -mono_ppc_set_func_into_sigctx (void *sigctx, void *func) -{ -#ifdef MONO_CROSS_COMPILE - g_assert_not_reached (); -#elif defined(PPC_USES_FUNCTION_DESCRIPTOR) - /* Have to set both the ip and the TOC reg */ - os_ucontext *uc = sigctx; - - UCONTEXT_REG_NIP(uc) = ((gsize*)func) [0]; - UCONTEXT_REG_Rn (uc, 2) = ((gsize*)func)[1]; -#else - g_assert_not_reached (); -#endif -} - static void altstack_handle_and_restore (void *sigctx, gpointer obj) { @@ -808,9 +792,21 @@ void mono_arch_setup_async_callback (MonoContext *ctx, void (*async_cb)(void *fun), gpointer user_data) { uintptr_t sp = (uintptr_t) MONO_CONTEXT_GET_SP(ctx); + ctx->regs [PPC_FIRST_ARG_REG] = user_data; sp -= PPC_MINIMAL_STACK_SIZE; *(unsigned long *)sp = MONO_CONTEXT_GET_SP(ctx); MONO_CONTEXT_SET_BP(ctx, sp); - MONO_CONTEXT_SET_IP(ctx, (unsigned long) async_cb); + mono_arch_setup_resume_sighandler_ctx(ctx, (unsigned long) async_cb); } +void +mono_arch_setup_resume_sighandler_ctx (MonoContext *ctx, gpointer func) +{ +#ifdef PPC_USES_FUNCTION_DESCRIPTOR + MonoPPCFunctionDescriptor *handler_ftnptr = (MonoPPCFunctionDescriptor*)func; + MONO_CONTEXT_SET_IP(ctx, (gulong)handler_ftnptr->code); + ctx->regs[2] = (gulong)handler_ftnptr->toc; +#else + MONO_CONTEXT_SET_IP(ctx, (unsigned long) func); +#endif +} diff --git a/mono/mini/exceptions-s390x.c b/mono/mini/exceptions-s390x.c index d0527a3b8d..23fecb60d2 100644 --- a/mono/mini/exceptions-s390x.c +++ b/mono/mini/exceptions-s390x.c @@ -312,7 +312,7 @@ mono_arch_get_throw_exception_generic (int size, MonoTrampInfo **info, s390_lgr (code, s390_r3, s390_r2); if (corlib) { S390_SET (code, s390_r1, (guint8 *)mono_exception_from_token); - S390_SET (code, s390_r2, (guint8 *)mono_defaults.exception_class->image); + S390_SET (code, s390_r2, (guint8 *)m_class_get_image (mono_defaults.exception_class)); s390_basr (code, s390_r14, s390_r1); } diff --git a/mono/mini/exceptions-sparc.c b/mono/mini/exceptions-sparc.c index 25cd6390aa..3790f970f9 100644 --- a/mono/mini/exceptions-sparc.c +++ b/mono/mini/exceptions-sparc.c @@ -303,7 +303,7 @@ mono_arch_get_throw_corlib_exception (MonoTrampInfo **info, gboolean aot) sparc_set (code, MONO_TOKEN_TYPE_DEF, sparc_o7); sparc_add (code, FALSE, sparc_i0, sparc_o7, sparc_o1); - sparc_set (code, mono_defaults.exception_class->image, sparc_o0); + sparc_set (code, m_class_get_image (mono_defaults.exception_class), sparc_o0); sparc_set (code, mono_exception_from_token, sparc_o7); sparc_jmpl (code, sparc_o7, sparc_g0, sparc_callsite); sparc_nop (code); diff --git a/mono/mini/exceptions-wasm.c b/mono/mini/exceptions-wasm.c index 301838df04..1ebc3202e5 100644 --- a/mono/mini/exceptions-wasm.c +++ b/mono/mini/exceptions-wasm.c @@ -22,7 +22,15 @@ mono_arch_unwind_frame (MonoDomain *domain, MonoJitTlsData *jit_tls, mgreg_t **save_locations, StackFrameInfo *frame) { - g_error ("mono_arch_unwind_frame"); + if (ji) + g_error ("Can't unwind compiled code"); + + if (*lmf) { + if ((*lmf)->top_entry) + return FALSE; + g_error ("Can't handle non-top-entry LMFs\n"); + } + return FALSE; } @@ -46,3 +54,8 @@ mono_arch_get_throw_exception (MonoTrampInfo **info, gboolean aot) g_error ("mono_arch_get_rethrow_exception"); return NULL; } + +void +mono_arch_undo_ip_adjustment (MonoContext *ctx) +{ +} diff --git a/mono/mini/exceptions-x86.c b/mono/mini/exceptions-x86.c index 1bdefb54bb..ac1f8cea40 100644 --- a/mono/mini/exceptions-x86.c +++ b/mono/mini/exceptions-x86.c @@ -499,7 +499,7 @@ mono_x86_throw_corlib_exception (mgreg_t *regs, guint32 ex_token_index, guint32 ex_token = MONO_TOKEN_TYPE_DEF | ex_token_index; MonoException *ex; - ex = mono_exception_from_token (mono_defaults.exception_class->image, ex_token); + ex = mono_exception_from_token (m_class_get_image (mono_defaults.exception_class), ex_token); eip -= pc_offset; diff --git a/mono/mini/generics.cs b/mono/mini/generics.cs index 57b35aecc9..6cb61e16e1 100644 --- a/mono/mini/generics.cs +++ b/mono/mini/generics.cs @@ -129,6 +129,20 @@ class Tests return ldelem_any (arr); } + public static int test_1_ldelem_stelem_any_single () { + float[] arr = new float [3]; + stelem_any (arr, 1); + + return (int) ldelem_any (arr); + } + + public static int test_1_ldelem_stelem_any_double () { + double[] arr = new double [3]; + stelem_any (arr, 1); + + return (int) ldelem_any (arr); + } + public static T return_ref (ref T t) { return t; } diff --git a/mono/mini/genmdesc.py b/mono/mini/genmdesc.py index bc820ee679..987332bdf1 100755 --- a/mono/mini/genmdesc.py +++ b/mono/mini/genmdesc.py @@ -95,9 +95,17 @@ def parse_mini_ops (target_define): return opcodes def parse_input(infile, opcodes): + + # Comments are pound sign to end of string. + remove_comments = re.compile ("#.*") + for line in infile: line = line.strip () - if line == "" or line.startswith ("#"): + # remove comments + line = re.sub (remove_comments, "", line) + + # Ignore empty lines -- including it was just a comment. + if line == "": continue # Lines look like: # expand_i2: dest:x src1:i len:18 diff --git a/mono/mini/iltests.il b/mono/mini/iltests.il index 1bcf07af6b..63d9a6f371 100644 --- a/mono/mini/iltests.il +++ b/mono/mini/iltests.il @@ -2264,6 +2264,7 @@ HAS_VALUE: ldc.i4.1 ret } +/* Disabled until they can be fixed to run on amd64 .method public static float32 GetFloat32() cil managed noinlining { .maxstack 8 @@ -2271,7 +2272,6 @@ HAS_VALUE: ldc.i4.1 ret } -/* Disabled until they can be fixed to run on amd64 .method public static default int32 test_0_implicit_float_to_double_conversion () cil managed { .maxstack 16 @@ -3178,6 +3178,20 @@ L_3: ret } + .method public hidebysig static int32 test_1_box_r8_r4_autoconv () cil managed + { + ldc.r8 1.234 + box float64 + unbox float64 + ldind.r8 + box float32 + unbox float32 + ldind.r4 + conv.r8 + conv.i4 + ret + } + .method public hidebysig static int32 test_1_dont_verify_ptr_byrefs () cil managed { .locals init (int32 v_0, int32 *& v_2, int32 *v_1) diff --git a/mono/mini/image-writer.c b/mono/mini/image-writer.c index 97ade6b06f..3e1d64b555 100644 --- a/mono/mini/image-writer.c +++ b/mono/mini/image-writer.c @@ -116,8 +116,6 @@ #define AS_TEMP_LABEL_PREFIX ".L" #endif -#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1)) -#define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1))) #define ROUND_DOWN(VALUE,SIZE) ((VALUE) & ~((SIZE) - 1)) #ifdef USE_BIN_WRITER diff --git a/mono/mini/interp-stubs.c b/mono/mini/interp-stubs.c index 28d3a63934..189b2c7c59 100644 --- a/mono/mini/interp-stubs.c +++ b/mono/mini/interp-stubs.c @@ -159,7 +159,6 @@ mono_interp_stub_init (void) c.init_delegate = stub_init_delegate; c.get_remoting_invoke = stub_get_remoting_invoke; 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; diff --git a/mono/mini/interp/interp-internals.h b/mono/mini/interp/interp-internals.h index 4713b8ca68..f72dcd5ef2 100644 --- a/mono/mini/interp/interp-internals.h +++ b/mono/mini/interp/interp-internals.h @@ -24,6 +24,7 @@ #define BOX_NOT_CLEAR_VT_SP 0x4000 +#define MINT_VT_ALIGNMENT 8 enum { VAL_I32 = 0, @@ -87,11 +88,13 @@ typedef struct _InterpMethod MonoMethod *method; struct _InterpMethod *next_jit_code_hash; guint32 locals_size; + guint32 total_locals_size; guint32 args_size; guint32 stack_size; guint32 vt_stack_size; guint32 alloca_size; unsigned int init_locals : 1; + unsigned int vararg : 1; unsigned short *code; unsigned short *new_body_start; /* after all STINARG instrs */ MonoPIFunc func; @@ -118,9 +121,9 @@ typedef struct _InterpMethod struct _InterpFrame { InterpFrame *parent; /* parent */ InterpMethod *imethod; /* parent */ - MonoMethod *method; /* parent */ stackval *retval; /* parent */ char *args; + char *varargs; stackval *stack_args; /* parent */ stackval *stack; stackval *sp; /* For GC stack marking */ @@ -145,7 +148,7 @@ typedef struct { } ThreadContext; extern int mono_interp_traceopt; -extern GSList *jit_classes; +extern GSList *mono_interp_jit_classes; MonoException * mono_interp_transform_method (InterpMethod *imethod, ThreadContext *context, InterpFrame *frame); @@ -200,7 +203,7 @@ enum_type: case MONO_TYPE_ARRAY: return MINT_TYPE_O; case MONO_TYPE_VALUETYPE: - if (type->data.klass->enumtype) { + if (m_class_is_enumtype (type->data.klass)) { type = mono_class_enum_basetype (type->data.klass); goto enum_type; } else @@ -208,7 +211,7 @@ enum_type: case MONO_TYPE_TYPEDBYREF: return MINT_TYPE_VT; case MONO_TYPE_GENERICINST: - type = &type->data.generic_class->container_class->byval_arg; + type = m_class_get_byval_arg (type->data.generic_class->container_class); goto enum_type; default: g_warning ("got type 0x%02x", type->type); diff --git a/mono/mini/interp/interp.c.REMOVED.git-id b/mono/mini/interp/interp.c.REMOVED.git-id index bcb764fb25..eb0d00dd56 100644 --- a/mono/mini/interp/interp.c.REMOVED.git-id +++ b/mono/mini/interp/interp.c.REMOVED.git-id @@ -1 +1 @@ -ebd8ca09e620615de32931a90fe0b09b8c3640d5 \ No newline at end of file +346952f06b1d65af35a60611088ac15fd7fc746a \ No newline at end of file diff --git a/mono/mini/interp/mintops.def b/mono/mini/interp/mintops.def index 80c8a2940d..bbf06e9269 100644 --- a/mono/mini/interp/mintops.def +++ b/mono/mini/interp/mintops.def @@ -40,6 +40,8 @@ OPDEF(MINT_LDC_I8, "ldc.i8", 5, MintOpLongInt) OPDEF(MINT_LDC_R4, "ldc.r4", 3, MintOpFloat) OPDEF(MINT_LDC_R8, "ldc.r8", 5, MintOpDouble) +OPDEF(MINT_ARGLIST, "arglist", 1, MintOpNoArgs) + OPDEF(MINT_LDARG_I1, "ldarg.i1", 2, MintOpUShortInt) OPDEF(MINT_LDARG_U1, "ldarg.u1", 2, MintOpUShortInt) OPDEF(MINT_LDARG_I2, "ldarg.i2", 2, MintOpUShortInt) @@ -177,6 +179,8 @@ OPDEF(MINT_THROW, "throw", 1, MintOpNoArgs) OPDEF(MINT_RETHROW, "rethrow", 2, MintOpUShortInt) OPDEF(MINT_ENDFINALLY, "endfinally", 2, MintOpNoArgs) +OPDEF(MINT_CHECKPOINT, "checkpoint", 1, MintOpNoArgs) + OPDEF(MINT_BRFALSE_I4, "brfalse.i4", 3, MintOpBranch) OPDEF(MINT_BRFALSE_I8, "brfalse.i8", 3, MintOpBranch) OPDEF(MINT_BRFALSE_R8, "brfalse.r8", 3, MintOpBranch) @@ -517,7 +521,7 @@ OPDEF(MINT_CLT_UN_R8, "clt.un.r8", 1, MintOpNoArgs) OPDEF(MINT_CKFINITE, "ckfinite", 1, MintOpNoArgs) OPDEF(MINT_MKREFANY, "mkrefany", 2, MintOpClassToken) OPDEF(MINT_REFANYTYPE, "refanytype", 1, MintOpNoArgs) -OPDEF(MINT_REFANYVAL, "refanyval", 1, MintOpNoArgs) +OPDEF(MINT_REFANYVAL, "refanyval", 2, MintOpNoArgs) OPDEF(MINT_CKNULL, "cknull", 1, MintOpNoArgs) OPDEF(MINT_CKNULL_N, "cknull_n", 2, MintOpInt) diff --git a/mono/mini/interp/transform.c.REMOVED.git-id b/mono/mini/interp/transform.c.REMOVED.git-id index 2d5ab92ccf..49d104a1b1 100644 --- a/mono/mini/interp/transform.c.REMOVED.git-id +++ b/mono/mini/interp/transform.c.REMOVED.git-id @@ -1 +1 @@ -2024e2faa2c369548911c13756565c494f8a5cb1 \ No newline at end of file +dce98aa88673c09e1a92b8e88fb3c4a80a3b7ad6 \ No newline at end of file diff --git a/mono/mini/ir-emit.h b/mono/mini/ir-emit.h index ad13b93015..f45fa3f1c1 100644 --- a/mono/mini/ir-emit.h +++ b/mono/mini/ir-emit.h @@ -324,9 +324,7 @@ alloc_dreg (MonoCompile *cfg, MonoStackType stack_type) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_METHOD_RGCTX, (method)); \ } else { \ MonoMethodRuntimeGenericContext *mrgctx; \ - MonoVTable *vt = mono_class_vtable_checked ((cfg)->domain, (method)->klass, &(cfg)->error); \ - mono_error_assert_ok (&(cfg)->error); \ - mrgctx = mono_method_lookup_rgctx (vt, mini_method_get_context ((method))->method_inst); \ + mrgctx = mini_method_get_rgctx ((method)); \ NEW_PCONST ((cfg), (dest), (mrgctx)); \ } \ } while (0) @@ -346,7 +344,7 @@ alloc_dreg (MonoCompile *cfg, MonoStackType stack_type) #define NEW_VARLOAD(cfg,dest,var,vartype) do { \ MONO_INST_NEW ((cfg), (dest), OP_MOVE); \ (dest)->opcode = mono_type_to_regmove ((cfg), (vartype)); \ - type_to_eval_stack_type ((cfg), (vartype), (dest)); \ + mini_type_to_eval_stack_type ((cfg), (vartype), (dest)); \ (dest)->klass = var->klass; \ (dest)->sreg1 = var->dreg; \ (dest)->dreg = alloc_dreg ((cfg), (MonoStackType)(dest)->type); \ @@ -432,7 +430,7 @@ handle_gsharedvt_ldaddr (MonoCompile *cfg) /* Variants which take a type argument and handle vtypes as well */ #define NEW_LOAD_MEMBASE_TYPE(cfg,dest,ltype,base,offset) do { \ NEW_LOAD_MEMBASE ((cfg), (dest), mono_type_to_load_membase ((cfg), (ltype)), 0, (base), (offset)); \ - type_to_eval_stack_type ((cfg), (ltype), (dest)); \ + mini_type_to_eval_stack_type ((cfg), (ltype), (dest)); \ (dest)->dreg = alloc_dreg ((cfg), (MonoStackType)(dest)->type); \ } while (0) @@ -441,7 +439,7 @@ handle_gsharedvt_ldaddr (MonoCompile *cfg) (dest)->sreg1 = sr; \ (dest)->inst_destbasereg = base; \ (dest)->inst_offset = offset; \ - type_to_eval_stack_type ((cfg), (ltype), (dest)); \ + mini_type_to_eval_stack_type ((cfg), (ltype), (dest)); \ (dest)->klass = mono_class_from_mono_type (ltype); \ } while (0) diff --git a/mono/mini/jit-icalls.c b/mono/mini/jit-icalls.c index 895cb879e4..0c1cb8a258 100644 --- a/mono/mini/jit-icalls.c +++ b/mono/mini/jit-icalls.c @@ -114,7 +114,7 @@ mono_helper_stelem_ref_check (MonoArray *array, MonoObject *val) mono_set_pending_exception (mono_get_exception_null_reference ()); return; } - if (val && !mono_object_isinst_checked (val, array->obj.vtable->klass->element_class, error)) { + if (val && !mono_object_isinst_checked (val, m_class_get_element_class (mono_object_class (array)), error)) { if (mono_error_set_pending_exception (error)) return; mono_set_pending_exception (mono_get_exception_array_type_mismatch ()); @@ -685,7 +685,7 @@ mono_array_new_va (MonoMethod *cm, ...) int i, d; pcount = mono_method_signature (cm)->param_count; - rank = cm->klass->rank; + rank = m_class_get_rank (cm->klass); va_start (ap, cm); @@ -695,7 +695,7 @@ mono_array_new_va (MonoMethod *cm, ...) if (rank == pcount) { /* Only lengths provided. */ - if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) { + if (m_class_get_byval_arg (cm->klass)->type == MONO_TYPE_ARRAY) { lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank); memset (lower_bounds, 0, sizeof (intptr_t) * rank); } else { @@ -732,13 +732,13 @@ mono_array_new_1 (MonoMethod *cm, guint32 length) int rank; pcount = mono_method_signature (cm)->param_count; - rank = cm->klass->rank; + rank = m_class_get_rank (cm->klass); lengths [0] = length; g_assert (rank == pcount); - if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) { + if (m_class_get_byval_arg (cm->klass)->type == MONO_TYPE_ARRAY) { lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank); memset (lower_bounds, 0, sizeof (intptr_t) * rank); } else { @@ -767,14 +767,14 @@ mono_array_new_2 (MonoMethod *cm, guint32 length1, guint32 length2) int rank; pcount = mono_method_signature (cm)->param_count; - rank = cm->klass->rank; + rank = m_class_get_rank (cm->klass); lengths [0] = length1; lengths [1] = length2; g_assert (rank == pcount); - if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) { + if (m_class_get_byval_arg (cm->klass)->type == MONO_TYPE_ARRAY) { lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank); memset (lower_bounds, 0, sizeof (intptr_t) * rank); } else { @@ -803,7 +803,7 @@ mono_array_new_3 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 leng int rank; pcount = mono_method_signature (cm)->param_count; - rank = cm->klass->rank; + rank = m_class_get_rank (cm->klass); lengths [0] = length1; lengths [1] = length2; @@ -811,7 +811,7 @@ mono_array_new_3 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 leng g_assert (rank == pcount); - if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) { + if (m_class_get_byval_arg (cm->klass)->type == MONO_TYPE_ARRAY) { lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank); memset (lower_bounds, 0, sizeof (intptr_t) * rank); } else { @@ -840,7 +840,7 @@ mono_array_new_4 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 leng int rank; pcount = mono_method_signature (cm)->param_count; - rank = cm->klass->rank; + rank = m_class_get_rank (cm->klass); lengths [0] = length1; lengths [1] = length2; @@ -849,7 +849,7 @@ mono_array_new_4 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 leng g_assert (rank == pcount); - if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) { + if (m_class_get_byval_arg (cm->klass)->type == MONO_TYPE_ARRAY) { lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank); memset (lower_bounds, 0, sizeof (intptr_t) * rank); } else { @@ -1118,7 +1118,7 @@ mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointe addr = mini_add_method_trampoline (vmethod, addr, mono_method_needs_static_rgctx_invoke (vmethod, FALSE), FALSE); /* Since this is a virtual call, have to unbox vtypes */ - if (obj->vtable->klass->valuetype) + if (m_class_is_valuetype (obj->vtable->klass)) *this_arg = mono_object_unbox (obj); else *this_arg = obj; @@ -1222,7 +1222,7 @@ mono_object_castclass_unbox (MonoObject *obj, MonoClass *klass) return NULL; oklass = obj->vtable->klass; - if ((klass->enumtype && oklass == klass->element_class) || (oklass->enumtype && klass == oklass->element_class)) + if ((m_class_is_enumtype (klass) && oklass == m_class_get_element_class (klass)) || (m_class_is_enumtype (oklass) && klass == m_class_get_element_class (oklass))) return obj; if (mono_object_isinst_checked (obj, klass, error)) return obj; @@ -1352,26 +1352,26 @@ constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *k } else { /* Lookup the virtual method */ mono_class_setup_vtable (klass); - g_assert (klass->vtable); + g_assert (m_class_get_vtable (klass)); vt_slot = mono_method_get_vtable_slot (cmethod); if (mono_class_is_interface (cmethod->klass)) { iface_offset = mono_class_interface_offset (klass, cmethod->klass); g_assert (iface_offset != -1); vt_slot += iface_offset; } - m = klass->vtable [vt_slot]; + m = m_class_get_vtable (klass) [vt_slot]; if (cmethod->is_inflated) { m = mono_class_inflate_generic_method_full_checked (m, NULL, mono_method_get_context (cmethod), error); return_val_if_nok (error, NULL); } } - if (klass->valuetype && (m->klass == mono_defaults.object_class || m->klass == mono_defaults.enum_class->parent || m->klass == mono_defaults.enum_class)) { + if (m_class_is_valuetype (klass) && (m->klass == mono_defaults.object_class || m->klass == m_class_get_parent (mono_defaults.enum_class) || m->klass == mono_defaults.enum_class)) { /* * Calling a non-vtype method with a vtype receiver, has to box. */ *this_arg = mono_value_box_checked (mono_domain_get (), klass, mp, error); - } else if (klass->valuetype) { + } else if (m_class_is_valuetype (klass)) { if (is_iface) { /* * The original type is an interface, so the receiver is a ref, @@ -1442,7 +1442,7 @@ mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *kl void mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass) { - if (klass->valuetype) + if (m_class_is_valuetype (klass)) mono_value_copy (dest, src, klass); else mono_gc_wbarrier_generic_store (dest, *(MonoObject**)src); @@ -1544,10 +1544,10 @@ resolve_iface_call (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, generic_virtual = imt_method; if (generic_virtual || variant_iface) { - if (vt->klass->valuetype) /*FIXME is this required variant iface?*/ + if (m_class_is_valuetype (vt->klass)) /*FIXME is this required variant iface?*/ need_unbox_tramp = TRUE; } else { - if (impl_method->klass->valuetype) + if (m_class_is_valuetype (impl_method->klass)) need_unbox_tramp = TRUE; } @@ -1614,7 +1614,7 @@ resolve_vcall (MonoVTable *vt, int slot, MonoMethod *imt_method, gpointer *out_a /* Avoid loading metadata or creating a generic vtable if possible */ addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, slot, error); return_val_if_nok (error, NULL); - if (addr && !vt->klass->valuetype) + if (addr && !m_class_is_valuetype (vt->klass)) return mono_create_ftnptr (mono_domain_get (), addr); m = mono_class_get_vtable_entry (vt->klass, slot); @@ -1643,10 +1643,10 @@ resolve_vcall (MonoVTable *vt, int slot, MonoMethod *imt_method, gpointer *out_a } if (generic_virtual) { - if (vt->klass->valuetype) + if (m_class_is_valuetype (vt->klass)) need_unbox_tramp = TRUE; } else { - if (m->klass->valuetype) + if (m_class_is_valuetype (m->klass)) need_unbox_tramp = TRUE; } @@ -1723,7 +1723,7 @@ mono_resolve_generic_virtual_call (MonoVTable *vt, int slot, MonoMethod *generic m = mono_class_inflate_generic_method_checked (declaring, &context, error); g_assert (mono_error_ok (error)); - if (vt->klass->valuetype) + if (m_class_is_valuetype (vt->klass)) need_unbox_tramp = TRUE; // FIXME: This can throw exceptions @@ -1771,7 +1771,7 @@ mono_resolve_generic_virtual_iface_call (MonoVTable *vt, int imt_slot, MonoMetho mono_llvm_throw_exception ((MonoObject*)ex); } - if (vt->klass->valuetype) + if (m_class_is_valuetype (vt->klass)) need_unbox_tramp = TRUE; if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) @@ -1850,7 +1850,7 @@ mono_llvmonly_init_delegate (MonoDelegate *del) if (mono_error_set_pending_exception (error)) return; - if (m->klass->valuetype && mono_method_signature (m)->hasthis) + if (m_class_is_valuetype (m->klass) && mono_method_signature (m)->hasthis) addr = mono_aot_get_unbox_trampoline (m); gpointer arg = mini_get_delegate_arg (del->method, addr); @@ -1879,7 +1879,7 @@ mono_llvmonly_init_delegate_virtual (MonoDelegate *del, MonoObject *target, Mono del->method_ptr = mono_compile_method_checked (method, error); if (mono_error_set_pending_exception (error)) return; - if (method->klass->valuetype) + if (m_class_is_valuetype (method->klass)) del->method_ptr = mono_aot_get_unbox_trampoline (method); del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr); } diff --git a/mono/mini/liveness.c b/mono/mini/liveness.c index eaa656e059..1ed551730c 100644 --- a/mono/mini/liveness.c +++ b/mono/mini/liveness.c @@ -982,8 +982,6 @@ mono_analyze_liveness2 (MonoCompile *cfg) #endif -#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1)) - static inline void update_liveness_gc (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins, gint32 *last_use, MonoMethodVar **vreg_to_varinfo, GSList **callsites) { diff --git a/mono/mini/local-propagation.c b/mono/mini/local-propagation.c index 923f53311c..2a418285cc 100644 --- a/mono/mini/local-propagation.c +++ b/mono/mini/local-propagation.c @@ -640,11 +640,9 @@ mono_local_cprop (MonoCompile *cfg) } /* Constant propagation */ - /* FIXME: Make is_inst_imm a macro */ - /* FIXME: Make is_inst_imm take an opcode argument */ /* is_inst_imm is only needed for binops */ if ((((def->opcode == OP_ICONST) || ((sizeof (gpointer) == 8) && (def->opcode == OP_I8CONST)) || (def->opcode == OP_PCONST)) && - (((srcindex == 0) && (ins->sreg2 == -1)) || mono_arch_is_inst_imm (def->inst_c0))) || + (((srcindex == 0) && (ins->sreg2 == -1)))) || (!MONO_ARCH_USE_FPSTACK && (def->opcode == OP_R8CONST))) { guint32 opcode2; @@ -669,7 +667,7 @@ mono_local_cprop (MonoCompile *cfg) } opcode2 = mono_op_to_op_imm (ins->opcode); - if ((opcode2 != -1) && mono_arch_is_inst_imm (def->inst_c0) && ((srcindex == 1) || (ins->sreg2 == -1))) { + if ((opcode2 != -1) && mono_arch_is_inst_imm (ins->opcode, opcode2, def->inst_c0) && ((srcindex == 1) || (ins->sreg2 == -1))) { ins->opcode = opcode2; if ((def->opcode == OP_I8CONST) && (sizeof (gpointer) == 4)) { ins->inst_ls_word = def->inst_ls_word; @@ -702,7 +700,7 @@ mono_local_cprop (MonoCompile *cfg) } #endif opcode2 = mono_load_membase_to_load_mem (ins->opcode); - if ((srcindex == 0) && (opcode2 != -1) && mono_arch_is_inst_imm (def->inst_c0)) { + if ((srcindex == 0) && (opcode2 != -1) && mono_arch_is_inst_imm (ins->opcode, opcode2, def->inst_c0)) { ins->opcode = opcode2; ins->inst_imm = def->inst_c0 + ins->inst_offset; ins->sreg1 = -1; diff --git a/mono/mini/memory-access.c b/mono/mini/memory-access.c index f53ad917fc..038c79fc00 100644 --- a/mono/mini/memory-access.c +++ b/mono/mini/memory-access.c @@ -246,13 +246,13 @@ create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bi if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) continue; - foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset; + foffset = m_class_is_valuetype (klass) ? field->offset - sizeof (MonoObject): field->offset; if (mini_type_is_reference (mono_field_get_type (field))) { g_assert ((foffset % SIZEOF_VOID_P) == 0); *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P); } else { MonoClass *field_class = mono_class_from_mono_type (field->type); - if (field_class->has_references) + if (m_class_has_references (field_class)) create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset); } } @@ -353,7 +353,7 @@ mini_emit_memory_copy_internal (MonoCompile *cfg, MonoInst *dest, MonoInst *src, */ if (cfg->gshared) - klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg)); + klass = mono_class_from_mono_type (mini_get_underlying_type (m_class_get_byval_arg (klass))); /* * This check breaks with spilled vars... need to handle it during verification anyway. @@ -376,7 +376,7 @@ mini_emit_memory_copy_internal (MonoCompile *cfg, MonoInst *dest, MonoInst *src, if (explicit_align) align = explicit_align; - if (mini_type_is_reference (&klass->byval_arg)) { // Refs *MUST* be naturally aligned + if (mini_type_is_reference (m_class_get_byval_arg (klass))) { // Refs *MUST* be naturally aligned MonoInst *store, *load; int dreg = alloc_ireg_ref (cfg); @@ -387,7 +387,9 @@ mini_emit_memory_copy_internal (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MONO_ADD_INS (cfg->cbb, store); mini_emit_write_barrier (cfg, dest, src); - } else if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) { /* if native is true there should be no references in the struct */ + return; + + } else if (cfg->gen_write_barriers && (m_class_has_references (klass) || size_ins) && !native) { /* if native is true there should be no references in the struct */ /* Avoid barriers when storing to the stack */ if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) || (dest->opcode == OP_LDADDR))) { diff --git a/mono/mini/method-to-ir.c.REMOVED.git-id b/mono/mini/method-to-ir.c.REMOVED.git-id index d821a29cb3..5e594cc71c 100644 --- a/mono/mini/method-to-ir.c.REMOVED.git-id +++ b/mono/mini/method-to-ir.c.REMOVED.git-id @@ -1 +1 @@ -98c74554c4f3345d0b6e95022def55c9fcb5e2d8 \ No newline at end of file +ce7377ebc15fd4a762cb1f66c9487dbfc2c84b07 \ No newline at end of file diff --git a/mono/mini/mini-amd64-gsharedvt.c b/mono/mini/mini-amd64-gsharedvt.c index dc78a80691..8a656c0d7c 100644 --- a/mono/mini/mini-amd64-gsharedvt.c +++ b/mono/mini/mini-amd64-gsharedvt.c @@ -31,8 +31,6 @@ #if defined (MONO_ARCH_GSHAREDVT_SUPPORTED) -#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1)) - gboolean mono_arch_gsharedvt_sig_supported (MonoMethodSignature *sig) { diff --git a/mono/mini/mini-amd64.c.REMOVED.git-id b/mono/mini/mini-amd64.c.REMOVED.git-id index 240cd6c56b..106db785bb 100644 --- a/mono/mini/mini-amd64.c.REMOVED.git-id +++ b/mono/mini/mini-amd64.c.REMOVED.git-id @@ -1 +1 @@ -293b7302145f5887e3be21fe4157f186f6c0bdc0 \ No newline at end of file +f25f10a67a06a3028fee4584bf81491fc5152aad \ No newline at end of file diff --git a/mono/mini/mini-amd64.h b/mono/mini/mini-amd64.h index 536c27f1af..505902925a 100644 --- a/mono/mini/mini-amd64.h +++ b/mono/mini/mini-amd64.h @@ -157,7 +157,6 @@ struct sigcontext { #define MONO_ARCH_CALLEE_SAVED_REGS AMD64_CALLEE_SAVED_REGS #define MONO_ARCH_USE_FPSTACK FALSE -#define MONO_ARCH_FPSTACK_SIZE 0 #define MONO_ARCH_INST_FIXED_REG(desc) ((desc == '\0') ? -1 : ((desc == 'i' ? -1 : ((desc == 'a') ? AMD64_RAX : ((desc == 's') ? AMD64_RCX : ((desc == 'd') ? AMD64_RDX : ((desc == 'A') ? MONO_AMD64_ARG_REG1 : -1))))))) @@ -420,14 +419,13 @@ typedef struct { * clobbered across method call boundaries. */ #define MONO_ARCH_RGCTX_REG MONO_ARCH_IMT_REG -#define MONO_ARCH_EXC_REG AMD64_RAX #define MONO_ARCH_HAVE_CMOV_OPS 1 #define MONO_ARCH_HAVE_EXCEPTIONS_INIT 1 #define MONO_ARCH_HAVE_GENERALIZED_IMT_TRAMPOLINE 1 -#define MONO_ARCH_HAVE_LIVERANGE_OPS 1 #define MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX 1 #define MONO_ARCH_HAVE_GET_TRAMPOLINES 1 +#define MONO_ARCH_INTERPRETER_SUPPORTED 1 #define MONO_ARCH_AOT_SUPPORTED 1 #define MONO_ARCH_SOFT_DEBUG_SUPPORTED 1 @@ -445,12 +443,12 @@ typedef struct { #define MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK 1 #define MONO_ARCH_HAVE_CREATE_LLVM_NATIVE_THUNK 1 #define MONO_ARCH_HAVE_OP_TAIL_CALL 1 -#define MONO_ARCH_HAVE_TRANSLATE_TLS_OFFSET 1 -#define MONO_ARCH_HAVE_DUMMY_INIT 1 +#define MONO_ARCH_HAVE_OP_TAIL_CALL_MEMBASE 1 #define MONO_ARCH_HAVE_SDB_TRAMPOLINES 1 #define MONO_ARCH_HAVE_PATCH_CODE_NEW 1 #define MONO_ARCH_HAVE_OP_GENERIC_CLASS_INIT 1 #define MONO_ARCH_HAVE_GENERAL_RGCTX_LAZY_FETCH_TRAMPOLINE 1 +#define MONO_ARCH_FLOAT32_SUPPORTED 1 #define MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP @@ -479,6 +477,10 @@ typedef struct { MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException"); \ } while (0) +// Does the ABI have a volatile non-parameter register, so tailcall +// can pass context to generics or interfaces? +#define MONO_ARCH_HAVE_VOLATILE_NON_PARAM_REGISTER 1 + void mono_amd64_patch (unsigned char* code, gpointer target); diff --git a/mono/mini/mini-arm-gsharedvt.c b/mono/mini/mini-arm-gsharedvt.c index 5ec0f4ac68..2ad36b13f9 100644 --- a/mono/mini/mini-arm-gsharedvt.c +++ b/mono/mini/mini-arm-gsharedvt.c @@ -24,8 +24,6 @@ #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED -#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1)) - /* * GSHAREDVT */ diff --git a/mono/mini/mini-arm.c.REMOVED.git-id b/mono/mini/mini-arm.c.REMOVED.git-id index 15753f661e..335bf737b6 100644 --- a/mono/mini/mini-arm.c.REMOVED.git-id +++ b/mono/mini/mini-arm.c.REMOVED.git-id @@ -1 +1 @@ -c4f30bb0b37fd257d5b466807cf1c977d6c0af40 \ No newline at end of file +320850533bf1e1804108ffff270daa6e725fb17b \ No newline at end of file diff --git a/mono/mini/mini-arm.h b/mono/mini/mini-arm.h index 0ab0aa4a5c..1bd8d32a40 100644 --- a/mono/mini/mini-arm.h +++ b/mono/mini/mini-arm.h @@ -93,7 +93,6 @@ #endif #define MONO_ARCH_USE_FPSTACK FALSE -#define MONO_ARCH_FPSTACK_SIZE 0 #define MONO_ARCH_INST_SREG2_MASK(ins) (0) @@ -332,6 +331,7 @@ typedef struct MonoCompileArch { #define MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES 1 #define MONO_ARCH_HAVE_DECOMPOSE_LONG_OPTS 1 +#define MONO_ARCH_INTERPRETER_SUPPORTED 1 #define MONO_ARCH_AOT_SUPPORTED 1 #define MONO_ARCH_LLVM_SUPPORTED 1 @@ -356,10 +356,10 @@ typedef struct MonoCompileArch { #define MONO_ARCH_HAVE_OPCODE_NEEDS_EMULATION 1 #define MONO_ARCH_HAVE_OBJC_GET_SELECTOR 1 #define MONO_ARCH_HAVE_OP_TAIL_CALL 1 -#define MONO_ARCH_HAVE_DUMMY_INIT 1 #define MONO_ARCH_HAVE_SDB_TRAMPOLINES 1 #define MONO_ARCH_HAVE_PATCH_CODE_NEW 1 #define MONO_ARCH_HAVE_OP_GENERIC_CLASS_INIT 1 +#define MONO_ARCH_FLOAT32_SUPPORTED 1 #define MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE 1 #define MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE 1 @@ -375,7 +375,10 @@ typedef struct MonoCompileArch { #define MONO_ARCH_IMT_REG MONO_ARCH_RGCTX_REG /* First argument reg */ #define MONO_ARCH_VTABLE_REG ARMREG_R0 -#define MONO_ARCH_EXC_REG ARMREG_R0 + +// Does the ABI have a volatile non-parameter register, so tailcall +// can pass context to generics or interfaces? +#define MONO_ARCH_HAVE_VOLATILE_NON_PARAM_REGISTER 0 #define MONO_CONTEXT_SET_LLVM_EXC_REG(ctx, exc) do { (ctx)->regs [0] = (gsize)exc; } while (0) diff --git a/mono/mini/mini-arm64-gsharedvt.c b/mono/mini/mini-arm64-gsharedvt.c index d2b1d27f61..09be1a059e 100644 --- a/mono/mini/mini-arm64-gsharedvt.c +++ b/mono/mini/mini-arm64-gsharedvt.c @@ -18,8 +18,6 @@ */ #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED -#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1)) - void mono_arm_gsharedvt_init (void) { diff --git a/mono/mini/mini-arm64.c.REMOVED.git-id b/mono/mini/mini-arm64.c.REMOVED.git-id index ee1804b80b..10886312ce 100644 --- a/mono/mini/mini-arm64.c.REMOVED.git-id +++ b/mono/mini/mini-arm64.c.REMOVED.git-id @@ -1 +1 @@ -c075fc0459f19d3168cab466518d1d12b02717cf \ No newline at end of file +45fa96a2d8399ccc4f1fcf73152edfbf46b26445 \ No newline at end of file diff --git a/mono/mini/mini-arm64.h b/mono/mini/mini-arm64.h index 108fcd3160..a7681b3d62 100644 --- a/mono/mini/mini-arm64.h +++ b/mono/mini/mini-arm64.h @@ -42,7 +42,6 @@ #define MONO_ARCH_CALLEE_SAVED_FREGS 0xff00 #define MONO_ARCH_USE_FPSTACK FALSE -#define MONO_ARCH_FPSTACK_SIZE 0 #define MONO_ARCH_INST_SREG2_MASK(ins) (0) @@ -120,20 +119,16 @@ typedef struct { #define MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS 1 #define MONO_ARCH_NEED_DIV_CHECK 1 #define MONO_ARCH_EMULATE_MUL_OVF 1 -#define MONO_ARCH_HAVE_IMT 1 #define MONO_ARCH_HAVE_OP_TAIL_CALL 1 -#define MONO_ARCH_THIS_AS_FIRST_ARG 1 #define MONO_ARCH_RGCTX_REG ARMREG_R15 #define MONO_ARCH_IMT_REG MONO_ARCH_RGCTX_REG #define MONO_ARCH_VTABLE_REG ARMREG_R0 -#define MONO_ARCH_EXC_REG ARMREG_R0 -#define MONO_ARCH_HAVE_XP_UNWIND 1 -#define MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE 1 #define MONO_ARCH_HAVE_GENERALIZED_IMT_TRAMPOLINE 1 #define MONO_ARCH_USE_SIGACTION 1 #define MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX 1 #define MONO_ARCH_HAVE_CONTEXT_SET_INT_REG 1 #define MONO_ARCH_GSHARED_SUPPORTED 1 +#define MONO_ARCH_INTERPRETER_SUPPORTED 1 #define MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE 1 #define MONO_ARCH_AOT_SUPPORTED 1 #define MONO_ARCH_LLVM_SUPPORTED 1 @@ -147,16 +142,19 @@ typedef struct { #define MONO_ARCH_HAVE_SETUP_RESUME_FROM_SIGNAL_HANDLER_CTX 1 #define MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK 1 #define MONO_ARCH_HAVE_GENERAL_RGCTX_LAZY_FETCH_TRAMPOLINE 1 -#define MONO_ARCH_HAVE_OP_GET_EX_OBJ 1 #define MONO_ARCH_HAVE_OBJC_GET_SELECTOR 1 #define MONO_ARCH_HAVE_SDB_TRAMPOLINES 1 #define MONO_ARCH_HAVE_PATCH_CODE_NEW 1 #define MONO_ARCH_HAVE_OP_GENERIC_CLASS_INIT 1 #define MONO_ARCH_HAVE_OPCODE_NEEDS_EMULATION 1 #define MONO_ARCH_HAVE_DECOMPOSE_LONG_OPTS 1 - +#define MONO_ARCH_FLOAT32_SUPPORTED 1 #define MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP 1 +// Does the ABI have a volatile non-parameter register, so tailcall +// can pass context to generics or interfaces? +#define MONO_ARCH_HAVE_VOLATILE_NON_PARAM_REGISTER 1 + #ifdef TARGET_IOS #define MONO_ARCH_REDZONE_SIZE 128 diff --git a/mono/mini/mini-codegen.c b/mono/mini/mini-codegen.c index 090b3c914a..8961d630ad 100644 --- a/mono/mini/mini-codegen.c +++ b/mono/mini/mini-codegen.c @@ -502,7 +502,7 @@ mono_print_ins_index_strbuf (int i, MonoInst *ins) break; case OP_ISINST: case OP_CASTCLASS: - g_string_append_printf (sbuf, " %s", ins->klass->name); + g_string_append_printf (sbuf, " %s", m_class_get_name (ins->klass)); break; default: break; @@ -596,7 +596,11 @@ mono_print_ins_index_strbuf (int i, MonoInst *ins) case OP_VCALL2_MEMBASE: case OP_VOIDCALL: case OP_VOIDCALL_MEMBASE: - case OP_TAILCALL: { + case OP_TAILCALL: + case OP_TAILCALL_MEMBASE: + case OP_RCALL: + case OP_RCALL_REG: + case OP_RCALL_MEMBASE: { MonoCallInst *call = (MonoCallInst*)ins; GSList *list; @@ -1038,6 +1042,9 @@ alloc_general_reg (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **last, MonoIn if (val < 0) val = get_register_spilling (cfg, bb, last, ins, dest_mask, sym_reg, bank); +#ifdef MONO_ARCH_HAVE_TRACK_FPREGS + cfg->arch.used_fp_regs |= 1 << val; +#endif return val; } @@ -2725,9 +2732,9 @@ mini_type_is_hfa (MonoType *t, int *out_nfields, int *out_esize) if (!mini_type_is_hfa (ftype, &nested_nfields, &nested_esize)) return FALSE; if (nested_esize == 4) - ftype = &mono_defaults.single_class->byval_arg; + ftype = m_class_get_byval_arg (mono_defaults.single_class); else - ftype = &mono_defaults.double_class->byval_arg; + ftype = m_class_get_byval_arg (mono_defaults.double_class); if (prev_ftype && prev_ftype->type != ftype->type) return FALSE; prev_ftype = ftype; diff --git a/mono/mini/mini-exceptions.c b/mono/mini/mini-exceptions.c deleted file mode 100644 index 31e2b55b78..0000000000 --- a/mono/mini/mini-exceptions.c +++ /dev/null @@ -1,3440 +0,0 @@ -/** - * \file - * generic exception support - * - * Authors: - * Dietmar Maurer (dietmar@ximian.com) - * Mono Team (mono-list@lists.ximian.com) - * - * Copyright 2001-2003 Ximian, Inc. - * Copyright 2003-2008 Novell, Inc. - * Copyright 2011 Xamarin Inc (http://www.xamarin.com). - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -#include -#include -#include - -#ifdef HAVE_SIGNAL_H -#include -#endif - -#ifdef HAVE_EXECINFO_H -#include -#endif - -#ifdef HAVE_SYS_TYPES_H -#include -#endif - -#ifdef HAVE_SYS_WAIT_H -#include -#endif - -#ifdef HAVE_UNISTD_H -#include -#endif - -#ifdef HAVE_SYS_SYSCALL_H -#include -#endif - -#ifdef HAVE_SYS_PRCTL_H -#include -#endif - -#ifdef HAVE_UNWIND_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mini.h" -#include "trace.h" -#include "debugger-agent.h" -#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 -#include "mini-llvm-cpp.h" -#endif - -#ifdef TARGET_ARM -#include "mini-arm.h" -#endif - -#ifndef MONO_ARCH_CONTEXT_DEF -#define MONO_ARCH_CONTEXT_DEF -#endif - -/* - * Raw frame information is stored in MonoException.trace_ips as an IntPtr[]. - * This structure represents one entry. - * This should consists of pointers only. - */ -typedef struct -{ - gpointer ip; - gpointer generic_info; - /* Only for interpreter frames */ - MonoJitInfo *ji; -} ExceptionTraceIp; - -/* Number of words in trace_ips belonging to one entry */ -#define TRACE_IP_ENTRY_SIZE (sizeof (ExceptionTraceIp) / sizeof (gpointer)) - -static gpointer restore_context_func, call_filter_func; -static gpointer throw_exception_func, rethrow_exception_func; -static gpointer throw_corlib_exception_func; - -static void mono_walk_stack_full (MonoJitStackWalk func, MonoContext *start_ctx, MonoDomain *domain, MonoJitTlsData *jit_tls, MonoLMF *lmf, MonoUnwindOptions unwind_options, gpointer user_data); -static void mono_raise_exception_with_ctx (MonoException *exc, MonoContext *ctx); -static void mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data); -static gboolean mono_current_thread_has_handle_block_guard (void); -static gboolean mono_install_handler_block_guard (MonoThreadUnwindState *ctx); - -static gboolean -first_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer addr) -{ - gpointer **data = (gpointer **)addr; - - if (!frame->managed) - return FALSE; - - if (!ctx) { - // FIXME: Happens with llvm_only - *data = NULL; - return TRUE; - } - - *data = MONO_CONTEXT_GET_SP (ctx); - g_assert (*data); - return TRUE; -} - -static gpointer -mono_thread_get_managed_sp (void) -{ - gpointer addr = NULL; - mono_walk_stack (first_managed, MONO_UNWIND_SIGNAL_SAFE, &addr); - return addr; -} - -static inline void -mini_clear_abort_threshold (void) -{ - MonoJitTlsData *jit_tls = mono_get_jit_tls (); - jit_tls->abort_exc_stack_threshold = NULL; -} - -static inline void -mini_set_abort_threshold (MonoContext *ctx) -{ - gpointer sp = MONO_CONTEXT_GET_SP (ctx); - MonoJitTlsData *jit_tls = mono_get_jit_tls (); - // Only move it up, to avoid thrown/caught - // exceptions lower in the stack from triggering - // a rethrow - gboolean above_threshold = (gsize) sp >= (gsize) jit_tls->abort_exc_stack_threshold; - if (!jit_tls->abort_exc_stack_threshold || above_threshold) { - jit_tls->abort_exc_stack_threshold = sp; - } -} - -// Note: In the case that the frame is above where the thread abort -// was set we bump the threshold so that functions called from the new, -// higher threshold don't trigger the thread abort exception -static inline gboolean -mini_above_abort_threshold (void) -{ - gpointer sp = mono_thread_get_managed_sp (); - MonoJitTlsData *jit_tls = (MonoJitTlsData*) mono_tls_get_jit_tls (); - - if (!sp) - return TRUE; - - gboolean above_threshold = (gsize) sp >= (gsize) jit_tls->abort_exc_stack_threshold; - - if (above_threshold) - jit_tls->abort_exc_stack_threshold = sp; - - return above_threshold; -} - -static int -mono_get_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset) -{ - SeqPoint sp; - if (mono_find_prev_seq_point_for_native_offset (domain, method, native_offset, NULL, &sp)) - return sp.il_offset; - return -1; -} - -void -mono_exceptions_init (void) -{ - MonoRuntimeExceptionHandlingCallbacks cbs; - if (mono_aot_only) { - restore_context_func = mono_aot_get_trampoline ("restore_context"); - call_filter_func = mono_aot_get_trampoline ("call_filter"); - throw_exception_func = mono_aot_get_trampoline ("throw_exception"); - rethrow_exception_func = mono_aot_get_trampoline ("rethrow_exception"); - } else { - MonoTrampInfo *info; - - restore_context_func = mono_arch_get_restore_context (&info, FALSE); - mono_tramp_info_register (info, NULL); - call_filter_func = mono_arch_get_call_filter (&info, FALSE); - mono_tramp_info_register (info, NULL); - throw_exception_func = mono_arch_get_throw_exception (&info, FALSE); - mono_tramp_info_register (info, NULL); - rethrow_exception_func = mono_arch_get_rethrow_exception (&info, FALSE); - mono_tramp_info_register (info, NULL); - } - -#ifdef MONO_ARCH_HAVE_EXCEPTIONS_INIT - mono_arch_exceptions_init (); -#endif - if (mono_use_interpreter) - cbs.mono_walk_stack_with_ctx = mini_get_interp_callbacks ()->walk_stack_with_ctx; - else - cbs.mono_walk_stack_with_ctx = mono_runtime_walk_stack_with_ctx; - - cbs.mono_walk_stack_with_state = mono_walk_stack_with_state; - - if (mono_llvm_only) { - cbs.mono_raise_exception = mono_llvm_raise_exception; - cbs.mono_reraise_exception = mono_llvm_reraise_exception; - } else { - cbs.mono_raise_exception = (void (*)(MonoException *))mono_get_throw_exception (); - cbs.mono_reraise_exception = (void (*)(MonoException *))mono_get_rethrow_exception (); - } - cbs.mono_raise_exception_with_ctx = mono_raise_exception_with_ctx; - cbs.mono_exception_walk_trace = mono_exception_walk_trace; - cbs.mono_install_handler_block_guard = mono_install_handler_block_guard; - cbs.mono_current_thread_has_handle_block_guard = mono_current_thread_has_handle_block_guard; - cbs.mono_clear_abort_threshold = mini_clear_abort_threshold; - cbs.mono_above_abort_threshold = mini_above_abort_threshold; - mono_install_eh_callbacks (&cbs); - mono_install_get_seq_point (mono_get_seq_point_for_native_offset); -} - -gpointer -mono_get_throw_exception (void) -{ - g_assert (throw_exception_func); - return throw_exception_func; -} - -gpointer -mono_get_rethrow_exception (void) -{ - g_assert (rethrow_exception_func); - return rethrow_exception_func; -} - -gpointer -mono_get_call_filter (void) -{ - g_assert (call_filter_func); - return call_filter_func; -} - -gpointer -mono_get_restore_context (void) -{ - g_assert (restore_context_func); - return restore_context_func; -} - -gpointer -mono_get_throw_corlib_exception (void) -{ - gpointer code = NULL; - MonoTrampInfo *info; - - /* This depends on corlib classes so cannot be inited in mono_exceptions_init () */ - if (throw_corlib_exception_func) - return throw_corlib_exception_func; - - if (mono_aot_only) - code = mono_aot_get_trampoline ("throw_corlib_exception"); - else { - code = mono_arch_get_throw_corlib_exception (&info, FALSE); - mono_tramp_info_register (info, NULL); - } - - mono_memory_barrier (); - - throw_corlib_exception_func = code; - - return throw_corlib_exception_func; -} - -/* - * mono_get_throw_exception_addr: - * - * Return an address which stores the result of - * mono_get_throw_exception. - */ -gpointer -mono_get_throw_exception_addr (void) -{ - return &throw_exception_func; -} - -static gboolean -is_address_protected (MonoJitInfo *ji, MonoJitExceptionInfo *ei, gpointer ip) -{ - MonoTryBlockHoleTableJitInfo *table; - int i; - guint32 offset; - guint16 clause; - - if (ei->try_start > ip || ip >= ei->try_end) - return FALSE; - - if (!ji->has_try_block_holes) - return TRUE; - - table = mono_jit_info_get_try_block_hole_table_info (ji); - offset = (guint32)((char*)ip - (char*)ji->code_start); - clause = (guint16)(ei - ji->clauses); - g_assert (clause < ji->num_clauses); - - for (i = 0; i < table->num_holes; ++i) { - MonoTryBlockHoleJitInfo *hole = &table->holes [i]; - if (hole->clause == clause && hole->offset <= offset && hole->offset + hole->length > offset) - return FALSE; - } - return TRUE; -} - -#ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE - -#if 0 -static gboolean show_native_addresses = TRUE; -#else -static gboolean show_native_addresses = FALSE; -#endif - -static _Unwind_Reason_Code -build_stack_trace (struct _Unwind_Context *frame_ctx, void *state) -{ - MonoDomain *domain = mono_domain_get (); - uintptr_t ip = _Unwind_GetIP (frame_ctx); - - if (show_native_addresses || mono_jit_info_table_find (domain, (char*)ip)) { - GList **trace_ips = (GList **)state; - *trace_ips = g_list_prepend (*trace_ips, (gpointer)ip); - } - - return _URC_NO_REASON; -} - -static GSList* -get_unwind_backtrace (void) -{ - GSList *ips = NULL; - - _Unwind_Backtrace (build_stack_trace, &ips); - - return g_slist_reverse (ips); -} - -#else - -static GSList* -get_unwind_backtrace (void) -{ - return NULL; -} - -#endif - -static gboolean -arch_unwind_frame (MonoDomain *domain, MonoJitTlsData *jit_tls, - MonoJitInfo *ji, MonoContext *ctx, - MonoContext *new_ctx, MonoLMF **lmf, - mgreg_t **save_locations, - StackFrameInfo *frame) -{ - if (!ji && *lmf) { - if (((guint64)(*lmf)->previous_lmf) & 2) { - MonoLMFExt *ext = (MonoLMFExt*)(*lmf); - - memset (frame, 0, sizeof (StackFrameInfo)); - frame->ji = ji; - - *new_ctx = *ctx; - - if (ext->debugger_invoke) { - /* - * This LMF entry is created by the soft debug code to mark transitions to - * managed code done during invokes. - */ - frame->type = FRAME_TYPE_DEBUGGER_INVOKE; - memcpy (new_ctx, &ext->ctx, sizeof (MonoContext)); - } else if (ext->interp_exit) { - frame->type = FRAME_TYPE_INTERP_TO_MANAGED; - frame->interp_exit_data = ext->interp_exit_data; - } else { - g_assert_not_reached (); - } - - *lmf = (MonoLMF *)(((guint64)(*lmf)->previous_lmf) & ~3); - - return TRUE; - } - } - - return mono_arch_unwind_frame (domain, jit_tls, ji, ctx, new_ctx, lmf, save_locations, frame); -} - -/* - * find_jit_info: - * - * Translate between the mono_arch_unwind_frame function and the old API. - */ -static MonoJitInfo * -find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx, - MonoContext *new_ctx, MonoLMF **lmf, gboolean *managed) -{ - StackFrameInfo frame; - MonoJitInfo *ji; - gboolean err; - gpointer ip = MONO_CONTEXT_GET_IP (ctx); - - /* Avoid costly table lookup during stack overflow */ - if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size))) - ji = prev_ji; - else - ji = mini_jit_info_table_find (domain, (char *)ip, NULL); - - if (managed) - *managed = FALSE; - - err = arch_unwind_frame (domain, jit_tls, ji, ctx, new_ctx, lmf, NULL, &frame); - if (!err) - return (MonoJitInfo *)-1; - - if (*lmf && ((*lmf) != jit_tls->first_lmf) && ((gpointer)MONO_CONTEXT_GET_SP (new_ctx) >= (gpointer)(*lmf))) { - /* - * Remove any unused lmf. - * Mask out the lower bits which might be used to hold additional information. - */ - *lmf = (MonoLMF *)(((gsize)(*lmf)->previous_lmf) & ~(SIZEOF_VOID_P -1)); - } - - /* Convert between the new and the old APIs */ - switch (frame.type) { - case FRAME_TYPE_MANAGED: - if (managed) - *managed = TRUE; - return frame.ji; - case FRAME_TYPE_TRAMPOLINE: - return frame.ji; - case FRAME_TYPE_MANAGED_TO_NATIVE: - if (frame.ji) - return frame.ji; - else { - memset (res, 0, sizeof (MonoJitInfo)); - res->d.method = frame.method; - return res; - } - case FRAME_TYPE_DEBUGGER_INVOKE: { - MonoContext tmp_ctx; - - /* - * The normal exception handling code can't handle this frame, so just - * skip it. - */ - ji = find_jit_info (domain, jit_tls, res, NULL, new_ctx, &tmp_ctx, lmf, managed); - memcpy (new_ctx, &tmp_ctx, sizeof (MonoContext)); - return ji; - } - default: - g_assert_not_reached (); - return NULL; - } -} - -/* mono_find_jit_info: - * - * This function is used to gather information from @ctx. It return the - * MonoJitInfo of the corresponding function, unwinds one stack frame and - * stores the resulting context into @new_ctx. It also stores a string - * describing the stack location into @trace (if not NULL), and modifies - * the @lmf if necessary. @native_offset return the IP offset from the - * start of the function or -1 if that info is not available. - */ -MonoJitInfo * -mono_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx, - MonoContext *new_ctx, char **trace, MonoLMF **lmf, int *native_offset, - gboolean *managed) -{ - gboolean managed2; - gpointer ip = MONO_CONTEXT_GET_IP (ctx); - MonoJitInfo *ji; - MonoMethod *method = NULL; - - if (trace) - *trace = NULL; - - if (native_offset) - *native_offset = -1; - - if (managed) - *managed = FALSE; - - ji = find_jit_info (domain, jit_tls, res, prev_ji, ctx, new_ctx, lmf, &managed2); - - if (ji == (gpointer)-1) - return ji; - - if (ji && !ji->is_trampoline) - method = jinfo_get_method (ji); - - if (managed2 || (method && method->wrapper_type)) { - const char *real_ip, *start; - gint32 offset; - - start = (const char *)ji->code_start; - if (!managed2) - /* ctx->ip points into native code */ - real_ip = (const char*)MONO_CONTEXT_GET_IP (new_ctx); - else - real_ip = (const char*)ip; - - if ((real_ip >= start) && (real_ip <= start + ji->code_size)) - offset = real_ip - start; - else - offset = -1; - - if (native_offset) - *native_offset = offset; - - if (managed) - if (!method->wrapper_type || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) - *managed = TRUE; - - if (trace) - *trace = mono_debug_print_stack_frame (method, offset, domain); - } else { - if (trace) { - char *fname = mono_method_full_name (jinfo_get_method (res), TRUE); - *trace = g_strdup_printf ("in (unmanaged) %s", fname); - g_free (fname); - } - } - - return ji; -} - -/* - * mono_find_jit_info_ext: - * - * A version of mono_find_jit_info which returns all data in the StackFrameInfo - * structure. - * A note about frames of type FRAME_TYPE_MANAGED_TO_NATIVE: - * - These frames are used to mark managed-to-native transitions, so CTX will refer to native - * code, and new_ctx will refer to the last managed frame. The caller should unwind once more - * to obtain the last managed frame. - * If SAVE_LOCATIONS is not NULL, it should point to an array of size MONO_MAX_IREGS. - * On return, it will be filled with the locations where callee saved registers are saved - * by the current frame. This is returned outside of StackFrameInfo because it can be - * quite large on some platforms. - * If ASYNC true, this function will be async safe, but some fields of frame and frame->ji will - * not be set. - */ -gboolean -mono_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls, - MonoJitInfo *prev_ji, MonoContext *ctx, - MonoContext *new_ctx, char **trace, MonoLMF **lmf, - mgreg_t **save_locations, - StackFrameInfo *frame) -{ - gboolean err; - gpointer ip = MONO_CONTEXT_GET_IP (ctx); - MonoJitInfo *ji; - MonoDomain *target_domain = domain; - MonoMethod *method = NULL; - gboolean async = mono_thread_info_is_async_context (); - - if (trace) - *trace = NULL; - - /* Avoid costly table lookup during stack overflow */ - if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size))) - ji = prev_ji; - else - ji = mini_jit_info_table_find_ext (domain, (char *)ip, TRUE, &target_domain); - - if (!target_domain) - target_domain = domain; - - if (save_locations) - memset (save_locations, 0, MONO_MAX_IREGS * sizeof (mgreg_t*)); - - err = arch_unwind_frame (target_domain, jit_tls, ji, ctx, new_ctx, lmf, save_locations, frame); - if (!err) - return FALSE; - - if (frame->type != FRAME_TYPE_INTERP_TO_MANAGED && *lmf && ((*lmf) != jit_tls->first_lmf) && ((gpointer)MONO_CONTEXT_GET_SP (new_ctx) >= (gpointer)(*lmf))) { - /* - * Remove any unused lmf. - * Mask out the lower bits which might be used to hold additional information. - */ - *lmf = (MonoLMF *)(((gsize)(*lmf)->previous_lmf) & ~(SIZEOF_VOID_P -1)); - } - - if (frame->ji && !frame->ji->is_trampoline && !frame->ji->async) - method = jinfo_get_method (frame->ji); - - if (frame->type == FRAME_TYPE_MANAGED && method) { - if (!method->wrapper_type || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) - frame->managed = TRUE; - } - - if (frame->type == FRAME_TYPE_MANAGED_TO_NATIVE) { - /* - * This type of frame is just a marker, the caller should unwind once more to get the - * last managed frame. - */ - frame->ji = NULL; - frame->method = NULL; - } - - frame->native_offset = -1; - frame->domain = target_domain; - frame->async_context = async; - frame->frame_addr = MONO_CONTEXT_GET_SP (ctx); - - ji = frame->ji; - - if (frame->type == FRAME_TYPE_MANAGED) - frame->method = method; - - if (ji && (frame->managed || (method && method->wrapper_type))) { - const char *real_ip, *start; - - start = (const char *)ji->code_start; - if (frame->type == FRAME_TYPE_MANAGED) - real_ip = (const char*)ip; - else - /* ctx->ip points into native code */ - real_ip = (const char*)MONO_CONTEXT_GET_IP (new_ctx); - - if ((real_ip >= start) && (real_ip <= start + ji->code_size)) - frame->native_offset = real_ip - start; - else { - frame->native_offset = -1; - } - - if (trace) - *trace = mono_debug_print_stack_frame (method, frame->native_offset, domain); - } else { - if (trace && frame->method) { - char *fname = mono_method_full_name (frame->method, TRUE); - *trace = g_strdup_printf ("in (unmanaged) %s", fname); - g_free (fname); - } - } - - return TRUE; -} - -typedef struct { - gboolean in_interp; - MonoInterpStackIter interp_iter; - gpointer last_frame_addr; -} Unwinder; - -static void -unwinder_init (Unwinder *unwinder) -{ - memset (unwinder, 0, sizeof (Unwinder)); -} - -#if defined(__GNUC__) && defined(TARGET_ARM64) -/* gcc 4.9.2 seems to miscompile this on arm64 */ -static __attribute__((optimize("O0"))) gboolean -#else -static gboolean -#endif -unwinder_unwind_frame (Unwinder *unwinder, - MonoDomain *domain, MonoJitTlsData *jit_tls, - MonoJitInfo *prev_ji, MonoContext *ctx, - MonoContext *new_ctx, char **trace, MonoLMF **lmf, - mgreg_t **save_locations, - StackFrameInfo *frame) -{ - gpointer parent; - if (unwinder->in_interp) { - memcpy (new_ctx, ctx, sizeof (MonoContext)); - - /* Process debugger invokes */ - /* The DEBUGGER_INVOKE should be returned before the first interpreter frame for the invoke */ - if (unwinder->last_frame_addr > (gpointer)(*lmf)) { - if (((guint64)(*lmf)->previous_lmf) & 2) { - MonoLMFExt *ext = (MonoLMFExt*)(*lmf); - if (ext->debugger_invoke) { - *lmf = (MonoLMF *)(((guint64)(*lmf)->previous_lmf) & ~7); - frame->type = FRAME_TYPE_DEBUGGER_INVOKE; - return TRUE; - } - } - } - - unwinder->in_interp = mini_get_interp_callbacks ()->frame_iter_next (&unwinder->interp_iter, frame); - if (frame->type == FRAME_TYPE_INTERP) { - parent = mini_get_interp_callbacks ()->frame_get_parent (frame->interp_frame); - unwinder->last_frame_addr = parent; - } - if (!unwinder->in_interp) - return unwinder_unwind_frame (unwinder, domain, jit_tls, prev_ji, ctx, new_ctx, trace, lmf, save_locations, frame); - return TRUE; - } else { - gboolean res = mono_find_jit_info_ext (domain, jit_tls, prev_ji, ctx, new_ctx, trace, lmf, - save_locations, frame); - if (!res) - return FALSE; - if (frame->type == FRAME_TYPE_INTERP_TO_MANAGED) { - unwinder->in_interp = TRUE; - mini_get_interp_callbacks ()->frame_iter_init (&unwinder->interp_iter, frame->interp_exit_data); - parent = mini_get_interp_callbacks ()->frame_get_parent (frame->interp_exit_data); - MONO_CONTEXT_SET_SP (new_ctx, parent); - } - unwinder->last_frame_addr = frame->frame_addr; - return TRUE; - } -} - -/* - * This function is async-safe. - */ -static gpointer -get_generic_info_from_stack_frame (MonoJitInfo *ji, MonoContext *ctx) -{ - MonoGenericJitInfo *gi; - MonoMethod *method; - gpointer info; - - if (!ji->has_generic_jit_info) - return NULL; - gi = mono_jit_info_get_generic_jit_info (ji); - if (!gi->has_this) - return NULL; - - info = NULL; - /* - * Search location list if available, it contains the precise location of the - * argument for every pc offset, even if the method was interrupted while it was in - * its prolog. - */ - if (gi->nlocs) { - int offset = (mgreg_t)MONO_CONTEXT_GET_IP (ctx) - (mgreg_t)ji->code_start; - int i; - - for (i = 0; i < gi->nlocs; ++i) { - MonoDwarfLocListEntry *entry = &gi->locations [i]; - - if (offset >= entry->from && (offset < entry->to || entry->to == 0)) { - if (entry->is_reg) - info = (gpointer)mono_arch_context_get_int_reg (ctx, entry->reg); - else - info = *(gpointer*)(gpointer)((char*)mono_arch_context_get_int_reg (ctx, entry->reg) + entry->offset); - break; - } - } - g_assert (i < gi->nlocs); - } else { - if (gi->this_in_reg) - info = (gpointer)mono_arch_context_get_int_reg (ctx, gi->this_reg); - else - info = *(gpointer*)(gpointer)((char*)mono_arch_context_get_int_reg (ctx, gi->this_reg) + - gi->this_offset); - } - - method = jinfo_get_method (ji); - if (mono_method_get_context (method)->method_inst) { - /* A MonoMethodRuntimeGenericContext* */ - return info; - } else if ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype) { - /* A MonoVTable* */ - return info; - } else { - /* Avoid returning a managed object */ - MonoObject *this_obj = (MonoObject *)info; - - return this_obj->vtable; - } -} - -/* - * generic_info is either a MonoMethodRuntimeGenericContext or a MonoVTable. - */ -static MonoGenericContext -get_generic_context_from_stack_frame (MonoJitInfo *ji, gpointer generic_info) -{ - MonoGenericContext context = { NULL, NULL }; - MonoClass *klass, *method_container_class; - MonoMethod *method; - - g_assert (generic_info); - - method = jinfo_get_method (ji); - g_assert (method->is_inflated); - if (mono_method_get_context (method)->method_inst) { - MonoMethodRuntimeGenericContext *mrgctx = (MonoMethodRuntimeGenericContext *)generic_info; - - klass = mrgctx->class_vtable->klass; - context.method_inst = mrgctx->method_inst; - g_assert (context.method_inst); - } else { - MonoVTable *vtable = (MonoVTable *)generic_info; - - klass = vtable->klass; - } - - //g_assert (!mono_class_is_gtd (method->klass)); - if (mono_class_is_ginst (method->klass)) - method_container_class = mono_class_get_generic_class (method->klass)->container_class; - else - method_container_class = method->klass; - - /* class might refer to a subclass of method's class */ - while (!(klass == method->klass || (mono_class_is_ginst (klass) && mono_class_get_generic_class (klass)->container_class == method_container_class))) { - klass = klass->parent; - g_assert (klass); - } - - if (mono_class_is_ginst (klass) || mono_class_is_gtd (klass)) - context.class_inst = mini_class_get_context (klass)->class_inst; - - if (mono_class_is_ginst (klass)) - g_assert (mono_class_has_parent_and_ignore_generics (mono_class_get_generic_class (klass)->container_class, method_container_class)); - else - g_assert (mono_class_has_parent_and_ignore_generics (klass, method_container_class)); - - return context; -} - -static MonoMethod* -get_method_from_stack_frame (MonoJitInfo *ji, gpointer generic_info) -{ - ERROR_DECL (error); - MonoGenericContext context; - MonoMethod *method; - - if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this) - return jinfo_get_method (ji); - context = get_generic_context_from_stack_frame (ji, generic_info); - - method = jinfo_get_method (ji); - method = mono_method_get_declaring_generic_method (method); - method = mono_class_inflate_generic_method_checked (method, &context, error); - g_assert (mono_error_ok (error)); /* FIXME don't swallow the error */ - - return method; -} - -/** - * mono_exception_walk_native_trace: - * \param ex The exception object whose frames should be walked - * \param func callback to call for each stack frame - * \param user_data data passed to the callback - * This function walks the stacktrace of an exception. For - * each frame the callback function is called with the relevant info. - * The walk ends when no more stack frames are found or when the callback - * returns a TRUE value. - */ - -gboolean -mono_exception_walk_trace (MonoException *ex, MonoExceptionFrameWalk func, gpointer user_data) -{ - MONO_REQ_GC_UNSAFE_MODE; - - MonoDomain *domain = mono_domain_get (); - MonoArray *ta = ex->trace_ips; - int len, i; - - if (ta == NULL) - return FALSE; - - len = mono_array_length (ta) / TRACE_IP_ENTRY_SIZE; - for (i = 0; i < len; i++) { - ExceptionTraceIp trace_ip; - - memcpy (&trace_ip, mono_array_addr_fast (ta, ExceptionTraceIp, i), sizeof (ExceptionTraceIp)); - gpointer ip = trace_ip.ip; - gpointer generic_info = trace_ip.generic_info; - MonoJitInfo *ji = mono_jit_info_table_find (domain, (char *)ip); - - if (ji == NULL) { - if (func (NULL, ip, 0, FALSE, user_data)) - return TRUE; - } else { - MonoMethod *method = get_method_from_stack_frame (ji, generic_info); - if (func (method, ji->code_start, (char *) ip - (char *) ji->code_start, TRUE, user_data)) - return TRUE; - } - } - - return len > 0; -} - -MonoArray * -ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info) -{ - ERROR_DECL (error); - MonoDomain *domain = mono_domain_get (); - MonoArray *res; - MonoArray *ta = exc->trace_ips; - MonoDebugSourceLocation *location; - int i, len; - - if (ta == NULL) { - /* Exception is not thrown yet */ - res = mono_array_new_checked (domain, mono_defaults.stack_frame_class, 0, error); - mono_error_set_pending_exception (error); - return res; - } - - len = mono_array_length (ta) / TRACE_IP_ENTRY_SIZE; - - res = mono_array_new_checked (domain, mono_defaults.stack_frame_class, len > skip ? len - skip : 0, error); - if (mono_error_set_pending_exception (error)) - return NULL; - - for (i = skip; i < len; i++) { - MonoJitInfo *ji; - MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, error); - if (!mono_error_ok (error)) { - mono_error_set_pending_exception (error); - return NULL; - } - ExceptionTraceIp trace_ip; - memcpy (&trace_ip, mono_array_addr_fast (ta, ExceptionTraceIp, i), sizeof (ExceptionTraceIp)); - gpointer ip = trace_ip.ip; - gpointer generic_info = trace_ip.generic_info; - MonoMethod *method; - - if (trace_ip.ji) { - ji = trace_ip.ji; - } else { - ji = mono_jit_info_table_find (domain, (char *)ip); - if (ji == NULL) { - /* Unmanaged frame */ - mono_array_setref (res, i, sf); - continue; - } - } - - g_assert (ji != NULL); - - if (mono_llvm_only || !generic_info) - /* Can't resolve actual method */ - method = jinfo_get_method (ji); - else - method = get_method_from_stack_frame (ji, generic_info); - if (jinfo_get_method (ji)->wrapper_type) { - char *s; - - sf->method = NULL; - s = mono_method_get_name_full (method, TRUE, FALSE, MONO_TYPE_NAME_FORMAT_REFLECTION); - MonoString *name = mono_string_new_checked (domain, s, error); - g_free (s); - if (!is_ok (error)) { - mono_error_set_pending_exception (error); - return NULL; - } - MONO_OBJECT_SETREF (sf, internal_method_name, name); - } - else { - MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error); - if (!mono_error_ok (error)) { - mono_error_set_pending_exception (error); - return NULL; - } - MONO_OBJECT_SETREF (sf, method, rm); - } - - sf->method_index = ji->from_aot ? mono_aot_find_method_index (method) : 0xffffff; - sf->method_address = (gsize) ji->code_start; - sf->native_offset = (char *)ip - (char *)ji->code_start; - - /* - * mono_debug_lookup_source_location() returns both the file / line number information - * and the IL offset. Note that computing the IL offset is already an expensive - * operation, so we shouldn't call this method twice. - */ - location = mono_debug_lookup_source_location (jinfo_get_method (ji), sf->native_offset, domain); - if (location) { - sf->il_offset = location->il_offset; - } else { - SeqPoint sp; - if (mono_find_prev_seq_point_for_native_offset (domain, jinfo_get_method (ji), sf->native_offset, NULL, &sp)) - sf->il_offset = sp.il_offset; - else - sf->il_offset = -1; - } - - if (need_file_info) { - if (location && location->source_file) { - MonoString *filename = mono_string_new_checked (domain, location->source_file, error); - if (!is_ok (error)) { - mono_error_set_pending_exception (error); - return NULL; - } - MONO_OBJECT_SETREF (sf, filename, filename); - sf->line = location->row; - sf->column = location->column; - } else { - sf->line = sf->column = 0; - sf->filename = NULL; - } - } - - mono_debug_free_source_location (location); - mono_array_setref (res, i, sf); - } - - return res; -} - -static void -mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data) -{ - if (!start_ctx) { - MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls (); - if (jit_tls && jit_tls->orig_ex_ctx_set) - start_ctx = &jit_tls->orig_ex_ctx; - } - mono_walk_stack_with_ctx (func, start_ctx, unwind_options, user_data); -} -/** - * mono_walk_stack_with_ctx: - * Unwind the current thread starting at \p start_ctx. - * If \p start_ctx is null, we capture the current context. - */ -void -mono_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data) -{ - MonoContext extra_ctx; - MonoThreadInfo *thread = mono_thread_info_current_unchecked (); - MONO_ARCH_CONTEXT_DEF - - if (!thread || !thread->jit_data) - return; - - if (!start_ctx) { - mono_arch_flush_register_windows (); - -#ifdef MONO_INIT_CONTEXT_FROM_CURRENT - MONO_INIT_CONTEXT_FROM_CURRENT (&extra_ctx); -#else - MONO_INIT_CONTEXT_FROM_FUNC (&extra_ctx, mono_walk_stack_with_ctx); -#endif - start_ctx = &extra_ctx; - } - - mono_walk_stack_full (func, start_ctx, mono_domain_get (), (MonoJitTlsData *)thread->jit_data, mono_get_lmf (), unwind_options, user_data); -} - -/** - * mono_walk_stack_with_state: - * Unwind a thread described by \p state. - * - * State must be valid (state->valid == TRUE). - * - * If you are using this function to unwind another thread, make sure it is suspended. - * - * If \p state is null, we capture the current context. - */ -void -mono_walk_stack_with_state (MonoJitStackWalk func, MonoThreadUnwindState *state, MonoUnwindOptions unwind_options, void *user_data) -{ - MonoThreadUnwindState extra_state; - if (!state) { - g_assert (!mono_thread_info_is_async_context ()); - if (!mono_thread_state_init_from_current (&extra_state)) - return; - state = &extra_state; - } - - g_assert (state->valid); - - if (!state->unwind_data [MONO_UNWIND_DATA_DOMAIN]) - /* Not attached */ - return; - - mono_walk_stack_full (func, - &state->ctx, - (MonoDomain *)state->unwind_data [MONO_UNWIND_DATA_DOMAIN], - (MonoJitTlsData *)state->unwind_data [MONO_UNWIND_DATA_JIT_TLS], - (MonoLMF *)state->unwind_data [MONO_UNWIND_DATA_LMF], - unwind_options, user_data); -} - -void -mono_walk_stack (MonoJitStackWalk func, MonoUnwindOptions options, void *user_data) -{ - MonoThreadUnwindState state; - if (!mono_thread_state_init_from_current (&state)) - return; - mono_walk_stack_with_state (func, &state, options, user_data); -} - -/** - * mono_walk_stack_full: - * \param func callback to call for each stack frame - * \param domain starting appdomain, can be NULL to use the current domain - * \param unwind_options what extra information the unwinder should gather - * \param start_ctx starting state of the stack walk, can be NULL. - * \param thread the thread whose stack to walk, can be NULL to use the current thread - * \param lmf the LMF of \p thread, can be NULL to use the LMF of the current thread - * \param user_data data passed to the callback - * This function walks the stack of a thread, starting from the state - * represented by \p start_ctx. For each frame the callback - * function is called with the relevant info. The walk ends when no more - * managed stack frames are found or when the callback returns a TRUE value. - */ -static void -mono_walk_stack_full (MonoJitStackWalk func, MonoContext *start_ctx, MonoDomain *domain, MonoJitTlsData *jit_tls, MonoLMF *lmf, MonoUnwindOptions unwind_options, gpointer user_data) -{ - gint il_offset, i; - MonoContext ctx, new_ctx; - StackFrameInfo frame; - gboolean res; - mgreg_t *reg_locations [MONO_MAX_IREGS]; - mgreg_t *new_reg_locations [MONO_MAX_IREGS]; - gboolean get_reg_locations = unwind_options & MONO_UNWIND_REG_LOCATIONS; - gboolean async = mono_thread_info_is_async_context (); - Unwinder unwinder; - - if (mono_llvm_only) { - GSList *l, *ips; - - if (async) - return; - - ips = get_unwind_backtrace (); - for (l = ips; l; l = l->next) { - guint8 *ip = (guint8*)l->data; - memset (&frame, 0, sizeof (StackFrameInfo)); - frame.ji = mini_jit_info_table_find (domain, (char*)ip, &frame.domain); - if (!frame.ji || frame.ji->is_trampoline) - continue; - frame.type = FRAME_TYPE_MANAGED; - frame.method = jinfo_get_method (frame.ji); - // FIXME: Cannot lookup the actual method - frame.actual_method = frame.method; - if (frame.type == FRAME_TYPE_MANAGED) { - if (!frame.method->wrapper_type || frame.method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) - frame.managed = TRUE; - } - frame.native_offset = ip - (guint8*)frame.ji->code_start; - frame.il_offset = -1; - - if (func (&frame, NULL, user_data)) - break; - } - g_free (ips); - return; - } - - g_assert (start_ctx); - g_assert (domain); - g_assert (jit_tls); - /*The LMF will be null if the target have no managed frames.*/ - /* g_assert (lmf); */ - - if (async) - g_assert (unwind_options == MONO_UNWIND_NONE); - - memcpy (&ctx, start_ctx, sizeof (MonoContext)); - memset (reg_locations, 0, sizeof (reg_locations)); - - unwinder_init (&unwinder); - - while (MONO_CONTEXT_GET_SP (&ctx) < jit_tls->end_of_stack) { - frame.lmf = lmf; - res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, get_reg_locations ? new_reg_locations : NULL, &frame); - if (!res) - return; - - if (frame.type == FRAME_TYPE_TRAMPOLINE) - goto next; - - if ((unwind_options & MONO_UNWIND_LOOKUP_IL_OFFSET) && frame.ji) { - MonoDebugSourceLocation *source; - - source = mono_debug_lookup_source_location (jinfo_get_method (frame.ji), frame.native_offset, domain); - if (source) { - il_offset = source->il_offset; - } else { - SeqPoint sp; - if (mono_find_prev_seq_point_for_native_offset (domain, jinfo_get_method (frame.ji), frame.native_offset, NULL, &sp)) - il_offset = sp.il_offset; - else - il_offset = -1; - } - mono_debug_free_source_location (source); - } else - il_offset = -1; - - frame.il_offset = il_offset; - - if ((unwind_options & MONO_UNWIND_LOOKUP_ACTUAL_METHOD) && frame.ji) { - frame.actual_method = get_method_from_stack_frame (frame.ji, get_generic_info_from_stack_frame (frame.ji, &ctx)); - } else { - frame.actual_method = frame.method; - } - - if (get_reg_locations) - frame.reg_locations = reg_locations; - - if (func (&frame, &ctx, user_data)) - return; - -next: - if (get_reg_locations) { - for (i = 0; i < MONO_MAX_IREGS; ++i) - if (new_reg_locations [i]) - reg_locations [i] = new_reg_locations [i]; - } - - ctx = new_ctx; - } -} - -MonoBoolean -ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info, - MonoReflectionMethod **method, - gint32 *iloffset, gint32 *native_offset, - MonoString **file, gint32 *line, gint32 *column) -{ - ERROR_DECL (error); - MonoDomain *domain = mono_domain_get (); - MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls (); - MonoLMF *lmf = mono_get_lmf (); - MonoJitInfo *ji = NULL; - MonoContext ctx, new_ctx; - MonoDebugSourceLocation *location; - MonoMethod *jmethod = NULL, *actual_method; - StackFrameInfo frame; - gboolean res; - Unwinder unwinder; - int il_offset = -1; - - MONO_ARCH_CONTEXT_DEF; - - if (mono_llvm_only) { - GSList *l, *ips; - MonoDomain *frame_domain; - guint8 *frame_ip = NULL; - - /* FIXME: Generalize this code with an interface which returns an array of StackFrame structures */ - jmethod = NULL; - ips = get_unwind_backtrace (); - for (l = ips; l && skip >= 0; l = l->next) { - guint8 *ip = (guint8*)l->data; - - frame_ip = ip; - - ji = mini_jit_info_table_find (mono_domain_get (), (char*)ip, &frame_domain); - if (!ji || ji->is_trampoline) - continue; - - /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */ - jmethod = jinfo_get_method (ji); - if (jmethod->wrapper_type != MONO_WRAPPER_NONE && jmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD && jmethod->wrapper_type != MONO_WRAPPER_MANAGED_TO_NATIVE) - continue; - skip--; - } - g_slist_free (ips); - if (!jmethod || !l) - return FALSE; - /* No way to resolve generic instances */ - actual_method = jmethod; - *native_offset = frame_ip - (guint8*)ji->code_start; - } else { - mono_arch_flush_register_windows (); - -#ifdef MONO_INIT_CONTEXT_FROM_CURRENT - MONO_INIT_CONTEXT_FROM_CURRENT (&ctx); -#else - MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_get_frame_info); -#endif - - unwinder_init (&unwinder); - - new_ctx = ctx; - do { - ctx = new_ctx; - res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, &frame); - if (!res) - return FALSE; - switch (frame.type) { - case FRAME_TYPE_MANAGED_TO_NATIVE: - case FRAME_TYPE_DEBUGGER_INVOKE: - case FRAME_TYPE_TRAMPOLINE: - case FRAME_TYPE_INTERP_TO_MANAGED: - continue; - case FRAME_TYPE_INTERP: - skip--; - break; - default: - ji = frame.ji; - *native_offset = frame.native_offset; - - /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */ - jmethod = jinfo_get_method (ji); - if (jmethod->wrapper_type != MONO_WRAPPER_NONE && jmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD && jmethod->wrapper_type != MONO_WRAPPER_MANAGED_TO_NATIVE) - continue; - skip--; - break; - } - } while (skip >= 0); - - if (frame.type == FRAME_TYPE_INTERP) { - jmethod = frame.method; - actual_method = frame.actual_method; - *native_offset = frame.native_offset; - } else { - actual_method = get_method_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, &ctx)); - } - } - - MonoReflectionMethod *rm = mono_method_get_object_checked (domain, actual_method, NULL, error); - if (!mono_error_ok (error)) { - mono_error_set_pending_exception (error); - return FALSE; - } - mono_gc_wbarrier_generic_store (method, (MonoObject*) rm); - - if (il_offset != -1) { - location = mono_debug_lookup_source_location_by_il (jmethod, il_offset, domain); - } else { - location = mono_debug_lookup_source_location (jmethod, *native_offset, domain); - } - if (location) - *iloffset = location->il_offset; - else - *iloffset = 0; - - if (need_file_info) { - if (location) { - MonoString *filename = mono_string_new_checked (domain, location->source_file, error); - if (!is_ok (error)) { - mono_error_set_pending_exception (error); - return FALSE; - } - mono_gc_wbarrier_generic_store (file, (MonoObject*)filename); - *line = location->row; - *column = location->column; - } else { - *file = NULL; - *line = *column = 0; - } - } - - mono_debug_free_source_location (location); - - return TRUE; -} - -static MonoClass* -get_exception_catch_class (MonoJitExceptionInfo *ei, MonoJitInfo *ji, MonoContext *ctx) -{ - ERROR_DECL (error); - MonoClass *catch_class = ei->data.catch_class; - MonoType *inflated_type; - MonoGenericContext context; - - /*MonoJitExceptionInfo::data is an union used by filter and finally clauses too.*/ - if (!catch_class || ei->flags != MONO_EXCEPTION_CLAUSE_NONE) - return NULL; - - if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this) - return catch_class; - context = get_generic_context_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, ctx)); - - /* FIXME: we shouldn't inflate but instead put the - type in the rgctx and fetch it from there. It - might be a good idea to do this lazily, i.e. only - when the exception is actually thrown, so as not to - waste space for exception clauses which might never - be encountered. */ - inflated_type = mono_class_inflate_generic_type_checked (&catch_class->byval_arg, &context, error); - mono_error_assert_ok (error); /* FIXME don't swallow the error */ - - catch_class = mono_class_from_mono_type (inflated_type); - mono_metadata_free_type (inflated_type); - - return catch_class; -} - -/* - * mini_jit_info_table_find_ext: - * - * Same as mono_jit_info_table_find, but search all the domains of the current thread - * if ADDR is not found in DOMAIN. The domain where the method was found is stored into - * OUT_DOMAIN if it is not NULL. - */ -MonoJitInfo* -mini_jit_info_table_find_ext (MonoDomain *domain, char *addr, gboolean allow_trampolines, MonoDomain **out_domain) -{ - MonoJitInfo *ji; - MonoInternalThread *t = mono_thread_internal_current (); - gpointer *refs; - - if (out_domain) - *out_domain = NULL; - - ji = mono_jit_info_table_find_internal (domain, addr, TRUE, allow_trampolines); - if (ji) { - if (out_domain) - *out_domain = domain; - return ji; - } - - /* maybe it is shared code, so we also search in the root domain */ - if (domain != mono_get_root_domain ()) { - ji = mono_jit_info_table_find_internal (mono_get_root_domain (), addr, TRUE, allow_trampolines); - if (ji) { - if (out_domain) - *out_domain = mono_get_root_domain (); - return ji; - } - } - - if (!t) - return NULL; - - refs = (gpointer *)((t->appdomain_refs) ? *(gpointer *) t->appdomain_refs : NULL); - for (; refs && *refs; refs++) { - if (*refs != domain && *refs != mono_get_root_domain ()) { - ji = mono_jit_info_table_find_internal ((MonoDomain*) *refs, addr, TRUE, allow_trampolines); - if (ji) { - if (out_domain) - *out_domain = (MonoDomain*) *refs; - return ji; - } - } - } - - return NULL; -} - -MonoJitInfo* -mini_jit_info_table_find (MonoDomain *domain, char *addr, MonoDomain **out_domain) -{ - return mini_jit_info_table_find_ext (domain, addr, FALSE, out_domain); -} - -/* Class lazy loading functions */ -static GENERATE_GET_CLASS_WITH_CACHE (runtime_compat_attr, "System.Runtime.CompilerServices", "RuntimeCompatibilityAttribute") - -/* - * wrap_non_exception_throws: - * - * Determine whenever M's assembly has a RuntimeCompatibilityAttribute with the - * WrapNonExceptionThrows flag set. - */ -static gboolean -wrap_non_exception_throws (MonoMethod *m) -{ - ERROR_DECL (error); - MonoAssembly *ass = m->klass->image->assembly; - MonoCustomAttrInfo* attrs; - MonoClass *klass; - int i; - gboolean val = FALSE; - - if (m->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) { - MonoDynamicMethod *dm = (MonoDynamicMethod *)m; - if (dm->assembly) - ass = dm->assembly; - } - g_assert (ass); - if (ass->wrap_non_exception_throws_inited) - return ass->wrap_non_exception_throws; - - klass = mono_class_get_runtime_compat_attr_class (); - - attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, error); - mono_error_cleanup (error); /* FIXME don't swallow the error */ - if (attrs) { - for (i = 0; i < attrs->num_attrs; ++i) { - MonoCustomAttrEntry *attr = &attrs->attrs [i]; - const gchar *p; - int num_named, named_type, name_len; - char *name; - - if (!attr->ctor || attr->ctor->klass != klass) - continue; - /* Decode the RuntimeCompatibilityAttribute. See reflection.c */ - p = (const char*)attr->data; - g_assert (read16 (p) == 0x0001); - p += 2; - num_named = read16 (p); - if (num_named != 1) - continue; - p += 2; - named_type = *p; - p ++; - /* data_type = *p; */ - p ++; - /* Property */ - if (named_type != 0x54) - continue; - name_len = mono_metadata_decode_blob_size (p, &p); - name = (char *)g_malloc (name_len + 1); - memcpy (name, p, name_len); - name [name_len] = 0; - p += name_len; - g_assert (!strcmp (name, "WrapNonExceptionThrows")); - g_free (name); - /* The value is a BOOLEAN */ - val = *p; - } - mono_custom_attrs_free (attrs); - } - - ass->wrap_non_exception_throws = val; - mono_memory_barrier (); - ass->wrap_non_exception_throws_inited = TRUE; - - return val; -} - -#define MAX_UNMANAGED_BACKTRACE 128 -static MonoArray* -build_native_trace (MonoError *error) -{ - error_init (error); -/* This puppy only makes sense on mobile, IOW, ARM. */ -#if defined (HAVE_BACKTRACE_SYMBOLS) && defined (TARGET_ARM) - MonoArray *res; - void *native_trace [MAX_UNMANAGED_BACKTRACE]; - int size = -1; - MONO_ENTER_GC_SAFE; - size = backtrace (native_trace, MAX_UNMANAGED_BACKTRACE); - MONO_EXIT_GC_SAFE; - int i; - - if (!size) - return NULL; - res = mono_array_new_checked (mono_domain_get (), mono_defaults.int_class, size, error); - return_val_if_nok (error, NULL); - - for (i = 0; i < size; i++) - mono_array_set (res, gpointer, i, native_trace [i]); - return res; -#else - return NULL; -#endif -} - -static void -setup_stack_trace (MonoException *mono_ex, GSList *dynamic_methods, GList **trace_ips) -{ - if (mono_ex) { - *trace_ips = g_list_reverse (*trace_ips); - ERROR_DECL (error); - MonoArray *ips_arr = mono_glist_to_array (*trace_ips, mono_defaults.int_class, error); - mono_error_assert_ok (error); - MONO_OBJECT_SETREF (mono_ex, trace_ips, ips_arr); - MONO_OBJECT_SETREF (mono_ex, native_trace_ips, build_native_trace (error)); - mono_error_assert_ok (error); - if (dynamic_methods) { - /* These methods could go away anytime, so save a reference to them in the exception object */ - GSList *l; - MonoMList *list = NULL; - - for (l = dynamic_methods; l; l = l->next) { - guint32 dis_link; - MonoDomain *domain = mono_domain_get (); - - if (domain->method_to_dyn_method) { - mono_domain_lock (domain); - dis_link = (guint32)(size_t)g_hash_table_lookup (domain->method_to_dyn_method, l->data); - mono_domain_unlock (domain); - if (dis_link) { - MonoObject *o = mono_gchandle_get_target (dis_link); - if (o) { - list = mono_mlist_prepend_checked (list, o, error); - mono_error_assert_ok (error); - } - } - } - } - - MONO_OBJECT_SETREF (mono_ex, dynamic_methods, list); - } - } - g_list_free (*trace_ips); - *trace_ips = NULL; -} - -/* - * handle_exception_first_pass: - * - * The first pass of exception handling. Unwind the stack until a catch clause which can catch - * OBJ is found. Store the index of the filter clause which caught the exception into - * OUT_FILTER_IDX. Return TRUE if the exception is caught, FALSE otherwise. - */ -static gboolean -handle_exception_first_pass (MonoContext *ctx, MonoObject *obj, gint32 *out_filter_idx, MonoJitInfo **out_ji, MonoJitInfo **out_prev_ji, MonoObject *non_exception, StackFrameInfo *catch_frame) -{ - ERROR_DECL (error); - MonoDomain *domain = mono_domain_get (); - MonoJitInfo *ji = NULL; - static int (*call_filter) (MonoContext *, gpointer) = NULL; - MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls (); - MonoLMF *lmf = mono_get_lmf (); - GList *trace_ips = NULL; - GSList *dynamic_methods = NULL; - MonoException *mono_ex; - gboolean stack_overflow = FALSE; - MonoContext initial_ctx; - MonoMethod *method; - int frame_count = 0; - gint32 filter_idx; - int i; - MonoObject *ex_obj; - Unwinder unwinder; - gboolean in_interp; - - g_assert (ctx != NULL); - - if (obj == (MonoObject *)domain->stack_overflow_ex) - stack_overflow = TRUE; - - mono_ex = (MonoException*)obj; - MonoArray *initial_trace_ips = mono_ex->trace_ips; - if (initial_trace_ips) { - int len = mono_array_length (initial_trace_ips) / TRACE_IP_ENTRY_SIZE; - - for (i = 0; i < (len - 1); i++) { - for (int j = 0; j < TRACE_IP_ENTRY_SIZE; ++j) { - gpointer p = mono_array_get (initial_trace_ips, gpointer, (i * TRACE_IP_ENTRY_SIZE) + j); - trace_ips = g_list_prepend (trace_ips, p); - } - } - } - - if (!mono_object_isinst_checked (obj, mono_defaults.exception_class, error)) { - mono_error_assert_ok (error); - mono_ex = NULL; - } - - if (!call_filter) - call_filter = (int (*) (MonoContext *, void *))mono_get_call_filter (); - - g_assert (jit_tls->end_of_stack); - g_assert (jit_tls->abort_func); - - if (out_filter_idx) - *out_filter_idx = -1; - if (out_ji) - *out_ji = NULL; - if (out_prev_ji) - *out_prev_ji = NULL; - filter_idx = 0; - initial_ctx = *ctx; - - unwinder_init (&unwinder); - - while (1) { - MonoContext new_ctx; - guint32 free_stack; - int clause_index_start = 0; - gboolean unwind_res = TRUE; - - StackFrameInfo frame; - - if (out_prev_ji) - *out_prev_ji = ji; - - unwind_res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame); - if (!unwind_res) { - setup_stack_trace (mono_ex, dynamic_methods, &trace_ips); - g_slist_free (dynamic_methods); - return FALSE; - } - - switch (frame.type) { - case FRAME_TYPE_DEBUGGER_INVOKE: - case FRAME_TYPE_MANAGED_TO_NATIVE: - case FRAME_TYPE_TRAMPOLINE: - case FRAME_TYPE_INTERP_TO_MANAGED: - *ctx = new_ctx; - continue; - case FRAME_TYPE_INTERP: - case FRAME_TYPE_MANAGED: - break; - default: - g_assert_not_reached (); - break; - } - - in_interp = frame.type == FRAME_TYPE_INTERP; - ji = frame.ji; - - gpointer ip; - if (in_interp) - ip = (guint8*)ji->code_start + frame.native_offset; - else - ip = MONO_CONTEXT_GET_IP (ctx); - - frame_count ++; - method = jinfo_get_method (ji); - //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count); - - if (mini_get_debug_options ()->reverse_pinvoke_exceptions && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) { - g_error ("A native frame was found while unwinding the stack after an exception.\n" - "The native frame called the managed method:\n%s\n", - mono_method_full_name (method, TRUE)); - } - - if (method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE && mono_ex) { - // avoid giant stack traces during a stack overflow - if (frame_count < 1000) { - trace_ips = g_list_prepend (trace_ips, ip); - trace_ips = g_list_prepend (trace_ips, get_generic_info_from_stack_frame (ji, ctx)); - trace_ips = g_list_prepend (trace_ips, ji); - } - } - - if (method->dynamic) - dynamic_methods = g_slist_prepend (dynamic_methods, method); - - if (stack_overflow) { - free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx)); - } else { - free_stack = 0xffffff; - } - - for (i = clause_index_start; i < ji->num_clauses; i++) { - MonoJitExceptionInfo *ei = &ji->clauses [i]; - gboolean filtered = FALSE; - - /* - * During stack overflow, wait till the unwinding frees some stack - * space before running handlers/finalizers. - */ - if (free_stack <= (64 * 1024)) - continue; - - if (is_address_protected (ji, ei, ip)) { - /* catch block */ - MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx); - - /* - * Have to unwrap RuntimeWrappedExceptions if the - * method's assembly doesn't have a RuntimeCompatibilityAttribute. - */ - if (non_exception && !wrap_non_exception_throws (method)) - ex_obj = non_exception; - else - ex_obj = obj; - - if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) { -#ifndef DISABLE_PERFCOUNTERS - mono_atomic_inc_i32 (&mono_perfcounters->exceptions_filters); -#endif - - if (!ji->is_interp) { -#ifndef MONO_CROSS_COMPILE -#ifdef MONO_CONTEXT_SET_LLVM_EXC_REG - if (ji->from_llvm) - MONO_CONTEXT_SET_LLVM_EXC_REG (ctx, ex_obj); - else - /* Can't pass the ex object in a register yet to filter clauses, because call_filter () might not support it */ - *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj; -#else - g_assert (!ji->from_llvm); - /* store the exception object in bp + ei->exvar_offset */ - *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj; -#endif -#endif - -#ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG - /* - * Pass the original il clause index to the landing pad so it can - * branch to the landing pad associated with the il clause. - * This is needed because llvm compiled code assumes that the EH - * code always branches to the innermost landing pad. - */ - if (ji->from_llvm) - MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx, ei->clause_index); -#endif - } - - mono_debugger_agent_begin_exception_filter (mono_ex, ctx, &initial_ctx); - if (ji->is_interp) { - filtered = mini_get_interp_callbacks ()->run_filter (&frame, (MonoException*)ex_obj, i, ei->data.filter); - } else { - filtered = call_filter (ctx, ei->data.filter); - } - mono_debugger_agent_end_exception_filter (mono_ex, ctx, &initial_ctx); - if (filtered && out_filter_idx) - *out_filter_idx = filter_idx; - if (out_ji) - *out_ji = ji; - filter_idx ++; - - if (filtered) { - setup_stack_trace (mono_ex, dynamic_methods, &trace_ips); - g_slist_free (dynamic_methods); - /* mono_debugger_agent_handle_exception () needs this */ - mini_set_abort_threshold (ctx); - MONO_CONTEXT_SET_IP (ctx, ei->handler_start); - frame.native_offset = (char*)ei->handler_start - (char*)ji->code_start; - *catch_frame = frame; - return TRUE; - } - } - - ERROR_DECL_VALUE (isinst_error); - error_init (&isinst_error); - if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst_checked (ex_obj, catch_class, error)) { - setup_stack_trace (mono_ex, dynamic_methods, &trace_ips); - g_slist_free (dynamic_methods); - - if (out_ji) - *out_ji = ji; - - /* mono_debugger_agent_handle_exception () needs this */ - if (!in_interp) - MONO_CONTEXT_SET_IP (ctx, ei->handler_start); - frame.native_offset = (char*)ei->handler_start - (char*)ji->code_start; - *catch_frame = frame; - return TRUE; - } - mono_error_cleanup (&isinst_error); - } - } - - *ctx = new_ctx; - } - - g_assert_not_reached (); -} - -/** - * mono_handle_exception_internal: - * \param ctx saved processor state - * \param obj the exception object - * \param resume whenever to resume unwinding based on the state in \c MonoJitTlsData. - */ -static gboolean -mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resume, MonoJitInfo **out_ji) -{ - ERROR_DECL (error); - MonoDomain *domain = mono_domain_get (); - MonoJitInfo *ji, *prev_ji; - static int (*call_filter) (MonoContext *, gpointer) = NULL; - MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls (); - MonoLMF *lmf = mono_get_lmf (); - MonoException *mono_ex; - gboolean stack_overflow = FALSE; - MonoContext initial_ctx; - MonoMethod *method; - int frame_count = 0; - gint32 filter_idx, first_filter_idx = 0; - int i; - MonoObject *ex_obj; - MonoObject *non_exception = NULL; - Unwinder unwinder; - gboolean in_interp; - - g_assert (ctx != NULL); - if (!obj) { - MonoException *ex = mono_get_exception_null_reference (); - MonoString *msg = mono_string_new_checked (domain, "Object reference not set to an instance of an object", error); - mono_error_assert_ok (error); - MONO_OBJECT_SETREF (ex, message, msg); - obj = (MonoObject *)ex; - } - - /* - * Allocate a new exception object instead of the preconstructed ones. - */ - if (obj == (MonoObject *)domain->stack_overflow_ex) { - /* - * It is not a good idea to try and put even more pressure on the little stack available. - * obj = mono_get_exception_stack_overflow (); - */ - stack_overflow = TRUE; - } - else if (obj == (MonoObject *)domain->null_reference_ex) { - obj = (MonoObject *)mono_get_exception_null_reference (); - } - - if (!mono_object_isinst_checked (obj, mono_defaults.exception_class, error)) { - mono_error_assert_ok (error); - non_exception = obj; - obj = (MonoObject *)mono_get_exception_runtime_wrapped_checked (obj, error); - mono_error_assert_ok (error); - } - - mono_ex = (MonoException*)obj; - - if (mini_get_debug_options ()->suspend_on_exception) { - mono_runtime_printf_err ("Exception thrown, suspending..."); - while (1) - ; - } - - if (mono_object_isinst_checked (obj, mono_defaults.exception_class, error)) { - mono_ex = (MonoException*)obj; - } else { - mono_error_assert_ok (error); - mono_ex = NULL; - } - - if (mono_ex && jit_tls->class_cast_from) { - if (!strcmp (mono_ex->object.vtable->klass->name, "InvalidCastException")) { - char *from_name = mono_type_get_full_name (jit_tls->class_cast_from); - char *to_name = mono_type_get_full_name (jit_tls->class_cast_to); - char *msg = g_strdup_printf ("Unable to cast object of type '%s' to type '%s'.", from_name, to_name); - mono_ex->message = mono_string_new_checked (domain, msg, error); - g_free (from_name); - g_free (to_name); - if (!is_ok (error)) { - mono_runtime_printf_err ("Error creating class cast exception message '%s'\n", msg); - mono_error_assert_ok (error); - } - g_free (msg); - } - if (!strcmp (mono_ex->object.vtable->klass->name, "ArrayTypeMismatchException")) { - char *from_name = mono_type_get_full_name (jit_tls->class_cast_from); - char *to_name = mono_type_get_full_name (jit_tls->class_cast_to); - char *msg = g_strdup_printf ("Source array of type '%s' cannot be cast to destination array type '%s'.", from_name, to_name); - mono_ex->message = mono_string_new_checked (domain, msg, error); - g_free (from_name); - g_free (to_name); - if (!is_ok (error)) { - mono_runtime_printf_err ("Error creating array type mismatch exception message '%s'\n", msg); - mono_error_assert_ok (error); - } - g_free (msg); - } - } - - if (!call_filter) - call_filter = (int (*)(MonoContext *, void*))mono_get_call_filter (); - - g_assert (jit_tls->end_of_stack); - g_assert (jit_tls->abort_func); - - /* - * We set orig_ex_ctx_set to TRUE/FALSE around profiler calls to make sure it doesn't - * end up being TRUE on any code path. - */ - memcpy (&jit_tls->orig_ex_ctx, ctx, sizeof (MonoContext)); - - if (!resume) { - gboolean res; - - MonoContext ctx_cp = *ctx; - if (mono_trace_is_enabled ()) { - MonoMethod *system_exception_get_message = mono_class_get_method_from_name (mono_defaults.exception_class, "get_Message", 0); - MonoMethod *get_message = system_exception_get_message == NULL ? NULL : mono_object_get_virtual_method (obj, system_exception_get_message); - MonoObject *message; - const char *type_name = mono_class_get_name (mono_object_class (mono_ex)); - char *msg = NULL; - if (get_message == NULL) { - message = NULL; - } else if (!strcmp (type_name, "OutOfMemoryException") || !strcmp (type_name, "StackOverflowException")) { - message = NULL; - msg = g_strdup_printf ("(No exception message for: %s)\n", type_name); - } else { - MonoObject *exc = NULL; - message = mono_runtime_try_invoke (get_message, obj, NULL, &exc, error); - g_assert (exc == NULL); - mono_error_assert_ok (error); - } - if (msg == NULL) { - if (message) { - msg = mono_string_to_utf8_checked ((MonoString *) message, error); - if (!is_ok (error)) { - mono_error_cleanup (error); - msg = g_strdup ("(error while display System.Exception.Message property)"); - } - } else { - msg = g_strdup ("(System.Exception.Message property not available)"); - } - } - g_print ("[%p:] EXCEPTION handling: %s.%s: %s\n", (void*)mono_native_thread_id_get (), mono_object_class (obj)->name_space, mono_object_class (obj)->name, msg); - g_free (msg); - if (mono_ex && mono_trace_eval_exception (mono_object_class (mono_ex))) - mono_print_thread_dump_from_ctx (ctx); - } - jit_tls->orig_ex_ctx_set = TRUE; - MONO_PROFILER_RAISE (exception_throw, (obj)); - jit_tls->orig_ex_ctx_set = FALSE; - - StackFrameInfo catch_frame; - res = handle_exception_first_pass (&ctx_cp, obj, &first_filter_idx, &ji, &prev_ji, non_exception, &catch_frame); - - if (!res) { - if (mini_get_debug_options ()->break_on_exc) - G_BREAKPOINT (); - mono_debugger_agent_handle_exception ((MonoException *)obj, ctx, NULL, NULL); - - if (mini_get_debug_options ()->suspend_on_unhandled) { - mono_runtime_printf_err ("Unhandled exception, suspending..."); - while (1) - ; - } - - // FIXME: This runs managed code so it might cause another stack overflow when - // we are handling a stack overflow - mini_set_abort_threshold (ctx); - mono_unhandled_exception (obj); - } else { - gboolean unhandled = FALSE; - - /* - * The exceptions caught by the mono_runtime_invoke_checked () calls - * in the threadpool needs to be treated as unhandled (#669836). - * - * FIXME: The check below is hackish, but its hard to distinguish - * these runtime invoke calls from others in the runtime. - */ - if (ji && jinfo_get_method (ji)->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE) { - if (prev_ji && jinfo_get_method (prev_ji) == mono_defaults.threadpool_perform_wait_callback_method) - unhandled = TRUE; - } - - if (unhandled) - mono_debugger_agent_handle_exception ((MonoException *)obj, ctx, NULL, NULL); - else - mono_debugger_agent_handle_exception ((MonoException *)obj, ctx, &ctx_cp, &catch_frame); - } - } - - if (out_ji) - *out_ji = NULL; - filter_idx = 0; - initial_ctx = *ctx; - - unwinder_init (&unwinder); - - while (1) { - MonoContext new_ctx; - guint32 free_stack; - int clause_index_start = 0; - gboolean unwind_res = TRUE; - StackFrameInfo frame; - gpointer ip; - - if (resume) { - resume = FALSE; - ji = jit_tls->resume_state.ji; - new_ctx = jit_tls->resume_state.new_ctx; - clause_index_start = jit_tls->resume_state.clause_index; - lmf = jit_tls->resume_state.lmf; - first_filter_idx = jit_tls->resume_state.first_filter_idx; - filter_idx = jit_tls->resume_state.filter_idx; - in_interp = FALSE; - } else { - unwind_res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame); - if (!unwind_res) { - *(mono_get_lmf_addr ()) = lmf; - - jit_tls->abort_func (obj); - g_assert_not_reached (); - } - switch (frame.type) { - case FRAME_TYPE_DEBUGGER_INVOKE: - case FRAME_TYPE_MANAGED_TO_NATIVE: - case FRAME_TYPE_TRAMPOLINE: - *ctx = new_ctx; - continue; - case FRAME_TYPE_INTERP_TO_MANAGED: - continue; - case FRAME_TYPE_INTERP: - case FRAME_TYPE_MANAGED: - break; - default: - g_assert_not_reached (); - break; - } - in_interp = frame.type == FRAME_TYPE_INTERP; - ji = frame.ji; - } - - if (in_interp) - ip = (guint8*)ji->code_start + frame.native_offset; - else - ip = MONO_CONTEXT_GET_IP (ctx); - - method = jinfo_get_method (ji); - frame_count ++; - //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count); - - if (stack_overflow) { - free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx)); - } else { - free_stack = 0xffffff; - } - - for (i = clause_index_start; i < ji->num_clauses; i++) { - MonoJitExceptionInfo *ei = &ji->clauses [i]; - gboolean filtered = FALSE; - - /* - * During stack overflow, wait till the unwinding frees some stack - * space before running handlers/finalizers. - */ - if (free_stack <= (64 * 1024)) - continue; - - if (is_address_protected (ji, ei, ip)) { - /* catch block */ - MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx); - - /* - * Have to unwrap RuntimeWrappedExceptions if the - * method's assembly doesn't have a RuntimeCompatibilityAttribute. - */ - if (non_exception && !wrap_non_exception_throws (method)) - ex_obj = non_exception; - else - ex_obj = obj; - - if (((ei->flags == MONO_EXCEPTION_CLAUSE_NONE) || (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER))) { -#ifndef MONO_CROSS_COMPILE -#ifdef MONO_CONTEXT_SET_LLVM_EXC_REG - MONO_CONTEXT_SET_LLVM_EXC_REG (ctx, ex_obj); -#else - g_assert (!ji->from_llvm); - /* store the exception object in bp + ei->exvar_offset */ - *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj; -#endif -#endif - } - -#ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG - if (ji->from_llvm) - MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx, ei->clause_index); -#endif - - if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) { - /* - * Filter clauses should only be run in the - * first pass of exception handling. - */ - filtered = (filter_idx == first_filter_idx); - filter_idx ++; - } - - error_init (error); - if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE && - mono_object_isinst_checked (ex_obj, catch_class, error)) || filtered) { - /* - * This guards against the situation that we abort a thread that is executing a finally clause - * that was called by the EH machinery. It won't have a guard trampoline installed, so we must - * check for this situation here and resume interruption if we are below the guarded block. - */ - if (G_UNLIKELY (jit_tls->handler_block)) { - gboolean is_outside = FALSE; - gpointer prot_bp = MONO_CONTEXT_GET_BP (&jit_tls->handler_block_context); - gpointer catch_bp = MONO_CONTEXT_GET_BP (ctx); - //FIXME make this stack direction aware - - if (catch_bp > prot_bp) { - is_outside = TRUE; - } else if (catch_bp == prot_bp) { - /* Can be either try { try { } catch {} } finally {} or try { try { } finally {} } catch {} - * So we check if the catch handler_start is protected by the guarded handler protected region - * - * Assumptions: - * If there is an outstanding guarded_block return address, it means the current thread must be aborted. - * This is the only way to reach out the guarded block as other cases are handled by the trampoline. - * There aren't any further finally/fault handler blocks down the stack over this exception. - * This must be ensured by the code that installs the guard trampoline. - */ - g_assert (ji == mini_jit_info_table_find (domain, (char *)MONO_CONTEXT_GET_IP (&jit_tls->handler_block_context), NULL)); - - if (!is_address_protected (ji, jit_tls->handler_block, ei->handler_start)) { - is_outside = TRUE; - } - } - if (is_outside) { - jit_tls->handler_block = NULL; - mono_thread_resume_interruption (TRUE); /*We ignore the exception here, it will be raised later*/ - } - } - - if (mono_trace_is_enabled () && mono_trace_eval (method)) - g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (method, TRUE)); - jit_tls->orig_ex_ctx_set = TRUE; - MONO_PROFILER_RAISE (exception_clause, (method, i, ei->flags, ex_obj)); - jit_tls->orig_ex_ctx_set = FALSE; - mini_set_abort_threshold (ctx); - - if (in_interp) { - /* - * ctx->pc points into the interpreter, after the call which transitioned to - * JITted code. Store the unwind state into the - * interpeter state, then resume, the interpreter will unwind itself until - * it reaches the target frame and will continue execution from there. - * The resuming is kinda hackish, from the native code standpoint, it looks - * 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. - */ - 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] ++; -#elif defined(TARGET_ARM) - ctx->pc ++; - if (mono_arm_thumb_supported ()) - ctx->pc |= 1; -#elif defined(TARGET_ARM64) - ctx->pc ++; -#elif defined (HOST_WASM) - //nada? -#else - NOT_IMPLEMENTED; -#endif - } else { - MONO_CONTEXT_SET_IP (ctx, ei->handler_start); - } - mono_set_lmf (lmf); -#ifndef DISABLE_PERFCOUNTERS - mono_atomic_fetch_add_i32 (&mono_perfcounters->exceptions_depth, frame_count); -#endif - if (obj == (MonoObject *)domain->stack_overflow_ex) - jit_tls->handling_stack_ovf = FALSE; - - return 0; - } - mono_error_cleanup (error); - if (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT) { - if (mono_trace_is_enabled () && mono_trace_eval (method)) - g_print ("EXCEPTION: fault clause %d of %s\n", i, mono_method_full_name (method, TRUE)); - jit_tls->orig_ex_ctx_set = TRUE; - MONO_PROFILER_RAISE (exception_clause, (method, i, ei->flags, ex_obj)); - jit_tls->orig_ex_ctx_set = FALSE; - } - if (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY) { - if (mono_trace_is_enabled () && mono_trace_eval (method)) - g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (method, TRUE)); - jit_tls->orig_ex_ctx_set = TRUE; - MONO_PROFILER_RAISE (exception_clause, (method, i, ei->flags, ex_obj)); - jit_tls->orig_ex_ctx_set = FALSE; -#ifndef DISABLE_PERFCOUNTERS - mono_atomic_inc_i32 (&mono_perfcounters->exceptions_finallys); -#endif - } - if (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT || ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY) { - mono_set_lmf (lmf); - if (ji->from_llvm) { - /* - * LLVM compiled finally handlers follow the design - * of the c++ ehabi, i.e. they call a resume function - * at the end instead of returning to the caller. - * So save the exception handling state, - * mono_resume_unwind () will call us again to continue - * the unwinding. - */ - jit_tls->resume_state.ex_obj = obj; - jit_tls->resume_state.ji = ji; - jit_tls->resume_state.clause_index = i + 1; - jit_tls->resume_state.ctx = *ctx; - jit_tls->resume_state.new_ctx = new_ctx; - jit_tls->resume_state.lmf = lmf; - jit_tls->resume_state.first_filter_idx = first_filter_idx; - jit_tls->resume_state.filter_idx = filter_idx; - mini_set_abort_threshold (ctx); - MONO_CONTEXT_SET_IP (ctx, ei->handler_start); - return 0; - } else { - mini_set_abort_threshold (ctx); - if (in_interp) { - gboolean has_ex = mini_get_interp_callbacks ()->run_finally (&frame, i, ei->handler_start); - if (has_ex) - return 0; - } else { - call_filter (ctx, ei->handler_start); - } - } - } - } - } - - if (MONO_PROFILER_ENABLED (method_exception_leave) && - mono_profiler_get_call_instrumentation_flags (method) & MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE) { - jit_tls->orig_ex_ctx_set = TRUE; - MONO_PROFILER_RAISE (method_exception_leave, (method, ex_obj)); - jit_tls->orig_ex_ctx_set = FALSE; - } - - *ctx = new_ctx; - } - - g_assert_not_reached (); -} - -/** - * mono_debugger_run_finally: - * \param start_ctx saved processor state - * This method is called by the Mono Debugger to call all \c finally clauses of the - * current stack frame. It's used when the user issues a \c return command to make - * the current stack frame return. After returning from this method, the debugger - * unwinds the stack one frame and gives control back to the user. - * NOTE: This method is only used when running inside the Mono Debugger. - */ -void -mono_debugger_run_finally (MonoContext *start_ctx) -{ - static int (*call_filter) (MonoContext *, gpointer) = NULL; - MonoDomain *domain = mono_domain_get (); - MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls (); - MonoLMF *lmf = mono_get_lmf (); - MonoContext ctx, new_ctx; - MonoJitInfo *ji, rji; - int i; - - ctx = *start_ctx; - - ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, NULL); - if (!ji || ji == (gpointer)-1) - return; - - if (!call_filter) - call_filter = (int (*)(MonoContext *, void *))mono_get_call_filter (); - - for (i = 0; i < ji->num_clauses; i++) { - MonoJitExceptionInfo *ei = &ji->clauses [i]; - - if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (&ctx)) && - (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) { - call_filter (&ctx, ei->handler_start); - } - } -} - -/** - * mono_handle_exception: - * \param ctx saved processor state - * \param obj the exception object - * - * Handle the exception OBJ starting from the state CTX. Modify CTX to point to the handler clause if the exception is caught, and - * return TRUE. - */ -gboolean -mono_handle_exception (MonoContext *ctx, MonoObject *obj) -{ - MONO_REQ_GC_UNSAFE_MODE; - -#ifndef DISABLE_PERFCOUNTERS - mono_atomic_inc_i32 (&mono_perfcounters->exceptions_thrown); -#endif - - return mono_handle_exception_internal (ctx, obj, FALSE, NULL); -} - -#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK - -#ifndef MONO_ARCH_USE_SIGACTION -#error "Can't use sigaltstack without sigaction" -#endif - -#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1)) - -void -mono_setup_altstack (MonoJitTlsData *tls) -{ - size_t stsize = 0; - stack_t sa; - guint8 *staddr = NULL; - - if (mono_running_on_valgrind ()) - return; - - mono_thread_info_get_stack_bounds (&staddr, &stsize); - - g_assert (staddr); - - tls->end_of_stack = staddr + stsize; - tls->stack_size = stsize; - - /*g_print ("thread %p, stack_base: %p, stack_size: %d\n", (gpointer)pthread_self (), staddr, stsize);*/ - - tls->stack_ovf_guard_base = staddr + mono_pagesize (); - tls->stack_ovf_guard_size = ALIGN_TO (8 * 4096, mono_pagesize ()); - - g_assert ((guint8*)&sa >= (guint8*)tls->stack_ovf_guard_base + tls->stack_ovf_guard_size); - - if (mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_NONE)) { - /* mprotect can fail for the main thread stack */ - gpointer gaddr = mono_valloc (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_NONE|MONO_MMAP_PRIVATE|MONO_MMAP_ANON|MONO_MMAP_FIXED, MONO_MEM_ACCOUNT_EXCEPTIONS); - g_assert (gaddr == tls->stack_ovf_guard_base); - tls->stack_ovf_valloced = TRUE; - } - - /* Setup an alternate signal stack */ - tls->signal_stack = mono_valloc (0, MONO_ARCH_SIGNAL_STACK_SIZE, MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_PRIVATE|MONO_MMAP_ANON, MONO_MEM_ACCOUNT_EXCEPTIONS); - tls->signal_stack_size = MONO_ARCH_SIGNAL_STACK_SIZE; - - g_assert (tls->signal_stack); - - sa.ss_sp = tls->signal_stack; - sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE; - sa.ss_flags = 0; - g_assert (sigaltstack (&sa, NULL) == 0); - - mono_gc_register_altstack ((char*)tls->stack_ovf_guard_base + tls->stack_ovf_guard_size, (char*)staddr + stsize - ((char*)tls->stack_ovf_guard_base + tls->stack_ovf_guard_size), tls->signal_stack, tls->signal_stack_size); -} - -void -mono_free_altstack (MonoJitTlsData *tls) -{ - stack_t sa; - int err; - - sa.ss_sp = tls->signal_stack; - sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE; - sa.ss_flags = SS_DISABLE; - err = sigaltstack (&sa, NULL); - g_assert (err == 0); - - if (tls->signal_stack) - mono_vfree (tls->signal_stack, MONO_ARCH_SIGNAL_STACK_SIZE, MONO_MEM_ACCOUNT_EXCEPTIONS); - if (tls->stack_ovf_valloced) - mono_vfree (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MEM_ACCOUNT_EXCEPTIONS); - else - mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE); -} - -#else /* !MONO_ARCH_SIGSEGV_ON_ALTSTACK */ - -void -mono_setup_altstack (MonoJitTlsData *tls) -{ -} - -void -mono_free_altstack (MonoJitTlsData *tls) -{ -} - -#endif /* MONO_ARCH_SIGSEGV_ON_ALTSTACK */ - -gboolean -mono_handle_soft_stack_ovf (MonoJitTlsData *jit_tls, MonoJitInfo *ji, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *siginfo, guint8* fault_addr) -{ - if (mono_llvm_only) - return FALSE; - - /* we got a stack overflow in the soft-guard pages - * There are two cases: - * 1) managed code caused the overflow: we unprotect the soft-guard page - * and let the arch-specific code trigger the exception handling mechanism - * in the thread stack. The soft-guard pages will be protected again as the stack is unwound. - * 2) unmanaged code caused the overflow: we unprotect the soft-guard page - * and hope we can continue with those enabled, at least until the hard-guard page - * is hit. The alternative to continuing here is to just print a message and abort. - * We may add in the future the code to protect the pages again in the codepath - * when we return from unmanaged to managed code. - */ - if (jit_tls->stack_ovf_guard_size && fault_addr >= (guint8*)jit_tls->stack_ovf_guard_base && - fault_addr < (guint8*)jit_tls->stack_ovf_guard_base + jit_tls->stack_ovf_guard_size) { - gboolean handled = FALSE; - - mono_mprotect (jit_tls->stack_ovf_guard_base, jit_tls->stack_ovf_guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE); -#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK - if (ji) { - mono_arch_handle_altstack_exception (ctx, siginfo, fault_addr, TRUE); - handled = TRUE; - } -#endif - if (!handled) { - /* We print a message: after this even managed stack overflows - * may crash the runtime - */ - mono_runtime_printf_err ("Stack overflow in unmanaged: IP: %p, fault addr: %p", mono_arch_ip_from_context (ctx), fault_addr); - if (!jit_tls->handling_stack_ovf) { - jit_tls->handling_stack_ovf = 1; - } else { - /*fprintf (stderr, "Already handling stack overflow\n");*/ - } - } - return TRUE; - } - return FALSE; -} - -typedef struct { - MonoMethod *omethod; - int count; -} PrintOverflowUserData; - -#ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX -static gboolean -print_overflow_stack_frame (StackFrameInfo *frame, MonoContext *ctx, gpointer data) -{ - MonoMethod *method = NULL; - PrintOverflowUserData *user_data = (PrintOverflowUserData *)data; - gchar *location; - - if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE) - method = jinfo_get_method (frame->ji); - - if (method) { - if (user_data->count == 0) { - /* The first frame is in its prolog, so a line number cannot be computed */ - user_data->count ++; - return FALSE; - } - - /* If this is a one method overflow, skip the other instances */ - if (method == user_data->omethod) - return FALSE; - - location = mono_debug_print_stack_frame (method, frame->native_offset, mono_domain_get ()); - mono_runtime_printf_err (" %s", location); - g_free (location); - - if (user_data->count == 1) { - mono_runtime_printf_err (" <...>"); - user_data->omethod = method; - } else { - user_data->omethod = NULL; - } - - user_data->count ++; - } else - mono_runtime_printf_err (" at <0x%05x>", frame->native_offset); - - return FALSE; -} -#endif - -void -mono_handle_hard_stack_ovf (MonoJitTlsData *jit_tls, MonoJitInfo *ji, void *ctx, guint8* fault_addr) -{ -#ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX - PrintOverflowUserData ud; - MonoContext mctx; -#endif - - /* we don't do much now, but we can warn the user with a useful message */ - mono_runtime_printf_err ("Stack overflow: IP: %p, fault addr: %p", mono_arch_ip_from_context (ctx), fault_addr); - -#ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX - mono_sigctx_to_monoctx (ctx, &mctx); - - mono_runtime_printf_err ("Stacktrace:"); - - memset (&ud, 0, sizeof (ud)); - - mono_walk_stack_with_ctx (print_overflow_stack_frame, &mctx, MONO_UNWIND_LOOKUP_ACTUAL_METHOD, &ud); -#else - if (ji && !ji->is_trampoline && jinfo_get_method (ji)) - mono_runtime_printf_err ("At %s", mono_method_full_name (jinfo_get_method (ji), TRUE)); - else - mono_runtime_printf_err ("At ."); -#endif - - _exit (1); -} - -static gboolean -print_stack_frame_to_stderr (StackFrameInfo *frame, MonoContext *ctx, gpointer data) -{ - MonoMethod *method = NULL; - - if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE) - method = jinfo_get_method (frame->ji); - - if (method) { - gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, mono_domain_get ()); - mono_runtime_printf_err (" %s", location); - g_free (location); - } else - mono_runtime_printf_err (" at <0x%05x>", frame->native_offset); - - return FALSE; -} - -static G_GNUC_UNUSED gboolean -print_stack_frame_to_string (StackFrameInfo *frame, MonoContext *ctx, gpointer data) -{ - GString *p = (GString*)data; - MonoMethod *method = NULL; - - if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE) - method = jinfo_get_method (frame->ji); - - if (method && frame->domain) { - gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain); - g_string_append_printf (p, " %s\n", location); - g_free (location); - } else - g_string_append_printf (p, " at <0x%05x>\n", frame->native_offset); - - return FALSE; -} - -#ifndef MONO_CROSS_COMPILE - -static void print_process_map (void) -{ -#ifdef __linux__ - FILE *fp = fopen ("/proc/self/maps", "r"); - char line [256]; - - if (fp == NULL) { - mono_runtime_printf_err ("no /proc/self/maps, not on linux?\n"); - return; - } - - mono_runtime_printf_err ("/proc/self/maps:"); - - while (fgets (line, sizeof (line), fp)) { - // strip newline - size_t len = strlen (line) - 1; - if (len >= 0 && line [len] == '\n') - line [len] = '\0'; - - mono_runtime_printf_err ("%s", line); - } - - fclose (fp); -#else - /* do nothing */ -#endif -} - -static gboolean handle_crash_loop = FALSE; - -/* - * mono_handle_native_crash: - * - * Handle a native crash (e.g. SIGSEGV) while in native code by - * printing diagnostic information and aborting. - */ -void -mono_handle_native_crash (const char *signal, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *info) -{ -#ifdef MONO_ARCH_USE_SIGACTION - struct sigaction sa; -#endif - MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls (); - - if (handle_crash_loop) - return; - - if (mini_get_debug_options ()->suspend_on_native_crash) { - mono_runtime_printf_err ("Received %s, suspending...", signal); -#ifdef HOST_WIN32 - while (1) - ; -#else - while (1) { - sleep (1); - } -#endif - } - - /* prevent infinite loops in crash handling */ - handle_crash_loop = TRUE; - - /* !jit_tls means the thread was not registered with the runtime */ - if (jit_tls && mono_thread_internal_current ()) { - mono_runtime_printf_err ("Stacktrace:\n"); - - /* FIXME: Is MONO_UNWIND_LOOKUP_IL_OFFSET correct here? */ - mono_walk_stack (print_stack_frame_to_stderr, MONO_UNWIND_LOOKUP_IL_OFFSET, NULL); - } - - print_process_map (); - -#ifdef HAVE_BACKTRACE_SYMBOLS - { - void *array [256]; - char **names; - int i, size; - - mono_runtime_printf_err ("\nNative stacktrace:\n"); - - size = backtrace (array, 256); - names = backtrace_symbols (array, size); - for (i =0; i < size; ++i) { - mono_runtime_printf_err ("\t%s", names [i]); - } - g_free (names); - - /* Try to get more meaningful information using gdb */ - -#if !defined(HOST_WIN32) && defined(HAVE_SYS_SYSCALL_H) && (defined(SYS_fork) || HAVE_FORK) - if (!mini_get_debug_options ()->no_gdb_backtrace) { - /* From g_spawn_command_line_sync () in eglib */ - pid_t pid; - int status; - pid_t crashed_pid = getpid (); - - /* - * glibc fork acquires some locks, so if the crash happened inside malloc/free, - * it will deadlock. Call the syscall directly instead. - */ -#if defined(HOST_ANDROID) - /* SYS_fork is defined to be __NR_fork which is not defined in some ndk versions */ - g_assert_not_reached (); -#elif !defined(HOST_DARWIN) && defined(SYS_fork) - pid = (pid_t) syscall (SYS_fork); -#elif HAVE_FORK - pid = (pid_t) fork (); -#else - g_assert_not_reached (); -#endif - -#if defined (HAVE_PRCTL) && defined(PR_SET_PTRACER) - if (pid > 0) { - // Allow gdb to attach to the process even if ptrace_scope sysctl variable is set to - // a value other than 0 (the most permissive ptrace scope). Most modern Linux - // distributions set the scope to 1 which allows attaching only to direct children of - // the current process - prctl (PR_SET_PTRACER, pid, 0, 0, 0); - } -#endif - -#if defined(TARGET_OSX) - if (mono_merp_enabled ()) { - if (pid == 0) { - MonoContext mctx; - if (!ctx) { - mono_runtime_printf_err ("\nMust always pass non-null context when using merp.\n"); - exit (1); - } - - mono_sigctx_to_monoctx (ctx, &mctx); - - intptr_t thread_pointer = (intptr_t) MONO_CONTEXT_GET_SP (&mctx); - - mono_merp_invoke (crashed_pid, thread_pointer, signal); - - exit (1); - } - } -#endif - - if (pid == 0) { - dup2 (STDERR_FILENO, STDOUT_FILENO); - - mono_gdb_render_native_backtraces (crashed_pid); - exit (1); - } - - mono_runtime_printf_err ("\nDebug info from gdb:\n"); - waitpid (pid, &status, 0); - } -#endif - } -#else -#ifdef HOST_ANDROID - /* set DUMPABLE for this process so debuggerd can attach with ptrace(2), see: - * https://android.googlesource.com/platform/bionic/+/151da681000c07da3c24cd30a3279b1ca017f452/linker/debugger.cpp#206 - * this has changed on later versions of Android. Also, we don't want to - * set this on start-up as DUMPABLE has security implications. */ - prctl (PR_SET_DUMPABLE, 1); - - mono_runtime_printf_err ("\nNo native Android stacktrace (see debuggerd output).\n"); -#endif -#endif - - /* - * A SIGSEGV indicates something went very wrong so we can no longer depend - * on anything working. So try to print out lots of diagnostics, starting - * with ones which have a greater chance of working. - */ - mono_runtime_printf_err ( - "\n" - "=================================================================\n" - "Got a %s while executing native code. This usually indicates\n" - "a fatal error in the mono runtime or one of the native libraries \n" - "used by your application.\n" - "=================================================================\n", - signal); - -#ifdef MONO_ARCH_USE_SIGACTION - sa.sa_handler = SIG_DFL; - sigemptyset (&sa.sa_mask); - sa.sa_flags = 0; - - /* Remove our SIGABRT handler */ - g_assert (sigaction (SIGABRT, &sa, NULL) != -1); - - /* On some systems we get a SIGILL when calling abort (), because it might - * fail to raise SIGABRT */ - g_assert (sigaction (SIGILL, &sa, NULL) != -1); -#endif - - if (!mono_do_crash_chaining) { - /*Android abort is a fluke, it doesn't abort, it triggers another segv. */ -#if defined (HOST_ANDROID) - exit (-1); -#else - abort (); -#endif - } -} - -#else - -void -mono_handle_native_crash (const char *signal, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *info) -{ - g_assert_not_reached (); -} - -#endif /* !MONO_CROSS_COMPILE */ - -static void -mono_print_thread_dump_internal (void *sigctx, MonoContext *start_ctx) -{ - MonoInternalThread *thread = mono_thread_internal_current (); -#ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX - MonoContext ctx; -#endif - GString* text; - char *name; - GError *gerror = NULL; - - if (!thread) - return; - - text = g_string_new (0); - if (thread->name) { - name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &gerror); - g_assert (!gerror); - g_string_append_printf (text, "\n\"%s\"", name); - g_free (name); - } - else if (thread->threadpool_thread) - g_string_append (text, "\n\"\""); - else - g_string_append (text, "\n\"\""); - - g_string_append_printf (text, " tid=0x%p this=0x%p ", (gpointer)(gsize)thread->tid, thread); - mono_thread_internal_describe (thread, text); - g_string_append (text, "\n"); - -#ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX - if (start_ctx) { - memcpy (&ctx, start_ctx, sizeof (MonoContext)); - } else if (!sigctx) - MONO_INIT_CONTEXT_FROM_FUNC (&ctx, mono_print_thread_dump); - else - mono_sigctx_to_monoctx (sigctx, &ctx); - - mono_walk_stack_with_ctx (print_stack_frame_to_string, &ctx, MONO_UNWIND_LOOKUP_ALL, text); -#else - mono_runtime_printf ("\t"); -#endif - - mono_runtime_printf ("%s", text->str); - -#if HOST_WIN32 && TARGET_WIN32 && _DEBUG - OutputDebugStringA(text->str); -#endif - - g_string_free (text, TRUE); - mono_runtime_stdout_fflush (); -} - -/** - * mono_print_thread_dump: - * - * Print information about the current thread to stdout. - * \p sigctx can be NULL, allowing this to be called from gdb. - */ -void -mono_print_thread_dump (void *sigctx) -{ - mono_print_thread_dump_internal (sigctx, NULL); -} - -void -mono_print_thread_dump_from_ctx (MonoContext *ctx) -{ - mono_print_thread_dump_internal (NULL, ctx); -} - -/* - * mono_resume_unwind: - * - * This is called by a trampoline from LLVM compiled finally clauses to continue - * unwinding. - */ -void -mono_resume_unwind (MonoContext *ctx) -{ - MONO_REQ_GC_UNSAFE_MODE; - - MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls (); - MonoContext new_ctx; - - MONO_CONTEXT_SET_IP (ctx, MONO_CONTEXT_GET_IP (&jit_tls->resume_state.ctx)); - MONO_CONTEXT_SET_SP (ctx, MONO_CONTEXT_GET_SP (&jit_tls->resume_state.ctx)); - new_ctx = *ctx; - - mono_handle_exception_internal (&new_ctx, (MonoObject *)jit_tls->resume_state.ex_obj, TRUE, NULL); - - mono_restore_context (&new_ctx); -} - -typedef struct { - MonoJitInfo *ji; - MonoContext ctx; - MonoJitExceptionInfo *ei; -} FindHandlerBlockData; - -static gboolean -find_last_handler_block (StackFrameInfo *frame, MonoContext *ctx, gpointer data) -{ - int i; - gpointer ip; - FindHandlerBlockData *pdata = (FindHandlerBlockData *)data; - MonoJitInfo *ji = frame->ji; - - if (!ji) - return FALSE; - - ip = MONO_CONTEXT_GET_IP (ctx); - - for (i = 0; i < ji->num_clauses; ++i) { - MonoJitExceptionInfo *ei = ji->clauses + i; - if (ei->flags != MONO_EXCEPTION_CLAUSE_FINALLY) - continue; - /*If ip points to the first instruction it means the handler block didn't start - so we can leave its execution to the EH machinery*/ - if (ei->handler_start <= ip && ip < ei->data.handler_end) { - pdata->ji = ji; - pdata->ei = ei; - pdata->ctx = *ctx; - break; - } - } - return FALSE; -} - - -static void -install_handler_block_guard (MonoJitInfo *ji, MonoContext *ctx) -{ - int i; - MonoJitExceptionInfo *clause = NULL; - gpointer ip; - guint8 *bp; - - ip = MONO_CONTEXT_GET_IP (ctx); - - for (i = 0; i < ji->num_clauses; ++i) { - clause = &ji->clauses [i]; - if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY) - continue; - if (clause->handler_start <= ip && clause->data.handler_end > ip) - break; - } - - /*no matching finally */ - if (i == ji->num_clauses) - return; - - /*Load the spvar*/ - bp = (guint8*)MONO_CONTEXT_GET_BP (ctx); - *(bp + clause->exvar_offset) = 1; -} - -/* - * Finds the bottom handler block running and install a block guard if needed. - */ -static gboolean -mono_install_handler_block_guard (MonoThreadUnwindState *ctx) -{ - FindHandlerBlockData data = { 0 }; - MonoJitTlsData *jit_tls = (MonoJitTlsData *)ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS]; - - /* Guard against a null MonoJitTlsData. This can happens if the thread receives the - * interrupt signal before the JIT has time to initialize its TLS data for the given thread. - */ - if (!jit_tls || jit_tls->handler_block) - return FALSE; - - /* Do an async safe stack walk */ - mono_thread_info_set_is_async_context (TRUE); - mono_walk_stack_with_state (find_last_handler_block, ctx, MONO_UNWIND_NONE, &data); - mono_thread_info_set_is_async_context (FALSE); - - if (!data.ji) - return FALSE; - - memcpy (&jit_tls->handler_block_context, &data.ctx, sizeof (MonoContext)); - - install_handler_block_guard (data.ji, &data.ctx); - - jit_tls->handler_block = data.ei; - - return TRUE; -} - -static gboolean -mono_current_thread_has_handle_block_guard (void) -{ - MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls (); - return jit_tls && jit_tls->handler_block != NULL; -} - -void -mono_set_cast_details (MonoClass *from, MonoClass *to) -{ - MonoJitTlsData *jit_tls = NULL; - - if (mini_get_debug_options ()->better_cast_details) { - jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls (); - jit_tls->class_cast_from = from; - jit_tls->class_cast_to = to; - } -} - - -/*returns false if the thread is not attached*/ -gboolean -mono_thread_state_init_from_sigctx (MonoThreadUnwindState *ctx, void *sigctx) -{ -#ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX - MonoThreadInfo *thread = mono_thread_info_current_unchecked (); - if (!thread) { - ctx->valid = FALSE; - return FALSE; - } - - if (sigctx) { - mono_sigctx_to_monoctx (sigctx, &ctx->ctx); - - ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get (); - ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf (); - ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data; - } - else { - mono_thread_state_init (ctx); - } - - if (!ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] || !ctx->unwind_data [MONO_UNWIND_DATA_LMF]) - return FALSE; - - ctx->valid = TRUE; - return TRUE; -#else - g_error ("Implement mono_arch_sigctx_to_monoctx for the current target"); - return FALSE; -#endif -} - -void -mono_thread_state_init (MonoThreadUnwindState *ctx) -{ - MonoThreadInfo *thread = mono_thread_info_current_unchecked (); - -#if defined(MONO_CROSS_COMPILE) - ctx->valid = FALSE; //A cross compiler doesn't need to suspend. -#elif MONO_ARCH_HAS_MONO_CONTEXT - MONO_CONTEXT_GET_CURRENT (ctx->ctx); -#else - g_error ("Use a null sigctx requires a working mono-context"); -#endif - - ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get (); - ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf (); - ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread ? thread->jit_data : NULL; - ctx->valid = TRUE; -} - - -gboolean -mono_thread_state_init_from_monoctx (MonoThreadUnwindState *ctx, MonoContext *mctx) -{ - MonoThreadInfo *thread = mono_thread_info_current_unchecked (); - if (!thread) { - ctx->valid = FALSE; - return FALSE; - } - - ctx->ctx = *mctx; - ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get (); - ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf (); - ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data; - ctx->valid = TRUE; - return TRUE; -} - -/*returns false if the thread is not attached*/ -gboolean -mono_thread_state_init_from_current (MonoThreadUnwindState *ctx) -{ - MonoThreadInfo *thread = mono_thread_info_current_unchecked (); - MONO_ARCH_CONTEXT_DEF - - mono_arch_flush_register_windows (); - - if (!thread || !thread->jit_data) { - ctx->valid = FALSE; - return FALSE; - } -#ifdef MONO_INIT_CONTEXT_FROM_CURRENT - MONO_INIT_CONTEXT_FROM_CURRENT (&ctx->ctx); -#else - MONO_INIT_CONTEXT_FROM_FUNC (&ctx->ctx, mono_thread_state_init_from_current); -#endif - - ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get (); - ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf (); - ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data; - ctx->valid = TRUE; - return TRUE; -} - -static void -mono_raise_exception_with_ctx (MonoException *exc, MonoContext *ctx) -{ - mono_handle_exception (ctx, (MonoObject *)exc); - mono_restore_context (ctx); -} - -/*FIXME Move all monoctx -> sigctx conversion to signal handlers once all archs support utils/mono-context */ -void -mono_setup_async_callback (MonoContext *ctx, void (*async_cb)(void *fun), gpointer user_data) -{ -#ifdef MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK - MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls (); - jit_tls->ex_ctx = *ctx; - - mono_arch_setup_async_callback (ctx, async_cb, user_data); -#else - g_error ("This target doesn't support mono_arch_setup_async_callback"); -#endif -} - -/* - * mono_restore_context: - * - * Call the architecture specific restore context function. - */ -void -mono_restore_context (MonoContext *ctx) -{ - static void (*restore_context) (MonoContext *); - - if (!restore_context) - restore_context = (void (*)(MonoContext *))mono_get_restore_context (); - restore_context (ctx); - g_assert_not_reached (); -} - -/* - * mono_jinfo_get_unwind_info: - * - * Return the unwind info for JI. - */ -guint8* -mono_jinfo_get_unwind_info (MonoJitInfo *ji, guint32 *unwind_info_len) -{ - if (ji->has_unwind_info) { - /* The address/length in the MonoJitInfo structure itself */ - MonoUnwindJitInfo *info = mono_jit_info_get_unwind_info (ji); - *unwind_info_len = info->unw_info_len; - return info->unw_info; - } else if (ji->from_aot) - return mono_aot_get_unwind_info (ji, unwind_info_len); - else - return mono_get_cached_unwind_info (ji->unwind_info, unwind_info_len); -} - -int -mono_jinfo_get_epilog_size (MonoJitInfo *ji) -{ - MonoArchEHJitInfo *info; - - info = mono_jit_info_get_arch_eh_info (ji); - g_assert (info); - - return info->epilog_size; -} - -/* - * LLVM/Bitcode exception handling. - */ - -static void -throw_exception (MonoObject *ex, gboolean rethrow) -{ - MONO_REQ_GC_UNSAFE_MODE; - - ERROR_DECL (error); - MonoJitTlsData *jit_tls = mono_get_jit_tls (); - MonoException *mono_ex; - - if (!mono_object_isinst_checked (ex, mono_defaults.exception_class, error)) { - mono_error_assert_ok (error); - mono_ex = mono_get_exception_runtime_wrapped_checked (ex, error); - mono_error_assert_ok (error); - jit_tls->thrown_non_exc = mono_gchandle_new (ex, FALSE); - } - else - mono_ex = (MonoException*)ex; - - // Note: Not pinned - jit_tls->thrown_exc = mono_gchandle_new ((MonoObject*)mono_ex, FALSE); - - if (!rethrow) { -#ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE - GList *l, *ips = NULL; - GList *trace; - - _Unwind_Backtrace (build_stack_trace, &ips); - /* The list contains ip-gshared info pairs */ - trace = NULL; - ips = g_list_reverse (ips); - for (l = ips; l; l = l->next) { - trace = g_list_append (trace, l->data); - trace = g_list_append (trace, NULL); - trace = g_list_append (trace, NULL); - } - MonoArray *ips_arr = mono_glist_to_array (trace, mono_defaults.int_class, error); - mono_error_assert_ok (error); - MONO_OBJECT_SETREF (mono_ex, trace_ips, ips_arr); - g_list_free (l); - g_list_free (trace); -#endif - } - - mono_llvm_cpp_throw_exception (); -} - -void -mono_llvm_throw_exception (MonoObject *ex) -{ - throw_exception (ex, FALSE); -} - -void -mono_llvm_rethrow_exception (MonoObject *ex) -{ - throw_exception (ex, TRUE); -} - -void -mono_llvm_raise_exception (MonoException *e) -{ - mono_llvm_throw_exception ((MonoObject*)e); -} - -void -mono_llvm_reraise_exception (MonoException *e) -{ - mono_llvm_rethrow_exception ((MonoObject*)e); -} - -void -mono_llvm_throw_corlib_exception (guint32 ex_token_index) -{ - guint32 ex_token = MONO_TOKEN_TYPE_DEF | ex_token_index; - MonoException *ex; - - ex = mono_exception_from_token (mono_defaults.exception_class->image, ex_token); - - mono_llvm_throw_exception ((MonoObject*)ex); -} - -/* - * mono_llvm_resume_exception: - * - * Resume exception propagation. - */ -void -mono_llvm_resume_exception (void) -{ - mono_llvm_cpp_throw_exception (); -} - -/* - * mono_llvm_load_exception: - * - * Return the currently thrown exception. - */ -MonoObject * -mono_llvm_load_exception (void) -{ - ERROR_DECL (error); - MonoJitTlsData *jit_tls = mono_get_jit_tls (); - - MonoException *mono_ex = (MonoException*)mono_gchandle_get_target (jit_tls->thrown_exc); - - if (mono_ex->trace_ips) { - GList *trace_ips = NULL; - gpointer ip = MONO_RETURN_ADDRESS (); - - size_t upper = mono_array_length (mono_ex->trace_ips); - - for (int i = 0; i < upper; i += TRACE_IP_ENTRY_SIZE) { - gpointer curr_ip = mono_array_get (mono_ex->trace_ips, gpointer, i); - for (int j = 0; j < TRACE_IP_ENTRY_SIZE; ++j) { - gpointer p = mono_array_get (mono_ex->trace_ips, gpointer, i + j); - trace_ips = g_list_append (trace_ips, p); - } - if (ip == curr_ip) - break; - } - - // FIXME: Does this work correctly for rethrows? - // We may be discarding useful information - // when this gets GC'ed - MonoArray *ips_arr = mono_glist_to_array (trace_ips, mono_defaults.int_class, error); - mono_error_assert_ok (error); - MONO_OBJECT_SETREF (mono_ex, trace_ips, ips_arr); - g_list_free (trace_ips); - - // FIXME: - //MONO_OBJECT_SETREF (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex)); - } else { - MONO_OBJECT_SETREF (mono_ex, trace_ips, mono_array_new_checked (mono_domain_get (), mono_defaults.int_class, 0, error)); - mono_error_assert_ok (error); - MONO_OBJECT_SETREF (mono_ex, stack_trace, mono_array_new_checked (mono_domain_get (), mono_defaults.stack_frame_class, 0, error)); - mono_error_assert_ok (error); - } - - return &mono_ex->object; -} - -/* - * mono_llvm_clear_exception: - * - * Mark the currently thrown exception as handled. - */ -void -mono_llvm_clear_exception (void) -{ - MonoJitTlsData *jit_tls = mono_get_jit_tls (); - mono_gchandle_free (jit_tls->thrown_exc); - jit_tls->thrown_exc = 0; - if (jit_tls->thrown_non_exc) - mono_gchandle_free (jit_tls->thrown_non_exc); - jit_tls->thrown_non_exc = 0; - - mono_memory_barrier (); -} - -/* - * mono_llvm_match_exception: - * - * Return the innermost clause containing REGION_START-REGION_END which can handle - * the current exception. - */ -gint32 -mono_llvm_match_exception (MonoJitInfo *jinfo, guint32 region_start, guint32 region_end, gpointer rgctx, MonoObject *this_obj) -{ - ERROR_DECL (error); - MonoJitTlsData *jit_tls = mono_get_jit_tls (); - MonoObject *exc; - gint32 index = -1; - - g_assert (jit_tls->thrown_exc); - exc = mono_gchandle_get_target (jit_tls->thrown_exc); - if (jit_tls->thrown_non_exc) { - /* - * Have to unwrap RuntimeWrappedExceptions if the - * method's assembly doesn't have a RuntimeCompatibilityAttribute. - */ - if (!wrap_non_exception_throws (jinfo_get_method (jinfo))) - exc = mono_gchandle_get_target (jit_tls->thrown_non_exc); - } - - for (int i = 0; i < jinfo->num_clauses; i++) { - MonoJitExceptionInfo *ei = &jinfo->clauses [i]; - MonoClass *catch_class; - - if (! (ei->try_offset == region_start && ei->try_offset + ei->try_len == region_end) ) - continue; - - catch_class = ei->data.catch_class; - if (mono_class_is_open_constructed_type (&catch_class->byval_arg)) { - MonoGenericContext context; - MonoType *inflated_type; - - g_assert (rgctx || this_obj); - context = get_generic_context_from_stack_frame (jinfo, rgctx ? rgctx : this_obj->vtable); - inflated_type = mono_class_inflate_generic_type_checked (&catch_class->byval_arg, &context, error); - mono_error_assert_ok (error); /* FIXME don't swallow the error */ - - catch_class = mono_class_from_mono_type (inflated_type); - mono_metadata_free_type (inflated_type); - } - - // FIXME: Handle edge cases handled in get_exception_catch_class - if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst_checked (exc, catch_class, error)) { - index = ei->clause_index; - break; - } else - mono_error_assert_ok (error); - - if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) { - g_assert_not_reached (); - } - } - - return index; -} - -#ifdef ENABLE_LLVM -_Unwind_Reason_Code -mono_debug_personality (int a, _Unwind_Action b, -uint64_t c, struct _Unwind_Exception *d, struct _Unwind_Context *e) -{ - g_assert_not_reached (); -} -#else -void -mono_debug_personality (void); - -void -mono_debug_personality (void) -{ - g_assert_not_reached (); -} -#endif diff --git a/mono/mini/mini-exceptions.c.REMOVED.git-id b/mono/mini/mini-exceptions.c.REMOVED.git-id new file mode 100644 index 0000000000..556edd60ac --- /dev/null +++ b/mono/mini/mini-exceptions.c.REMOVED.git-id @@ -0,0 +1 @@ +0af7d703a70750aa07b26a5dd0552e8bb896be00 \ No newline at end of file diff --git a/mono/mini/mini-gc.c b/mono/mini/mini-gc.c index 5d95290ed8..de0c84609f 100644 --- a/mono/mini/mini-gc.c +++ b/mono/mini/mini-gc.c @@ -96,8 +96,6 @@ typedef struct { guint8 *reg_pin_bitmap; } MonoCompileGC; -#define ALIGN_TO(val,align) ((((mgreg_t)val) + ((align) - 1)) & ~((align) - 1)) - #undef DEBUG #if 0 diff --git a/mono/mini/mini-generic-sharing.c.REMOVED.git-id b/mono/mini/mini-generic-sharing.c.REMOVED.git-id index df65dbf035..7b2712f4cd 100644 --- a/mono/mini/mini-generic-sharing.c.REMOVED.git-id +++ b/mono/mini/mini-generic-sharing.c.REMOVED.git-id @@ -1 +1 @@ -72a502a095b99e5181288df5a5d9989a45882158 \ No newline at end of file +92a0681d3d62953f9f03c281843cf8038b7ab599 \ No newline at end of file diff --git a/mono/mini/mini-llvm.c.REMOVED.git-id b/mono/mini/mini-llvm.c.REMOVED.git-id index 290f73089e..536fa39a8a 100644 --- a/mono/mini/mini-llvm.c.REMOVED.git-id +++ b/mono/mini/mini-llvm.c.REMOVED.git-id @@ -1 +1 @@ -230af7a2d0778f0ea7c9b6b897dafeca0497ac88 \ No newline at end of file +741e2651dcdcdecf5ac93994dfb77b53acf446ba \ No newline at end of file diff --git a/mono/mini/mini-mips.c.REMOVED.git-id b/mono/mini/mini-mips.c.REMOVED.git-id index fc10e18dce..468003fe69 100644 --- a/mono/mini/mini-mips.c.REMOVED.git-id +++ b/mono/mini/mini-mips.c.REMOVED.git-id @@ -1 +1 @@ -8452e9714a37dce0f68e415219379fb3f647b05c \ No newline at end of file +3e6586c29c0e2f2fe70e2bf01cb03615318a3478 \ No newline at end of file diff --git a/mono/mini/mini-mips.h b/mono/mini/mini-mips.h index c24bf22d60..223fdd430f 100644 --- a/mono/mini/mini-mips.h +++ b/mono/mini/mini-mips.h @@ -166,7 +166,6 @@ typedef gdouble mips_freg; #define mips_ftemp mips_f18 #define MONO_ARCH_USE_FPSTACK FALSE -#define MONO_ARCH_FPSTACK_SIZE 0 /* Parameters used by the register allocator */ @@ -290,6 +289,10 @@ typedef struct MonoCompileArch { #define MONO_ARCH_NEED_DIV_CHECK 1 #define MONO_ARCH_NO_IOV_CHECK 1 +// Does the ABI have a volatile non-parameter register, so tailcall +// can pass context to generics or interfaces? +#define MONO_ARCH_HAVE_VOLATILE_NON_PARAM_REGISTER 0 // FIXME? + #define MIPS_NUM_REG_ARGS (MIPS_LAST_ARG_REG-MIPS_FIRST_ARG_REG+1) #define MIPS_NUM_REG_FPARGS (MIPS_LAST_FPARG_REG-MIPS_FIRST_FPARG_REG+1) diff --git a/mono/mini/mini-native-types.c b/mono/mini/mini-native-types.c index 0ff01dc176..9aea306e1a 100644 --- a/mono/mini/mini-native-types.c +++ b/mono/mini/mini-native-types.c @@ -351,7 +351,7 @@ MonoInst* mono_emit_native_types_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args) { if (mono_class_is_magic_int (cmethod->klass)) { - const char *class_name = cmethod->klass->name; + const char *class_name = m_class_get_name (cmethod->klass); if (!strcmp ("nint", class_name)) return emit_intrinsics (cfg, cmethod, fsig, args, &type_info [0]); else @@ -367,18 +367,19 @@ mono_emit_native_types_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMe static inline gboolean mono_class_is_magic_assembly (MonoClass *klass) { - if (!klass->image->assembly_name) + const char *aname = m_class_get_image (klass)->assembly_name; + if (!aname) return FALSE; - if (!strcmp ("Xamarin.iOS", klass->image->assembly_name)) + if (!strcmp ("Xamarin.iOS", aname)) return TRUE; - if (!strcmp ("Xamarin.Mac", klass->image->assembly_name)) + if (!strcmp ("Xamarin.Mac", aname)) return TRUE; - if (!strcmp ("Xamarin.WatchOS", klass->image->assembly_name)) + if (!strcmp ("Xamarin.WatchOS", aname)) return TRUE; /* regression test suite */ - if (!strcmp ("builtin-types", klass->image->assembly_name)) + if (!strcmp ("builtin-types", aname)) return TRUE; - if (!strcmp ("mini_tests", klass->image->assembly_name)) + if (!strcmp ("mini_tests", aname)) return TRUE; return FALSE; } @@ -401,15 +402,15 @@ mono_class_is_magic_int (MonoClass *klass) if (!mono_class_is_magic_assembly (klass)) return FALSE; - if (strcmp ("System", klass->name_space) != 0) + if (strcmp ("System", m_class_get_name_space (klass)) != 0) return FALSE; - if (strcmp ("nint", klass->name) == 0) { + if (strcmp ("nint", m_class_get_name (klass)) == 0) { magic_nint_class = klass; return TRUE; } - if (strcmp ("nuint", klass->name) == 0){ + if (strcmp ("nuint", m_class_get_name (klass)) == 0){ magic_nuint_class = klass; return TRUE; } @@ -430,19 +431,19 @@ mono_class_is_magic_float (MonoClass *klass) if (!mono_class_is_magic_assembly (klass)) return FALSE; - if (strcmp ("System", klass->name_space) != 0) + if (strcmp ("System", m_class_get_name_space (klass)) != 0) return FALSE; - if (strcmp ("nfloat", klass->name) == 0) { + if (strcmp ("nfloat", m_class_get_name (klass)) == 0) { magic_nfloat_class = klass; /* Assert that we are using the matching assembly */ MonoClassField *value_field = mono_class_get_field_from_name (klass, "v"); g_assert (value_field); MonoType *t = mono_field_get_type (value_field); - MonoType *native = mini_native_type_replace_type (&klass->byval_arg); + MonoType *native = mini_native_type_replace_type (m_class_get_byval_arg (klass)); if (t->type != native->type) - g_error ("Assembly used for native types '%s' doesn't match this runtime, %s is mapped to %s, expecting %s.\n", klass->image->name, klass->name, mono_type_full_name (t), mono_type_full_name (native)); + g_error ("Assembly used for native types '%s' doesn't match this runtime, %s is mapped to %s, expecting %s.\n", m_class_get_image (klass)->name, m_class_get_name (klass), mono_type_full_name (t), mono_type_full_name (native)); return TRUE; } return FALSE; @@ -474,12 +475,12 @@ mini_native_type_replace_type (MonoType *type) klass = type->data.klass; if (mono_class_is_magic_int (klass)) - return type->byref ? &mono_defaults.int_class->this_arg : &mono_defaults.int_class->byval_arg; + return type->byref ? m_class_get_this_arg (mono_defaults.int_class) : m_class_get_byval_arg (mono_defaults.int_class); if (mono_class_is_magic_float (klass)) #if SIZEOF_VOID_P == 8 - return type->byref ? &mono_defaults.double_class->this_arg : &mono_defaults.double_class->byval_arg; + return type->byref ? m_class_get_this_arg (mono_defaults.double_class) : m_class_get_byval_arg (mono_defaults.double_class); #else - return type->byref ? &mono_defaults.single_class->this_arg : &mono_defaults.single_class->byval_arg; + return type->byref ? m_class_get_this_arg (mono_defaults.single_class) : m_class_get_byval_arg (mono_defaults.single_class); #endif return type; } diff --git a/mono/mini/mini-ops.h b/mono/mini/mini-ops.h index 3381b21cef..b449febb06 100644 --- a/mono/mini/mini-ops.h +++ b/mono/mini/mini-ops.h @@ -210,6 +210,7 @@ MINI_OP(OP_BR, "br", NONE, NONE, NONE) MINI_OP(OP_JMP, "jmp", NONE, NONE, NONE) /* Same as OP_JMP, but the passing of arguments is done similarly to calls */ MINI_OP(OP_TAILCALL, "tailcall", NONE, NONE, NONE) +MINI_OP(OP_TAILCALL_MEMBASE, "tailcall_membase", NONE, IREG, NONE) MINI_OP(OP_BREAK, "break", NONE, NONE, NONE) MINI_OP(OP_CEQ, "ceq", IREG, NONE, NONE) @@ -731,7 +732,6 @@ MINI_OP(OP_TLS_SET_REG, "tls_set_reg", NONE, IREG, IREG) MINI_OP(OP_LOAD_GOTADDR, "load_gotaddr", IREG, NONE, NONE) MINI_OP(OP_DUMMY_USE, "dummy_use", NONE, IREG, NONE) -MINI_OP(OP_DUMMY_STORE, "dummy_store", NONE, NONE, NONE) MINI_OP(OP_NOT_REACHED, "not_reached", NONE, NONE, NONE) MINI_OP(OP_NOT_NULL, "not_null", NONE, IREG, NONE) diff --git a/mono/mini/mini-posix.c b/mono/mini/mini-posix.c index c462fe13e5..da8e9d82db 100644 --- a/mono/mini/mini-posix.c +++ b/mono/mini/mini-posix.c @@ -58,6 +58,7 @@ #include #include #include +#include #include "mini.h" #include @@ -202,7 +203,7 @@ MONO_SIG_HANDLER_FUNC (static, sigabrt_signal_handler) MONO_SIG_HANDLER_GET_CONTEXT; if (mono_thread_internal_current ()) - ji = mono_jit_info_table_find_internal (mono_domain_get (), (char *)mono_arch_ip_from_context (ctx), TRUE, TRUE); + ji = mono_jit_info_table_find_internal (mono_domain_get (), mono_arch_ip_from_context (ctx), TRUE, TRUE); if (!ji) { if (mono_chain_signal (MONO_SIG_HANDLER_PARAMS)) return; @@ -517,7 +518,7 @@ clock_sleep_ns_abs (guint64 ns_abs) #else -clockid_t sampling_posix_clock; +static clockid_t sampling_posix_clock; static void clock_init (MonoProfilerSampleMode mode) @@ -630,12 +631,23 @@ clock_sleep_ns_abs (guint64 ns_abs) static int profiler_signal; static volatile gint32 sampling_thread_exiting; +static MonoOSEvent sampling_thread_exited; -static mono_native_thread_return_t -sampling_thread_func (void *data) +static gsize +sampling_thread_func (gpointer unused) { - mono_threads_attach_tools_thread (); - mono_native_thread_set_name (mono_native_thread_id_get (), "Profiler sampler"); + MonoInternalThread *thread = mono_thread_internal_current (); + + thread->flags |= MONO_THREAD_FLAG_DONT_MANAGE; + + ERROR_DECL (error); + + MonoString *name = mono_string_new_checked (mono_get_root_domain (), "Profiler Sampler", error); + mono_error_assert_ok (error); + mono_thread_set_name_internal (thread, name, FALSE, FALSE, error); + mono_error_assert_ok (error); + + mono_thread_info_set_flags (MONO_THREAD_INFO_FLAGS_NO_GC | MONO_THREAD_INFO_FLAGS_NO_SAMPLE); int old_policy; struct sched_param old_sched; @@ -687,9 +699,8 @@ init: sleep += 1000000000 / freq; - FOREACH_THREAD_SAFE (info) { - /* info should never be this thread as we're a tools thread. */ - g_assert (mono_thread_info_get_tid (info) != mono_native_thread_id_get ()); + FOREACH_THREAD_SAFE_EXCLUDE (info, MONO_THREAD_INFO_FLAGS_NO_SAMPLE) { + g_assert (mono_thread_info_get_tid (info) != sampling_thread); /* * Require an ack for the last sampling signal sent to the thread @@ -711,9 +722,11 @@ done: pthread_setschedparam (pthread_self (), old_policy, &old_sched); - mono_thread_info_detach (); + mono_thread_info_set_flags (MONO_THREAD_INFO_FLAGS_NONE); - return NULL; + mono_os_event_set (&sampling_thread_exited); + + return 0; } void @@ -751,7 +764,8 @@ mono_runtime_shutdown_stat_profiler (void) } #endif - mono_native_thread_join (sampling_thread); + mono_os_event_wait_one (&sampling_thread_exited, MONO_INFINITE_WAIT, FALSE); + mono_os_event_destroy (&sampling_thread_exited); /* * We can't safely remove the signal handler because we have no guarantee @@ -793,8 +807,15 @@ mono_runtime_setup_stat_profiler (void) mono_counters_register ("Sampling signals accepted", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &profiler_signals_accepted); mono_counters_register ("Shutdown signals received", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &profiler_interrupt_signals_received); + mono_os_event_init (&sampling_thread_exited, FALSE); + mono_atomic_store_i32 (&sampling_thread_running, 1); - mono_native_thread_create (&sampling_thread, sampling_thread_func, NULL); + + MonoError error; + MonoInternalThread *thread = mono_thread_create_internal (mono_get_root_domain (), sampling_thread_func, NULL, MONO_THREAD_CREATE_FLAGS_NONE, &error); + mono_error_assert_ok (&error); + + sampling_thread = MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid); } #else diff --git a/mono/mini/mini-ppc.c.REMOVED.git-id b/mono/mini/mini-ppc.c.REMOVED.git-id index ab8ef3b4b8..c0a2d7c64e 100644 --- a/mono/mini/mini-ppc.c.REMOVED.git-id +++ b/mono/mini/mini-ppc.c.REMOVED.git-id @@ -1 +1 @@ -7370aebd3f42fa943264a8b70c9e5404df8480c1 \ No newline at end of file +a81816d7bf7059fab0b3cd76cb0d3c4665f74cda \ No newline at end of file diff --git a/mono/mini/mini-ppc.h b/mono/mini/mini-ppc.h index 167f6ed115..8847e6ed00 100644 --- a/mono/mini/mini-ppc.h +++ b/mono/mini/mini-ppc.h @@ -112,7 +112,6 @@ typedef struct MonoCompileArch { #define MONO_ARCH_CALLEE_SAVED_FREGS (~(MONO_ARCH_CALLEE_FREGS | 1)) #define MONO_ARCH_USE_FPSTACK FALSE -#define MONO_ARCH_FPSTACK_SIZE 0 #ifdef __mono_ppc64__ #define MONO_ARCH_INST_FIXED_REG(desc) (((desc) == 'a')? ppc_r3:\ @@ -147,8 +146,6 @@ typedef struct MonoCompileArch { #define PPC_PASS_SMALL_FLOAT_STRUCTS_IN_FR_REGS 0 #define PPC_RETURN_SMALL_FLOAT_STRUCTS_IN_FR_REGS 0 #define PPC_RETURN_SMALL_STRUCTS_IN_REGS 0 -#define MONO_ARCH_HAVE_DECOMPOSE_VTYPE_OPTS 0 -#define MONO_ARCH_RETURN_CAN_USE_MULTIPLE_REGISTERS 0 #elif defined(_AIX) /* FIXME: are these values valid? on 32-bit? */ #define PPC_RET_ADDR_OFFSET 16 @@ -164,14 +161,11 @@ typedef struct MonoCompileArch { #define PPC_PASS_SMALL_FLOAT_STRUCTS_IN_FR_REGS 0 #define PPC_RETURN_SMALL_FLOAT_STRUCTS_IN_FR_REGS 0 #define PPC_RETURN_SMALL_STRUCTS_IN_REGS 0 -#define MONO_ARCH_HAVE_DECOMPOSE_VTYPE_OPTS 0 -#define MONO_ARCH_RETURN_CAN_USE_MULTIPLE_REGISTERS 0 -//#define MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK 1 +#define MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK 1 #define PPC_MINIMAL_PARAM_AREA_SIZE 64 #define PPC_LAST_FPARG_REG ppc_f13 #define PPC_PASS_STRUCTS_BY_VALUE 1 #define PPC_THREAD_PTR_REG ppc_r13 -#define MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX 1 #define PPC_FIRST_ARG_REG ppc_r3 #define PPC_LAST_ARG_REG ppc_r10 #define PPC_FIRST_FPARG_REG ppc_f1 @@ -188,8 +182,6 @@ typedef struct MonoCompileArch { #define PPC_PASS_SMALL_FLOAT_STRUCTS_IN_FR_REGS 1 #define PPC_RETURN_SMALL_FLOAT_STRUCTS_IN_FR_REGS 1 #define PPC_RETURN_SMALL_STRUCTS_IN_REGS 1 - #define MONO_ARCH_HAVE_DECOMPOSE_VTYPE_OPTS 1 - #define MONO_ARCH_RETURN_CAN_USE_MULTIPLE_REGISTERS 1 // Define "DEBUG_ELFABIV2" to allow for debugging output for ELF ABI v2 function call and return codegen // #define DEBUG_ELFABIV2 @@ -204,8 +196,6 @@ typedef struct MonoCompileArch { #define PPC_PASS_SMALL_FLOAT_STRUCTS_IN_FR_REGS 0 #define PPC_RETURN_SMALL_FLOAT_STRUCTS_IN_FR_REGS 0 #define PPC_RETURN_SMALL_STRUCTS_IN_REGS 0 - #define MONO_ARCH_HAVE_DECOMPOSE_VTYPE_OPTS 0 - #define MONO_ARCH_RETURN_CAN_USE_MULTIPLE_REGISTERS 0 #endif #define MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK 1 #define PPC_MINIMAL_PARAM_AREA_SIZE 64 @@ -224,11 +214,8 @@ typedef struct MonoCompileArch { #define PPC_PASS_SMALL_FLOAT_STRUCTS_IN_FR_REGS 0 #define PPC_RETURN_SMALL_FLOAT_STRUCTS_IN_FR_REGS 0 #define PPC_RETURN_SMALL_STRUCTS_IN_REGS 0 -#define MONO_ARCH_HAVE_DECOMPOSE_VTYPE_OPTS 0 -#define MONO_ARCH_RETURN_CAN_USE_MULTIPLE_REGISTERS 0 #define PPC_THREAD_PTR_REG ppc_r2 #endif -#define MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX 1 #define PPC_FIRST_ARG_REG ppc_r3 #define PPC_LAST_ARG_REG ppc_r10 #define PPC_FIRST_FPARG_REG ppc_f1 @@ -246,6 +233,9 @@ typedef struct MonoCompileArch { #define MONO_ARCH_VTABLE_REG ppc_r11 #define MONO_ARCH_RGCTX_REG MONO_ARCH_IMT_REG +#define MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX 1 +#define MONO_ARCH_HAVE_SETUP_RESUME_FROM_SIGNAL_HANDLER_CTX 1 + #define MONO_ARCH_NO_IOV_CHECK 1 #define MONO_ARCH_HAVE_DECOMPOSE_OPTS 1 #define MONO_ARCH_HAVE_DECOMPOSE_LONG_OPTS 1 @@ -263,6 +253,20 @@ typedef struct MonoCompileArch { #define MONO_ARCH_SOFT_DEBUG_SUPPORTED 1 #endif #define MONO_ARCH_HAVE_OP_TAIL_CALL 1 +#define MONO_ARCH_HAVE_PATCH_CODE_NEW 1 + +// Does the ABI have a volatile non-parameter register, so tailcall +// can pass context to generics or interfaces? +#define MONO_ARCH_HAVE_VOLATILE_NON_PARAM_REGISTER 0 // FIXME? + +#if defined(_AIX) +/* + * HACK: AIX always allows accessing page 0! We can't rely on SIGSEGV + * to save us when a null dereference in managed code occurs, so we + * always have to check for null. + */ +#define MONO_ARCH_EXPLICIT_NULL_CHECKS 1 +#endif #define PPC_NUM_REG_ARGS (PPC_LAST_ARG_REG-PPC_FIRST_ARG_REG+1) #define PPC_NUM_REG_FPARGS (PPC_LAST_FPARG_REG-PPC_FIRST_FPARG_REG+1) @@ -390,8 +394,6 @@ gboolean mono_ppc_is_direct_call_sequence (guint32 *code); void mono_ppc_patch_plt_entry (guint8 *code, gpointer *got, mgreg_t *regs, guint8 *addr); -void mono_ppc_set_func_into_sigctx (void *sigctx, void *func); - // Debugging macros for ELF ABI v2 #ifdef DEBUG_ELFABIV2 diff --git a/mono/mini/mini-profiler.c b/mono/mini/mini-profiler.c index c05660e751..8d274c740f 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 (mini_get_interp_callbacks ()->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), m_class_get_this_arg (ctx->method->klass)); MonoDebugMethodJitInfo *info = mono_debug_find_method (ctx->method, mono_domain_get ()); diff --git a/mono/mini/mini-runtime.c.REMOVED.git-id b/mono/mini/mini-runtime.c.REMOVED.git-id index 27e825b982..6d9caebce8 100644 --- a/mono/mini/mini-runtime.c.REMOVED.git-id +++ b/mono/mini/mini-runtime.c.REMOVED.git-id @@ -1 +1 @@ -30473fec52330026da763214017ba02e9686702a \ No newline at end of file +52d96ac2667edf62d2f3cc4ba34f349b3d4fd8ab \ No newline at end of file diff --git a/mono/mini/mini-runtime.h b/mono/mini/mini-runtime.h index 835f77400c..e7a7a1642f 100644 --- a/mono/mini/mini-runtime.h +++ b/mono/mini/mini-runtime.h @@ -51,6 +51,9 @@ typedef struct GHashTable *llvm_jit_callees; /* Maps MonoMethod -> RuntimeMethod */ MonoInternalHashTable interp_code_hash; + /* Maps MonoMethod -> MonoMethodRuntimeGenericContext */ + GHashTable *mrgctx_hash; + GHashTable *method_rgctx_hash; } MonoJitDomainInfo; #define domain_jit_info(domain) ((MonoJitDomainInfo*)((domain)->runtime_info)) @@ -153,7 +156,9 @@ typedef struct { gpointer interp_exit_data; } MonoLMFExt; -typedef struct { +typedef void (*MonoFtnPtrEHCallback) (guint32 gchandle); + +typedef struct MonoDebugOptions { gboolean handle_sigint; gboolean keep_delegates; gboolean reverse_pinvoke_exceptions; @@ -215,6 +220,9 @@ typedef struct { * identify the stack on some platforms */ gboolean disable_omit_fp; + + // Internal testing feature. + gboolean test_tailcall_require; } MonoDebugOptions; @@ -329,7 +337,8 @@ extern MonoMethod *mono_current_single_method; extern GSList *mono_single_method_list; extern GHashTable *mono_single_method_hash; extern GList* mono_aot_paths; -extern MonoDebugOptions debug_options; +extern MonoDebugOptions mini_debug_options; +extern GSList *mono_interp_only_classes; static inline MonoMethod* jinfo_get_method (MonoJitInfo *ji) @@ -352,6 +361,9 @@ void mini_cleanup (MonoDomain *domain); MONO_API MonoDebugOptions *mini_get_debug_options (void); MONO_API gboolean mini_parse_debug_option (const char *option); +MONO_API void +mono_install_ftnptr_eh_callback (MonoFtnPtrEHCallback callback); + void mini_jit_init (void); void mini_jit_cleanup (void); void mono_disable_optimizations (guint32 opts); @@ -381,6 +393,8 @@ MonoJumpInfo *mono_patch_info_list_prepend (MonoJumpInfo *list, int ip, MonoJum MonoJumpInfoToken* mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token); MonoJumpInfoToken* mono_jump_info_token_new2 (MonoMemPool *mp, MonoImage *image, guint32 token, MonoGenericContext *context); gpointer mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors, MonoError *error) MONO_LLVM_INTERNAL; +void mini_register_jump_site (MonoDomain *domain, MonoMethod *method, gpointer ip); +void mini_patch_jump_sites (MonoDomain *domain, MonoMethod *method, gpointer addr); gpointer mono_jit_find_compiled_method_with_jit_info (MonoDomain *domain, MonoMethod *method, MonoJitInfo **ji); gpointer mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method); gpointer mono_jit_compile_method (MonoMethod *method, MonoError *error); @@ -480,4 +494,3 @@ void mini_register_sigterm_handler (void); #endif #endif /* __MONO_MINI_RUNTIME_H__ */ - diff --git a/mono/mini/mini-s390x.c.REMOVED.git-id b/mono/mini/mini-s390x.c.REMOVED.git-id index 45dd3fdbf8..76cecc0cc0 100644 --- a/mono/mini/mini-s390x.c.REMOVED.git-id +++ b/mono/mini/mini-s390x.c.REMOVED.git-id @@ -1 +1 @@ -3fcadb7fe332842cfd9dea6e608e9500e4c5a716 \ No newline at end of file +79ed2977ce63d36f2c169171a23f2290e3295b3e \ No newline at end of file diff --git a/mono/mini/mini-s390x.h b/mono/mini/mini-s390x.h index 21fff66e3a..88cffdf2f9 100644 --- a/mono/mini/mini-s390x.h +++ b/mono/mini/mini-s390x.h @@ -30,9 +30,9 @@ struct MonoLMF { }; typedef struct MonoCompileArch { - gpointer litpool; - glong litsize; int bkchain_reg; + uint32_t used_fp_regs; + int fpSize; } MonoCompileArch; typedef struct @@ -64,6 +64,8 @@ typedef struct #define MONO_ARCH_HAVE_INVALIDATE_METHOD 1 #define MONO_ARCH_HAVE_OP_GENERIC_CLASS_INIT 1 #define MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK 1 +#define MONO_ARCH_HAVE_TRACK_FPREGS 1 +#define MONO_ARCH_HAVE_OP_TAIL_CALL 1 #define S390_STACK_ALIGNMENT 8 #define S390_FIRST_ARG_REG s390_r2 @@ -97,7 +99,6 @@ typedef struct #define MONO_ARCH_CALLEE_SAVED_FREGS 0 #define MONO_ARCH_USE_FPSTACK FALSE -#define MONO_ARCH_FPSTACK_SIZE 0 #define MONO_ARCH_INST_FIXED_REG(desc) ((desc == 'o') ? s390_r2 : \ ((desc == 'g') ? s390_f0 : \ @@ -123,6 +124,10 @@ typedef struct #define MONO_ARCH_CALLEE_XREGS 0x0 #define MONO_ARCH_CALLEE_SAVED_XREGS 0x0 +// Does the ABI have a volatile non-parameter register, so tailcall +// can pass context to generics or interfaces? +#define MONO_ARCH_HAVE_VOLATILE_NON_PARAM_REGISTER 0 // FIXME? + /*-----------------------------------------------*/ /* Macros used to generate instructions */ /*-----------------------------------------------*/ diff --git a/mono/mini/mini-sparc.c.REMOVED.git-id b/mono/mini/mini-sparc.c.REMOVED.git-id index 0e1d1a11d2..3ce4e84864 100644 --- a/mono/mini/mini-sparc.c.REMOVED.git-id +++ b/mono/mini/mini-sparc.c.REMOVED.git-id @@ -1 +1 @@ -bed8228bf24fd206d6134255110f548ddc9984a4 \ No newline at end of file +a4194ce08a2a0904a114ac0bc19943687d7c0057 \ No newline at end of file diff --git a/mono/mini/mini-sparc.h b/mono/mini/mini-sparc.h index 8140006cfe..0bea1fdbd7 100644 --- a/mono/mini/mini-sparc.h +++ b/mono/mini/mini-sparc.h @@ -37,7 +37,6 @@ #define MONO_ARCH_CALLEE_SAVED_FREGS 0 #define MONO_ARCH_USE_FPSTACK FALSE -#define MONO_ARCH_FPSTACK_SIZE 0 #ifdef SPARCV9 #define MONO_ARCH_INST_FIXED_REG(desc) ((desc == 'o') ? sparc_o0 : -1) #else @@ -108,6 +107,10 @@ typedef struct MonoCompileArch { #define MONO_ARCH_HAVE_DECOMPOSE_LONG_OPTS 1 #define MONO_ARCH_HAVE_TLS_INIT 1 +// Does the ABI have a volatile non-parameter register, so tailcall +// can pass context to generics or interfaces? +#define MONO_ARCH_HAVE_VOLATILE_NON_PARAM_REGISTER 0 // FIXME? + void mono_arch_tls_init (void); #ifdef SPARCV9 diff --git a/mono/mini/mini-trampolines.c b/mono/mini/mini-trampolines.c index 63ec68c1c8..f17214fbc8 100644 --- a/mono/mini/mini-trampolines.c +++ b/mono/mini/mini-trampolines.c @@ -203,7 +203,7 @@ mini_resolve_imt_method (MonoVTable *vt, gpointer *vtable_slot, MonoMethod *imt_ /* This has to be variance aware since imt_method can be from an interface that vt->klass doesn't directly implement */ interface_offset = mono_class_interface_offset_with_variance (vt->klass, imt_method->klass, &variance_used); if (interface_offset < 0) - g_error ("%s doesn't implement interface %s\n", mono_type_get_name_full (&vt->klass->byval_arg, MONO_TYPE_NAME_FORMAT_IL), mono_type_get_name_full (&imt_method->klass->byval_arg, MONO_TYPE_NAME_FORMAT_IL)); + g_error ("%s doesn't implement interface %s\n", mono_type_get_name_full (m_class_get_byval_arg (vt->klass), MONO_TYPE_NAME_FORMAT_IL), mono_type_get_name_full (m_class_get_byval_arg (imt_method->klass), MONO_TYPE_NAME_FORMAT_IL)); *variant_iface = NULL; if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst) { @@ -239,7 +239,7 @@ mini_resolve_imt_method (MonoVTable *vt, gpointer *vtable_slot, MonoMethod *imt_ } else { /* Avoid loading metadata or creating a generic vtable if possible */ - if (lookup_aot && !vt->klass->valuetype) { + if (lookup_aot && !m_class_is_valuetype (vt->klass)) { aot_addr = (guint8 *)mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, interface_offset + mono_method_get_vtable_slot (imt_method), error); return_val_if_nok (error, NULL); } else { @@ -594,8 +594,33 @@ common_call_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, MonoVTable * vtable_slot = mini_resolve_imt_method (vt, vtable_slot, imt_method, &impl_method, &addr, &need_rgctx_tramp, &variant_iface, error); return_val_if_nok (error, NULL); + if (mono_class_has_dim_conflicts (vt->klass)) { + GSList *conflicts = mono_class_get_dim_conflicts (vt->klass); + GSList *l; + MonoMethod *decl = imt_method; + + if (decl->is_inflated) + decl = mono_method_get_declaring_generic_method (decl); + + gboolean in_conflict = FALSE; + for (l = conflicts; l; l = l->next) { + if (decl == l->data) { + in_conflict = TRUE; + break; + } + } + if (in_conflict) { + char *class_name = mono_class_full_name (vt->klass); + char *method_name = mono_method_full_name (decl, TRUE); + mono_error_set_not_supported (error, "Interface method '%s' in class '%s' has multiple candidate implementations.", method_name, class_name); + g_free (class_name); + g_free (method_name); + return NULL; + } + } + /* We must handle magic interfaces on rank 1 arrays of ref types as if they were variant */ - if (!variant_iface && vt->klass->rank == 1 && !vt->klass->element_class->valuetype && imt_method->klass->is_array_special_interface) + if (!variant_iface && m_class_get_rank (vt->klass) == 1 && !m_class_is_valuetype (m_class_get_element_class (vt->klass)) && m_class_is_array_special_interface (imt_method->klass)) variant_iface = imt_method; /* This is the vcall slot which gets called through the IMT trampoline */ @@ -651,8 +676,6 @@ common_call_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, MonoVTable * vtable_slot = NULL; generic_shared = TRUE; - g_assert (code); - /* * The caller is gshared code, compute the actual method to call from M and this/rgctx. */ @@ -661,7 +684,7 @@ common_call_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, MonoVTable * klass = mrgctx->class_vtable->klass; method_inst = mrgctx->method_inst; - } else if ((m->flags & METHOD_ATTRIBUTE_STATIC) || m->klass->valuetype) { + } else if ((m->flags & METHOD_ATTRIBUTE_STATIC) || m_class_is_valuetype (m->klass)) { MonoVTable *vtable = mono_arch_find_static_call_vtable (regs, code); klass = vtable->klass; @@ -671,11 +694,11 @@ common_call_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, MonoVTable * vt = this_argument->vtable; vtable_slot = orig_vtable_slot; - g_assert (this_argument->vtable->klass->inited); + g_assert (m_class_is_inited (this_argument->vtable->klass)); if (!vtable_slot) { mono_class_setup_supertypes (this_argument->vtable->klass); - klass = this_argument->vtable->klass->supertypes [m->klass->idepth - 1]; + klass = m_class_get_supertypes (this_argument->vtable->klass) [m_class_get_idepth (m->klass) - 1]; } } @@ -688,7 +711,7 @@ common_call_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, MonoVTable * g_assert (displacement > 0); - actual_method = vt->klass->vtable [displacement]; + actual_method = m_class_get_vtable (vt->klass) [displacement]; } if (method_inst || m->wrapper_type) { @@ -729,19 +752,15 @@ common_call_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, MonoVTable * need_rgctx_tramp = FALSE; } - /* Calls made through delegates on platforms without delegate trampolines */ - if (!code && mono_method_needs_static_rgctx_invoke (m, FALSE)) - need_rgctx_tramp = TRUE; - addr = compiled_method = mono_jit_compile_method (m, error); if (!addr) return NULL; if (generic_virtual || variant_iface) { - if (vt->klass->valuetype) /*FIXME is this required variant iface?*/ + if (m_class_is_valuetype (vt->klass)) /*FIXME is this required variant iface?*/ need_unbox_tramp = TRUE; } else if (orig_vtable_slot) { - if (m->klass->valuetype) + if (m_class_is_valuetype (m->klass)) need_unbox_tramp = TRUE; } @@ -764,6 +783,8 @@ common_call_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, MonoVTable * if (!code) { MonoDomain *domain = mono_domain_get (); + mini_patch_jump_sites (domain, m, mono_get_addr_from_ftnptr (addr)); + /* Patch the got entries pointing to this method */ /* * We do this here instead of in mono_codegen () to cover the case when m @@ -915,7 +936,7 @@ mono_vcall_trampoline (mgreg_t *regs, guint8 *code, int slot, guint8 *tramp) /* Avoid loading metadata or creating a generic vtable if possible */ addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, slot, error); goto_if_nok (error, leave); - if (addr && !vt->klass->valuetype) { + if (addr && !m_class_is_valuetype (vt->klass)) { if (mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot)) *vtable_slot = addr; @@ -1178,7 +1199,7 @@ mono_delegate_trampoline (mgreg_t *regs, guint8 *code, gpointer *arg, guint8* tr } } - if (sig->hasthis && method->klass->valuetype) { + if (sig->hasthis && m_class_is_valuetype (method->klass)) { gboolean need_unbox = TRUE; if (tramp_info->invoke_sig->param_count > sig->param_count && tramp_info->invoke_sig->params [0]->byref) @@ -1196,7 +1217,7 @@ mono_delegate_trampoline (mgreg_t *regs, guint8 *code, gpointer *arg, guint8* tr // ftnptrs are being used. "method" would end up null on archtitectures without // ftnptrs so we can just skip this. } else if (delegate->method_ptr) { - ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (delegate->method_ptr)); + ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (delegate->method_ptr)); if (ji) method = jinfo_get_method (ji); } @@ -1608,7 +1629,7 @@ no_delegate_trampoline (void) gpointer mono_create_delegate_trampoline (MonoDomain *domain, MonoClass *klass) { - if (mono_llvm_only || mono_use_interpreter) + if (mono_llvm_only || (mono_use_interpreter && !mono_aot_only)) return no_delegate_trampoline; return mono_create_delegate_trampoline_info (domain, klass, NULL)->invoke_impl; @@ -1764,7 +1785,7 @@ mini_get_single_step_trampoline (void) /* * mini_get_breakpoint_trampoline: * - * Return a trampoline which calls debugger_agent_breakpoint_from_context (). + * Return a trampoline which calls mono_debugger_agent_breakpoint_from_context (). */ gpointer mini_get_breakpoint_trampoline (void) diff --git a/mono/mini/mini-wasm.c b/mono/mini/mini-wasm.c index 236892a486..8a4870235e 100644 --- a/mono/mini/mini-wasm.c +++ b/mono/mini/mini-wasm.c @@ -1,4 +1,39 @@ #include "mini.h" +#include "mini-runtime.h" +#include +#include +#include +#include +#include +#include + +//XXX This is dirty, extend ee.h to support extracting info from MonoInterpFrameHandle +#include + +#include + + +static int log_level = 1; + +#define DEBUG_PRINTF(level, ...) do { if (G_UNLIKELY ((level) <= log_level)) { fprintf (stdout, __VA_ARGS__); } } while (0) + +//functions exported to be used by JS +EMSCRIPTEN_KEEPALIVE int mono_wasm_set_breakpoint (const char *assembly_name, int method_token, int il_offset); +EMSCRIPTEN_KEEPALIVE void mono_set_timeout_exec (int id); +EMSCRIPTEN_KEEPALIVE int mono_wasm_current_bp_id (void); +EMSCRIPTEN_KEEPALIVE void mono_wasm_enum_frames (void); +EMSCRIPTEN_KEEPALIVE void mono_wasm_get_var_info (int scope, int pos); + +//JS functions imported that we use +extern void mono_wasm_add_frame (int il_offset, int method_token, const char *assembly_name); +extern void mono_wasm_fire_bp (void); +extern void mono_set_timeout (int t, int d); +extern void mono_wasm_add_bool_var (gint8); +extern void mono_wasm_add_int_var (gint32); +extern void mono_wasm_add_long_var (gint64); +extern void mono_wasm_add_float_var (float); +extern void mono_wasm_add_double_var (double); +extern void mono_wasm_add_string_var (const char*); gpointer @@ -154,9 +189,64 @@ mono_thread_state_init_from_handle (MonoThreadUnwindState *tctx, MonoThreadInfo } +EMSCRIPTEN_KEEPALIVE void +mono_set_timeout_exec (int id) +{ + ERROR_DECL (error); + MonoClass *klass = mono_class_load_from_name (mono_defaults.corlib, "System.Threading", "WasmRuntime"); + g_assert (klass); + + MonoMethod *method = mono_class_get_method_from_name (klass, "TimeoutCallback", -1); + g_assert (method); + + gpointer params[1] = { &id }; + MonoObject *exc = NULL; + + mono_runtime_try_invoke (method, NULL, params, &exc, error); + + //YES we swallow exceptions cuz there's nothing much we can do from here. + //FIXME Maybe call the unhandled exception function? + if (!is_ok (error)) { + printf ("timeout callback failed due to %s\n", mono_error_get_message (error)); + mono_error_cleanup (error); + } + + if (exc) { + char *type_name = mono_type_get_full_name (mono_object_get_class (exc)); + printf ("timeout callback threw a %s\n", type_name); + g_free (type_name); + } +} + +void +mono_wasm_set_timeout (int timeout, int id) +{ + mono_set_timeout (timeout, id); +} + +void +mono_arch_register_icall (void) +{ + mono_add_internal_call ("System.Threading.WasmRuntime::SetTimeout", mono_wasm_set_timeout); +} + +void +mono_arch_patch_code_new (MonoCompile *cfg, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gpointer target) +{ + g_error ("mono_arch_patch_code_new"); +} + /* 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); +void * getgrnam (const char *name); +void * getgrgid (gid_t gid); +int inotify_init (void); +int inotify_rm_watch (int fd, int wd); +int inotify_add_watch (int fd, const char *pathname, uint32_t mask); +int sem_timedwait (sem_t *sem, const struct timespec *abs_timeout); + //w32file-wasm.c gboolean @@ -260,3 +350,589 @@ sem_timedwait (sem_t *sem, const struct timespec *abs_timeout) return 0; } + + +typedef struct { + //request data + MonoAssembly *assembly; + MonoMethod *method; + int il_offset; + + //bp id + int bp_id; + + + GPtrArray *children; +} BreakPointRequest; + +typedef struct { + long il_offset, native_offset; + guint8 *ip; + MonoJitInfo *ji; + MonoDomain *domain; +} BreakpointInstance; + + +//FIXME move all of those fields to the profiler object +static gboolean debugger_enabled; +static int bp_id_count; +static GHashTable *bp_locs; +static GPtrArray *active_breakpoints; + +static void +breakpoint_request_free (BreakPointRequest *bp) +{ + g_free (bp); +} + +static void +inplace_tolower (char *c) +{ + int i; + for (i = strlen (c) - 1; i >= 0; --i) + c [i] = tolower (c [i]); +} + +static BreakPointRequest * +breakpoint_request_new (MonoAssembly *assembly, MonoMethod *method, int il_offset) +{ + //dup and lower + BreakPointRequest *req = g_new0(BreakPointRequest, 1); + req->assembly = assembly; + req->method = method; + req->il_offset = il_offset; + + return req; +} + +static gboolean +breakpoint_matches (BreakPointRequest *bp, MonoMethod *method) +{ + if (!bp->method) + return FALSE; + if (method == bp->method) + return TRUE; + if (method->is_inflated && ((MonoMethodInflated*)method)->declaring == bp->method) + return TRUE; + //XXX we don't support setting a breakpoint on a specif ginst, so whatever + + return FALSE; +} +//LOCKING: loader lock must be held +static void +find_applicable_methods (BreakPointRequest *bp, GPtrArray *methods, GPtrArray *method_seq_points) +{ + GHashTableIter iter; + MonoMethod *method; + MonoSeqPointInfo *seq_points; + + mono_domain_lock (mono_get_root_domain ()); + g_hash_table_iter_init (&iter, domain_jit_info (mono_get_root_domain ())->seq_points); + while (g_hash_table_iter_next (&iter, (void**)&method, (void**)&seq_points)) { + if (breakpoint_matches (bp, method)) { + g_ptr_array_add (methods, method); + g_ptr_array_add (method_seq_points, seq_points); + } + } + mono_domain_unlock (mono_get_root_domain ()); +} + +static gboolean +insert_breakpoint (MonoSeqPointInfo *seq_points, MonoDomain *domain, MonoJitInfo *ji, BreakPointRequest *bp, MonoError *error) +{ + int count; + SeqPointIterator it; + gboolean it_has_sp = FALSE; + + error_init (error); + + DEBUG_PRINTF (1, "insert_breakpoint: JI [%p] method %s at %d SP %p\n", ji, jinfo_get_method (ji)->name, bp->il_offset, seq_points); + + mono_seq_point_iterator_init (&it, seq_points); + while (mono_seq_point_iterator_next (&it)) { + if (it.seq_point.il_offset == bp->il_offset) { + it_has_sp = TRUE; + break; + } + } + + if (!it_has_sp) { + /* + * The set of IL offsets with seq points doesn't completely match the + * info returned by CMD_METHOD_GET_DEBUG_INFO (#407). + */ + mono_seq_point_iterator_init (&it, seq_points); + while (mono_seq_point_iterator_next (&it)) { + if (it.seq_point.il_offset != METHOD_ENTRY_IL_OFFSET && + it.seq_point.il_offset != METHOD_EXIT_IL_OFFSET && + it.seq_point.il_offset + 1 == bp->il_offset) { + it_has_sp = TRUE; + break; + } + } + } + + if (!it_has_sp) { + DEBUG_PRINTF (1, "Unable to insert breakpoint at %s:%d. SeqPoint data:", mono_method_full_name (jinfo_get_method (ji), TRUE), bp->il_offset); + + mono_seq_point_iterator_init (&it, seq_points); + while (mono_seq_point_iterator_next (&it)) + DEBUG_PRINTF (1, "\t%d\n", it.seq_point.il_offset); + + DEBUG_PRINTF (1, "End of data\n"); + mono_error_set_error (error, MONO_ERROR_GENERIC, "Failed to find the SP for the given il offset"); + return FALSE; + } + + BreakpointInstance *inst = g_new0 (BreakpointInstance, 1); + inst->il_offset = it.seq_point.il_offset; + inst->native_offset = it.seq_point.native_offset; + inst->ip = (guint8*)ji->code_start + it.seq_point.native_offset; + inst->ji = ji; + inst->domain = mono_get_root_domain (); + + mono_loader_lock (); + + if (!bp->children) + bp->children = g_ptr_array_new (); + g_ptr_array_add (bp->children, inst); + + mono_loader_unlock (); + + // dbg_lock (); + count = GPOINTER_TO_INT (g_hash_table_lookup (bp_locs, inst->ip)); + g_hash_table_insert (bp_locs, inst->ip, GINT_TO_POINTER (count + 1)); + // dbg_unlock (); + + if (it.seq_point.native_offset == SEQ_POINT_NATIVE_OFFSET_DEAD_CODE) { + DEBUG_PRINTF (1, "Attempting to insert seq point at dead IL offset %d, ignoring.\n", (int)bp->il_offset); + } else if (count == 0) { + DEBUG_PRINTF (1, "ACTIVATING BREAKPOINT in %s\n", jinfo_get_method (ji)->name); + if (ji->is_interp) { + mini_get_interp_callbacks ()->set_breakpoint (ji, inst->ip); + } else { + g_error ("no idea how to deal with compiled code"); +#ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED + mono_arch_set_breakpoint (ji, inst->ip); +#else + NOT_IMPLEMENTED; +#endif + } + } + + return TRUE; +} + +static gboolean +set_breakpoint (MonoMethod *method, MonoSeqPointInfo *seq_points, BreakPointRequest *bp, MonoError *error) +{ + MonoJitInfo *ji = NULL; + + error_init (error); + + MonoDomain *domain = mono_get_root_domain (); + gpointer code = mono_jit_find_compiled_method_with_jit_info (domain, method, &ji); + if (!code) { + /* Might be AOTed code */ + mono_class_init (method->klass); + code = mono_aot_get_method (domain, method, error); + if (code) { + mono_error_assert_ok (error); + ji = mono_jit_info_table_find (domain, code); + } else { + /* Might be interpreted */ + ji = mini_get_interp_callbacks ()->find_jit_info (domain, method); + } + g_assert (ji); + } + + return insert_breakpoint (seq_points, domain, ji, bp, error); +} + +static void +add_breakpoint (BreakPointRequest *bp) +{ + int i; + ERROR_DECL (error); + bp->bp_id = ++bp_id_count; + + error_init (error); + + GPtrArray *methods = g_ptr_array_new (); + GPtrArray *method_seq_points = g_ptr_array_new (); + + mono_loader_lock (); + + find_applicable_methods (bp, methods, method_seq_points); + + for (i = 0; i < methods->len; ++i) { + MonoMethod *method = (MonoMethod *)g_ptr_array_index (methods, i); + MonoSeqPointInfo *seq_points = (MonoSeqPointInfo *)g_ptr_array_index (method_seq_points, i); + + if (!set_breakpoint (method, seq_points, bp, error)) { + //FIXME don't swallow the error + DEBUG_PRINTF (1, "Error setting breaking due to %s\n", mono_error_get_message (error)); + mono_error_cleanup (error); + return; + } + } + + g_ptr_array_add (active_breakpoints, bp); + + mono_loader_unlock (); + + g_ptr_array_free (methods, TRUE); + g_ptr_array_free (method_seq_points, TRUE); +} + +static void +add_pending_breakpoints (MonoMethod *method, MonoJitInfo *ji) +{ + int i, j; + MonoSeqPointInfo *seq_points; + MonoDomain *domain; + MonoMethod *jmethod; + + if (!active_breakpoints) + return; + + domain = mono_domain_get (); + + mono_loader_lock (); + + for (i = 0; i < active_breakpoints->len; ++i) { + BreakPointRequest *bp = (BreakPointRequest *)g_ptr_array_index (active_breakpoints, i); + gboolean found = FALSE; + + if (!breakpoint_matches (bp, method)) + continue; + + for (j = 0; j < bp->children->len; ++j) { + BreakpointInstance *inst = (BreakpointInstance *)g_ptr_array_index (bp->children, j); + + if (inst->ji == ji) + found = TRUE; + } + + if (!found) { + ERROR_DECL (error); + MonoMethod *declaring = NULL; + + jmethod = jinfo_get_method (ji); + if (jmethod->is_inflated) + declaring = mono_method_get_declaring_generic_method (jmethod); + + mono_domain_lock (domain); + seq_points = (MonoSeqPointInfo *)g_hash_table_lookup (domain_jit_info (domain)->seq_points, jmethod); + if (!seq_points && declaring) + seq_points = (MonoSeqPointInfo *)g_hash_table_lookup (domain_jit_info (domain)->seq_points, declaring); + mono_domain_unlock (domain); + if (!seq_points) { + /* Could be AOT code */ + continue; + } + g_assert (seq_points); + + if (!insert_breakpoint (seq_points, domain, ji, bp, error)) { + DEBUG_PRINTF (1, "Failed to resolve pending BP due to %s\n", mono_error_get_message (error)); + mono_error_cleanup (error); + } + } + } + + mono_loader_unlock (); +} + +static void +jit_done (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo) +{ + add_pending_breakpoints (method, jinfo); +} + +void +mono_wasm_debugger_init (void) +{ + if (!debugger_enabled) + return; + + mono_debug_init (MONO_DEBUG_FORMAT_MONO); + mini_get_debug_options ()->gen_sdb_seq_points = TRUE; + mini_get_debug_options ()->mdb_optimizations = TRUE; + mono_disable_optimizations (MONO_OPT_LINEARS); + mini_get_debug_options ()->load_aot_jit_info_eagerly = TRUE; + + MonoProfilerHandle prof = mono_profiler_create (NULL); + mono_profiler_set_jit_done_callback (prof, jit_done); + + bp_locs = g_hash_table_new (NULL, NULL); + active_breakpoints = g_ptr_array_new (); +} + +MONO_API void +mono_wasm_enable_debugging (void) +{ + DEBUG_PRINTF (1, "DEBUGGING ENABLED"); + debugger_enabled = TRUE; +} + + +EMSCRIPTEN_KEEPALIVE int +mono_wasm_set_breakpoint (const char *assembly_name, int method_token, int il_offset) +{ + int i; + ERROR_DECL (error); + DEBUG_PRINTF (1, "SET BREAKPOINT: assembly %s method %x offset %x\n", assembly_name, method_token, il_offset); + + + //we get 'foo.dll' but mono_assembly_load expects 'foo' so we strip the last dot + char *lookup_name = g_strdup (assembly_name); + for (i = strlen (lookup_name) - 1; i >= 0; --i) { + if (lookup_name [i] == '.') { + lookup_name [i] = 0; + break; + } + } + + //resolve the assembly + MonoImageOpenStatus status; + MonoAssemblyName* aname = mono_assembly_name_new (lookup_name); + MonoAssembly *assembly = mono_assembly_load (aname, NULL, &status); + g_free (lookup_name); + if (!assembly) { + DEBUG_PRINTF (1, "Could not resolve assembly %s\n", assembly_name); + return -1; + } + + mono_assembly_name_free (aname); + + MonoMethod *method = mono_get_method_checked (assembly->image, MONO_TOKEN_METHOD_DEF | method_token, NULL, NULL, error); + if (!method) { + //FIXME don't swallow the error + DEBUG_PRINTF (1, "Could not find method due to %s\n", mono_error_get_message (error)); + mono_error_cleanup (error); + return -1; + } + + BreakPointRequest *req = breakpoint_request_new (assembly, method, il_offset); + + add_breakpoint (req); + return req->bp_id; +} + +//trampoline + +void +mono_wasm_breakpoint_hit (void) +{ + mono_wasm_fire_bp (); +} + +EMSCRIPTEN_KEEPALIVE int +mono_wasm_current_bp_id (void) +{ + int i, j; + + DEBUG_PRINTF (1, "COMPUTING breapoint ID\n"); + //FIXME handle compiled case + + /* Interpreter */ + MonoLMF *lmf = mono_get_lmf (); + + g_assert (((guint64)lmf->previous_lmf) & 2); + MonoLMFExt *ext = (MonoLMFExt*)lmf; + + g_assert (ext->interp_exit); + MonoInterpFrameHandle *frame = ext->interp_exit_data; + MonoJitInfo *ji = mini_get_interp_callbacks ()->frame_get_jit_info (frame); + guint8 *ip = mini_get_interp_callbacks ()->frame_get_ip (frame); + + g_assert (ji && !ji->is_trampoline); + MonoMethod *method = jinfo_get_method (ji); + + /* Compute the native offset of the breakpoint from the ip */ + guint32 native_offset = ip - (guint8*)ji->code_start; + + MonoSeqPointInfo *info = NULL; + SeqPoint sp; + gboolean found_sp = mono_find_prev_seq_point_for_native_offset (mono_domain_get (), method, native_offset, &info, &sp); + if (!found_sp) + DEBUG_PRINTF (1, "Could not find SP\n"); + + for (i = 0; i < active_breakpoints->len; ++i) { + BreakPointRequest *bp = (BreakPointRequest *)g_ptr_array_index (active_breakpoints, i); + + if (!bp->method) + continue; + + for (j = 0; j < bp->children->len; ++j) { + BreakpointInstance *inst = (BreakpointInstance *)g_ptr_array_index (bp->children, j); + if (inst->ji == ji && inst->il_offset == sp.il_offset && inst->native_offset == sp.native_offset) { + DEBUG_PRINTF (1, "FOUND BREAKPOINT idx %d ID %d\n", i, bp->bp_id); + return bp->bp_id; + } + } + } + DEBUG_PRINTF (1, "BP NOT FOUND for method %s JI %p il_offset %d\n", method->name, ji, sp.il_offset); + + return -1; +} + +static gboolean +list_frames (MonoStackFrameInfo *info, MonoContext *ctx, gpointer data) +{ + SeqPoint sp; + MonoMethod *method; + + //skip wrappers + if (info->type != FRAME_TYPE_MANAGED && info->type != FRAME_TYPE_INTERP) + return FALSE; + + + if (info->ji) + method = jinfo_get_method (info->ji); + else + method = info->method; + + if (!method) + return FALSE; + + DEBUG_PRINTF (2, "Reporting method %s native_offset %d\n", method->name, info->native_offset); + + if (!mono_find_prev_seq_point_for_native_offset (mono_get_root_domain (), method, info->native_offset, NULL, &sp)) + DEBUG_PRINTF (1, "Failed to lookup sequence point\n"); + + while (method->is_inflated) + method = ((MonoMethodInflated*)method)->declaring; + + char *assembly_name = g_strdup (m_class_get_image (method->klass)->module_name); + inplace_tolower (assembly_name); + + if (method->wrapper_type == MONO_WRAPPER_NONE) { + DEBUG_PRINTF (2, "adding off %d token %d assembly name %s\n", sp.il_offset, mono_metadata_token_index (method->token), assembly_name); + mono_wasm_add_frame (sp.il_offset, mono_metadata_token_index (method->token), assembly_name); + } + + g_free (assembly_name); + + return FALSE; +} + +EMSCRIPTEN_KEEPALIVE void +mono_wasm_enum_frames (void) +{ + mono_walk_stack_with_ctx (list_frames, NULL, MONO_UNWIND_NONE, NULL); +} + +typedef struct { + int cur_frame; + int target_frame; + int variable; +} FrameDescData; + +static gboolean +describe_variable (MonoStackFrameInfo *info, MonoContext *ctx, gpointer ud) +{ + ERROR_DECL (error); + MonoMethodHeader *header = NULL; + + FrameDescData *data = ud; + + //skip wrappers + if (info->type != FRAME_TYPE_MANAGED && info->type != FRAME_TYPE_INTERP) { + return FALSE; + } + + if (data->cur_frame < data->target_frame) { + ++data->cur_frame; + return FALSE; + } + + InterpFrame *frame = info->interp_frame; + g_assert (frame); + MonoMethod *method = frame->imethod->method; + g_assert (method); + + MonoType *type = NULL; + gpointer addr = NULL; + int pos = data->variable; + if (pos < 0) { + pos = -pos - 1; + type = mono_method_signature (method)->params [pos]; + addr = mini_get_interp_callbacks ()->frame_get_arg (frame, pos); + } else { + header = mono_method_get_header_checked (method, error); + mono_error_assert_ok (error); /* FIXME report error */ + + type = header->locals [pos]; + addr = mini_get_interp_callbacks ()->frame_get_local (frame, pos); + } + + DEBUG_PRINTF (2, "adding val %p type [%p] %s\n", addr, type, mono_type_full_name (type)); + + switch (type->type) { + case MONO_TYPE_BOOLEAN: + mono_wasm_add_bool_var (*(gint8*)addr); + break; + case MONO_TYPE_I1: + case MONO_TYPE_U1: + mono_wasm_add_int_var (*(gint8*)addr); + break; + case MONO_TYPE_CHAR: + case MONO_TYPE_I2: + case MONO_TYPE_U2: + mono_wasm_add_int_var (*(gint16*)addr); + break; + case MONO_TYPE_I4: + case MONO_TYPE_U4: + case MONO_TYPE_I: + case MONO_TYPE_U: + mono_wasm_add_int_var (*(gint32*)addr); + break; + case MONO_TYPE_I8: + case MONO_TYPE_U8: + mono_wasm_add_long_var (*(gint32*)addr); + break; + case MONO_TYPE_R4: + mono_wasm_add_float_var (*(float*)addr); + break; + case MONO_TYPE_R8: + mono_wasm_add_float_var (*(double*)addr); + break; + case MONO_TYPE_STRING: { + MonoString *str_obj = *(MonoString **)addr; + if (!str_obj) + mono_wasm_add_string_var (NULL); + char *str = mono_string_to_utf8_checked (str_obj, error); + mono_error_assert_ok (error); /* FIXME report error */ + + mono_wasm_add_string_var (str); + g_free (str); + break; + } + default: { + char *type_name = mono_type_full_name (type); + char *msg = g_strdup_printf("can't handle type %s [%p, %x]", type_name, type, type->type); + mono_wasm_add_string_var (msg); + g_free (msg); + g_free (type_name); + } + } + if (header) + mono_metadata_free_mh (header); + + return TRUE; +} + +//FIXME this doesn't support getting the return value pseudo-var +EMSCRIPTEN_KEEPALIVE void +mono_wasm_get_var_info (int scope, int pos) +{ + DEBUG_PRINTF (2, "getting var %d of scope %d\n", pos, scope); + + FrameDescData data; + data.cur_frame = 0; + data.target_frame = scope; + data.variable = pos; + + mono_walk_stack_with_ctx (describe_variable, NULL, MONO_UNWIND_NONE, &data); +} diff --git a/mono/mini/mini-wasm.h b/mono/mini/mini-wasm.h index e4f76af6f0..99178ac850 100644 --- a/mono/mini/mini-wasm.h +++ b/mono/mini/mini-wasm.h @@ -20,9 +20,7 @@ struct MonoLMF { gpointer previous_lmf; gpointer lmf_addr; - /* This is only set in trampoline LMF frames */ - MonoMethod *method; - + /* This is set to signal this is the top lmf entry */ gboolean top_entry; }; @@ -35,10 +33,11 @@ typedef struct { #define MONO_CONTEXT_SET_LLVM_EXC_REG(ctx, exc) do { (ctx)->llvm_exc_reg = (gsize)exc; } while (0) #define MONO_INIT_CONTEXT_FROM_FUNC(ctx,start_func) do { \ - MONO_CONTEXT_SET_IP ((ctx), (start_func)); \ - MONO_CONTEXT_SET_BP ((ctx), (0)); \ - MONO_CONTEXT_SET_SP ((ctx), (0)); \ - } while (0) + int ___tmp = 99; \ + MONO_CONTEXT_SET_IP ((ctx), (start_func)); \ + MONO_CONTEXT_SET_BP ((ctx), (0)); \ + MONO_CONTEXT_SET_SP ((ctx), (&___tmp)); \ +} while (0) #define MONO_ARCH_VTABLE_REG WASM_REG_0 @@ -48,4 +47,14 @@ typedef struct { /* must be at a power of 2 and >= 8 */ #define MONO_ARCH_FRAME_ALIGNMENT 16 +#define MONO_ARCH_INTERPRETER_SUPPORTED 1 +#define MONO_ARCH_HAS_REGISTER_ICALL 1 +#define MONO_ARCH_HAVE_PATCH_CODE_NEW 1 + +void mono_wasm_debugger_init (void); + +void mono_wasm_enable_debugging (void); +void mono_wasm_breakpoint_hit (void); +void mono_wasm_set_timeout (int timeout, int id); + #endif /* __MONO_MINI_WASM_H__ */ diff --git a/mono/mini/mini-x86-gsharedvt.c b/mono/mini/mini-x86-gsharedvt.c index 7aea192c9d..8cb1f514fb 100644 --- a/mono/mini/mini-x86-gsharedvt.c +++ b/mono/mini/mini-x86-gsharedvt.c @@ -12,8 +12,6 @@ #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED -#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1)) - /* * GSHAREDVT */ diff --git a/mono/mini/mini-x86.c.REMOVED.git-id b/mono/mini/mini-x86.c.REMOVED.git-id index df9aaaf8af..17d21abce5 100644 --- a/mono/mini/mini-x86.c.REMOVED.git-id +++ b/mono/mini/mini-x86.c.REMOVED.git-id @@ -1 +1 @@ -7f79e2fdba6c8fb8406d80cb5d8554af451ee962 \ No newline at end of file +f7a22970ee8c2e4b6eb06ac03b0c9d67763429c6 \ No newline at end of file diff --git a/mono/mini/mini-x86.h b/mono/mini/mini-x86.h index b7de33748f..a4dab679a6 100644 --- a/mono/mini/mini-x86.h +++ b/mono/mini/mini-x86.h @@ -198,9 +198,7 @@ typedef struct { #define MONO_ARCH_IMT_REG X86_EDX #define MONO_ARCH_VTABLE_REG X86_EDX #define MONO_ARCH_RGCTX_REG MONO_ARCH_IMT_REG -#define MONO_ARCH_EXC_REG X86_EAX #define MONO_ARCH_HAVE_GENERALIZED_IMT_TRAMPOLINE 1 -#define MONO_ARCH_HAVE_LIVERANGE_OPS 1 #define MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX 1 #define MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES 1 #define MONO_ARCH_GOT_REG X86_EBX @@ -231,8 +229,6 @@ typedef struct { #define MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK 1 #define MONO_ARCH_GSHAREDVT_SUPPORTED 1 #define MONO_ARCH_HAVE_OP_TAIL_CALL 1 -#define MONO_ARCH_HAVE_TRANSLATE_TLS_OFFSET 1 -#define MONO_ARCH_HAVE_DUMMY_INIT 1 #define MONO_ARCH_HAVE_SDB_TRAMPOLINES 1 #define MONO_ARCH_HAVE_PATCH_CODE_NEW 1 @@ -249,6 +245,10 @@ typedef struct { MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException"); \ } while (0) +// Does the ABI have a volatile non-parameter register, so tailcall +// can pass context to generics or interfaces? +#define MONO_ARCH_HAVE_VOLATILE_NON_PARAM_REGISTER 1 + /* Return value marshalling for calls between gsharedvt and normal code */ typedef enum { GSHAREDVT_RET_NONE = 0, diff --git a/mono/mini/mini.c.REMOVED.git-id b/mono/mini/mini.c.REMOVED.git-id index a55d7f5538..66a936131a 100644 --- a/mono/mini/mini.c.REMOVED.git-id +++ b/mono/mini/mini.c.REMOVED.git-id @@ -1 +1 @@ -9956fa202cdd0264f9863369cd02938b3ce0549e \ No newline at end of file +35d000902c9db262b9884149efc349e1f59288d3 \ No newline at end of file diff --git a/mono/mini/mini.h.REMOVED.git-id b/mono/mini/mini.h.REMOVED.git-id index 37248205c7..ad5d9f2b7b 100644 --- a/mono/mini/mini.h.REMOVED.git-id +++ b/mono/mini/mini.h.REMOVED.git-id @@ -1 +1 @@ -c9ef3d396433f9c5e079412d64ad4a673e61f988 \ No newline at end of file +317bc7c6ef200a6b591f2cbb6e52fbaf4170eaa6 \ No newline at end of file diff --git a/mono/mini/mixed.cs b/mono/mini/mixed.cs index 940c19345e..5d4b808895 100644 --- a/mono/mini/mixed.cs +++ b/mono/mini/mixed.cs @@ -80,6 +80,11 @@ class InterpClass return new StackTrace (true); } + [MethodImplAttribute (MethodImplOptions.NoInlining)] + public static StackTrace get_stacktrace_interp2 () { + return JitClass.get_stacktrace_jit (); + } + [MethodImplAttribute (MethodImplOptions.NoInlining)] public static void throw_ex () { JitClass.throw_ex (); @@ -161,6 +166,11 @@ class JitClass public static StackTrace get_stacktrace_jit () { return InterpClass.get_stacktrace_interp (); } + + [MethodImplAttribute (MethodImplOptions.NoInlining)] + public static StackTrace get_stacktrace_jit2 () { + return InterpClass.get_stacktrace_interp2 (); + } } #if __MOBILE__ @@ -249,16 +259,28 @@ class Tests // // Get a stacktrace for an interp->jit->interp call stack // - StackTrace st = JitClass.get_stacktrace_jit (); - var frame = st.GetFrame (0); - if (frame.GetMethod ().Name != "get_stacktrace_interp") + StackTrace st = JitClass.get_stacktrace_jit2 (); + + var frame0 = st.GetFrame (0); + var frame1 = st.GetFrame (1); + var frame2 = st.GetFrame (2); + var frame3 = st.GetFrame (3); + var frame4 = st.GetFrame (4); + + if (frame0.GetMethod ().Name != "get_stacktrace_interp") return 1; - frame = st.GetFrame (1); - if (frame.GetMethod ().Name != "get_stacktrace_jit") + + if (frame1.GetMethod ().Name != "get_stacktrace_jit") return 2; - frame = st.GetFrame (2); - if (frame.GetMethod ().Name != "test_0_stack_traces") + + if (frame2.GetMethod ().Name != "get_stacktrace_interp2") return 3; + + if (frame3.GetMethod ().Name != "get_stacktrace_jit2") + return 4; + + if (frame4.GetMethod ().Name != "test_0_stack_traces") + return 5; return 0; } } \ No newline at end of file diff --git a/mono/mini/objects.cs b/mono/mini/objects.cs index d873b6e784..82d3e8de23 100644 --- a/mono/mini/objects.cs +++ b/mono/mini/objects.cs @@ -1836,6 +1836,31 @@ ncells ) { return 0; } + enum FooEnum { Bar } + //https://github.com/mono/mono/issues/6666 + public static int test_0_bad_unbox_nullable_of_enum () { + try { + var enumValue = FooEnum.Bar; + object value = (int)enumValue; + var res = (FooEnum?)value; // Should throw + } catch (InvalidCastException) { + return 0; + } + return 1; + } + + //https://github.com/mono/mono/issues/6666 + public static int test_0_unbox_nullable_of_enum () { + try { + var enumValue = FooEnum.Bar; + object value = (object)enumValue; + var res = (FooEnum?)value; // Should not throw + } catch (InvalidCastException) { + return 1; + } + return 0; + } + static void decode (out sbyte v) { byte tmp = 134; v = (sbyte)tmp; @@ -1872,6 +1897,16 @@ ncells ) { return 0; } + + static volatile bool abool; + + public static unsafe int test_0_stind_r4_float32_stack_merge () { + Single* dataPtr = stackalloc Single[4]; + abool = true; + dataPtr[0] = abool ? 1.0f : 2.0f; + return dataPtr [0] == 1.0f ? 0 : 1; + } + } #if __MOBILE__ diff --git a/mono/mini/seq-points.c b/mono/mini/seq-points.c index 4bb9871147..8f8c08a3ba 100644 --- a/mono/mini/seq-points.c +++ b/mono/mini/seq-points.c @@ -253,12 +253,14 @@ mono_save_seq_point_info (MonoCompile *cfg) MonoSeqPointInfo* mono_get_seq_points (MonoDomain *domain, MonoMethod *method) { + ERROR_DECL (error); MonoSeqPointInfo *seq_points; MonoMethod *declaring_generic_method = NULL, *shared_method = NULL; if (method->is_inflated) { declaring_generic_method = mono_method_get_declaring_generic_method (method); - shared_method = mini_get_shared_method (method); + shared_method = mini_get_shared_method_full (method, SHARE_MODE_NONE, error); + mono_error_assert_ok (error); } mono_loader_lock (); diff --git a/mono/mini/simd-intrinsics.c b/mono/mini/simd-intrinsics.c index 01530aa55a..dfaf3f9cbf 100644 --- a/mono/mini/simd-intrinsics.c +++ b/mono/mini/simd-intrinsics.c @@ -671,7 +671,7 @@ mono_simd_simplify_indirection (MonoCompile *cfg) for (i = 0; i < cfg->num_varinfo; i++) { MonoInst *var = cfg->varinfo [i]; - if (var->klass->simd_type) { + if (m_class_is_simd_type (var->klass)) { var->flags &= ~MONO_INST_INDIRECT; max_vreg = MAX (var->dreg, max_vreg); } @@ -683,7 +683,7 @@ mono_simd_simplify_indirection (MonoCompile *cfg) for (ins = bb->code; ins; ins = ins->next) { if (ins->opcode == OP_LDADDR) { MonoInst *var = (MonoInst*)ins->inst_p0; - if (var->klass->simd_type) { + if (m_class_is_simd_type (var->klass)) { var->flags |= MONO_INST_INDIRECT; } } @@ -696,7 +696,7 @@ mono_simd_simplify_indirection (MonoCompile *cfg) for (i = 0; i < cfg->num_varinfo; i++) { MonoInst *var = cfg->varinfo [i]; - if (var->klass->simd_type && !(var->flags & (MONO_INST_INDIRECT|MONO_INST_VOLATILE))) { + if (m_class_is_simd_type (var->klass) && !(var->flags & (MONO_INST_INDIRECT|MONO_INST_VOLATILE))) { vreg_flags [var->dreg] = VREG_USED; DEBUG (printf ("[simd-simplify] processing var %d with vreg %d\n", i, var->dreg)); } @@ -728,7 +728,7 @@ mono_simd_simplify_indirection (MonoCompile *cfg) if (IS_DEBUG_ON (cfg)) { for (i = 0; i < cfg->num_varinfo; i++) { MonoInst *var = cfg->varinfo [i]; - if (var->klass->simd_type) { + if (m_class_is_simd_type (var->klass)) { if ((vreg_flags [var->dreg] & VREG_HAS_XZERO_BB0)) DEBUG (printf ("[simd-simplify] R%d has xzero only\n", var->dreg)); if ((vreg_flags [var->dreg] & VREG_HAS_OTHER_OP_BB0)) @@ -770,7 +770,7 @@ mono_simd_simplify_indirection (MonoCompile *cfg) for (i = 0; i < cfg->num_varinfo; i++) { MonoInst *var = cfg->varinfo [i]; - if (!var->klass->simd_type) + if (!m_class_is_simd_type (var->klass)) continue; if ((vreg_flags [var->dreg] & VREG_SINGLE_BB_USE)) DEBUG (printf ("[simd-simplify] R%d has single bb use\n", var->dreg)); @@ -884,7 +884,7 @@ static MonoInst* get_double_spill_area (MonoCompile *cfg) { if (!cfg->fconv_to_r8_x_var) { - cfg->fconv_to_r8_x_var = mono_compile_create_var (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL); + cfg->fconv_to_r8_x_var = mono_compile_create_var (cfg, m_class_get_byval_arg (mono_defaults.double_class), OP_LOCAL); cfg->fconv_to_r8_x_var->flags |= MONO_INST_VOLATILE; /*FIXME, use the don't regalloc flag*/ } return cfg->fconv_to_r8_x_var; @@ -893,7 +893,7 @@ static MonoInst* get_simd_ctor_spill_area (MonoCompile *cfg, MonoClass *avector_klass) { if (!cfg->simd_ctor_var) { - cfg->simd_ctor_var = mono_compile_create_var (cfg, &avector_klass->byval_arg, OP_LOCAL); + cfg->simd_ctor_var = mono_compile_create_var (cfg, m_class_get_byval_arg (avector_klass), OP_LOCAL); cfg->simd_ctor_var->flags |= MONO_INST_VOLATILE; /*FIXME, use the don't regalloc flag*/ } return cfg->simd_ctor_var; @@ -1157,7 +1157,7 @@ get_simd_vreg_or_expanded_scalar (MonoCompile *cfg, MonoClass *klass, MonoType * MonoInst *ins; int expand_op; - if (mono_class_from_mono_type (param_type)->simd_type) + if (m_class_is_simd_type (mono_class_from_mono_type (param_type))) return get_simd_vreg (cfg, NULL, src); expand_op = mono_type_to_expand_op (param_type); @@ -1818,12 +1818,12 @@ emit_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi { const SimdIntrinsic *result = (const SimdIntrinsic *)mono_binary_search (cmethod->name, intrinsics, size, sizeof (SimdIntrinsic), &simd_intrinsic_compare_by_name); if (!result) { - DEBUG (printf ("function doesn't have a simd intrinsic %s::%s/%d\n", cmethod->klass->name, cmethod->name, fsig->param_count)); + DEBUG (printf ("function doesn't have a simd intrinsic %s::%s/%d\n", m_class_get_name (cmethod->klass), cmethod->name, fsig->param_count)); return NULL; } if (IS_DEBUG_ON (cfg)) { int i, max; - printf ("found call to intrinsic %s::%s/%d -> %s\n", cmethod->klass->name, cmethod->name, fsig->param_count, method_name (result->name)); + printf ("found call to intrinsic %s::%s/%d -> %s\n", m_class_get_name (cmethod->klass), cmethod->name, fsig->param_count, method_name (result->name)); max = fsig->param_count + fsig->hasthis; for (i = 0; i < max; ++i) { printf ("param %d: ", i); @@ -1833,7 +1833,7 @@ emit_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi if (result->simd_version_flags && !(result->simd_version_flags & simd_supported_versions)) { if (IS_DEBUG_ON (cfg)) { int x; - printf ("function %s::%s/%d requires one of unsuported SIMD instruction set(s): ", cmethod->klass->name, cmethod->name, fsig->param_count); + printf ("function %s::%s/%d requires one of unsuported SIMD instruction set(s): ", m_class_get_name (cmethod->klass), cmethod->name, fsig->param_count); for (x = 1; x <= SIMD_VERSION_INDEX_END; x++) if (result->simd_version_flags & (1 << x)) printf ("%s ", simd_version_name (1 << x)); @@ -1985,17 +1985,17 @@ mono_emit_simd_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign { const char *class_name; - if (is_sys_numerics_assembly (cmethod->klass->image->assembly)) + if (is_sys_numerics_assembly (m_class_get_image (cmethod->klass)->assembly)) return emit_sys_numerics_intrinsics (cfg, cmethod, fsig, args); - if (is_sys_numerics_vectors_assembly (cmethod->klass->image->assembly)) + if (is_sys_numerics_vectors_assembly (m_class_get_image (cmethod->klass)->assembly)) return emit_sys_numerics_vectors_intrinsics (cfg, cmethod, fsig, args); - if (strcmp ("Mono.Simd", cmethod->klass->image->assembly->aname.name) || - strcmp ("Mono.Simd", cmethod->klass->name_space)) + if (strcmp ("Mono.Simd", m_class_get_image (cmethod->klass)->assembly->aname.name) || + strcmp ("Mono.Simd", m_class_get_name_space (cmethod->klass))) return NULL; - class_name = cmethod->klass->name; + class_name = m_class_get_name (cmethod->klass); if (!strcmp ("SimdRuntime", class_name)) return emit_simd_runtime_intrinsics (cfg, cmethod, fsig, args); @@ -2005,8 +2005,8 @@ mono_emit_simd_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign if (!strcmp ("VectorOperations", class_name)) { if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) return NULL; - class_name = mono_class_from_mono_type (mono_method_signature (cmethod)->params [0])->name; - } else if (!cmethod->klass->simd_type) + class_name = m_class_get_name (mono_class_from_mono_type (mono_method_signature (cmethod)->params [0])); + } else if (!m_class_is_simd_type (cmethod->klass)) return NULL; cfg->uses_simd_intrinsics = 1; @@ -2046,7 +2046,7 @@ assert_handled (MonoCompile *cfg, MonoMethod *method) if (cattr) { gboolean has_attr = FALSE; for (int i = 0; i < cattr->num_attrs; ++i) - if (cattr->attrs [i].ctor && (!strcmp (cattr->attrs [i].ctor->klass->name, "JitIntrinsicAttribute"))) + if (cattr->attrs [i].ctor && (!strcmp (m_class_get_name (cattr->attrs [i].ctor->klass), "JitIntrinsicAttribute"))) has_attr = TRUE; if (has_attr) { printf ("SIMD intrinsic unhandled: %s\n", mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL)); @@ -2079,9 +2079,9 @@ emit_vector_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignatu { const SimdIntrinsic *intrins; MonoMethodSignature *sig = mono_method_signature (cmethod); - MonoType *type = &cmethod->klass->byval_arg; + MonoType *type = m_class_get_byval_arg (cmethod->klass); - if (!cmethod->klass->simd_type) + if (!m_class_is_simd_type (cmethod->klass)) return NULL; /* @@ -2220,7 +2220,7 @@ emit_vector_t_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSigna return NULL; } - type = &cmethod->klass->byval_arg; + type = m_class_get_byval_arg (cmethod->klass); etype = mono_class_get_context (cmethod->klass)->class_inst->type_argv [0]; size = mono_class_value_size (mono_class_from_mono_type (etype), NULL); g_assert (size); @@ -2456,8 +2456,8 @@ emit_vector_t_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSigna static MonoInst* emit_sys_numerics_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args) { - const char *nspace = cmethod->klass->name_space; - const char *class_name = cmethod->klass->name; + const char *nspace = m_class_get_name_space (cmethod->klass); + const char *class_name = m_class_get_name (cmethod->klass); if (!strcmp ("Vector2", class_name) || !strcmp ("Vector4", class_name) || !strcmp ("Vector3", class_name)) return emit_vector_intrinsics (cfg, cmethod, fsig, args); @@ -2473,8 +2473,8 @@ emit_sys_numerics_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodS static MonoInst* emit_sys_numerics_vectors_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args) { - const char *nspace = cmethod->klass->name_space; - const char *class_name = cmethod->klass->name; + const char *nspace = m_class_get_name_space (cmethod->klass); + const char *class_name = m_class_get_name (cmethod->klass); if (!strcmp (class_name, "Vector`1")) return emit_vector_t_intrinsics (cfg, cmethod, fsig, args); @@ -2490,12 +2490,13 @@ emit_sys_numerics_vectors_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, Mon MonoInst* mono_emit_simd_field_load (MonoCompile *cfg, MonoClassField *field, MonoInst *addr) { - if (is_sys_numerics_assembly (field->parent->image->assembly)) { + if (is_sys_numerics_assembly (m_class_get_image (field->parent)->assembly)) { int index = -1; - if (!strcmp (field->parent->name, "Vector2") || - !strcmp (field->parent->name, "Vector3") || - !strcmp (field->parent->name, "Vector4")) { + const char *parent_name = m_class_get_name (field->parent); + if (!strcmp (parent_name, "Vector2") || + !strcmp (parent_name, "Vector3") || + !strcmp (parent_name, "Vector4")) { if (!strcmp (field->name, "X")) index = 0; else if (!strcmp (field->name, "Y")) diff --git a/mono/mini/ssa.c b/mono/mini/ssa.c index 187ac213f3..5a761ba54b 100644 --- a/mono/mini/ssa.c +++ b/mono/mini/ssa.c @@ -509,7 +509,7 @@ mono_ssa_remove_gsharedvt (MonoCompile *cfg) printf ("\nREMOVE SSA %d:\n", bb->block_num); for (ins = bb->code; ins; ins = ins->next) { - if (!(MONO_IS_PHI (ins) && ins->opcode == OP_VPHI && mini_is_gsharedvt_variable_type (&ins->klass->byval_arg))) + if (!(MONO_IS_PHI (ins) && ins->opcode == OP_VPHI && mini_is_gsharedvt_variable_type (m_class_get_byval_arg (ins->klass)))) continue; g_assert (ins->inst_phi_args [0] == bb->in_count); diff --git a/mono/mini/trace.c b/mono/mini/trace.c index fb6ad1ccf5..017a643cb7 100644 --- a/mono/mini/trace.c +++ b/mono/mini/trace.c @@ -174,7 +174,7 @@ mono_trace_enter_method (MonoMethod *method, char *ebp) if (mono_method_signature (method)->hasthis) { gpointer *this_obj = (gpointer *)(ebp + arg_info [0].offset); - if (method->klass->valuetype) { + if (m_class_is_valuetype (method->klass)) { printf ("value:%p, ", *arg_in_stack_slot(this_obj, gpointer *)); } else { o = *arg_in_stack_slot(this_obj, MonoObject *); @@ -189,7 +189,7 @@ mono_trace_enter_method (MonoMethod *method, char *ebp) printf ("this:[STRING:%p:%s], ", o, as); g_free (as); } else { - printf ("this:%p[%s.%s %s], ", o, klass->name_space, klass->name, o->vtable->domain->friendly_name); + printf ("this:%p[%s.%s %s], ", o, m_class_get_name_space (klass), m_class_get_name (klass), o->vtable->domain->friendly_name); } } else printf ("this:NULL, "); @@ -254,7 +254,7 @@ mono_trace_enter_method (MonoMethod *method, char *ebp) } else if (klass == mono_defaults.runtimetype_class) { printf ("[TYPE:%s], ", mono_type_full_name (((MonoReflectionType*)o)->type)); } else - printf ("[%s.%s:%p], ", klass->name_space, klass->name, o); + printf ("[%s.%s:%p], ", m_class_get_name_space (klass), m_class_get_name (klass), o); } else { printf ("%p, ", *arg_in_stack_slot(cpos, gpointer)); } @@ -381,7 +381,7 @@ mono_trace_leave_method (MonoMethod *method, ...) } else if (o->vtable->klass == mono_defaults.int64_class) { printf ("[INT64:%p:%lld]", o, (long long)*((gint64 *)((char *)o + sizeof (MonoObject)))); } else - printf ("[%s.%s:%p]", o->vtable->klass->name_space, o->vtable->klass->name, o); + printf ("[%s.%s:%p]", m_class_get_name_space (mono_object_class (o)), m_class_get_name (mono_object_class (o)), o); } else printf ("[OBJECT:%p]", o); diff --git a/mono/mini/tramp-amd64-gsharedvt.c b/mono/mini/tramp-amd64-gsharedvt.c index 17a6849ed2..2ea5645a9d 100644 --- a/mono/mini/tramp-amd64-gsharedvt.c +++ b/mono/mini/tramp-amd64-gsharedvt.c @@ -31,8 +31,6 @@ #if defined (MONO_ARCH_GSHAREDVT_SUPPORTED) -#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1)) - #define SRC_REG_SHIFT 0 #define SRC_REG_MASK 0xFFFF diff --git a/mono/mini/tramp-amd64.c b/mono/mini/tramp-amd64.c index 8dc1155023..082d788b5a 100644 --- a/mono/mini/tramp-amd64.c +++ b/mono/mini/tramp-amd64.c @@ -35,8 +35,6 @@ #include "interp/interp.h" #endif -#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1)) - #define IS_REX(inst) (((inst) >= 0x40) && ((inst) <= 0x4f)) #ifndef DISABLE_JIT @@ -822,7 +820,7 @@ mono_arch_get_plt_info_offset (guint8 *plt_entry, mgreg_t *regs, guint8 *code) * mono_arch_create_sdb_trampoline: * * Return a trampoline which captures the current context, passes it to - * debugger_agent_single_step_from_context ()/debugger_agent_breakpoint_from_context (), + * mono_debugger_agent_single_step_from_context ()/mono_debugger_agent_breakpoint_from_context (), * then restores the (potentially changed) context. */ guint8* @@ -887,9 +885,9 @@ mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gbo code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "debugger_agent_breakpoint_from_context"); } else { if (single_step) - amd64_mov_reg_imm (code, AMD64_R11, debugger_agent_single_step_from_context); + amd64_mov_reg_imm (code, AMD64_R11, mono_debugger_agent_single_step_from_context); else - amd64_mov_reg_imm (code, AMD64_R11, debugger_agent_breakpoint_from_context); + amd64_mov_reg_imm (code, AMD64_R11, mono_debugger_agent_breakpoint_from_context); } amd64_call_reg (code, AMD64_R11); diff --git a/mono/mini/tramp-arm-gsharedvt.c b/mono/mini/tramp-arm-gsharedvt.c index c7f2e8b1f7..1c01b2fa45 100644 --- a/mono/mini/tramp-arm-gsharedvt.c +++ b/mono/mini/tramp-arm-gsharedvt.c @@ -23,8 +23,6 @@ #include "mini-arm.h" #include "mini-runtime.h" -#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1)) - #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED static inline guint8* diff --git a/mono/mini/tramp-arm.c b/mono/mini/tramp-arm.c index a49c7ffa44..7d042841dd 100644 --- a/mono/mini/tramp-arm.c +++ b/mono/mini/tramp-arm.c @@ -32,8 +32,6 @@ #include "interp/interp.h" #endif -#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1)) - void mono_arch_patch_callsite (guint8 *method_start, guint8 *code_ptr, guint8 *addr) { @@ -818,9 +816,9 @@ mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gbo ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0); ARM_B (code, 0); if (single_step) - *(gpointer*)code = debugger_agent_single_step_from_context; + *(gpointer*)code = mono_debugger_agent_single_step_from_context; else - *(gpointer*)code = debugger_agent_breakpoint_from_context; + *(gpointer*)code = mono_debugger_agent_breakpoint_from_context; code += 4; ARM_BLX_REG (code, ARMREG_IP); } diff --git a/mono/mini/tramp-arm64.c b/mono/mini/tramp-arm64.c index 7a58d99bfc..7c6c563e21 100644 --- a/mono/mini/tramp-arm64.c +++ b/mono/mini/tramp-arm64.c @@ -27,8 +27,6 @@ #endif -#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1)) - void mono_arch_patch_callsite (guint8 *method_start, guint8 *code_ptr, guint8 *addr) { @@ -329,7 +327,7 @@ mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_ty */ tramp = mono_get_trampoline_code (tramp_type); - buf = code = mono_global_codeman_reserve (buf_len); + buf = code = mono_domain_code_reserve (domain, buf_len); code = mono_arm_emit_imm64 (code, ARMREG_IP1, (guint64)arg1); code = mono_arm_emit_imm64 (code, ARMREG_IP0, (guint64)tramp); @@ -517,7 +515,7 @@ mono_arch_create_general_rgctx_lazy_fetch_trampoline (MonoTrampInfo **info, gboo * mono_arch_create_sdb_trampoline: * * Return a trampoline which captures the current context, passes it to - * debugger_agent_single_step_from_context ()/debugger_agent_breakpoint_from_context (), + * mono_debugger_agent_single_step_from_context ()/mono_debugger_agent_breakpoint_from_context (), * then restores the (potentially changed) context. */ guint8* @@ -583,7 +581,7 @@ mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gbo else code = mono_arm_emit_aotconst (&ji, code, buf, ARMREG_IP0, MONO_PATCH_INFO_JIT_ICALL_ADDR, "debugger_agent_breakpoint_from_context"); } else { - gpointer addr = single_step ? debugger_agent_single_step_from_context : debugger_agent_breakpoint_from_context; + gpointer addr = single_step ? mono_debugger_agent_single_step_from_context : mono_debugger_agent_breakpoint_from_context; code = mono_arm_emit_imm64 (code, ARMREG_IP0, (guint64)addr); } diff --git a/mono/mini/tramp-mips.c b/mono/mini/tramp-mips.c index 0930b7324f..8b8d375db1 100644 --- a/mono/mini/tramp-mips.c +++ b/mono/mini/tramp-mips.c @@ -112,8 +112,6 @@ mono_arch_patch_plt_entry (guint8 *code, gpointer *got, mgreg_t *regs, guint8 *a * STACK would be 444 for 32 bit darwin */ -#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1)) - #define STACK (int)(ALIGN_TO(4*IREG_SIZE + 8 + sizeof(MonoLMF) + 32, 8)) /* diff --git a/mono/mini/tramp-ppc.c b/mono/mini/tramp-ppc.c index 3376cc4af8..bfbeca9f72 100644 --- a/mono/mini/tramp-ppc.c +++ b/mono/mini/tramp-ppc.c @@ -634,10 +634,3 @@ mono_arch_get_plt_info_offset (guint8 *plt_entry, mgreg_t *regs, guint8 *code) return ((guint32*)plt_entry) [6]; #endif } - -gpointer -mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) -{ - g_assert_not_reached (); - return NULL; -} diff --git a/mono/mini/tramp-s390x.c b/mono/mini/tramp-s390x.c index 3582a992f6..368f00f5ec 100644 --- a/mono/mini/tramp-s390x.c +++ b/mono/mini/tramp-s390x.c @@ -603,20 +603,3 @@ mono_arch_get_static_rgctx_trampoline (gpointer arg, gpointer addr) } /*========================= End of Function ========================*/ - -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_get_interp_to_native_trampoline. */ -/* */ -/* Function - */ -/* */ -/*------------------------------------------------------------------*/ - -gpointer -mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) -{ - g_assert_not_reached (); - return NULL; -} - -/*========================= End of Function ========================*/ diff --git a/mono/mini/tramp-sparc.c b/mono/mini/tramp-sparc.c index a36b64dd3c..41284e4110 100644 --- a/mono/mini/tramp-sparc.c +++ b/mono/mini/tramp-sparc.c @@ -36,7 +36,7 @@ mono_arch_get_unbox_trampoline (MonoMethod *m, gpointer addr) guint8 *code, *start; int reg; - start = code = mono_global_codeman_reserve (36); + start = code = mono_domain_code_reserve (mono_domain_get (), 36); /* This executes in the context of the caller, hence o0 */ sparc_add_imm (code, 0, sparc_o0, sizeof (MonoObject), sparc_o0); @@ -72,8 +72,6 @@ mono_arch_patch_plt_entry (guint8 *code, gpointer *got, mgreg_t *regs, guint8 *a g_assert_not_reached (); } -#define ALIGN_TO(val,align) (((val) + ((align) - 1)) & ~((align) - 1)) - guchar* mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInfo **info, gboolean aot) { diff --git a/mono/mini/tramp-wasm.c b/mono/mini/tramp-wasm.c index 6f0fff47aa..7cc84bd5f6 100644 --- a/mono/mini/tramp-wasm.c +++ b/mono/mini/tramp-wasm.c @@ -25,14 +25,6 @@ mono_arch_patch_plt_entry (guint8 *code, gpointer *got, mgreg_t *regs, guint8 *a g_error ("mono_arch_patch_plt_entry"); } -gpointer -mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) -{ - printf ("mono_arch_get_interp_to_native_trampoline"); - g_assert (0); - return NULL; -} - void mono_arch_patch_callsite (guint8 *method_start, guint8 *orig_code, guint8 *addr) { @@ -52,3 +44,10 @@ mono_arch_get_static_rgctx_trampoline (gpointer arg, gpointer addr) g_error ("mono_arch_get_static_rgctx_trampoline"); return NULL; } + +gpointer +mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) +{ + g_error ("mono_arch_get_interp_to_native_trampoline"); + return NULL; +} diff --git a/mono/mini/tramp-x86.c b/mono/mini/tramp-x86.c index dbb24336ce..2d030e42b5 100644 --- a/mono/mini/tramp-x86.c +++ b/mono/mini/tramp-x86.c @@ -28,8 +28,6 @@ #include "debugger-agent.h" #include "jit-icalls.h" -#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1)) - /* * mono_arch_get_unbox_trampoline: * @m: method pointer @@ -654,7 +652,7 @@ mono_arch_get_gsharedvt_arg_trampoline (MonoDomain *domain, gpointer arg, gpoint * mono_arch_create_sdb_trampoline: * * Return a trampoline which captures the current context, passes it to - * debugger_agent_single_step_from_context ()/debugger_agent_breakpoint_from_context (), + * mono_debugger_agent_single_step_from_context ()/mono_debugger_agent_breakpoint_from_context (), * then restores the (potentially changed) context. */ guint8* @@ -718,9 +716,9 @@ mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gbo x86_breakpoint (code); } else { if (single_step) - x86_call_code (code, debugger_agent_single_step_from_context); + x86_call_code (code, mono_debugger_agent_single_step_from_context); else - x86_call_code (code, debugger_agent_breakpoint_from_context); + x86_call_code (code, mono_debugger_agent_breakpoint_from_context); } /* Restore registers from ctx */ @@ -750,11 +748,3 @@ mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gbo return buf; } - -gpointer -mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) -{ - g_assert_not_reached (); - return NULL; -} - diff --git a/mono/mini/type-checking.c b/mono/mini/type-checking.c index 84982b9dcc..2576aa64f7 100644 --- a/mono/mini/type-checking.c +++ b/mono/mini/type-checking.c @@ -10,9 +10,10 @@ #include "mini.h" #include "ir-emit.h" #include +#include -#define is_complex_isinst(klass) (mono_class_is_interface (klass) || klass->rank || mono_class_is_nullable (klass) || mono_class_is_marshalbyref (klass) || mono_class_is_sealed (klass) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR) +#define is_complex_isinst(klass) (mono_class_is_interface (klass) || m_class_get_rank (klass) || mono_class_is_nullable (klass) || mono_class_is_marshalbyref (klass) || mono_class_is_sealed (klass) || m_class_get_byval_arg (klass)->type == MONO_TYPE_VAR || m_class_get_byval_arg (klass)->type == MONO_TYPE_MVAR) static int get_castclass_cache_idx (MonoCompile *cfg) @@ -108,13 +109,13 @@ mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, mono_class_setup_supertypes (klass); - if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) { - MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth)); - MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth); + if (m_class_get_idepth (klass) > MONO_DEFAULT_SUPERTABLE_SIZE) { + MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, m_class_offsetof_idepth ()); + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, m_class_get_idepth (klass)); MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target); } - MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes)); - MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P)); + MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, m_class_offsetof_supertypes ()); + MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((m_class_get_idepth (klass) - 1) * SIZEOF_VOID_P)); if (klass_ins) { MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg); } else if (cfg->compile_aot) { @@ -162,8 +163,8 @@ mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_r MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg); MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg); } else { - MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3); - MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7)); + MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, m_class_get_interface_id (klass) >> 3); + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (m_class_get_interface_id (klass) & 7)); } #endif } @@ -175,7 +176,7 @@ mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_r static void mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass) { - mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, interface_bitmap), klass); + mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, m_class_offsetof_interface_bitmap (), klass); } /* @@ -202,7 +203,7 @@ mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass, MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg); } else - MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id); + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, m_class_get_interface_id (klass)); if (false_target) MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target); else @@ -227,7 +228,7 @@ mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass { int max_iid_reg = alloc_preg (cfg); - MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU4_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id)); + MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU4_MEMBASE, max_iid_reg, klass_reg, m_class_offsetof_max_interface_id ()); mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target); } @@ -289,34 +290,34 @@ mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *kl static void mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null) { - if (klass->rank) { + if (m_class_get_rank (klass)) { int rank_reg = alloc_preg (cfg); int eclass_reg = alloc_preg (cfg); g_assert (!klass_inst); - MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, rank)); - MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank); + MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, m_class_offsetof_rank ()); + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, m_class_get_rank (klass)); MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException"); // MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass)); - MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class)); - if (klass->cast_class == mono_defaults.object_class) { + MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, m_class_offsetof_cast_class ()); + if (m_class_get_cast_class (klass) == mono_defaults.object_class) { int parent_reg = alloc_preg (cfg); - MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent)); - mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null); + MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, m_class_offsetof_parent ()); + mini_emit_class_check_branch (cfg, parent_reg, m_class_get_parent (mono_defaults.enum_class), OP_PBNE_UN, object_is_null); mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class); - } else if (klass->cast_class == mono_defaults.enum_class->parent) { - mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null); + } else if (m_class_get_cast_class (klass) == m_class_get_parent (mono_defaults.enum_class)) { + mini_emit_class_check_branch (cfg, eclass_reg, m_class_get_parent (mono_defaults.enum_class), OP_PBEQ, object_is_null); mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class); - } else if (klass->cast_class == mono_defaults.enum_class) { + } else if (m_class_get_cast_class (klass) == mono_defaults.enum_class) { mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class); - } else if (mono_class_is_interface (klass->cast_class)) { - mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL); + } else if (mono_class_is_interface (m_class_get_cast_class (klass))) { + mini_emit_iface_class_cast (cfg, eclass_reg, m_class_get_cast_class (klass), NULL, NULL); } else { // Pass -1 as obj_reg to skip the check below for arrays of arrays - mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null); + mini_emit_castclass (cfg, -1, eclass_reg, m_class_get_cast_class (klass), object_is_null); } - if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) { + if ((m_class_get_rank (klass) == 1) && (m_class_get_byval_arg (klass)->type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) { /* Check that the object is a vector too */ int bounds_reg = alloc_preg (cfg); MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds)); @@ -330,13 +331,13 @@ mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClas mono_class_setup_supertypes (klass); - if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) { - MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth)); - MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth); + if (m_class_get_idepth (klass) > MONO_DEFAULT_SUPERTABLE_SIZE) { + MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, m_class_offsetof_idepth ()); + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, m_class_get_idepth (klass)); MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException"); } - MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes)); - MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P)); + MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, m_class_offsetof_supertypes ()); + MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((m_class_get_idepth (klass) - 1) * SIZEOF_VOID_P)); mini_emit_class_check_inst (cfg, stype, klass, klass_inst); } } @@ -353,7 +354,7 @@ emit_special_array_iface_check (MonoCompile *cfg, MonoInst *src, MonoClass* klas MonoBasicBlock *not_an_array; int rank_reg; - if (!klass->is_array_special_interface) + if (!m_class_is_array_special_interface (klass)) return; rank_reg = alloc_ireg (cfg); @@ -494,7 +495,7 @@ handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable)); - if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && mono_class_is_sealed (klass)) { + if (!m_class_get_rank (klass) && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && mono_class_is_sealed (klass)) { /* the remoting code is broken, access the class for now */ if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/ MonoVTable *vt = mono_class_vtable_checked (cfg->domain, klass, &cfg->error); @@ -563,7 +564,7 @@ handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_us mini_emit_iface_cast (cfg, vtable_reg, klass, interface_fail_bb, is_null_bb); MONO_START_BB (cfg, interface_fail_bb); - if (klass->is_array_special_interface) { + if (m_class_is_array_special_interface (klass)) { MonoBasicBlock *not_an_array; MonoInst *move; int rank_reg = alloc_ireg (cfg); @@ -648,11 +649,11 @@ handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_us } else { int klass_reg = alloc_preg (cfg); - if (klass->rank) { + if (m_class_get_rank (klass)) { int rank_reg = alloc_preg (cfg); int eclass_reg = alloc_preg (cfg); - if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) { + if ((m_class_get_rank (klass) == 1) && (m_class_get_byval_arg (klass)->type == MONO_TYPE_SZARRAY)) { /* Check that the object is a vector too */ int bounds_reg = alloc_preg (cfg); MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds)); @@ -662,34 +663,34 @@ handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_us g_assert (!context_used); MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank)); - MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank); + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, m_class_get_rank (klass)); MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb); MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass)); - MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class)); - if (klass->cast_class == mono_defaults.object_class) { + MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, m_class_offsetof_cast_class ()); + if (m_class_get_cast_class (klass) == mono_defaults.object_class) { int parent_reg = alloc_preg (cfg); - MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent)); - mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb); + MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, m_class_offsetof_parent ()); + mini_emit_class_check_branch (cfg, parent_reg, m_class_get_parent (mono_defaults.enum_class), OP_PBNE_UN, is_null_bb); mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb); MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb); - } else if (klass->cast_class == mono_defaults.enum_class->parent) { - mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb); + } else if (m_class_get_cast_class (klass) == m_class_get_parent (mono_defaults.enum_class)) { + mini_emit_class_check_branch (cfg, eclass_reg, m_class_get_parent (mono_defaults.enum_class), OP_PBEQ, is_null_bb); mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb); MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb); - } else if (klass->cast_class == mono_defaults.enum_class) { + } else if (m_class_get_cast_class (klass) == mono_defaults.enum_class) { mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb); MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb); - } else if (mono_class_is_interface (klass->cast_class)) { - mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb); + } else if (mono_class_is_interface (m_class_get_cast_class (klass))) { + mini_emit_iface_class_cast (cfg, eclass_reg, m_class_get_cast_class (klass), false_bb, is_null_bb); } else { /* the is_null_bb target simply copies the input register to the output */ - mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb); + mini_emit_isninst_cast (cfg, eclass_reg, m_class_get_cast_class (klass), false_bb, is_null_bb); } } else if (mono_class_is_nullable (klass)) { g_assert (!context_used); MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass)); /* the is_null_bb target simply copies the input register to the output */ - mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb); + mini_emit_isninst_cast (cfg, klass_reg, m_class_get_cast_class (klass), false_bb, is_null_bb); } else { if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && mono_class_is_sealed (klass)) { g_assert (!context_used); @@ -737,7 +738,7 @@ mono_decompose_typecheck (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins) g_assert (is_isinst || ins->opcode == OP_CASTCLASS); source = get_vreg_to_inst (cfg, ins->sreg1); if (!source || source == (MonoInst *) -1) - source = mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, ins->sreg1); + source = mono_compile_create_var_for_vreg (cfg, m_class_get_byval_arg (mono_defaults.object_class), OP_LOCAL, ins->sreg1); g_assert (source && source != (MonoInst *) -1); MonoBasicBlock *first_bb; diff --git a/mono/mini/unwind.c b/mono/mini/unwind.c index 72f5d0d59e..b75fd558cf 100644 --- a/mono/mini/unwind.c +++ b/mono/mini/unwind.c @@ -32,8 +32,6 @@ typedef struct { guint8 info [MONO_ZERO_LEN_ARRAY]; } MonoUnwindInfo; -#define ALIGN_TO(val,align) ((((size_t)val) + ((align) - 1)) & ~((align) - 1)) - static mono_mutex_t unwind_mutex; static MonoUnwindInfo **cached_info; @@ -93,8 +91,15 @@ static int map_hw_reg_to_dwarf_reg [ppc_lr + 1] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, #endif #define NUM_DWARF_REGS (DWARF_PC_REG + 1) #elif defined (TARGET_S390X) -static int map_hw_reg_to_dwarf_reg [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; -#define NUM_DWARF_REGS 16 +/* + * 0-15 = GR0-15 + * 16-31 = FP0-15 + */ +static int map_hw_reg_to_dwarf_reg [] = { 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31}; +#define NUM_DWARF_REGS 32 #define DWARF_DATA_ALIGN (-8) #define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (14)) #elif defined (TARGET_MIPS) diff --git a/mono/mini/version.h b/mono/mini/version.h index 32aa850a13..324401f88c 100644 --- a/mono/mini/version.h +++ b/mono/mini/version.h @@ -1 +1 @@ -#define FULL_VERSION "explicit/93e3daf" +#define FULL_VERSION "explicit/ecf6b88" diff --git a/mono/profiler/Makefile.am b/mono/profiler/Makefile.am index 58a1fc99d6..247c3c5885 100644 --- a/mono/profiler/Makefile.am +++ b/mono/profiler/Makefile.am @@ -25,9 +25,7 @@ lib_LTLIBRARIES = \ $(vtune_libs) suppressiondir = $(datadir)/mono-$(API_VER)/mono/profiler -suppression_DATA = \ - mono-profiler-coverage.suppression \ - mono-profiler-log.suppression +suppression_DATA = mono-profiler-coverage.suppression # FIXME: The profiler tests currently don't work with coop because the # sampling infrastructure depends on signals being available. @@ -99,7 +97,7 @@ endif # builds. libmono_profiler_aot_la_SOURCES = aot.c -libmono_profiler_aot_la_LIBADD = $(libmono_dep) $(GLIB_LIBS) $(LIBICONV) +libmono_profiler_aot_la_LIBADD = $(libmono_dep) $(GLIB_LIBS) libmono_profiler_aot_la_LDFLAGS = $(prof_ldflags) libmono_profiler_aot_static_la_SOURCES = aot.c libmono_profiler_aot_static_la_LDFLAGS = -static @@ -119,7 +117,7 @@ libmono_profiler_coverage_static_la_LDFLAGS = -static if HAVE_VTUNE libmono_profiler_vtune_la_SOURCES = vtune.c libmono_profiler_vtune_la_CFLAGS = $(VTUNE_CFLAGS) -libmono_profiler_vtune_la_LIBADD = $(VTUNE_LIBS) $(libmono_dep) $(GLIB_LIBS) $(LIBICONV) +libmono_profiler_vtune_la_LIBADD = $(VTUNE_LIBS) $(libmono_dep) $(GLIB_LIBS) libmono_profiler_vtune_la_LDFLAGS = $(prof_ldflags) libmono_profiler_vtune_static_la_SOURCES = vtune.c libmono_profiler_vtune_static_la_LDFLAGS = -static @@ -128,7 +126,7 @@ libmono_profiler_vtune_static_la_LIBADD = $(VTUNE_LIBS) endif mprof_report_SOURCES = mprof-report.c -mprof_report_LDADD = $(GLIB_LIBS) $(LIBICONV) $(zlib_dep) +mprof_report_LDADD = $(GLIB_LIBS) $(zlib_dep) PLOG_TESTS_SRC = \ test-alloc.cs \ diff --git a/mono/profiler/Makefile.in b/mono/profiler/Makefile.in index a498f25e6c..61dee0ae3f 100644 --- a/mono/profiler/Makefile.in +++ b/mono/profiler/Makefile.in @@ -87,8 +87,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs $(top_srcdir)/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -150,7 +148,7 @@ libmono_profiler_aot_static_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ @HOST_ANDROID_TRUE@ $(top_builddir)/mono/mini/$(LIBMONO_LA) am__DEPENDENCIES_2 = libmono_profiler_aot_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_2) + $(am__DEPENDENCIES_2) am_libmono_profiler_aot_la_OBJECTS = aot.lo libmono_profiler_aot_la_OBJECTS = \ $(am_libmono_profiler_aot_la_OBJECTS) @@ -218,7 +216,7 @@ libmono_profiler_vtune_static_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ @DISABLE_LIBRARIES_FALSE@@DISABLE_PROFILER_FALSE@@HAVE_VTUNE_TRUE@@HOST_WIN32_FALSE@ $(libdir) @HAVE_VTUNE_TRUE@libmono_profiler_vtune_la_DEPENDENCIES = \ @HAVE_VTUNE_TRUE@ $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ -@HAVE_VTUNE_TRUE@ $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_2) +@HAVE_VTUNE_TRUE@ $(am__DEPENDENCIES_2) am__libmono_profiler_vtune_la_SOURCES_DIST = vtune.c @HAVE_VTUNE_TRUE@am_libmono_profiler_vtune_la_OBJECTS = \ @HAVE_VTUNE_TRUE@ libmono_profiler_vtune_la-vtune.lo @@ -234,7 +232,7 @@ PROGRAMS = $(bin_PROGRAMS) am_mprof_report_OBJECTS = mprof-report.$(OBJEXT) mprof_report_OBJECTS = $(am_mprof_report_OBJECTS) mprof_report_DEPENDENCIES = $(am__DEPENDENCIES_2) \ - $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_2) + $(am__DEPENDENCIES_2) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false @@ -384,6 +382,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -402,7 +401,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -416,7 +414,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -530,7 +527,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ @@ -569,10 +565,7 @@ AM_CPPFLAGS = \ @DISABLE_LIBRARIES_FALSE@@DISABLE_PROFILER_FALSE@@HOST_WIN32_FALSE@ $(vtune_libs) @DISABLE_LIBRARIES_FALSE@@DISABLE_PROFILER_FALSE@@HOST_WIN32_FALSE@suppressiondir = $(datadir)/mono-$(API_VER)/mono/profiler -@DISABLE_LIBRARIES_FALSE@@DISABLE_PROFILER_FALSE@@HOST_WIN32_FALSE@suppression_DATA = \ -@DISABLE_LIBRARIES_FALSE@@DISABLE_PROFILER_FALSE@@HOST_WIN32_FALSE@ mono-profiler-coverage.suppression \ -@DISABLE_LIBRARIES_FALSE@@DISABLE_PROFILER_FALSE@@HOST_WIN32_FALSE@ mono-profiler-log.suppression - +@DISABLE_LIBRARIES_FALSE@@DISABLE_PROFILER_FALSE@@HOST_WIN32_FALSE@suppression_DATA = mono-profiler-coverage.suppression # FIXME: The profiler tests currently don't work with coop because the # sampling infrastructure depends on signals being available. @@ -618,7 +611,7 @@ AM_CPPFLAGS = \ # the shared version on those targets since it's useful for e.g. simulator # builds. libmono_profiler_aot_la_SOURCES = aot.c -libmono_profiler_aot_la_LIBADD = $(libmono_dep) $(GLIB_LIBS) $(LIBICONV) +libmono_profiler_aot_la_LIBADD = $(libmono_dep) $(GLIB_LIBS) libmono_profiler_aot_la_LDFLAGS = $(prof_ldflags) libmono_profiler_aot_static_la_SOURCES = aot.c libmono_profiler_aot_static_la_LDFLAGS = -static @@ -634,14 +627,14 @@ libmono_profiler_coverage_static_la_SOURCES = coverage.c libmono_profiler_coverage_static_la_LDFLAGS = -static @HAVE_VTUNE_TRUE@libmono_profiler_vtune_la_SOURCES = vtune.c @HAVE_VTUNE_TRUE@libmono_profiler_vtune_la_CFLAGS = $(VTUNE_CFLAGS) -@HAVE_VTUNE_TRUE@libmono_profiler_vtune_la_LIBADD = $(VTUNE_LIBS) $(libmono_dep) $(GLIB_LIBS) $(LIBICONV) +@HAVE_VTUNE_TRUE@libmono_profiler_vtune_la_LIBADD = $(VTUNE_LIBS) $(libmono_dep) $(GLIB_LIBS) @HAVE_VTUNE_TRUE@libmono_profiler_vtune_la_LDFLAGS = $(prof_ldflags) @HAVE_VTUNE_TRUE@libmono_profiler_vtune_static_la_SOURCES = vtune.c @HAVE_VTUNE_TRUE@libmono_profiler_vtune_static_la_LDFLAGS = -static @HAVE_VTUNE_TRUE@libmono_profiler_vtune_static_la_CFLAGS = $(VTUNE_CFLAGS) @HAVE_VTUNE_TRUE@libmono_profiler_vtune_static_la_LIBADD = $(VTUNE_LIBS) mprof_report_SOURCES = mprof-report.c -mprof_report_LDADD = $(GLIB_LIBS) $(LIBICONV) $(zlib_dep) +mprof_report_LDADD = $(GLIB_LIBS) $(zlib_dep) PLOG_TESTS_SRC = \ test-alloc.cs \ test-busy.cs \ diff --git a/mono/profiler/aot.c b/mono/profiler/aot.c index 0f70085971..75a86c4b91 100644 --- a/mono/profiler/aot.c +++ b/mono/profiler/aot.c @@ -330,7 +330,7 @@ add_class (MonoProfiler *prof, MonoClass *klass) if (id) return id - 1; - image_id = add_image (prof, klass->image); + image_id = add_image (prof, mono_class_get_image (klass)); if (mono_class_is_ginst (klass)) { MonoGenericContext *ctx = mono_class_get_context (klass); @@ -339,10 +339,11 @@ add_class (MonoProfiler *prof, MonoClass *klass) return -1; } - if (klass->nested_in) - name = g_strdup_printf ("%s.%s/%s", klass->nested_in->name_space, klass->nested_in->name, klass->name); + MonoClass *klass_nested_in = mono_class_get_nesting_type (klass); + if (klass_nested_in) + name = g_strdup_printf ("%s.%s/%s", mono_class_get_namespace (klass_nested_in), mono_class_get_name (klass_nested_in), mono_class_get_name (klass)); else - name = g_strdup_printf ("%s.%s", klass->name_space, klass->name); + name = g_strdup_printf ("%s.%s", mono_class_get_namespace (klass), mono_class_get_name (klass)); id = prof->id ++; emit_record (prof, AOTPROF_RECORD_TYPE, id); diff --git a/mono/profiler/coverage.c b/mono/profiler/coverage.c index 2f791392a0..4939402935 100644 --- a/mono/profiler/coverage.c +++ b/mono/profiler/coverage.c @@ -64,6 +64,7 @@ #include #include #include +#include #include diff --git a/mono/profiler/log-args.c b/mono/profiler/log-args.c index 0c8bd040a3..ccd0935d2c 100644 --- a/mono/profiler/log-args.c +++ b/mono/profiler/log-args.c @@ -78,7 +78,7 @@ 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"); + mono_profiler_printf_err ("The nodefaults option 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)) { @@ -105,10 +105,9 @@ parse_arg (const char *arg, ProfilerConfig *config) config->enter_leave = TRUE; } else if (match_option (arg, "nocalls", NULL)) { if (!compat_args_parsing) - mono_profiler_printf_err ("Could not parse argument: %s", arg); + mono_profiler_printf_err ("Could not parse argument '%s'", arg); } else if (match_option (arg, "coverage", NULL)) { - g_warning ("the log profiler support for code coverage is obsolete, use the \"coverage\" profiler"); - config->collect_coverage = TRUE; + mono_profiler_printf_err ("The log profiler no longer supports code coverage. Please use the dedicated coverage profiler instead. See mono-profilers(1) for more information."); } else if (match_option (arg, "zip", NULL)) { config->use_zip = TRUE; } else if (match_option (arg, "output", &val)) { @@ -141,17 +140,11 @@ parse_arg (const char *arg, ProfilerConfig *config) spec[speclen - 1] = '\0'; char *errstr; if (!mono_callspec_parse (spec, &config->callspec, &errstr)) { - mono_profiler_printf_err ( - "Could not parse callspec: '%s': %s", spec, - errstr); + mono_profiler_printf_err ("Could not parse callspec '%s': %s", spec, errstr); g_free (errstr); mono_callspec_cleanup (&config->callspec); } g_free (spec); - } else if (match_option (arg, "covfilter-file", &val)) { - if (config->cov_filter_files == NULL) - config->cov_filter_files = g_ptr_array_new (); - g_ptr_array_add (config->cov_filter_files, g_strdup (val)); } else { int i; @@ -169,7 +162,7 @@ parse_arg (const char *arg, ProfilerConfig *config) } if (i == G_N_ELEMENTS (event_list)) - mono_profiler_printf_err ("Could not parse argument: %s", arg); + mono_profiler_printf_err ("Could not parse argument '%s'", arg); } } diff --git a/mono/profiler/log.c.REMOVED.git-id b/mono/profiler/log.c.REMOVED.git-id index 6b3e1f5547..3f0c0d8721 100644 --- a/mono/profiler/log.c.REMOVED.git-id +++ b/mono/profiler/log.c.REMOVED.git-id @@ -1 +1 @@ -caef0e7dea62aed9cc76ce36f4baccf18d3c5bc0 \ No newline at end of file +fcdfbcba9993acf7ced4f9ad09252a3629d03d3a \ No newline at end of file diff --git a/mono/profiler/log.h b/mono/profiler/log.h index 8ea1991e36..a865e6e653 100644 --- a/mono/profiler/log.h +++ b/mono/profiler/log.h @@ -7,14 +7,15 @@ #define BUF_ID 0x4D504C01 #define LOG_HEADER_ID 0x4D505A01 -#define LOG_VERSION_MAJOR 2 +#define LOG_VERSION_MAJOR 3 #define LOG_VERSION_MINOR 0 -#define LOG_DATA_VERSION 15 +#define LOG_DATA_VERSION 16 /* * Changes in major/minor versions: * version 1.0: removed sysid field from header * added args, arch, os fields to header + * version 3.0: added nanoseconds startup time to header * * Changes in data versions: * version 2: added offsets in heap walk @@ -78,6 +79,12 @@ 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 + added MONO_ROOT_SOURCE_EPHEMERON + * version 16: removed TYPE_COVERAGE + added mvid to image load events + added generation field to TYPE_HEAO_OBJECT + added TYPE_AOT_ID + removed TYPE_SAMPLE_UBIN */ /* @@ -93,10 +100,12 @@ * * header format: * [id: 4 bytes] constant value: LOG_HEADER_ID - * [major: 1 byte] [minor: 1 byte] major and minor version of the log profiler + * [major: 1 byte] major version of the log profiler + * [minor: 1 byte] minor version of the log profiler * [format: 1 byte] version of the data format for the rest of the file * [ptrsize: 1 byte] size in bytes of a pointer in the profiled program * [startup time: 8 bytes] time in milliseconds since the unix epoch when the program started + * [ns startup time: 8 bytes] time in nanoseconds since an unspecified epoch when the program started * [timer overhead: 4 bytes] approximate overhead in nanoseconds of the timer * [flags: 4 bytes] file format flags, should be 0 for now * [pid: 4 bytes] pid of the profiled process @@ -204,6 +213,7 @@ * [name: string] full class name * if mtype == TYPE_IMAGE * [name: string] image file name + * [mvid: string] image mvid, can be empty for dynamic images * if mtype == TYPE_ASSEMBLY * [image: sleb128] MonoImage* as a pointer difference from ptr_base * [name: string] assembly name @@ -264,6 +274,7 @@ * [object: sleb128] the object as a difference from obj_base * [vtable: sleb128] MonoVTable* as a pointer difference from ptr_base * [size: uleb128] size of the object on the heap + * [generation: byte] generation the object is in * [num_refs: uleb128] number of object references * each referenced objref is preceded by a uleb128 encoded offset: the * first offset is from the object address and each next offset is relative @@ -288,7 +299,7 @@ * * type sample format * type: TYPE_SAMPLE - * exinfo: one of TYPE_SAMPLE_HIT, TYPE_SAMPLE_USYM, TYPE_SAMPLE_UBIN, TYPE_SAMPLE_COUNTERS_DESC, TYPE_SAMPLE_COUNTERS + * exinfo: one of TYPE_SAMPLE_HIT, TYPE_SAMPLE_USYM, TYPE_SAMPLE_COUNTERS_DESC, TYPE_SAMPLE_COUNTERS * if exinfo == TYPE_SAMPLE_HIT * [thread: sleb128] thread id as difference from ptr_base * [count: uleb128] number of following instruction addresses @@ -300,11 +311,6 @@ * [address: sleb128] symbol address as a difference from ptr_base * [size: uleb128] symbol size (may be 0 if unknown) * [name: string] symbol name - * if exinfo == TYPE_SAMPLE_UBIN - * [address: sleb128] address where binary has been loaded as a difference from ptr_base - * [offset: uleb128] file offset of mapping (the same file can be mapped multiple times) - * [size: uleb128] memory size - * [name: string] binary name * if exinfo == TYPE_SAMPLE_COUNTERS_DESC * [len: uleb128] number of counters * for i = 0 to len @@ -331,61 +337,26 @@ * else: * [value: uleb128/sleb128/double] counter value, can be sleb128, uleb128 or double (determined by using type) * - * type coverage format - * type: TYPE_COVERAGE - * exinfo: one of TYPE_COVERAGE_METHOD, TYPE_COVERAGE_STATEMENT, TYPE_COVERAGE_ASSEMBLY, TYPE_COVERAGE_CLASS - * if exinfo == TYPE_COVERAGE_METHOD - * [assembly: string] name of assembly - * [class: string] name of the class - * [name: string] name of the method - * [signature: string] the signature of the method - * [filename: string] the file path of the file that contains this method - * [token: uleb128] the method token - * [method_id: uleb128] an ID for this data to associate with the buffers of TYPE_COVERAGE_STATEMENTS - * [len: uleb128] the number of TYPE_COVERAGE_BUFFERS associated with this method - * if exinfo == TYPE_COVERAGE_STATEMENTS - * [method_id: uleb128] an the TYPE_COVERAGE_METHOD buffer to associate this with - * [offset: uleb128] the il offset relative to the previous offset - * [counter: uleb128] the counter for this instruction - * [line: uleb128] the line of filename containing this instruction - * [column: uleb128] the column containing this instruction - * if exinfo == TYPE_COVERAGE_ASSEMBLY - * [name: string] assembly name - * [guid: string] assembly GUID - * [filename: string] assembly filename - * [number_of_methods: uleb128] the number of methods in this assembly - * [fully_covered: uleb128] the number of fully covered methods - * [partially_covered: uleb128] the number of partially covered methods - * currently partially_covered will always be 0, and fully_covered is the - * number of methods that are fully and partially covered. - * if exinfo == TYPE_COVERAGE_CLASS - * [name: string] assembly name - * [class: string] class name - * [number_of_methods: uleb128] the number of methods in this class - * [fully_covered: uleb128] the number of fully covered methods - * [partially_covered: uleb128] the number of partially covered methods - * currently partially_covered will always be 0, and fully_covered is the - * number of methods that are fully and partially covered. - * * type meta format: * type: TYPE_META - * exinfo: one of: TYPE_SYNC_POINT + * exinfo: one of: TYPE_SYNC_POINT, TYPE_AOT_ID * if exinfo == TYPE_SYNC_POINT * [type: byte] MonoProfilerSyncPointType enum value + * if exinfo == TYPE_AOT_ID + * [aot id: string] current runtime's AOT ID */ enum { - TYPE_ALLOC, - TYPE_GC, - TYPE_METADATA, - TYPE_METHOD, - TYPE_EXCEPTION, - TYPE_MONITOR, - TYPE_HEAP, - TYPE_SAMPLE, - TYPE_RUNTIME, - TYPE_COVERAGE, - TYPE_META, + TYPE_ALLOC = 0, + TYPE_GC = 1, + TYPE_METADATA = 2, + TYPE_METHOD = 3, + TYPE_EXCEPTION = 4, + TYPE_MONITOR = 5, + TYPE_HEAP = 6, + TYPE_SAMPLE = 7, + TYPE_RUNTIME = 8, + TYPE_META = 10, /* extended type for TYPE_HEAP */ TYPE_HEAP_START = 0 << 4, TYPE_HEAP_END = 1 << 4, @@ -426,18 +397,13 @@ enum { /* extended type for TYPE_SAMPLE */ TYPE_SAMPLE_HIT = 0 << 4, TYPE_SAMPLE_USYM = 1 << 4, - TYPE_SAMPLE_UBIN = 2 << 4, TYPE_SAMPLE_COUNTERS_DESC = 3 << 4, TYPE_SAMPLE_COUNTERS = 4 << 4, /* extended type for TYPE_RUNTIME */ TYPE_JITHELPER = 1 << 4, - /* extended type for TYPE_COVERAGE */ - TYPE_COVERAGE_ASSEMBLY = 0 << 4, - TYPE_COVERAGE_METHOD = 1 << 4, - TYPE_COVERAGE_STATEMENT = 2 << 4, - TYPE_COVERAGE_CLASS = 3 << 4, /* extended type for TYPE_META */ TYPE_SYNC_POINT = 0 << 4, + TYPE_AOT_ID = 1 << 4, }; enum { @@ -509,9 +475,6 @@ typedef struct { // Whether to do method prologue/epilogue instrumentation. Only used at startup. gboolean enter_leave; - // Whether to collect code coverage by instrumenting basic blocks. - gboolean collect_coverage; - //Emit a report at the end of execution gboolean do_report; @@ -548,9 +511,6 @@ typedef struct { //Name of the generated mlpd file const char *output_filename; - //Filter files used by the code coverage mode - GPtrArray *cov_filter_files; - // Port to listen for profiling commands (e.g. "heapshot" for on-demand heapshot). int command_port; diff --git a/mono/profiler/mono-profiler-log.suppression b/mono/profiler/mono-profiler-log.suppression deleted file mode 100644 index ed781116e8..0000000000 --- a/mono/profiler/mono-profiler-log.suppression +++ /dev/null @@ -1,149 +0,0 @@ -Commons.Xml.Relaxng -Compat.ICSharpCode.SharpZipLib -I18N -I18N.CJK -I18N.MidEast -I18N.Other -I18N.Rare -I18N.West -IBM.Data.DB2 -ICSharpCode.SharpZipLib -gconf-sharp -gdk-sharp -glib-sharp -gnome-sharp -gnome-vfs-sharp -gtk-sharp -Mainsoft.Configuration -Mainsoft.Web -Managed.Windows.Forms -MicrosoftAjaxLibrary -Microsoft.Build -Microsoft.Build.Engine -Microsoft.Build.Framework -Microsoft.Build.Tasks -Microsoft.Build.Utilities -Microsoft.CSharp -Microsoft.VisualC -Microsoft.Web.Infrastructure -Mono.Addins -Mono.Addins.Setup -Mono.C5 -Mono.Cairo -Mono.Cecil -Mono.Cecil.Mdb -Mono.CodeContracts -Mono.CompilerServices.SymbolWriter -Mono.CSharp -Mono.Data.Sqlite -Mono.Data.Tds -Mono.Debugger.Soft -Mono.Directory.LDAP -Mono.Dynamic.Interpreter -Mono.Http -Mono.Management -Mono.Messaging -Mono.Messaging.RabbitMQ -Mono.Options -Mono.Parallel -Mono.Posix -Mono.Reactive.Testing -Mono.Security -Mono.Security.Win32 -Mono.ServiceModel.IdentitySelectors -Mono.Simd -Mono.Tasklets -Mono.WebBrowser -Mono.XBuild.Tasks -Mono.Xml.Ext -mscorlib -Novell.Directory.Ldap -pango-sharp -System -System.ComponentModel.Composition.4.5 -System.ComponentModel.DataAnnotations -System.Configuration -System.Configuration.Install -System.Core -System.Data -System.Data.DataSetExtensions -System.Data.Entity -System.Data.Linq -System.Data.OracleClient -System.Data.Services -System.Data.Services.Client -System.Design -System.DirectoryServices -System.DirectoryServices.Protocols -System.Drawing -System.Drawing.Design -System.Dynamic -System.EnterpriseServices -System.IdentityModel -System.IdentityModel.Selectors -System.Interactive -System.Interactive.Async -System.Interactive.Providers -System.IO.Compression -System.IO.Compression.FileSystem -System.Json -System.Json.Microsoft -System.Management -System.Messaging -System.Net -System.Net.Http -System.Net.Http.Formatting -System.Net.Http.WebRequest -System.Numerics -System.Reactive.Core -System.Reactive.Debugger -System.Reactive.Experimental -System.Reactive.Interfaces -System.Reactive.Linq -System.Reactive.Observable.Aliases -System.Reactive.PlatformServices -System.Reactive.Providers -System.Reactive.Runtime.Remoting -System.Reactive.Windows.Forms -System.Reactive.Windows.Threading -System.Runtime.Caching -System.Runtime.DurableInstancing -System.Runtime.Remoting -System.Runtime.Serialization -System.Runtime.Serialization.Formatters.Soap -System.Runtime.Serialization.Json -System.Security -System.ServiceModel -System.ServiceModel.Activation -System.ServiceModel.Discovery -System.ServiceModel.Routing -System.ServiceModel.Syndication -System.ServiceModel.Web -System.ServiceModel.Web.Extensions -System.ServiceProcess -System.Threading.Tasks.Dataflow -System.Transactions -System.Web -System.Web.Abstractions -System.Web.ApplicationServices -System.Web.DynamicData -System.Web.Extensions -System.Web.Extensions.Design -System.Web.Http -System.Web.Http.SelfHost -System.Web.Http.WebHost -System.Web.Mvc3 -System.Web.Razor -System.Web.Routing -System.Web.Services -SystemWebTestShim -System.Web.WebPages -System.Web.WebPages.Deployment -System.Web.WebPages.Razor -System.Windows -System.Windows.Forms.DataVisualization -System.Xaml -System.Xml -System.Xml.Linq -System.Xml.Serialization -WebMatrix.Data diff --git a/mono/profiler/mprof-report.c.REMOVED.git-id b/mono/profiler/mprof-report.c.REMOVED.git-id index 8a8d8a7358..81821e2be0 100644 --- a/mono/profiler/mprof-report.c.REMOVED.git-id +++ b/mono/profiler/mprof-report.c.REMOVED.git-id @@ -1 +1 @@ -bca403abe16cf6c28717dcc99a23d320df91f4eb \ No newline at end of file +741fb8e9379ee2457fa667e1db34aa0f9dca6c10 \ No newline at end of file diff --git a/mono/sgen/Makefile.in b/mono/sgen/Makefile.in index 2dc589d468..c7b525fd10 100644 --- a/mono/sgen/Makefile.in +++ b/mono/sgen/Makefile.in @@ -84,8 +84,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs $(top_srcdir)/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -263,6 +261,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -281,7 +280,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -295,7 +293,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -409,7 +406,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ diff --git a/mono/sgen/gc-internal-agnostic.h b/mono/sgen/gc-internal-agnostic.h index 1bc27c711c..b14713fb62 100644 --- a/mono/sgen/gc-internal-agnostic.h +++ b/mono/sgen/gc-internal-agnostic.h @@ -73,7 +73,7 @@ typedef struct { gint64 major_gc_time_concurrent; } GCStats; -extern GCStats gc_stats; +extern GCStats mono_gc_stats; #ifdef HAVE_SGEN_GC typedef SgenDescriptor MonoGCDescriptor; diff --git a/mono/sgen/sgen-alloc.c b/mono/sgen/sgen-alloc.c index 0e6278fea2..3a9bac55dc 100644 --- a/mono/sgen/sgen-alloc.c +++ b/mono/sgen/sgen-alloc.c @@ -70,7 +70,7 @@ alloc_degraded (GCVTable vtable, size_t size, gboolean for_mature) if (!for_mature) { sgen_client_degraded_allocation (); - SGEN_ATOMIC_ADD_P (degraded_mode, size); + SGEN_ATOMIC_ADD_P (sgen_degraded_mode, size); sgen_ensure_free_space (size, GENERATION_OLD); } else { if (sgen_need_major_collection (size)) @@ -78,10 +78,10 @@ alloc_degraded (GCVTable vtable, size_t size, gboolean for_mature) } - p = major_collector.alloc_degraded (vtable, size); + p = sgen_major_collector.alloc_degraded (vtable, size); if (!for_mature) - binary_protocol_alloc_degraded (p, vtable, size, sgen_client_get_provenance ()); + sgen_binary_protocol_alloc_degraded (p, vtable, size, sgen_client_get_provenance ()); return p; } @@ -89,7 +89,7 @@ alloc_degraded (GCVTable vtable, size_t size, gboolean for_mature) static void zero_tlab_if_necessary (void *p, size_t size) { - if (nursery_clear_policy == CLEAR_AT_TLAB_CREATION || nursery_clear_policy == CLEAR_AT_TLAB_CREATION_DEBUG) { + if (sgen_nursery_clear_policy == CLEAR_AT_TLAB_CREATION || sgen_nursery_clear_policy == CLEAR_AT_TLAB_CREATION_DEBUG) { memset (p, 0, size); } else { /* @@ -136,20 +136,20 @@ sgen_alloc_obj_nolock (GCVTable vtable, size_t size) SGEN_ASSERT (6, sgen_vtable_get_descriptor (vtable), "VTable without descriptor"); - if (G_UNLIKELY (has_per_allocation_action)) { + if (G_UNLIKELY (sgen_has_per_allocation_action)) { static int alloc_count; int current_alloc = mono_atomic_inc_i32 (&alloc_count); - if (collect_before_allocs) { - if (((current_alloc % collect_before_allocs) == 0) && nursery_section) { + if (sgen_collect_before_allocs) { + if (((current_alloc % sgen_collect_before_allocs) == 0) && sgen_nursery_section) { sgen_perform_collection (0, GENERATION_NURSERY, "collect-before-alloc-triggered", TRUE, TRUE); - if (!degraded_mode && sgen_can_alloc_size (size) && real_size <= SGEN_MAX_SMALL_OBJ_SIZE) { + if (!sgen_degraded_mode && sgen_can_alloc_size (size) && real_size <= SGEN_MAX_SMALL_OBJ_SIZE) { // FIXME: g_assert_not_reached (); } } - } else if (verify_before_allocs) { - if ((current_alloc % verify_before_allocs) == 0) + } else if (sgen_verify_before_allocs) { + if ((current_alloc % sgen_verify_before_allocs) == 0) sgen_check_whole_heap_stw (); } } @@ -180,7 +180,7 @@ sgen_alloc_obj_nolock (GCVTable vtable, size_t size) CANARIFY_ALLOC(p,real_size); SGEN_LOG (6, "Allocated object %p, vtable: %p (%s), size: %zd", p, vtable, sgen_client_vtable_get_name (vtable), size); - binary_protocol_alloc (p , vtable, size, sgen_client_get_provenance ()); + sgen_binary_protocol_alloc (p , vtable, size, sgen_client_get_provenance ()); g_assert (*p == NULL); mono_atomic_store_seq (p, vtable); @@ -211,11 +211,11 @@ sgen_alloc_obj_nolock (GCVTable vtable, size_t size) /* when running in degraded mode, we continue allocing that way * for a while, to decrease the number of useless nursery collections. */ - if (degraded_mode && degraded_mode < sgen_nursery_size) + if (sgen_degraded_mode && sgen_degraded_mode < sgen_nursery_size) return alloc_degraded (vtable, size, FALSE); available_in_tlab = (int)(TLAB_REAL_END - TLAB_NEXT);//We'll never have tlabs > 2Gb - if (size > tlab_size || available_in_tlab > SGEN_MAX_NURSERY_WASTE) { + if (size > sgen_tlab_size || available_in_tlab > SGEN_MAX_NURSERY_WASTE) { /* Allocate directly from the nursery */ p = (void **)sgen_nursery_alloc (size); if (!p) { @@ -237,7 +237,7 @@ sgen_alloc_obj_nolock (GCVTable vtable, size_t size) * OOM). */ sgen_ensure_free_space (real_size, GENERATION_NURSERY); - if (!degraded_mode) + if (!sgen_degraded_mode) p = (void **)sgen_nursery_alloc (size); } if (!p) @@ -250,12 +250,12 @@ sgen_alloc_obj_nolock (GCVTable vtable, size_t size) SGEN_LOG (3, "Retire TLAB: %p-%p [%ld]", TLAB_START, TLAB_REAL_END, (long)(TLAB_REAL_END - TLAB_NEXT - size)); sgen_nursery_retire_region (p, available_in_tlab); - p = (void **)sgen_nursery_alloc_range (tlab_size, size, &alloc_size); + p = (void **)sgen_nursery_alloc_range (sgen_tlab_size, size, &alloc_size); if (!p) { /* See comment above in similar case. */ - sgen_ensure_free_space (tlab_size, GENERATION_NURSERY); - if (!degraded_mode) - p = (void **)sgen_nursery_alloc_range (tlab_size, size, &alloc_size); + sgen_ensure_free_space (sgen_tlab_size, GENERATION_NURSERY); + if (!sgen_degraded_mode) + p = (void **)sgen_nursery_alloc_range (sgen_tlab_size, size, &alloc_size); } if (!p) return alloc_degraded (vtable, size, TRUE); @@ -287,7 +287,7 @@ sgen_alloc_obj_nolock (GCVTable vtable, size_t size) if (G_LIKELY (p)) { SGEN_LOG (6, "Allocated object %p, vtable: %p (%s), size: %zd", p, vtable, sgen_client_vtable_get_name (vtable), size); - binary_protocol_alloc (p, vtable, size, sgen_client_get_provenance ()); + sgen_binary_protocol_alloc (p, vtable, size, sgen_client_get_provenance ()); mono_atomic_store_seq (p, vtable); } @@ -312,7 +312,7 @@ sgen_try_alloc_obj_nolock (GCVTable vtable, size_t size) if (real_size > SGEN_MAX_SMALL_OBJ_SIZE) return NULL; - if (G_UNLIKELY (size > tlab_size)) { + if (G_UNLIKELY (size > sgen_tlab_size)) { /* Allocate directly from the nursery */ p = (void **)sgen_nursery_alloc (size); if (!p) @@ -354,7 +354,7 @@ sgen_try_alloc_obj_nolock (GCVTable vtable, size_t size) size_t alloc_size = 0; sgen_nursery_retire_region (p, available_in_tlab); - new_next = (char *)sgen_nursery_alloc_range (tlab_size, size, &alloc_size); + new_next = (char *)sgen_nursery_alloc_range (sgen_tlab_size, size, &alloc_size); p = (void**)new_next; if (!p) return NULL; @@ -374,7 +374,7 @@ sgen_try_alloc_obj_nolock (GCVTable vtable, size_t size) CANARIFY_ALLOC(p,real_size); SGEN_LOG (6, "Allocated object %p, vtable: %p (%s), size: %zd", p, vtable, sgen_client_vtable_get_name (vtable), size); - binary_protocol_alloc (p, vtable, size, sgen_client_get_provenance ()); + sgen_binary_protocol_alloc (p, vtable, size, sgen_client_get_provenance ()); g_assert (*p == NULL); /* FIXME disable this in non debug builds */ mono_atomic_store_seq (p, vtable); @@ -391,19 +391,19 @@ sgen_alloc_obj (GCVTable vtable, size_t size) if (!SGEN_CAN_ALIGN_UP (size)) return NULL; - if (G_UNLIKELY (has_per_allocation_action)) { + if (G_UNLIKELY (sgen_has_per_allocation_action)) { static int alloc_count; int current_alloc = mono_atomic_inc_i32 (&alloc_count); - if (verify_before_allocs) { - if ((current_alloc % verify_before_allocs) == 0) { + if (sgen_verify_before_allocs) { + if ((current_alloc % sgen_verify_before_allocs) == 0) { LOCK_GC; sgen_check_whole_heap_stw (); UNLOCK_GC; } } - if (collect_before_allocs) { - if (((current_alloc % collect_before_allocs) == 0) && nursery_section) { + if (sgen_collect_before_allocs) { + if (((current_alloc % sgen_collect_before_allocs) == 0) && sgen_nursery_section) { LOCK_GC; sgen_perform_collection (0, GENERATION_NURSERY, "collect-before-alloc-triggered", TRUE, TRUE); UNLOCK_GC; @@ -445,11 +445,11 @@ sgen_alloc_obj_pinned (GCVTable vtable, size_t size) p = (GCObject *)sgen_los_alloc_large_inner (vtable, size); } else { SGEN_ASSERT (9, sgen_client_vtable_is_inited (vtable), "class %s:%s is not initialized", sgen_client_vtable_get_namespace (vtable), sgen_client_vtable_get_name (vtable)); - p = major_collector.alloc_small_pinned_obj (vtable, size, SGEN_VTABLE_HAS_REFERENCES (vtable)); + p = sgen_major_collector.alloc_small_pinned_obj (vtable, size, SGEN_VTABLE_HAS_REFERENCES (vtable)); } if (G_LIKELY (p)) { SGEN_LOG (6, "Allocated pinned object %p, vtable: %p (%s), size: %zd", p, vtable, sgen_client_vtable_get_name (vtable), size); - binary_protocol_alloc_pinned (p, vtable, size, sgen_client_get_provenance ()); + sgen_binary_protocol_alloc_pinned (p, vtable, size, sgen_client_get_provenance ()); } UNLOCK_GC; return p; @@ -477,7 +477,7 @@ sgen_alloc_obj_mature (GCVTable vtable, size_t size) void sgen_clear_tlabs (void) { - FOREACH_THREAD (info) { + FOREACH_THREAD_ALL (info) { /* A new TLAB will be allocated when the thread does its first allocation */ info->tlab_start = NULL; info->tlab_next = NULL; diff --git a/mono/sgen/sgen-cardtable.c b/mono/sgen/sgen-cardtable.c index c3a1cf23d3..360ad4a9c4 100644 --- a/mono/sgen/sgen-cardtable.c +++ b/mono/sgen/sgen-cardtable.c @@ -152,7 +152,7 @@ sgen_card_table_wbarrier_range_copy (gpointer _dest, gpointer _src, int size) while (size) { GCObject *value = *src; *dest = value; - if (SGEN_PTR_IN_NURSERY (value, nursery_bits, start, end) || concurrent_collection_in_progress) { + if (SGEN_PTR_IN_NURSERY (value, nursery_bits, start, end) || sgen_concurrent_collection_in_progress) { *card_address = 1; sgen_dummy_use (value); } @@ -571,7 +571,7 @@ sgen_cardtable_scan_object (GCObject *obj, mword block_obj_size, guint8 *cards, ctx.ops->scan_object (obj, sgen_obj_get_descriptor (obj), ctx.queue); } - binary_protocol_card_scan (obj, sgen_safe_object_get_size (obj)); + sgen_binary_protocol_card_scan (obj, sgen_safe_object_get_size (obj)); } void diff --git a/mono/sgen/sgen-copy-object.h b/mono/sgen/sgen-copy-object.h index bb97e4a681..17a6e64fac 100644 --- a/mono/sgen/sgen-copy-object.h +++ b/mono/sgen/sgen-copy-object.h @@ -47,7 +47,7 @@ static MONO_ALWAYS_INLINE void par_copy_object_no_checks (char *destination, GCVTable vt, void *obj, mword objsize) { sgen_client_pre_copy_checks (destination, vt, obj, objsize); - binary_protocol_copy (obj, destination, vt, objsize); + sgen_binary_protocol_copy (obj, destination, vt, objsize); /* FIXME: assumes object layout */ memcpy ((char*)destination + sizeof (mword), (char*)obj + sizeof (mword), objsize - sizeof (mword)); diff --git a/mono/sgen/sgen-debug.c b/mono/sgen/sgen-debug.c index 3fa79443e2..d313dcf024 100644 --- a/mono/sgen/sgen-debug.c +++ b/mono/sgen/sgen-debug.c @@ -26,14 +26,18 @@ #include "mono/sgen/sgen-pinning.h" #include "mono/sgen/sgen-client.h" + +#ifndef DISABLE_SGEN_DEBUG_HELPERS + + #define LOAD_VTABLE SGEN_LOAD_VTABLE #define object_is_forwarded SGEN_OBJECT_IS_FORWARDED #define object_is_pinned SGEN_OBJECT_IS_PINNED #define safe_object_get_size sgen_safe_object_get_size -void describe_ptr (char *ptr); -void check_object (GCObject *obj); +void sgen_describe_ptr (char *ptr); +void sgen_check_object (GCObject *obj); /* * ###################################################################### @@ -80,7 +84,7 @@ describe_pointer (char *ptr, gboolean need_setup) ptr = start; mono_sgen_los_describe_pointer (ptr); vtable = LOAD_VTABLE ((GCObject*)ptr); - } else if (major_collector.ptr_is_in_non_pinned_space (ptr, &start)) { + } else if (sgen_major_collector.ptr_is_in_non_pinned_space (ptr, &start)) { if (ptr == start) printf ("Pointer is the start of object %p in oldspace.\n", start); else if (start) @@ -89,8 +93,8 @@ describe_pointer (char *ptr, gboolean need_setup) printf ("Pointer inside oldspace.\n"); if (start) ptr = start; - vtable = (GCVTable)major_collector.describe_pointer (ptr); - } else if (major_collector.ptr_is_from_pinned_alloc (ptr)) { + vtable = (GCVTable)sgen_major_collector.describe_pointer (ptr); + } else if (sgen_major_collector.ptr_is_from_pinned_alloc (ptr)) { // FIXME: Handle pointers to the inside of objects printf ("Pointer is inside a pinned chunk.\n"); vtable = LOAD_VTABLE ((GCObject*)ptr); @@ -135,7 +139,7 @@ describe_pointer (char *ptr, gboolean need_setup) } void -describe_ptr (char *ptr) +sgen_describe_ptr (char *ptr) { describe_pointer (ptr, TRUE); } @@ -155,7 +159,7 @@ static gboolean missing_remsets; GCVTable __vt = SGEN_LOAD_VTABLE (obj); \ gboolean is_pinned = object_is_pinned (*(ptr)); \ SGEN_LOG (0, "Oldspace->newspace reference %p at offset %zd in object %p (%s.%s) not found in remsets%s.", *(ptr), (char*)(ptr) - (char*)(obj), (obj), sgen_client_vtable_get_namespace (__vt), sgen_client_vtable_get_name (__vt), is_pinned ? ", but object is pinned" : ""); \ - binary_protocol_missing_remset ((obj), __vt, (int) ((char*)(ptr) - (char*)(obj)), *(ptr), (gpointer)LOAD_VTABLE(*(ptr)), is_pinned); \ + sgen_binary_protocol_missing_remset ((obj), __vt, (int) ((char*)(ptr) - (char*)(obj)), *(ptr), (gpointer)LOAD_VTABLE(*(ptr)), is_pinned); \ if (!is_pinned) \ missing_remsets = TRUE; \ } \ @@ -192,15 +196,15 @@ sgen_check_remset_consistency (void) SGEN_LOG (1, "Begin heap consistency check..."); // Check that oldspace->newspace pointers are registered with the collector - major_collector.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL, (IterateObjectCallbackFunc)check_consistency_callback, NULL); + sgen_major_collector.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL, (IterateObjectCallbackFunc)check_consistency_callback, NULL); sgen_los_iterate_objects ((IterateObjectCallbackFunc)check_consistency_callback, NULL); SGEN_LOG (1, "Heap consistency check done."); if (missing_remsets) - binary_protocol_flush_buffers (TRUE); - if (!binary_protocol_is_enabled ()) + sgen_binary_protocol_flush_buffers (TRUE); + if (!sgen_binary_protocol_is_enabled ()) g_assert (!missing_remsets); } @@ -220,7 +224,7 @@ is_major_or_los_object_marked (GCObject *obj) if (!cards || !sgen_get_remset ()->find_address_with_cards (start, cards, (char*)(ptr))) { \ GCVTable __vt = SGEN_LOAD_VTABLE (obj); \ SGEN_LOG (0, "major->major reference %p at offset %zd in object %p (%s.%s) not found in remsets.", *(ptr), (char*)(ptr) - (char*)(obj), (obj), sgen_client_vtable_get_namespace (__vt), sgen_client_vtable_get_name (__vt)); \ - binary_protocol_missing_remset ((obj), __vt, (int) ((char*)(ptr) - (char*)(obj)), *(ptr), (gpointer)LOAD_VTABLE(*(ptr)), object_is_pinned (*(ptr))); \ + sgen_binary_protocol_missing_remset ((obj), __vt, (int) ((char*)(ptr) - (char*)(obj)), *(ptr), (gpointer)LOAD_VTABLE(*(ptr)), object_is_pinned (*(ptr))); \ missing_remsets = TRUE; \ } \ } \ @@ -252,11 +256,11 @@ sgen_check_mod_union_consistency (void) { missing_remsets = FALSE; - major_collector.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL, (IterateObjectCallbackFunc)check_mod_union_callback, (void*)FALSE); + sgen_major_collector.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL, (IterateObjectCallbackFunc)check_mod_union_callback, (void*)FALSE); sgen_los_iterate_objects ((IterateObjectCallbackFunc)check_mod_union_callback, (void*)TRUE); - if (!binary_protocol_is_enabled ()) + if (!sgen_binary_protocol_is_enabled ()) g_assert (!missing_remsets); } @@ -278,7 +282,7 @@ check_major_refs_callback (GCObject *obj, size_t size, void *dummy) void sgen_check_major_refs (void) { - major_collector.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL, (IterateObjectCallbackFunc)check_major_refs_callback, NULL); + sgen_major_collector.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL, (IterateObjectCallbackFunc)check_major_refs_callback, NULL); sgen_los_iterate_objects ((IterateObjectCallbackFunc)check_major_refs_callback, NULL); } @@ -291,13 +295,13 @@ sgen_check_major_refs (void) } while (0) /* - * check_object: + * sgen_check_object: * * Perform consistency check on an object. Currently we only check that the * reference fields are valid. */ void -check_object (GCObject *obj) +sgen_check_object (GCObject *obj) { char *start = (char*)obj; SgenDescriptor desc; @@ -327,7 +331,7 @@ setup_valid_nursery_objects (void) if (!valid_nursery_objects) valid_nursery_objects = (GCObject **)sgen_alloc_os_memory (sgen_nursery_max_size, (SgenAllocFlags)(SGEN_ALLOC_INTERNAL | SGEN_ALLOC_ACTIVATE), "debugging data", MONO_MEM_ACCOUNT_SGEN_DEBUGGING); valid_nursery_object_count = 0; - sgen_scan_area_with_callback (nursery_section->data, nursery_section->end_data, setup_mono_sgen_scan_area_with_callback, NULL, FALSE, FALSE); + sgen_scan_area_with_callback (sgen_nursery_section->data, sgen_nursery_section->end_data, setup_mono_sgen_scan_area_with_callback, NULL, FALSE, FALSE); } static gboolean @@ -393,7 +397,7 @@ is_valid_object_pointer (char *object) if (sgen_los_is_valid_object (object)) return TRUE; - if (major_collector.is_valid_object (object)) + if (sgen_major_collector.is_valid_object (object)) return TRUE; return FALSE; } @@ -460,8 +464,8 @@ sgen_check_whole_heap (gboolean allow_missing_pinned) setup_valid_nursery_objects (); broken_heap = FALSE; - sgen_scan_area_with_callback (nursery_section->data, nursery_section->end_data, verify_object_pointers_callback, (void*) (size_t) allow_missing_pinned, FALSE, TRUE); - major_collector.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL, verify_object_pointers_callback, (void*) (size_t) allow_missing_pinned); + sgen_scan_area_with_callback (sgen_nursery_section->data, sgen_nursery_section->end_data, verify_object_pointers_callback, (void*) (size_t) allow_missing_pinned, FALSE, TRUE); + sgen_major_collector.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL, verify_object_pointers_callback, (void*) (size_t) allow_missing_pinned); sgen_los_iterate_objects (verify_object_pointers_callback, (void*) (size_t) allow_missing_pinned); g_assert (!broken_heap); @@ -476,7 +480,7 @@ ptr_in_heap (char *object) if (sgen_los_is_valid_object (object)) return TRUE; - if (major_collector.is_valid_object (object)) + if (sgen_major_collector.is_valid_object (object)) return TRUE; return FALSE; } @@ -497,10 +501,10 @@ find_pinning_ref_from_thread (char *obj, size_t size) #ifndef SGEN_WITHOUT_MONO char *endobj = obj + size; - FOREACH_THREAD (info) { + FOREACH_THREAD_EXCLUDE (info, MONO_THREAD_INFO_FLAGS_NO_GC) { mword *ctxstart, *ctxcurrent, *ctxend; char **start = (char**)info->client_info.stack_start; - if (info->client_info.skip || info->client_info.gc_disabled) + if (info->client_info.skip) continue; while (start < (char**)info->client_info.info.stack_end) { if (*start >= obj && *start < endobj) @@ -528,7 +532,7 @@ find_pinning_reference (char *obj, size_t size) RootRecord *root; char *endobj = obj + size; - SGEN_HASH_TABLE_FOREACH (&roots_hash [ROOT_TYPE_NORMAL], char **, start, RootRecord *, root) { + SGEN_HASH_TABLE_FOREACH (&sgen_roots_hash [ROOT_TYPE_NORMAL], char **, start, RootRecord *, root) { /* if desc is non-null it has precise info */ if (!root->root_desc) { while (start < (char**)root->end_root) { @@ -552,7 +556,7 @@ find_pinning_reference (char *obj, size_t size) } else { \ mword __size = sgen_safe_object_get_size ((GCObject*)__target); \ if (__size <= SGEN_MAX_SMALL_OBJ_SIZE) \ - g_assert (major_collector.is_object_live ((GCObject*)__target)); \ + g_assert (sgen_major_collector.is_object_live ((GCObject*)__target)); \ else \ g_assert (sgen_los_object_is_pinned ((GCObject*)__target)); \ } \ @@ -573,7 +577,7 @@ check_marked_callback (GCObject *obj, size_t size, void *dummy) if (!sgen_los_object_is_pinned (obj)) return; } else { - if (!major_collector.is_object_live (obj)) + if (!sgen_major_collector.is_object_live (obj)) return; } @@ -588,7 +592,7 @@ sgen_check_heap_marked (gboolean nursery_must_be_pinned) setup_valid_nursery_objects (); iterate_valid_nursery_objects (check_marked_callback, (void*)(size_t)nursery_must_be_pinned); - major_collector.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL, check_marked_callback, (void*)FALSE); + sgen_major_collector.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL, check_marked_callback, (void*)FALSE); sgen_los_iterate_objects (check_marked_callback, (void*)TRUE); } @@ -608,7 +612,7 @@ void sgen_check_nursery_objects_pinned (gboolean pinned) { sgen_clear_nursery_fragments (); - sgen_scan_area_with_callback (nursery_section->data, nursery_section->end_data, + sgen_scan_area_with_callback (sgen_nursery_section->data, sgen_nursery_section->end_data, (IterateObjectCallbackFunc)check_nursery_objects_pinned_callback, (void*) (size_t) pinned /* (void*)&ctx */, FALSE, TRUE); } @@ -617,8 +621,8 @@ verify_scan_starts (char *start, char *end) { size_t i; - for (i = 0; i < nursery_section->num_scan_start; ++i) { - char *addr = nursery_section->scan_starts [i]; + for (i = 0; i < sgen_nursery_section->num_scan_start; ++i) { + char *addr = sgen_nursery_section->scan_starts [i]; if (addr > start && addr < end) SGEN_LOG (0, "NFC-BAD SCAN START [%zu] %p for obj [%p %p]", i, addr, start, end); } @@ -629,7 +633,7 @@ sgen_debug_verify_nursery (gboolean do_dump_nursery_content) { char *start, *end, *cur, *hole_start; - if (nursery_canaries_enabled ()) + if (sgen_nursery_canaries_enabled ()) SGEN_LOG (0, "Checking nursery canaries..."); /*This cleans up unused fragments */ @@ -664,7 +668,7 @@ sgen_debug_verify_nursery (gboolean do_dump_nursery_content) sgen_client_vtable_get_namespace (vtable), sgen_client_vtable_get_name (vtable), is_array_fill); } - if (nursery_canaries_enabled () && !is_array_fill) { + if (sgen_nursery_canaries_enabled () && !is_array_fill) { CHECK_CANARY_FOR_OBJECT ((GCObject*)cur, TRUE); CANARIFY_SIZE (size); } @@ -772,7 +776,7 @@ scan_roots_for_specific_ref (GCObject *key, int root_type) RootRecord *root; check_key = key; - SGEN_HASH_TABLE_FOREACH (&roots_hash [root_type], void **, start_root, RootRecord *, root) { + SGEN_HASH_TABLE_FOREACH (&sgen_roots_hash [root_type], void **, start_root, RootRecord *, root) { SgenDescriptor desc = root->root_desc; check_root = root; @@ -838,17 +842,17 @@ mono_gc_scan_for_specific_ref (GCObject *key, gboolean precise) scan_object_for_specific_ref_precise = precise; - sgen_scan_area_with_callback (nursery_section->data, nursery_section->end_data, + sgen_scan_area_with_callback (sgen_nursery_section->data, sgen_nursery_section->end_data, (IterateObjectCallbackFunc)scan_object_for_specific_ref_callback, key, TRUE, FALSE); - major_collector.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL, (IterateObjectCallbackFunc)scan_object_for_specific_ref_callback, key); + sgen_major_collector.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL, (IterateObjectCallbackFunc)scan_object_for_specific_ref_callback, key); sgen_los_iterate_objects ((IterateObjectCallbackFunc)scan_object_for_specific_ref_callback, key); scan_roots_for_specific_ref (key, ROOT_TYPE_NORMAL); scan_roots_for_specific_ref (key, ROOT_TYPE_WBARRIER); - SGEN_HASH_TABLE_FOREACH (&roots_hash [ROOT_TYPE_PINNED], void **, ptr, RootRecord *, root) { + SGEN_HASH_TABLE_FOREACH (&sgen_roots_hash [ROOT_TYPE_PINNED], void **, ptr, RootRecord *, root) { while (ptr < (void**)root->end_root) { check_root_obj_specific_ref (root, (GCObject *)*ptr, key); ++ptr; @@ -882,7 +886,7 @@ sgen_scan_for_registered_roots_in_domain (MonoDomain *domain, int root_type) void **start_root; RootRecord *root; check_domain = domain; - SGEN_HASH_TABLE_FOREACH (&roots_hash [root_type], void **, start_root, RootRecord *, root) { + SGEN_HASH_TABLE_FOREACH (&sgen_roots_hash [root_type], void **, start_root, RootRecord *, root) { SgenDescriptor desc = root->root_desc; /* The MonoDomain struct is allowed to hold @@ -955,7 +959,7 @@ is_xdomain_ref_allowed (GCObject **ptr, GCObject *obj, MonoDomain *domain) return TRUE; #ifndef DISABLE_REMOTING - if (mono_defaults.real_proxy_class->supertypes && mono_class_has_parent_fast (o->vtable->klass, mono_defaults.real_proxy_class) && + if (m_class_get_supertypes (mono_defaults.real_proxy_class) && mono_class_has_parent_fast (o->vtable->klass, mono_defaults.real_proxy_class) && offset == G_STRUCT_OFFSET (MonoRealProxy, unwrapped_server)) return TRUE; #endif @@ -970,10 +974,10 @@ is_xdomain_ref_allowed (GCObject **ptr, GCObject *obj, MonoDomain *domain) * at System.Runtime.Remoting.Channels.CrossAppDomainSink.ProcessMessageInDomain (byte[],System.Runtime.Remoting.Messaging.CADMethodCallMessage) [0x00008] in /home/schani/Work/novell/trunk/mcs/class/corlib/System.Runtime.Remoting.Channels/CrossAppDomainChannel.cs:198 * at (wrapper runtime-invoke) object.runtime_invoke_CrossAppDomainSink/ProcessMessageRes_object_object (object,intptr,intptr,intptr) */ - if (!strcmp (ref->vtable->klass->name_space, "System") && - !strcmp (ref->vtable->klass->name, "Byte[]") && - !strcmp (o->vtable->klass->name_space, "System.IO") && - !strcmp (o->vtable->klass->name, "MemoryStream")) + if (!strcmp (m_class_get_name_space (ref->vtable->klass), "System") && + !strcmp (m_class_get_name (ref->vtable->klass), "Byte[]") && + !strcmp (m_class_get_name_space (o->vtable->klass), "System.IO") && + !strcmp (m_class_get_name (o->vtable->klass), "MemoryStream")) return TRUE; return FALSE; } @@ -993,13 +997,14 @@ check_reference_for_xdomain (GCObject **ptr, GCObject *obj, MonoDomain *domain) return; field = NULL; - for (klass = obj->vtable->klass; klass; klass = klass->parent) { + for (klass = obj->vtable->klass; klass; klass = m_class_get_parent (klass)) { int i; int fcount = mono_class_get_field_count (klass); + MonoClassField *klass_fields = m_class_get_fields (klass); for (i = 0; i < fcount; ++i) { - if (klass->fields[i].offset == offset) { - field = &klass->fields[i]; + if (klass_fields[i].offset == offset) { + field = &klass_fields[i]; break; } } @@ -1014,9 +1019,9 @@ check_reference_for_xdomain (GCObject **ptr, GCObject *obj, MonoDomain *domain) } else str = NULL; g_print ("xdomain reference in %p (%s.%s) at offset %d (%s) to %p (%s.%s) (%s) - pointed to by:\n", - obj, obj->vtable->klass->name_space, obj->vtable->klass->name, + obj, m_class_get_name_space (obj->vtable->klass), m_class_get_name (obj->vtable->klass), offset, field ? field->name : "", - ref, ref->vtable->klass->name_space, ref->vtable->klass->name, str ? str : ""); + ref, m_class_get_name_space (ref->vtable->klass), m_class_get_name (ref->vtable->klass), str ? str : ""); mono_gc_scan_for_specific_ref (obj, TRUE); if (str) g_free (str); @@ -1041,12 +1046,12 @@ sgen_check_for_xdomain_refs (void) { LOSObject *bigobj; - sgen_scan_area_with_callback (nursery_section->data, nursery_section->end_data, + sgen_scan_area_with_callback (sgen_nursery_section->data, sgen_nursery_section->end_data, (IterateObjectCallbackFunc)scan_object_for_xdomain_refs, NULL, FALSE, TRUE); - major_collector.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL, (IterateObjectCallbackFunc)scan_object_for_xdomain_refs, NULL); + sgen_major_collector.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL, (IterateObjectCallbackFunc)scan_object_for_xdomain_refs, NULL); - for (bigobj = los_object_list; bigobj; bigobj = bigobj->next) + for (bigobj = sgen_los_object_list; bigobj; bigobj = bigobj->next) scan_object_for_xdomain_refs ((GCObject*)bigobj->data, sgen_los_object_size (bigobj), NULL); } @@ -1121,16 +1126,16 @@ dump_object (GCObject *obj, gboolean dump_location) * in strings, so we just ignore them; */ i = j = 0; - while (klass->name [i] && j < sizeof (class_name) - 1) { - if (!strchr ("<>\"", klass->name [i])) - class_name [j++] = klass->name [i]; + while (m_class_get_name (klass) [i] && j < sizeof (class_name) - 1) { + if (!strchr ("<>\"", m_class_get_name (klass) [i])) + class_name [j++] = m_class_get_name (klass) [i]; ++i; } g_assert (j < sizeof (class_name)); class_name [j] = 0; fprintf (heap_dump_file, "name_space, class_name, + m_class_get_name_space (klass), class_name, safe_object_get_size (obj)); if (dump_location) { const char *location; @@ -1184,12 +1189,12 @@ sgen_debug_dump_heap (const char *type, int num, const char *reason) dump_object ((GCObject *)pinned_objects->data [i], TRUE); fprintf (heap_dump_file, "\n"); - sgen_dump_section (nursery_section, "nursery"); + sgen_dump_section (sgen_nursery_section, "nursery"); - major_collector.dump_heap (heap_dump_file); + sgen_major_collector.dump_heap (heap_dump_file); fprintf (heap_dump_file, "\n"); - for (bigobj = los_object_list; bigobj; bigobj = bigobj->next) + for (bigobj = sgen_los_object_list; bigobj; bigobj = bigobj->next) dump_object ((GCObject*)bigobj->data, FALSE); fprintf (heap_dump_file, "\n"); @@ -1213,9 +1218,9 @@ find_object_for_ptr_callback (GCObject *obj, size_t size, void *user_data) GCObject* sgen_find_object_for_ptr (char *ptr) { - if (ptr >= nursery_section->data && ptr < nursery_section->end_data) { + if (ptr >= sgen_nursery_section->data && ptr < sgen_nursery_section->end_data) { found_obj = NULL; - sgen_scan_area_with_callback (nursery_section->data, nursery_section->end_data, + sgen_scan_area_with_callback (sgen_nursery_section->data, sgen_nursery_section->end_data, find_object_for_ptr_callback, ptr, TRUE, FALSE); if (found_obj) return found_obj; @@ -1231,8 +1236,76 @@ sgen_find_object_for_ptr (char *ptr) * be called from gdb, so we don't care. */ found_obj = NULL; - major_collector.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL, find_object_for_ptr_callback, ptr); + sgen_major_collector.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL, find_object_for_ptr_callback, ptr); return found_obj; } +#else + +void +sgen_check_for_xdomain_refs (void) +{ +} + +void +sgen_check_heap_marked (gboolean nursery_must_be_pinned) +{ +} + +void +sgen_check_major_refs (void) +{ +} + +void +sgen_check_mod_union_consistency (void) +{ +} + +void +sgen_check_nursery_objects_pinned (gboolean pinned) +{ +} + +void +sgen_check_remset_consistency (void) +{ +} + +void +sgen_check_whole_heap (gboolean allow_missing_pinned) +{ +} + +void +sgen_debug_check_nursery_is_clean (void) +{ +} + +void +sgen_debug_dump_heap (const char *type, int num, const char *reason) +{ +} + +void +sgen_debug_enable_heap_dump (const char *filename) +{ +} + +void +sgen_debug_verify_nursery (gboolean do_dump_nursery_content) +{ +} + +void +sgen_dump_occupied (char *start, char *end, char *section_start) +{ +} + +void +sgen_scan_for_registered_roots_in_domain (MonoDomain *domain, int root_type) +{ +} + +#endif /*DISABLE_SGEN_DEBUG_HELPERS */ #endif /*HAVE_SGEN_GC*/ diff --git a/mono/sgen/sgen-descriptor.c b/mono/sgen/sgen-descriptor.c index 9a160744b6..320efe5d62 100644 --- a/mono/sgen/sgen-descriptor.c +++ b/mono/sgen/sgen-descriptor.c @@ -39,8 +39,6 @@ #define MAX_USER_DESCRIPTORS 16 #define MAKE_ROOT_DESC(type,val) ((type) | ((val) << ROOT_DESC_TYPE_SHIFT)) -#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1)) - static SgenArrayList complex_descriptors = SGEN_ARRAY_LIST_INIT (NULL, NULL, NULL, INTERNAL_MEM_COMPLEX_DESCRIPTORS); static SgenUserRootMarkFunc user_descriptors [MAX_USER_DESCRIPTORS]; diff --git a/mono/sgen/sgen-fin-weak-hash.c b/mono/sgen/sgen-fin-weak-hash.c index 9f37ae317d..0a953bf27b 100644 --- a/mono/sgen/sgen-fin-weak-hash.c +++ b/mono/sgen/sgen-fin-weak-hash.c @@ -122,7 +122,7 @@ sgen_collect_bridge_objects (int generation, ScanCopyContext ctx) continue; /* Object is a bridge object and major heap says it's dead */ - if (major_collector.is_object_live (object)) + if (sgen_major_collector.is_object_live (object)) continue; /* Nursery says the object is dead. */ @@ -186,7 +186,7 @@ sgen_finalize_in_range (int generation, ScanCopyContext ctx) SGEN_HASH_TABLE_FOREACH (hash_table, GCObject *, object, gpointer, dummy) { int tag = tagged_object_get_tag (object); object = tagged_object_get_object (object); - if (!major_collector.is_object_live (object)) { + if (!sgen_major_collector.is_object_live (object)) { gboolean is_fin_ready = sgen_gc_is_object_ready_for_finalization (object); GCObject *copy = object; copy_func (©, queue); @@ -548,7 +548,7 @@ sgen_process_fin_stage_entries (void) } void -sgen_object_register_for_finalization (GCObject *obj, void *user_data) +sgen_object_register_for_finalization (GCObject *obj, SGenFinalizationProc user_data) { while (add_stage_entry (NUM_FIN_STAGE_ENTRIES, &next_fin_stage_entry, fin_stage_entries, obj, user_data) == -1) { if (try_lock_stage_for_processing (NUM_FIN_STAGE_ENTRIES, &next_fin_stage_entry)) { diff --git a/mono/sgen/sgen-gc.c.REMOVED.git-id b/mono/sgen/sgen-gc.c.REMOVED.git-id index 6e8e890409..3edc2d689d 100644 --- a/mono/sgen/sgen-gc.c.REMOVED.git-id +++ b/mono/sgen/sgen-gc.c.REMOVED.git-id @@ -1 +1 @@ -036eee9ce918ffd99cdc95154daa051133476ff4 \ No newline at end of file +cd76d578a783e685388886cfaeccd896493e9457 \ No newline at end of file diff --git a/mono/sgen/sgen-gc.h b/mono/sgen/sgen-gc.h index cbf1da2ea9..c34de3af4f 100644 --- a/mono/sgen/sgen-gc.h +++ b/mono/sgen/sgen-gc.h @@ -137,25 +137,25 @@ extern guint64 stat_objects_copied_major; #endif #define SGEN_LOG(level, format, ...) do { \ - if (G_UNLIKELY ((level) <= SGEN_MAX_DEBUG_LEVEL && (level) <= gc_debug_level)) { \ + if (G_UNLIKELY ((level) <= SGEN_MAX_DEBUG_LEVEL && (level) <= sgen_gc_debug_level)) { \ char logTime[80]; \ LOG_TIMESTAMP; \ - mono_gc_printf (gc_debug_file, "%s " format "\n", logTime, ##__VA_ARGS__); \ + mono_gc_printf (sgen_gc_debug_file, "%s " format "\n", logTime, ##__VA_ARGS__); \ } } while (0) #define SGEN_COND_LOG(level, cond, format, ...) do { \ - if (G_UNLIKELY ((level) <= SGEN_MAX_DEBUG_LEVEL && (level) <= gc_debug_level)) { \ + if (G_UNLIKELY ((level) <= SGEN_MAX_DEBUG_LEVEL && (level) <= sgen_gc_debug_level)) { \ if (cond) { \ char logTime[80]; \ LOG_TIMESTAMP; \ - mono_gc_printf (gc_debug_file, "%s " format "\n", logTime, ##__VA_ARGS__); \ + mono_gc_printf (sgen_gc_debug_file, "%s " format "\n", logTime, ##__VA_ARGS__); \ } \ } } while (0) -extern int gc_debug_level; -extern FILE* gc_debug_file; +extern int sgen_gc_debug_level; +extern FILE* sgen_gc_debug_file; -extern int current_collection_generation; +extern int sgen_current_collection_generation; extern unsigned int sgen_global_stop_count; @@ -392,7 +392,7 @@ enum { ROOT_TYPE_NUM }; -extern SgenHashTable roots_hash [ROOT_TYPE_NUM]; +extern SgenHashTable sgen_roots_hash [ROOT_TYPE_NUM]; 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)); @@ -465,7 +465,7 @@ void sgen_add_to_global_remset (gpointer ptr, GCObject *obj); int sgen_get_current_collection_generation (void); gboolean sgen_collection_is_concurrent (void); -gboolean sgen_concurrent_collection_in_progress (void); +gboolean sgen_get_concurrent_collection_in_progress (void); typedef struct _SgenFragment SgenFragment; @@ -686,7 +686,7 @@ struct _SgenMajorCollector { void (*init_block_free_lists) (gpointer *list_p); }; -extern SgenMajorCollector major_collector; +extern SgenMajorCollector sgen_major_collector; void sgen_marksweep_init (SgenMajorCollector *collector); void sgen_marksweep_conc_init (SgenMajorCollector *collector); @@ -827,7 +827,10 @@ void sgen_null_link_in_range (int generation, ScanCopyContext ctx, gboolean trac void sgen_process_fin_stage_entries (void) MONO_PERMIT (need (sgen_gc_locked)); gboolean sgen_have_pending_finalizers (void); -void sgen_object_register_for_finalization (GCObject *obj, void *user_data) + +typedef void (*SGenFinalizationProc)(gpointer, gpointer); // same as MonoFinalizationProc, GC_finalization_proc + +void sgen_object_register_for_finalization (GCObject *obj, SGenFinalizationProc user_data) MONO_PERMIT (need (sgen_lock_gc)); void sgen_finalize_if (SgenObjectPredicateFunc predicate, void *user_data) @@ -889,9 +892,9 @@ struct _LOSObject { GCObject data [MONO_ZERO_LEN_ARRAY]; }; -extern LOSObject *los_object_list; -extern mword los_memory_usage; -extern mword los_memory_usage_total; +extern LOSObject *sgen_los_object_list; +extern mword sgen_los_memory_usage; +extern mword sgen_los_memory_usage_total; void sgen_los_free_object (LOSObject *obj); void* sgen_los_alloc_large_inner (GCVTable vtable, size_t size) @@ -961,7 +964,7 @@ sgen_major_is_object_alive (GCObject *object) if (objsize > SGEN_MAX_SMALL_OBJ_SIZE) return sgen_los_object_is_pinned (object); - return major_collector.is_object_live (object); + return sgen_major_collector.is_object_live (object); } @@ -991,7 +994,7 @@ sgen_is_object_alive_for_current_gen (GCObject *object) if (sgen_ptr_in_nursery (object)) return sgen_nursery_is_object_alive (object); - if (current_collection_generation == GENERATION_NURSERY) + if (sgen_current_collection_generation == GENERATION_NURSERY) return TRUE; return sgen_major_is_object_alive (object); @@ -1024,30 +1027,30 @@ void sgen_gchandle_free (guint32 gchandle); /* Other globals */ -extern GCMemSection *nursery_section; -extern guint32 collect_before_allocs; -extern guint32 verify_before_allocs; -extern gboolean has_per_allocation_action; -extern size_t degraded_mode; +extern GCMemSection *sgen_nursery_section; +extern guint32 sgen_collect_before_allocs; +extern guint32 sgen_verify_before_allocs; +extern gboolean sgen_has_per_allocation_action; +extern size_t sgen_degraded_mode; extern int default_nursery_size; -extern guint32 tlab_size; -extern NurseryClearPolicy nursery_clear_policy; +extern guint32 sgen_tlab_size; +extern NurseryClearPolicy sgen_nursery_clear_policy; extern gboolean sgen_try_free_some_memory; -extern mword total_promoted_size; -extern mword total_allocated_major; +extern mword sgen_total_promoted_size; +extern mword sgen_total_allocated_major; extern volatile gboolean sgen_suspend_finalizers; -extern MonoCoopMutex gc_mutex; -extern volatile gboolean concurrent_collection_in_progress; +extern MonoCoopMutex sgen_gc_mutex; +extern volatile gboolean sgen_concurrent_collection_in_progress; /* Nursery helpers. */ static inline void sgen_set_nursery_scan_start (char *p) { - size_t idx = (p - (char*)nursery_section->data) / SGEN_SCAN_START_SIZE; - char *old = nursery_section->scan_starts [idx]; + size_t idx = (p - (char*)sgen_nursery_section->data) / SGEN_SCAN_START_SIZE; + char *old = sgen_nursery_section->scan_starts [idx]; if (!old || old > p) - nursery_section->scan_starts [idx] = p; + sgen_nursery_section->scan_starts [idx] = p; } @@ -1111,22 +1114,22 @@ gint64 sgen_timestamp (void); * - Canary space is not included on checks against SGEN_MAX_SMALL_OBJ_SIZE */ -gboolean nursery_canaries_enabled (void); +gboolean sgen_nursery_canaries_enabled (void); #define CANARY_SIZE 8 #define CANARY_STRING "koupepia" -#define CANARIFY_SIZE(size) if (nursery_canaries_enabled ()) { \ +#define CANARIFY_SIZE(size) if (sgen_nursery_canaries_enabled ()) { \ size = size + CANARY_SIZE; \ } -#define CANARIFY_ALLOC(addr,size) if (nursery_canaries_enabled ()) { \ +#define CANARIFY_ALLOC(addr,size) if (sgen_nursery_canaries_enabled ()) { \ memcpy ((char*) (addr) + (size), CANARY_STRING, CANARY_SIZE); \ } #define CANARY_VALID(addr) (strncmp ((char*) (addr), CANARY_STRING, CANARY_SIZE) == 0) -#define CHECK_CANARY_FOR_OBJECT(addr,fail) if (nursery_canaries_enabled ()) { \ +#define CHECK_CANARY_FOR_OBJECT(addr,fail) if (sgen_nursery_canaries_enabled ()) { \ guint size = sgen_safe_object_get_size_unaligned ((GCObject *) (addr)); \ char* canary_ptr = (char*) (addr) + size; \ if (!CANARY_VALID(canary_ptr)) { \ diff --git a/mono/sgen/sgen-gchandles.c b/mono/sgen/sgen-gchandles.c index a13ca56dce..b5a6ac69fb 100644 --- a/mono/sgen/sgen-gchandles.c +++ b/mono/sgen/sgen-gchandles.c @@ -48,11 +48,11 @@ protocol_gchandle_update (int handle_type, gpointer link, gpointer old_value, gp return; if (!old && new_) - binary_protocol_dislink_add (link, MONO_GC_REVEAL_POINTER (new_value, TRUE), track); + sgen_binary_protocol_dislink_add (link, MONO_GC_REVEAL_POINTER (new_value, TRUE), track); else if (old && !new_) - binary_protocol_dislink_remove (link, track); + sgen_binary_protocol_dislink_remove (link, track); else if (old && new_ && old_value != new_value) - binary_protocol_dislink_update (link, MONO_GC_REVEAL_POINTER (new_value, TRUE), track); + sgen_binary_protocol_dislink_update (link, MONO_GC_REVEAL_POINTER (new_value, TRUE), track); } /* Returns the new value in the slot, or NULL if the CAS failed. */ @@ -406,7 +406,7 @@ null_link_if_necessary (gpointer hidden, GCHandleType handle_type, int max_gener if (object_older_than (obj, max_generation)) return hidden; - if (major_collector.is_object_live (obj)) + if (sgen_major_collector.is_object_live (obj)) return hidden; /* Clear link if object is ready for finalization. This check may be redundant wrt is_object_live(). */ diff --git a/mono/sgen/sgen-gray.c b/mono/sgen/sgen-gray.c index e496970f9a..8192c19d8b 100644 --- a/mono/sgen/sgen-gray.c +++ b/mono/sgen/sgen-gray.c @@ -140,7 +140,7 @@ sgen_gray_object_enqueue (SgenGrayQueue *queue, GCObject *obj, SgenDescriptor de *++queue->cursor = entry; #ifdef SGEN_HEAVY_BINARY_PROTOCOL - binary_protocol_gray_enqueue (queue, queue->cursor, obj); + sgen_binary_protocol_gray_enqueue (queue, queue->cursor, obj); #endif } @@ -224,7 +224,7 @@ sgen_gray_object_dequeue (SgenGrayQueue *queue, gboolean is_parallel) entry = *queue->cursor--; #ifdef SGEN_HEAVY_BINARY_PROTOCOL - binary_protocol_gray_dequeue (queue, queue->cursor + 1, entry.obj); + sgen_binary_protocol_gray_dequeue (queue, queue->cursor + 1, entry.obj); #endif if (G_UNLIKELY (queue->cursor < GRAY_FIRST_CURSOR_POSITION (queue->first))) { diff --git a/mono/sgen/sgen-gray.h b/mono/sgen/sgen-gray.h index 3ea4037af2..7da84ba073 100644 --- a/mono/sgen/sgen-gray.h +++ b/mono/sgen/sgen-gray.h @@ -173,7 +173,7 @@ GRAY_OBJECT_ENQUEUE (SgenGrayQueue *queue, GCObject *obj, SgenDescriptor desc, g *++queue->cursor = entry; #ifdef SGEN_HEAVY_BINARY_PROTOCOL - binary_protocol_gray_enqueue (queue, queue->cursor, obj); + sgen_binary_protocol_gray_enqueue (queue, queue->cursor, obj); #endif } #endif @@ -203,7 +203,7 @@ GRAY_OBJECT_DEQUEUE (SgenGrayQueue *queue, GCObject** obj, SgenDescriptor *desc, *obj = entry.obj; *desc = entry.desc; #ifdef SGEN_HEAVY_BINARY_PROTOCOL - binary_protocol_gray_dequeue (queue, queue->cursor + 1, *obj); + sgen_binary_protocol_gray_dequeue (queue, queue->cursor + 1, *obj); #endif } #endif diff --git a/mono/sgen/sgen-los.c b/mono/sgen/sgen-los.c index 195cd10213..87e055a27f 100644 --- a/mono/sgen/sgen-los.c +++ b/mono/sgen/sgen-los.c @@ -64,11 +64,11 @@ struct _LOSSection { }; /* We allow read only access on the list while sweep is not running */ -LOSObject *los_object_list = NULL; +LOSObject *sgen_los_object_list = NULL; /* Memory used by LOS objects */ -mword los_memory_usage = 0; +mword sgen_los_memory_usage = 0; /* Total memory used by the LOS allocator */ -mword los_memory_usage_total = 0; +mword sgen_los_memory_usage_total = 0; static LOSSection *los_sections = NULL; static LOSFreeChunks *los_fast_free_lists [LOS_NUM_FAST_SIZES]; /* 0 is for larger sizes */ @@ -101,7 +101,7 @@ los_consistency_check (void) int i; mword memory_usage = 0; - for (obj = los_object_list; obj; obj = obj->next) { + for (obj = sgen_los_object_list; obj; obj = obj->next) { mword obj_size = sgen_los_object_size (obj); char *end = obj->data + obj_size; int start_index, num_chunks; @@ -139,7 +139,7 @@ los_consistency_check (void) } } - g_assert (los_memory_usage == memory_usage); + g_assert (sgen_los_memory_usage == memory_usage); } #endif @@ -272,7 +272,7 @@ get_los_section_memory (size_t size) section->next = los_sections; los_sections = section; - los_memory_usage_total += LOS_SECTION_SIZE; + sgen_los_memory_usage_total += LOS_SECTION_SIZE; ++los_num_sections; goto retry; @@ -318,9 +318,9 @@ sgen_los_free_object (LOSObject *obj) #ifndef LOS_DUMMY mword size = sgen_los_object_size (obj); SGEN_LOG (4, "Freed large object %p, size %lu", obj->data, (unsigned long)size); - binary_protocol_empty (obj->data, size); + sgen_binary_protocol_empty (obj->data, size); - los_memory_usage -= size; + sgen_los_memory_usage -= size; los_num_objects--; #ifdef USE_MALLOC @@ -331,7 +331,7 @@ sgen_los_free_object (LOSObject *obj) size += sizeof (LOSObject); size = SGEN_ALIGN_UP_TO (size, pagesize); sgen_free_os_memory ((gpointer)SGEN_ALIGN_DOWN_TO ((mword)obj, pagesize), size, SGEN_ALLOC_HEAP, MONO_MEM_ACCOUNT_SGEN_LOS); - los_memory_usage_total -= size; + sgen_los_memory_usage_total -= size; sgen_memgov_release_space (size, SPACE_LOS); } else { free_los_section_memory (obj, size + sizeof (LOSObject)); @@ -390,7 +390,7 @@ sgen_los_alloc_large_inner (GCVTable vtable, size_t size) if (sgen_memgov_try_alloc_space (alloc_size, SPACE_LOS)) { obj = (LOSObject *)sgen_alloc_os_memory (alloc_size, (SgenAllocFlags)(SGEN_ALLOC_HEAP | SGEN_ALLOC_ACTIVATE), NULL, MONO_MEM_ACCOUNT_SGEN_LOS); if (obj) { - los_memory_usage_total += alloc_size; + sgen_los_memory_usage_total += alloc_size; obj = randomize_los_object_start (obj, obj_size, alloc_size, pagesize); } } @@ -408,17 +408,17 @@ sgen_los_alloc_large_inner (GCVTable vtable, size_t size) vtslot = (void**)obj->data; *vtslot = vtable; sgen_update_heap_boundaries ((mword)obj->data, (mword)obj->data + size); - obj->next = los_object_list; + obj->next = sgen_los_object_list; /* * We need a memory barrier so we don't expose as head of the los object list * a LOSObject that doesn't have its fields initialized. */ mono_memory_write_barrier (); - los_object_list = obj; - los_memory_usage += size; + sgen_los_object_list = obj; + sgen_los_memory_usage += size; los_num_objects++; SGEN_LOG (4, "Allocated large object %p, vtable: %p (%s), size: %zd", obj->data, vtable, sgen_client_vtable_get_name (vtable), size); - binary_protocol_alloc (obj->data, vtable, size, sgen_client_get_provenance ()); + sgen_binary_protocol_alloc (obj->data, vtable, size, sgen_client_get_provenance ()); #ifdef LOS_CONSISTENCY_CHECK los_consistency_check (); @@ -439,7 +439,7 @@ sgen_los_sweep (void) /* sweep the big objects list */ prevbo = NULL; - for (bigobj = los_object_list; bigobj;) { + for (bigobj = sgen_los_object_list; bigobj;) { SGEN_ASSERT (0, !SGEN_OBJECT_IS_PINNED (bigobj->data), "Who pinned a LOS object?"); if (sgen_los_object_is_pinned (bigobj->data)) { @@ -457,7 +457,7 @@ sgen_los_sweep (void) if (prevbo) prevbo->next = bigobj->next; else - los_object_list = bigobj->next; + sgen_los_object_list = bigobj->next; to_free = bigobj; bigobj = bigobj->next; sgen_los_free_object (to_free); @@ -484,7 +484,7 @@ sgen_los_sweep (void) sgen_memgov_release_space (LOS_SECTION_SIZE, SPACE_LOS); section = next; --los_num_sections; - los_memory_usage_total -= LOS_SECTION_SIZE; + sgen_los_memory_usage_total -= LOS_SECTION_SIZE; continue; } @@ -509,7 +509,7 @@ sgen_los_sweep (void) #endif /* - g_print ("LOS sections: %d objects: %d usage: %d\n", num_sections, los_num_objects, los_memory_usage); + g_print ("LOS sections: %d objects: %d usage: %d\n", num_sections, los_num_objects, sgen_los_memory_usage); for (i = 0; i < LOS_NUM_FAST_SIZES; ++i) { int num_chunks = 0; LOSFreeChunks *free_chunks; @@ -529,7 +529,7 @@ sgen_ptr_is_in_los (char *ptr, char **start) if (start) *start = NULL; - for (obj = los_object_list; obj; obj = obj->next) { + for (obj = sgen_los_object_list; obj; obj = obj->next) { char *end = (char*)obj->data + sgen_los_object_size (obj); if (ptr >= (char*)obj->data && ptr < end) { @@ -546,7 +546,7 @@ sgen_los_iterate_objects (IterateObjectCallbackFunc cb, void *user_data) { LOSObject *obj; - for (obj = los_object_list; obj; obj = obj->next) + for (obj = sgen_los_object_list; obj; obj = obj->next) cb (obj->data, sgen_los_object_size (obj), user_data); } @@ -555,7 +555,7 @@ sgen_los_is_valid_object (char *object) { LOSObject *obj; - for (obj = los_object_list; obj; obj = obj->next) { + for (obj = sgen_los_object_list; obj; obj = obj->next) { if ((char*)obj->data == object) return TRUE; } @@ -567,7 +567,7 @@ mono_sgen_los_describe_pointer (char *ptr) { LOSObject *obj; - for (obj = los_object_list; obj; obj = obj->next) { + for (obj = sgen_los_object_list; obj; obj = obj->next) { const char *los_kind; mword size; gboolean pinned; @@ -599,7 +599,7 @@ void sgen_los_iterate_live_block_ranges (sgen_cardtable_block_callback callback) { LOSObject *obj; - for (obj = los_object_list; obj; obj = obj->next) { + for (obj = sgen_los_object_list; obj; obj = obj->next) { GCVTable vt = SGEN_LOAD_VTABLE (obj->data); if (SGEN_VTABLE_HAS_REFERENCES (vt)) callback ((mword)obj->data, sgen_los_object_size (obj)); @@ -630,8 +630,8 @@ sgen_los_scan_card_table (CardTableScanType scan_type, ScanCopyContext ctx, int LOSObject *obj; int i = 0; - binary_protocol_los_card_table_scan_start (sgen_timestamp (), scan_type & CARDTABLE_SCAN_MOD_UNION); - for (obj = los_object_list; obj; obj = obj->next, i++) { + sgen_binary_protocol_los_card_table_scan_start (sgen_timestamp (), scan_type & CARDTABLE_SCAN_MOD_UNION); + for (obj = sgen_los_object_list; obj; obj = obj->next, i++) { mword num_cards = 0; guint8 *cards; @@ -669,7 +669,7 @@ sgen_los_scan_card_table (CardTableScanType scan_type, ScanCopyContext ctx, int if (scan_type == CARDTABLE_SCAN_MOD_UNION_PRECLEAN) sgen_free_internal_dynamic (cards, num_cards, INTERNAL_MEM_CARDTABLE_MOD_UNION); } - binary_protocol_los_card_table_scan_end (sgen_timestamp (), scan_type & CARDTABLE_SCAN_MOD_UNION); + sgen_binary_protocol_los_card_table_scan_end (sgen_timestamp (), scan_type & CARDTABLE_SCAN_MOD_UNION); } void @@ -679,7 +679,7 @@ sgen_los_count_cards (long long *num_total_cards, long long *num_marked_cards) long long total_cards = 0; long long marked_cards = 0; - for (obj = los_object_list; obj; obj = obj->next) { + for (obj = sgen_los_object_list; obj; obj = obj->next) { int i; guint8 *cards = sgen_card_table_get_card_scan_address ((mword) obj->data); guint8 *cards_end = sgen_card_table_get_card_scan_address ((mword) obj->data + sgen_los_object_size (obj) - 1); @@ -704,7 +704,7 @@ sgen_los_update_cardtable_mod_union (void) { LOSObject *obj; - for (obj = los_object_list; obj; obj = obj->next) { + for (obj = sgen_los_object_list; obj; obj = obj->next) { if (!SGEN_OBJECT_HAS_REFERENCES (obj->data)) continue; sgen_card_table_update_mod_union (get_cardtable_mod_union_for_object (obj), @@ -727,7 +727,7 @@ sgen_los_pin_object (GCObject *data) { LOSObject *obj = sgen_los_header_for_object (data); obj->size = obj->size | 1; - binary_protocol_pin (data, (gpointer)SGEN_LOAD_VTABLE (data), sgen_safe_object_get_size (data)); + sgen_binary_protocol_pin (data, (gpointer)SGEN_LOAD_VTABLE (data), sgen_safe_object_get_size (data)); } gboolean @@ -744,7 +744,7 @@ sgen_los_pin_object_par (GCObject *data) #endif if (old_size & 1) return FALSE; - binary_protocol_pin (data, (gpointer)SGEN_LOAD_VTABLE (data), sgen_safe_object_get_size (data)); + sgen_binary_protocol_pin (data, (gpointer)SGEN_LOAD_VTABLE (data), sgen_safe_object_get_size (data)); return TRUE; } diff --git a/mono/sgen/sgen-marksweep-drain-gray-stack.h b/mono/sgen/sgen-marksweep-drain-gray-stack.h index 4a76eb4603..856df09695 100644 --- a/mono/sgen/sgen-marksweep-drain-gray-stack.h +++ b/mono/sgen/sgen-marksweep-drain-gray-stack.h @@ -42,7 +42,7 @@ COPY_OR_MARK_FUNCTION_NAME (GCObject **ptr, GCObject *obj, SgenGrayQueue *queue) SGEN_ASSERT (9, obj, "null object from pointer %p", ptr); #if !defined(COPY_OR_MARK_CONCURRENT) && !defined(COPY_OR_MARK_CONCURRENT_WITH_EVACUATION) - SGEN_ASSERT (9, current_collection_generation == GENERATION_OLD, "old gen parallel allocator called from a %d collection", current_collection_generation); + SGEN_ASSERT (9, sgen_current_collection_generation == GENERATION_OLD, "old gen parallel allocator called from a %d collection", sgen_current_collection_generation); #endif if (sgen_ptr_in_nursery (obj)) { @@ -127,7 +127,7 @@ COPY_OR_MARK_FUNCTION_NAME (GCObject **ptr, GCObject *obj, SgenGrayQueue *queue) MS_SET_MARK_BIT (block, word, bit); #endif if (first) - binary_protocol_mark (obj, (gpointer)SGEN_LOAD_VTABLE (obj), sgen_safe_object_get_size (obj)); + sgen_binary_protocol_mark (obj, (gpointer)SGEN_LOAD_VTABLE (obj), sgen_safe_object_get_size (obj)); return FALSE; #endif @@ -202,7 +202,7 @@ COPY_OR_MARK_FUNCTION_NAME (GCObject **ptr, GCObject *obj, SgenGrayQueue *queue) #endif if (first) { - binary_protocol_pin (obj, (gpointer)SGEN_LOAD_VTABLE (obj), sgen_safe_object_get_size (obj)); + sgen_binary_protocol_pin (obj, (gpointer)SGEN_LOAD_VTABLE (obj), sgen_safe_object_get_size (obj)); if (SGEN_OBJECT_HAS_REFERENCES (obj)) #ifdef COPY_OR_MARK_PARALLEL GRAY_OBJECT_ENQUEUE_PARALLEL (queue, obj, desc); @@ -238,7 +238,7 @@ SCAN_OBJECT_FUNCTION_NAME (GCObject *full_object, SgenDescriptor desc, SgenGrayQ #if defined(COPY_OR_MARK_CONCURRENT_WITH_EVACUATION) #define HANDLE_PTR(ptr,obj) do { \ GCObject *__old = *(ptr); \ - binary_protocol_scan_process_reference ((full_object), (ptr), __old); \ + sgen_binary_protocol_scan_process_reference ((full_object), (ptr), __old); \ if (__old && !sgen_ptr_in_nursery (__old)) { \ if (G_UNLIKELY (full_object && !sgen_ptr_in_nursery (ptr) && \ sgen_safe_object_is_small (__old, sgen_obj_get_descriptor (__old) & DESC_TYPE_MASK) && \ @@ -256,7 +256,7 @@ SCAN_OBJECT_FUNCTION_NAME (GCObject *full_object, SgenDescriptor desc, SgenGrayQ #elif defined(COPY_OR_MARK_CONCURRENT) #define HANDLE_PTR(ptr,obj) do { \ GCObject *__old = *(ptr); \ - binary_protocol_scan_process_reference ((full_object), (ptr), __old); \ + sgen_binary_protocol_scan_process_reference ((full_object), (ptr), __old); \ if (__old && !sgen_ptr_in_nursery (__old)) { \ PREFETCH_READ (__old); \ COPY_OR_MARK_FUNCTION_NAME ((ptr), __old, queue); \ @@ -268,7 +268,7 @@ SCAN_OBJECT_FUNCTION_NAME (GCObject *full_object, SgenDescriptor desc, SgenGrayQ #else #define HANDLE_PTR(ptr,obj) do { \ GCObject *__old = *(ptr); \ - binary_protocol_scan_process_reference ((full_object), (ptr), __old); \ + sgen_binary_protocol_scan_process_reference ((full_object), (ptr), __old); \ if (__old) { \ gboolean __still_in_nursery = COPY_OR_MARK_FUNCTION_NAME ((ptr), __old, queue); \ if (G_UNLIKELY (__still_in_nursery && !sgen_ptr_in_nursery ((ptr)) && !SGEN_OBJECT_IS_CEMENTED (*(ptr)))) { \ diff --git a/mono/sgen/sgen-marksweep.c b/mono/sgen/sgen-marksweep.c index 2624aa7f51..0bbe570218 100644 --- a/mono/sgen/sgen-marksweep.c +++ b/mono/sgen/sgen-marksweep.c @@ -199,7 +199,7 @@ static volatile int sweep_state = SWEEP_STATE_SWEPT; static gboolean concurrent_mark; static gboolean concurrent_sweep = DEFAULT_SWEEP_MODE; -int sweep_pool_context = -1; +static int sweep_pool_context = -1; #define BLOCK_IS_TAGGED_HAS_REFERENCES(bl) SGEN_POINTER_IS_TAGGED_1 ((bl)) #define BLOCK_TAG_HAS_REFERENCES(bl) SGEN_POINTER_TAG_1 ((bl)) @@ -295,7 +295,7 @@ static SgenPointerQueue scanned_objects_list; static void add_scanned_object (void *ptr) { - if (!binary_protocol_is_enabled ()) + if (!sgen_binary_protocol_is_enabled ()) return; mono_os_mutex_lock (&scanned_objects_list_lock); @@ -434,7 +434,7 @@ ms_free_block (MSBlockInfo *info) SGEN_ATOMIC_ADD_P (num_empty_blocks, 1); - binary_protocol_block_free (block, ms_block_size); + sgen_binary_protocol_block_free (block, ms_block_size); } static gboolean @@ -511,7 +511,7 @@ consistency_check (void) g_assert (num_free == 0); /* check all mark words are zero */ - if (!sgen_concurrent_collection_in_progress () && block_is_swept_or_marking (block)) { + if (!sgen_get_concurrent_collection_in_progress () && block_is_swept_or_marking (block)) { for (i = 0; i < MS_NUM_MARK_WORDS; ++i) g_assert (block->mark_words [i] == 0); } @@ -568,14 +568,14 @@ ms_alloc_block (int size_index, gboolean pinned, gboolean has_references) * want further evacuation. We also don't want to evacuate objects allocated during * the concurrent mark since it would add pointless stress on the finishing pause. */ - info->is_to_space = (sgen_get_current_collection_generation () == GENERATION_OLD) || sgen_concurrent_collection_in_progress (); + info->is_to_space = (sgen_get_current_collection_generation () == GENERATION_OLD) || sgen_get_concurrent_collection_in_progress (); info->state = info->is_to_space ? BLOCK_STATE_MARKING : BLOCK_STATE_SWEPT; SGEN_ASSERT (6, !sweep_in_progress () || info->state == BLOCK_STATE_SWEPT, "How do we add a new block to be swept while sweeping?"); info->cardtable_mod_union = NULL; update_heap_boundaries_for_block (info); - binary_protocol_block_alloc (info, ms_block_size); + sgen_binary_protocol_block_alloc (info, ms_block_size); /* build free list */ obj_start = MS_BLOCK_FOR_BLOCK_INFO (info) + MS_BLOCK_SKIP; @@ -708,7 +708,7 @@ alloc_obj (GCVTable vtable, size_t size, gboolean pinned, gboolean has_reference /* FIXME: assumes object layout */ *(GCVTable*)obj = vtable; - total_allocated_major += block_obj_sizes [size_index]; + sgen_total_allocated_major += block_obj_sizes [size_index]; return (GCObject *)obj; } @@ -763,7 +763,7 @@ get_block: *(GCVTable*)obj = vtable; /* FIXME is it worth CAS-ing here */ - total_allocated_major += block_obj_sizes [size_index]; + sgen_total_allocated_major += block_obj_sizes [size_index]; return (GCObject *)obj; } @@ -1150,7 +1150,7 @@ mark_mod_union_card (GCObject *obj, void **ptr, GCObject *value_obj) } else { sgen_los_mark_mod_union_card (obj, ptr); } - binary_protocol_mod_union_remset (obj, ptr, value_obj, SGEN_LOAD_VTABLE (value_obj)); + sgen_binary_protocol_mod_union_remset (obj, ptr, value_obj, SGEN_LOAD_VTABLE (value_obj)); } static inline gboolean @@ -1171,7 +1171,7 @@ major_block_is_evacuating (MSBlockInfo *block) MS_SET_MARK_BIT ((block), __word, __bit); \ if (sgen_gc_descr_has_references (desc)) \ GRAY_OBJECT_ENQUEUE_SERIAL ((queue), (obj), (desc)); \ - binary_protocol_mark ((obj), (gpointer)SGEN_LOAD_VTABLE ((obj)), sgen_safe_object_get_size ((obj))); \ + sgen_binary_protocol_mark ((obj), (gpointer)SGEN_LOAD_VTABLE ((obj)), sgen_safe_object_get_size ((obj))); \ INC_NUM_MAJOR_OBJECTS_MARKED (); \ } \ } while (0) @@ -1184,7 +1184,7 @@ major_block_is_evacuating (MSBlockInfo *block) if (first) { \ if (sgen_gc_descr_has_references (desc)) \ GRAY_OBJECT_ENQUEUE_PARALLEL ((queue), (obj), (desc)); \ - binary_protocol_mark ((obj), (gpointer)SGEN_LOAD_VTABLE ((obj)), sgen_safe_object_get_size ((obj))); \ + sgen_binary_protocol_mark ((obj), (gpointer)SGEN_LOAD_VTABLE ((obj)), sgen_safe_object_get_size ((obj))); \ INC_NUM_MAJOR_OBJECTS_MARKED (); \ } \ } while (0) @@ -1443,7 +1443,7 @@ sweep_block_for_size (MSBlockInfo *block, int count, int obj_size) * overhead. Maybe memset * will also benefit? */ - binary_protocol_empty (obj, obj_size); + sgen_binary_protocol_empty (obj, obj_size); memset (obj, 0, obj_size); } *(void**)obj = block->free_list; @@ -1458,7 +1458,7 @@ try_set_block_state (MSBlockInfo *block, gint32 new_state, gint32 expected_state gint32 old_state = SGEN_CAS (&block->state, new_state, expected_state); gboolean success = old_state == expected_state; if (success) - binary_protocol_block_set_state (block, ms_block_size, old_state, new_state); + sgen_binary_protocol_block_set_state (block, ms_block_size, old_state, new_state); return success; } @@ -1467,7 +1467,7 @@ set_block_state (MSBlockInfo *block, gint32 new_state, gint32 expected_state) { SGEN_ASSERT (6, block->state == expected_state, "Block state incorrect before set"); block->state = new_state; - binary_protocol_block_set_state (block, ms_block_size, expected_state, new_state); + sgen_binary_protocol_block_set_state (block, ms_block_size, expected_state, new_state); } /* @@ -1757,7 +1757,7 @@ ensure_block_is_checked_for_sweeping (guint32 block_index, gboolean wait, gboole SGEN_ASSERT (6, block_index < allocated_blocks.next_slot, "How did the number of blocks shrink?"); SGEN_ASSERT (6, *block_slot == BLOCK_TAG_CHECKING (tagged_block), "How did the block move?"); - binary_protocol_empty (MS_BLOCK_OBJ (block, 0), (char*)MS_BLOCK_OBJ (block, count) - (char*)MS_BLOCK_OBJ (block, 0)); + sgen_binary_protocol_empty (MS_BLOCK_OBJ (block, 0), (char*)MS_BLOCK_OBJ (block, count) - (char*)MS_BLOCK_OBJ (block, 0)); ms_free_block (block); SGEN_ATOMIC_ADD_P (num_major_sections, -1); @@ -1868,7 +1868,7 @@ sweep_finish (void) set_sweep_state (SWEEP_STATE_SWEPT, SWEEP_STATE_COMPACTING); if (concurrent_sweep) - binary_protocol_concurrent_sweep_end (sgen_timestamp ()); + sgen_binary_protocol_concurrent_sweep_end (sgen_timestamp ()); } static void @@ -1995,7 +1995,7 @@ major_start_nursery_collection (void) old_num_major_sections = num_major_sections; /* Compact the block list if it hasn't been compacted in a while and nobody is using it */ - if (compact_blocks && !sweep_in_progress () && !sweep_blocks_job && !sgen_concurrent_collection_in_progress ()) { + if (compact_blocks && !sweep_in_progress () && !sweep_blocks_job && !sgen_get_concurrent_collection_in_progress ()) { /* * We support null elements in the array but do regular compaction to avoid * excessive traversal of the array and to facilitate splitting into well @@ -2092,7 +2092,7 @@ major_start_major_collection (void) if (!evacuate_block_obj_sizes [i]) continue; - binary_protocol_evacuating_blocks (block_obj_sizes [i]); + sgen_binary_protocol_evacuating_blocks (block_obj_sizes [i]); sgen_evacuation_freelist_blocks (&free_block_lists [0][i], i); sgen_evacuation_freelist_blocks (&free_block_lists [MS_BLOCK_FLAG_REFS][i], i); @@ -2114,7 +2114,7 @@ major_start_major_collection (void) } if (lazy_sweep && !concurrent_sweep) - binary_protocol_sweep_begin (GENERATION_OLD, TRUE); + sgen_binary_protocol_sweep_begin (GENERATION_OLD, TRUE); /* Sweep all unswept blocks and set them to MARKING */ FOREACH_BLOCK_NO_LOCK (block) { if (lazy_sweep && !concurrent_sweep) @@ -2130,7 +2130,7 @@ major_start_major_collection (void) block->is_to_space = TRUE; } END_FOREACH_BLOCK_NO_LOCK; if (lazy_sweep && !concurrent_sweep) - binary_protocol_sweep_end (GENERATION_OLD, TRUE); + sgen_binary_protocol_sweep_end (GENERATION_OLD, TRUE); set_sweep_state (SWEEP_STATE_NEED_SWEEPING, SWEEP_STATE_SWEPT); } @@ -2139,7 +2139,7 @@ static void major_finish_major_collection (ScannedObjectCounts *counts) { #ifdef SGEN_HEAVY_BINARY_PROTOCOL - if (binary_protocol_is_enabled ()) { + if (sgen_binary_protocol_is_enabled ()) { counts->num_scanned_objects = scanned_objects_list.next_slot; sgen_pointer_queue_sort_uniq (&scanned_objects_list); @@ -2595,7 +2595,7 @@ scan_card_table_for_block (MSBlockInfo *block, CardTableScanType scan_type, Scan obj = first_obj = (char*)MS_BLOCK_OBJ_FAST (block_start, block_obj_size, first_object_index); - binary_protocol_card_scan (first_obj, end - first_obj); + sgen_binary_protocol_card_scan (first_obj, end - first_obj); while (obj < end) { if (obj < scan_front || !MS_OBJ_ALLOCED_FAST (obj, block_start)) @@ -2660,7 +2660,7 @@ major_scan_card_table (CardTableScanType scan_type, ScanCopyContext ctx, int job SGEN_ASSERT (0, !sweep_in_progress (), "Sweep should be finished when we scan mod union card table"); was_sweeping = sweep_in_progress (); - binary_protocol_major_card_table_scan_start (sgen_timestamp (), scan_type & CARDTABLE_SCAN_MOD_UNION); + sgen_binary_protocol_major_card_table_scan_start (sgen_timestamp (), scan_type & CARDTABLE_SCAN_MOD_UNION); FOREACH_BLOCK_RANGE_HAS_REFERENCES_NO_LOCK (block, first_block, last_block, index, has_references) { #ifdef PREFETCH_CARDS int prefetch_index = index + 6; @@ -2707,7 +2707,7 @@ major_scan_card_table (CardTableScanType scan_type, ScanCopyContext ctx, int job if (!skip_scan) scan_card_table_for_block (block, scan_type, ctx); } END_FOREACH_BLOCK_RANGE_NO_LOCK; - binary_protocol_major_card_table_scan_end (sgen_timestamp (), scan_type & CARDTABLE_SCAN_MOD_UNION); + sgen_binary_protocol_major_card_table_scan_end (sgen_timestamp (), scan_type & CARDTABLE_SCAN_MOD_UNION); } static void @@ -2811,6 +2811,11 @@ sgen_marksweep_init_internal (SgenMajorCollector *collector, gboolean is_concurr { int i; +#ifdef DISABLE_SGEN_MAJOR_MARKSWEEP_CONC + g_assert (is_concurrent == FALSE); + g_assert (is_parallel == FALSE); +#endif + ms_block_size = mono_pagesize (); if (ms_block_size < MS_BLOCK_SIZE_MIN) @@ -2885,10 +2890,12 @@ sgen_marksweep_init_internal (SgenMajorCollector *collector, gboolean is_concurr collector->scan_card_table = major_scan_card_table; collector->iterate_live_block_ranges = major_iterate_live_block_ranges; collector->iterate_block_ranges = major_iterate_block_ranges; +#ifndef DISABLE_SGEN_MAJOR_MARKSWEEP_CONC if (is_concurrent) { collector->update_cardtable_mod_union = update_cardtable_mod_union; collector->get_cardtable_mod_union_for_reference = major_get_cardtable_mod_union_for_reference; } +#endif collector->init_to_space = major_init_to_space; collector->sweep = major_sweep; collector->have_swept = major_have_swept; @@ -2918,6 +2925,7 @@ sgen_marksweep_init_internal (SgenMajorCollector *collector, gboolean is_concurr collector->major_ops_serial.scan_object = major_scan_object_with_evacuation; collector->major_ops_serial.scan_ptr_field = major_scan_ptr_field_with_evacuation; collector->major_ops_serial.drain_gray_stack = drain_gray_stack; +#ifndef DISABLE_SGEN_MAJOR_MARKSWEEP_CONC if (is_concurrent) { collector->major_ops_concurrent_start.copy_or_mark_object = major_copy_or_mark_object_concurrent_canonical; collector->major_ops_concurrent_start.scan_object = major_scan_object_concurrent_with_evacuation; @@ -2945,6 +2953,7 @@ sgen_marksweep_init_internal (SgenMajorCollector *collector, gboolean is_concurr collector->major_ops_conc_par_finish.drain_gray_stack = drain_gray_stack_par; } } +#endif #ifdef HEAVY_STATISTICS mono_counters_register ("Optimized copy", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_optimized_copy); @@ -2973,6 +2982,7 @@ sgen_marksweep_init_internal (SgenMajorCollector *collector, gboolean is_concurr /*cardtable requires major pages to be 8 cards aligned*/ g_assert ((ms_block_size % (8 * CARD_SIZE_IN_BYTES)) == 0); +#ifndef DISABLE_SGEN_MAJOR_MARKSWEEP_CONC if (is_concurrent && is_parallel) sgen_workers_create_context (GENERATION_OLD, mono_cpu_count ()); else if (is_concurrent) @@ -2980,6 +2990,7 @@ sgen_marksweep_init_internal (SgenMajorCollector *collector, gboolean is_concurr if (concurrent_sweep) sweep_pool_context = sgen_thread_pool_create_context (1, NULL, NULL, NULL, NULL, NULL); +#endif } void @@ -2988,6 +2999,7 @@ sgen_marksweep_init (SgenMajorCollector *collector) sgen_marksweep_init_internal (collector, FALSE, FALSE); } +#ifndef DISABLE_SGEN_MAJOR_MARKSWEEP_CONC void sgen_marksweep_conc_init (SgenMajorCollector *collector) { @@ -2999,5 +3011,7 @@ sgen_marksweep_conc_par_init (SgenMajorCollector *collector) { sgen_marksweep_init_internal (collector, TRUE, TRUE); } +#endif + #endif diff --git a/mono/sgen/sgen-memory-governor.c b/mono/sgen/sgen-memory-governor.c index ab9b254e6c..fad08626a0 100644 --- a/mono/sgen/sgen-memory-governor.c +++ b/mono/sgen/sgen-memory-governor.c @@ -34,8 +34,8 @@ static SgenPointerQueue log_entries = SGEN_POINTER_QUEUE_INIT (INTERNAL_MEM_TEMPORARY); static mono_mutex_t log_entries_mutex; -mword total_promoted_size = 0; -mword total_allocated_major = 0; +mword sgen_total_promoted_size = 0; +mword sgen_total_allocated_major = 0; static mword total_promoted_size_start; static mword total_allocated_major_end; @@ -85,9 +85,9 @@ sgen_memgov_calculate_minor_collection_allowance (void) if (!need_calculate_minor_collection_allowance) return; - SGEN_ASSERT (0, major_collector.have_swept (), "Can only calculate allowance if heap is swept"); + SGEN_ASSERT (0, sgen_major_collector.have_swept (), "Can only calculate allowance if heap is swept"); - new_major = major_collector.get_bytes_survived_last_sweep (); + new_major = sgen_major_collector.get_bytes_survived_last_sweep (); new_heap_size = new_major + last_collection_los_memory_usage; /* @@ -116,8 +116,8 @@ sgen_memgov_calculate_minor_collection_allowance (void) } /* FIXME: Why is this here? */ - if (major_collector.free_swept_blocks) - major_collector.free_swept_blocks (major_collector.get_num_major_sections () * SGEN_DEFAULT_ALLOWANCE_HEAP_SIZE_RATIO); + if (sgen_major_collector.free_swept_blocks) + sgen_major_collector.free_swept_blocks (sgen_major_collector.get_num_major_sections () * SGEN_DEFAULT_ALLOWANCE_HEAP_SIZE_RATIO); major_collection_trigger_size = new_heap_size + allowance; @@ -133,7 +133,7 @@ sgen_memgov_calculate_minor_collection_allowance (void) static inline size_t get_heap_size (void) { - return major_collector.get_num_major_sections () * major_collector.section_size + los_memory_usage; + return sgen_major_collector.get_num_major_sections () * sgen_major_collector.section_size + sgen_los_memory_usage; } gboolean @@ -141,7 +141,7 @@ sgen_need_major_collection (mword space_needed) { size_t heap_size; - if (sgen_concurrent_collection_in_progress ()) { + if (sgen_get_concurrent_collection_in_progress ()) { heap_size = get_heap_size (); if (heap_size <= major_collection_trigger_size) @@ -159,7 +159,7 @@ sgen_need_major_collection (mword space_needed) } /* FIXME: This is a cop-out. We should have some way of figuring this out. */ - if (!major_collector.have_swept ()) + if (!sgen_major_collector.have_swept ()) return FALSE; if (space_needed > sgen_memgov_available_free_space ()) @@ -175,7 +175,7 @@ sgen_need_major_collection (mword space_needed) void sgen_memgov_minor_collection_start (void) { - total_promoted_size_start = total_promoted_size; + total_promoted_size_start = sgen_total_promoted_size; SGEN_TV_GETTIME (last_minor_start); } @@ -199,11 +199,11 @@ sgen_memgov_minor_collection_end (const char *reason, gboolean is_overflow) log_entry->reason = reason; log_entry->is_overflow = is_overflow; log_entry->time = SGEN_TV_ELAPSED (last_minor_start, current_time); - log_entry->promoted_size = total_promoted_size - total_promoted_size_start; - log_entry->major_size = major_collector.get_num_major_sections () * major_collector.section_size; - log_entry->major_size_in_use = last_used_slots_size + total_allocated_major - total_allocated_major_end; - log_entry->los_size = los_memory_usage_total; - log_entry->los_size_in_use = los_memory_usage; + log_entry->promoted_size = sgen_total_promoted_size - total_promoted_size_start; + log_entry->major_size = sgen_major_collector.get_num_major_sections () * sgen_major_collector.section_size; + log_entry->major_size_in_use = last_used_slots_size + sgen_total_allocated_major - total_allocated_major_end; + log_entry->los_size = sgen_los_memory_usage_total; + log_entry->los_size_in_use = sgen_los_memory_usage; sgen_add_log_entry (log_entry); } @@ -212,7 +212,7 @@ sgen_memgov_minor_collection_end (const char *reason, gboolean is_overflow) void sgen_memgov_major_pre_sweep (void) { - if (sgen_concurrent_collection_in_progress ()) { + if (sgen_get_concurrent_collection_in_progress ()) { major_pre_sweep_heap_size = get_heap_size (); } else { /* We decrease the allowance only in the concurrent case */ @@ -227,8 +227,8 @@ sgen_memgov_major_post_sweep (mword used_slots_size) SgenLogEntry *log_entry = (SgenLogEntry*)sgen_alloc_internal (INTERNAL_MEM_LOG_ENTRY); log_entry->type = SGEN_LOG_MAJOR_SWEEP_FINISH; - log_entry->major_size = major_collector.get_num_major_sections () * major_collector.section_size; - log_entry->major_size_in_use = used_slots_size + total_allocated_major - total_allocated_major_end; + log_entry->major_size = sgen_major_collector.get_num_major_sections () * sgen_major_collector.section_size; + log_entry->major_size_in_use = used_slots_size + sgen_total_allocated_major - total_allocated_major_end; sgen_add_log_entry (log_entry); } @@ -271,14 +271,14 @@ sgen_memgov_major_collection_end (gboolean forced, gboolean concurrent, const ch log_entry->time = SGEN_TV_ELAPSED (last_major_start, current_time); log_entry->reason = reason; log_entry->is_overflow = is_overflow; - log_entry->los_size = los_memory_usage_total; - log_entry->los_size_in_use = los_memory_usage; + log_entry->los_size = sgen_los_memory_usage_total; + log_entry->los_size_in_use = sgen_los_memory_usage; sgen_add_log_entry (log_entry); } - last_collection_los_memory_usage = los_memory_usage; - total_allocated_major_end = total_allocated_major; + last_collection_los_memory_usage = sgen_los_memory_usage; + total_allocated_major_end = sgen_total_allocated_major; if (forced) { sgen_get_major_collector ()->finish_sweeping (); sgen_memgov_calculate_minor_collection_allowance (); diff --git a/mono/sgen/sgen-minor-copy-object.h b/mono/sgen/sgen-minor-copy-object.h index b1e07c167a..5597ab41bb 100644 --- a/mono/sgen/sgen-minor-copy-object.h +++ b/mono/sgen/sgen-minor-copy-object.h @@ -80,7 +80,7 @@ SERIAL_COPY_OBJECT (GCObject **obj_slot, SgenGrayQueue *queue) GCObject *copy; GCObject *obj = *obj_slot; - SGEN_ASSERT (9, current_collection_generation == GENERATION_NURSERY, "calling minor-serial-copy from a %d generation collection", current_collection_generation); + SGEN_ASSERT (9, sgen_current_collection_generation == GENERATION_NURSERY, "calling minor-serial-copy from a %d generation collection", sgen_current_collection_generation); HEAVY_STAT (++stat_copy_object_called_nursery); @@ -142,7 +142,7 @@ SERIAL_COPY_OBJECT_FROM_OBJ (GCObject **obj_slot, SgenGrayQueue *queue) GCObject *obj = *obj_slot; GCObject *copy; - SGEN_ASSERT (9, current_collection_generation == GENERATION_NURSERY, "calling minor-serial-copy-from-obj from a %d generation collection", current_collection_generation); + SGEN_ASSERT (9, sgen_current_collection_generation == GENERATION_NURSERY, "calling minor-serial-copy-from-obj from a %d generation collection", sgen_current_collection_generation); HEAVY_STAT (++stat_copy_object_called_nursery); diff --git a/mono/sgen/sgen-minor-scan-object.h b/mono/sgen/sgen-minor-scan-object.h index f0baac8f87..dcde27acf8 100644 --- a/mono/sgen/sgen-minor-scan-object.h +++ b/mono/sgen/sgen-minor-scan-object.h @@ -67,7 +67,7 @@ extern guint64 stat_scan_object_called_nursery; #define HANDLE_PTR(ptr,obj) do { \ void *__old = *(ptr); \ SGEN_OBJECT_LAYOUT_STATISTICS_MARK_BITMAP ((obj), (ptr)); \ - binary_protocol_scan_process_reference ((full_object), (ptr), __old); \ + sgen_binary_protocol_scan_process_reference ((full_object), (ptr), __old); \ if (__old) { \ SERIAL_COPY_OBJECT_FROM_OBJ ((ptr), queue); \ SGEN_COND_LOG (9, __old != *(ptr), "Overwrote field at %p with %p (was: %p)", (ptr), *(ptr), __old); \ diff --git a/mono/sgen/sgen-nursery-allocator.c b/mono/sgen/sgen-nursery-allocator.c index 60f0156f9b..af4bcfd90a 100644 --- a/mono/sgen/sgen-nursery-allocator.c +++ b/mono/sgen/sgen-nursery-allocator.c @@ -652,7 +652,7 @@ static void add_nursery_frag (SgenFragmentAllocator *allocator, size_t frag_size, char* frag_start, char* frag_end) { SGEN_LOG (4, "Found empty fragment: %p-%p, size: %zd", frag_start, frag_end, frag_size); - binary_protocol_empty (frag_start, frag_size); + sgen_binary_protocol_empty (frag_start, frag_size); /* Not worth dealing with smaller fragments: need to tune */ if (frag_size >= SGEN_MAX_NURSERY_WASTE) { /* memsetting just the first chunk start is bound to provide better cache locality */ @@ -927,7 +927,7 @@ sgen_resize_nursery (gboolean need_shrink) if (sgen_nursery_min_size == sgen_nursery_max_size) return; - major_size = major_collector.get_num_major_sections () * major_collector.section_size + los_memory_usage; + major_size = sgen_major_collector.get_num_major_sections () * sgen_major_collector.section_size + sgen_los_memory_usage; /* * We attempt to use a larger nursery size, as long as it doesn't * exceed a certain percentage of the major heap. @@ -939,8 +939,8 @@ sgen_resize_nursery (gboolean need_shrink) */ if ((sgen_nursery_size * 2) < (major_size / SGEN_DEFAULT_ALLOWANCE_NURSERY_SIZE_RATIO) && (sgen_nursery_size * 2) <= sgen_nursery_max_size && !need_shrink) { - if ((nursery_section->end_data - nursery_section->data) == sgen_nursery_size) - nursery_section->end_data += sgen_nursery_size; + if ((sgen_nursery_section->end_data - sgen_nursery_section->data) == sgen_nursery_size) + sgen_nursery_section->end_data += sgen_nursery_size; sgen_nursery_size *= 2; } else if ((sgen_nursery_size > (major_size / SGEN_DEFAULT_ALLOWANCE_NURSERY_SIZE_RATIO) || need_shrink) && (sgen_nursery_size / 2) >= sgen_nursery_min_size) { diff --git a/mono/sgen/sgen-pinning-stats.c b/mono/sgen/sgen-pinning-stats.c index f98158077b..448fcca927 100644 --- a/mono/sgen/sgen-pinning-stats.c +++ b/mono/sgen/sgen-pinning-stats.c @@ -168,7 +168,7 @@ sgen_pin_stats_register_object (GCObject *obj, int generation) int pin_types = 0; size_t size = 0; - if (binary_protocol_is_enabled ()) { + if (sgen_binary_protocol_is_enabled ()) { size = sgen_safe_object_get_size (obj); pinned_bytes_in_generation [generation] += size; ++pinned_objects_in_generation [generation]; @@ -209,27 +209,27 @@ sgen_pin_stats_report (void) PinnedClassEntry *pinned_entry; GlobalRemsetClassEntry *remset_entry; - binary_protocol_pin_stats (pinned_objects_in_generation [GENERATION_NURSERY], pinned_bytes_in_generation [GENERATION_NURSERY], + sgen_binary_protocol_pin_stats (pinned_objects_in_generation [GENERATION_NURSERY], pinned_bytes_in_generation [GENERATION_NURSERY], pinned_objects_in_generation [GENERATION_OLD], pinned_bytes_in_generation [GENERATION_OLD]); if (!do_pin_stats) return; - mono_gc_printf (gc_debug_file, "\n%-50s %10s %10s %10s\n", "Class", "Stack", "Static", "Other"); + mono_gc_printf (sgen_gc_debug_file, "\n%-50s %10s %10s %10s\n", "Class", "Stack", "Static", "Other"); SGEN_HASH_TABLE_FOREACH (&pinned_class_hash_table, char *, name, PinnedClassEntry *, pinned_entry) { int i; - mono_gc_printf (gc_debug_file, "%-50s", name); + mono_gc_printf (sgen_gc_debug_file, "%-50s", name); for (i = 0; i < PIN_TYPE_MAX; ++i) - mono_gc_printf (gc_debug_file, " %10ld", pinned_entry->num_pins [i]); - mono_gc_printf (gc_debug_file, "\n"); + mono_gc_printf (sgen_gc_debug_file, " %10ld", pinned_entry->num_pins [i]); + mono_gc_printf (sgen_gc_debug_file, "\n"); } SGEN_HASH_TABLE_FOREACH_END; - mono_gc_printf (gc_debug_file, "\n%-50s %10s\n", "Class", "#Remsets"); + mono_gc_printf (sgen_gc_debug_file, "\n%-50s %10s\n", "Class", "#Remsets"); SGEN_HASH_TABLE_FOREACH (&global_remset_class_hash_table, char *, name, GlobalRemsetClassEntry *, remset_entry) { - mono_gc_printf (gc_debug_file, "%-50s %10ld\n", name, remset_entry->num_remsets); + mono_gc_printf (sgen_gc_debug_file, "%-50s %10ld\n", name, remset_entry->num_remsets); } SGEN_HASH_TABLE_FOREACH_END; - mono_gc_printf (gc_debug_file, "\nTotal bytes pinned from stack: %ld static: %ld other: %ld\n", + mono_gc_printf (sgen_gc_debug_file, "\nTotal bytes pinned from stack: %ld static: %ld other: %ld\n", pinned_byte_counts [PIN_TYPE_STACK], pinned_byte_counts [PIN_TYPE_STATIC_DATA], pinned_byte_counts [PIN_TYPE_OTHER]); diff --git a/mono/sgen/sgen-pinning.c b/mono/sgen/sgen-pinning.c index b23b20b588..c73e7a1f8b 100644 --- a/mono/sgen/sgen-pinning.c +++ b/mono/sgen/sgen-pinning.c @@ -243,7 +243,7 @@ sgen_cement_reset (void) cement_hash [i].count = 0; } } - binary_protocol_cement_reset (); + sgen_binary_protocol_cement_reset (); } @@ -350,7 +350,7 @@ sgen_cement_lookup_or_register (GCObject *obj) SGEN_ASSERT (9, SGEN_OBJECT_IS_PINNED (obj), "Can only cement pinned objects"); SGEN_CEMENT_OBJECT (obj); - binary_protocol_cement (obj, (gpointer)SGEN_LOAD_VTABLE (obj), + sgen_binary_protocol_cement (obj, (gpointer)SGEN_LOAD_VTABLE (obj), (int)sgen_safe_object_get_size (obj)); } @@ -370,7 +370,7 @@ pin_from_hash (CementHashEntry *hash, gboolean has_been_reset) sgen_client_pinned_cemented_object (hash [i].obj); sgen_pin_stage_ptr (hash [i].obj); - binary_protocol_cement_stage (hash [i].obj); + sgen_binary_protocol_cement_stage (hash [i].obj); /* FIXME: do pin stats if enabled */ SGEN_CEMENT_OBJECT (hash [i].obj); diff --git a/mono/sgen/sgen-protocol.c b/mono/sgen/sgen-protocol.c index 7e22ad6546..7184e6aebe 100644 --- a/mono/sgen/sgen-protocol.c +++ b/mono/sgen/sgen-protocol.c @@ -128,7 +128,7 @@ binary_protocol_open_file (gboolean assert_on_failure) } void -binary_protocol_init (const char *filename, long long limit) +sgen_binary_protocol_init (const char *filename, long long limit) { file_size_limit = limit; @@ -148,11 +148,11 @@ binary_protocol_init (const char *filename, long long limit) if (file_size_limit == 0) g_free (filename_or_prefix); - binary_protocol_header (PROTOCOL_HEADER_CHECK, PROTOCOL_HEADER_VERSION, SIZEOF_VOID_P, G_BYTE_ORDER == G_LITTLE_ENDIAN); + sgen_binary_protocol_header (PROTOCOL_HEADER_CHECK, PROTOCOL_HEADER_VERSION, SIZEOF_VOID_P, G_BYTE_ORDER == G_LITTLE_ENDIAN); } gboolean -binary_protocol_is_enabled (void) +sgen_binary_protocol_is_enabled (void) { return binary_protocol_file != invalid_file_value; } @@ -275,7 +275,7 @@ binary_protocol_check_file_overflow (void) * The protocol entries that do flush have `FLUSH()` in their definition. */ gboolean -binary_protocol_flush_buffers (gboolean force) +sgen_binary_protocol_flush_buffers (gboolean force) { int num_buffers = 0, i; BinaryProtocolBuffer *header; @@ -390,48 +390,48 @@ protocol_entry (unsigned char type, gpointer data, int size) #define TYPE_BOOL gboolean #define BEGIN_PROTOCOL_ENTRY0(method) \ - void method (void) { \ + void sgen_ ## method (void) { \ int __type = PROTOCOL_ID(method); \ gpointer __data = NULL; \ int __size = 0; \ CLIENT_PROTOCOL_NAME (method) (); #define BEGIN_PROTOCOL_ENTRY1(method,t1,f1) \ - void method (t1 f1) { \ + void sgen_ ## method (t1 f1) { \ PROTOCOL_STRUCT(method) __entry = { f1 }; \ int __type = PROTOCOL_ID(method); \ gpointer __data = &__entry; \ int __size = sizeof (PROTOCOL_STRUCT(method)); \ CLIENT_PROTOCOL_NAME (method) (f1); #define BEGIN_PROTOCOL_ENTRY2(method,t1,f1,t2,f2) \ - void method (t1 f1, t2 f2) { \ + void sgen_ ## method (t1 f1, t2 f2) { \ PROTOCOL_STRUCT(method) __entry = { f1, f2 }; \ int __type = PROTOCOL_ID(method); \ gpointer __data = &__entry; \ int __size = sizeof (PROTOCOL_STRUCT(method)); \ CLIENT_PROTOCOL_NAME (method) (f1, f2); #define BEGIN_PROTOCOL_ENTRY3(method,t1,f1,t2,f2,t3,f3) \ - void method (t1 f1, t2 f2, t3 f3) { \ + void sgen_ ## method (t1 f1, t2 f2, t3 f3) { \ PROTOCOL_STRUCT(method) __entry = { f1, f2, f3 }; \ int __type = PROTOCOL_ID(method); \ gpointer __data = &__entry; \ int __size = sizeof (PROTOCOL_STRUCT(method)); \ CLIENT_PROTOCOL_NAME (method) (f1, f2, f3); #define BEGIN_PROTOCOL_ENTRY4(method,t1,f1,t2,f2,t3,f3,t4,f4) \ - void method (t1 f1, t2 f2, t3 f3, t4 f4) { \ + void sgen_ ## method (t1 f1, t2 f2, t3 f3, t4 f4) { \ PROTOCOL_STRUCT(method) __entry = { f1, f2, f3, f4 }; \ int __type = PROTOCOL_ID(method); \ gpointer __data = &__entry; \ int __size = sizeof (PROTOCOL_STRUCT(method)); \ CLIENT_PROTOCOL_NAME (method) (f1, f2, f3, f4); #define BEGIN_PROTOCOL_ENTRY5(method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5) \ - void method (t1 f1, t2 f2, t3 f3, t4 f4, t5 f5) { \ + void sgen_ ## method (t1 f1, t2 f2, t3 f3, t4 f4, t5 f5) { \ PROTOCOL_STRUCT(method) __entry = { f1, f2, f3, f4, f5 }; \ int __type = PROTOCOL_ID(method); \ gpointer __data = &__entry; \ int __size = sizeof (PROTOCOL_STRUCT(method)); \ CLIENT_PROTOCOL_NAME (method) (f1, f2, f3, f4, f5); #define BEGIN_PROTOCOL_ENTRY6(method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5,t6,f6) \ - void method (t1 f1, t2 f2, t3 f3, t4 f4, t5 f5, t6 f6) { \ + void sgen_ ## method (t1 f1, t2 f2, t3 f3, t4 f4, t5 f5, t6 f6) { \ PROTOCOL_STRUCT(method) __entry = { f1, f2, f3, f4, f5, f6 }; \ int __type = PROTOCOL_ID(method); \ gpointer __data = &__entry; \ @@ -451,7 +451,7 @@ protocol_entry (unsigned char type, gpointer data, int size) #define END_PROTOCOL_ENTRY_FLUSH \ protocol_entry (__type, __data, __size); \ - binary_protocol_flush_buffers (FALSE); \ + sgen_binary_protocol_flush_buffers (FALSE); \ } #ifdef SGEN_HEAVY_BINARY_PROTOCOL diff --git a/mono/sgen/sgen-protocol.h b/mono/sgen/sgen-protocol.h index 8b82dc3794..a29eb7d3e3 100644 --- a/mono/sgen/sgen-protocol.h +++ b/mono/sgen/sgen-protocol.h @@ -169,28 +169,28 @@ enum { /* missing: finalizers, roots, non-store wbarriers */ -void binary_protocol_init (const char *filename, long long limit); -gboolean binary_protocol_is_enabled (void); +void sgen_binary_protocol_init (const char *filename, long long limit); +gboolean sgen_binary_protocol_is_enabled (void); -gboolean binary_protocol_flush_buffers (gboolean force); +gboolean sgen_binary_protocol_flush_buffers (gboolean force); #define BEGIN_PROTOCOL_ENTRY0(method) \ - void method (void); + void sgen_ ## method (void); #define BEGIN_PROTOCOL_ENTRY1(method,t1,f1) \ - void method (t1 f1); + void sgen_ ## method (t1 f1); #define BEGIN_PROTOCOL_ENTRY2(method,t1,f1,t2,f2) \ - void method (t1 f1, t2 f2); + void sgen_ ## method (t1 f1, t2 f2); #define BEGIN_PROTOCOL_ENTRY3(method,t1,f1,t2,f2,t3,f3) \ - void method (t1 f1, t2 f2, t3 f3); + void sgen_ ## method (t1 f1, t2 f2, t3 f3); #define BEGIN_PROTOCOL_ENTRY4(method,t1,f1,t2,f2,t3,f3,t4,f4) \ - void method (t1 f1, t2 f2, t3 f3, t4 f4); + void sgen_ ## method (t1 f1, t2 f2, t3 f3, t4 f4); #define BEGIN_PROTOCOL_ENTRY5(method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5) \ - void method (t1 f1, t2 f2, t3 f3, t4 f4, t5 f5); + void sgen_ ## method (t1 f1, t2 f2, t3 f3, t4 f4, t5 f5); #define BEGIN_PROTOCOL_ENTRY6(method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5,t6,f6) \ - void method (t1 f1, t2 f2, t3 f3, t4 f4, t5 f5, t6 f6); + void sgen_ ## method (t1 f1, t2 f2, t3 f3, t4 f4, t5 f5, t6 f6); #ifdef SGEN_HEAVY_BINARY_PROTOCOL -#define binary_protocol_is_heavy_enabled() binary_protocol_is_enabled () +#define sgen_binary_protocol_is_heavy_enabled() sgen_binary_protocol_is_enabled () #define BEGIN_PROTOCOL_ENTRY_HEAVY0(method) \ BEGIN_PROTOCOL_ENTRY0 (method) @@ -207,22 +207,22 @@ gboolean binary_protocol_flush_buffers (gboolean force); #define BEGIN_PROTOCOL_ENTRY_HEAVY6(method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5,t6,f6) \ BEGIN_PROTOCOL_ENTRY6 (method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5,t6,f6) #else -#define binary_protocol_is_heavy_enabled() FALSE +#define sgen_binary_protocol_is_heavy_enabled() FALSE #define BEGIN_PROTOCOL_ENTRY_HEAVY0(method) \ - static inline void method (void) {} + static inline void sgen_ ## method (void) {} #define BEGIN_PROTOCOL_ENTRY_HEAVY1(method,t1,f1) \ - static inline void method (t1 f1) {} + static inline void sgen_ ## method (t1 f1) {} #define BEGIN_PROTOCOL_ENTRY_HEAVY2(method,t1,f1,t2,f2) \ - static inline void method (t1 f1, t2 f2) {} + static inline void sgen_ ## method (t1 f1, t2 f2) {} #define BEGIN_PROTOCOL_ENTRY_HEAVY3(method,t1,f1,t2,f2,t3,f3) \ - static inline void method (t1 f1, t2 f2, t3 f3) {} + static inline void sgen_ ## method (t1 f1, t2 f2, t3 f3) {} #define BEGIN_PROTOCOL_ENTRY_HEAVY4(method,t1,f1,t2,f2,t3,f3,t4,f4) \ - static inline void method (t1 f1, t2 f2, t3 f3, t4 f4) {} + static inline void sgen_ ## method (t1 f1, t2 f2, t3 f3, t4 f4) {} #define BEGIN_PROTOCOL_ENTRY_HEAVY5(method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5) \ - static inline void method (t1 f1, t2 f2, t3 f3, t4 f4, t5 f5) {} + static inline void sgen_ ## method (t1 f1, t2 f2, t3 f3, t4 f4, t5 f5) {} #define BEGIN_PROTOCOL_ENTRY_HEAVY6(method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5,t6,f6) \ - static inline void method (t1 f1, t2 f2, t3 f3, t4 f4, t5 f5, t6 f6) {} + static inline void sgen_ ## method (t1 f1, t2 f2, t3 f3, t4 f4, t5 f5, t6 f6) {} #endif #define DEFAULT_PRINT() diff --git a/mono/sgen/sgen-scan-object.h b/mono/sgen/sgen-scan-object.h index d6da307a73..334944f25b 100644 --- a/mono/sgen/sgen-scan-object.h +++ b/mono/sgen/sgen-scan-object.h @@ -36,11 +36,11 @@ { #ifndef SCAN_OBJECT_NOVTABLE #if defined(SGEN_HEAVY_BINARY_PROTOCOL) && defined(SCAN_OBJECT_PROTOCOL) - binary_protocol_scan_begin ((GCObject*)start, SGEN_LOAD_VTABLE ((GCObject*)start), sgen_safe_object_get_size ((GCObject*)start)); + sgen_binary_protocol_scan_begin ((GCObject*)start, SGEN_LOAD_VTABLE ((GCObject*)start), sgen_safe_object_get_size ((GCObject*)start)); #endif #else #if defined(SGEN_HEAVY_BINARY_PROTOCOL) && defined(SCAN_OBJECT_PROTOCOL) - binary_protocol_scan_vtype_begin (start + SGEN_CLIENT_OBJECT_HEADER_SIZE, size); + sgen_binary_protocol_scan_vtype_begin (start + SGEN_CLIENT_OBJECT_HEADER_SIZE, size); #endif #endif switch (desc & DESC_TYPE_MASK) { diff --git a/mono/sgen/sgen-simple-nursery.c b/mono/sgen/sgen-simple-nursery.c index 29ab4ed135..a61560a269 100644 --- a/mono/sgen/sgen-simple-nursery.c +++ b/mono/sgen/sgen-simple-nursery.c @@ -26,8 +26,8 @@ static inline GCObject* alloc_for_promotion (GCVTable vtable, GCObject *obj, size_t objsize, gboolean has_references) { - total_promoted_size += objsize; - return major_collector.alloc_object (vtable, objsize, has_references); + sgen_total_promoted_size += objsize; + return sgen_major_collector.alloc_object (vtable, objsize, has_references); } static inline GCObject* @@ -35,12 +35,12 @@ alloc_for_promotion_par (GCVTable vtable, GCObject *obj, size_t objsize, gboolea { /* * FIXME - * Note that the stat is not precise. total_promoted_size incrementing is not atomic and + * Note that the stat is not precise. sgen_total_promoted_size incrementing is not atomic and * even in that case, the same object might be promoted simultaneously by different workers * leading to one of the allocated major object to be discarded. */ - total_promoted_size += objsize; - return major_collector.alloc_object_par (vtable, objsize, has_references); + sgen_total_promoted_size += objsize; + return sgen_major_collector.alloc_object_par (vtable, objsize, has_references); } static SgenFragment* @@ -104,6 +104,8 @@ fill_serial_ops (SgenObjectOperations *ops) FILL_MINOR_COLLECTOR_SCAN_OBJECT (ops); } +#ifndef DISABLE_SGEN_MAJOR_MARKSWEEP_CONC + #define SGEN_SIMPLE_PAR_NURSERY #include "sgen-minor-copy-object.h" @@ -141,12 +143,18 @@ fill_parallel_with_concurrent_major_ops (SgenObjectOperations *ops) FILL_MINOR_COLLECTOR_SCAN_OBJECT (ops); } +#endif + void sgen_simple_nursery_init (SgenMinorCollector *collector, gboolean parallel) { if (mono_cpu_count () <= 1) parallel = FALSE; +#ifdef DISABLE_SGEN_MAJOR_MARKSWEEP_CONC + g_assert (parallel == FALSE); +#endif + collector->is_split = FALSE; collector->is_parallel = parallel; @@ -161,7 +169,9 @@ sgen_simple_nursery_init (SgenMinorCollector *collector, gboolean parallel) collector->init_nursery = init_nursery; fill_serial_ops (&collector->serial_ops); +#ifndef DISABLE_SGEN_MAJOR_MARKSWEEP_CONC fill_serial_with_concurrent_major_ops (&collector->serial_ops_with_concurrent_major); + fill_parallel_ops (&collector->parallel_ops); fill_parallel_with_concurrent_major_ops (&collector->parallel_ops_with_concurrent_major); @@ -171,6 +181,8 @@ sgen_simple_nursery_init (SgenMinorCollector *collector, gboolean parallel) */ if (parallel) sgen_workers_create_context (GENERATION_NURSERY, mono_cpu_count ()); +#endif + } diff --git a/mono/sgen/sgen-split-nursery.c b/mono/sgen/sgen-split-nursery.c index 38dc0c8c3a..28c7e58981 100644 --- a/mono/sgen/sgen-split-nursery.c +++ b/mono/sgen/sgen-split-nursery.c @@ -16,6 +16,8 @@ #include "config.h" #ifdef HAVE_SGEN_GC +#ifndef DISABLE_SGEN_SPLIT_NURSERY + #include #include @@ -256,8 +258,8 @@ alloc_for_promotion (GCVTable vtable, GCObject *obj, size_t objsize, gboolean ha age = get_object_age (obj); if (age >= promote_age) { - total_promoted_size += objsize; - return major_collector.alloc_object (vtable, objsize, has_references); + sgen_total_promoted_size += objsize; + return sgen_major_collector.alloc_object (vtable, objsize, has_references); } /* Promote! */ @@ -269,8 +271,8 @@ alloc_for_promotion (GCVTable vtable, GCObject *obj, size_t objsize, gboolean ha } else { p = alloc_for_promotion_slow_path (age, objsize); if (!p) { - total_promoted_size += objsize; - return major_collector.alloc_object (vtable, objsize, has_references); + sgen_total_promoted_size += objsize; + return sgen_major_collector.alloc_object (vtable, objsize, has_references); } } @@ -287,7 +289,7 @@ minor_alloc_for_promotion (GCVTable vtable, GCObject *obj, size_t objsize, gbool We only need to check for a non-nursery object if we're doing a major collection. */ if (!sgen_ptr_in_nursery (obj)) - return major_collector.alloc_object (vtable, objsize, has_references); + return sgen_major_collector.alloc_object (vtable, objsize, has_references); return alloc_for_promotion (vtable, obj, objsize, has_references); } @@ -469,5 +471,6 @@ sgen_split_nursery_init (SgenMinorCollector *collector) fill_serial_with_concurrent_major_ops (&collector->serial_ops_with_concurrent_major); } +#endif //#ifndef DISABLE_SGEN_SPLIT_NURSERY #endif diff --git a/mono/sgen/sgen-workers.c b/mono/sgen/sgen-workers.c index 5914946b43..292e117c04 100644 --- a/mono/sgen/sgen-workers.c +++ b/mono/sgen/sgen-workers.c @@ -12,6 +12,7 @@ #include "config.h" #ifdef HAVE_SGEN_GC + #include #include "mono/sgen/sgen-gc.h" @@ -20,6 +21,8 @@ #include "mono/utils/mono-membar.h" #include "mono/sgen/sgen-client.h" +#ifndef DISABLE_SGEN_MAJOR_MARKSWEEP_CONC + static WorkerContext worker_contexts [GENERATION_MAX]; /* @@ -139,7 +142,7 @@ worker_try_finish (WorkerData *data) * Log to be able to get the duration of normal concurrent M&S phase. * Worker indexes are 1 based, since 0 is logically considered gc thread. */ - binary_protocol_worker_finish_stats (data - &context->workers_data [0] + 1, context->generation, context->forced_stop, data->major_scan_time, data->los_scan_time, data->total_time + sgen_timestamp () - last_start); + sgen_binary_protocol_worker_finish_stats (data - &context->workers_data [0] + 1, context->generation, context->forced_stop, data->major_scan_time, data->los_scan_time, data->total_time + sgen_timestamp () - last_start); goto work_available; } } @@ -165,7 +168,7 @@ worker_try_finish (WorkerData *data) mono_os_mutex_unlock (&context->finished_lock); data->total_time += (sgen_timestamp () - last_start); - binary_protocol_worker_finish_stats (data - &context->workers_data [0] + 1, context->generation, context->forced_stop, data->major_scan_time, data->los_scan_time, data->total_time); + sgen_binary_protocol_worker_finish_stats (data - &context->workers_data [0] + 1, context->generation, context->forced_stop, data->major_scan_time, data->los_scan_time, data->total_time); sgen_gray_object_queue_trim_free_list (&data->private_gray_queue); return; @@ -245,7 +248,7 @@ workers_steal_work (WorkerData *data) static void concurrent_enqueue_check (GCObject *obj) { - g_assert (sgen_concurrent_collection_in_progress ()); + g_assert (sgen_get_concurrent_collection_in_progress ()); g_assert (!sgen_ptr_in_nursery (obj)); g_assert (SGEN_LOAD_VTABLE (obj)); } @@ -606,4 +609,84 @@ sgen_workers_is_worker_thread (MonoNativeThreadId id) return sgen_thread_pool_is_thread_pool_thread (id); } -#endif +#else +// Single theaded sgen-workers impl + +void +sgen_workers_enqueue_job (int generation, SgenThreadPoolJob *job, gboolean enqueue) +{ + if (!enqueue) { + job->func (NULL, job); + sgen_thread_pool_job_free (job); + return; + } +} + +gboolean +sgen_workers_all_done (void) +{ + return TRUE; +} + +void +sgen_workers_assert_gray_queue_is_empty (int generation) +{ +} + +void +sgen_workers_foreach (int generation, SgenWorkerCallback callback) +{ +} + +SgenObjectOperations* +sgen_workers_get_idle_func_object_ops (WorkerData *worker) +{ + g_assert (worker->context->idle_func_object_ops); + return worker->context->idle_func_object_ops; +} + +int +sgen_workers_get_job_split_count (int generation) +{ + return 1; +} + +gboolean +sgen_workers_have_idle_work (int generation) +{ + return FALSE; +} + +gboolean +sgen_workers_is_worker_thread (MonoNativeThreadId id) +{ + return FALSE; +} + +void +sgen_workers_join (int generation) +{ +} + +void +sgen_workers_set_num_active_workers (int generation, int num_workers) +{ +} + +void +sgen_workers_start_all_workers (int generation, SgenObjectOperations *object_ops_nopar, SgenObjectOperations *object_ops_par, SgenWorkersFinishCallback callback) +{ +} + +void +sgen_workers_stop_all_workers (int generation) +{ +} + +void +sgen_workers_take_from_queue (int generation, SgenGrayQueue *queue) +{ +} + +#endif //#ifdef DISABLE_SGEN_MAJOR_MARKSWEEP_CONC +#endif // #ifdef HAVE_SGEN_GC diff --git a/mono/tests/Makefile.am b/mono/tests/Makefile.am deleted file mode 100755 index 45dd88855d..0000000000 --- a/mono/tests/Makefile.am +++ /dev/null @@ -1,2121 +0,0 @@ -SUBDIRS = gc-descriptors . testing_gac - -check-local: - ok=:; \ - $(MAKE) test-jit || ok=false; \ - $(MAKE) test-generic-sharing || ok=false; \ - $(MAKE) test-type-load || ok=false; \ - $(MAKE) test-multi-netmodule || ok=false; \ - $(MAKE) test-cattr-type-load || ok=false; \ - $(MAKE) test-reflection-load-with-context || ok=false; \ - $(MAKE) test-platform || ok=false; \ - $(MAKE) test-console-output || ok=false; \ - $(MAKE) test-env-options || ok=false; \ - $(MAKE) test-unhandled-exception-2 || ok=false; \ - $(MAKE) test-appdomain-unload || ok=false; \ - $(MAKE) test-process-stress || ok=false; \ - $(MAKE) test-pedump || ok=false; \ - $(MAKE) test-internalsvisibleto || ok=false; \ - $(MAKE) rm-empty-logs || ok=false; \ - $(MAKE) runtest-gac-loading || ok=false; \ - $$ok - -check-full: - ok=; \ - $(MAKE) test-sgen || ok=false; \ - $(MAKE) check-local || ok=false; \ - $$ok - -check-parallel: - ok=; \ - $(MAKE) compile-tests; \ - $(MAKE) check-full || ok=false; \ - $$ok - -check-coreclr: - $(MAKE) -C $(mono_build_root)/acceptance-tests check-coreclr - -check-stress: - $(MAKE) test-stress-sgen - -# for backwards compatibility on Wrench -test-wrench: check-parallel - -aotcheck: testaot gshared-aot - -JITTEST_PROG = $(if $(VALGRIND), valgrind $(VALGRIND_ARGS),) $(if $(SGEN),$(top_builddir)/mono/mini/mono-sgen,$(top_builddir)/mono/mini/mono) - -JITTEST_PROG_RUN = MONO_CFG_DIR=$(mono_build_root)/runtime/etc $(LIBTOOL) --mode=execute $(JITTEST_PROG) - - -RUNTIME_ARGS=--config tests-config --optimize=all --debug -TEST_RUNTIME_ARGS ?= $(RUNTIME_ARGS) -TEST_AOT_BUILD_FLAGS ?= $(AOT_BUILD_FLAGS) -TEST_AOT_RUN_FLAGS ?= $(AOT_RUN_FLAGS) - -CLASS=$(mcs_topdir)/class/lib/$(DEFAULT_PROFILE) - -with_mono_path = MONO_PATH=$(CLASS) - -RUNTIME = $(with_mono_path) $(top_builddir)/runtime/mono-wrapper -TOOLS_RUNTIME = MONO_PATH=$(mcs_topdir)/class/lib/build $(top_builddir)/runtime/mono-wrapper --aot-path=$(mcs_topdir)/class/lib/build - -MKBUNDLE = \ - PKG_CONFIG_PATH=$(top_builddir):$(PKG_CONFIG_PATH) \ - $(RUNTIME) $(CLASS)/mkbundle.exe - -if FULL_AOT_TESTS -PROFILE_MCS_FLAGS = -d:MOBILE,MOBILE_LEGACY,FULL_AOT_DESKTOP -endif - -if HYBRID_AOT_TESTS -PROFILE_MCS_FLAGS = -d:MOBILE,MOBILE_LEGACY -endif - -MCS_NO_UNSAFE = $(TOOLS_RUNTIME) $(CSC) -debug:portable \ - -noconfig -nologo \ - -nowarn:0162 -nowarn:0168 -nowarn:0219 -nowarn:0414 -nowarn:0618 \ - -nowarn:0169 -nowarn:1690 -nowarn:0649 -nowarn:0612 -nowarn:3021 \ - -nowarn:0197 $(PROFILE_MCS_FLAGS) -MCS_NO_LIB = $(MCS_NO_UNSAFE) -unsafe - -MCS = $(MCS_NO_LIB) - -ILASM = $(TOOLS_RUNTIME) $(mcs_topdir)/class/lib/build/ilasm.exe - -TEST_RUNNER = ./test-runner.exe --runtime $(top_builddir)/runtime/mono-wrapper --mono-path "$(CLASS)" - -if FULL_AOT_TESTS -TEST_RUNNER += --runtime-args "$(TEST_AOT_RUN_FLAGS)" -endif - -if HYBRID_AOT_TESTS -TEST_RUNNER += --runtime-args "$(TEST_AOT_RUN_FLAGS)" -endif - -if HOST_WIN32 -TEST_RUNNER += --config tests-config --runtime $(if $(MONO_EXECUTABLE),$(shell cygpath -w -a $(MONO_EXECUTABLE) | sed 's/\\/\\\\/g'),mono) -else -TEST_RUNNER += --config tests-config --runtime $(if $(MONO_EXECUTABLE),$(MONO_EXECUTABLE),mono) -endif - -TEST_RUNNER += $(if $(V), --verbose,) - -TESTS_BENCH_SRC=fib.cs random.cs nested-loops.cs ackermann.cs tight-loop.cs sieve.cs - -TESTS_STRESS_SRC= \ - abort-stress-1.cs \ - abort-stress-2.cs \ - abort-stress-3.cs \ - domain-stress.cs \ - gchandle-stress.cs \ - monitor-stress.cs \ - thread-stress.cs \ - gc-stress.cs \ - gc-copy-stress.cs \ - gc-graystack-stress.cs \ - exit-stress.cs \ - process-stress.cs \ - assembly-load-stress.cs - -# Disabled until ?mcs is fixed -# bug-331958.cs -TESTS_CS_SRC= \ - generic-unloading-sub.2.cs \ - create-instance.cs \ - bug-2907.cs \ - array-init.cs \ - arraylist.cs \ - assembly-load-remap.cs \ - assemblyresolve_event.cs \ - assemblyresolve_event3.cs \ - assemblyresolve_event4.cs \ - assemblyresolve_event5.cs \ - assemblyresolve_event6.cs \ - checked.cs \ - char-isnumber.cs \ - field-layout.cs \ - pack-layout.cs \ - pack-bug.cs \ - hash-table.cs \ - test-ops.cs \ - obj.cs \ - test-dup-mp.cs \ - string.cs \ - stringbuilder.cs \ - switch.cs \ - outparm.cs \ - delegate.cs \ - bitconverter.cs \ - exception.cs \ - exception2.cs \ - exception3.cs \ - exception4.cs \ - exception5.cs \ - exception6.cs \ - exception7.cs \ - exception8.cs \ - exception10.cs \ - exception11.cs \ - exception12.cs \ - exception13.cs \ - exception14.cs \ - exception15.cs \ - exception16.cs \ - exception17.cs \ - exception18.cs \ - typeload-unaligned.cs \ - struct.cs \ - valuetype-gettype.cs \ - typeof-ptr.cs \ - static-constructor.cs \ - pinvoke.cs \ - pinvoke-utf8.cs \ - pinvoke3.cs \ - pinvoke11.cs \ - pinvoke13.cs \ - pinvoke17.cs \ - invoke.cs \ - invoke2.cs \ - runtime-invoke.cs \ - invoke-string-ctors.cs \ - reinit.cs \ - box.cs \ - array.cs \ - enum.cs \ - enum2.cs \ - enum-intrins.cs \ - property.cs \ - enumcast.cs \ - assignable-tests.cs \ - array-cast.cs \ - array-subtype-attr.cs \ - cattr-compile.cs \ - cattr-field.cs \ - cattr-object.cs \ - custom-attr.cs \ - double-cast.cs \ - newobj-valuetype.cs \ - arraylist-clone.cs \ - setenv.cs \ - vtype.cs \ - isvaluetype.cs \ - iface6.cs \ - iface7.cs \ - ipaddress.cs \ - array-vt.cs \ - interface1.cs \ - reflection-enum.cs \ - reflection-prop.cs \ - reflection4.cs \ - reflection5.cs \ - reflection-const-field.cs \ - many-locals.cs \ - string-compare.cs \ - test-prime.cs \ - test-tls.cs \ - params.cs \ - reflection.cs \ - interface.cs \ - iface.cs \ - iface2.cs \ - iface3.cs \ - iface4.cs \ - iface-large.cs \ - iface-contravariant1.cs \ - virtual-method.cs \ - intptrcast.cs \ - indexer.cs \ - stream.cs \ - console.cs \ - shift.cs \ - jit-int.cs \ - jit-uint.cs \ - jit-long.cs \ - long.cs \ - jit-ulong.cs \ - jit-float.cs \ - pop.cs \ - time.cs \ - pointer.cs \ - hashcode.cs \ - delegate1.cs \ - delegate2.cs \ - delegate3.cs \ - delegate5.cs \ - delegate6.cs \ - delegate7.cs \ - delegate8.cs \ - delegate10.cs \ - delegate11.cs \ - delegate12.cs \ - delegate13.cs \ - delegate14.cs \ - delegate15.cs \ - largeexp.cs \ - largeexp2.cs \ - marshalbyref1.cs \ - static-ctor.cs \ - inctest.cs \ - bound.cs \ - array-invoke.cs \ - test-arr.cs \ - decimal.cs \ - decimal-array.cs \ - marshal.cs \ - marshal1.cs \ - marshal2.cs \ - marshal3.cs \ - marshal5.cs \ - marshal6.cs \ - marshal7.cs \ - marshal8.cs \ - marshal9.cs \ - marshalbool.cs \ - test-byval-in-struct.cs \ - thread.cs \ - thread5.cs \ - thread-static.cs \ - thread-static-init.cs \ - context-static.cs \ - float-pop.cs \ - interfacecast.cs \ - array3.cs \ - classinit.cs \ - classinit2.cs \ - classinit3.cs \ - synchronized.cs \ - async_read.cs \ - threadpool.cs \ - threadpool1.cs \ - threadpool-exceptions1.cs \ - threadpool-exceptions2.cs \ - threadpool-exceptions3.cs \ - threadpool-exceptions4.cs \ - threadpool-exceptions5.cs \ - threadpool-exceptions6.cs \ - base-definition.cs \ - bug-27420.cs \ - bug-46781.cs \ - bug-42136.cs \ - bug-59286.cs \ - bug-70561.cs \ - bug-78311.cs \ - bug-78653.cs \ - bug-78656.cs \ - bug-77127.cs \ - bug-323114.cs \ - bug-Xamarin-5278.cs \ - interlocked.cs \ - delegate-async-exit.cs \ - delegate-delegate-exit.cs \ - delegate-exit.cs \ - delegate-disposed-hashcode.cs \ - finalizer-abort.cs \ - finalizer-exception.cs \ - finalizer-exit.cs \ - finalizer-thread.cs \ - main-exit.cs \ - main-returns-abort-resetabort.cs \ - main-returns-background-abort-resetabort.cs \ - main-returns-background-resetabort.cs \ - main-returns-background.cs \ - main-returns-background-change.cs \ - main-returns.cs \ - subthread-exit.cs \ - desweak.cs \ - exists.cs \ - handleref.cs \ - dbnull-missing.cs \ - test-type-ctor.cs \ - soft-float-tests.cs \ - thread-exit.cs \ - finalize-parent.cs \ - interlocked-2.2.cs \ - pinvoke-2.2.cs \ - bug-78431.2.cs \ - bug-79684.2.cs \ - catch-generics.2.cs \ - event-get.2.cs \ - safehandle.2.cs \ - module-cctor-loader.2.cs \ - generics-invoke-byref.2.cs \ - generic-signature-compare.2.cs \ - generics-sharing.2.cs \ - shared-generic-methods.2.cs \ - shared-generic-synchronized.2.cs \ - generic-inlining.2.cs \ - generic-initobj.2.cs \ - generic-delegate.2.cs \ - generic-sizeof.2.cs \ - generic-virtual.2.cs \ - generic-interface-methods.2.cs \ - generic-array-type.2.cs \ - generic-method-patching.2.cs \ - generic-static-methods.2.cs \ - generic-null-call.2.cs \ - generic-special.2.cs \ - generic-special2.2.cs \ - generic-exceptions.2.cs \ - generic-virtual2.2.cs \ - generic-valuetype-interface.2.cs \ - generic-getgenericarguments.2.cs \ - generic-synchronized.2.cs \ - generic-delegate-ctor.2.cs \ - generic-array-iface-set.2.cs \ - generic-typedef.2.cs \ - bug-431413.2.cs \ - bug-459285.2.cs \ - generic-virtual-invoke.2.cs \ - bug-461198.2.cs \ - generic-sealed-virtual.2.cs \ - generic-system-arrays.2.cs \ - generic-stack-traces.2.cs \ - generic-stack-traces2.2.cs \ - bug-472600.2.cs \ - recursive-generics.2.cs \ - bug-473482.2.cs \ - bug-473999.2.cs \ - bug-479763.2.cs \ - bug-616463.cs \ - bug-80392.2.cs \ - bug-82194.2.cs \ - anonarray.2.cs \ - ienumerator-interfaces.2.cs \ - array-enumerator-ifaces.2.cs \ - generic_type_definition_encoding.2.cs \ - bug-333798.2.cs \ - bug-348522.2.cs \ - bug-340662_bug.cs \ - bug-325283.2.cs \ - thunks.cs \ - winx64structs.cs \ - nullable_boxing.2.cs \ - valuetype-equals.cs \ - custom-modifiers.2.cs \ - bug-382986.cs \ - test-inline-call-stack.cs \ - bug-324535.cs \ - modules.cs \ - bug-81673.cs \ - bug-81691.cs \ - bug-415577.cs \ - filter-stack.cs \ - vararg.cs \ - vararg2.cs \ - bug-461867.cs \ - bug-461941.cs \ - bug-461261.cs \ - bug-400716.cs \ - bug-459094.cs \ - bug-467456.cs \ - bug-508538.cs \ - bug-472692.2.cs \ - gchandles.cs \ - interlocked-3.cs \ - interlocked-4.2.cs \ - w32message.cs \ - gc-altstack.cs \ - large-gc-bitmap.cs \ - bug-561239.cs \ - bug-562150.cs \ - bug-599469.cs \ - monitor-resurrection.cs \ - monitor-wait-abort.cs \ - monitor-abort.cs \ - bug-666008.cs \ - bug-685908.cs \ - sgen-long-vtype.cs \ - delegate-invoke.cs \ - bug-696593.cs \ - bug-705140.cs \ - bug-1147.cs \ - mono-path.cs \ - bug-bxc-795.cs \ - bug-3903.cs \ - async-with-cb-throws.cs \ - bug-6148.cs \ - bug-10127.cs \ - bug-18026.cs \ - allow-synchronous-major.cs \ - block_guard_restore_aligment_on_exit.cs \ - thread_static_gc_layout.cs \ - sleep.cs \ - bug-27147.cs \ - bug-30085.cs \ - bug-17537.cs \ - pinvoke_ppcc.cs \ - pinvoke_ppcs.cs \ - pinvoke_ppci.cs \ - pinvoke_ppcf.cs \ - pinvoke_ppcd.cs \ - bug-29585.cs \ - priority.cs \ - abort-cctor.cs \ - abort-try-holes.cs \ - thread-native-exit.cs \ - reference-loader.cs \ - thread-suspend-suspended.cs \ - thread-suspend-selfsuspended.cs \ - remoting4.cs \ - remoting1.cs \ - remoting2.cs \ - remoting3.cs \ - remoting5.cs \ - appdomain.cs \ - appdomain-client.cs \ - appdomain-unload.cs \ - appdomain-async-invoke.cs \ - appdomain-thread-abort.cs \ - appdomain1.cs \ - appdomain2.cs \ - appdomain-exit.cs \ - appdomain-serialize-exception.cs \ - assemblyresolve_event2.2.cs \ - appdomain-unload-callback.cs \ - appdomain-unload-doesnot-raise-pending-events.cs \ - appdomain-unload-asmload.cs \ - appdomain-unload-exception.cs \ - unload-appdomain-on-shutdown.cs \ - appdomain-marshalbyref-assemblyload.cs \ - bug-47295.cs \ - loader.cs \ - pinvoke2.cs \ - generic-type-builder.2.cs \ - dynamic-generic-size.cs \ - cominterop.cs \ - dynamic-method-access.2.cs \ - dynamic-method-finalize.2.cs \ - dynamic-method-stack-traces.cs \ - generic_type_definition.2.cs \ - bug-333798-tb.2.cs \ - bug-335131.2.cs \ - bug-322722_patch_bx.2.cs \ - bug-322722_dyn_method_throw.2.cs \ - bug-389886-2.cs \ - bug-349190.2.cs \ - bug-389886-sre-generic-interface-instances.cs \ - bug-462592.cs \ - bug-575941.cs \ - bug-389886-3.cs \ - constant-division.cs \ - dynamic-method-resurrection.cs \ - bug-80307.cs \ - assembly_append_ordering.cs \ - bug-544446.cs \ - bug-36848.cs \ - generic-marshalbyref.2.cs \ - stackframes-async.2.cs \ - transparentproxy.cs \ - bug-48015.cs \ - delegate9.cs \ - marshal-valuetypes.cs \ - xdomain-threads.cs \ - monitor.cs \ - generic-xdomain.2.cs \ - threadpool-exceptions7.cs \ - cross-domain.cs \ - generic-unloading.2.cs \ - namedmutex-destroy-race.cs \ - thread6.cs \ - appdomain-threadpool-unload.cs \ - process-unref-race.cs \ - bug-46661.cs \ - w32message.cs \ - runtime-invoke.gen.cs \ - imt_big_iface_test.cs \ - bug-58782-plain-throw.cs \ - bug-58782-capture-and-throw.cs \ - recursive-struct-arrays.cs \ - struct-explicit-layout.cs \ - bug-59281.cs \ - init_array_with_lazy_type.cs \ - weak-fields.cs \ - threads-leak.cs \ - threads-init.cs \ - bug-60848.cs \ - bug-59400.cs \ - nested_type_visibility.cs - -if AMD64 -TESTS_CS_SRC += async-exc-compilation.cs finally_guard.cs finally_block_ending_in_dead_bb.cs -if !HOST_WIN32 -# requires working altstack -TESTS_CS_SRC += bug-60862.cs -endif -endif - -if X86 -TESTS_CS_SRC += async-exc-compilation.cs finally_guard.cs finally_block_ending_in_dead_bb.cs -if !HOST_WIN32 -# requires working altstack -TESTS_CS_SRC += bug-60862.cs -endif -endif - -TESTS_IL_SRC= \ - field-access.il \ - method-access.il \ - ldftn-access.il \ - cpblkTest.il \ - vbinterface.il \ - calliTest.il \ - calliGenericTest.il \ - ckfiniteTest.il \ - fault-handler.il \ - locallocTest.il \ - initblkTest.il \ - qt-instance.il \ - vararg3.il \ - bug-29859.il \ - bug-78549.il \ - static-fields-nonconst.il \ - reload-at-bb-end.il \ - test-enum-indstoreil.il \ - filter-bug.il \ - even-odd.il \ - bug-82022.il \ - vt-sync-method.il \ - enum_types.il \ - invalid-token.il \ - call_missing_method.il \ - call_missing_class.il \ - ldfld_missing_field.il \ - ldfld_missing_class.il \ - find-method.2.il \ - bug-79215.2.il \ - bug-79956.2.il \ - bug-327438.2.il \ - bug-387274.2.il \ - bug-426309.2.il \ - ldtoken_with_byref_typespec.2.il \ - resolve_method_bug.2.il \ - resolve_field_bug.2.il \ - resolve_type_bug.2.il \ - generics-sharing-other-exc.2.il \ - generic-ldobj.2.il \ - generic-mkrefany.2.il \ - generic-refanyval.2.il \ - generic-ldtoken.2.il \ - generic-ldtoken-method.2.il \ - generic-ldtoken-field.2.il \ - generic-tailcall.2.il \ - generic-tailcall2.2.il \ - generic-array-exc.2.il \ - generic-valuetype-newobj2.2.il \ - generic-valuetype-newobj.2.il \ - generic-constrained.2.il \ - generic-type-load-exception.2.il \ - bug-81466.il \ - bug457574.il \ - bug445361.il \ - bug-463303.il \ - bug469742.2.il \ - bug-528055.il \ - array_load_exception.il \ - bug-481403.il \ - interface-with-static-method.il \ - bug-633291.il \ - delegate-with-null-target.il \ - bug-318677.il \ - gsharing-valuetype-layout.il \ - invalid_generic_instantiation.il \ - bug-45841-fpstack-exceptions.il \ - instance_tailrec.il \ - dim-constrainedcall.il \ - dim-diamondshape.il \ - dim-genericmethods.il \ - dim-methodimpl.il \ - dim-sharedgenerics.il \ - dim-simple.il \ - dim-valuetypes.il - -TESTS_GSHARED_SRC = \ - generics-sharing.2.cs \ - shared-generic-methods.2.cs \ - shared-generic-synchronized.2.cs \ - generic-initobj.2.cs \ - generics-sharing-other-exc.2.cs \ - generic-box.2.cs \ - generic-unbox.2.cs \ - generic-delegate.2.cs \ - generic-sizeof.2.cs \ - generic-ldobj.2.cs \ - generic-mkrefany.2.cs \ - generic-refanyval.2.cs \ - generic-ldtoken.2.cs \ - generic-ldtoken-method.2.cs \ - generic-ldtoken-field.2.cs \ - generic-virtual.2.cs \ - generic-tailcall.2.cs \ - generic-interface-methods.2.cs \ - generic-array-type.2.cs \ - generic-method-patching.2.cs \ - generic-static-methods.2.cs \ - generic-null-call.2.cs \ - generic-tailcall2.2.cs \ - generic-array-exc.2.cs \ - generic-special.2.cs \ - generic-special2.2.cs \ - generic-exceptions.2.cs \ - generic-delegate2.2.cs \ - generic-virtual2.2.cs \ - generic-valuetype-interface.2.cs \ - generic-valuetype-newobj.2.cs \ - generic-valuetype-newobj2.2.cs \ - generic-getgenericarguments.2.cs \ - generic-synchronized.2.cs \ - generic-delegate-ctor.2.cs \ - generic-constrained.2.cs \ - bug-431413.2.cs \ - generic-virtual-invoke.2.cs \ - generic-typedef.2.cs \ - generic-marshalbyref.2.cs \ - bug-459285.2.cs \ - bug-461198.2.cs \ - generic-sealed-virtual.2.cs \ - generic-system-arrays.2.cs \ - generic-stack-traces.2.cs \ - generic-stack-traces2.2.cs \ - bug-472600.2.cs \ - bug-473482.2.cs \ - bug-473999.2.cs \ - bug-479763.2.cs \ - generic-type-load-exception.2.cs \ - bug-616463.cs \ - bug-1147.cs \ - generic-type-builder.2.cs - -PLATFORM_DISABLED_TESTS= - -if HOST_WIN32 -PLATFORM_DISABLED_TESTS += bug-58782-plain-throw.exe bug-58782-capture-and-throw.exe -endif - -if AMD64 -# #651684 -PLATFORM_DISABLED_TESTS += finally_guard.exe - -if HOST_WIN32 -PLATFORM_DISABLED_TESTS += w32message.exe -endif - -endif - -if X86 - -if HOST_WIN32 -PLATFORM_DISABLED_TESTS += async-exc-compilation.exe finally_guard.exe finally_block_ending_in_dead_bb.exe \ - bug-18026.exe monitor.exe threadpool-exceptions5.exe process-unref-race.exe w32message.exe \ - unhandled-exception-1.exe unhandled-exception-2.exe unhandled-exception-3.exe unhandled-exception-4.exe \ - unhandled-exception-5.exe unhandled-exception-6.exe unhandled-exception-7.exe unhandled-exception-8.exe -endif - -endif - -if POWERPC -# bug #71274 -PLATFORM_DISABLED_TESTS += finalizer-abort.exe finalizer-exception.exe finalizer-exit.exe -endif - -if POWERPC64 -# FIXME: These tests hang/fail for unknown reasons -PLATFORM_DISABLED_TESTS += monitor.exe threadpool-exceptions5.exe appdomain-unload.exe \ - pinvoke2.exe pinvoke3.exe pinvoke11.exe threadpool-exceptions7.exe winx64structs.exe bug-10127.exe pinvoke_ppcc.exe \ - pinvoke_ppcs.exe pinvoke_ppci.exe pinvoke_ppcf.exe pinvoke_ppcd.exe abort-cctor.exe load-exceptions.exe \ - sgen-domain-unload-2.exe sgen-weakref-stress.exe sgen-cementing-stress.exe sgen-new-threads-dont-join-stw.exe \ - sgen-new-threads-dont-join-stw-2.exe sgen-new-threads-collect.exe sgen-bridge.exe -endif - -if ARM -PLATFORM_DISABLED_TESTS += filter-stack.exe weak-fields.exe -INTERP_PLATFORM_DISABLED_TESTS= \ - assemblyresolve_event6.exe \ - delegate-async-exit.exe \ - delegate-delegate-exit.exe \ - delegate-exit.exe \ - delegate1.exe \ - delegate3.exe \ - thunks.exe \ - finalizer-exception.exe \ - delegate5.exe \ - delegate8.exe \ - bug-323114.exe \ - threadpool-exceptions3.exe \ - threadpool-exceptions6.exe \ - bug-80392.2.exe \ - remoting3.exe \ - remoting2.exe \ - appdomain-unload-callback.exe \ - monitor-abort.exe -endif - -if ARM64 -PLATFORM_DISABLED_TESTS += weak-fields.exe -INTERP_PLATFORM_DISABLED_TESTS= \ - assemblyresolve_event6.exe \ - finalizer-exception.exe -endif - -if MIPS -# monitor.exe is racy -PLATFORM_DISABLED_TESTS += filter-stack.exe monitor.exe -endif - -if S390X -PLATFORM_DISABLED_TESTS += dynamic-method-resurrection.exe -#PLATFORM_DISABLED_TESTS=dynamic-method-resurrection.exe exception17.exe - -PLATFORM_DISABLED_TESTS += \ - sgen-toggleref.exe \ - sgen-bridge.exe \ - sgen-bridge-major-fragmentation.exe \ - sgen-bridge-xref.exe -endif - -if ENABLE_COOP -COOP_DISABLED_TESTS= thunks.exe -else -COOP_DISABLED_TESTS= -endif - -PROFILE_DISABLED_TESTS= - -if FULL_AOT_TESTS -# Tests which rely on TypeLoadExceptions -# In full-aot mode, these cause the relevant methods to be not AOTed. -PROFILE_DISABLED_TESTS += \ - typeload-unaligned.exe \ - field-access.exe \ - invalid_generic_instantiation.exe \ - bug-481403.exe \ - array_ldelema.exe \ - array_load_exception.exe \ - bug445361.exe \ - generic-type-load-exception.2.exe \ - invalid-token.exe \ - call_missing_method.exe \ - call_missing_class.exe \ - ldfld_missing_field.exe \ - ldfld_missing_class.exe \ - vt-sync-method.exe \ - resolve_method_bug.2.exe \ - resolve_field_bug.2.exe \ - resolve_type_bug.2.exe \ - bug-81691.exe \ - bug-327438.2.exe - -# Tests which rely on remoting -PROFILE_DISABLED_TESTS += \ - context-static.exe \ - bug-415577.exe \ - generic-marshalbyref.2.exe \ - unhandled-exception-7.exe - -# Tests which use unsupported pinvoke+full aot -# functionality -PROFILE_DISABLED_TESTS += \ - marshal.exe \ - marshal2.exe \ - marshal6.exe \ - marshal7.exe \ - marshal8.exe \ - pinvoke-2.2.exe \ - pinvoke3.exe \ - thunks.exe \ - bug-58782-plain-throw.exe \ - bug-58782-capture-and-throw.exe - -# Tests which load assemblies which are not -# in the testing_aot_full profile -PROFILE_DISABLED_TESTS += \ - assembly-load-remap.exe - -# Test which needs remoting support -PROFILE_DISABLED_TESTS += \ - remoting4.exe \ - remoting1.exe \ - remoting2.exe \ - remoting3.exe \ - remoting5.exe - -# Tests which needs AppDomain support -PROFILE_DISABLED_TESTS += \ - appdomain.exe \ - appdomain-client.exe \ - appdomain-unload.exe \ - appdomain-async-invoke.exe \ - appdomain-thread-abort.exe \ - appdomain1.exe \ - appdomain2.exe \ - appdomain-exit.exe \ - appdomain-unload-asmload.exe \ - appdomain-unload-callback.exe \ - appdomain-unload-doesnot-raise-pending-events.exe \ - unload-appdomain-on-shutdown.exe \ - appdomain-marshalbyref-assemblyload.exe \ - assemblyresolve_event2.2.exe \ - assemblyresolve_event6.exe \ - bug-544446.exe \ - bug-36848.exe \ - generic-marshalbyref.2.exe \ - stackframes-async.2.exe \ - transparentproxy.exe \ - bug-48015.exe \ - delegate9.exe \ - marshal-valuetypes.exe \ - xdomain-threads.exe \ - monitor.exe \ - generic-xdomain.2.exe \ - threadpool-exceptions7.exe \ - cross-domain.exe \ - generic-unloading.2.exe \ - appdomain-threadpool-unload.exe - -# Tests which needs System.Reflection.Emit support -PROFILE_DISABLED_TESTS += \ - bug-47295.exe \ - loader.exe \ - pinvoke2.exe \ - generic-type-builder.2.exe \ - dynamic-generic-size.exe \ - cominterop.exe \ - dynamic-method-access.2.exe \ - dynamic-method-finalize.2.exe \ - dynamic-method-stack-traces.exe \ - generic_type_definition.2.exe \ - bug-333798-tb.2.exe \ - bug-335131.2.exe \ - bug-322722_patch_bx.2.exe \ - bug-322722_dyn_method_throw.2.exe \ - bug-389886-2.exe \ - bug-349190.2.exe \ - bug-389886-sre-generic-interface-instances.exe \ - bug-462592.exe \ - bug-575941.exe \ - bug-389886-3.exe \ - constant-division.exe \ - dynamic-method-resurrection.exe \ - assembly_append_ordering.exe \ - assemblyresolve_event5.exe - -# Test which needs System.Web support -PROFILE_DISABLED_TESTS += \ - bug-80307.exe - -# Tests which needs named Mutex support -PROFILE_DISABLED_TESTS += \ - namedmutex-destroy-race.exe - -# ThreadAbortException doesn't have necessary field for this test -PROFILE_DISABLED_TESTS += \ - thread6.exe - -# can't AOT the TestingReferenceAssembly.dll which is a dependency -# of reference-loader.exe because it contains the [ReferenceAssemblyAttribute] -# and the runtime errors out with "File does not contain a valid CIL image." -PROFILE_DISABLED_TESTS += \ - reference-loader.exe - -# constraints-load.il: -# Failed to load method 0x6000007 from '..../mono/tests/constraints-load.exe' due to -# Could not resolve type with token 01000002 assembly:mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 type:System.BrokenIComparable`1 member:. -PROFILE_DISABLED_TESTS += \ - constraints-load.exe \ - bug-515884.exe - -PROFILE_DISABLED_TESTS += \ - generic-type-builder.2.exe - -PROFILE_DISABLED_TESTS += \ - sgen-domain-unload.exe \ - sgen-domain-unload-2.exe - -PROFILE_DISABLED_TESTS += \ - appdomain-loader.exe \ - assemblyresolve_event3.exe \ - appdomain-serialize-exception.exe - -PROFILE_DISABLED_TESTS += \ - delegate15.exe - -# https://bugzilla.xamarin.com/show_bug.cgi?id=60973 -PROFILE_DISABLED_TESTS += \ - weak-fields.exe -endif - -if HYBRID_AOT_TESTS -PROFILE_DISABLED_TESTS += \ - bug-80307.exe \ - namedmutex-destroy-race.exe -endif - -AOT_DISABLED_TESTS= \ - constraints-load.exe - -CI_DISABLED_TESTS = \ - main-returns-background-resetabort.exe \ - main-returns-background-abort-resetabort.exe \ - assemblyresolve_event3.exe \ - delegate2.exe \ - finally_guard.exe \ - generic-xdomain.2.exe - -# failing tests which we temporarily disable for PRs -# so they don't interfere with other people's work -CI_PR_DISABLED_TESTS = \ - appdomain-threadpool-unload.exe - -if ENABLE_COOP -CI_PR_DISABLED_TESTS += \ - abort-cctor.exe \ - bug-58782-plain-throw.exe \ - bug-58782-capture-and-throw.exe -endif - -# appdomain-threadpool-unload.exe creates 100 appdomains, takes too long with llvm -LLVM_DISABLED_TESTS = \ - finally_block_ending_in_dead_bb.exe \ - appdomain-threadpool-unload.exe - -# https://github.com/mono/mono/issues/6490 -LLVM_DISABLED_TESTS += \ - weak-fields.exe - -LLVM = $(filter --llvm, $(MONO_ENV_OPTIONS)) - -# The two finalizer tests only work under sgen -# gc-altstack.exe fails under boehm because it has no support for altstack -# bug-459094.exe creates an extremely deep directory tree -# delegate-invoke.exe depends on 929c6bc9b6d76a273f251e6f5dfacac36e9c38bd which was -# reverted. -# bug-Xamarin-5278.exe got broken by 5d26590e79da139a284459299aee95c25f4cd835 -# appdomain-thread-abort.exe: https://bugzilla.xamarin.com/show_bug.cgi?id=47054 -# abort-try-holes.exe is flaky due to unwinding failure to the finally block when aborting -# appdomain-marshalbyref-assemblyload.exe: https://bugzilla.xamarin.com/show_bug.cgi?id=49308 -# dim-*: https://github.com/mono/mono/pull/6252 -KNOWN_FAILING_TESTS = \ - delegate-async-exception.exe \ - bug-348522.2.exe \ - bug-459094.exe \ - delegate-invoke.exe \ - bug-Xamarin-5278.exe \ - appdomain-marshalbyref-assemblyload.exe \ - abort-try-holes.exe \ - dim-constrainedcall.exe \ - dim-diamondshape.exe - -DISABLED_TESTS = \ - $(KNOWN_FAILING_TESTS) \ - $(PLATFORM_DISABLED_TESTS) \ - $(EXTRA_DISABLED_TESTS) \ - $(COOP_DISABLED_TESTS) \ - $(PROFILE_DISABLED_TESTS) \ - $(if $(AOT),$(AOT_DISABLED_TESTS)) \ - $(if $(CI),$(CI_DISABLED_TESTS)) \ - $(if $(CI_PR),$(CI_PR_DISABLED_TESTS)) \ - $(if $(LLVM),$(LLVM_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 -# bug-60862.exe: missing support to map IP->method; only works on platforms with altstack support. -INTERP_DISABLED_TESTS = \ - $(KNOWN_FAILING_TESTS) \ - $(INTERP_PLATFORM_DISABLED_TESTS) \ - $(COOP_DISABLED_TESTS) \ - $(if $(CI),$(CI_DISABLED_TESTS)) \ - $(if $(CI_PR),$(CI_PR_DISABLED_TESTS)) \ - appdomain-unload.exe \ - array_load_exception.exe \ - async-exc-compilation.exe \ - async-with-cb-throws.exe \ - block_guard_restore_aligment_on_exit.exe \ - bug-335131.2.exe \ - bug-415577.exe \ - bug-45841-fpstack-exceptions.exe \ - bug-48015.exe \ - bug-58782-capture-and-throw.exe \ - bug-58782-plain-throw.exe \ - bug445361.exe \ - bug-60862.exe \ - calliGenericTest.exe \ - cominterop.exe \ - context-static.exe \ - delegate-with-null-target.exe \ - delegate9.exe \ - dynamic-method-stack-traces.exe \ - even-odd.exe \ - exception18.exe \ - field-access.exe \ - handleref.exe \ - nullable_boxing.2.exe \ - pinvoke2.exe \ - pinvoke3.exe \ - safehandle.2.exe \ - stackframes-async.2.exe \ - static-constructor.exe \ - thread6.exe \ - threadpool-exceptions2.exe \ - threadpool-exceptions4.exe \ - threadpool-exceptions5.exe \ - typeload-unaligned.exe \ - weak-fields.exe \ - vararg.exe \ - vararg2.exe \ - vararg3.exe - -TESTS_CS=$(filter-out $(DISABLED_TESTS),$(TESTS_CS_SRC:.cs=.exe)) -TESTS_IL=$(filter-out $(DISABLED_TESTS),$(TESTS_IL_SRC:.il=.exe)) -TESTS_BENCH=$(filter-out $(DISABLED_TESTS),$(TESTS_BENCH_SRC:.cs=.exe)) -TESTS_STRESS=$(filter-out $(DISABLED_TESTS),$(TESTS_STRESS_SRC:.cs=.exe)) -TESTS_GSHARED=$(filter-out $(DISABLED_TESTS),$(TESTS_GSHARED_SRC:.cs=.exe)) - -if FULL_AOT_TESTS -TESTSAOT_CS=$(TESTS_CS:.exe=.exe$(PLATFORM_AOT_SUFFIX)) -TESTSAOT_IL=$(TESTS_IL:.exe=.exe$(PLATFORM_AOT_SUFFIX)) -TESTSAOT_BENCH=$(TESTS_BENCH:.exe=.exe$(PLATFORM_AOT_SUFFIX)) -TESTSAOT_STRESS=$(TESTS_STRESS:.exe=.exe$(PLATFORM_AOT_SUFFIX)) -TESTSAOT_GSHARED=$(TESTS_GSHARED:.exe=.exe$(PLATFORM_AOT_SUFFIX)) -endif - -if HYBRID_AOT_TESTS -TESTSAOT_CS=$(TESTS_CS:.exe=.exe$(PLATFORM_AOT_SUFFIX)) -TESTSAOT_IL=$(TESTS_IL:.exe=.exe$(PLATFORM_AOT_SUFFIX)) -TESTSAOT_BENCH=$(TESTS_BENCH:.exe=.exe$(PLATFORM_AOT_SUFFIX)) -TESTSAOT_STRESS=$(TESTS_STRESS:.exe=.exe$(PLATFORM_AOT_SUFFIX)) -TESTSAOT_GSHARED=$(TESTS_GSHARED:.exe=.exe$(PLATFORM_AOT_SUFFIX)) -endif - -EXTRA_DIST=test-driver test-runner.cs $(TESTS_CS_SRC) $(TESTS_IL_SRC) \ - $(TESTS_BENCH_SRC) $(TESTS_STRESS_SRC) stress-runner.pl - -%.exe: %.il - $(ILASM) -out:$@ $< - -if !FULL_AOT_TESTS -if !HYBRID_AOT_TESTS -TEST_DRIVER_HARD_KILL_FEATURE=-r:$(CLASS)/Mono.Posix.dll -endif -endif - -if FULL_AOT_TESTS -TEST_DRIVER_DEPEND=TestDriver.dll$(PLATFORM_AOT_SUFFIX) -else -if HYBRID_AOT_TESTS -TEST_DRIVER_DEPEND=TestDriver.dll$(PLATFORM_AOT_SUFFIX) -else -TEST_DRIVER_DEPEND=TestDriver.dll -endif -endif - -%.exe: %.cs $(TEST_DRIVER_DEPEND) - $(MCS) -r:$(CLASS)/System.dll -r:$(CLASS)/System.Xml.dll -r:$(CLASS)/System.Core.dll -r:TestDriver.dll $(TEST_DRIVER_HARD_KILL_FEATURE) -out:$@ $< - -# N.B. test-runner.exe references the TOOLS_RUNTIME versions of the framework assemblies -test-runner.exe: test-runner.cs $(TEST_DRIVER_DEPEND) - $(MCS) -r:System.dll -r:System.Xml.dll -r:System.Core.dll -r:TestDriver.dll $(TEST_DRIVER_HARD_KILL_FEATURE) -out:$@ $< - -%.dll: %.cs - $(MCS) -r:$(CLASS)/System.dll -target:library -out:$@ $< -%.dll: %.il - $(ILASM) /dll /output:$@ $< - -reference-loader.exe: reference-loader.cs TestingReferenceAssembly.dll TestingReferenceReferenceAssembly.dll $(TEST_DRIVER_DEPEND) - $(MCS) -r:$(CLASS)/System.dll -r:TestDriver.dll -r:TestingReferenceAssembly.dll -r:TestingReferenceReferenceAssembly.dll $(TEST_DRIVER_HARD_KILL_FEATURE) -out:$@ $(srcdir)/reference-loader.cs - -TestingReferenceAssembly.dll: TestingReferenceAssembly.cs - $(MCS) -target:library -out:$@ $< - -TestingReferenceReferenceAssembly.dll: TestingReferenceReferenceAssembly.cs TestingReferenceAssembly.dll - $(MCS) -r:TestingReferenceAssembly.dll -target:library -out:$@ $< - -%.exe$(PLATFORM_AOT_SUFFIX): %.exe - $(RUNTIME) $(TEST_AOT_BUILD_FLAGS) $< - -%.dll$(PLATFORM_AOT_SUFFIX): %.dll - $(RUNTIME) $(TEST_AOT_BUILD_FLAGS) $< - -# mkbundle works on ppc, but the pkg-config POC doesn't when run with make test -if POWERPC -test-platform: -else -# Can't use mkbundle on win32 since there is no static build there -# Can't run test-unhandled-exception on Windows because of all the debug popups... -if HOST_WIN32 -test-platform: -else -# mkbundle uses the installed mono-2.pc so it won't work if there is no system mono -#test-platform: testbundle test-iomap-regression -test-platform: test-iomap-regression -endif -endif - -# Target to precompile the test executables -tests: compile-tests - -# -# Test that no symbols are missed in eglib-remap.h -# -if HOST_LINUX -test-platform: test-eglib-remap -else -if HOST_DARWIN -test-platform: test-eglib-remap -endif -endif -# The following regexp describes all symbols that start with "g_" but are not part of eglibc. -# The optional underscore prepending symbol names may or may not appear depending on the -# system and the state of the leading-underscore compiler flag. -OK_G_SYMBOLS='\<_?g_(s?list_(pre|ap)pend_(image|mempool)|concat_dir_and_file|Ctoc)\>' -test-eglib-remap: - @echo "Testing eglib remap..." - @if which nm > /dev/null; then if nm $(top_builddir)/mono/mini/mono | grep -Ev $(OK_G_SYMBOLS) | grep -E 't _?g_'; then exit 1; else exit 0; fi; fi - -test-env-options: - MONO_ENV_OPTIONS="--version" $(RUNTIME) array-init.exe | grep -q Architecture: - -# Precompile the test assemblies in parallel -compile-tests: - $(MAKE) -j4 $(TESTS_CS) $(TESTS_IL) $(TESTS_BENCH) $(TESTS_STRESS) $(TESTS_GSHARED) $(TESTSAOT_CS) $(TESTSAOT_IL) $(TESTSAOT_BENCH) $(TESTSAOT_STRESS) $(TESTSAOT_GSHARED) compile-gac-loading - -# Remove empty .stdout and .stderr files for wrench -rm-empty-logs: - @echo "Removing empty logs..." - find . '(' -name "*.stdout" -o -name "*.stderr" ')' -size 0 -exec rm {} \; - -TestDriver.dll: - $(MCS) -target:library -out:$@ $(srcdir)/../mini/TestDriver.cs $(srcdir)/../mini/TestHelpers.cs - -runtest: compile-tests - @failed=0; \ - passed=0; \ - failed_tests="";\ - if [ "x$$V" = "x1" ]; then dump_action="dump-output"; else dump_action="no-dump"; fi; \ - rm -f testlist testlist.sorted; \ - for i in $(TESTS_CS) $(TESTS_IL) $(TESTS_BENCH); do echo $${i} >> testlist; sort testlist > testlist.sorted; done; \ - for i in `cat testlist.sorted`; do \ - rm -f $${i}.so; \ - $(with_mono_path) $(JITTEST_PROG_RUN) --aot $(TEST_AOT_BUILD_FLAGS) --debug $${i} > $${i}.aotlog 2>&1 || exit 1; \ - if $(srcdir)/test-driver '$(with_mono_path) $(JITTEST_PROG_RUN)' $$i "$(DISABLED_TESTS)" "$${dump_action}" $(TEST_RUNTIME_ARGS) $(TEST_AOT_RUN_FLAGS) ; \ - then \ - passed=`expr $${passed} + 1`; \ - else \ - if [ $$? = 2 ]; then break; fi; \ - failed=`expr $${failed} + 1`; \ - failed_tests="$${failed_tests} $$i"; \ - fi \ - done; \ - echo "$${passed} test(s) passed. $${failed} test(s) did not pass."; \ - rm -f testlist testlist.sorted; \ - if [ $${failed} != 0 ]; then \ - echo -e "\nFailed tests:\n"; \ - for i in $${failed_tests}; do \ - echo $${i}; \ - if [ "x$$V" = "x1" ]; then \ - cat $${i}.stdout; \ - cat $${i}.stderr; \ - fi; \ - done; \ - exit 1; \ - fi - -runtest-managed: test-runner.exe compile-tests - $(TOOLS_RUNTIME) --debug $(TEST_RUNNER) -j a --testsuite-name "runtime" --timeout 300 --disabled "$(DISABLED_TESTS)" --runtime-args "$(TEST_RUNTIME_FLAGS)" $(TESTS_CS) $(TESTS_IL) $(TESTS_BENCH) - -runtest-managed-serial: test-runner.exe compile-tests - $(TOOLS_RUNTIME) --debug $(TEST_RUNNER) -j 1 --testsuite-name "runtime" --disabled "$(DISABLED_TESTS)" $(TESTS_CS) $(TESTS_IL) $(TESTS_BENCH) - -test-jit: - @if test x$(M) != x0; then $(MAKE) runtest-managed; else $(MAKE) runtest; fi - -testaot: - @$(MAKE) AOT=1 runtest - -testtrace: - @$(MAKE) TEST_RUNTIME_ARGS="$${TEST_RUNTIME_ARGS} --trace" runtest - -testinterp: test-runner.exe compile-tests - $(TOOLS_RUNTIME) --debug $(TEST_RUNNER) -j a --runtime-args "--interpreter" --testsuite-name "runtime-interp" --timeout 300 --disabled "$(INTERP_DISABLED_TESTS)" $(TESTS_CS) $(TESTS_IL) $(TESTS_BENCH) - -testjitspeed: $(JITTEST_PROG) compile-tests - for i in $(TESTS_BENCH); do \ - echo $$i; \ - time $(JITTEST_PROG) $$i; \ - done - -test-iomap-regression: exists.exe - @echo "Testing exists.exe..." - @MONO_IOMAP=all $(RUNTIME) exists.exe - -stresstest: compile-tests - @failed=0; \ - passed=0; \ - failed_tests="";\ - for i in $(TESTS_STRESS); do \ - if $(srcdir)/stress-runner.pl $$i ../mini/mono $(TEST_RUNTIME_ARGS); \ - then \ - passed=`expr $${passed} + 1`; \ - else \ - if [ $$? = 2 ]; then break; fi; \ - failed=`expr $${failed} + 1`; \ - failed_tests="$${failed_tests} $$i"; \ - fi \ - done; \ - echo "$${passed} test(s) passed. $${failed} test(s) did not pass."; \ - if [ $${failed} != 0 ]; then echo -e "\nFailed tests:\n"; \ - for i in $${failed_tests}; do echo $${i}; done; exit 1; fi - -testbundle: console.exe - @echo "Testing mkbundle..." - @$(MKBUNDLE) --static console.exe > mkbundle.stdout - @$(with_mono_path) MONO_CFG_DIR=$(mono_cfg_dir) ./a.out >> mkbundle.stdout - @- rm -rf a.out - -EXTRA_DIST += load-missing.il t-missing.cs load-exceptions.cs - -load-missing.dll: load-missing.il - $(Q) $(ILASM) /dll /output:$@ $< - -load-exceptions.exe t.dll: load-exceptions.cs t-missing.cs load-missing.dll $(TEST_DRIVER_DEPEND) - $(Q) $(MCS) -t:library -out:t.dll -d:FOUND t-missing.cs - $(Q) $(MCS) -r:TestDriver.dll -r:load-missing.dll -r:t.dll -out:$@ $< - $(Q) $(MCS) -t:library -out:t.dll t-missing.cs - -test-type-load: load-exceptions.exe -if !POWERPC64 - $(Q) $(RUNTIME) load-exceptions.exe > load-exceptions.exe.stdout 2> load-exceptions.exe.stderr -endif - -EXTRA_DIST += test-multi-netmodule-1-netmodule.cs test-multi-netmodule-2-dll1.cs test-multi-netmodule-3-dll2.cs test-multi-netmodule-4-exe.cs - -test-multi-netmodule-1-netmodule.netmodule: test-multi-netmodule-1-netmodule.cs - $(Q) $(MCS) -t:module -out:$@ $< -test-multi-netmodule-2-dll1.dll: test-multi-netmodule-2-dll1.cs test-multi-netmodule-1-netmodule.netmodule - $(Q) $(MCS) -addmodule:test-multi-netmodule-1-netmodule.netmodule -t:library -out:$@ $< -test-multi-netmodule-3-dll2.dll: test-multi-netmodule-3-dll2.cs test-multi-netmodule-1-netmodule.netmodule - $(Q) $(MCS) -addmodule:test-multi-netmodule-1-netmodule.netmodule -t:library -out:$@ $< -test-multi-netmodule-4-exe.exe: test-multi-netmodule-4-exe.cs test-multi-netmodule-2-dll1.dll test-multi-netmodule-3-dll2.dll - $(Q) $(MCS) -r:test-multi-netmodule-2-dll1.dll -out:$@ $< - -test-multi-netmodule: test-multi-netmodule-4-exe.exe - $(Q) $(RUNTIME) test-multi-netmodule-4-exe.exe > test-multi-netmodule-4-exe.exe.stdout 2> test-multi-netmodule-4-exe.exe.stderr - -EXTRA_DIST += custom-attr-errors.cs custom-attr-errors-lib.cs - -custom-attr-errors.exe custom-attr-errors-lib.dll: custom-attr-errors.cs custom-attr-errors-lib.cs $(TEST_DRIVER_DEPEND) - $(Q) $(MCS) /t:library -D:WITH_MEMBERS custom-attr-errors-lib.cs - $(Q) $(MCS) -r:TestDriver.dll -r:custom-attr-errors-lib.dll custom-attr-errors.cs - $(Q) $(MCS) /t:library custom-attr-errors-lib.cs - -test-cattr-type-load: custom-attr-errors.exe - $(Q) $(RUNTIME) custom-attr-errors.exe > custom-attr-errors.exe.stdout 2> custom-attr-errors.exe.stderr - -EXTRA_DIST += reflection-load-with-context-lib.cs reflection-load-with-context-second-lib.cs reflection-load-with-context.cs - -reflection-load-with-context-second-lib.dll: reflection-load-with-context-second-lib.cs - $(Q) $(MCS) /t:library -out:$@ $< -reflection-load-with-context-lib.dll: reflection-load-with-context-lib.cs reflection-load-with-context-second-lib.dll - $(Q) $(MCS) /t:library -r:reflection-load-with-context-second-lib.dll -out:$@ $< -reflection-load-with-context.exe: reflection-load-with-context-lib.dll - -test-reflection-load-with-context: reflection-load-with-context.exe - $(Q) $(RUNTIME) reflection-load-with-context.exe > reflection-load-with-context.exe.stdout 2> reflection-load-with-context.exe.stderr - - -EXTRA_DIST += debug-casts.cs -# This depends on TLS, so its not ran by default -debug-casts: debug-casts.exe - $(Q) $(RUNTIME) --debug=casts debug-casts.exe - -EXTRA_DIST += sgen-bridge.cs sgen-descriptors.cs sgen-gshared-vtype.cs sgen-bridge-major-fragmentation.cs sgen-domain-unload.cs sgen-weakref-stress.cs sgen-cementing-stress.cs sgen-case-23400.cs finalizer-wait.cs critical-finalizers.cs sgen-domain-unload-2.cs sgen-suspend.cs sgen-new-threads-dont-join-stw.cs sgen-new-threads-dont-join-stw-2.cs sgen-new-threads-collect.cs sgen-bridge-xref.cs bug-17590.cs sgen-toggleref.cs sgen-bridge-gchandle.cs - -test-sgen: - ok=; \ - $(MAKE) test-sgen-regular || ok=false; \ - $(MAKE) test-sgen-toggleref || ok=false; \ - $(MAKE) test-sgen-bridge || ok=false; \ - $(MAKE) test-sgen-bridge2 || ok=false; \ - $(MAKE) test-sgen-bridge3 || ok=false; \ - $$ok - -test-stress-sgen: - ok=; \ - $(MAKE) test-stress-sgen-regular || ok=false; \ - $(MAKE) test-stress-sgen-toggleref || ok=false; \ - $(MAKE) test-stress-sgen-bridge || ok=false; \ - $(MAKE) test-stress-sgen-bridge2 || ok=false; \ - $(MAKE) test-stress-sgen-bridge3 || ok=false; \ - $$ok - -TESTS_SGEN_REGULAR_SRC = \ - finalizer-wait.cs \ - critical-finalizers.cs \ - sgen-descriptors.cs \ - sgen-gshared-vtype.cs \ - sgen-weakref-stress.cs \ - sgen-cementing-stress.cs \ - sgen-case-23400.cs \ - sgen-new-threads-dont-join-stw.cs \ - sgen-new-threads-dont-join-stw-2.cs \ - sgen-new-threads-collect.cs \ - gc-graystack-stress.cs \ - bug-17590.cs \ - sgen-domain-unload.cs \ - sgen-domain-unload-2.cs - -TESTS_SGEN_REGULAR=$(filter-out $(DISABLED_TESTS),$(TESTS_SGEN_REGULAR_SRC:.cs=.exe)) - -if FULL_AOT_TESTS -TESTSAOT_SGEN_REGULAR=$(TESTS_SGEN_REGULAR:.exe=.exe$(PLATFORM_AOT_SUFFIX)) -endif - -if HYBRID_AOT_TESTS -TESTSAOT_SGEN_REGULAR=$(TESTS_SGEN_REGULAR:.exe=.exe$(PLATFORM_AOT_SUFFIX)) -endif - -test-sgen-regular: $(TESTS_SGEN_REGULAR) $(TESTSAOT_SGEN_REGULAR) - ok=; \ - $(MAKE) test-sgen-regular-ms-simple || ok=false; \ - $(MAKE) test-sgen-regular-ms-conc-simple || ok=false; \ - $$ok - -test-stress-sgen-regular: $(TESTS_SGEN_REGULAR) $(TESTSAOT_SGEN_REGULAR) - ok=; \ - $(MAKE) test-sgen-regular-ms-simple MONO_TESTS_STRESS=1 || ok=false; \ - $(MAKE) test-sgen-regular-ms-conc-simple MONO_TESTS_STRESS=1 || ok=false; \ - $(MAKE) test-sgen-regular-ms-conc-par-simple MONO_TESTS_STRESS=1 || ok=false; \ - $(MAKE) test-sgen-regular-ms-conc-split MONO_TESTS_STRESS=1 || ok=false; \ - $(MAKE) test-sgen-regular-ms-conc-split-95-clear-at-gc MONO_TESTS_STRESS=1 || ok=false; \ - $(MAKE) test-sgen-regular-ms-conc-par-simple-par-dyn MONO_TESTS_STRESS=1 || ok=false; \ - $(MAKE) test-sgen-regular-ms-conc-par-simple-par-512k MONO_TESTS_STRESS=1 || ok=false; \ - $(MAKE) test-sgen-regular-ms-conc-par-simple-par-32m MONO_TESTS_STRESS=1 || ok=false; \ - $(MAKE) test-sgen-regular-ms-conc-par-simple-par-dyn-clear-at-gc MONO_TESTS_STRESS=1 || ok=false; \ - $$ok - -test-sgen-regular-ms-simple: $(TESTS_SGEN_REGULAR) $(TESTSAOT_SGEN_REGULAR) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug= --gc-params=major=marksweep,minor=simple" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_REGULAR) -test-sgen-regular-ms-conc-simple: $(TESTS_SGEN_REGULAR) $(TESTSAOT_SGEN_REGULAR) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug= --gc-params=major=marksweep-conc,minor=simple" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_REGULAR) -test-sgen-regular-ms-conc-par-simple: $(TESTS_SGEN_REGULAR) $(TESTSAOT_SGEN_REGULAR) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug= --gc-params=major=marksweep-conc-par,minor=simple" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_REGULAR) -test-sgen-regular-ms-conc-split: $(TESTS_SGEN_REGULAR) $(TESTSAOT_SGEN_REGULAR) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug= --gc-params=major=marksweep-conc,minor=split" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_REGULAR) -test-sgen-regular-ms-conc-split-95-clear-at-gc: $(TESTS_SGEN_REGULAR) $(TESTSAOT_SGEN_REGULAR) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=clear-at-gc --gc-params=major=marksweep-conc,minor=split,alloc-ratio=95" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_REGULAR) -test-sgen-regular-ms-conc-par-simple-par-dyn: $(TESTS_SGEN_REGULAR) $(TESTSAOT_SGEN_REGULAR) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug= --gc-params=major=marksweep-conc-par,minor=simple-par,dynamic-nursery" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_REGULAR) -test-sgen-regular-ms-conc-par-simple-par-512k: $(TESTS_SGEN_REGULAR) $(TESTSAOT_SGEN_REGULAR) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug= --gc-params=major=marksweep-conc-par,minor=simple-par,nursery-size=512k" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_REGULAR) -test-sgen-regular-ms-conc-par-simple-par-32m: $(TESTS_SGEN_REGULAR) $(TESTSAOT_SGEN_REGULAR) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug= --gc-params=major=marksweep-conc-par,minor=simple-par,nursery-size=32m" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_REGULAR) -test-sgen-regular-ms-conc-par-simple-par-dyn-clear-at-gc: $(TESTS_SGEN_REGULAR) $(TESTSAOT_SGEN_REGULAR) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=clear-at-gc --gc-params=major=marksweep-conc-par,minor=simple-par,dynamic-nursery" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_REGULAR) - -TESTS_SGEN_TOGGLEREF_SRC= \ - sgen-toggleref.cs - -TESTS_SGEN_TOGGLEREF=$(filter-out $(DISABLED_TESTS),$(TESTS_SGEN_TOGGLEREF_SRC:.cs=.exe)) - -if FULL_AOT_TESTS -TESTSAOT_SGEN_TOGGLEREF=$(TESTS_SGEN_TOGGLEREF:.exe=.exe$(PLATFORM_AOT_SUFFIX)) -endif - -if HYBRID_AOT_TESTS -TESTSAOT_SGEN_TOGGLEREF=$(TESTS_SGEN_TOGGLEREF:.exe=.exe$(PLATFORM_AOT_SUFFIX)) -endif - -test-sgen-toggleref: $(TESTS_SGEN_TOGGLEREF) $(TESTSAOT_SGEN_TOGGLEREF) - ok=; \ - $(MAKE) test-sgen-toggleref-ms-simple || ok=false; \ - $(MAKE) test-sgen-toggleref-ms-conc-simple || ok=false; \ - $$ok - -test-stress-sgen-toggleref: $(TESTS_SGEN_TOGGLEREF) $(TESTSAOT_SGEN_TOGGLEREF) - ok=; \ - $(MAKE) test-sgen-toggleref-ms-simple MONO_TESTS_STRESS=1 || ok=false; \ - $(MAKE) test-sgen-toggleref-ms-conc-simple MONO_TESTS_STRESS=1 || ok=false; \ - $(MAKE) test-sgen-toggleref-ms-conc-par-simple MONO_TESTS_STRESS=1 || ok=false; \ - $(MAKE) test-sgen-toggleref-ms-conc-split MONO_TESTS_STRESS=1 || ok=false; \ - $(MAKE) test-sgen-toggleref-ms-conc-split-95-clear-at-gc MONO_TESTS_STRESS=1 || ok=false; \ - $(MAKE) test-sgen-toggleref-ms-conc-par-simple-par-dyn MONO_TESTS_STRESS=1 || ok=false; \ - $(MAKE) test-sgen-toggleref-ms-conc-par-simple-par-512k MONO_TESTS_STRESS=1 || ok=false; \ - $(MAKE) test-sgen-toggleref-ms-conc-par-simple-par-32m MONO_TESTS_STRESS=1 || ok=false; \ - $(MAKE) test-sgen-toggleref-ms-conc-par-simple-par-dyn-clear-at-gc MONO_TESTS_STRESS=1 || ok=false; \ - $$ok - -test-sgen-toggleref-ms-simple: $(TESTS_SGEN_TOGGLEREF) $(TESTSAOT_SGEN_TOGGLEREF) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug= --gc-params=toggleref-test,major=marksweep,minor=simple" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_TOGGLEREF) -test-sgen-toggleref-ms-conc-simple: $(TESTS_SGEN_TOGGLEREF) $(TESTSAOT_SGEN_TOGGLEREF) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug= --gc-params=toggleref-test,major=marksweep-conc,minor=simple" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_TOGGLEREF) -test-sgen-toggleref-ms-conc-par-simple: $(TESTS_SGEN_TOGGLEREF) $(TESTSAOT_SGEN_TOGGLEREF) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug= --gc-params=toggleref-test,major=marksweep-conc-par,minor=simple" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_TOGGLEREF) -test-sgen-toggleref-ms-conc-split: $(TESTS_SGEN_TOGGLEREF) $(TESTSAOT_SGEN_TOGGLEREF) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug= --gc-params=toggleref-test,major=marksweep-conc,minor=split" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_TOGGLEREF) -test-sgen-toggleref-ms-conc-split-95-clear-at-gc: $(TESTS_SGEN_TOGGLEREF) $(TESTSAOT_SGEN_TOGGLEREF) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=clear-at-gc --gc-params=toggleref-test,major=marksweep-conc,minor=split,alloc-ratio=95" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_TOGGLEREF) -test-sgen-toggleref-ms-conc-par-simple-par-dyn: $(TESTS_SGEN_TOGGLEREF) $(TESTSAOT_SGEN_TOGGLEREF) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug= --gc-params=toggleref-test,major=marksweep-conc-par,minor=simple-par,dynamic-nursery" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_TOGGLEREF) -test-sgen-toggleref-ms-conc-par-simple-par-512k: $(TESTS_SGEN_TOGGLEREF) $(TESTSAOT_SGEN_TOGGLEREF) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug= --gc-params=toggleref-test,major=marksweep-conc-par,minor=simple-par,nursery-size=512k" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_TOGGLEREF) -test-sgen-toggleref-ms-conc-par-simple-par-32m: $(TESTS_SGEN_TOGGLEREF) $(TESTSAOT_SGEN_TOGGLEREF) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug= --gc-params=toggleref-test,major=marksweep-conc-par,minor=simple-par,nursery-size=32m" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_TOGGLEREF) -test-sgen-toggleref-ms-conc-par-simple-par-dyn-clear-at-gc: $(TESTS_SGEN_TOGGLEREF) $(TESTSAOT_SGEN_TOGGLEREF) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=clear-at-gc --gc-params=toggleref-test,major=marksweep-conc-par,minor=simple-par,dynamic-nursery" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_TOGGLEREF) - -TESTS_SGEN_BRIDGE_SRC= \ - sgen-bridge.cs \ - sgen-bridge-major-fragmentation.cs - -TESTS_SGEN_BRIDGE=$(filter-out $(DISABLED_TESTS),$(TESTS_SGEN_BRIDGE_SRC:.cs=.exe)) - -if FULL_AOT_TESTS -TESTSAOT_SGEN_BRIDGE=$(TESTS_SGEN_BRIDGE:.exe=.exe$(PLATFORM_AOT_SUFFIX)) -endif - -if HYBRID_AOT_TESTS -TESTSAOT_SGEN_BRIDGE=$(TESTS_SGEN_BRIDGE:.exe=.exe$(PLATFORM_AOT_SUFFIX)) -endif - -test-sgen-bridge: $(TESTS_SGEN_BRIDGE) $(TESTSAOT_SGEN_BRIDGE) - ok=; \ - $(MAKE) test-sgen-bridge-ms-simple-tarjan-bridge || ok=false; \ - $(MAKE) test-sgen-bridge-ms-conc-simple-tarjan-bridge || ok=false; \ - $$ok - -test-stress-sgen-bridge: $(TESTS_SGEN_BRIDGE) $(TESTSAOT_SGEN_BRIDGE) - ok=; \ - $(MAKE) test-sgen-bridge-ms-simple-tarjan-bridge MONO_TESTS_STRESS=1 || ok=false; \ - $(MAKE) test-sgen-bridge-ms-conc-simple-tarjan-bridge MONO_TESTS_STRESS=1 || ok=false; \ - $(MAKE) test-sgen-bridge-ms-conc-split-tarjan-bridge MONO_TESTS_STRESS=1 || ok=false; \ - $(MAKE) test-sgen-bridge-ms-conc-simple-new-bridge MONO_TESTS_STRESS=1 || ok=false; \ - $(MAKE) test-sgen-bridge-ms-conc-simple-old-bridge MONO_TESTS_STRESS=1 || ok=false; \ - $(MAKE) test-sgen-bridge-ms-conc-par-simple-par-dyn-tarjan-bridge MONO_TESTS_STRESS=1 || ok=false; \ - $(MAKE) test-sgen-bridge-ms-conc-par-simple-par-512k-tarjan-bridge MONO_TESTS_STRESS=1 || ok=false; \ - $(MAKE) test-sgen-bridge-ms-conc-par-simple-par-32m-tarjan-bridge MONO_TESTS_STRESS=1 || ok=false; \ - $$ok - -test-sgen-bridge-ms-simple-tarjan-bridge: $(TESTS_SGEN_BRIDGE) $(TESTSAOT_SGEN_BRIDGE) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=Bridge --gc-params=major=marksweep,minor=simple,bridge-implementation=tarjan" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE) -test-sgen-bridge-ms-conc-simple-tarjan-bridge: $(TESTS_SGEN_BRIDGE) $(TESTSAOT_SGEN_BRIDGE) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=Bridge --gc-params=major=marksweep-conc,minor=simple,bridge-implementation=tarjan" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE) -test-sgen-bridge-ms-conc-split-tarjan-bridge: $(TESTS_SGEN_BRIDGE) $(TESTSAOT_SGEN_BRIDGE) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=Bridge --gc-params=major=marksweep-conc,minor=split,bridge-implementation=tarjan" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE) -test-sgen-bridge-ms-conc-simple-new-bridge: $(TESTS_SGEN_BRIDGE) $(TESTSAOT_SGEN_BRIDGE) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=Bridge --gc-params=major=marksweep-conc,minor=simple,bridge-implementation=new" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE) -test-sgen-bridge-ms-conc-simple-old-bridge: $(TESTS_SGEN_BRIDGE) $(TESTSAOT_SGEN_BRIDGE) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=Bridge --gc-params=major=marksweep-conc,minor=simple,bridge-implementation=old" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE) -test-sgen-bridge-ms-conc-par-simple-par-dyn-tarjan-bridge: $(TESTS_SGEN_BRIDGE) $(TESTSAOT_SGEN_BRIDGE) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=Bridge --gc-params=major=marksweep-conc-par,minor=simple-par,dynamic-nursery,bridge-implementation=tarjan" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE) -test-sgen-bridge-ms-conc-par-simple-par-512k-tarjan-bridge: $(TESTS_SGEN_BRIDGE) $(TESTSAOT_SGEN_BRIDGE) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=Bridge --gc-params=major=marksweep-conc-par,minor=simple-par,nursery-size=512k,bridge-implementation=tarjan" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE) -test-sgen-bridge-ms-conc-par-simple-par-32m-tarjan-bridge: $(TESTS_SGEN_BRIDGE) $(TESTSAOT_SGEN_BRIDGE) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=Bridge --gc-params=major=marksweep-conc-par,minor=simple-par,nursery-size=32m,bridge-implementation=tarjan" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE) - -TESTS_SGEN_BRIDGE2_SRC= \ - sgen-bridge-xref.cs - -TESTS_SGEN_BRIDGE2=$(filter-out $(DISABLED_TESTS),$(TESTS_SGEN_BRIDGE2_SRC:.cs=.exe)) - -if FULL_AOT_TESTS -TESTSAOT_SGEN_BRIDGE2=$(TESTS_SGEN_BRIDGE2:.exe=.exe$(PLATFORM_AOT_SUFFIX)) -endif - -if HYBRID_AOT_TESTS -TESTSAOT_SGEN_BRIDGE2=$(TESTS_SGEN_BRIDGE2:.exe=.exe$(PLATFORM_AOT_SUFFIX)) -endif - -test-sgen-bridge2: $(TESTS_SGEN_BRIDGE2) $(TESTSAOT_SGEN_BRIDGE2) - ok=; \ - $(MAKE) test-sgen-bridge2-ms-simple-tarjan-bridge || ok=false; \ - $(MAKE) test-sgen-bridge2-ms-conc-simple-tarjan-bridge || ok=false; \ - $$ok - -test-stress-sgen-bridge2: $(TESTS_SGEN_BRIDGE2) $(TESTSAOT_SGEN_BRIDGE2) - ok=; \ - $(MAKE) test-sgen-bridge2-ms-simple-tarjan-bridge MONO_TESTS_STRESS=1 || ok=false; \ - $(MAKE) test-sgen-bridge2-ms-conc-simple-tarjan-bridge MONO_TESTS_STRESS=1 || ok=false; \ - $(MAKE) test-sgen-bridge2-ms-conc-split-tarjan-bridge MONO_TESTS_STRESS=1 || ok=false; \ - $(MAKE) test-sgen-bridge2-ms-conc-simple-new-bridge MONO_TESTS_STRESS=1 || ok=false; \ - $(MAKE) test-sgen-bridge2-ms-conc-simple-old-bridge MONO_TESTS_STRESS=1 || ok=false; \ - $(MAKE) test-sgen-bridge2-ms-conc-par-simple-par-dyn-tarjan-bridge MONO_TESTS_STRESS=1 || ok=false; \ - $(MAKE) test-sgen-bridge2-ms-conc-par-simple-par-512k-tarjan-bridge MONO_TESTS_STRESS=1 || ok=false; \ - $(MAKE) test-sgen-bridge2-ms-conc-par-simple-par-32m-tarjan-bridge MONO_TESTS_STRESS=1 || ok=false; \ - $$ok - -test-sgen-bridge2-ms-simple-tarjan-bridge: $(TESTS_SGEN_BRIDGE2) $(TESTSAOT_SGEN_BRIDGE2) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=2Bridge --gc-params=major=marksweep,minor=simple,bridge-implementation=tarjan" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE2) -test-sgen-bridge2-ms-conc-simple-tarjan-bridge: $(TESTS_SGEN_BRIDGE2) $(TESTSAOT_SGEN_BRIDGE2) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=2Bridge --gc-params=major=marksweep-conc,minor=simple,bridge-implementation=tarjan" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE2) -test-sgen-bridge2-ms-conc-split-tarjan-bridge: $(TESTS_SGEN_BRIDGE2) $(TESTSAOT_SGEN_BRIDGE2) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=2Bridge --gc-params=major=marksweep-conc,minor=split,bridge-implementation=tarjan" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE2) -test-sgen-bridge2-ms-conc-simple-new-bridge: $(TESTS_SGEN_BRIDGE2) $(TESTSAOT_SGEN_BRIDGE2) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=2Bridge --gc-params=major=marksweep-conc,minor=simple,bridge-implementation=new" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE2) -test-sgen-bridge2-ms-conc-simple-old-bridge: $(TESTS_SGEN_BRIDGE2) $(TESTSAOT_SGEN_BRIDGE2) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=2Bridge --gc-params=major=marksweep-conc,minor=simple,bridge-implementation=old" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE2) -test-sgen-bridge2-ms-conc-par-simple-par-dyn-tarjan-bridge: $(TESTS_SGEN_BRIDGE2) $(TESTSAOT_SGEN_BRIDGE2) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=2Bridge --gc-params=major=marksweep-conc-par,minor=simple-par,dynamic-nursery,bridge-implementation=tarjan" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE2) -test-sgen-bridge2-ms-conc-par-simple-par-512k-tarjan-bridge: $(TESTS_SGEN_BRIDGE2) $(TESTSAOT_SGEN_BRIDGE2) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=2Bridge --gc-params=major=marksweep-conc-par,minor=simple-par,nursery-size=512k,bridge-implementation=tarjan" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE2) -test-sgen-bridge2-ms-conc-par-simple-par-32m-tarjan-bridge: $(TESTS_SGEN_BRIDGE2) $(TESTSAOT_SGEN_BRIDGE2) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=2Bridge --gc-params=major=marksweep-conc-par,minor=simple-par,nursery-size=32m,bridge-implementation=tarjan" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE2) - -TESTS_SGEN_BRIDGE3_SRC= \ - sgen-bridge-gchandle.cs - -TESTS_SGEN_BRIDGE3=$(filter-out $(DISABLED_TESTS),$(TESTS_SGEN_BRIDGE3_SRC:.cs=.exe)) - -if FULL_AOT_TESTS -TESTSAOT_SGEN_BRIDGE3=$(TESTS_SGEN_BRIDGE3:.exe=.exe$(PLATFORM_AOT_SUFFIX)) -endif - -if HYBRID_AOT_TESTS -TESTSAOT_SGEN_BRIDGE3=$(TESTS_SGEN_BRIDGE3:.exe=.exe$(PLATFORM_AOT_SUFFIX)) -endif - -test-sgen-bridge3: $(TESTS_SGEN_BRIDGE3) $(TESTSAOT_SGEN_BRIDGE3) - ok=; \ - $(MAKE) test-sgen-bridge3-ms-simple-tarjan-bridge || ok=false; \ - $(MAKE) test-sgen-bridge3-ms-conc-simple-tarjan-bridge || ok=false; \ - $$ok - -test-stress-sgen-bridge3: $(TESTS_SGEN_BRIDGE3) $(TESTSAOT_SGEN_BRIDGE3) - ok=; \ - $(MAKE) test-sgen-bridge3-ms-simple-tarjan-bridge MONO_TESTS_STRESS=1 || ok=false; \ - $(MAKE) test-sgen-bridge3-ms-conc-simple-tarjan-bridge MONO_TESTS_STRESS=1 || ok=false; \ - $(MAKE) test-sgen-bridge3-ms-conc-split-tarjan-bridge MONO_TESTS_STRESS=1 || ok=false; \ - $(MAKE) test-sgen-bridge3-ms-conc-simple-new-bridge MONO_TESTS_STRESS=1 || ok=false; \ - $(MAKE) test-sgen-bridge3-ms-conc-simple-old-bridge MONO_TESTS_STRESS=1 || ok=false; \ - $(MAKE) test-sgen-bridge3-ms-conc-par-simple-par-dyn-tarjan-bridge MONO_TESTS_STRESS=1 || ok=false; \ - $(MAKE) test-sgen-bridge3-ms-conc-par-simple-par-512k-tarjan-bridge MONO_TESTS_STRESS=1 || ok=false; \ - $(MAKE) test-sgen-bridge3-ms-conc-par-simple-par-32m-tarjan-bridge MONO_TESTS_STRESS=1 || ok=false; \ - $$ok - -test-sgen-bridge3-ms-simple-tarjan-bridge: $(TESTS_SGEN_BRIDGE3) $(TESTSAOT_SGEN_BRIDGE3) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=3Bridge --gc-params=major=marksweep,minor=simple,bridge-implementation=tarjan" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE3) -test-sgen-bridge3-ms-conc-simple-tarjan-bridge: $(TESTS_SGEN_BRIDGE3) $(TESTSAOT_SGEN_BRIDGE3) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=3Bridge --gc-params=major=marksweep-conc,minor=simple,bridge-implementation=tarjan" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE3) -test-sgen-bridge3-ms-conc-split-tarjan-bridge: $(TESTS_SGEN_BRIDGE3) $(TESTSAOT_SGEN_BRIDGE3) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=3Bridge --gc-params=major=marksweep-conc,minor=split,bridge-implementation=tarjan" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE3) -test-sgen-bridge3-ms-conc-simple-new-bridge: $(TESTS_SGEN_BRIDGE3) $(TESTSAOT_SGEN_BRIDGE3) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=3Bridge --gc-params=major=marksweep-conc,minor=simple,bridge-implementation=new" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE3) -test-sgen-bridge3-ms-conc-simple-old-bridge: $(TESTS_SGEN_BRIDGE3) $(TESTSAOT_SGEN_BRIDGE3) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=3Bridge --gc-params=major=marksweep-conc,minor=simple,bridge-implementation=old" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE3) -test-sgen-bridge3-ms-conc-par-simple-par-dyn-tarjan-bridge: $(TESTS_SGEN_BRIDGE3) $(TESTSAOT_SGEN_BRIDGE3) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=3Bridge --gc-params=major=marksweep-conc-par,minor=simple-par,dynamic-nursery,bridge-implementation=tarjan" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE3) -test-sgen-bridge3-ms-conc-par-simple-par-512k-tarjan-bridge: $(TESTS_SGEN_BRIDGE3) $(TESTSAOT_SGEN_BRIDGE3) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=3Bridge --gc-params=major=marksweep-conc-par,minor=simple-par,nursery-size=512k,bridge-implementation=tarjan" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE3) -test-sgen-bridge3-ms-conc-par-simple-par-32m-tarjan-bridge: $(TESTS_SGEN_BRIDGE3) $(TESTSAOT_SGEN_BRIDGE3) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=bridge=3Bridge --gc-params=major=marksweep-conc-par,minor=simple-par,nursery-size=32m,bridge-implementation=tarjan" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_BRIDGE3) - -TESTS_SGEN_OOM_SRC = \ - sgen-oom-cementing-stress.cs \ - sgen-oom-new-threads-dont-join-stw-2.cs \ - sgen-oom-bridge-major-fragmentation.cs \ - gc-oom-handling.cs \ - gc-oom-handling2.cs - -TESTS_SGEN_OOM=$(filter-out $(DISABLED_TESTS),$(TESTS_SGEN_OOM_SRC:.cs=.exe)) - -if FULL_AOT_TESTS -TESTSAOT_SGEN_OOM=$(TESTS_SGEN_OOM:.exe=.exe$(PLATFORM_AOT_SUFFIX)) -endif - -if HYBRID_AOT_TESTS -TESTSAOT_SGEN_OOM=$(TESTS_SGEN_OOM:.exe=.exe$(PLATFORM_AOT_SUFFIX)) -endif - -tests-sgen-oom: $(TESTS_SGEN_OOM) $(TESTSAOT_SGEN_OOM) test-runner.exe sgen-cementing-stress.exe sgen-new-threads-dont-join-stw-2.exe sgen-bridge-major-fragmentation.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) $(TEST_RUNNER_ARGS) --testsuite-name $@ --runtime-args "--gc=sgen --gc-debug=max-valloc-size=50M,bridge=Bridge" --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_SGEN_OOM) - -AOT_CONFIGURATIONS= \ - "|regular" \ - "--gc=boehm|boehm" - -#LLVM crashes, got to fix it first. -# "--llvm|llvm" \ -# "--llvm --gc=boehm|llvm+boehm" - - -test-aot: - @failed=0; \ - passed=0; \ - failed_tests="";\ - profile=$(DEFAULT_PROFILE); \ - tmpfile=`mktemp -t mono_aot_outputXXXXXX` || exit 1; \ - rm -f test-aot-$${name}.stdout test-aot-$${name}.stderr; \ - for assembly in $(mcs_topdir)/class/lib/$$profile/*.dll ; do \ - asm_name=`basename $$assembly`; \ - echo "... $$asm_name"; \ - for conf in $(AOT_CONFIGURATIONS); do \ - name=`echo $$conf | cut -d\| -f 2`; \ - params=`echo $$conf | cut -d\| -f 1`; \ - test_name="$${asm_name}|$${name}"; \ - echo " $$test_name"; \ - if MONO_PATH=$(mcs_topdir)/class/lib/$$profile $(JITTEST_PROG_RUN) $$params --aot=outfile=$$tmpfile $$assembly >> test-aot-$${name}.stdout 2>> test-aot-$${name}.stderr; \ - then \ - passed=`expr $${passed} + 1`; \ - else \ - failed=`expr $${failed} + 1`; \ - failed_tests="$${failed_tests} $$test_name"; \ - fi \ - done; \ - done; \ - rm $$tmpfile; \ - echo "$${passed} test(s) passed. $${failed} test(s) did not pass."; \ - if [ $${failed} != 0 ]; then echo -e "\nFailed tests:\n"; \ - for i in $${failed_tests}; do echo $${i}; done; exit 1; fi - - -# Generated tests for runtime invoke -EXTRA_DIST += gen-runtime-invoke.cs - -runtime-invoke.gen.cs: gen-runtime-invoke.exe - $(Q) $(RUNTIME) gen-runtime-invoke.exe > runtime-invoke.gen.cs - -EXTRA_DIST += make-imt-test.cs - -imt_big_iface_test.cs: make-imt-test.exe - $(Q) $(RUNTIME) make-imt-test.exe > imt_big_iface_test.cs - -EXTRA_DIST += test-inline-call-stack-library.cs test-inline-call-stack.cs - -test-inline-call-stack-library.dll: $(srcdir)/test-inline-call-stack-library.cs - $(MCS) -t:library -out:$@ $< - -test-inline-call-stack.exe$(PLATFORM_AOT_SUFFIX): test-inline-call-stack-library.dll$(PLATFORM_AOT_SUFFIX) -test-inline-call-stack.exe: test-inline-call-stack.cs test-inline-call-stack-library.dll $(TEST_DRIVER_DEPEND) - $(MCS) -r:TestDriver.dll -r:test-inline-call-stack-library.dll -out:$@ $< - -EXTRA_DIST += unhandled-exception-base-configuration.config -EXTRA_DIST += unhandled-exception-legacy-configuration.config -EXTRA_DIST += appdomain-unload.exe.config -EXTRA_DIST += unhandled-exception-test-case.2.cs -EXTRA_DIST += unhandled-exception-test-runner.2.cs -unhandled-exception-test-case.1.cs: unhandled-exception-test-case.2.cs - cp unhandled-exception-test-case.2.cs unhandled-exception-test-case.1.cs -unhandled-exception-test-case-legacy.1.cs: unhandled-exception-test-case.1.cs - cp unhandled-exception-test-case.1.cs unhandled-exception-test-case-legacy.1.cs -unhandled-exception-test-case-legacy.2.cs: unhandled-exception-test-case.2.cs - cp unhandled-exception-test-case.2.cs unhandled-exception-test-case-legacy.2.cs -unhandled-exception-config_files: unhandled-exception-base-configuration.config unhandled-exception-legacy-configuration.config - cp unhandled-exception-base-configuration.config unhandled-exception-test-case.1.exe.config - cp unhandled-exception-base-configuration.config unhandled-exception-test-case.2.exe.config - cp unhandled-exception-legacy-configuration.config unhandled-exception-test-case-legacy.1.exe.config - cp unhandled-exception-legacy-configuration.config unhandled-exception-test-case-legacy.2.exe.config - -unhandled-exception-test-runner.2.exe: unhandled-exception-config_files unhandled-exception-test-case.1.exe unhandled-exception-test-case-legacy.1.exe unhandled-exception-test-case.2.exe unhandled-exception-test-case-legacy.2.exe - -test-unhandled-exception: unhandled-exception-test-runner.2.exe - $(Q) $(RUNTIME) unhandled-exception-test-runner.2.exe RUNTIME:../mini/mono,GTC:F - -safehandle.2.exe winx64structs.exe thunks.exe pinvoke3.exe pinvoke2.exe pinvoke-2.2.exe pinvoke17.exe pinvoke13.exe \ - pinvoke11.exe pinvoke_ppcs.exe pinvoke_ppci.exe pinvoke_ppcf.exe pinvoke_ppcd.exe pinvoke_ppcc.exe pinvoke.exe \ - marshalbool.exe marshal9.exe marshal5.exe marshal.exe handleref.exe cominterop.exe bug-Xamarin-5278.exe \ - bug-58782-plain-throw.exe bug-58782-capture-and-throw.exe: libtest.la - -event-get.2.exe$(PLATFORM_AOT_SUFFIX): event-il.exe$(PLATFORM_AOT_SUFFIX) -event-get.2.exe: event-il.exe - -module-cctor-loader.2.exe$(PLATFORM_AOT_SUFFIX): module-cctor.exe$(PLATFORM_AOT_SUFFIX) -module-cctor-loader.2.exe: module-cctor.exe - -reference-loader.exe$(PLATFORM_AOT_SUFFIX): TestingReferenceAssembly.dll$(PLATFORM_AOT_SUFFIX) TestingReferenceReferenceAssembly.dll$(PLATFORM_AOT_SUFFIX) -reference-loader.exe: TestingReferenceAssembly.dll TestingReferenceReferenceAssembly.dll - -assemblyresolve_asm.dll$(PLATFORM_AOT_SUFFIX): assemblyresolve_asm.dll assemblyresolve_deps/Test.dll$(PLATFORM_AOT_SUFFIX) - MONO_PATH="assemblyresolve_deps:$(CLASS)" $(top_builddir)/runtime/mono-wrapper $(TEST_AOT_BUILD_FLAGS) assemblyresolve_asm.dll -assemblyresolve_deps/Test.dll$(PLATFORM_AOT_SUFFIX): assemblyresolve_deps/Test.dll assemblyresolve_deps/TestBase.dll$(PLATFORM_AOT_SUFFIX) - -EXTRA_DIST += assemblyresolve_TestBase.cs assemblyresolve_Test.cs assemblyresolve_asm.cs -assemblyresolve_deps: - mkdir -p assemblyresolve_deps -assemblyresolve_deps/TestBase.dll: assemblyresolve_deps $(srcdir)/assemblyresolve_TestBase.cs - $(MCS) -target:library -out:assemblyresolve_deps/TestBase.dll $(srcdir)/assemblyresolve_TestBase.cs -assemblyresolve_deps/Test.dll: assemblyresolve_deps assemblyresolve_deps/TestBase.dll $(srcdir)/assemblyresolve_Test.cs - $(MCS) -target:library -r:assemblyresolve_deps/TestBase.dll -out:assemblyresolve_deps/Test.dll $(srcdir)/assemblyresolve_Test.cs -assemblyresolve_asm.dll: assemblyresolve_deps/Test.dll $(srcdir)/assemblyresolve_asm.cs - $(MCS) -target:library -r:assemblyresolve_deps/TestBase.dll -r:assemblyresolve_deps/Test.dll -out:assemblyresolve_asm.dll $(srcdir)/assemblyresolve_asm.cs - -assemblyresolve_event3.exe$(PLATFORM_AOT_SUFFIX): assemblyresolve_asm.dll$(PLATFORM_AOT_SUFFIX) assemblyresolve_deps/Test.dll$(PLATFORM_AOT_SUFFIX) assemblyresolve_deps/TestBase.dll$(PLATFORM_AOT_SUFFIX) -assemblyresolve_event3.exe: assemblyresolve_asm.dll assemblyresolve_deps/Test.dll assemblyresolve_deps/TestBase.dll - -assemblyresolve_event4.exe$(PLATFORM_AOT_SUFFIX): assemblyresolve_deps/Test.dll$(PLATFORM_AOT_SUFFIX) assemblyresolve_deps/TestBase.dll$(PLATFORM_AOT_SUFFIX) -assemblyresolve_event4.exe: assemblyresolve_deps/Test.dll assemblyresolve_deps/TestBase.dll - -EXTRA_DIST += assemblyresolve_event5_label.cs assemblyresolve_event5_helper.cs -assemblyresolve_deps/assemblyresolve_event5_label.dll: assemblyresolve_event5_label.cs assemblyresolve_deps - $(MCS) -target:library -out:assemblyresolve_deps/assemblyresolve_event5_label.dll $(srcdir)/assemblyresolve_event5_label.cs -assemblyresolve_event5_helper.dll: assemblyresolve_event5_helper.cs assemblyresolve_deps/assemblyresolve_event5_label.dll - $(MCS) -target:library -out:assemblyresolve_event5_helper.dll -r:assemblyresolve_deps/assemblyresolve_event5_label.dll $(srcdir)/assemblyresolve_event5_helper.cs -assemblyresolve_event5.exe: assemblyresolve_event5_helper.dll - -assemblyresolve_event6.exe$(PLATFORM_AOT_SUFFIX): assemblyresolve_asm.dll$(PLATFORM_AOT_SUFFIX) assemblyresolve_deps/Test.dll$(PLATFORM_AOT_SUFFIX) assemblyresolve_deps/TestBase.dll$(PLATFORM_AOT_SUFFIX) -assemblyresolve_event6.exe: assemblyresolve_asm.dll assemblyresolve_deps/Test.dll assemblyresolve_deps/TestBase.dll - -# We use 'test-support-files' to handle an ordering issue between the 'mono/' and 'runtime/' directories -bug-80307.exe: $(srcdir)/bug-80307.cs - $(MCS) -r:$(CLASS)/System.Web.dll -out:$@ $(srcdir)/bug-80307.cs - cd $(top_builddir)/runtime && $(MAKE) test-support-files - -EXTRA_DIST += bug-81673-interface.cs - -bug-81673.exe$(PLATFORM_AOT_SUFFIX): bug-81673-interface.dll$(PLATFORM_AOT_SUFFIX) -bug-81673.exe bug-81673-interface.dll: $(srcdir)/bug-81673.cs $(srcdir)/bug-81673-interface.cs - $(MCS) -target:library -out:bug-81673-interface.dll $(srcdir)/bug-81673-interface.cs - $(MCS) -r:bug-81673-interface.dll -out:bug-81673.exe $(srcdir)/bug-81673.cs - $(MCS) -define:WITH_STOP -target:library -out:bug-81673-interface.dll $(srcdir)/bug-81673-interface.cs - -EXTRA_DIST += bug-36848-a.cs - -bug-36848.exe$(PLATFORM_AOT_SUFFIX): bug-36848-a.dll$(PLATFORM_AOT_SUFFIX) -bug-36848.exe bug-36848-a.dll: $(srcdir)/bug-36848.cs $(srcdir)/bug-36848-a.cs - $(MCS) -target:library -out:bug-36848-a.dll $(srcdir)/bug-36848-a.cs - $(MCS) -r:bug-36848-a.dll -out:bug-36848.exe $(srcdir)/bug-36848.cs - $(MCS) -define:WITH_STOP -target:library -out:bug-36848-a.dll $(srcdir)/bug-36848-a.cs - -EXTRA_DIST += bug-81691-a.cs bug-81691-b.cs - -bug-81691.exe$(PLATFORM_AOT_SUFFIX): bug-81691-b.dll$(PLATFORM_AOT_SUFFIX) -bug-81691.exe bug-81691-a.dll bug-81691-b.dll: $(srcdir)/bug-81691.cs $(srcdir)/bug-81691-a.cs $(srcdir)/bug-81691-b.cs - $(MCS) -target:library -out:bug-81691-a.dll $(srcdir)/bug-81691-a.cs - $(MCS) -r:bug-81691-a.dll -target:library -out:bug-81691-b.dll $(srcdir)/bug-81691-b.cs - $(MCS) -r:bug-81691-b.dll -out:bug-81691.exe $(srcdir)/bug-81691.cs - rm -f bug-81691-a.dll - -EXTRA_DIST += bug-81466-lib.il - -bug-81466.exe$(PLATFORM_AOT_SUFFIX): bug-81466-lib.dll$(PLATFORM_AOT_SUFFIX) -bug-81466.exe bug-81466-lib.dll: $(srcdir)/bug-81466.il $(srcdir)/bug-81466-lib.il - $(ILASM) /dll /output:bug-81466-lib.dll $(srcdir)/bug-81466-lib.il - $(ILASM) /exe /output:bug-81466.exe $(srcdir)/bug-81466.il - -EXTRA_DIST += bug-324535-il.il - -bug-324535.exe$(PLATFORM_AOT_SUFFIX): bug-324535-il.dll$(PLATFORM_AOT_SUFFIX) -bug-324535.exe bug-324535-il.dll: $(srcdir)/bug-324535.cs $(srcdir)/bug-324535-il.il - $(ILASM) /dll /output:bug-324535-il.dll $(srcdir)/bug-324535-il.il - $(MCS) -r:bug-324535-il.dll -out:bug-324535.exe $(srcdir)/bug-324535.cs - -EXTRA_DIST += custom-modifiers.2.cs custom-modifiers-lib.il - -custom-modifiers.2.exe$(PLATFORM_AOT_SUFFIX): custom-modifiers-lib.dll$(PLATFORM_AOT_SUFFIX) -custom-modifiers.2.exe custom-modifiers-lib.dll: $(srcdir)/custom-modifiers.2.cs $(srcdir)/custom-modifiers-lib.il - $(ILASM) /dll /output:custom-modifiers-lib.dll $(srcdir)/custom-modifiers-lib.il - $(MCS) -r:custom-modifiers-lib.dll -out:custom-modifiers.2.exe $(srcdir)/custom-modifiers.2.cs - -EXTRA_DIST += bug-382986-lib.cs - -bug-382986.exe$(PLATFORM_AOT_SUFFIX): bug-382986-lib.dll$(PLATFORM_AOT_SUFFIX) -bug-382986.exe bug-382986-lib.dll: $(srcdir)/bug-382986.cs $(srcdir)/bug-382986-lib.cs - $(MCS) -target:library -out:bug-382986-lib.dll $(srcdir)/bug-382986-lib.cs - $(MCS) -r:bug-382986-lib.dll -out:bug-382986.exe $(srcdir)/bug-382986.cs - -EXTRA_DIST += bug-17537-helper.cs - -bug-17537.exe$(PLATFORM_AOT_SUFFIX): bug-17537-helper.exe$(PLATFORM_AOT_SUFFIX) -bug-17537-helper.exe: $(srcdir)/bug-17537-helper.cs - $(MCS) -out:$@ $< - chmod -x $@ -bug-17537.exe: bug-17537-helper.exe - -EXTRA_DIST += coreclr-security.cs - -test-coreclr-security : coreclr-security.exe - @$(RUNTIME_MOONLIGHT) --security=core-clr-test coreclr-security.exe - -EXTRA_DIST += generic-unboxing.2.il generic-boxing.2.il - -generic-unboxing.2.dll: $(srcdir)/generic-unboxing.2.il - $(ILASM) /dll /output:$@ $< -generic-boxing.2.dll: $(srcdir)/generic-boxing.2.il generic-unboxing.2.dll - $(ILASM) /dll /output:$@ $< - -EXTRA_DIST += generic-unbox.2.cs - -generic-unbox.2.exe$(PLATFORM_AOT_SUFFIX): generic-unboxing.2.dll$(PLATFORM_AOT_SUFFIX) -generic-unbox.2.exe: $(srcdir)/generic-unbox.2.cs generic-unboxing.2.dll - $(MCS) -r:generic-unboxing.2.dll -out:$@ $< - -EXTRA_DIST += generic-box.2.cs - -generic-box.2.exe$(PLATFORM_AOT_SUFFIX): generic-unboxing.2.dll$(PLATFORM_AOT_SUFFIX) generic-boxing.2.dll$(PLATFORM_AOT_SUFFIX) -generic-box.2.exe : $(srcdir)/generic-box.2.cs generic-unboxing.2.dll generic-boxing.2.dll - $(MCS) -r:generic-unboxing.2.dll,generic-boxing.2.dll -out:$@ $< - -EXTRA_DIST += generic-delegate2.2.cs generic-delegate2-lib.2.il - -generic-delegate2-lib.2.dll: $(srcdir)/generic-delegate2-lib.2.il - $(ILASM) /dll /output:$@ $< - -generic-delegate2.2.exe$(PLATFORM_AOT_SUFFIX): generic-delegate2-lib.2.dll$(PLATFORM_AOT_SUFFIX) -generic-delegate2.2.exe: $(srcdir)/generic-delegate2.2.cs generic-delegate2-lib.2.dll - $(MCS) -r:generic-delegate2-lib.2.dll -out:$@ $< - -bug-3903.exe: bug-3903.cs - $(MCS_NO_LIB) $(srcdir)/bug-3903.cs -nostdlib -r:$(srcdir)/../../external/binary-reference-assemblies/v2.0/mscorlib.dll -r:$(srcdir)/../../external/binary-reference-assemblies/v2.0/System.Core.dll -out:$@ - -EXTRA_DIST += appdomain-marshalbyref-assemblyload-MidAssembly.cs appdomain-marshalbyref-assemblyload-LeafAssembly.cs - -LeafAssembly.dll: appdomain-marshalbyref-assemblyload-LeafAssembly.cs - mkdir -p appdomain-marshalbyref-assemblyload1 - $(MCS) -target:library -out:$@ $< - -appdomain-marshalbyref-assemblyload2/LeafAssembly.dll: appdomain-marshalbyref-assemblyload-LeafAssembly.cs - mkdir -p appdomain-marshalbyref-assemblyload2 - $(MCS) -target:library -out:$@ $< -define:UNDEFINE_OTHER_METHOD - -MidAssembly.dll: appdomain-marshalbyref-assemblyload-MidAssembly.cs LeafAssembly.dll - mkdir -p appdomain-marshalbyref-assemblyload1 - $(MCS) -target:library -out:$@ $< -r:LeafAssembly.dll - -appdomain-marshalbyref-assemblyload.exe: appdomain-marshalbyref-assemblyload.cs MidAssembly.dll LeafAssembly.dll appdomain-marshalbyref-assemblyload2/LeafAssembly.dll - $(MCS) -out:$@ $< -r:MidAssembly.dll -r:LeafAssembly.dll - -gshared: - $(MAKE) test-generic-sharing - -gshared-aot: - @$(MAKE) AOT=1 gshared - -test-generic-sharing-normal: $(TESTS_GSHARED) $(TESTSAOT_GSHARED) - @for fn in $+ ; do \ - echo "Testing $$fn ..."; \ - $(RUNTIME) -O=gshared $$fn > $$fn.stdout || exit 1; \ - $(RUNTIME) -O=gshared,shared $$fn > $$fn.stdout || exit 1; \ - $(RUNTIME) -O=gshared,-inline $$fn > $$fn.stdout || exit 1; \ - $(RUNTIME) -O=gshared,-inline,shared $$fn > $fn.stdout || exit 1; \ - if [ x$(AOT) = x1 ]; then $(with_mono_path) $(JITTEST_PROG_RUN) --aot --debug $$fn > /dev/null || exit 1; $(RUNTIME) $$fn > $$fn.stdout || exit 1; fi; \ - done - -test-generic-sharing-managed: test-runner.exe $(TESTS_GSHARED) $(TESTSAOT_GSHARED) - $(Q) $(TOOLS_RUNTIME) $(TEST_RUNNER) -j a --testsuite-name "gshared" --disabled "$(DISABLED_TESTS)" --opt-sets "gshared gshared,shared gshared,-inline gshared,-inline,shared" $(TESTS_GSHARED) - -test-generic-sharing: - @if test x$(M) != x0; then $(MAKE) test-generic-sharing-managed; else $(MAKE) test-generic-sharing-normal; fi - -EXTRA_DIST += async-exceptions.cs -async-exceptions.exe : async-exceptions.cs - $(MCS) -out:async-exceptions.exe $(srcdir)/async-exceptions.cs -test-async-exceptions : async-exceptions.exe - for i in `echo 0 1 2 3 4 5 6 7 8 9 10`; do $(RUNTIME) --inject-async-exc Tests:foo $$i async-exceptions.exe || exit 1; done - for i in `echo 0 1 2 3 4 5 6 7 8 9 10`; do $(RUNTIME) --inject-async-exc Tests:bar $$i async-exceptions.exe || exit 1; done - -EXTRA_DIST += modules.cs modules-m1.cs -modules-m1.netmodule: modules-m1.cs - $(MCS) -out:$@ /target:module $(srcdir)/modules-m1.cs -modules.exe: modules.cs modules-m1.netmodule $(TEST_DRIVER_DEPEND) - $(MCS) -out:$@ /addmodule:modules-m1.netmodule -r:TestDriver.dll $(srcdir)/modules.cs - -# Useful if mono is compiled with --enable-shared=no -patch-libtool: - cp "../../libtool" . - sed -e 's,build_libtool_libs=no,build_libtool_libs=yes,g' libtool > 2; mv 2 libtool - sed -e 's,LIBTOOL =,LIBTOOL2 =,g' Makefile > 2 && echo "LIBTOOL = bash ./libtool" > 1 && cat 1 2 > Makefile - touch libtest.c - - -EXTRA_DIST += threadpool-in-processexit.cs threadpool-in-processexit.exe.stdout.expected -test-process-exit: - @$(MCS) $(srcdir)/threadpool-in-processexit.cs -out:threadpool-in-processexit.exe - @echo "Testing threadpool-in-processexit.exe..." - @$(RUNTIME) threadpool-in-processexit.exe > threadpool-in-processexit.exe.stdout - @diff -w threadpool-in-processexit.exe.stdout $(srcdir)/threadpool-in-processexit.exe.stdout.expected - -# tests that expect a 1 exit code -TESTS_UNHANDLED_EXCEPTION_1_SRC = \ - unhandled-exception-1.cs \ - unhandled-exception-9.cs - -# tests that expect a 255 exit code -TESTS_UNHANDLED_EXCEPTION_255_SRC = \ - unhandled-exception-2.cs \ - unhandled-exception-3.cs \ - unhandled-exception-4.cs \ - unhandled-exception-5.cs \ - unhandled-exception-6.cs \ - unhandled-exception-7.cs \ - unhandled-exception-8.cs - -TESTS_UNHANDLED_EXCEPTION_1=$(filter-out $(DISABLED_TESTS),$(TESTS_UNHANDLED_EXCEPTION_1_SRC:.cs=.exe)) -TESTS_UNHANDLED_EXCEPTION_255=$(filter-out $(DISABLED_TESTS),$(TESTS_UNHANDLED_EXCEPTION_255_SRC:.cs=.exe)) - -if FULL_AOT_TESTS -TESTSAOT_UNHANDLED_EXCEPTION_1=$(TESTS_UNHANDLED_EXCEPTION_1:.exe=.exe$(PLATFORM_AOT_SUFFIX)) -TESTSAOT_UNHANDLED_EXCEPTION_255=$(TESTS_UNHANDLED_EXCEPTION_255:.exe=.exe$(PLATFORM_AOT_SUFFIX)) -endif - -if HYBRID_AOT_TESTS -TESTSAOT_UNHANDLED_EXCEPTION_1=$(TESTS_UNHANDLED_EXCEPTION_1:.exe=.exe$(PLATFORM_AOT_SUFFIX)) -TESTSAOT_UNHANDLED_EXCEPTION_255=$(TESTS_UNHANDLED_EXCEPTION_255:.exe=.exe$(PLATFORM_AOT_SUFFIX)) -endif - -test-unhandled-exception-2: $(TESTS_UNHANDLED_EXCEPTION_1) $(TESTS_UNHANDLED_EXCEPTION_255) $(TESTSAOT_UNHANDLED_EXCEPTION_1) $(TESTSAOT_UNHANDLED_EXCEPTION_255) - ok=; \ - $(MAKE) test-unhandled-exception-2-1-with-managed-handler || ok=false; \ - $(MAKE) test-unhandled-exception-2-1-without-managed-handler || ok=false; \ - $(MAKE) test-unhandled-exception-2-255-with-managed-handler || ok=false; \ - $(MAKE) test-unhandled-exception-2-255-without-managed-handler || ok=false; \ - $$ok - -test-unhandled-exception-2-1-with-managed-handler: $(TESTS_UNHANDLED_EXCEPTION_1) $(TESTSAOT_UNHANDLED_EXCEPTION_1) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) -j a --testsuite-name $@ --disabled "$(DISABLED_TESTS)" --expected-exit-code 1 $(TESTS_UNHANDLED_EXCEPTION_1) -test-unhandled-exception-2-1-without-managed-handler: $(TESTS_UNHANDLED_EXCEPTION_1) $(TESTSAOT_UNHANDLED_EXCEPTION_1) test-runner.exe - TEST_UNHANDLED_EXCEPTION_HANDLER=1 $(TOOLS_RUNTIME) $(TEST_RUNNER) -j a --testsuite-name $@ --disabled "$(DISABLED_TESTS)" --expected-exit-code 1 $(TESTS_UNHANDLED_EXCEPTION_1) -test-unhandled-exception-2-255-with-managed-handler: $(TESTS_UNHANDLED_EXCEPTION_255) $(TESTSAOT_UNHANDLED_EXCEPTION_255) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) -j a --testsuite-name $@ --disabled "$(DISABLED_TESTS)" --expected-exit-code 255 $(TESTS_UNHANDLED_EXCEPTION_255) -test-unhandled-exception-2-255-without-managed-handler: $(TESTS_UNHANDLED_EXCEPTION_255) $(TESTSAOT_UNHANDLED_EXCEPTION_255) test-runner.exe - TEST_UNHANDLED_EXCEPTION_HANDLER=1 $(TOOLS_RUNTIME) $(TEST_RUNNER) -j a --testsuite-name $@ --disabled "$(DISABLED_TESTS)" --expected-exit-code 255 $(TESTS_UNHANDLED_EXCEPTION_255) - -EXTRA_DIST += appdomain-loader.cs appdomain-tester.cs - -if FULL_AOT_TESTS -test-appdomain-unload: -else -appdomain-loader.exe: appdomain-tester.exe - -test-appdomain-unload: appdomain-loader.exe appdomain-tester.exe - $(RUNTIME) -O=gshared appdomain-loader.exe > appdomain-loader.exe.1.stdout || exit 1; - $(RUNTIME) appdomain-loader.exe > appdomain-loader.exe.2.stdout || exit 1; - MONO_DEBUG_ASSEMBLY_UNLOAD=1 $(RUNTIME) -O=gshared appdomain-loader.exe > appdomain-loader.exe.3.stdout || exit 1; - MONO_DEBUG_ASSEMBLY_UNLOAD=1 $(RUNTIME) appdomain-loader.exe > appdomain-loader.exe.4.stdout || exit 1; -endif - -EXTRA_DIST += console-output.cs console-output.exe.stderr.expected console-output.exe.stdout.expected -test-console-output: console-output.exe - @$(RUNTIME) console-output.exe 1>console-output.exe.stdout - @$(RUNTIME) console-output.exe 2>console-output.exe.stderr - @diff -w console-output.exe.stdout $(srcdir)/console-output.exe.stdout.expected \ - && diff -w console-output.exe.stderr $(srcdir)/console-output.exe.stderr.expected - -test-pedump: test-runner.exe - $(with_mono_path) $(mono_build_root)/tools/pedump/pedump --verify error test-runner.exe - -.PHONY: test-gac-loading test-eglib-remap - -runtest-gac-loading: test-runner.exe - $(MAKE) -C testing_gac runtest - -compile-gac-loading: - $(MAKE) -C testing_gac compile-tests - -TESTS_STRESS_PROCESS_SRC= \ - process-stress-1.cs \ - process-stress-2.cs \ - process-stress-3.cs \ - process-leak.cs - -TESTS_STRESS_PROCESS=$(filter-out $(DISABLED_TESTS),$(TESTS_STRESS_PROCESS_SRC:.cs=.exe)) - -if FULL_AOT_TESTS -TESTSAOT_STRESS_PROCESS=$(TESTS_STRESS_PROCESS:.exe=.exe$(PLATFORM_AOT_SUFFIX)) -endif - -if HYBRID_AOT_TESTS -TESTSAOT_STRESS_PROCESS=$(TESTS_STRESS_PROCESS:.exe=.exe$(PLATFORM_AOT_SUFFIX)) -endif - -test-process-stress: $(TESTS_STRESS_PROCESS) $(TESTSAOT_STRESS_PROCESS) test-runner.exe - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ --disabled "$(DISABLED_TESTS)" --timeout 900 $(TESTS_STRESS_PROCESS) - -coreclr-gcstress: - $(MAKE) -C $(mono_build_root)/acceptance-tests coreclr-gcstress - -# Tests for the Mono lldb plugin -EXTRA_DIST += test_lldb.py test-lldb.cs -test-lldb: test-lldb.exe - python test_lldb.py $(JITTEST_PROG) - -noinst_LTLIBRARIES = libtest.la - -AM_CPPFLAGS = $(GLIB_CFLAGS) - -if HOST_WIN32 -# gcc-3.4.4 emits incorrect code when making indirect calls to stdcall functions using a tail call -# This shows up when compiling mono_test_marshal_delegate () -libtest_la_CFLAGS=-fno-optimize-sibling-calls -# the exported names created by gcc for stdcall functions are missing the leading _, so MS.NET -# can't find them. So we use --kill-at to remove the @ suffix as well. -libtest_la_LDFLAGS=-no-undefined -rpath `pwd` -Wl,--kill-at -else -libtest_la_LDFLAGS = -rpath `pwd` -endif -libtest_la_SOURCES = libtest.c -libtest_la_LIBADD = $(GLIB_LIBS) $(LIBICONV) - -INTERNALSVISIBLETO_TEST_SRC = \ - internalsvisibleto-runtimetest.cs \ - internalsvisibleto-compilertest.cs - -INTERNALSVISIBLETO_TEST_LIB_SRC = \ - internalsvisibleto-library.cs - -INTERNALSVISIBLETO_TEST_LIBS = \ - internalsvisibleto-correctcase.dll \ - internalsvisibleto-wrongcase.dll \ - internalsvisibleto-correctcase-2.dll \ - internalsvisibleto-wrongcase-2.dll \ - internalsvisibleto-correctcase-sign2048.dll \ - internalsvisibleto-wrongcase-sign2048.dll \ - internalsvisibleto-correctcase-2-sign2048.dll \ - internalsvisibleto-wrongcase-2-sign2048.dll - - -INTERNALSVISIBLETO_TEST = \ - $(INTERNALSVISIBLETO_TEST_SRC:.cs=.exe) \ - $(INTERNALSVISIBLETO_TEST_SRC:.cs=-sign2048.exe) - -if FULL_AOT_TESTS -INTERNALSVISIBLETO_TESTAOT = \ - $(INTERNALSVISIBLETO_TEST:.exe=.exe$(PLATFORM_AOT_SUFFIX)) -INTERNALSVISIBLETO_TESTAOT_LIBS = \ - $(INTERNALSVISIBLETO_TEST_LIBS:.dll=.dll$(PLATFORM_AOT_SUFFIX)) -endif - -if HYBRID_AOT_TESTS -INTERNALSVISIBLETO_TESTAOT = \ - $(INTERNALSVISIBLETO_TEST:.exe=.exe$(PLATFORM_AOT_SUFFIX)) -INTERNALSVISIBLETO_TESTAOT_LIBS = \ - $(INTERNALSVISIBLETO_TEST_LIBS:.dll=.dll$(PLATFORM_AOT_SUFFIX)) -endif - -EXTRA_DIST += $(INTERNALSVISIBLETO_TEST_SRC) $(INTERNALSVISIBLETO_TEST_LIB_SRC) - -test-internalsvisibleto: test-runner.exe $(INTERNALSVISIBLETO_TEST) $(INTERNALSVISIBLETO_TESTAOT) $(INTERNALSVISIBLETO_TESTAOT_LIBS) - $(TOOLS_RUNTIME) $(TEST_RUNNER) --testsuite-name $@ $(INTERNALSVISIBLETO_TEST) - -internalsvisibleto-correctcase.dll internalsvisibleto-wrongcase.dll internalsvisibleto-runtimetest.exe: internalsvisibleto-runtimetest.cs internalsvisibleto-library.cs - $(Q) $(MCS_NO_UNSAFE) -out:internalsvisibleto-correctcase.dll -target:library -d:CORRECT_CASE -d:PERMISSIVE internalsvisibleto-library.cs - $(Q) $(MCS_NO_UNSAFE) -out:internalsvisibleto-wrongcase.dll -target:library -d:WRONG_CASE -d:PERMISSIVE internalsvisibleto-library.cs - $(Q) $(MCS_NO_UNSAFE) -out:internalsvisibleto-runtimetest.exe -warn:0 -r:internalsvisibleto-correctcase.dll -r:internalsvisibleto-wrongcase.dll internalsvisibleto-runtimetest.cs - $(Q) $(MCS_NO_UNSAFE) -out:internalsvisibleto-correctcase.dll -target:library -d:CORRECT_CASE internalsvisibleto-library.cs - $(Q) $(MCS_NO_UNSAFE) -out:internalsvisibleto-wrongcase.dll -target:library -d:WRONG_CASE internalsvisibleto-library.cs - -internalsvisibleto-correctcase-2.dll internalsvisibleto-wrongcase-2.dll internalsvisibleto-compilertest.exe: internalsvisibleto-compilertest.cs internalsvisibleto-library.cs - $(Q) $(MCS_NO_UNSAFE) -out:internalsvisibleto-correctcase-2.dll -target:library -d:CORRECT_CASE internalsvisibleto-library.cs - $(Q) $(MCS_NO_UNSAFE) -out:internalsvisibleto-wrongcase-2.dll -target:library -d:WRONG_CASE internalsvisibleto-library.cs - $(Q) $(MCS_NO_UNSAFE) -out:internalsvisibleto-compilertest.exe -warn:0 -r:internalsvisibleto-correctcase-2.dll -r:internalsvisibleto-wrongcase-2.dll internalsvisibleto-compilertest.cs - -internalsvisibleto-correctcase-sign2048.dll internalsvisibleto-wrongcase-sign2048.dll internalsvisibleto-runtimetest-sign2048.exe: internalsvisibleto-runtimetest.cs internalsvisibleto-library.cs internalsvisibleto-2048.snk - $(Q) $(MCS_NO_UNSAFE) -out:internalsvisibleto-correctcase-sign2048.dll -target:library -d:CORRECT_CASE -d:PERMISSIVE -d:SIGN2048 internalsvisibleto-library.cs - $(Q) $(MCS_NO_UNSAFE) -out:internalsvisibleto-wrongcase-sign2048.dll -target:library -d:WRONG_CASE -d:PERMISSIVE -d:SIGN2048 internalsvisibleto-library.cs - $(Q) $(MCS_NO_UNSAFE) -out:internalsvisibleto-runtimetest-sign2048.exe -warn:0 -r:internalsvisibleto-correctcase-sign2048.dll -r:internalsvisibleto-wrongcase-sign2048.dll -d:SIGN2048 internalsvisibleto-runtimetest.cs - $(Q) $(MCS_NO_UNSAFE) -out:internalsvisibleto-correctcase-sign2048.dll -target:library -d:CORRECT_CASE -d:SIGN2048 internalsvisibleto-library.cs - $(Q) $(MCS_NO_UNSAFE) -out:internalsvisibleto-wrongcase-sign2048.dll -target:library -d:WRONG_CASE -d:SIGN2048 internalsvisibleto-library.cs - -internalsvisibleto-correctcase-2-sign2048.dll internalsvisibleto-wrongcase-2-sign2048.dll internalsvisibleto-compilertest-sign2048.exe: internalsvisibleto-compilertest.cs internalsvisibleto-library.cs internalsvisibleto-2048.snk - $(Q) $(MCS_NO_UNSAFE) -out:internalsvisibleto-correctcase-2-sign2048.dll -target:library -d:CORRECT_CASE -d:SIGN2048 internalsvisibleto-library.cs - $(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/Makefile.am.REMOVED.git-id b/mono/tests/Makefile.am.REMOVED.git-id new file mode 100644 index 0000000000..2682371196 --- /dev/null +++ b/mono/tests/Makefile.am.REMOVED.git-id @@ -0,0 +1 @@ +09e17da74e1e4895b6753068212820cf64201eb3 \ No newline at end of file diff --git a/mono/tests/Makefile.in.REMOVED.git-id b/mono/tests/Makefile.in.REMOVED.git-id index c772fd1e1a..b9f332512d 100644 --- a/mono/tests/Makefile.in.REMOVED.git-id +++ b/mono/tests/Makefile.in.REMOVED.git-id @@ -1 +1 @@ -8a8a82272702ca44a05c569b5bf95b6b7877df68 \ No newline at end of file +1ed852d2a81feaf7c07273397fa52351d11b9e66 \ No newline at end of file diff --git a/mono/tests/abort-cctor.cs b/mono/tests/abort-cctor.cs index 7ff7a3b28e..d4551e0349 100644 --- a/mono/tests/abort-cctor.cs +++ b/mono/tests/abort-cctor.cs @@ -5,6 +5,7 @@ using System.Runtime.CompilerServices; class Driver { + public static SemaphoreSlim sema1 = new SemaphoreSlim (0); public static ManualResetEvent mre1 = new ManualResetEvent (false); public static ManualResetEvent mre2 = new ManualResetEvent (false); @@ -367,6 +368,62 @@ class Driver Environment.Exit (15); } + public static bool got_to_the_end_of_outer_finally = false; + public static bool got_to_the_end_of_inner_finally = false; + + class StaticConstructor6 { + + static StaticConstructor6 () + { + try { + Setup6 (); + } finally { + Driver.got_to_the_end_of_outer_finally = true; + } + } + + [MethodImplAttribute (MethodImplOptions.NoInlining)] + public static void Setup6 () { + try { + } finally { + Driver.sema1.Release (); + Thread.Sleep (1000); /* hopefully we get woken up here */ + Driver.got_to_the_end_of_inner_finally = true; + } + } + } + + [MethodImplAttribute (MethodImplOptions.NoInlining)] + static void IsStaticConstructor6Viable () { + Console.WriteLine ("IsStaticConstructor6Viable? got to inner finally? {0} got to outer finally? {1}", + Driver.got_to_the_end_of_inner_finally, + Driver.got_to_the_end_of_outer_finally); + new StaticConstructor6 (); + if (!Driver.got_to_the_end_of_inner_finally) + Environment.Exit (17); + if (!Driver.got_to_the_end_of_outer_finally) + Environment.Exit (18); + } + + public static void Test6 () + { + Thread thread = new Thread (() => { + new StaticConstructor6 (); + }); + + thread.Start (); + Driver.sema1.Wait (); + thread.Abort (); + thread.Join (); + try { + IsStaticConstructor6Viable (); + Console.WriteLine ("StaticConstructor6 is viable"); + } catch (TypeInitializationException e) { + Console.WriteLine ("StaticConstructor6 is not viable"); + Environment.Exit (19); + } + } + public static int Main () { Test1 (); @@ -374,6 +431,7 @@ class Driver Test3 (); Test4 (); Test5 (); + Test6 (); Console.WriteLine ("done, all things good"); return 0; } diff --git a/mono/tests/bug-60843.cs b/mono/tests/bug-60843.cs new file mode 100644 index 0000000000..29523464f2 --- /dev/null +++ b/mono/tests/bug-60843.cs @@ -0,0 +1,49 @@ +using System; +using System.Runtime.CompilerServices; + +class A : Attribute +{ + public object X; + + public static void Main() + { + var x = (C.E)AttributeTest(typeof(C<>.E)); + Assert(C.E.V == x); + var y = (C.E2[])AttributeTest(typeof(C<>.E2)); + Assert(y.Length == 2); + Assert(y[0] == C.E2.A); + Assert(y[1] == C.E2.B); + } + + public static object AttributeTest (Type t) { + var cas = t.GetCustomAttributes(false); + Assert(cas.Length == 1); + Assert(cas[0] is A); + var a = (A)cas[0]; + return a.X; + } + + private static int AssertCount = 0; + + public static void Assert ( + bool b, + [CallerFilePath] string sourceFile = null, + [CallerLineNumber] int lineNumber = 0 + ) { + AssertCount++; + + if (!b) { + Console.Error.WriteLine($"Assert failed at {sourceFile}:{lineNumber}"); + Environment.Exit(AssertCount); + } + } +} + +public class C +{ + [A(X = C.E.V)] + public enum E { V } + + [A(X = new [] { C.E2.A, C.E2.B })] + public enum E2 { A, B } +} \ No newline at end of file diff --git a/mono/tests/gc-descriptors/Makefile.in b/mono/tests/gc-descriptors/Makefile.in index f110f508bb..645d678f0c 100644 --- a/mono/tests/gc-descriptors/Makefile.in +++ b/mono/tests/gc-descriptors/Makefile.in @@ -83,8 +83,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -193,6 +191,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -211,7 +210,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -225,7 +223,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -339,7 +336,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ diff --git a/mono/tests/gptail1.il b/mono/tests/gptail1.il new file mode 100755 index 0000000000..2da9652281 --- /dev/null +++ b/mono/tests/gptail1.il @@ -0,0 +1,92 @@ +.assembly extern mscorlib { } +.assembly tailcall1 { } +.class A extends [mscorlib]System.Object { +.method public hidebysig specialname rtspecialname instance void .ctor() cil managed +{ +.maxstack 8 +ldarg.0 +call instance void [mscorlib]System.Object::.ctor() +ret +} +.method public hidebysig static int32 gptail1() cil managed noinlining { +.entrypoint +.maxstack 4 +.locals init (uint8 V_0) +newobj instance void A::.ctor() +ldloca.s V_0 +conv.u +ldc.i4.0 +conv.i8 +ldc.i4.7 +call instance int32 A::gptail2(uint8*, int64, int32) +ret +} +.method private hidebysig instance int32 gptail2(uint8* root_stack, int64 diff_stack, int32 counter) cil managed noinlining { +.maxstack 5 +.locals init (uint8 V_0) +ldarg.3 +ldc.i4.0 +ble.s IL_0017 +ldarg.0 +ldarg.1 +ldloca.s V_0 +conv.u +ldarg.1 +sub +ldc.i4.1 +div +conv.i8 +ldarg.3 +ldc.i4.1 +sub +tail. call instance int32 A::gptail2(uint8*, int64, int32) +ret +IL_0017: ldarg.1 +ldloca.s V_0 +conv.u +ldarg.2 +ldstr "gptail1" +call int32 A::check(uint8*, uint8*, int64, string) +ret +} +.method private hidebysig static int32 check(uint8* root_stack, uint8* local, int64 diff_stack, string name) cil managed noinlining { +.maxstack 8 +ldarg.1 +ldarg.0 +sub +ldc.i4.1 +div +conv.i8 +ldarg.2 +beq.s IL_0026 +ldstr "{0} failure {1}" +ldarg.3 +ldarg.0 +ldarg.1 +sub +ldc.i4.1 +div +conv.i8 +box [mscorlib]System.Int64 +call string [mscorlib]System.String::Format(string, object, object) +call void [mscorlib]System.Console::WriteLine(string) +ldc.i4.1 +ret +IL_0026: ldstr "{0} success" +ldarg.3 +call string [mscorlib]System.String::Format(string, object) +call void [mscorlib]System.Console::WriteLine(string) +ldc.i4.0 +ret +} +.method private hidebysig static int32 check(int64 root_stack, uint8* local, int64 diff_stack, string name) cil managed noinlining { +.maxstack 8 +ldarg.0 +conv.u +ldarg.1 +ldarg.2 +ldarg.3 +call int32 A::check(uint8*, uint8*, int64, string) +ret +} +} diff --git a/mono/tests/install_eh_callback.cs b/mono/tests/install_eh_callback.cs new file mode 100644 index 0000000000..26fd88dea8 --- /dev/null +++ b/mono/tests/install_eh_callback.cs @@ -0,0 +1,93 @@ +using System; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; + +public class MonoPInvokeCallbackAttribute : Attribute { + public MonoPInvokeCallbackAttribute (Type delegateType) { } +} + +public class Tests { + + [DllImport ("libtest")] + public static extern void mono_test_setjmp_and_call (VoidVoidDelegate del, out IntPtr handle); + + public delegate void VoidVoidDelegate (); + + public class SpecialExn : Exception { + } + + public class SomeOtherExn : Exception { + } + + [MethodImpl (MethodImplOptions.NoInlining)] + private static void callee (ref bool called) { + called = true; + throw new SpecialExn (); + } + + public class Caller { + public static bool called; + public static bool finally_called; + + public static void Setup () { + called = false; + finally_called = false; + } + + [MonoPInvokeCallback (typeof (VoidVoidDelegate))] + public static void M () { + try { + callee (ref called); + throw new Exception ("unexpected return from callee"); + } catch (SomeOtherExn) { + } finally { + finally_called = true; + } + } + } + + public static int test_0_setjmp_exn_handler () + { + IntPtr res; + Caller.Setup (); + VoidVoidDelegate f = new VoidVoidDelegate (Caller.M); + + try { + mono_test_setjmp_and_call (f, out res); + } catch (SpecialExn) { + Console.Error.WriteLine ("should not have caught a SpecialExn"); + return 1; + } + if (!Caller.called) { + Console.Error.WriteLine ("delegate not even called"); + return 2; + } + if (!Caller.finally_called) { + Console.Error.WriteLine ("finally not reached"); + return 3; + } + if (res == IntPtr.Zero) { + Console.Error.WriteLine ("res should be a GCHandle, was 0"); + return 4; + } + GCHandle h = GCHandle.FromIntPtr (res); + object o = h.Target; + h.Free (); + if (o == null) { + Console.Error.WriteLine ("GCHandle target was null"); + return 5; + } + else if (o is SpecialExn) + return 0; + else { + Console.Error.WriteLine ("o was not a SpecialExn, it is {0}", o); + return 6; + } + } + + + static int Main () + { + return TestDriver.RunTests (typeof (Tests)); + } +} diff --git a/mono/tests/itail1.il b/mono/tests/itail1.il new file mode 100755 index 0000000000..6f3eed6c9d --- /dev/null +++ b/mono/tests/itail1.il @@ -0,0 +1,91 @@ +.assembly extern mscorlib { } +.assembly tailcall1 { } +.class A extends [mscorlib]System.Object { +.method public hidebysig specialname rtspecialname instance void .ctor() cil managed +{ +.maxstack 8 +ldarg.0 +call instance void [mscorlib]System.Object::.ctor() +ret +} +.method public hidebysig static int32 itail1() cil managed noinlining { +.entrypoint +.maxstack 4 +.locals init (uint8 V_0) +newobj instance void A::.ctor() +ldloca.s V_0 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +ldc.i4.2 +call instance int32 A::itail2(int64, int64, int32) +ret +} +.method private hidebysig instance int32 itail2(int64 root_stack, int64 diff_stack, int32 counter) cil managed noinlining { +.maxstack 5 +.locals init (uint8 V_0) +ldarg.3 +ldc.i4.0 +ble.s IL_0015 +ldarg.0 +ldarg.1 +ldloca.s V_0 +conv.u +conv.u8 +ldarg.1 +sub +ldarg.3 +ldc.i4.1 +sub +tail. call instance int32 A::itail2(int64, int64, int32) +ret +IL_0015: ldarg.1 +ldloca.s V_0 +conv.u +ldarg.2 +ldstr "itail1" +call int32 A::check(int64, uint8*, int64, string) +ret +} +.method private hidebysig static int32 check(uint8* root_stack, uint8* local, int64 diff_stack, string name) cil managed noinlining { +.maxstack 8 +ldarg.1 +ldarg.0 +sub +ldc.i4.1 +div +conv.i8 +ldarg.2 +beq.s IL_0026 +ldstr "{0} failure {1}" +ldarg.3 +ldarg.0 +ldarg.1 +sub +ldc.i4.1 +div +conv.i8 +box [mscorlib]System.Int64 +call string [mscorlib]System.String::Format(string, object, object) +call void [mscorlib]System.Console::WriteLine(string) +ldc.i4.1 +ret +IL_0026: ldstr "{0} success" +ldarg.3 +call string [mscorlib]System.String::Format(string, object) +call void [mscorlib]System.Console::WriteLine(string) +ldc.i4.0 +ret +} +.method private hidebysig static int32 check(int64 root_stack, uint8* local, int64 diff_stack, string name) cil managed noinlining { +.maxstack 8 +ldarg.0 +conv.u +ldarg.1 +ldarg.2 +ldarg.3 +call int32 A::check(uint8*, uint8*, int64, string) +ret +} +} diff --git a/mono/tests/itaili1.il b/mono/tests/itaili1.il new file mode 100755 index 0000000000..df1ed39778 --- /dev/null +++ b/mono/tests/itaili1.il @@ -0,0 +1,83 @@ +.assembly extern mscorlib { } +.assembly tailcall1 { } +.class A extends [mscorlib]System.Object { +.method public hidebysig static int32 itaili1() cil managed noinlining { +.entrypoint +.maxstack 3 +.locals init (uint8 V_0) +ldloca.s V_0 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +ldc.i4.s 9 +call int32 A::itaili2(int64, int64, int32) +ret +} +.method private hidebysig static int32 itaili2(int64 root_stack, int64 diff_stack, int32 counter) cil managed noinlining { +.maxstack 4 +.locals init (uint8 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0014 +ldarg.0 +ldloca.s V_0 +conv.u +conv.u8 +ldarg.0 +sub +ldarg.2 +ldc.i4.1 +sub +ldftn int32 A::itaili2(int64, int64, int32) +tail. calli int32 (int64, int64, int32) +ret +IL_0014: ldarg.0 +ldloca.s V_0 +conv.u +ldarg.1 +ldstr "itaili1" +call int32 A::check(int64, uint8*, int64, string) +ret +} +.method private hidebysig static int32 check(uint8* root_stack, uint8* local, int64 diff_stack, string name) cil managed noinlining { +.maxstack 8 +ldarg.1 +ldarg.0 +sub +ldc.i4.1 +div +conv.i8 +ldarg.2 +beq.s IL_0026 +ldstr "{0} failure {1}" +ldarg.3 +ldarg.0 +ldarg.1 +sub +ldc.i4.1 +div +conv.i8 +box [mscorlib]System.Int64 +call string [mscorlib]System.String::Format(string, object, object) +call void [mscorlib]System.Console::WriteLine(string) +ldc.i4.1 +ret +IL_0026: ldstr "{0} success" +ldarg.3 +call string [mscorlib]System.String::Format(string, object) +call void [mscorlib]System.Console::WriteLine(string) +ldc.i4.0 +ret +} +.method private hidebysig static int32 check(int64 root_stack, uint8* local, int64 diff_stack, string name) cil managed noinlining { +.maxstack 8 +ldarg.0 +conv.u +ldarg.1 +ldarg.2 +ldarg.3 +call int32 A::check(uint8*, uint8*, int64, string) +ret +} +} diff --git a/mono/tests/ivtail1.il b/mono/tests/ivtail1.il new file mode 100755 index 0000000000..4ac28d045a --- /dev/null +++ b/mono/tests/ivtail1.il @@ -0,0 +1,91 @@ +.assembly extern mscorlib { } +.assembly tailcall1 { } +.class A extends [mscorlib]System.Object { +.method public hidebysig specialname rtspecialname instance void .ctor() cil managed +{ +.maxstack 8 +ldarg.0 +call instance void [mscorlib]System.Object::.ctor() +ret +} +.method public hidebysig static int32 ivtail1() cil managed noinlining { +.entrypoint +.maxstack 4 +.locals init (uint8 V_0) +newobj instance void A::.ctor() +ldloca.s V_0 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +ldc.i4.6 +callvirt instance int32 A::ivtail2(int64, int64, int32) +ret +} +.method public hidebysig newslot virtual instance int32 ivtail2(int64 root_stack, int64 diff_stack, int32 counter) cil managed noinlining { +.maxstack 5 +.locals init (uint8 V_0) +ldarg.3 +ldc.i4.0 +ble.s IL_0015 +ldarg.0 +ldarg.1 +ldloca.s V_0 +conv.u +conv.u8 +ldarg.1 +sub +ldarg.3 +ldc.i4.1 +sub +tail. callvirt instance int32 A::ivtail2(int64, int64, int32) +ret +IL_0015: ldarg.1 +ldloca.s V_0 +conv.u +ldarg.2 +ldstr "ivtail1" +call int32 A::check(int64, uint8*, int64, string) +ret +} +.method private hidebysig static int32 check(uint8* root_stack, uint8* local, int64 diff_stack, string name) cil managed noinlining { +.maxstack 8 +ldarg.1 +ldarg.0 +sub +ldc.i4.1 +div +conv.i8 +ldarg.2 +beq.s IL_0026 +ldstr "{0} failure {1}" +ldarg.3 +ldarg.0 +ldarg.1 +sub +ldc.i4.1 +div +conv.i8 +box [mscorlib]System.Int64 +call string [mscorlib]System.String::Format(string, object, object) +call void [mscorlib]System.Console::WriteLine(string) +ldc.i4.1 +ret +IL_0026: ldstr "{0} success" +ldarg.3 +call string [mscorlib]System.String::Format(string, object) +call void [mscorlib]System.Console::WriteLine(string) +ldc.i4.0 +ret +} +.method private hidebysig static int32 check(int64 root_stack, uint8* local, int64 diff_stack, string name) cil managed noinlining { +.maxstack 8 +ldarg.0 +conv.u +ldarg.1 +ldarg.2 +ldarg.3 +call int32 A::check(uint8*, uint8*, int64, string) +ret +} +} diff --git a/mono/tests/libtest.c.REMOVED.git-id b/mono/tests/libtest.c.REMOVED.git-id index 45b7bb7d02..e0a8433fd2 100644 --- a/mono/tests/libtest.c.REMOVED.git-id +++ b/mono/tests/libtest.c.REMOVED.git-id @@ -1 +1 @@ -e1c68d5ca8b25c0e0b0c471ceb5ea335670f714d \ No newline at end of file +531b8ee1f7552e3554e60ee299457cdfa5b71555 \ No newline at end of file diff --git a/mono/tests/marshal2.cs b/mono/tests/marshal2.cs index 05550ac227..7707b32dbb 100644 --- a/mono/tests/marshal2.cs +++ b/mono/tests/marshal2.cs @@ -60,6 +60,26 @@ public class Tests { byte b; PackStruct1 s; } + + [StructLayout (LayoutKind.Sequential)] + struct InvalidArrayForMarshalingStruct + { + // Missing the following needed directive + // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public readonly char[] CharArray; + } + + [StructLayout(LayoutKind.Sequential)] + struct TwoDimensionalArrayStruct + { + public TwoDimensionalArrayStruct(int[,] vals) + { + TwoDimensionalArray = vals; + } + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + public readonly int[,] TwoDimensionalArray; + } public unsafe static int Main (String[] args) { if (TestDriver.RunTests (typeof (Tests), args) != 0) @@ -293,4 +313,26 @@ public class Tests { return 2; return 0; } + + public static int test_0_invalid_array_throws () { + var ptr = Marshal.AllocHGlobal(Marshal.SizeOf (typeof (InvalidArrayForMarshalingStruct))); + try { + Marshal.PtrToStructure (ptr, typeof (InvalidArrayForMarshalingStruct)); + } + catch (MarshalDirectiveException e) { + return 0; + } + return 1; + } + + public static int test_0_multidimentional_arrays () { + var structToMarshal = new TwoDimensionalArrayStruct (new[, ] { {1, 2, 3}, {4, 5, 6} }); + var ptr = Marshal.AllocHGlobal (Marshal.SizeOf (structToMarshal)); + Marshal.StructureToPtr (structToMarshal, ptr, false); + unsafe { + if(((int*)ptr)[4] == 5) + return 0; + } + return 1; + } } diff --git a/mono/tests/pinvoke11.cs b/mono/tests/pinvoke11.cs index 252700fe34..776dbc4035 100644 --- a/mono/tests/pinvoke11.cs +++ b/mono/tests/pinvoke11.cs @@ -60,6 +60,39 @@ public struct NestedFloat { public float f4; } +[Serializable] +[StructLayout(LayoutKind.Sequential)] +public struct Rectangle +{ + public int X; + public int Y; + public int Width; + public int Height; + + public Rectangle(int x, int y, int width, int height) + { + X = x; + Y = y; + Width = width; + Height = height; + } +} + +[Serializable] +public struct Scalar4 { + public double Val0; + public double Val1; + public double Val2; + public double Val3; + + public Scalar4 (double v0, double v1, double v2, double v3) { + Val0 = v0; + Val1 = v1; + Val2 = v2; + Val3 = v3; + } +} + public class Test { [DllImport ("libtest")] @@ -89,6 +122,10 @@ public class Test [DllImport ("libtest", EntryPoint="mono_return_nested_float")] public static extern NestedFloat mono_return_nested_float (); + [DllImport("libtest", EntryPoint="mono_return_struct_4_double")] + [return: MarshalAs(UnmanagedType.LPStr)] + public static extern string mono_return_struct_4_double (IntPtr ptr, Rectangle rect, Scalar4 sc4, int a, int b, int c); + static int Main() { if (mono_return_int (5) != 5) @@ -159,6 +196,14 @@ public class Test if (f.fi.f1 != 1.0) return 12; + Rectangle rect = new Rectangle (10, 10, 100, 20); + Scalar4 sc4 = new Scalar4 (32, 64, 128, 256); + var sc4_ret = mono_return_struct_4_double (IntPtr.Zero, rect, sc4, 0x1337, 0x1234, 0x9876); + if (sc4_ret != "sc4 = {32.0, 64.0, 128.0, 256.0 }, a=1337, b=1234, c=9876\n") { + Console.WriteLine ("sc4_ret = " + sc4_ret); + return 13; + } + return 0; } } diff --git a/mono/tests/roslyn-bug-19038.cs b/mono/tests/roslyn-bug-19038.cs new file mode 100644 index 0000000000..5a4a83a3cd --- /dev/null +++ b/mono/tests/roslyn-bug-19038.cs @@ -0,0 +1,35 @@ +using System; +using System.Reflection; + +unsafe public class C { + public int Value; + + static void Main() + { + C a = new C { Value = 12 }; + FieldInfo info = typeof(C).GetField("Value"); + TypedReference reference = __makeref(a); + + if (!(reference is TypedReference reference0)) + throw new Exception("TypedReference"); + + info.SetValueDirect(reference0, 34); + + Console.WriteLine($"a.Value = {a.Value}"); + if (a.Value != 34) + throw new Exception("SetValueDirect"); + + int z = 56; + if (CopyRefInt(ref z) != 56) + throw new Exception("ref z"); + + Console.WriteLine("ok"); + } + + static int CopyRefInt(ref int z) + { + if (!(z is int z0)) + throw new Exception("CopyRefInt"); + return z0; + } +} \ No newline at end of file diff --git a/mono/tests/sirtail1.il b/mono/tests/sirtail1.il new file mode 100755 index 0000000000..b87be0a9e6 --- /dev/null +++ b/mono/tests/sirtail1.il @@ -0,0 +1,86 @@ +.assembly extern mscorlib { } +.assembly tailcall1 { } +.class A extends [mscorlib]System.Object { +.method public hidebysig static int32 sirtail1() cil managed noinlining { +.entrypoint +.maxstack 4 +.locals init (uint8 V_0, object V_1) +newobj instance void [mscorlib]System.Object::.ctor() +stloc.1 +ldloca.s V_0 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +ldc.i4.s 11 +ldloca.s V_1 +call int32 A::sirtail2(int64, int64, int32, object&) +ret +} +.method private hidebysig static int32 sirtail2(int64 root_stack, int64 diff_stack, int32 counter, object& o) cil managed noinlining { +.maxstack 4 +.locals init (uint8 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0015 +ldarg.0 +ldloca.s V_0 +conv.u +conv.u8 +ldarg.0 +sub +ldarg.2 +ldc.i4.1 +sub +ldarg.3 +tail. call int32 A::sirtail2(int64, int64, int32, object&) +ret +IL_0015: ldarg.0 +ldloca.s V_0 +conv.u +ldarg.1 +ldstr "irtail1" +call int32 A::check(int64, uint8*, int64, string) +ret +} +.method private hidebysig static int32 check(uint8* root_stack, uint8* local, int64 diff_stack, string name) cil managed noinlining { +.maxstack 8 +ldarg.1 +ldarg.0 +sub +ldc.i4.1 +div +conv.i8 +ldarg.2 +beq.s IL_0026 +ldstr "{0} failure {1}" +ldarg.3 +ldarg.0 +ldarg.1 +sub +ldc.i4.1 +div +conv.i8 +box [mscorlib]System.Int64 +call string [mscorlib]System.String::Format(string, object, object) +call void [mscorlib]System.Console::WriteLine(string) +ldc.i4.1 +ret +IL_0026: ldstr "{0} success" +ldarg.3 +call string [mscorlib]System.String::Format(string, object) +call void [mscorlib]System.Console::WriteLine(string) +ldc.i4.0 +ret +} +.method private hidebysig static int32 check(int64 root_stack, uint8* local, int64 diff_stack, string name) cil managed noinlining { +.maxstack 8 +ldarg.0 +conv.u +ldarg.1 +ldarg.2 +ldarg.3 +call int32 A::check(uint8*, uint8*, int64, string) +ret +} +} diff --git a/mono/tests/sitail1.il b/mono/tests/sitail1.il new file mode 100755 index 0000000000..a3a99ced69 --- /dev/null +++ b/mono/tests/sitail1.il @@ -0,0 +1,82 @@ +.assembly extern mscorlib { } +.assembly tailcall1 { } +.class A extends [mscorlib]System.Object { +.method public hidebysig static int32 sitail1() cil managed noinlining { +.entrypoint +.maxstack 3 +.locals init (uint8 V_0) +ldloca.s V_0 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +ldc.i4.4 +call int32 A::sitail2(int64, int64, int32) +ret +} +.method private hidebysig static int32 sitail2(int64 root_stack, int64 diff_stack, int32 counter) cil managed noinlining { +.maxstack 4 +.locals init (uint8 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0014 +ldarg.0 +ldloca.s V_0 +conv.u +conv.u8 +ldarg.0 +sub +ldarg.2 +ldc.i4.1 +sub +tail. call int32 A::sitail2(int64, int64, int32) +ret +IL_0014: ldarg.0 +ldloca.s V_0 +conv.u +ldarg.1 +ldstr "sitail1" +call int32 A::check(int64, uint8*, int64, string) +ret +} +.method private hidebysig static int32 check(uint8* root_stack, uint8* local, int64 diff_stack, string name) cil managed noinlining { +.maxstack 8 +ldarg.1 +ldarg.0 +sub +ldc.i4.1 +div +conv.i8 +ldarg.2 +beq.s IL_0026 +ldstr "{0} failure {1}" +ldarg.3 +ldarg.0 +ldarg.1 +sub +ldc.i4.1 +div +conv.i8 +box [mscorlib]System.Int64 +call string [mscorlib]System.String::Format(string, object, object) +call void [mscorlib]System.Console::WriteLine(string) +ldc.i4.1 +ret +IL_0026: ldstr "{0} success" +ldarg.3 +call string [mscorlib]System.String::Format(string, object) +call void [mscorlib]System.Console::WriteLine(string) +ldc.i4.0 +ret +} +.method private hidebysig static int32 check(int64 root_stack, uint8* local, int64 diff_stack, string name) cil managed noinlining { +.maxstack 8 +ldarg.0 +conv.u +ldarg.1 +ldarg.2 +ldarg.3 +call int32 A::check(uint8*, uint8*, int64, string) +ret +} +} diff --git a/mono/tests/sizeof-empty-structs.cs b/mono/tests/sizeof-empty-structs.cs new file mode 100644 index 0000000000..ff222c8599 --- /dev/null +++ b/mono/tests/sizeof-empty-structs.cs @@ -0,0 +1,99 @@ +using System; +using System.Runtime.InteropServices; +using System.Reflection; +using System.Linq; + +public struct EmptyStruct { +} + +[StructLayout(LayoutKind.Sequential)] +public struct EmptySequentialStruct { +} + +[StructLayout(LayoutKind.Explicit)] +public struct EmptyExplicitStruct { +} + +[StructLayout(LayoutKind.Sequential, Pack = 4)] +public struct EmptySequentialPackStruct { +} + +[StructLayout(LayoutKind.Explicit, Pack = 4)] +public struct EmptyExplicitPackStruct { +} + +[StructLayout(LayoutKind.Explicit, Size = 0)] +public struct EmptyExplicitSize0Struct { +} + +[StructLayout(LayoutKind.Explicit, Size = 1)] +public struct EmptyExplicitSize1Struct { +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct TestOffsets { + public int A; + public EmptyStruct B; + public int C; + public EmptyExplicitSize0Struct D; + public int E; + public EmptySequentialStruct F; + public int G; +} + +class Program { + private static unsafe void CheckSize (int expected, ref int exitCode) { + var t = typeof(T); + var actualSize = Marshal.SizeOf(t); + + Console.WriteLine($"Marshal.SizeOf({t.Name}) == {actualSize}, expected {expected}"); + + if (actualSize != expected) + exitCode += 1; + } + + // https://bugzilla.xamarin.com/show_bug.cgi?id=18941 + // Marshal.SizeOf should never report 0, even for empty structs or structs with Size=0 attribute + public static int Main () { + int exitCode = 0; + + CheckSize(1, ref exitCode); + CheckSize(1, ref exitCode); + CheckSize(1, ref exitCode); + CheckSize(1, ref exitCode); + CheckSize(1, ref exitCode); + CheckSize(1, ref exitCode); + CheckSize(1, ref exitCode); + CheckSize(19, ref exitCode); + + Console.WriteLine("--"); + + var t = typeof(TestOffsets); + var actualOffsets = ( + from f in t.GetFields() + select (name: f.Name, offset: Marshal.OffsetOf(t, f.Name).ToInt32()) + ).ToList(); + + var expectedOffsets = new [] { + (name: "A", offset: 0), + (name: "B", offset: 4), + (name: "C", offset: 5), + (name: "D", offset: 9), + (name: "E", offset: 10), + (name: "F", offset: 14), + (name: "G", offset: 15) + }; + + if (!actualOffsets.SequenceEqual(expectedOffsets)) { + Console.WriteLine("Field offset mismatch:"); + + for (int i = 0; i < expectedOffsets.Length; i++) { + var expected = expectedOffsets[i]; + var actual = actualOffsets[i]; + Console.WriteLine($"OffsetOf({t.Name}.{actual.name}) == {actual.offset}, expected OffsetOf({expected.name}) == {expected.offset}."); + } + } + + return exitCode; + } +} \ No newline at end of file diff --git a/mono/tests/sleep.cs b/mono/tests/sleep.cs index 0d2110898c..f85d540358 100644 --- a/mono/tests/sleep.cs +++ b/mono/tests/sleep.cs @@ -13,8 +13,10 @@ public class Tests public static int test_0_time_drift () { // Test the Thread.Sleep () is able to deal with time drifting due to interrupts Thread t = new Thread (delegate () { - while (!finished) + while (!finished) { GC.Collect (); + Thread.Yield (); + } }); t.Start (); diff --git a/mono/tests/srtail1.il b/mono/tests/srtail1.il new file mode 100755 index 0000000000..be0fc24442 --- /dev/null +++ b/mono/tests/srtail1.il @@ -0,0 +1,87 @@ +.assembly extern mscorlib { } +.assembly tailcall1 { } +.class A extends [mscorlib]System.Object { +.method public hidebysig static int32 srtail1() cil managed noinlining { +.entrypoint +.maxstack 4 +.locals init (uint8 V_0, object V_1) +newobj instance void [mscorlib]System.Object::.ctor() +stloc.1 +ldloca.s V_0 +conv.u +ldc.i4.0 +conv.i8 +ldc.i4.s 10 +ldloca.s V_1 +call int32 A::srtail2(uint8*, int64, int32, object&) +ret +} +.method private hidebysig static int32 srtail2(uint8* root_stack, int64 diff_stack, int32 counter, object& o) cil managed noinlining { +.maxstack 4 +.locals init (uint8 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0017 +ldarg.0 +ldloca.s V_0 +conv.u +ldarg.0 +sub +ldc.i4.1 +div +conv.i8 +ldarg.2 +ldc.i4.1 +sub +ldarg.3 +tail. call int32 A::srtail2(uint8*, int64, int32, object&) +ret +IL_0017: ldarg.0 +ldloca.s V_0 +conv.u +ldarg.1 +ldstr "rtail1" +call int32 A::check(uint8*, uint8*, int64, string) +ret +} +.method private hidebysig static int32 check(uint8* root_stack, uint8* local, int64 diff_stack, string name) cil managed noinlining { +.maxstack 8 +ldarg.1 +ldarg.0 +sub +ldc.i4.1 +div +conv.i8 +ldarg.2 +beq.s IL_0026 +ldstr "{0} failure {1}" +ldarg.3 +ldarg.0 +ldarg.1 +sub +ldc.i4.1 +div +conv.i8 +box [mscorlib]System.Int64 +call string [mscorlib]System.String::Format(string, object, object) +call void [mscorlib]System.Console::WriteLine(string) +ldc.i4.1 +ret +IL_0026: ldstr "{0} success" +ldarg.3 +call string [mscorlib]System.String::Format(string, object) +call void [mscorlib]System.Console::WriteLine(string) +ldc.i4.0 +ret +} +.method private hidebysig static int32 check(int64 root_stack, uint8* local, int64 diff_stack, string name) cil managed noinlining { +.maxstack 8 +ldarg.0 +conv.u +ldarg.1 +ldarg.2 +ldarg.3 +call int32 A::check(uint8*, uint8*, int64, string) +ret +} +} diff --git a/mono/tests/stail1.il b/mono/tests/stail1.il new file mode 100755 index 0000000000..144472bbb6 --- /dev/null +++ b/mono/tests/stail1.il @@ -0,0 +1,83 @@ +.assembly extern mscorlib { } +.assembly tailcall1 { } +.class A extends [mscorlib]System.Object { +.method public hidebysig static int32 stail1() cil managed noinlining { +.entrypoint +.maxstack 3 +.locals init (uint8 V_0) +ldloca.s V_0 +conv.u +ldc.i4.0 +conv.i8 +ldc.i4.3 +call int32 A::stail2(uint8*, int64, int32) +ret +} +.method private hidebysig static int32 stail2(uint8* root_stack, int64 diff_stack, int32 counter) cil managed noinlining { +.maxstack 4 +.locals init (uint8 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0016 +ldarg.0 +ldloca.s V_0 +conv.u +ldarg.0 +sub +ldc.i4.1 +div +conv.i8 +ldarg.2 +ldc.i4.1 +sub +tail. call int32 A::stail2(uint8*, int64, int32) +ret +IL_0016: ldarg.0 +ldloca.s V_0 +conv.u +ldarg.1 +ldstr "stail1" +call int32 A::check(uint8*, uint8*, int64, string) +ret +} +.method private hidebysig static int32 check(uint8* root_stack, uint8* local, int64 diff_stack, string name) cil managed noinlining { +.maxstack 8 +ldarg.1 +ldarg.0 +sub +ldc.i4.1 +div +conv.i8 +ldarg.2 +beq.s IL_0026 +ldstr "{0} failure {1}" +ldarg.3 +ldarg.0 +ldarg.1 +sub +ldc.i4.1 +div +conv.i8 +box [mscorlib]System.Int64 +call string [mscorlib]System.String::Format(string, object, object) +call void [mscorlib]System.Console::WriteLine(string) +ldc.i4.1 +ret +IL_0026: ldstr "{0} success" +ldarg.3 +call string [mscorlib]System.String::Format(string, object) +call void [mscorlib]System.Console::WriteLine(string) +ldc.i4.0 +ret +} +.method private hidebysig static int32 check(int64 root_stack, uint8* local, int64 diff_stack, string name) cil managed noinlining { +.maxstack 8 +ldarg.0 +conv.u +ldarg.1 +ldarg.2 +ldarg.3 +call int32 A::check(uint8*, uint8*, int64, string) +ret +} +} diff --git a/mono/tests/tail1.il b/mono/tests/tail1.il new file mode 100755 index 0000000000..e36a62a090 --- /dev/null +++ b/mono/tests/tail1.il @@ -0,0 +1,92 @@ +.assembly extern mscorlib { } +.assembly tailcall1 { } +.class A extends [mscorlib]System.Object { +.method public hidebysig specialname rtspecialname instance void .ctor() cil managed +{ +.maxstack 8 +ldarg.0 +call instance void [mscorlib]System.Object::.ctor() +ret +} +.method public hidebysig static int32 tail1() cil managed noinlining { +.entrypoint +.maxstack 4 +.locals init (uint8 V_0) +newobj instance void A::.ctor() +ldloca.s V_0 +conv.u +ldc.i4.0 +conv.i8 +ldc.i4.1 +call instance int32 A::tail2(uint8*, int64, int32) +ret +} +.method private hidebysig instance int32 tail2(uint8* root_stack, int64 diff_stack, int32 counter) cil managed noinlining { +.maxstack 5 +.locals init (uint8 V_0) +ldarg.3 +ldc.i4.0 +ble.s IL_0017 +ldarg.0 +ldarg.1 +ldloca.s V_0 +conv.u +ldarg.1 +sub +ldc.i4.1 +div +conv.i8 +ldarg.3 +ldc.i4.1 +sub +tail. call instance int32 A::tail2(uint8*, int64, int32) +ret +IL_0017: ldarg.1 +ldloca.s V_0 +conv.u +ldarg.2 +ldstr "tail1" +call int32 A::check(uint8*, uint8*, int64, string) +ret +} +.method private hidebysig static int32 check(uint8* root_stack, uint8* local, int64 diff_stack, string name) cil managed noinlining { +.maxstack 8 +ldarg.1 +ldarg.0 +sub +ldc.i4.1 +div +conv.i8 +ldarg.2 +beq.s IL_0026 +ldstr "{0} failure {1}" +ldarg.3 +ldarg.0 +ldarg.1 +sub +ldc.i4.1 +div +conv.i8 +box [mscorlib]System.Int64 +call string [mscorlib]System.String::Format(string, object, object) +call void [mscorlib]System.Console::WriteLine(string) +ldc.i4.1 +ret +IL_0026: ldstr "{0} success" +ldarg.3 +call string [mscorlib]System.String::Format(string, object) +call void [mscorlib]System.Console::WriteLine(string) +ldc.i4.0 +ret +} +.method private hidebysig static int32 check(int64 root_stack, uint8* local, int64 diff_stack, string name) cil managed noinlining { +.maxstack 8 +ldarg.0 +conv.u +ldarg.1 +ldarg.2 +ldarg.3 +call int32 A::check(uint8*, uint8*, int64, string) +ret +} +} diff --git a/mono/tests/tailcall-generic-cast-conservestack-il.il b/mono/tests/tailcall-generic-cast-conservestack-il.il new file mode 100644 index 0000000000..acf680543f --- /dev/null +++ b/mono/tests/tailcall-generic-cast-conservestack-il.il @@ -0,0 +1,672 @@ +/* +Test tailcall-generic-cast-il.il. + +Author: + Jay Krell (jaykrell@microsoft.com) + +Copyright 2018 Microsoft +Licensed under the MIT license. See LICENSE file in the project root for full license information. + +This derived from nearby tailcall-generic-cast-cs.cs. +*/ + +.assembly extern mscorlib { } + +.assembly 'tailcall-generic-cast' { } + +.class public A { } + +.class public B +{ + .method public instance void .ctor ( ) + { + ldarg.0 + tail. call instance void [mscorlib]System.Object::.ctor ( ) + ret + } +} + +.class public C +{ + .field private static int32 i + + .method public static void + check (int64 stack1, int64 stack2) noinlining + { + ldsfld int32 C::i + ldc.i4.1 + add + stsfld int32 C::i + //ldarg.0 + //brfalse.s IL_0010 + //ret + +//IL_0010: + ldarg.0 + ldarg.1 + beq.s IL_0037 + + ldstr "{0} tailcall failure" + ldsfld int32 C::i + box [mscorlib]System.Int32 + call void [mscorlib]System.Console::WriteLine (string, object) + ldc.i4.1 + tail. call void [mscorlib]System.Environment::Exit (int32) +IL_0037: + ret + } + + .method public static !!T + cast1 (object o, int32 counter, int64 stack) noinlining + { + .locals init (int32 V_0) + + ldarg.1 + ldc.i4.0 + ble.s IL_0012 + + ldarg.0 + ldarg.1 + ldc.i4.1 + sub + ldloca.s V_0 + conv.u + conv.u8 + tail. call !!0 C::cast1 (object, int32, int64) + ret + +IL_0012: + ldloca.s V_0 + conv.u + conv.u8 + ldarg.2 + call void C::check (int64, int64) + ldarg.0 + unbox.any !!T + ret + } + + .method public static class B + cast2 (object o, int32 counter, int64 stack) noinlining + { + .locals init (int32 V_0) + + ldarg.1 + ldc.i4.0 + ble.s IL_0012 + + ldarg.0 + ldarg.1 + ldc.i4.1 + sub + ldloca.s V_0 + conv.u + conv.u8 + tail. call class B C::cast2 (object, int32, int64) + ret + +IL_0012: + ldloca.s V_0 + conv.u + conv.u8 + ldarg.2 + call void C::check (int64, int64) + ldarg.0 + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + tail. call !!0 C::cast1 (object, int32, int64) + ret + } + + .method public static !!T + cast3 (object o, int32 counter, int64 stack) noinlining + { + .locals init (int32 V_0) + + ldarg.1 + ldc.i4.0 + ble.s IL_0012 + + ldarg.0 + ldarg.1 + ldc.i4.1 + sub + ldloca.s V_0 + conv.u + conv.u8 + tail. call !!0 C::cast3 (object, int32, int64) + ret + +IL_0012: + ldloca.s V_0 + conv.u + conv.u8 + ldarg.2 + call void C::check (int64, int64) + ldarg.0 + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + tail. call !!0 C::cast1 (object, int32, int64) + ret + } + + .method public static class B[] + cast4 (object o, int32 counter, int64 stack) noinlining + { + .locals init (int32 V_0) + + ldarg.1 + ldc.i4.0 + ble.s IL_0012 + + ldarg.0 + ldarg.1 + ldc.i4.1 + sub + ldloca.s V_0 + conv.u + conv.u8 + tail. call class B[] C::cast4 (object, int32, int64) + ret + +IL_0012: + ldloca.s V_0 + conv.u + conv.u8 + ldarg.2 + call void C::check (int64, int64) + ldarg.0 + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + tail. call !!0 C::cast1 (object, int32, int64) + ret + } + + .method public static !!T[] + cast5 (object o, int32 counter, int64 stack) noinlining + { + .locals init (int32 V_0) + + ldarg.1 + ldc.i4.0 + ble.s IL_0012 + + ldarg.0 + ldarg.1 + ldc.i4.1 + sub + ldloca.s V_0 + conv.u + conv.u8 + tail. call !!0[] C::cast5 (object, int32, int64) + ret + +IL_0012: + ldloca.s V_0 + conv.u + conv.u8 + ldarg.2 + call void C::check (int64, int64) + ldarg.0 + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + tail. call !!0 C::cast1 (object, int32, int64) + ret + } +} + +.class public D`1 +{ + .method public static void + check (int64 stack1, int64 stack2) noinlining + { + ldarg.0 + ldarg.1 + tail. call void C::check (int64, int64) + ret + } + + .method public static !!T + cast1 (object o, int32 counter, int64 stack) noinlining + { + .locals init (int32 V_0) + + ldarg.1 + ldc.i4.0 + ble.s IL_0012 + + ldarg.0 + ldarg.1 + ldc.i4.1 + sub + ldloca.s V_0 + conv.u + conv.u8 + tail. call !!0 class D`1::cast1 (object, int32, int64) + ret + +IL_0012: + ldloca.s V_0 + conv.u + conv.u8 + ldarg.2 + call void class D`1::check (int64, int64) + ldarg.0 + unbox.any !!T + ret + } + + .method public static class B + cast2 (object o, int32 counter, int64 stack) noinlining + { + .locals init (int32 V_0) + + ldarg.1 + ldc.i4.0 + ble.s IL_0012 + + ldarg.0 + ldarg.1 + ldc.i4.1 + sub + ldloca.s V_0 + conv.u + conv.u8 + tail. call class B class D`1::cast2 (object, int32, int64) + ret + +IL_0012: + ldloca.s V_0 + conv.u + conv.u8 + ldarg.2 + call void class D`1::check (int64, int64) + ldarg.0 + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + tail. call !!0 class D`1::cast1 (object, int32, int64) + ret + } + + .method public static !!T + cast3 (object o, int32 counter, int64 stack) noinlining + { + .locals init (int32 V_0) + + ldarg.1 + ldc.i4.0 + ble.s IL_0012 + + ldarg.0 + ldarg.1 + ldc.i4.1 + sub + ldloca.s V_0 + conv.u + conv.u8 + tail. call !!0 class D`1::cast3 (object, int32, int64) + ret + +IL_0012: + ldloca.s V_0 + conv.u + conv.u8 + ldarg.2 + call void class D`1::check (int64, int64) + ldarg.0 + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + tail. call !!0 class D`1::cast1 (object, int32, int64) + ret + } + + .method public static class B[] + cast4 (object o, int32 counter, int64 stack) noinlining + { + .locals init (int32 V_0) + + ldarg.1 + ldc.i4.0 + ble.s IL_0012 + + ldarg.0 + ldarg.1 + ldc.i4.1 + sub + ldloca.s V_0 + conv.u + conv.u8 + tail. call class B[] class D`1::cast4 (object, int32, int64) + ret + +IL_0012: + ldloca.s V_0 + conv.u + conv.u8 + ldarg.2 + call void class D`1::check (int64, int64) + ldarg.0 + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + tail. call !!0 class D`1::cast1 (object, int32, int64) + ret + } + + .method public static !!T[] + cast5 (object o, int32 counter, int64 stack) noinlining + { + .locals init (int32 V_0) + + ldarg.1 + ldc.i4.0 + ble.s IL_0012 + + ldarg.0 + ldarg.1 + ldc.i4.1 + sub + ldloca.s V_0 + conv.u + conv.u8 + tail. call !!0[] class D`1::cast5 (object, int32, int64) + ret + +IL_0012: + ldloca.s V_0 + conv.u + conv.u8 + ldarg.2 + call void class D`1::check (int64, int64) + ldarg.0 + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + tail. call !!0 class D`1::cast1 (object, int32, int64) + ret + } + + .method public static !T1 + cast6 (object o, int32 counter, int64 stack) noinlining + { + .locals init (int32 V_0) + + ldarg.1 + ldc.i4.0 + ble.s IL_0012 + + ldarg.0 + ldarg.1 + ldc.i4.1 + sub + ldloca.s V_0 + conv.u + conv.u8 + tail. call !0 class D`1::cast6 (object, int32, int64) + ret + +IL_0012: + ldloca.s V_0 + conv.u + conv.u8 + ldarg.2 + call void class D`1::check (int64, int64) + ldarg.0 + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + tail. call !!0 class D`1::cast1 (object, int32, int64) + ret + } + + .method public static !T1 + cast7 (object o, int32 counter, int64 stack) noinlining + { + .locals init (int32 V_0) + + ldarg.1 + ldc.i4.0 + ble.s IL_0012 + + ldarg.0 + ldarg.1 + ldc.i4.1 + sub + ldloca.s V_0 + conv.u + conv.u8 + tail. call !0 class D`1::cast7 (object, int32, int64) + ret + +IL_0012: + ldloca.s V_0 + conv.u + conv.u8 + ldarg.2 + call void class D`1::check (int64, int64) + ldarg.0 + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + tail. call !!0 class D`1::cast1 (object, int32, int64) + ret + } + + .method public static !T1[] + cast8 (object o, int32 counter, int64 stack) noinlining + { + .locals init (int32 V_0) + + ldarg.1 + ldc.i4.0 + ble.s IL_0012 + + ldarg.0 + ldarg.1 + ldc.i4.1 + sub + ldloca.s V_0 + conv.u + conv.u8 + tail. call !0[] class D`1::cast8 (object, int32, int64) + ret + +IL_0012: + ldloca.s V_0 + conv.u + conv.u8 + ldarg.2 + call void class D`1::check (int64, int64) + ldarg.0 + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + tail. call !!0 class D`1::cast3 (object, int32, int64) + ret + } + + .method public static !T1[] + cast9 (object o, int32 counter, int64 stack) noinlining + { + .locals init (int32 V_0) + + ldarg.1 + ldc.i4.0 + ble.s IL_0012 + + ldarg.0 + ldarg.1 + ldc.i4.1 + sub + ldloca.s V_0 + conv.u + conv.u8 + tail. call !0[] class D`1::cast9 (object, int32, int64) + ret + +IL_0012: + ldloca.s V_0 + conv.u + conv.u8 + ldarg.2 + call void class D`1::check (int64, int64) + ldarg.0 + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + tail. call !!0 class D`1::cast3 (object, int32, int64) + ret + } + + .method public + instance void .ctor ( ) + { + ldarg.0 + tail. call instance void [mscorlib]System.Object::.ctor ( ) + ret + } +} + +.class public E +{ + .field private static int32 i + + .method private static void + print (object o) noinlining + { + ldsfld int32 E::i + ldc.i4.1 + add + stsfld int32 E::i + ret + } + + .method public static void + Main (string[] args) noinlining + { + .entrypoint + + newobj instance void B::.ctor ( ) + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + call class B C::cast2 (object, int32, int64) + call void E::print (object) + + newobj instance void B::.ctor ( ) + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + call !!0 C::cast3 (object, int32, int64) + call void E::print (object) + + ldc.i4.1 + newarr B + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + call !!0 C::cast3 (object, int32, int64) + call void E::print (object) + + ldc.i4.1 + newarr B + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + call class B[] C::cast4 (object, int32, int64) + call void E::print (object) + + ldc.i4.1 + newarr B + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + call !!0[] C::cast5 (object, int32, int64) + call void E::print (object) + + newobj instance void B::.ctor ( ) + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + call class B class D`1::cast2 (object, int32, int64) + call void E::print (object) + + newobj instance void B::.ctor ( ) + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + call !!0 class D`1::cast3 (object, int32, int64) + call void E::print (object) + + ldc.i4.1 + newarr B + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + call !!0 class D`1::cast3 (object, int32, int64) + call void E::print (object) + + ldc.i4.1 + newarr B + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + call class B[] class D`1::cast4 (object, int32, int64) + call void E::print (object) + + ldc.i4.1 + newarr B + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + call !!0[] class D`1::cast5 (object, int32, int64) + call void E::print (object) + + newobj instance void B::.ctor ( ) + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + call !0 class D`1::cast6 (object, int32, int64) + call void E::print (object) + + newobj instance void B::.ctor ( ) + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + call !0 class D`1::cast7 (object, int32, int64) + call void E::print (object) + + ldc.i4.1 + newarr B + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + call !0 class D`1::cast7 (object, int32, int64) + call void E::print (object) + + ldc.i4.1 + newarr B + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + call !0[] class D`1::cast8 (object, int32, int64) + call void E::print (object) + + ldc.i4.1 + newarr B + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + + call !0[] class D`1::cast9 (object, int32, int64) + call void E::print (object) + + ret + } +} diff --git a/mono/tests/tailcall-generic-cast-cs.cs b/mono/tests/tailcall-generic-cast-cs.cs new file mode 100755 index 0000000000..80fbb0839f --- /dev/null +++ b/mono/tests/tailcall-generic-cast-cs.cs @@ -0,0 +1,229 @@ +/* +Test tailcall-generic-cast-cs.cs. + +Author: + Jay Krell (jaykrell@microsoft.com) + +Copyright 2018 Microsoft +Licensed under the MIT license. See LICENSE file in the project root for full license information. + +Test many (but not all) variations of tail calls with generics and vtable_arg. +Yet missing here is actual virtual functions. + +This is compiled both from C# w/o tail. prefixes and IL w/. +The C# code does not presently check for tail calling. +*/ +using System; +using System.Runtime.CompilerServices; +using static System.Runtime.CompilerServices.MethodImplOptions; + +public class A { } + +public class B { } + +unsafe public class C +{ + static int i; + + [MethodImpl (NoInlining)] + public static void check (long stack1, long stack2) + { +// NOTE: This is mangled in order to feed into the edited IL. + ++i; + if (stack1 != 0) // remove from IL + return; // remove from IL + if (stack1 != stack2) { + Console.WriteLine ("{0} tailcall failure", i); + Environment.Exit (1); + return; + } + //Console.WriteLine ("{0} tailcall success", ++i); + } + + [MethodImpl (NoInlining)] + public static T cast1 (object o, int counter = 100, long stack = 0) + { + int local; + if (counter > 0) + return cast1 (o, counter - 1, (long)&local); + check ((long)&local, stack); + return (T)o; + } + + [MethodImpl (NoInlining)] + public static B cast2 (object o, int counter = 100, long stack = 0) + { + int local; + if (counter > 0) + return cast2 (o, counter - 1, (long)&local); + check ((long)&local, stack); + return cast1 (o); + } + + [MethodImpl (NoInlining)] + public static T cast3 (object o, int counter = 100, long stack = 0) + { + int local; + if (counter > 0) + return cast3 (o, counter - 1, (long)&local); + check ((long)&local, stack); + return cast1 (o); + } + + [MethodImpl (NoInlining)] + public static B[] cast4 (object o, int counter = 100, long stack = 0) + { + int local; + if (counter > 0) + return cast4 (o, counter - 1, (long)&local); + check ((long)&local, stack); + return cast1 (o); + } + + [MethodImpl (NoInlining)] + public static T[] cast5 (object o, int counter = 100, long stack = 0) + { + int local; + if (counter > 0) + return cast5 (o, counter - 1, (long)&local); + check ((long)&local, stack); + return cast1 (o); + } +} + +unsafe public class D +{ + [MethodImpl (NoInlining)] + public static void check (long stack1, long stack2) + { + C.check (stack1, stack2); + } + + [MethodImpl (NoInlining)] + public static T cast1 (object o, int counter = 100, long stack = 0) + { + int local; + if (counter > 0) + return cast1 (o, counter - 1, (long)&local); + check ((long)&local, stack); + return (T)o; + } + + [MethodImpl (NoInlining)] + public static B cast2 (object o, int counter = 100, long stack = 0) + { + int local; + if (counter > 0) + return cast2 (o, counter - 1, (long)&local); + check ((long)&local, stack); + return cast1 (o); + } + + [MethodImpl (NoInlining)] + public static T cast3 (object o, int counter = 100, long stack = 0) + { + int local; + if (counter > 0) + return cast3 (o, counter - 1, (long)&local); + check ((long)&local, stack); + return cast1 (o); + } + + [MethodImpl (NoInlining)] + public static B[] cast4 (object o, int counter = 100, long stack = 0) + { + int local; + if (counter > 0) + return cast4 (o, counter - 1, (long)&local); + check ((long)&local, stack); + return cast1 (o); + } + + [MethodImpl (NoInlining)] + public static T[] cast5 (object o, int counter = 100, long stack = 0) + { + int local; + if (counter > 0) + return cast5 (o, counter - 1, (long)&local); + check ((long)&local, stack); + return cast1 (o); + } + + [MethodImpl (NoInlining)] + public static T1 cast6 (object o, int counter = 100, long stack = 0) + { + int local; + if (counter > 0) + return cast6 (o, counter - 1, (long)&local); + check ((long)&local, stack); + return cast1 (o); + } + + [MethodImpl (NoInlining)] + public static T1 cast7 (object o, int counter = 100, long stack = 0) + { + int local; + if (counter > 0) + return cast7 (o, counter - 1, (long)&local); + check ((long)&local, stack); + return cast1 (o); + } + + [MethodImpl (NoInlining)] + public static T1[] cast8 (object o, int counter = 100, long stack = 0) + { + int local; + if (counter > 0) + return cast8 (o, counter - 1, (long)&local); + check ((long)&local, stack); + return cast3 (o); + } + + [MethodImpl (NoInlining)] + public static T1[] cast9 (object o, int counter = 100, long stack = 0) + { + int local; + if (counter > 0) + return cast9 (o, counter - 1, (long)&local); + check ((long)&local, stack); + return cast3 (o); + } +} + +public class E +{ + static int i; + + [MethodImpl (NoInlining)] + static void print (object o) + { + ++i; + //Console.WriteLine("{0} {1}", i, o); + //Console.WriteLine(i); + } + + [MethodImpl (NoInlining)] + public static void Main(string[] args) + { + print (C.cast2 (new B())); + print (C.cast3 (new B())); + print (C.cast3 (new B[1])); + print (C.cast4 (new B[1])); + print (C.cast5 (new B [1])); + + print (D.cast2 (new B())); + print (D.cast3 (new B())); + print (D.cast3 (new B[1])); + print (D.cast4 (new B[1])); + print (D.cast5 (new B [1])); + + print (D.cast6 (new B())); + print (D.cast7 (new B())); + print (D.cast7 (new B[1])); + print (D.cast8 (new B[1])); + print (D.cast9 (new B [1])); + + //Console.WriteLine("done"); + //Console.WriteLine("success"); + } +} diff --git a/mono/tests/tailcall-generic-cast-nocrash-il.il b/mono/tests/tailcall-generic-cast-nocrash-il.il new file mode 100644 index 0000000000..656bbbae00 --- /dev/null +++ b/mono/tests/tailcall-generic-cast-nocrash-il.il @@ -0,0 +1,674 @@ +/* +Test tailcall-generic-cast-il.il. + +Author: + Jay Krell (jaykrell@microsoft.com) + +Copyright 2018 Microsoft +Licensed under the MIT license. See LICENSE file in the project root for full license information. + +This derived from nearby tailcall-generic-cast-cs.cs. +*/ + +.assembly extern mscorlib { } + +.assembly 'tailcall-generic-cast' { } + +.class public A { } + +.class public B +{ + .method public instance void .ctor ( ) + { + ldarg.0 + tail. call instance void [mscorlib]System.Object::.ctor ( ) + ret + } +} + +.class public C +{ + .field private static int32 i + + .method public static void + check (int64 stack1, int64 stack2) noinlining + { +/* + ldsfld int32 C::i + ldc.i4.1 + add + stsfld int32 C::i + //ldarg.0 + //brfalse.s IL_0010 + //ret + +//IL_0010: + ldarg.0 + ldarg.1 + beq.s IL_0037 + + ldstr "{0} tailcall failure" + ldsfld int32 C::i + box [mscorlib]System.Int32 + call void [mscorlib]System.Console::WriteLine (string, object) + ldc.i4.1 + tail. call void [mscorlib]System.Environment::Exit (int32) +IL_0037: +*/ + ret + } + + .method public static !!T + cast1 (object o, int32 counter, int64 stack) noinlining + { + .locals init (int32 V_0) + + ldarg.1 + ldc.i4.0 + ble.s IL_0012 + + ldarg.0 + ldarg.1 + ldc.i4.1 + sub + ldloca.s V_0 + conv.u + conv.u8 + tail. call !!0 C::cast1 (object, int32, int64) + ret + +IL_0012: + ldloca.s V_0 + conv.u + conv.u8 + ldarg.2 + call void C::check (int64, int64) + ldarg.0 + unbox.any !!T + ret + } + + .method public static class B + cast2 (object o, int32 counter, int64 stack) noinlining + { + .locals init (int32 V_0) + + ldarg.1 + ldc.i4.0 + ble.s IL_0012 + + ldarg.0 + ldarg.1 + ldc.i4.1 + sub + ldloca.s V_0 + conv.u + conv.u8 + tail. call class B C::cast2 (object, int32, int64) + ret + +IL_0012: + ldloca.s V_0 + conv.u + conv.u8 + ldarg.2 + call void C::check (int64, int64) + ldarg.0 + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + tail. call !!0 C::cast1 (object, int32, int64) + ret + } + + .method public static !!T + cast3 (object o, int32 counter, int64 stack) noinlining + { + .locals init (int32 V_0) + + ldarg.1 + ldc.i4.0 + ble.s IL_0012 + + ldarg.0 + ldarg.1 + ldc.i4.1 + sub + ldloca.s V_0 + conv.u + conv.u8 + tail. call !!0 C::cast3 (object, int32, int64) + ret + +IL_0012: + ldloca.s V_0 + conv.u + conv.u8 + ldarg.2 + call void C::check (int64, int64) + ldarg.0 + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + tail. call !!0 C::cast1 (object, int32, int64) + ret + } + + .method public static class B[] + cast4 (object o, int32 counter, int64 stack) noinlining + { + .locals init (int32 V_0) + + ldarg.1 + ldc.i4.0 + ble.s IL_0012 + + ldarg.0 + ldarg.1 + ldc.i4.1 + sub + ldloca.s V_0 + conv.u + conv.u8 + tail. call class B[] C::cast4 (object, int32, int64) + ret + +IL_0012: + ldloca.s V_0 + conv.u + conv.u8 + ldarg.2 + call void C::check (int64, int64) + ldarg.0 + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + tail. call !!0 C::cast1 (object, int32, int64) + ret + } + + .method public static !!T[] + cast5 (object o, int32 counter, int64 stack) noinlining + { + .locals init (int32 V_0) + + ldarg.1 + ldc.i4.0 + ble.s IL_0012 + + ldarg.0 + ldarg.1 + ldc.i4.1 + sub + ldloca.s V_0 + conv.u + conv.u8 + tail. call !!0[] C::cast5 (object, int32, int64) + ret + +IL_0012: + ldloca.s V_0 + conv.u + conv.u8 + ldarg.2 + call void C::check (int64, int64) + ldarg.0 + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + tail. call !!0 C::cast1 (object, int32, int64) + ret + } +} + +.class public D`1 +{ + .method public static void + check (int64 stack1, int64 stack2) noinlining + { + ldarg.0 + ldarg.1 + tail. call void C::check (int64, int64) + ret + } + + .method public static !!T + cast1 (object o, int32 counter, int64 stack) noinlining + { + .locals init (int32 V_0) + + ldarg.1 + ldc.i4.0 + ble.s IL_0012 + + ldarg.0 + ldarg.1 + ldc.i4.1 + sub + ldloca.s V_0 + conv.u + conv.u8 + tail. call !!0 class D`1::cast1 (object, int32, int64) + ret + +IL_0012: + ldloca.s V_0 + conv.u + conv.u8 + ldarg.2 + call void class D`1::check (int64, int64) + ldarg.0 + unbox.any !!T + ret + } + + .method public static class B + cast2 (object o, int32 counter, int64 stack) noinlining + { + .locals init (int32 V_0) + + ldarg.1 + ldc.i4.0 + ble.s IL_0012 + + ldarg.0 + ldarg.1 + ldc.i4.1 + sub + ldloca.s V_0 + conv.u + conv.u8 + tail. call class B class D`1::cast2 (object, int32, int64) + ret + +IL_0012: + ldloca.s V_0 + conv.u + conv.u8 + ldarg.2 + call void class D`1::check (int64, int64) + ldarg.0 + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + tail. call !!0 class D`1::cast1 (object, int32, int64) + ret + } + + .method public static !!T + cast3 (object o, int32 counter, int64 stack) noinlining + { + .locals init (int32 V_0) + + ldarg.1 + ldc.i4.0 + ble.s IL_0012 + + ldarg.0 + ldarg.1 + ldc.i4.1 + sub + ldloca.s V_0 + conv.u + conv.u8 + tail. call !!0 class D`1::cast3 (object, int32, int64) + ret + +IL_0012: + ldloca.s V_0 + conv.u + conv.u8 + ldarg.2 + call void class D`1::check (int64, int64) + ldarg.0 + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + tail. call !!0 class D`1::cast1 (object, int32, int64) + ret + } + + .method public static class B[] + cast4 (object o, int32 counter, int64 stack) noinlining + { + .locals init (int32 V_0) + + ldarg.1 + ldc.i4.0 + ble.s IL_0012 + + ldarg.0 + ldarg.1 + ldc.i4.1 + sub + ldloca.s V_0 + conv.u + conv.u8 + tail. call class B[] class D`1::cast4 (object, int32, int64) + ret + +IL_0012: + ldloca.s V_0 + conv.u + conv.u8 + ldarg.2 + call void class D`1::check (int64, int64) + ldarg.0 + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + tail. call !!0 class D`1::cast1 (object, int32, int64) + ret + } + + .method public static !!T[] + cast5 (object o, int32 counter, int64 stack) noinlining + { + .locals init (int32 V_0) + + ldarg.1 + ldc.i4.0 + ble.s IL_0012 + + ldarg.0 + ldarg.1 + ldc.i4.1 + sub + ldloca.s V_0 + conv.u + conv.u8 + tail. call !!0[] class D`1::cast5 (object, int32, int64) + ret + +IL_0012: + ldloca.s V_0 + conv.u + conv.u8 + ldarg.2 + call void class D`1::check (int64, int64) + ldarg.0 + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + tail. call !!0 class D`1::cast1 (object, int32, int64) + ret + } + + .method public static !T1 + cast6 (object o, int32 counter, int64 stack) noinlining + { + .locals init (int32 V_0) + + ldarg.1 + ldc.i4.0 + ble.s IL_0012 + + ldarg.0 + ldarg.1 + ldc.i4.1 + sub + ldloca.s V_0 + conv.u + conv.u8 + tail. call !0 class D`1::cast6 (object, int32, int64) + ret + +IL_0012: + ldloca.s V_0 + conv.u + conv.u8 + ldarg.2 + call void class D`1::check (int64, int64) + ldarg.0 + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + tail. call !!0 class D`1::cast1 (object, int32, int64) + ret + } + + .method public static !T1 + cast7 (object o, int32 counter, int64 stack) noinlining + { + .locals init (int32 V_0) + + ldarg.1 + ldc.i4.0 + ble.s IL_0012 + + ldarg.0 + ldarg.1 + ldc.i4.1 + sub + ldloca.s V_0 + conv.u + conv.u8 + tail. call !0 class D`1::cast7 (object, int32, int64) + ret + +IL_0012: + ldloca.s V_0 + conv.u + conv.u8 + ldarg.2 + call void class D`1::check (int64, int64) + ldarg.0 + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + tail. call !!0 class D`1::cast1 (object, int32, int64) + ret + } + + .method public static !T1[] + cast8 (object o, int32 counter, int64 stack) noinlining + { + .locals init (int32 V_0) + + ldarg.1 + ldc.i4.0 + ble.s IL_0012 + + ldarg.0 + ldarg.1 + ldc.i4.1 + sub + ldloca.s V_0 + conv.u + conv.u8 + tail. call !0[] class D`1::cast8 (object, int32, int64) + ret + +IL_0012: + ldloca.s V_0 + conv.u + conv.u8 + ldarg.2 + call void class D`1::check (int64, int64) + ldarg.0 + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + tail. call !!0 class D`1::cast3 (object, int32, int64) + ret + } + + .method public static !T1[] + cast9 (object o, int32 counter, int64 stack) noinlining + { + .locals init (int32 V_0) + + ldarg.1 + ldc.i4.0 + ble.s IL_0012 + + ldarg.0 + ldarg.1 + ldc.i4.1 + sub + ldloca.s V_0 + conv.u + conv.u8 + tail. call !0[] class D`1::cast9 (object, int32, int64) + ret + +IL_0012: + ldloca.s V_0 + conv.u + conv.u8 + ldarg.2 + call void class D`1::check (int64, int64) + ldarg.0 + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + tail. call !!0 class D`1::cast3 (object, int32, int64) + ret + } + + .method public + instance void .ctor ( ) + { + ldarg.0 + tail. call instance void [mscorlib]System.Object::.ctor ( ) + ret + } +} + +.class public E +{ + .field private static int32 i + + .method private static void + print (object o) noinlining + { + ldsfld int32 E::i + ldc.i4.1 + add + stsfld int32 E::i + ret + } + + .method public static void + Main (string[] args) noinlining + { + .entrypoint + + newobj instance void B::.ctor ( ) + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + call class B C::cast2 (object, int32, int64) + call void E::print (object) + + newobj instance void B::.ctor ( ) + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + call !!0 C::cast3 (object, int32, int64) + call void E::print (object) + + ldc.i4.1 + newarr B + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + call !!0 C::cast3 (object, int32, int64) + call void E::print (object) + + ldc.i4.1 + newarr B + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + call class B[] C::cast4 (object, int32, int64) + call void E::print (object) + + ldc.i4.1 + newarr B + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + call !!0[] C::cast5 (object, int32, int64) + call void E::print (object) + + newobj instance void B::.ctor ( ) + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + call class B class D`1::cast2 (object, int32, int64) + call void E::print (object) + + newobj instance void B::.ctor ( ) + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + call !!0 class D`1::cast3 (object, int32, int64) + call void E::print (object) + + ldc.i4.1 + newarr B + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + call !!0 class D`1::cast3 (object, int32, int64) + call void E::print (object) + + ldc.i4.1 + newarr B + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + call class B[] class D`1::cast4 (object, int32, int64) + call void E::print (object) + + ldc.i4.1 + newarr B + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + call !!0[] class D`1::cast5 (object, int32, int64) + call void E::print (object) + + newobj instance void B::.ctor ( ) + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + call !0 class D`1::cast6 (object, int32, int64) + call void E::print (object) + + newobj instance void B::.ctor ( ) + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + call !0 class D`1::cast7 (object, int32, int64) + call void E::print (object) + + ldc.i4.1 + newarr B + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + call !0 class D`1::cast7 (object, int32, int64) + call void E::print (object) + + ldc.i4.1 + newarr B + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + call !0[] class D`1::cast8 (object, int32, int64) + call void E::print (object) + + ldc.i4.1 + newarr B + ldc.i4.s 100 + ldc.i4.0 + conv.i8 + + call !0[] class D`1::cast9 (object, int32, int64) + tail. call void E::print (object) + + ret + } +} diff --git a/mono/tests/tailcall-interface-conservestack.il b/mono/tests/tailcall-interface-conservestack.il new file mode 100644 index 0000000000..22d266901c --- /dev/null +++ b/mono/tests/tailcall-interface-conservestack.il @@ -0,0 +1,1711 @@ +/* +Author: + Jay Krell (jaykrell@microsoft.com) + +Copyright 2018 Microsoft +Licensed under the MIT license. See LICENSE file in the project root for full license information. + +Derived from tailcall-interface.cs. +*/ +.assembly extern mscorlib { } +.assembly 'tailcall-interface' { } + +.class public sequential sealed Point +extends [mscorlib]System.ValueType +{ +.field public int32 x +.field public int32 y +} +.class interface private abstract I1 +{ + +.method public newslot abstract virtual instance void perturb_interface_offset1() { } + +.method public newslot abstract virtual instance int32 F1(class I2 i2, int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ +} + +.method public newslot abstract virtual instance int32 GF1(class I2 i2, int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ +} + +} + +.class interface private abstract GI1`1 +{ + +.method public newslot abstract virtual instance void perturb_interface_offset1() +{ +} + +.method public newslot abstract virtual instance void perturb_interface_offset2() +{ +} + +.method public newslot abstract virtual instance int32 F1(class GI2`1 i2, int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ +} + +.method public newslot abstract virtual instance int32 GF1(class GI2`1 i2, int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ +} + +.method public newslot abstract virtual instance int32 HF1(class GI2`1 i2, int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ +} +} + +.class interface private abstract I2 +{ +.method public newslot abstract virtual instance void perturb_interface_offset1() { } + +.method public newslot abstract virtual instance void perturb_interface_offset2() { } + +.method public newslot abstract virtual instance void perturb_interface_offset3() { } + +.method public newslot abstract virtual instance int32 F2(class I1 i1, int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ +} + +.method public newslot abstract virtual instance int32 GF2(class I1 i1, int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ +} + +} + +.class interface private abstract GI2`1 +{ + +.method public newslot abstract virtual instance void perturb_interface_offset1() +{ +} + +.method public newslot abstract virtual instance void perturb_interface_offset2() +{ +} + +.method public newslot abstract virtual instance void perturb_interface_offset3() +{ +} + +.method public newslot abstract virtual instance void perturb_interface_offset4() +{ +} + +.method public newslot abstract virtual instance int32 F2(class GI1`1 i1, int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ +} +.method public newslot abstract virtual instance int32 GF2(class GI1`1 i1, int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ +} +.method public newslot abstract virtual instance int32 HF2(class GI1`1 i1, int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ +} +} + +.class public C1 implements I1 +{ +.field private static int32 i +.field public static int32 errors + +.method private newslot virtual final instance void I1.perturb_interface_offset1() +{ +.override I1::perturb_interface_offset1 +ret +} + +.method public static int32 check(int64 stack1, int64 stack2) +{ +.locals init (int32 V_0) +ldsfld int32 C1::i +ldc.i4.1 +add +stsfld int32 C1::i +ldarg.0 +ldarg.1 +bne.un.s IL_0013 +ldc.i4.0 +br.s IL_0014 +IL_0013: +ldc.i4.1 +IL_0014: +stloc.0 +ldloc.0 +brtrue.s IL_001a +ldc.i4.0 +ret + +IL_001a: +ldsfld int32 C1::errors +ldc.i4.1 +add +stsfld int32 C1::errors +ldstr "{0} tailcall failure" +ldsfld int32 C1::i +box [mscorlib]System.Int32 +call void [mscorlib]System.Console::WriteLine(string, object) +ldloc.0 +ret +} +.method private newslot virtual final instance int32 I1.F1(class I2 i2, int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ +.override I1::F1 +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0014 +ldarg.1 +ldarg.0 +ldarg.2 +ldc.i4.1 +sub +ldarg.3 +ldloca.s V_0 +conv.u +conv.u8 +tail. +callvirt instance int32 I2::F2(class I1, int32, int64, int64) +ret +IL_0014: +ldloca.s V_0 +conv.u +conv.u8 +ldarg.s current_stack +tail. +call int32 C1::check(int64, int64) +ret +} +.method private newslot virtual final instance int32 I1.GF1(class I2 i2, int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ +.override I1::GF1 +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0014 +ldarg.1 +ldarg.0 +ldarg.2 +ldc.i4.1 +sub +ldarg.3 +ldloca.s V_0 +conv.u +conv.u8 +tail. +callvirt instance int32 I2::GF2(class I1, int32, int64, int64) +ret +IL_0014: +ldloca.s V_0 +conv.u +conv.u8 +ldarg.s current_stack +tail. +call int32 C1::check(int64, int64) +ret +} +.method public instance void .ctor() +{ +ldarg.0 +tail. +call instance void [mscorlib]System.Object::.ctor() +ret +} +} +.class public GC1`1 +implements class GI1`1 +{ +.method private newslot virtual final instance void 'GI1.perturb_interface_offset1'() +{ +.override method instance void class GI1`1::perturb_interface_offset1() +ret +} +.method private newslot virtual final instance void 'GI1.perturb_interface_offset2'() +{ +.override method instance void class GI1`1::perturb_interface_offset2() +ret +} +.method public static int32 check(int64 stack1, int64 stack2) +{ +ldarg.0 +ldarg.1 +tail. +call int32 C1::check(int64, int64) +ret +} +.method private newslot virtual final instance int32 'GI1.F1'(class GI2`1 i2, int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ +.override method instance int32 class GI1`1::F1(class GI2`1, +int32, +int64, +int64) +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0014 +ldarg.1 +ldarg.0 +ldarg.2 +ldc.i4.1 +sub +ldarg.3 +ldloca.s V_0 +conv.u +conv.u8 +tail. +callvirt instance int32 class GI2`1::F2(class GI1`1, int32, int64, int64) +ret +IL_0014: +ldloca.s V_0 +conv.u +conv.u8 +ldarg.s current_stack +tail. +call int32 class GC1`1::check(int64, int64) +ret +} +.method private newslot virtual final instance int32 'GI1.GF1'(class GI2`1 i2, int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ +.override method instance int32 class GI1`1::GF1<[1]>(class GI2`1, +int32, +int64, +int64) +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0014 +ldarg.1 +ldarg.0 +ldarg.2 +ldc.i4.1 +sub +ldarg.3 +ldloca.s V_0 +conv.u +conv.u8 +tail. +callvirt instance int32 class GI2`1::GF2(class GI1`1, int32, int64, int64) +ret +IL_0014: +ldloca.s V_0 +conv.u +conv.u8 +ldarg.s current_stack +tail. +call int32 class GC1`1::check(int64, int64) +ret +} +.method private newslot virtual final instance int32 'GI1.HF1'(class GI2`1 i2, int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ +.override method instance int32 class GI1`1::HF1<[1]>(class GI2`1, +int32, +int64, +int64) +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0014 +ldarg.1 +ldarg.0 +ldarg.2 +ldc.i4.1 +sub +ldarg.3 +ldloca.s V_0 +conv.u +conv.u8 +tail. +callvirt instance int32 class GI2`1::HF2(class GI1`1, int32, int64, int64) +ret +IL_0014: +ldloca.s V_0 +conv.u +conv.u8 +ldarg.s current_stack +tail. +call int32 class GC1`1::check(int64, int64) +ret +} +.method public instance void .ctor() +{ +ldarg.0 +tail. +call instance void [mscorlib]System.Object::.ctor() +ret +} +} +.class public C2 +implements I2 +{ +.method private newslot virtual final instance void I2.perturb_interface_offset1() +{ +.override I2::perturb_interface_offset1 +ret +} +.method private newslot virtual final instance void I2.perturb_interface_offset2() +{ +.override I2::perturb_interface_offset2 +ret +} +.method private newslot virtual final instance void I2.perturb_interface_offset3() +{ +.override I2::perturb_interface_offset3 +ret +} +.method private static int32 check(int64 stack1, int64 stack2) +{ +ldarg.0 +ldarg.1 +tail. +call int32 C1::check(int64, int64) +ret +} +.method private newslot virtual final instance int32 I2.F2(class I1 i1, int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ +.override I2::F2 +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0014 +ldarg.1 +ldarg.0 +ldarg.2 +ldc.i4.1 +sub +ldarg.3 +ldloca.s V_0 +conv.u +conv.u8 +tail. +callvirt instance int32 I1::F1(class I2, int32, int64, int64) +ret +IL_0014: +ldloca.s V_0 +conv.u +conv.u8 +ldarg.s current_stack +tail. +call int32 C2::check(int64, int64) +ret +} +.method private newslot virtual final instance int32 I2.GF2(class I1 i1, int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ +.override I2::GF2 +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0014 +ldarg.1 +ldarg.0 +ldarg.2 +ldc.i4.1 +sub +ldarg.3 +ldloca.s V_0 +conv.u +conv.u8 +tail. +callvirt instance int32 I1::GF1(class I2, int32, int64, int64) +ret +IL_0014: +ldloca.s V_0 +conv.u +conv.u8 +ldarg.s current_stack +tail. +call int32 C2::check(int64, int64) +ret +} +.method public instance void .ctor() +{ +ldarg.0 +tail. +call instance void [mscorlib]System.Object::.ctor() +ret +} +} +.class public GC2`1 +implements class GI2`1 +{ +.method private newslot virtual final instance void 'GI2.perturb_interface_offset1'() +{ +.override method instance void class GI2`1::perturb_interface_offset1() +ret +} +.method private newslot virtual final instance void 'GI2.perturb_interface_offset2'() +{ +.override method instance void class GI2`1::perturb_interface_offset2() +ret +} +.method private newslot virtual final instance void 'GI2.perturb_interface_offset3'() +{ +.override method instance void class GI2`1::perturb_interface_offset3() +ret +} +.method private newslot virtual final instance void 'GI2.perturb_interface_offset4'() +{ +.override method instance void class GI2`1::perturb_interface_offset4() +ret +} +.method public static int32 check(int64 stack1, int64 stack2) +{ +ldarg.0 +ldarg.1 +tail. +call int32 C1::check(int64, int64) +ret +} +.method private newslot virtual final instance int32 'GI2.F2'(class GI1`1 i1, int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ +.override method instance int32 class GI2`1::F2(class GI1`1, +int32, +int64, +int64) +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0014 +ldarg.1 +ldarg.0 +ldarg.2 +ldc.i4.1 +sub +ldarg.3 +ldloca.s V_0 +conv.u +conv.u8 +tail. +callvirt instance int32 class GI1`1::F1(class GI2`1, int32, int64, int64) +ret +IL_0014: +ldloca.s V_0 +conv.u +conv.u8 +ldarg.s current_stack +tail. +call int32 class GC2`1::check(int64, int64) +ret +} +.method private newslot virtual final instance int32 'GI2.GF2'(class GI1`1 i1, int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ +.override method instance int32 class GI2`1::GF2<[1]>(class GI1`1, +int32, +int64, +int64) +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0014 +ldarg.1 +ldarg.0 +ldarg.2 +ldc.i4.1 +sub +ldarg.3 +ldloca.s V_0 +conv.u +conv.u8 +tail. +callvirt instance int32 class GI1`1::GF1(class GI2`1, int32, int64, int64) +ret +IL_0014: +ldloca.s V_0 +conv.u +conv.u8 +ldarg.s current_stack +tail. +call int32 class GC2`1::check(int64, int64) +ret +} +.method private newslot virtual final instance int32 'GI2.HF2'(class GI1`1 i1, int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ +.override method instance int32 class GI2`1::HF2<[1]>(class GI1`1, +int32, +int64, +int64) +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0014 +ldarg.1 +ldarg.0 +ldarg.2 +ldc.i4.1 +sub +ldarg.3 +ldloca.s V_0 +conv.u +conv.u8 +tail. +callvirt instance int32 class GI1`1::HF1(class GI2`1, int32, int64, int64) +ret +IL_0014: +ldloca.s V_0 +conv.u +conv.u8 +ldarg.s current_stack +tail. +call int32 class GC2`1::check(int64, int64) +ret +} +.method public instance void .ctor() +{ +ldarg.0 +tail. +call instance void [mscorlib]System.Object::.ctor() +ret +} +} +.class public A +{ +.method public instance void .ctor() +{ +ldarg.0 +tail. +call instance void [mscorlib]System.Object::.ctor() +ret +} +} +.class public B +{ +.method public instance void .ctor() +{ +ldarg.0 +tail. +call instance void [mscorlib]System.Object::.ctor() +ret +} +} +.class interface private abstract IC +{ +.method public newslot abstract virtual instance !!T cast1(object o, int32 counter, int64 stack) noinlining +{ +} +.method public newslot abstract virtual instance class B cast2(object o, int32 counter, int64 stack) noinlining +{ +} +.method public newslot abstract virtual instance !!T cast3(object o, int32 counter, int64 stack) noinlining +{ +} +.method public newslot abstract virtual instance class B[] cast4(object o, int32 counter, int64 stack) noinlining +{ +} +.method public newslot abstract virtual instance !!T[] cast5(object o, int32 counter, int64 stack) noinlining +{ +} +} +.class public C +{ +.method public static void check(int64 stack1, int64 stack2) noinlining +{ +ldarg.0 +ldarg.1 +call int32 C1::check(int64, int64) +pop +ret +} +.method public instance !!T cast1(object o, int32 counter, int64 stack) noinlining +{ +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0013 +ldarg.0 +ldarg.1 +ldarg.2 +ldc.i4.1 +sub +ldloca.s V_0 +conv.u +conv.u8 +tail. +call instance !!0 C::cast1(object, int32, int64) +ret +IL_0013: +ldloca.s V_0 +conv.u +conv.u8 +ldarg.3 +call void C::check(int64, int64) +ldarg.1 +unbox.any !!T +ret +} +.method public instance class B cast2(object o, int32 counter, int64 stack) noinlining +{ +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0013 +ldarg.0 +ldarg.1 +ldarg.2 +ldc.i4.1 +sub +ldloca.s V_0 +conv.u +conv.u8 +tail. +call instance class B C::cast2(object, int32, int64) +ret +IL_0013: +ldloca.s V_0 +conv.u +conv.u8 +ldarg.3 +call void C::check(int64, int64) +ldarg.0 +ldarg.1 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +tail. +call instance !!0 C::cast1(object, int32, int64) +ret +} +.method public instance !!T cast3(object o, int32 counter, int64 stack) noinlining +{ +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0013 +ldarg.0 +ldarg.1 +ldarg.2 +ldc.i4.1 +sub +ldloca.s V_0 +conv.u +conv.u8 +tail. +call instance !!0 C::cast3(object, int32, int64) +ret +IL_0013: +ldloca.s V_0 +conv.u +conv.u8 +ldarg.3 +call void C::check(int64, int64) +ldarg.0 +ldarg.1 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +tail. +call instance !!0 C::cast1(object, int32, int64) +ret +} +.method public instance class B[] cast4(object o, int32 counter, int64 stack) noinlining +{ +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0013 +ldarg.0 +ldarg.1 +ldarg.2 +ldc.i4.1 +sub +ldloca.s V_0 +conv.u +conv.u8 +tail. +call instance class B[] C::cast4(object, int32, int64) +ret +IL_0013: +ldloca.s V_0 +conv.u +conv.u8 +ldarg.3 +call void C::check(int64, int64) +ldarg.0 +ldarg.1 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +tail. +call instance !!0 C::cast1(object, int32, int64) +ret +} +.method public instance !!T[] cast5(object o, int32 counter, int64 stack) noinlining +{ +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0013 +ldarg.0 +ldarg.1 +ldarg.2 +ldc.i4.1 +sub +ldloca.s V_0 +conv.u +conv.u8 +tail. +call instance !!0[] C::cast5(object, int32, int64) +ret +IL_0013: +ldloca.s V_0 +conv.u +conv.u8 +ldarg.3 +call void C::check(int64, int64) +ldarg.0 +ldarg.1 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +tail. +call instance !!0 C::cast1(object, int32, int64) +ret +} +.method public instance void .ctor() +{ +ldarg.0 +tail. +call instance void [mscorlib]System.Object::.ctor() +ret +} +} +.class public D`1 +{ +.method public static void check(int64 stack1, int64 stack2) noinlining +{ +ldarg.0 +ldarg.1 +tail. +call void C::check(int64, int64) +ret +} +.method public static !!T cast1(object o, int32 counter, int64 stack) noinlining +{ +.locals init (int32 V_0) +ldarg.1 +ldc.i4.0 +ble.s IL_0012 +ldarg.0 +ldarg.1 +ldc.i4.1 +sub +ldloca.s V_0 +conv.u +conv.u8 +tail. +call !!0 class D`1::cast1(object, int32, int64) +ret +IL_0012: +ldloca.s V_0 +conv.u +conv.u8 +ldarg.2 +call void class D`1::check(int64, int64) +ldarg.0 +unbox.any !!T +ret +} +.method public instance class B cast2(object o, int32 counter, int64 stack) noinlining +{ +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0013 +ldarg.0 +ldarg.1 +ldarg.2 +ldc.i4.1 +sub +ldloca.s V_0 +conv.u +conv.u8 +tail. +call instance class B class D`1::cast2(object, int32, int64) +ret +IL_0013: +ldloca.s V_0 +conv.u +conv.u8 +ldarg.3 +call void class D`1::check(int64, int64) +ldarg.1 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +tail. +call !!0 class D`1::cast1(object, int32, int64) +ret +} +.method public instance !!T cast3(object o, int32 counter, int64 stack) noinlining +{ +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0013 +ldarg.0 +ldarg.1 +ldarg.2 +ldc.i4.1 +sub +ldloca.s V_0 +conv.u +conv.u8 +tail. +call instance !!0 class D`1::cast3(object, int32, int64) +ret +IL_0013: +ldloca.s V_0 +conv.u +conv.u8 +ldarg.3 +call void class D`1::check(int64, int64) +ldarg.1 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +tail. +call !!0 class D`1::cast1(object, int32, int64) +ret +} +.method public instance class B[] cast4(object o, int32 counter, int64 stack) noinlining +{ +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0013 +ldarg.0 +ldarg.1 +ldarg.2 +ldc.i4.1 +sub +ldloca.s V_0 +conv.u +conv.u8 +tail. +call instance class B[] class D`1::cast4(object, int32, int64) +ret +IL_0013: +ldloca.s V_0 +conv.u +conv.u8 +ldarg.3 +call void class D`1::check(int64, int64) +ldarg.1 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +tail. +call !!0 class D`1::cast1(object, int32, int64) +ret +} +.method public instance !!T[] cast5(object o, int32 counter, int64 stack) noinlining +{ +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0013 +ldarg.0 +ldarg.1 +ldarg.2 +ldc.i4.1 +sub +ldloca.s V_0 +conv.u +conv.u8 +tail. +call instance !!0[] class D`1::cast5(object, int32, int64) +ret +IL_0013: +ldloca.s V_0 +conv.u +conv.u8 +ldarg.3 +call void class D`1::check(int64, int64) +ldarg.1 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +tail. +call !!0 class D`1::cast1(object, int32, int64) +ret +} +.method public instance !T1 cast6(object o, int32 counter, int64 stack) noinlining +{ +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0013 +ldarg.0 +ldarg.1 +ldarg.2 +ldc.i4.1 +sub +ldloca.s V_0 +conv.u +conv.u8 +tail. +call instance !0 class D`1::cast6(object, int32, int64) +ret +IL_0013: +ldloca.s V_0 +conv.u +conv.u8 +ldarg.3 +call void class D`1::check(int64, int64) +ldarg.1 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +tail. +call !!0 class D`1::cast1(object, int32, int64) +ret +} +.method public instance !T1 cast7(object o, int32 counter, int64 stack) noinlining +{ +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0013 +ldarg.0 +ldarg.1 +ldarg.2 +ldc.i4.1 +sub +ldloca.s V_0 +conv.u +conv.u8 +tail. +call instance !0 class D`1::cast7(object, int32, int64) +ret +IL_0013: +ldloca.s V_0 +conv.u +conv.u8 +ldarg.3 +call void class D`1::check(int64, int64) +ldarg.1 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +tail. +call !!0 class D`1::cast1(object, int32, int64) +ret +} +.method public instance !T1[] cast8(object o, int32 counter, int64 stack) noinlining +{ +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0013 +ldarg.0 +ldarg.1 +ldarg.2 +ldc.i4.1 +sub +ldloca.s V_0 +conv.u +conv.u8 +tail. +call instance !0[] class D`1::cast8(object, int32, int64) +ret +IL_0013: +ldloca.s V_0 +conv.u +conv.u8 +ldarg.3 +call void class D`1::check(int64, int64) +ldarg.0 +ldarg.1 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +tail. +call instance !!0 class D`1::cast3(object, int32, int64) +ret +} +.method public instance !T1[] cast9(object o, int32 counter, int64 stack) noinlining +{ +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0013 +ldarg.0 +ldarg.1 +ldarg.2 +ldc.i4.1 +sub +ldloca.s V_0 +conv.u +conv.u8 +tail. +call instance !0[] class D`1::cast9(object, int32, int64) +ret +IL_0013: +ldloca.s V_0 +conv.u +conv.u8 +ldarg.3 +call void class D`1::check(int64, int64) +ldarg.0 +ldarg.1 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +tail. +call instance !!0 class D`1::cast3(object, int32, int64) +ret +} +.method public instance void .ctor() +{ +ldarg.0 +tail. +call instance void [mscorlib]System.Object::.ctor() +ret +} +} +.class private C3 +{ +.field private int32 i +.method private instance void print(object o) noinlining +{ +ldarg.0 +ldarg.0 +ldfld int32 C3::i +ldc.i4.1 +add +stfld int32 C3::i +ret +} +.method public instance void Main() noinlining +{ +.locals init (class D`1 V_0, class D`1 V_1, class D`1 V_2, class C V_3, class B V_4, class B[] V_5, int32 V_6, class I1 V_7, class I2 V_8, int32 V_9, class GI1`1 V_10, class GI1`1 V_11, class GI1`1 V_12, class GI1`1 V_13, class GI1`1 V_14, class GI1`1 V_15, class GI2`1 V_16, class GI2`1 V_17, class GI2`1 V_18, class GI2`1 V_19, class GI2`1 V_20, class GI2`1 V_21) +newobj instance void class D`1::.ctor() +stloc.0 +newobj instance void class D`1::.ctor() +stloc.1 +newobj instance void class D`1::.ctor() +stloc.2 +newobj instance void C::.ctor() +stloc.3 +newobj instance void B::.ctor() +stloc.s V_4 +ldc.i4.1 +newarr B +stloc.s V_5 + +newobj instance void C1::.ctor() +stloc.s V_7 +newobj instance void C2::.ctor() +stloc.s V_8 + +newobj instance void class GC1`1::.ctor() +stloc.s V_10 +newobj instance void class GC1`1::.ctor() +stloc.s V_11 +newobj instance void class GC1`1::.ctor() +stloc.s V_12 +newobj instance void class GC1`1::.ctor() +stloc.s V_13 +newobj instance void class GC1`1::.ctor() +stloc.s V_14 +newobj instance void class GC1`1::.ctor() +stloc.s V_15 +newobj instance void class GC2`1::.ctor() +stloc.s V_16 +newobj instance void class GC2`1::.ctor() +stloc.s V_17 +newobj instance void class GC2`1::.ctor() +stloc.s V_18 +newobj instance void class GC2`1::.ctor() +stloc.s V_19 +newobj instance void class GC2`1::.ctor() +stloc.s V_20 +newobj instance void class GC2`1::.ctor() +stloc.s V_21 + +ldc.i4.0 +stloc.s V_9 + +ldarg.0 +ldloc.0 +ldloc.s V_4 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +callvirt instance class B class D`1::cast2(object, int32, int64) +call instance void C3::print(object) + +ldarg.0 +ldloc.0 +ldloc.s V_4 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +callvirt instance !!0 class D`1::cast3(object, int32, int64) +call instance void C3::print(object) + +ldarg.0 +ldloc.0 +ldloc.s V_5 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +callvirt instance !!0 class D`1::cast3(object, int32, int64) +call instance void C3::print(object) + +ldarg.0 +ldloc.0 +ldloc.s V_5 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +callvirt instance class B[] class D`1::cast4(object, int32, int64) +call instance void C3::print(object) + +ldarg.0 +ldloc.0 +ldloc.s V_5 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +callvirt instance !!0[] class D`1::cast5(object, int32, int64) +call instance void C3::print(object) + +ldarg.0 +ldloc.1 +ldloc.s V_4 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +callvirt instance !0 class D`1::cast6(object, int32, int64) +call instance void C3::print(object) + +ldarg.0 +ldloc.1 +ldloc.s V_4 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +callvirt instance !0 class D`1::cast7(object, int32, int64) +call instance void C3::print(object) + +ldarg.0 +ldloc.2 +ldloc.s V_5 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +callvirt instance !0 class D`1::cast7(object, int32, int64) +call instance void C3::print(object) + +ldarg.0 +ldloc.1 +ldloc.s V_5 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +callvirt instance !0[] class D`1::cast8(object, int32, int64) +call instance void C3::print(object) + +ldarg.0 +ldloc.1 +ldloc.s V_5 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +callvirt instance !0[] class D`1::cast9(object, int32, int64) +call instance void C3::print(object) + +ldarg.0 +ldloc.3 +ldloc.s V_4 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +callvirt instance class B C::cast2(object, int32, int64) +call instance void C3::print(object) + + +ldc.i4.0 + + +ldarg.0 +ldloc.3 +ldloc.s V_4 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +callvirt instance !!0 C::cast3(object, int32, int64) +call instance void C3::print(object) + +ldarg.0 +ldloc.3 +ldloc.s V_5 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +callvirt instance !!0 C::cast3(object, int32, int64) +call instance void C3::print(object) + +ldarg.0 +ldloc.3 +ldloc.s V_5 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +callvirt instance class B[] C::cast4(object, int32, int64) +call instance void C3::print(object) + +ldarg.0 +ldloc.3 +ldloc.s V_5 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +callvirt instance !!0[] C::cast5(object, int32, int64) +call instance void C3::print(object) + +ldloc.s V_7 +ldloc.s V_8 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance int32 I1::F1(class I2, int32, int64, int64) +add + +ldloc.s V_7 +ldloc.s V_8 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance int32 I1::GF1(class I2, int32, int64, int64) +add + +ldloc.s V_7 +ldloc.s V_8 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance int32 I1::GF1(class I2, int32, int64, int64) +add + +ldloc.s V_7 +ldloc.s V_8 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance int32 I1::GF1(class I2, int32, int64, int64) +add + +ldloc.s V_7 +ldloc.s V_8 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance int32 I1::GF1(class I2, int32, int64, int64) +add + +ldloc.s V_7 +ldloc.s V_8 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance int32 I1::GF1(class I2, int32, int64, int64) +add + +// This is the only failure on desktop. +ldloc.s V_10 +ldloc.s V_16 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance int32 class GI1`1::F1(class GI2`1, int32, int64, int64) +add + +ldloc.s V_10 +ldloc.s V_16 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance int32 class GI1`1::GF1(class GI2`1, int32, int64, int64) +add + +ldloc.s V_10 +ldloc.s V_16 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance int32 class GI1`1::GF1(class GI2`1, int32, int64, int64) +add + +ldloc.s V_10 +ldloc.s V_16 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance int32 class GI1`1::GF1(class GI2`1, int32, int64, int64) +add + +ldloc.s V_10 +ldloc.s V_16 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance int32 class GI1`1::GF1(class GI2`1, int32, int64, int64) +add + +ldloc.s V_10 +ldloc.s V_16 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance int32 class GI1`1::GF1(class GI2`1, int32, int64, int64) +add + +ldloc.s V_11 +ldloc.s V_17 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance int32 class GI1`1::GF1(class GI2`1, int32, int64, int64) +add + +ldloc.s V_11 +ldloc.s V_17 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance int32 class GI1`1::GF1(class GI2`1, int32, int64, int64) +add + +ldloc.s V_11 +ldloc.s V_17 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance int32 class GI1`1::GF1(class GI2`1, int32, int64, int64) +add + +ldloc.s V_11 +ldloc.s V_17 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance int32 class GI1`1::GF1(class GI2`1, int32, int64, int64) +add + +ldloc.s V_11 +ldloc.s V_17 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance int32 class GI1`1::GF1(class GI2`1, int32, int64, int64) +add + +ldloc.s V_12 +ldloc.s V_18 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance int32 class GI1`1::GF1(class GI2`1, int32, int64, int64) +add + +ldloc.s V_12 +ldloc.s V_18 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance int32 class GI1`1::GF1(class GI2`1, int32, int64, int64) +add + +ldloc.s V_12 +ldloc.s V_18 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance int32 class GI1`1::GF1(class GI2`1, int32, int64, int64) +add + +ldloc.s V_12 +ldloc.s V_18 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance int32 class GI1`1::GF1(class GI2`1, int32, int64, int64) +add + +ldloc.s V_12 +ldloc.s V_18 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance int32 class GI1`1::GF1(class GI2`1, int32, int64, int64) +add + +ldloc.s V_13 +ldloc.s V_19 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance int32 class GI1`1::GF1(class GI2`1, int32, int64, int64) +add + +ldloc.s V_13 +ldloc.s V_19 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance int32 class GI1`1::GF1(class GI2`1, int32, int64, int64) +add + +ldloc.s V_13 +ldloc.s V_19 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance int32 class GI1`1::GF1(class GI2`1, int32, int64, int64) +add + +ldloc.s V_13 +ldloc.s V_19 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance int32 class GI1`1::GF1(class GI2`1, int32, int64, int64) +add + +ldloc.s V_13 +ldloc.s V_19 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance int32 class GI1`1::GF1(class GI2`1, int32, int64, int64) +add + +ldloc.s V_14 +ldloc.s V_20 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance int32 class GI1`1::GF1(class GI2`1, int32, int64, int64) +add + +ldloc.s V_14 +ldloc.s V_20 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance int32 class GI1`1::GF1(class GI2`1, int32, int64, int64) +add + +ldloc.s V_14 +ldloc.s V_20 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance int32 class GI1`1::GF1(class GI2`1, int32, int64, int64) +add + +ldloc.s V_14 +ldloc.s V_20 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance int32 class GI1`1::GF1(class GI2`1, int32, int64, int64) +add + +ldloc.s V_14 +ldloc.s V_20 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance int32 class GI1`1::GF1(class GI2`1, int32, int64, int64) +add + +ldloc.s V_15 +ldloc.s V_21 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance int32 class GI1`1::GF1(class GI2`1, int32, int64, int64) +add + +ldloc.s V_15 +ldloc.s V_21 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance int32 class GI1`1::GF1(class GI2`1, int32, int64, int64) +add + +ldloc.s V_15 +ldloc.s V_21 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance int32 class GI1`1::GF1(class GI2`1, int32, int64, int64) +add + +ldloc.s V_15 +ldloc.s V_21 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance int32 class GI1`1::GF1(class GI2`1, int32, int64, int64) +add + +ldloc.s V_15 +ldloc.s V_21 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance int32 class GI1`1::GF1(class GI2`1, int32, int64, int64) +add + +ldsfld int32 C1::errors +add +dup +stloc.s V_9 +brfalse.s IL_0591 + +ldstr "failure {0}" +br.s IL_0596 + +IL_0591: +ldstr "success" + +IL_0596: +ldloc.s V_9 +box [mscorlib]System.Int32 +call void [mscorlib]System.Console::WriteLine(string, object) +ldloc.s V_9 +tail. +call void [mscorlib]System.Environment::Exit(int32) +ret +} + +.method public static void Main(string[] args) noinlining +{ +.entrypoint +newobj instance void C3::.ctor() +tail. +call instance void C3::Main() +ret +} + +.method public instance void .ctor() +{ +ldarg.0 +tail. +call instance void [mscorlib]System.Object::.ctor() +ret +} +} diff --git a/mono/tests/tailcall-interface-justrun.il b/mono/tests/tailcall-interface-justrun.il new file mode 100644 index 0000000000..649c8a6a7e --- /dev/null +++ b/mono/tests/tailcall-interface-justrun.il @@ -0,0 +1,1417 @@ +/* +Author: + Jay Krell (jaykrell@microsoft.com) + +Copyright 2018 Microsoft +Licensed under the MIT license. See LICENSE file in the project root for full license information. + +Derived from tailcall-interface.cs. +*/ +.assembly extern mscorlib { } +.assembly 'tailcall-interface' { } + +.class public sequential sealed Point +extends [mscorlib]System.ValueType +{ +.field public int32 x +.field public int32 y +} + +.class interface private abstract I1 +{ +.method public newslot abstract virtual instance void perturb_interface_offset1() { } +.method public newslot abstract virtual instance void F1(class I2 i2, int32 counter, int64 initial_stack, int64 current_stack) noinlining { } +.method public newslot abstract virtual instance void GF1(class I2 i2, int32 counter, int64 initial_stack, int64 current_stack) noinlining { } +} + +.class interface private abstract GI1`1 +{ +.method public newslot abstract virtual instance void perturb_interface_offset1() { } +.method public newslot abstract virtual instance void perturb_interface_offset2() { } +.method public newslot abstract virtual instance void F1(class GI2`1 i2, int32 counter, int64 initial_stack, int64 current_stack) noinlining { } +.method public newslot abstract virtual instance void GF1(class GI2`1 i2, int32 counter, int64 initial_stack, int64 current_stack) noinlining { } +.method public newslot abstract virtual instance void HF1(class GI2`1 i2, int32 counter, int64 initial_stack, int64 current_stack) noinlining { } +} + +.class interface private abstract I2 +{ +.method public newslot abstract virtual instance void perturb_interface_offset1() { } +.method public newslot abstract virtual instance void perturb_interface_offset2() { } +.method public newslot abstract virtual instance void perturb_interface_offset3() { } +.method public newslot abstract virtual instance void F2(class I1 i1, int32 counter, int64 initial_stack, int64 current_stack) noinlining { } +.method public newslot abstract virtual instance void GF2(class I1 i1, int32 counter, int64 initial_stack, int64 current_stack) noinlining { } +} + +.class interface private abstract GI2`1 +{ +.method public newslot abstract virtual instance void perturb_interface_offset1() { } +.method public newslot abstract virtual instance void perturb_interface_offset2() { } +.method public newslot abstract virtual instance void perturb_interface_offset3() { } +.method public newslot abstract virtual instance void perturb_interface_offset4() { } +.method public newslot abstract virtual instance void F2(class GI1`1 i1, int32 counter, int64 initial_stack, int64 current_stack) noinlining { } +.method public newslot abstract virtual instance void GF2(class GI1`1 i1, int32 counter, int64 initial_stack, int64 current_stack) noinlining { } +.method public newslot abstract virtual instance void HF2(class GI1`1 i1, int32 counter, int64 initial_stack, int64 current_stack) noinlining { } +} + +.class public C1 implements I1 +{ +.method private newslot virtual final instance void I1.perturb_interface_offset1() +{ +.override I1::perturb_interface_offset1 +ret +} + +.method private newslot virtual final instance void I1.F1(class I2 i2, int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ +.override I1::F1 +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0014 +ldarg.1 +ldarg.0 +ldarg.2 +ldc.i4.1 +sub +ldarg.3 +ldloca.s V_0 +conv.u +conv.u8 +tail. +callvirt instance void I2::F2(class I1, int32, int64, int64) +IL_0014: +ret +} + +.method private newslot virtual final instance void I1.GF1(class I2 i2, int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ +.override I1::GF1 +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0014 + +ldarg.1 +ldarg.0 +ldarg.2 +ldc.i4.1 +sub +ldarg.3 +ldloca.s V_0 +conv.u +conv.u8 +tail. +callvirt instance void I2::GF2(class I1, int32, int64, int64) +IL_0014: +ret +} + +.method public instance void .ctor() +{ +ldarg.0 +tail. +call instance void [mscorlib]System.Object::.ctor() +ret +} + +} +.class public GC1`1 implements class GI1`1 +{ + +.method private newslot virtual final instance void 'GI1.perturb_interface_offset1'() +{ +.override method instance void class GI1`1::perturb_interface_offset1() +ret +} + +.method private newslot virtual final instance void 'GI1.perturb_interface_offset2'() +{ +.override method instance void class GI1`1::perturb_interface_offset2() +ret +} + +.method private newslot virtual final instance void 'GI1.F1'(class GI2`1 i2, int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ +.override method instance void class GI1`1::F1(class GI2`1, int32, int64, int64) +.locals init (int32 V_0) + +ldarg.2 +ldc.i4.0 +ble.s IL_0014 + +ldarg.1 +ldarg.0 +ldarg.2 +ldc.i4.1 +sub +ldarg.3 +ldloca.s V_0 +conv.u +conv.u8 +tail. +callvirt instance void class GI2`1::F2(class GI1`1, int32, int64, int64) +IL_0014: +ret +} + +.method private newslot virtual final instance void 'GI1.GF1'(class GI2`1 i2, int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ +.override method instance void class GI1`1::GF1<[1]>(class GI2`1, int32, int64, int64) +.locals init (int32 V_0) + +ldarg.2 +ldc.i4.0 +ble.s IL_0014 + +ldarg.1 +ldarg.0 +ldarg.2 +ldc.i4.1 +sub +ldarg.3 +ldloca.s V_0 +conv.u +conv.u8 +tail. +callvirt instance void class GI2`1::GF2(class GI1`1, int32, int64, int64) + +IL_0014: +ret +} + +.method private newslot virtual final instance void 'GI1.HF1'(class GI2`1 i2, int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ +.override method instance void class GI1`1::HF1<[1]>(class GI2`1, int32, int64, int64) +.locals init (int32 V_0) + +ldarg.2 +ldc.i4.0 +ble.s IL_0014 + +ldarg.1 +ldarg.0 +ldarg.2 +ldc.i4.1 +sub +ldarg.3 +ldloca.s V_0 +conv.u +conv.u8 +tail. +callvirt instance void class GI2`1::HF2(class GI1`1, int32, int64, int64) +IL_0014: +ret +} + +.method public instance void .ctor() +{ +ldarg.0 +tail. +call instance void [mscorlib]System.Object::.ctor() +ret +} + +} + +.class public C2 implements I2 +{ + +.method private newslot virtual final instance void I2.perturb_interface_offset1() +{ +.override I2::perturb_interface_offset1 +ret +} + +.method private newslot virtual final instance void I2.perturb_interface_offset2() +{ +.override I2::perturb_interface_offset2 +ret +} + +.method private newslot virtual final instance void I2.perturb_interface_offset3() +{ +.override I2::perturb_interface_offset3 +ret +} + +.method private newslot virtual final instance void I2.F2(class I1 i1, int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ +.override I2::F2 +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0014 + +ldarg.1 +ldarg.0 +ldarg.2 +ldc.i4.1 +sub +ldarg.3 +ldloca.s V_0 +conv.u +conv.u8 +tail. +callvirt instance void I1::F1(class I2, int32, int64, int64) +IL_0014: +ret +} + +.method private newslot virtual final instance void I2.GF2(class I1 i1, int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ +.override I2::GF2 +.locals init (int32 V_0) + +ldarg.2 +ldc.i4.0 +ble.s IL_0014 + +ldarg.1 +ldarg.0 +ldarg.2 +ldc.i4.1 +sub +ldarg.3 +ldloca.s V_0 +conv.u +conv.u8 +tail. +callvirt instance void I1::GF1(class I2, int32, int64, int64) +IL_0014: +ret +} + +.method public instance void .ctor() +{ +ldarg.0 +tail. +call instance void [mscorlib]System.Object::.ctor() +ret +} + +} +.class public GC2`1 implements class GI2`1 +{ + +.method private newslot virtual final instance void 'GI2.perturb_interface_offset1'() +{ +.override method instance void class GI2`1::perturb_interface_offset1() +ret +} + +.method private newslot virtual final instance void 'GI2.perturb_interface_offset2'() +{ +.override method instance void class GI2`1::perturb_interface_offset2() +ret +} + +.method private newslot virtual final instance void 'GI2.perturb_interface_offset3'() +{ +.override method instance void class GI2`1::perturb_interface_offset3() +ret +} + +.method private newslot virtual final instance void 'GI2.perturb_interface_offset4'() +{ +.override method instance void class GI2`1::perturb_interface_offset4() +ret +} + +.method private newslot virtual final instance void 'GI2.F2'(class GI1`1 i1, int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ +.override method instance void class GI2`1::F2(class GI1`1, int32, int64, int64) +.locals init (int32 V_0) + +ldarg.2 +ldc.i4.0 +ble.s IL_0014 + +ldarg.1 +ldarg.0 +ldarg.2 +ldc.i4.1 +sub +ldarg.3 +ldloca.s V_0 +conv.u +conv.u8 +tail. +callvirt instance void class GI1`1::F1(class GI2`1, int32, int64, int64) +IL_0014: +ret +} + +.method private newslot virtual final instance void 'GI2.GF2'(class GI1`1 i1, int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ +.override method instance void class GI2`1::GF2<[1]>(class GI1`1, int32, int64, int64) +.locals init (int32 V_0) + +ldarg.2 +ldc.i4.0 +ble.s IL_0014 + +ldarg.1 +ldarg.0 +ldarg.2 +ldc.i4.1 +sub +ldarg.3 +ldloca.s V_0 +conv.u +conv.u8 +tail. +callvirt instance void class GI1`1::GF1(class GI2`1, int32, int64, int64) +IL_0014: +ret +} + +.method private newslot virtual final instance void 'GI2.HF2'(class GI1`1 i1, int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ +.override method instance void class GI2`1::HF2<[1]>(class GI1`1, int32, int64, int64) +.locals init (int32 V_0) + +ldarg.2 +ldc.i4.0 +ble.s IL_0014 + +ldarg.1 +ldarg.0 +ldarg.2 +ldc.i4.1 +sub +ldarg.3 +ldloca.s V_0 +conv.u +conv.u8 +tail. +callvirt instance void class GI1`1::HF1(class GI2`1, int32, int64, int64) +IL_0014: +ret +} + +.method public instance void .ctor() +{ +ldarg.0 +tail. +call instance void [mscorlib]System.Object::.ctor() +ret +} + +} + +.class public A +{ + +.method public instance void .ctor() +{ +ldarg.0 +tail. +call instance void [mscorlib]System.Object::.ctor() +ret +} + +} + +.class public B +{ + +.method public instance void .ctor() +{ +ldarg.0 +tail. +call instance void [mscorlib]System.Object::.ctor() +ret +} + +} + +.class interface private abstract IC +{ +.method public newslot abstract virtual instance !!T cast1(object o, int32 counter, int64 stack) noinlining { } +.method public newslot abstract virtual instance class B cast2(object o, int32 counter, int64 stack) noinlining { } +.method public newslot abstract virtual instance !!T cast3(object o, int32 counter, int64 stack) noinlining { } +.method public newslot abstract virtual instance class B[] cast4(object o, int32 counter, int64 stack) noinlining { } +.method public newslot abstract virtual instance !!T[] cast5(object o, int32 counter, int64 stack) noinlining { } +} + +.class public C +{ + +.method public instance !!T cast1(object o, int32 counter, int64 stack) noinlining +{ +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0013 + +ldarg.0 +ldarg.1 +ldarg.2 +ldc.i4.1 +sub +ldloca.s V_0 +conv.u +conv.u8 +tail. +call instance !!0 C::cast1(object, int32, int64) +ret + +IL_0013: +ldarg.1 +unbox.any !!T +ret +} +.method public instance class B cast2(object o, int32 counter, int64 stack) noinlining +{ +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0013 + +ldarg.0 +ldarg.1 +ldarg.2 +ldc.i4.1 +sub +ldloca.s V_0 +conv.u +conv.u8 +tail. +call instance class B C::cast2(object, int32, int64) +ret + +IL_0013: +ldarg.0 +ldarg.1 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +tail. +call instance !!0 C::cast1(object, int32, int64) +ret +} +.method public instance !!T cast3(object o, int32 counter, int64 stack) noinlining +{ +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0013 + +ldarg.0 +ldarg.1 +ldarg.2 +ldc.i4.1 +sub +ldloca.s V_0 +conv.u +conv.u8 +tail. +call instance !!0 C::cast3(object, int32, int64) +ret + +IL_0013: +ldarg.0 +ldarg.1 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +tail. +call instance !!0 C::cast1(object, int32, int64) +ret +} + +.method public instance class B[] cast4(object o, int32 counter, int64 stack) noinlining +{ +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0013 +ldarg.0 +ldarg.1 +ldarg.2 +ldc.i4.1 +sub +ldloca.s V_0 +conv.u +conv.u8 +tail. +call instance class B[] C::cast4(object, int32, int64) +ret + +IL_0013: +ldarg.0 +ldarg.1 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +tail. +call instance !!0 C::cast1(object, int32, int64) +ret +} +.method public instance !!T[] cast5(object o, int32 counter, int64 stack) noinlining +{ +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0013 +ldarg.0 +ldarg.1 +ldarg.2 +ldc.i4.1 +sub +ldloca.s V_0 +conv.u +conv.u8 +tail. +call instance !!0[] C::cast5(object, int32, int64) +ret +IL_0013: +ldarg.0 +ldarg.1 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +tail. +call instance !!0 C::cast1(object, int32, int64) +ret +} +.method public instance void .ctor() +{ +ldarg.0 +tail. +call instance void [mscorlib]System.Object::.ctor() +ret +} +} +.class public D`1 +{ +.method public static !!T cast1(object o, int32 counter, int64 stack) noinlining +{ +.locals init (int32 V_0) +ldarg.1 +ldc.i4.0 +ble.s IL_0012 + +ldarg.0 +ldarg.1 +ldc.i4.1 +sub +ldloca.s V_0 +conv.u +conv.u8 +tail. +call !!0 class D`1::cast1(object, int32, int64) +ret + +IL_0012: +ldarg.0 +unbox.any !!T +ret +} +.method public instance class B cast2(object o, int32 counter, int64 stack) noinlining +{ +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0013 + +ldarg.0 +ldarg.1 +ldarg.2 +ldc.i4.1 +sub +ldloca.s V_0 +conv.u +conv.u8 +tail. +call instance class B class D`1::cast2(object, int32, int64) +ret + +IL_0013: +ldarg.1 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +tail. +call !!0 class D`1::cast1(object, int32, int64) +ret +} +.method public instance !!T cast3(object o, int32 counter, int64 stack) noinlining +{ +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0013 +ldarg.0 +ldarg.1 +ldarg.2 +ldc.i4.1 +sub +ldloca.s V_0 +conv.u +conv.u8 +tail. +call instance !!0 class D`1::cast3(object, int32, int64) +ret +IL_0013: +ldarg.1 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +tail. +call !!0 class D`1::cast1(object, int32, int64) +ret +} +.method public instance class B[] cast4(object o, int32 counter, int64 stack) noinlining +{ +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0013 +ldarg.0 +ldarg.1 +ldarg.2 +ldc.i4.1 +sub +ldloca.s V_0 +conv.u +conv.u8 +tail. +call instance class B[] class D`1::cast4(object, int32, int64) +ret +IL_0013: +ldarg.1 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +tail. +call !!0 class D`1::cast1(object, int32, int64) +ret +} +.method public instance !!T[] cast5(object o, int32 counter, int64 stack) noinlining +{ +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0013 +ldarg.0 +ldarg.1 +ldarg.2 +ldc.i4.1 +sub +ldloca.s V_0 +conv.u +conv.u8 +tail. +call instance !!0[] class D`1::cast5(object, int32, int64) +ret +IL_0013: +ldarg.1 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +tail. +call !!0 class D`1::cast1(object, int32, int64) +ret +} +.method public instance !T1 cast6(object o, int32 counter, int64 stack) noinlining +{ +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0013 +ldarg.0 +ldarg.1 +ldarg.2 +ldc.i4.1 +sub +ldloca.s V_0 +conv.u +conv.u8 +tail. +call instance !0 class D`1::cast6(object, int32, int64) +ret +IL_0013: +ldarg.1 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +tail. +call !!0 class D`1::cast1(object, int32, int64) +ret +} +.method public instance !T1 cast7(object o, int32 counter, int64 stack) noinlining +{ +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0013 +ldarg.0 +ldarg.1 +ldarg.2 +ldc.i4.1 +sub +ldloca.s V_0 +conv.u +conv.u8 +tail. +call instance !0 class D`1::cast7(object, int32, int64) +ret +IL_0013: +ldarg.1 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +tail. +call !!0 class D`1::cast1(object, int32, int64) +ret +} +.method public instance !T1[] cast8(object o, int32 counter, int64 stack) noinlining +{ +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0013 +ldarg.0 +ldarg.1 +ldarg.2 +ldc.i4.1 +sub +ldloca.s V_0 +conv.u +conv.u8 +tail. +call instance !0[] class D`1::cast8(object, int32, int64) +ret +IL_0013: +ldarg.0 +ldarg.1 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +tail. +call instance !!0 class D`1::cast3(object, int32, int64) +ret +} +.method public instance !T1[] cast9(object o, int32 counter, int64 stack) noinlining +{ +.locals init (int32 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0013 +ldarg.0 +ldarg.1 +ldarg.2 +ldc.i4.1 +sub +ldloca.s V_0 +conv.u +conv.u8 +tail. +call instance !0[] class D`1::cast9(object, int32, int64) +ret +IL_0013: +ldarg.0 +ldarg.1 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +tail. +call instance !!0 class D`1::cast3(object, int32, int64) +ret +} +.method public instance void .ctor() +{ +ldarg.0 +tail. +call instance void [mscorlib]System.Object::.ctor() +ret +} +} +.class private C3 +{ +.field private int32 i +.method private instance void print(object o) noinlining +{ +ldarg.0 +ldarg.0 +ldfld int32 C3::i +ldc.i4.1 +add +stfld int32 C3::i +ret +} +.method public instance void Main() noinlining +{ +.locals init (class D`1 V_0, class D`1 V_1, class D`1 V_2, class C V_3, class B V_4, class B[] V_5, int32 V_6, class I1 V_7, class I2 V_8, class GI1`1 V_10, class GI1`1 V_11, class GI1`1 V_12, class GI1`1 V_13, class GI1`1 V_14, class GI1`1 V_15, class GI2`1 V_16, class GI2`1 V_17, class GI2`1 V_18, class GI2`1 V_19, class GI2`1 V_20, class GI2`1 V_21) + +newobj instance void class D`1::.ctor() +stloc.0 +newobj instance void class D`1::.ctor() +stloc.1 +newobj instance void class D`1::.ctor() +stloc.2 +newobj instance void C::.ctor() +stloc.3 +newobj instance void B::.ctor() +stloc.s V_4 +ldc.i4.1 +newarr B +stloc.s V_5 + +newobj instance void class GC1`1::.ctor() +stloc.s V_10 +newobj instance void class GC1`1::.ctor() +stloc.s V_11 +newobj instance void class GC1`1::.ctor() +stloc.s V_12 +newobj instance void class GC1`1::.ctor() +stloc.s V_13 +newobj instance void class GC1`1::.ctor() +stloc.s V_14 +newobj instance void class GC1`1::.ctor() +stloc.s V_15 +newobj instance void class GC2`1::.ctor() +stloc.s V_16 +newobj instance void class GC2`1::.ctor() +stloc.s V_17 +newobj instance void class GC2`1::.ctor() +stloc.s V_18 +newobj instance void class GC2`1::.ctor() +stloc.s V_19 +newobj instance void class GC2`1::.ctor() +stloc.s V_20 +newobj instance void class GC2`1::.ctor() +stloc.s V_21 + +newobj instance void C1::.ctor() +stloc.s V_7 +newobj instance void C2::.ctor() +stloc.s V_8 + +ldarg.0 +ldloc.0 +ldloc.s V_4 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +callvirt instance class B class D`1::cast2(object, int32, int64) +call instance void C3::print(object) + +ldarg.0 +ldloc.0 +ldloc.s V_4 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +callvirt instance !!0 class D`1::cast3(object, int32, int64) +call instance void C3::print(object) + +ldarg.0 +ldloc.0 +ldloc.s V_5 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +callvirt instance !!0 class D`1::cast3(object, int32, int64) +call instance void C3::print(object) + +ldarg.0 +ldloc.0 +ldloc.s V_5 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +callvirt instance class B[] class D`1::cast4(object, int32, int64) +call instance void C3::print(object) + +ldarg.0 +ldloc.0 +ldloc.s V_5 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +callvirt instance !!0[] class D`1::cast5(object, int32, int64) +call instance void C3::print(object) + +ldarg.0 +ldloc.1 +ldloc.s V_4 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +callvirt instance !0 class D`1::cast6(object, int32, int64) +call instance void C3::print(object) + +ldarg.0 +ldloc.1 +ldloc.s V_4 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +callvirt instance !0 class D`1::cast7(object, int32, int64) +call instance void C3::print(object) + +ldarg.0 +ldloc.2 +ldloc.s V_5 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +callvirt instance !0 class D`1::cast7(object, int32, int64) +call instance void C3::print(object) + +ldarg.0 +ldloc.1 +ldloc.s V_5 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +callvirt instance !0[] class D`1::cast8(object, int32, int64) +call instance void C3::print(object) + +ldarg.0 +ldloc.1 +ldloc.s V_5 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +callvirt instance !0[] class D`1::cast9(object, int32, int64) +call instance void C3::print(object) + +ldarg.0 +ldloc.3 +ldloc.s V_4 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +callvirt instance class B C::cast2(object, int32, int64) +call instance void C3::print(object) + +ldarg.0 +ldloc.3 +ldloc.s V_4 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +callvirt instance !!0 C::cast3(object, int32, int64) +call instance void C3::print(object) + +ldarg.0 +ldloc.3 +ldloc.s V_5 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +callvirt instance !!0 C::cast3(object, int32, int64) +call instance void C3::print(object) + +ldarg.0 +ldloc.3 +ldloc.s V_5 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +callvirt instance class B[] C::cast4(object, int32, int64) +call instance void C3::print(object) + +ldarg.0 +ldloc.3 +ldloc.s V_5 +ldc.i4.s 100 +ldc.i4.0 +conv.i8 +callvirt instance !!0[] C::cast5(object, int32, int64) +call instance void C3::print(object) + +ldloc.s V_7 +ldloc.s V_8 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance void I1::F1(class I2, int32, int64, int64) + +ldloc.s V_7 +ldloc.s V_8 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance void I1::GF1(class I2, int32, int64, int64) + +ldloc.s V_7 +ldloc.s V_8 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance void I1::GF1(class I2, int32, int64, int64) + +ldloc.s V_7 +ldloc.s V_8 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance void I1::GF1(class I2, int32, int64, int64) + +ldloc.s V_7 +ldloc.s V_8 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance void I1::GF1(class I2, int32, int64, int64) + +ldloc.s V_7 +ldloc.s V_8 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance void I1::GF1(class I2, int32, int64, int64) + +ldloc.s V_10 +ldloc.s V_16 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance void class GI1`1::F1(class GI2`1, int32, int64, int64) + +ldloc.s V_10 +ldloc.s V_16 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance void class GI1`1::GF1(class GI2`1, int32, int64, int64) + +ldloc.s V_10 +ldloc.s V_16 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance void class GI1`1::GF1(class GI2`1, int32, int64, int64) + +ldloc.s V_10 +ldloc.s V_16 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance void class GI1`1::GF1(class GI2`1, int32, int64, int64) + +ldloc.s V_10 +ldloc.s V_16 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance void class GI1`1::GF1(class GI2`1, int32, int64, int64) + +ldloc.s V_10 +ldloc.s V_16 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance void class GI1`1::GF1(class GI2`1, int32, int64, int64) + +ldloc.s V_11 +ldloc.s V_17 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance void class GI1`1::GF1(class GI2`1, int32, int64, int64) + +ldloc.s V_11 +ldloc.s V_17 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance void class GI1`1::GF1(class GI2`1, int32, int64, int64) + +ldloc.s V_11 +ldloc.s V_17 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance void class GI1`1::GF1(class GI2`1, int32, int64, int64) + +ldloc.s V_11 +ldloc.s V_17 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance void class GI1`1::GF1(class GI2`1, int32, int64, int64) + +ldloc.s V_11 +ldloc.s V_17 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance void class GI1`1::GF1(class GI2`1, int32, int64, int64) + +ldloc.s V_12 +ldloc.s V_18 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance void class GI1`1::GF1(class GI2`1, int32, int64, int64) + +ldloc.s V_12 +ldloc.s V_18 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance void class GI1`1::GF1(class GI2`1, int32, int64, int64) + +ldloc.s V_12 +ldloc.s V_18 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance void class GI1`1::GF1(class GI2`1, int32, int64, int64) + +ldloc.s V_12 +ldloc.s V_18 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance void class GI1`1::GF1(class GI2`1, int32, int64, int64) + +ldloc.s V_12 +ldloc.s V_18 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance void class GI1`1::GF1(class GI2`1, int32, int64, int64) + +ldloc.s V_13 +ldloc.s V_19 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance void class GI1`1::GF1(class GI2`1, int32, int64, int64) + +ldloc.s V_13 +ldloc.s V_19 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance void class GI1`1::GF1(class GI2`1, int32, int64, int64) + +ldloc.s V_13 +ldloc.s V_19 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance void class GI1`1::GF1(class GI2`1, int32, int64, int64) + +ldloc.s V_13 +ldloc.s V_19 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance void class GI1`1::GF1(class GI2`1, int32, int64, int64) + +ldloc.s V_13 +ldloc.s V_19 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance void class GI1`1::GF1(class GI2`1, int32, int64, int64) + +ldloc.s V_14 +ldloc.s V_20 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance void class GI1`1::GF1(class GI2`1, int32, int64, int64) + +ldloc.s V_14 +ldloc.s V_20 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance void class GI1`1::GF1(class GI2`1, int32, int64, int64) + +ldloc.s V_14 +ldloc.s V_20 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance void class GI1`1::GF1(class GI2`1, int32, int64, int64) + +ldloc.s V_14 +ldloc.s V_20 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance void class GI1`1::GF1(class GI2`1, int32, int64, int64) + +ldloc.s V_14 +ldloc.s V_20 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance void class GI1`1::GF1(class GI2`1, int32, int64, int64) + +ldloc.s V_15 +ldloc.s V_21 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance void class GI1`1::GF1(class GI2`1, int32, int64, int64) + +ldloc.s V_15 +ldloc.s V_21 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance void class GI1`1::GF1(class GI2`1, int32, int64, int64) + +ldloc.s V_15 +ldloc.s V_21 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance void class GI1`1::GF1(class GI2`1, int32, int64, int64) + +ldloc.s V_15 +ldloc.s V_21 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +callvirt instance void class GI1`1::GF1(class GI2`1, int32, int64, int64) + +ldloc.s V_15 +ldloc.s V_21 +ldc.i4.s 100 +ldloca.s V_6 +conv.u +conv.u8 +ldc.i4.0 +conv.i8 +tail. +callvirt instance void class GI1`1::GF1(class GI2`1, int32, int64, int64) + +ret +} + +.method public static void Main(string[] args) noinlining +{ +.entrypoint +newobj instance void C3::.ctor() +tail. +call instance void C3::Main() +ret +} + +.method public instance void .ctor() +{ +ldarg.0 +tail. +call instance void [mscorlib]System.Object::.ctor() +ret +} +} diff --git a/mono/tests/tailcall-interface.cs b/mono/tests/tailcall-interface.cs new file mode 100644 index 0000000000..59c8541875 --- /dev/null +++ b/mono/tests/tailcall-interface.cs @@ -0,0 +1,517 @@ +/* +Author: + Jay Krell (jaykrell@microsoft.com) + +Copyright 2018 Microsoft +Licensed under the MIT license. See LICENSE file in the project root for full license information. +*/ +using System; +using System.Runtime.CompilerServices; +using static System.Runtime.CompilerServices.MethodImplOptions; + +public struct Point +{ + public int x; + public int y; +} + +interface I1 +{ + void perturb_interface_offset1 ( ); + + [MethodImpl (NoInlining)] + int F1 (I2 i2, int counter, long initial_stack, long current_stack = 0); + + [MethodImpl (NoInlining)] + int GF1 (I2 i2, int counter, long initial_stack, long current_stack = 0); +} + +interface GI1 +{ + void perturb_interface_offset1 ( ); + void perturb_interface_offset2 ( ); + + [MethodImpl (NoInlining)] + int F1 (GI2 i2, int counter, long initial_stack, long current_stack = 0); + + [MethodImpl (NoInlining)] + int GF1 (GI2 i2, int counter, long initial_stack, long current_stack = 0); + + [MethodImpl (NoInlining)] + int HF1 (GI2 i2, int counter, long initial_stack, long current_stack = 0); +} + +interface I2 +{ + void perturb_interface_offset1 ( ); + void perturb_interface_offset2 ( ); + void perturb_interface_offset3 ( ); + + [MethodImpl (NoInlining)] + int F2 (I1 i1, int counter, long initial_stack, long current_stack = 0); + + [MethodImpl (NoInlining)] + int GF2 (I1 i1, int counter, long initial_stack, long current_stack = 0); +} + +interface GI2 +{ + void perturb_interface_offset1 ( ); + void perturb_interface_offset2 ( ); + void perturb_interface_offset3 ( ); + void perturb_interface_offset4 ( ); + + [MethodImpl (NoInlining)] + int F2 (GI1 i1, int counter, long initial_stack, long current_stack = 0); + + [MethodImpl (NoInlining)] + int GF2 (GI1 i1, int counter, long initial_stack, long current_stack = 0); + + [MethodImpl (NoInlining)] + int HF2 (GI1 i1, int counter, long initial_stack, long current_stack = 0); +} + +unsafe public class C1 : I1 +{ + void I1.perturb_interface_offset1 ( ) { } + + static int i; + static public int errors; + + public static int check (long stack1, long stack2) + { +// NOTE: This is odd in order to feed into the edited IL. + ++i; + if (stack1 != 0) + return 0; + int error = (stack1 != stack2) ? 1 : 0; + if (error == 0) + return 0; + errors += 1; + Console.WriteLine ("{0} tailcall failure", i); + return error; + } + + [MethodImpl (NoInlining)] + int I1.F1 (I2 i2, int counter, long initial_stack, long current_stack) + { + int local; + if (counter > 0) + return i2.F2 (this, counter - 1, initial_stack, (long)&local); + return check ((long)&local, current_stack); + } + + [MethodImpl (NoInlining)] + int I1.GF1 (I2 i2, int counter, long initial_stack, long current_stack) + { + int local; + if (counter > 0) + return i2.GF2 (this, counter - 1, initial_stack, (long)&local); + return check ((long)&local, current_stack); + } +} + +unsafe public class GC1 : GI1 +{ + void GI1.perturb_interface_offset1 ( ) { } + void GI1.perturb_interface_offset2 ( ) { } + + public static int check (long stack1, long stack2) + { + return C1.check (stack1, stack2); + } + + [MethodImpl (NoInlining)] + int GI1.F1 (GI2 i2, int counter, long initial_stack, long current_stack) + { + int local; + if (counter > 0) + return i2.F2 (this, counter - 1, initial_stack, (long)&local); + return check ((long)&local, current_stack); + } + + [MethodImpl (NoInlining)] + int GI1.GF1 (GI2 i2, int counter, long initial_stack, long current_stack) + { + int local; + if (counter > 0) + return i2.GF2 (this, counter - 1, initial_stack, (long)&local); + return check ((long)&local, current_stack); + } + + [MethodImpl (NoInlining)] + int GI1.HF1 (GI2 i2, int counter, long initial_stack, long current_stack) + { + int local; + if (counter > 0) + return i2.HF2 (this, counter - 1, initial_stack, (long)&local); + return check ((long)&local, current_stack); + } +} + +unsafe public class C2 : I2 +{ + void I2.perturb_interface_offset1 ( ) { } + void I2.perturb_interface_offset2 ( ) { } + void I2.perturb_interface_offset3 ( ) { } + + static int check (long stack1, long stack2) + { + return C1.check (stack1, stack2); + } + + [MethodImpl (NoInlining)] + int I2.F2 (I1 i1, int counter, long initial_stack, long current_stack) + { + int local; + if (counter > 0) + return i1.F1 (this, counter - 1, initial_stack, (long)&local); + return check ((long)&local, current_stack); + } + + [MethodImpl (NoInlining)] + int I2.GF2 (I1 i1, int counter, long initial_stack, long current_stack) + { + int local; + if (counter > 0) + return i1.GF1 (this, counter - 1, initial_stack, (long)&local); + return check ((long)&local, current_stack); + } +} + +unsafe public class GC2 : GI2 +{ + void GI2.perturb_interface_offset1 ( ) { } + void GI2.perturb_interface_offset2 ( ) { } + void GI2.perturb_interface_offset3 ( ) { } + void GI2.perturb_interface_offset4 ( ) { } + + public static int check (long stack1, long stack2) + { + return C1.check (stack1, stack2); + } + + [MethodImpl (NoInlining)] + int GI2.F2 (GI1 i1, int counter, long initial_stack, long current_stack) + { + int local; + if (counter > 0) + return i1.F1 (this, counter - 1, initial_stack, (long)&local); + return check ((long)&local, current_stack); + } + + [MethodImpl (NoInlining)] + int GI2.GF2 (GI1 i1, int counter, long initial_stack, long current_stack) + { + int local; + if (counter > 0) + return i1.GF1 (this, counter - 1, initial_stack, (long)&local); + return check ((long)&local, current_stack); + } + + [MethodImpl (NoInlining)] + int GI2.HF2 (GI1 i1, int counter, long initial_stack, long current_stack) + { + int local; + if (counter > 0) + return i1.HF1 (this, counter - 1, initial_stack, (long)&local); + return check ((long)&local, current_stack); + } +} + +public class A { } + +public class B { } + +interface IC +{ + [MethodImpl (NoInlining)] + T cast1 (object o, int counter = 100, long stack = 0); + + [MethodImpl (NoInlining)] + B cast2 (object o, int counter = 100, long stack = 0); + + [MethodImpl (NoInlining)] + T cast3 (object o, int counter = 100, long stack = 0); + + [MethodImpl (NoInlining)] + B[] cast4 (object o, int counter = 100, long stack = 0); + + [MethodImpl (NoInlining)] + T[] cast5 (object o, int counter = 100, long stack = 0); +} + +unsafe public class C +{ + [MethodImpl (NoInlining)] + public static void check (long stack1, long stack2) + { + C1.check (stack1, stack2); + } + + [MethodImpl (NoInlining)] + public T cast1 (object o, int counter = 100, long stack = 0) + { + int local; + if (counter > 0) + return cast1 (o, counter - 1, (long)&local); + check ((long)&local, stack); + return (T)o; + } + + [MethodImpl (NoInlining)] + public B cast2 (object o, int counter = 100, long stack = 0) + { + int local; + if (counter > 0) + return cast2 (o, counter - 1, (long)&local); + check ((long)&local, stack); + return cast1 (o); + } + + [MethodImpl (NoInlining)] + public T cast3 (object o, int counter = 100, long stack = 0) + { + int local; + if (counter > 0) + return cast3 (o, counter - 1, (long)&local); + check ((long)&local, stack); + return cast1 (o); + } + + [MethodImpl (NoInlining)] + public B[] cast4 (object o, int counter = 100, long stack = 0) + { + int local; + if (counter > 0) + return cast4 (o, counter - 1, (long)&local); + check ((long)&local, stack); + return cast1 (o); + } + + [MethodImpl (NoInlining)] + public T[] cast5 (object o, int counter = 100, long stack = 0) + { + int local; + if (counter > 0) + return cast5 (o, counter - 1, (long)&local); + check ((long)&local, stack); + return cast1 (o); + } +} + +unsafe public class D +{ + [MethodImpl (NoInlining)] + public static void check (long stack1, long stack2) + { + C.check (stack1, stack2); + } + + [MethodImpl (NoInlining)] + public static T cast1 (object o, int counter = 100, long stack = 0) + { + int local; + if (counter > 0) + return cast1 (o, counter - 1, (long)&local); + check ((long)&local, stack); + return (T)o; + } + + [MethodImpl (NoInlining)] + public B cast2 (object o, int counter = 100, long stack = 0) + { + int local; + if (counter > 0) + return cast2 (o, counter - 1, (long)&local); + check ((long)&local, stack); + return cast1 (o); + } + + [MethodImpl (NoInlining)] + public T cast3 (object o, int counter = 100, long stack = 0) + { + int local; + if (counter > 0) + return cast3 (o, counter - 1, (long)&local); + check ((long)&local, stack); + return cast1 (o); + } + + [MethodImpl (NoInlining)] + public B[] cast4 (object o, int counter = 100, long stack = 0) + { + int local; + if (counter > 0) + return cast4 (o, counter - 1, (long)&local); + check ((long)&local, stack); + return cast1 (o); + } + + [MethodImpl (NoInlining)] + public T[] cast5 (object o, int counter = 100, long stack = 0) + { + int local; + if (counter > 0) + return cast5 (o, counter - 1, (long)&local); + check ((long)&local, stack); + return cast1 (o); + } + + [MethodImpl (NoInlining)] + public T1 cast6 (object o, int counter = 100, long stack = 0) + { + int local; + if (counter > 0) + return cast6 (o, counter - 1, (long)&local); + check ((long)&local, stack); + return cast1 (o); + } + + [MethodImpl (NoInlining)] + public T1 cast7 (object o, int counter = 100, long stack = 0) + { + int local; + if (counter > 0) + return cast7 (o, counter - 1, (long)&local); + check ((long)&local, stack); + return cast1 (o); + } + + [MethodImpl (NoInlining)] + public T1[] cast8 (object o, int counter = 100, long stack = 0) + { + int local; + if (counter > 0) + return cast8 (o, counter - 1, (long)&local); + check ((long)&local, stack); + return cast3 (o); + } + + [MethodImpl (NoInlining)] + public T1[] cast9 (object o, int counter = 100, long stack = 0) + { + int local; + if (counter > 0) + return cast9 (o, counter - 1, (long)&local); + check ((long)&local, stack); + return cast3 (o); + } +} + +unsafe class C3 +{ + int i; + + [MethodImpl (NoInlining)] + void print (object o) + { + ++i; + //Console.WriteLine("{0} {1}", i, o); + //Console.WriteLine(i); + } + + [MethodImpl (NoInlining)] + public void Main() + { + var da = new D (); + var db = new D (); + var dba = new D (); + var c = new C (); + var b = new B (); + var ba = new B [1]; + int stack; + var c1 = (I1)new C1 (); + var c2 = (I2)new C2 (); + int result; + var c1o = (GI1)new GC1 (); + var c1oa = (GI1)new GC1 (); + var c1i = (GI1)new GC1 (); + var c1ia = (GI1)new GC1 (); + var c1s = (GI1)new GC1 (); + var c1sa = (GI1)new GC1 (); + var c2o = (GI2)new GC2 (); + var c2oa = (GI2)new GC2 (); + var c2i = (GI2)new GC2 (); + var c2ia = (GI2)new GC2 (); + var c2s = (GI2)new GC2 (); + var c2sa = (GI2)new GC2 (); + + print (da.cast2 (b)); + print (da.cast3 (b)); + print (da.cast3 (ba)); + print (da.cast4 (ba)); + print (da.cast5 (ba)); + + print (db.cast6 (b)); + print (db.cast7 (b)); + print (dba.cast7 (ba)); + print (db.cast8 (ba)); + print (db.cast9 (ba)); + + print (c.cast2 (b)); + print (c.cast3 (b)); + print (c.cast3 (ba)); + print (c.cast4 (ba)); + print (c.cast5 (ba)); + + //Console.WriteLine("done"); + //Console.WriteLine("success"); + + result = c1.F1 (c2, 100, (long)&stack, 0) + + c1.GF1 (c2, 100, (long)&stack, 0) + + c1.GF1 (c2, 100, (long)&stack, 0) + + c1.GF1 (c2, 100, (long)&stack, 0) + + c1.GF1 (c2, 100, (long)&stack, 0) + + c1.GF1 (c2, 100, (long)&stack, 0) + + + c1o.F1 (c2o, 100, (long)&stack) + + c1o.GF1 (c2o, 100, (long)&stack) + + c1o.GF1 (c2o, 100, (long)&stack) + + c1o.GF1 (c2o, 100, (long)&stack) + + c1o.GF1 (c2o, 100, (long)&stack) + + c1o.GF1 (c2o, 100, (long)&stack) + + + c1oa.GF1 (c2oa, 100, (long)&stack) + + c1oa.GF1 (c2oa, 100, (long)&stack) + + c1oa.GF1 (c2oa, 100, (long)&stack) + + c1oa.GF1 (c2oa, 100, (long)&stack) + + c1oa.GF1 (c2oa, 100, (long)&stack) + + + c1i.GF1 (c2i, 100, (long)&stack) + + c1i.GF1 (c2i, 100, (long)&stack) + + c1i.GF1 (c2i, 100, (long)&stack) + + c1i.GF1 (c2i, 100, (long)&stack) + + c1i.GF1 (c2i, 100, (long)&stack) + + + c1ia.GF1 (c2ia, 100, (long)&stack) + + c1ia.GF1 (c2ia, 100, (long)&stack) + + c1ia.GF1 (c2ia, 100, (long)&stack) + + c1ia.GF1 (c2ia, 100, (long)&stack) + + c1ia.GF1 (c2ia, 100, (long)&stack) + + + c1s.GF1 (c2s, 100, (long)&stack) + + c1s.GF1 (c2s, 100, (long)&stack) + + c1s.GF1 (c2s, 100, (long)&stack) + + c1s.GF1 (c2s, 100, (long)&stack) + + c1s.GF1 (c2s, 100, (long)&stack) + + + c1sa.GF1 (c2sa, 100, (long)&stack) + + c1sa.GF1 (c2sa, 100, (long)&stack) + + c1sa.GF1 (c2sa, 100, (long)&stack) + + c1sa.GF1 (c2sa, 100, (long)&stack) + + c1sa.GF1 (c2sa, 100, (long)&stack) + + C1.errors; + + //Console.WriteLine (result == 0 ? "success" : "failure {0}", result); + + Environment.Exit (result); + } + + [MethodImpl (NoInlining)] + public static void Main(string[] args) + { + new C3 ().Main (); + } + +} diff --git a/mono/tests/tailcall-mrgctx.il b/mono/tests/tailcall-mrgctx.il new file mode 100644 index 0000000000..8ee5c8706f --- /dev/null +++ b/mono/tests/tailcall-mrgctx.il @@ -0,0 +1,163 @@ +/* +Author: + Jay Krell (jaykrell@microsoft.com) + +Copyright 2018 Microsoft +Licensed under the MIT license. See LICENSE file in the project root for full license information. + +http://www.mono-project.com/docs/advanced/runtime/docs/generic-sharing/ +1. Non-generic non-static methods of reference types have access to the + RGCTX via the “this” argument (this->vtable->rgctx). +2. a. Non-generic static methods of reference types and b. non-generic methods + of value types need to be passed a pointer to the caller’s class’s VTable in the MONO_ARCH_RGCTX_REG register. +3. Generic methods need to be passed a pointer to the MRGCTX in the MONO_ARCH_RGCTX_REG register + +Test case 3. + +using System; +using System.Runtime.CompilerServices; +using static System.Runtime.CompilerServices.MethodImplOptions; + +unsafe class A +{ + [MethodImpl (NoInlining)] + static int check (long stack1, long stack2) + { + return (stack1 == stack2) ? 0 : 1; + } + + [MethodImpl (NoInlining)] + public int f1 (int counter, long initial_stack, long current_stack) + { + int local; + if (counter > 0) + return f2 (counter - 1, initial_stack, (long)&local); + return check ((long)&local, current_stack); + } + + [MethodImpl (NoInlining)] + public int f2 (int counter, long initial_stack, long current_stack) + { + int local; + if (counter > 0) + return f1 (counter - 1, initial_stack, (long)&local); + return check ((long)&local, current_stack); + } +} + +unsafe class B +{ + [MethodImpl (NoInlining)] + public static void Main() + { + int stack; + Environment.Exit(new A().f1 (100, (long)&stack, 0)); + } +} +*/ +.assembly extern mscorlib { } +.assembly tailcall_mrgctx { } + +.class A +{ +.method static int32 check (int64 stack1, int64 stack2) noinlining +{ + ldarg.0 + ldarg.1 + beq.s IL_0006 + + ldc.i4.1 + ret + +IL_0006: + ldc.i4.0 + ret +} + +.method instance int32 f1 (int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ + .locals init (int32 V_0) + ldarg.1 // counter + ldc.i4.0 // 0 + ble.s IL_0013 // if (counter <= 0) goto 13. + + ldarg.0 // this + ldarg.1 // counter + ldc.i4.1 // 1 + sub // counter - 1 + ldarg.2 // initial_stack + ldloca.s V_0 // &local + conv.u // (long)&local + conv.u8 // (long)&local + tail. call instance int32 A::f2 (int32, int64, int64) + ret + +IL_0013: + ldloca.s V_0 // &local + conv.u // (long)&local + conv.u8 // (long)&local + ldarg.3 // current_stack + tail. call int32 A::check (int64, int64) + ret +} + +.method instance int32 f2 (int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ + .locals init (int32 V_0) + ldarg.1 + ldc.i4.0 + ble.s IL_0013 + + ldarg.0 + ldarg.1 + ldc.i4.1 + sub + ldarg.2 + ldloca.s V_0 + conv.u + conv.u8 + tail. call instance int32 A::f1 (int32, int64, int64) + ret + +IL_0013: + ldloca.s V_0 + conv.u + conv.u8 + ldarg.3 + tail. call int32 A::check (int64, int64) + ret +} + +.method instance void .ctor () +{ + ldarg.0 + tail. call instance void [mscorlib]System.Object::.ctor () + ret +} + +} + +.class B +{ +.method static int32 Main () noinlining +{ + .entrypoint + .locals init (int32 V_0) + newobj instance void A::.ctor () + ldc.i4.s 100 + ldloca.s V_0 + conv.u + conv.u8 + ldc.i4.0 + conv.i8 + tail. call instance int32 A::f1 (int32, int64, int64) + ret +} + +.method instance void .ctor () +{ + ldarg.0 + tail. call instance void [mscorlib]System.Object::.ctor () + ret +} +} diff --git a/mono/tests/tailcall-rgctxa.il b/mono/tests/tailcall-rgctxa.il new file mode 100644 index 0000000000..dc93e35a06 --- /dev/null +++ b/mono/tests/tailcall-rgctxa.il @@ -0,0 +1,157 @@ +/* +Author: + Jay Krell (jaykrell@microsoft.com) + +Copyright 2018 Microsoft +Licensed under the MIT license. See LICENSE file in the project root for full license information. + +http://www.mono-project.com/docs/advanced/runtime/docs/generic-sharing/ +1. Non-generic non-static methods of reference types have access to the + RGCTX via the “this” argument (this->vtable->rgctx). +2. a. Non-generic static methods of reference types and b. non-generic methods + of value types need to be passed a pointer to the caller’s class’s VTable in the MONO_ARCH_RGCTX_REG register. +3. Generic methods need to be passed a pointer to the MRGCTX in the MONO_ARCH_RGCTX_REG register + +Test case 2a. + +using System; +using System.Runtime.CompilerServices; +using static System.Runtime.CompilerServices.MethodImplOptions; + +unsafe class A +{ + [MethodImpl (NoInlining)] + static int check (long stack1, long stack2) + { + return (stack1 == stack2) ? 0 : 1; + } + + [MethodImpl (NoInlining)] + public static int f1 (int counter, long initial_stack, long current_stack) + { + int local; + if (counter > 0) + return f2 (counter - 1, initial_stack, (long)&local); + return check ((long)&local, current_stack); + } + + [MethodImpl (NoInlining)] + public static int f2 (int counter, long initial_stack, long current_stack) + { + int local; + if (counter > 0) + return f1 (counter - 1, initial_stack, (long)&local); + return check ((long)&local, current_stack); + } +} + +unsafe class B +{ + [MethodImpl (NoInlining)] + public static void Main() + { + int stack; + Environment.Exit(A.f1 (100, (long)&stack, 0)); + } +} +*/ + +.assembly extern mscorlib { } +.assembly tailcall_rgctxa { } + +.class A`1 +{ +.method static int32 check (int64 stack1, int64 stack2) noinlining +{ + ldarg.0 + ldarg.1 + beq.s IL_0006 + ldc.i4.1 + ret + +IL_0006: + ldc.i4.0 + ret +} + +.method static int32 f1 (int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ + .locals init (int32 V_0) + ldarg.0 + ldc.i4.0 + ble.s IL_0012 + ldarg.0 + ldc.i4.1 + sub + ldarg.1 + ldloca.s V_0 + conv.u + conv.u8 + tail. call int32 class A`1::f2 (int32, int64, int64) + ret + +IL_0012: + ldloca.s V_0 + conv.u + conv.u8 + ldarg.2 + tail. call int32 class A`1::check (int64, int64) + ret +} + +.method public hidebysig static int32 f2 (int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ + .locals init (int32 V_0) + ldarg.0 + ldc.i4.0 + ble.s IL_0012 + ldarg.0 + ldc.i4.1 + sub + ldarg.1 + ldloca.s V_0 + conv.u + conv.u8 + tail. call int32 class A`1::f1 (int32, int64, int64) + ret + +IL_0012: + ldloca.s V_0 + conv.u + conv.u8 + ldarg.2 + tail. call int32 class A`1::check (int64, int64) + ret +} + +.method instance void .ctor() +{ + ldarg.0 + tail. call instance void [mscorlib]System.Object::.ctor () + ret +} +} + +.class B +{ +.method static int32 Main () noinlining +{ + .entrypoint + .locals init (int32 V_0) + ldc.i4.s 100 + ldloca.s V_0 + conv.u + conv.u8 + ldc.i4.0 + conv.i8 + tail. call int32 class A`1::f1(int32, int64, int64) + ret +} + +.method instance void .ctor() +{ + ldarg.0 + tail. call instance void [mscorlib]System.Object::.ctor() + ret +} +} diff --git a/mono/tests/tailcall-rgctxb.il b/mono/tests/tailcall-rgctxb.il new file mode 100644 index 0000000000..04af93cc5a --- /dev/null +++ b/mono/tests/tailcall-rgctxb.il @@ -0,0 +1,175 @@ +/* +Author: + Jay Krell (jaykrell@microsoft.com) + +Copyright 2018 Microsoft +Licensed under the MIT license. See LICENSE file in the project root for full license information. + +http://www.mono-project.com/docs/advanced/runtime/docs/generic-sharing/ +1. Non-generic non-static methods of reference types have access to the + RGCTX via the “this” argument (this->vtable->rgctx). +2. a. Non-generic static methods of reference types and b. non-generic methods + of value types need to be passed a pointer to the caller’s class’s VTable in the MONO_ARCH_RGCTX_REG register. +3. Generic methods need to be passed a pointer to the MRGCTX in the MONO_ARCH_RGCTX_REG register + +Test case 2b. +This passes on desktop but not Mono, despite seeming like it is implemented. + +using System; +using System.Runtime.CompilerServices; +using static System.Runtime.CompilerServices.MethodImplOptions; + +unsafe struct A +{ + void f3 () + { + a = b = c = d = e = f = g = h = 1; + } + public int a, b, c, d, e, f, g, h; + + [MethodImpl (NoInlining)] + static int check (long stack1, long stack2) + { + return (stack1 == stack2) ? 0 : 1; + } + + [MethodImpl (NoInlining)] + public int f1 (int counter, long initial_stack, long current_stack) + { + int local; + object a = new T[101]; + if (counter > 0) + return f2 (counter - 1, initial_stack, (long)&local); + return check ((long)&local, current_stack); + } + + [MethodImpl (NoInlining)] + public int f2 (int counter, long initial_stack, long current_stack) + { + int local; + object a = new T[101]; + if (counter > 0) + return f1 (counter - 1, initial_stack, (long)&local); + return check ((long)&local, current_stack); + } +} + +unsafe class B +{ + [MethodImpl (NoInlining)] + public static void Main() + { + int stack; + Environment.Exit(new A().f1 (100, (long)&stack, 0)); + } +} +*/ + +.assembly extern mscorlib { } +.assembly tailcall_rgctxb { } + +.class A`1 + +// Remove this change the test a lot and make it pass. +extends [mscorlib]System.ValueType + +{ +.method static int32 check (int64 stack1, int64 stack2) noinlining +{ + ldarg.0 + ldarg.1 + beq.s IL_0006 + + ldc.i4.1 + ret + +IL_0006: + ldc.i4.0 + ret +} + +.method instance int32 f1 (int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ + .locals init (int32 V_0) + + ldarg.1 + ldc.i4.0 + ble.s IL_001b + + ldarg.0 + ldarg.1 + ldc.i4.1 + sub + ldarg.2 + ldloca.s V_0 + conv.u + conv.u8 + tail. call instance int32 valuetype A`1::f2 (int32, int64, int64) + ret + +IL_001b: + ldloca.s V_0 + conv.u + conv.u8 + ldarg.3 + tail. call int32 valuetype A`1::check (int64, int64) + ret +} + +.method instance int32 f2 (int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ + .locals init (int32 V_0) + ldarg.1 + ldc.i4.0 + ble.s IL_001b + + ldarg.0 + ldarg.1 + ldc.i4.1 + sub + ldarg.2 + ldloca.s V_0 + conv.u + conv.u8 + tail. call instance int32 valuetype A`1::f1 (int32, int64, int64) + ret + +IL_001b: + ldloca.s V_0 + conv.u + conv.u8 + ldarg.3 + tail. call int32 valuetype A`1::check (int64, int64) + ret +} +} + +.class B extends [mscorlib]System.Object +{ + +.method static int32 Main() noinlining +{ + .entrypoint + .locals init (int32 V_0, valuetype A`1 V_1) + ldloca.s V_1 + initobj valuetype A`1 + ldloc.1 + stloc.1 + ldloca.s V_1 + ldc.i4.s 100 + ldloca.s V_0 + conv.u + conv.u8 + ldc.i4.0 + conv.i8 + tail. call instance int32 valuetype A`1::f1 (int32, int64, int64) + ret +} + +.method instance void .ctor() +{ + ldarg.0 + tail. call instance void [mscorlib]System.Object::.ctor () + ret +} +} diff --git a/mono/tests/tailcall-virt.il b/mono/tests/tailcall-virt.il new file mode 100644 index 0000000000..87e42fcabd --- /dev/null +++ b/mono/tests/tailcall-virt.il @@ -0,0 +1,163 @@ +/* +Test tail.callvirt. + +Author: + Jay Krell (jaykrell@microsoft.com) + +Copyright 2018 Microsoft +Licensed under the MIT license. See LICENSE file in the project root for full license information. + +This IL will exit with 0 for success, 1 for failure. +It is based on nearby C# that is based on nearby F#. + +This test covers tail.callvirt. +Incidentally it is a mutual recursion, not a self-recursion, +no generics, no pointers, small function signature, no value types, etc. + +This is based on F#, that stack overflows or exit with 1 or 2. +If testing the F#, be sure to compile with --optimize- else +the tailcall might be optimized away: + type A() = + member this.f2 (a) = if a > 0 then this.f1(a - 1) + else 1 + member this.f1 (a) = if a > 0 then this.f2(a - 1) + else 2 + + let a = A() + printfn "%d" (a.f1(1000 * 1000 * 10)) + +and more closely on C#, csc -optimize to keep +ret next call, ildasm and add tail.: + using System; + using System.Runtime.CompilerServices; + using static System.Runtime.CompilerServices.MethodImplOptions; + + unsafe class A + { + static int check (long stack1, long stack2) + { + return (stack1 == stack2) ? 0 : 1; + } + + [MethodImpl (NoInlining)] + public virtual int f1(int counter, long initial_stack, long current_stack) + { + int local; + if (counter > 0) + return f2(counter - 1, initial_stack, (long)&local); + return check((long)&local, current_stack); + } + + [MethodImpl (NoInlining)] + public virtual int f2(int counter, long initial_stack, long current_stack) + { + int local; + if (counter > 0) + return f1(counter - 1, initial_stack, (long)&local); + return check((long)&local, current_stack); + } + + [MethodImpl (NoInlining)] + public static void Main() + { + int stack; + Environment.Exit(new A().f1(100, (long)&stack, 0)); + } + } +*/ + +.assembly extern mscorlib { } + +.assembly b { } + +.class A +{ +.method static int32 check(int64 stack1, int64 stack2) +{ + ldarg.0 + ldarg.1 + beq.s IL_0006 + ldc.i4.1 + ret + +IL_0006: + ldc.i4.0 + ret +} + +.method newslot virtual instance int32 f1(int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ + .locals init (int32 V_0) + ldarg.1 + ldc.i4.0 + ble.s IL_0013 + ldarg.0 + ldarg.1 + ldc.i4.1 + sub + ldarg.2 + ldloca.s V_0 + conv.u + conv.u8 + tail. callvirt instance int32 A::f2(int32, int64, int64) + ret + +IL_0013: + ldloca.s V_0 + conv.u + conv.u8 + ldarg.3 + tail. call int32 A::check(int64, int64) + ret +} + +.method newslot virtual instance int32 f2(int32 counter, int64 initial_stack, int64 current_stack) noinlining +{ + .locals init (int32 V_0) + ldarg.1 + ldc.i4.0 + ble.s IL_0013 + ldarg.0 + ldarg.1 + ldc.i4.1 + sub + ldarg.2 + ldloca.s V_0 + conv.u + conv.u8 + tail. callvirt instance int32 A::f1(int32, int64, int64) + ret + +IL_0013: + ldloca.s V_0 + conv.u + conv.u8 + ldarg.3 + tail. call int32 A::check(int64, int64) + ret +} + +.method static void Main() noinlining +{ + .entrypoint + .locals init (int32 V_0) + newobj instance void A::.ctor() + ldc.i4 0x100 + ldloca.s V_0 + conv.u + conv.u8 + ldc.i4.0 + conv.i8 + callvirt instance int32 A::f1(int32, int64, int64) + tail. call void [mscorlib]System.Environment::Exit(int32) + ret +} + +.method instance void .ctor() +{ + ldarg.0 + tail. call instance void [mscorlib]System.Object::.ctor() + ret +} + +} diff --git a/mono/tests/tailcall/coreclr/JIT/CodeGenBringUpTests/RecursiveTailCall.cs b/mono/tests/tailcall/coreclr/JIT/CodeGenBringUpTests/RecursiveTailCall.cs new file mode 100644 index 0000000000..a38b34d799 --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/CodeGenBringUpTests/RecursiveTailCall.cs @@ -0,0 +1,172 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// + +using System; +using System.Runtime.CompilerServices; + +public struct Struct1 +{ + public bool bfield; + + public Struct1(bool b) + { + bfield = b; + } +} + +public struct Struct8 +{ + public double dfield; + + public Struct8(double d) + { + dfield = d; + } +} + +class GenericClass { } +class GenericException : Exception +{ +} + +public class Test +{ + // Test a recursive tail call with a 1-byte struct parameter. + static bool TestStruct1Param(Struct1 str1, int count) + { + Console.WriteLine(count); + Console.WriteLine(count); + Console.WriteLine(count); + Console.WriteLine(count); + if (!CheckStruct1(str1)) + { + return false; + } + + if (count <= 0) + { + return true; + } + + return TestStruct1Param(str1, count - 1); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool CheckStruct1(Struct1 str1) + { + return str1.bfield; + } + + // Test a recursive tail call with an 8-byte struct parameter. + static bool TestStruct8Param(Struct8 str8, int count) + { + Console.WriteLine(count); + Console.WriteLine(count); + Console.WriteLine(count); + Console.WriteLine(count); + if (!CheckStruct8(str8)) + { + return false; + } + + if (count <= 0) + { + return true; + } + + return TestStruct8Param(str8, count - 1); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool CheckStruct8(Struct8 str8) + { + return (str8.dfield == 1.0); + } + + // Test a recursive tail call to a method with generic sharing. + bool TestGenericSharing() + { + if (typeof(T) == typeof(string)) + { + return true; + } + else + { + return TestGenericSharing(); + } + } + + // Test a recursive tail call to a method with hidden generic context param. + // This test will make sure that when a recursive call is converte to a loop + // there is no mismatch of generic context reported to VM and the one used + // within the method. + public static int TestGenericContext(int x) + { + try + { + if (x == 1) throw new GenericException(); + } + catch (GenericException) + { + return 1; + } + + return x * TestGenericContext>(x - 1); + } + + // Test a recursive tail call to a method that has a 'this' parameter + // and a parameter passed on the stack. + bool TestStackParam(int i1, int i2, int i3, int i4) + { + if ((i3 != 5) || (i4 != 7)) + { + return false; + } + if (i1 == 0) + { + return true; + } + return TestStackParam(i1 - 1, i2, i3, i4); + } + + public static int Main() + { + const int Pass = 100; + const int Fail = -1; + + Struct1 str1 = new Struct1(true); + + if (!TestStruct1Param(str1, 4)) + { + return Fail; + } + + Struct8 str8 = new Struct8(1.0); + + if (!TestStruct8Param(str8, 4)) + { + return Fail; + } + + Test test = new Test(); + + if (!test.TestGenericSharing()) + { + return Fail; + } + + if (!test.TestStackParam(1, 0, 5, 7)) + { + return Fail; + } + + if (TestGenericContext>(5) != 120) + { + return Fail; + } + + return Pass; + } +} diff --git a/mono/tests/tailcall/coreclr/JIT/Directed/IL/PInvokeTail/PInvokeTail.il b/mono/tests/tailcall/coreclr/JIT/Directed/IL/PInvokeTail/PInvokeTail.il new file mode 100644 index 0000000000..b1d2573aaf --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Directed/IL/PInvokeTail/PInvokeTail.il @@ -0,0 +1,99 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly pinvoketail +{ +} + + +.class public auto ansi Wrapper +{ + .method public static pinvokeimpl("msvcrt.dll" cdecl) int32 puts(int8* A_0) il managed preservesig{ } + .method public specialname rtspecialname instance void .ctor() il managed + { + .maxstack 1 + + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method 'Wrapper::.ctor' + +} // end of class 'Wrapper' + +.method public static int32 ?callputs1@@YAHXZ() il managed +{ + .maxstack 1 + + IL_0000: ldstr bytearray(48 65 6C 6C 6F 20 57 6F 72 6C 64 21 00 00 00 00) //ldptr D_00003000 + IL_0005: tail. call int32 puts(int8*) + IL_000a: ret +} // end of global method '?callputs1@@YAHXZ' + +.method public static int32 ?callputs2@@YAHXZ() il managed +{ + .maxstack 1 + + IL_0000: ldstr bytearray(48 65 6C 6C 6F 20 57 6F 72 6C 64 21 00 00 00 00) //" " //ldptr D_00003010 + IL_0005: tail. call int32 Wrapper::puts(int8*) + IL_000a: ret +} // end of global method '?callputs2@@YAHXZ' + +.method public static int32 main() il managed +{ + .entrypoint + .maxstack 2 + + IL_0000: call int32 ?callputs1@@YAHXZ() + IL_0005: ldc.i4 0x0 + IL_000a: bge IL_0029 + + IL_000f: call class [mscorlib]System.IO.TextWriter [mscorlib]System.Console::get_Out() + IL_0014: ldstr "Puts Failed" //ldptr D_00003020 + IL_0019: //newobj instance void [mscorlib]System.String::.ctor(wchar*) + IL_001e: callvirt instance void [mscorlib]System.IO.TextWriter::WriteLine(string) + IL_0023: ldc.i4 0x1 + IL_0028: ret + + IL_0029: call int32 ?callputs2@@YAHXZ() + IL_002e: ldc.i4 0x0 + IL_0033: bge IL_0052 + + IL_0038: call class [mscorlib]System.IO.TextWriter [mscorlib]System.Console::get_Out() + IL_003d: ldstr "wrapper: Puts failed"//ldptr D_00003040 + IL_0042: //newobj instance void [mscorlib]System.String::.ctor(wchar*) + IL_0047: callvirt instance void [mscorlib]System.IO.TextWriter::WriteLine(string) + IL_004c: ldc.i4 0x1 + IL_0051: ret + + IL_0052: call class [mscorlib]System.IO.TextWriter [mscorlib]System.Console::get_Out() + IL_0057: ldstr "passed"//ldptr D_00003070 + IL_005c: //newobj instance void [mscorlib]System.String::.ctor(wchar*) + IL_0061: callvirt instance void [mscorlib]System.IO.TextWriter::WriteLine(string) + IL_0066: ldc.i4 0x64 + IL_006b: ret +} // end of global method 'main' + +.method public static int32 _mainMSIL(int32 argc,int8** argv,int8** envp) il managed +{ + .maxstack 1 + + IL_0000: tail. call int32 main() + IL_0005: ret +} // end of global method '_mainMSIL' + +.method public static pinvokeimpl("msvcrt.dll" cdecl) int32 puts(int8* A_0) il managed preservesig{ } +.data D_00003000 = bytearray ( + 48 65 6C 6C 6F 20 57 6F 72 6C 64 21 00 00 00 00) // Hello World!.... +.data D_00003010 = bytearray ( + 48 65 6C 6C 6F 20 57 6F 72 6C 64 21 00 00 00 00) // Hello World!.... +.data D_00003020 = bytearray ( + 70 00 75 00 74 00 73 00 28 00 29 00 20 00 66 00 // p.u.t.s.(.). .f. + 61 00 69 00 6C 00 65 00 64 00 2E 00 00 00 00 00) // a.i.l.e.d....... +.data D_00003040 = bytearray ( + 57 00 72 00 61 00 70 00 70 00 65 00 72 00 3A 00 // W.r.a.p.p.e.r.:. + 3A 00 70 00 75 00 74 00 73 00 28 00 29 00 20 00 // :.p.u.t.s.(.). . + 66 00 61 00 69 00 6C 00 65 00 64 00 2E 00 00 00) // f.a.i.l.e.d..... +.data D_00003070 = bytearray ( + 50 00 61 00 73 00 73 00 65 00 64 00 00 00) // P.a.s.s.e.d... diff --git a/mono/tests/tailcall/coreclr/JIT/Directed/IL/PInvokeTail/tailwinapi.il b/mono/tests/tailcall/coreclr/JIT/Directed/IL/PInvokeTail/tailwinapi.il new file mode 100644 index 0000000000..214e91af4f --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Directed/IL/PInvokeTail/tailwinapi.il @@ -0,0 +1,214 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } + +.assembly tailwinapi +{ +} + + +.class public auto ansi Win32 +{ + + .method family static pinvokeimpl("kernel32.dll" ansi winapi) unsigned int32 GetSystemDirectoryA(class [mscorlib]System.Text.StringBuilder lpText,unsigned int32 uSize) il managed preservesig {} + .method family static pinvokeimpl("kernel32.dll" unicode winapi) unsigned int32 GetSystemDirectoryW(class [mscorlib]System.Text.StringBuilder lpText,unsigned int32 uSize) il managed preservesig {} + .method family static pinvokeimpl("kernel32.dll" as "GetSystemDirectory" autochar winapi) unsigned int32 GetSystemDirectoryAuto(class [mscorlib]System.Text.StringBuilder pText,unsigned int32 uSize) il managed preservesig {} + .method family static pinvokeimpl("kernel32.dll" as "GetSystemDirectoryA" ansi winapi) unsigned int32 GetSystemDirectory(class [mscorlib]System.Text.StringBuilder lpText,unsigned int32 uSize) il managed preservesig {} + .method public specialname rtspecialname instance void .ctor() il managed + { + // Method begins at RVA 0x1000 + // Code size 7 (0x7) + .maxstack 1 + + IL_0000: ldarg.0 + IL_0001: tail. call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method 'Win32::.ctor' + +} // end of class 'Win32' + +.class public auto ansi TailWin32 extends Win32 +{ + .method public static unsigned int32 GetSystemDirectoryA(class [mscorlib]System.Text.StringBuilder lpText,unsigned int32 uSize) il managed + { + // Method begins at RVA 0x1020 + // Code size 8 (0x8) + .maxstack 2 + + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: tail. call unsigned int32 Win32::GetSystemDirectoryA(class [mscorlib]System.Text.StringBuilder,unsigned int32) + IL_0007: ret + } // end of method 'TailWin32::GetSystemDirectoryA' + + .method public instance unsigned int32 GetSystemDirectoryW(class [mscorlib]System.Text.StringBuilder lpText,unsigned int32 uSize) il managed + { + // Method begins at RVA 0x1040 + // Code size 8 (0x8) + .maxstack 2 + + IL_0000: ldarg.1 + IL_0001: ldarg.2 + IL_0002: tail. call unsigned int32 Win32::GetSystemDirectoryW(class [mscorlib]System.Text.StringBuilder,unsigned int32) + IL_0007: ret + } // end of method 'TailWin32::GetSystemDirectoryW' + + .method public static unsigned int32 GetSystemDirectoryAuto(class [mscorlib]System.Text.StringBuilder lpText,unsigned int32 uSize) il managed + { + // Method begins at RVA 0x1060 + // Code size 8 (0x8) + .maxstack 2 + + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: tail. call unsigned int32 Win32::GetSystemDirectoryAuto(class [mscorlib]System.Text.StringBuilder,unsigned int32) + IL_0007: ret + } // end of method 'TailWin32::GetSystemDirectoryAuto' + + .method public instance unsigned int32 GetSystemDirectory(class [mscorlib]System.Text.StringBuilder lpText,unsigned int32 uSize) il managed + { + // Method begins at RVA 0x1080 + // Code size 8 (0x8) + .maxstack 2 + + IL_0000: ldarg.1 + IL_0001: ldarg.2 + IL_0002: tail. call unsigned int32 Win32::GetSystemDirectory(class [mscorlib]System.Text.StringBuilder,unsigned int32) + IL_0007: ret + } // end of method 'TailWin32::GetSystemDirectory' + + .method public specialname rtspecialname instance void .ctor() il managed + { + // Method begins at RVA 0x10a0 + // Code size 7 (0x7) + .maxstack 1 + + IL_0000: ldarg.0 + IL_0001: tail. call instance void Win32::.ctor() + IL_0006: ret + } // end of method 'TailWin32::.ctor' + +} // end of class 'TailWin32' + +//Global methods +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.method public static int32 main() il managed +{ + .entrypoint + // Method begins at RVA 0x10c0 + // Code size 241 (0xf1) + .maxstack 3 + .locals (class [mscorlib]System.Text.StringBuilder V_0, + int32 V_1, + class TailWin32 V_2, + int32 V_3) + + IL_0000: ldc.i4 0x100 + IL_0005: newobj instance void [mscorlib]System.Text.StringBuilder::.ctor(int32) + IL_000a: stloc.0 + IL_000b: ldc.i4 0x1 + IL_0010: stloc.1 + IL_0011: newobj instance void TailWin32::.ctor() + IL_0016: stloc.2 + IL_0017: ldloc.0 + IL_0018: ldc.i4 0x100 + IL_001d: call unsigned int32 TailWin32::GetSystemDirectoryA(class [mscorlib]System.Text.StringBuilder,unsigned int32) + IL_0022: stloc.3 + IL_0023: ldloc.0 + IL_0024: castclass [mscorlib]System.Object + IL_0029: call void [mscorlib]System.Console::WriteLine(class [mscorlib]System.Object) + IL_002e: ldloc.3 + IL_002f: ldc.i4 0x0 + IL_0034: bne.un IL_004e + + IL_0039: ldstr "Call ansi API failed"//ldptr D_00003000 + IL_003e: //newobj instance void [mscorlib]System.String::.ctor(wchar*) + IL_0043: call void [mscorlib]System.Console::WriteLine(class [mscorlib]System.String) + IL_0048: ldc.i4 0x0 + IL_004d: stloc.1 + IL_004e: ldloc.2 + IL_004f: ldloc.0 + IL_0050: ldc.i4 0x100 + IL_0055: call instance unsigned int32 TailWin32::GetSystemDirectory(class [mscorlib]System.Text.StringBuilder,unsigned int32) + IL_005a: stloc.3 + IL_005b: ldloc.0 + IL_005c: castclass [mscorlib]System.Object + IL_0061: call void [mscorlib]System.Console::WriteLine(class [mscorlib]System.Object) + IL_0066: ldloc.3 + IL_0067: ldc.i4 0x0 + IL_006c: bne.un IL_0086 + + IL_0071: ldstr "Called unicode/ansi based." //ldptr D_00003030 + IL_0076: //newobj instance void [mscorlib]System.String::.ctor(wchar*) + IL_007b: call void [mscorlib]System.Console::WriteLine(class [mscorlib]System.String) + IL_0080: ldc.i4 0x0 + IL_0085: stloc.1 + IL_0086: ldloc.0 + IL_0087: ldc.i4 0x100 + IL_008c: call unsigned int32 TailWin32::GetSystemDirectoryAuto(class [mscorlib]System.Text.StringBuilder,unsigned int32) + IL_0091: stloc.3 + IL_0092: ldloc.0 + IL_0093: castclass [mscorlib]System.Object + IL_0098: call void [mscorlib]System.Console::WriteLine(class [mscorlib]System.Object) + IL_009d: ldloc.3 + IL_009e: ldc.i4 0x0 + IL_00a3: bne.un IL_00bc + + IL_00a8: ldstr "Call unicode/ansi" //ldptr D_000030A0 + IL_00ad: //newobj instance void [mscorlib]System.String::.ctor(wchar*) + IL_00b2: call void [mscorlib]System.Console::WriteLine(class [mscorlib]System.String) + IL_00b7: br IL_00dc + + IL_00bc: ldloc.1 + IL_00bd: ldc.i4 0x0 + IL_00c2: beq IL_00dc + + IL_00c7: ldstr "Passed" //ldptr D_000030EC + IL_00cc: //newobj instance void [mscorlib]System.String::.ctor(wchar*) + IL_00d1: call void [mscorlib]System.Console::WriteLine(class [mscorlib]System.String) + IL_00d6: ldc.i4 0x64 + IL_00db: ret + + IL_00dc: ldstr "failed"//ldptr D_00003100 + IL_00e1: //newobj instance void [mscorlib]System.String::.ctor(wchar*) + IL_00e6: call void [mscorlib]System.Console::WriteLine(class [mscorlib]System.String) + IL_00eb: ldc.i4 0x1 + IL_00f0: ret +} // end of global method 'main' + +.method public static int32 _mainMSIL(int32 argc,int8** argv,int8** envp) il managed +{ + // Method begins at RVA 0x11c0 + // Code size 6 (0x6) + .maxstack 1 + + IL_0000: call int32 main() + IL_0005: ret +} // end of global method '_mainMSIL' + +.data D_00003000 = bytearray ( + 43 00 61 00 6C 00 6C 00 20 00 61 00 6E 00 73 00 // C.a.l.l. .a.n.s. + 69 00 20 00 41 00 50 00 49 00 20 00 66 00 61 00 // i. .A.P.I. .f.a. + 69 00 6C 00 65 00 64 00 00 00 00 00 00 00 00 00) // i.l.e.d......... +.data D_00003030 = bytearray ( + 43 00 61 00 6C 00 6C 00 20 00 75 00 6E 00 69 00 // C.a.l.l. .u.n.i. + 63 00 6F 00 64 00 65 00 2F 00 61 00 6E 00 73 00 // c.o.d.e./.a.n.s. + 69 00 20 00 62 00 61 00 73 00 65 00 64 00 20 00 // i. .b.a.s.e.d. . + 6F 00 6E 00 20 00 64 00 65 00 66 00 69 00 6E 00 // o.n. .d.e.f.i.n. + 65 00 20 00 6F 00 66 00 20 00 5F 00 55 00 4E 00 // e. .o.f. ._.U.N. + 49 00 43 00 4F 00 44 00 45 00 20 00 66 00 61 00 // I.C.O.D.E. .f.a. + 69 00 6C 00 65 00 64 00 00 00 00 00 00 00 00 00) // i.l.e.d......... +.data D_000030A0 = bytearray ( + 20 00 43 00 61 00 6C 00 6C 00 20 00 75 00 6E 00 // .C.a.l.l. .u.n. + 69 00 63 00 6F 00 64 00 65 00 2F 00 61 00 6E 00 // i.c.o.d.e./.a.n. + 73 00 69 00 20 00 62 00 61 00 73 00 65 00 64 00 // s.i. .b.a.s.e.d. + 20 00 6F 00 6E 00 20 00 4F 00 53 00 20 00 66 00 // .o.n. .O.S. .f. + 61 00 69 00 6C 00 65 00 64 00 00 00) // a.i.l.e.d... +.data D_000030EC = bytearray ( + 50 00 61 00 73 00 73 00 65 00 64 00 21 00 21 00 // P.a.s.s.e.d.!.!. + 00 00 00 00) +.data D_00003100 = bytearray ( + 46 00 61 00 69 00 6C 00 65 00 64 00 21 00 21 00 // F.a.i.l.e.d.!.!. + 00 00) diff --git a/mono/tests/tailcall/coreclr/JIT/Directed/IL/Tailcall/JitTailcall1.il b/mono/tests/tailcall/coreclr/JIT/Directed/IL/Tailcall/JitTailcall1.il new file mode 100644 index 0000000000..1a8857c578 --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Directed/IL/Tailcall/JitTailcall1.il @@ -0,0 +1,69 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } + +.assembly jittailcall1 +{ +} +.class EvenOdd +{ .method static bool IsEven(int32 N) + { .maxstack 2 + ldarg.0 // N + ldc.i4.0 + bne.un NonZero + ldc.i4.1 + ret +NonZero: + ldarg.0 + ldc.i4.1 + sub + tail. call bool EvenOdd::IsOdd(int32) + ret + } // end of method 'EvenOdd::IsEven' + + .method static bool IsOdd(int32 N) + { .maxstack 2 + ldarg N + ldc.i4.0 + bne.un NonZero + ldc.i4.0 + ret +NonZero: + ldarg N + ldc.i4.1 + sub + tail. call bool EvenOdd::IsEven(int32) + ret + } // end of method 'EvenOdd::IsOdd' + + .method static void Test(int32 N) + { .maxstack 1 + ldarg N + call void [mscorlib]System.Console::Write(int32) + ldstr " is " + call void [mscorlib]System.Console::Write(class [mscorlib]System.String) + ldarg N + call bool EvenOdd::IsEven(int32) + brfalse LoadOdd + ldstr "even" +Print: + tail. call void [mscorlib]System.Console::WriteLine(class [mscorlib]System.String) + ret +LoadOdd: + ldstr "odd" + br Print + } // end of method 'EvenOdd::Test' + +//Global method + +.method public static int32 main() +{ .entrypoint + .maxstack 1 + ldc.i4.5 + call void EvenOdd::Test(int32) + ldc.i4 0x64 + ret +} // end of global method 'main' +} // end of class 'EvenOdd' diff --git a/mono/tests/tailcall/coreclr/JIT/Directed/IL/Tailcall/Jittailcall2.il b/mono/tests/tailcall/coreclr/JIT/Directed/IL/Tailcall/Jittailcall2.il new file mode 100644 index 0000000000..30581b96b5 --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Directed/IL/Tailcall/Jittailcall2.il @@ -0,0 +1,236 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib {} + +.assembly 'aaa'// as "aaa.exe" +{ +} + +.namespace DefaultNamespace +{ + .class auto ansi dotailcall extends [mscorlib]System.Object + { + .field private static int32 ifoo + .field private static int32 iboo + .field private static int32 igoo + .method public instance int32 foo(int32 i, + float32 f, + wchar c) il managed + { + // Code size 45 (0x2d) + .maxstack 6 + .locals (float32 V_0, + int64 V_1, + int16 V_2, + int16 V_3) + IL_0000: ldsfld int32 DefaultNamespace.dotailcall::ifoo + IL_0005: ldc.i4.1 + IL_0006: add + IL_0007: stsfld int32 DefaultNamespace.dotailcall::ifoo + IL_000c: ldarg.2 + IL_000d: stloc.0 + IL_000e: ldarg.2 + IL_000f: conv.i8 + IL_0010: stloc.1 + IL_0011: ldarg.3 + IL_0012: conv.i2 + IL_0013: stloc.2 + IL_0014: ldarg.3 + IL_0015: conv.i2 + IL_0016: stloc.3 + IL_0017: ldarg.1 + IL_0018: ldc.i4.0 + IL_0019: bne.un.s IL_001d + + IL_001b: ldc.i4.0 + IL_001c: ret + + IL_001d: ldarg.0 + IL_001e: ldarg.1 + IL_001f: ldc.i4.1 + IL_0020: sub + IL_0021: ldloc.0 + IL_0022: ldloc.1 + IL_0023: ldloc.2 + IL_0024: ldloc.3 + IL_0025: tail. call instance int32 DefaultNamespace.dotailcall::boo(int32, + float32, + int64, + int16, + int16) +// IL_002a: pop +// IL_002b: ldc.i4.1 + IL_002c: ret + } // end of method 'dotailcall::foo' + + .method public instance int32 boo(int32 i, + float32 d, + int64 l, + int16 s, + int16 v16) il managed + { + // Code size 66 (0x42) + .maxstack 5 + .locals (class [mscorlib]System.Object V_0, + bool V_1, + class [mscorlib]System.String V_2) + IL_0000: ldsfld int32 DefaultNamespace.dotailcall::iboo + IL_0005: ldc.i4.1 + IL_0006: add + IL_0007: stsfld int32 DefaultNamespace.dotailcall::iboo + IL_000c: newobj instance void [mscorlib]System.Object::.ctor() + IL_0011: stloc.0 + IL_0012: ldarg.s d + IL_0014: box [mscorlib]System.Single + IL_0019: stloc.0 + IL_001a: ldarg.s v16 + IL_001c: ldc.i4.0 + IL_001d: beq.s IL_0023 + + IL_001f: ldc.i4.1 + IL_0020: stloc.1 + IL_0021: br.s IL_0025 + + IL_0023: ldc.i4.0 + IL_0024: stloc.1 + IL_0025: ldarga.s s + IL_0027: call instance class [mscorlib]System.String [mscorlib]System.Int16::ToString() + IL_002c: stloc.2 + IL_002d: ldarg.1 + IL_002e: ldc.i4.0 + IL_002f: bne.un.s IL_0033 + + IL_0031: ldc.i4.0 + IL_0032: ret + + IL_0033: ldarg.0 + IL_0034: ldarg.1 + IL_0035: ldc.i4.1 + IL_0036: sub + IL_0037: ldloc.0 + IL_0038: ldloc.2 + IL_0039: ldloc.1 + IL_003a: tail. call instance int32 DefaultNamespace.dotailcall::goo(int32, + class [mscorlib]System.Object, + class [mscorlib]System.String, + bool) +// IL_003f: pop +// IL_0040: ldc.i4.1 + IL_0041: ret + } // end of method 'dotailcall::boo' + + .method public instance int32 goo(int32 i, + class [mscorlib]System.Object v, + class [mscorlib]System.String str, + bool b) il managed + { + // Code size 41 (0x29) + .maxstack 4 + .locals (float32 V_0, + wchar V_1) + IL_0000: ldsfld int32 DefaultNamespace.dotailcall::igoo + IL_0005: ldc.i4.1 + IL_0006: add + IL_0007: stsfld int32 DefaultNamespace.dotailcall::igoo + IL_000c: ldarg.2 + IL_000d: unbox [mscorlib]System.Single + IL_0012: ldind.r4 + IL_0013: stloc.0 + IL_0014: ldarg.1 + IL_0015: conv.u2 + IL_0016: stloc.1 + IL_0017: ldarg.1 + IL_0018: ldc.i4.0 + IL_0019: bne.un.s IL_001d + + IL_001b: ldc.i4.0 + IL_001c: ret + + IL_001d: ldarg.0 + IL_001e: ldarg.1 + IL_001f: ldc.i4.1 + IL_0020: sub + IL_0021: ldloc.0 + IL_0022: ldloc.1 + IL_0023: tail. call instance int32 DefaultNamespace.dotailcall::foo(int32, + float32, + wchar) + IL_0028: ret + } // end of method 'dotailcall::goo' + + .method public static int32 Main(class [mscorlib]System.String[] Args) il managed + { + .entrypoint + // Code size 117 (0x75) + .maxstack 4 + .locals (int32 V_0, + float32 V_1, + wchar V_2, + class DefaultNamespace.dotailcall V_3) + IL_0000: ldc.i4 10000 + IL_0005: stloc.0 + IL_0006: ldc.r4 (CD FC F9 44) + IL_000b: stloc.1 + IL_000c: ldc.i4.s 10 + IL_000e: stloc.2 + IL_000f: newobj instance void DefaultNamespace.dotailcall::.ctor() + IL_0014: stloc.3 + IL_0015: ldloc.3 + IL_0016: ldloc.0 + IL_0017: ldloc.1 + IL_0018: ldloc.2 + IL_0019: call instance int32 DefaultNamespace.dotailcall::foo(int32, + float32, + wchar) + IL_001e: pop + IL_001f: ldstr "How many times foo() was called: " + IL_0024: ldsfld int32 DefaultNamespace.dotailcall::ifoo + IL_0029: box [mscorlib]System.Int32 + IL_002e: call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.Object, + class [mscorlib]System.Object) + IL_0033: call void [mscorlib]System.Console::WriteLine(class [mscorlib]System.String) + IL_0038: ldstr "How many times boo() was called: " + IL_003d: ldsfld int32 DefaultNamespace.dotailcall::iboo + IL_0042: box [mscorlib]System.Int32 + IL_0047: call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.Object, + class [mscorlib]System.Object) + IL_004c: call void [mscorlib]System.Console::WriteLine(class [mscorlib]System.String) + IL_0051: ldstr "How many times goo() was called: " + IL_0056: ldsfld int32 DefaultNamespace.dotailcall::igoo + IL_005b: box [mscorlib]System.Int32 + IL_0060: call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.Object, + class [mscorlib]System.Object) + IL_0065: call void [mscorlib]System.Console::WriteLine(class [mscorlib]System.String) + IL_006a: ldstr "Passed" + IL_006f: call void [mscorlib]System.Console::WriteLine(class [mscorlib]System.String) + IL_0074: ldc.i4 0x64 + IL_0079: ret + } // end of method 'dotailcall::Main' + + .method public specialname rtspecialname static void .cctor() il managed + { + // Code size 19 (0x13) + .maxstack 8 + IL_0000: ldc.i4.0 + IL_0001: stsfld int32 DefaultNamespace.dotailcall::ifoo + IL_0006: ldc.i4.0 + IL_0007: stsfld int32 DefaultNamespace.dotailcall::iboo + IL_000c: ldc.i4.0 + IL_000d: stsfld int32 DefaultNamespace.dotailcall::igoo + IL_0012: ret + } // end of method 'dotailcall::.cctor' + + .method public specialname rtspecialname instance void .ctor() il managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method 'dotailcall::.ctor' + + } // end of class 'dotailcall' + +} // end of namespace 'DefaultNamespace' diff --git a/mono/tests/tailcall/coreclr/JIT/Directed/IL/mutualrecur-tailcall/MutualRecur-TailCall.il.REMOVED.git-id b/mono/tests/tailcall/coreclr/JIT/Directed/IL/mutualrecur-tailcall/MutualRecur-TailCall.il.REMOVED.git-id new file mode 100644 index 0000000000..1121872110 --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Directed/IL/mutualrecur-tailcall/MutualRecur-TailCall.il.REMOVED.git-id @@ -0,0 +1 @@ +744c781ef9da279713b7da20d9996bc9f35869c1 \ No newline at end of file diff --git a/mono/tests/tailcall/coreclr/JIT/Directed/coverage/importer/Desktop/badtailcall.il b/mono/tests/tailcall/coreclr/JIT/Directed/coverage/importer/Desktop/badtailcall.il new file mode 100644 index 0000000000..bfbc962a7b --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Directed/coverage/importer/Desktop/badtailcall.il @@ -0,0 +1,32 @@ +.assembly extern mscorlib {} +.assembly badtailcall { } +.method public static int32 f() +{ +ldc.i4 100 +ret +} +.method public static int32 f0() +{ +ldc.i4 1 +tail. call int32 f() +ret +} +.method public static int32 Main() +{ +.entrypoint +.try +{ +call int32 f() +leave.s FAIL +} +catch [mscorlib]System.Security.VerificationException +{ +leave.s PASS +} +FAIL: +ldc.i4 100 +ret +PASS: +ldc.i4 100 +ret +} diff --git a/mono/tests/tailcall/coreclr/JIT/Directed/coverage/importer/badtailcall.il b/mono/tests/tailcall/coreclr/JIT/Directed/coverage/importer/badtailcall.il new file mode 100644 index 0000000000..5bc15c421d --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Directed/coverage/importer/badtailcall.il @@ -0,0 +1,37 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly badtailcall {} +.assembly extern mscorlib { } + +.method public static int32 f() +{ +ldc.i4 100 +ret +} +.method public static int32 f0() +{ +ldc.i4 1 +tail. call int32 f() +ret +} +.method public static int32 Main() +{ +.entrypoint +.try +{ +call int32 f() +leave.s FAIL +} +catch [mscorlib]System.Security.VerificationException +{ +leave.s PASS +} +FAIL: +ldc.i4 100 +ret +PASS: +ldc.i4 100 +ret +} diff --git a/mono/tests/tailcall/coreclr/JIT/Directed/pinvoke/tail.il b/mono/tests/tailcall/coreclr/JIT/Directed/pinvoke/tail.il new file mode 100644 index 0000000000..b40faa1062 --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Directed/pinvoke/tail.il @@ -0,0 +1,219 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly menus { } +.namespace JitTest +{ + .class private auto ansi beforefieldinit Test + extends [mscorlib]System.Object + { + .method private hidebysig static pinvokeimpl("user32" ansi winapi) + native uint CreatePopupMenu() cil managed preservesig + { + } + .method private hidebysig static pinvokeimpl("user32" ansi winapi) + bool DestroyMenu(native uint hMenu) cil managed preservesig + { + } + .method private hidebysig static pinvokeimpl("user32" ansi winapi) + bool AppendMenu(native uint hMenu, + unsigned int32 uFlags, + unsigned int32 uID, + string item) cil managed preservesig + { + } + .method private hidebysig static pinvokeimpl("user32" ansi winapi) + int32 GetMenuString(native uint hMenu, + unsigned int32 uIDItem, + class [mscorlib]System.Text.StringBuilder data, + int32 nMaxCount, + unsigned int32 uFlag) cil managed preservesig + { + } + + .method private hidebysig static native uint __CreatePopupMenu() cil managed + { + tail. call native uint JitTest.Test::CreatePopupMenu() + ret + } + .method private hidebysig static bool __DestroyMenu(native uint hMenu) cil managed + { + ldarg.0 + ldftn bool JitTest.Test::DestroyMenu(native uint) + tail. calli bool(native uint) + ret + } + .method private hidebysig static bool __AppendMenu(native uint hMenu, + unsigned int32 uFlags, + unsigned int32 uID, + string item) cil managed + { + .locals (bool) + .try { + ldarg.0 + ldarg.1 + ldarg.2 + ldarg.3 + call bool JitTest.Test::AppendMenu(native uint, + unsigned int32, + unsigned int32, + string) + stloc.0 + leave.s IL_END + } + catch [mscorlib]System.Exception + { + ldc.i4.0 + stloc.0 + leave.s IL_END + } + IL_END: + ldloc.0 + ret + } + .method private hidebysig static int32 __GetMenuString(native uint hMenu, + unsigned int32 uIDItem, + class [mscorlib]System.Text.StringBuilder data, + int32 nMaxCount, + unsigned int32 uFlag) cil managed + { + ldarga.s 0 + pop + jmp int32 JitTest.Test::GetMenuString(native uint, + unsigned int32, + class [mscorlib]System.Text.StringBuilder, + int32, + unsigned int32) + } + + .method private hidebysig static int32 + Main() cil managed + { + .entrypoint + .maxstack 5 + .locals (native uint V_0, + unsigned int32 V_1, + class [mscorlib]System.Text.StringBuilder V_2, + int32 V_3) + IL_0000: call native uint JitTest.Test::__CreatePopupMenu() + IL_0005: stloc.0 + IL_0006: ldloc.0 + IL_0007: brtrue.s IL_001b + + IL_0009: ldstr "CreatePopupMenu failed" + IL_000e: call void [mscorlib]System.Console::WriteLine(string) + IL_0013: ldc.i4.s 101 + IL_0015: stloc.3 + IL_0016: br IL_00af + + .try + { + IL_001b: ldc.i4.0 + IL_001c: stloc.1 + IL_001d: br.s IL_003c + + IL_001f: ldloc.0 + IL_0020: ldc.i4.0 + IL_0021: ldloc.1 + IL_0022: ldc.i4.1 + IL_0023: add + IL_0024: ldloca.s V_1 + IL_0026: call instance string [mscorlib]System.UInt32::ToString() + IL_002b: call bool JitTest.Test::__AppendMenu(native uint, + unsigned int32, + unsigned int32, + string) + IL_0030: brtrue.s IL_0038 + + IL_0032: newobj instance void [mscorlib]System.Exception::.ctor() + IL_0037: throw + + IL_0038: ldloc.1 + IL_0039: ldc.i4.1 + IL_003a: add + IL_003b: stloc.1 + IL_003c: ldloc.1 + IL_003d: ldc.i4.s 30 + IL_003f: blt.un.s IL_001f + + IL_0041: ldloc.1 + IL_0042: ldc.i4.1 + IL_0043: sub + IL_0044: stloc.1 + IL_0045: br.s IL_008a + + IL_0047: ldc.i4 0x3e8 + IL_004c: newobj instance void [mscorlib]System.Text.StringBuilder::.ctor(int32) + IL_0051: stloc.2 + IL_0052: ldloc.0 + IL_0053: ldloc.1 + IL_0054: ldloc.2 + IL_0055: ldc.i4 0x3e7 + IL_005a: ldc.i4 0x400 + IL_005f: call int32 JitTest.Test::__GetMenuString(native uint, + unsigned int32, + class [mscorlib]System.Text.StringBuilder, + int32, + unsigned int32) + IL_0064: brtrue.s IL_006c + + IL_0066: newobj instance void [mscorlib]System.Exception::.ctor() + IL_006b: throw + + IL_006c: ldloc.2 + IL_006d: callvirt instance string [mscorlib]System.Text.StringBuilder::ToString() + IL_0072: ldloca.s V_1 + IL_0074: call instance string [mscorlib]System.UInt32::ToString() + IL_0079: call bool [mscorlib]System.String::op_Inequality(string, + string) + IL_007e: brfalse.s IL_0086 + + IL_0080: newobj instance void [mscorlib]System.Exception::.ctor() + IL_0085: throw + + IL_0086: ldloc.1 + IL_0087: ldc.i4.1 + IL_0088: sub + IL_0089: stloc.1 + IL_008a: ldloc.1 + IL_008b: ldc.i4.s 30 + IL_008d: blt.un.s IL_0047 + + IL_008f: leave.s IL_00a0 + + } // end .try + finally + { + IL_0091: ldloc.0 + IL_0092: call bool JitTest.Test::__DestroyMenu(native uint) + IL_0097: brtrue.s IL_009f + + IL_0099: newobj instance void [mscorlib]System.Exception::.ctor() + IL_009e: throw + + IL_009f: endfinally + } // end handler + IL_00a0: ldstr "=== PASSED ===" + IL_00a5: call void [mscorlib]System.Console::WriteLine(string) + IL_00aa: ldc.i4.s 100 + IL_00ac: stloc.3 + IL_00ad: br.s IL_00af + + IL_00af: ldloc.3 + IL_00b0: ret + } // end of method Test::Main + + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method Test::.ctor + + } // end of class Test + +} // end of namespace JitTest diff --git a/mono/tests/tailcall/coreclr/JIT/Directed/tailcall/tailcall.il b/mono/tests/tailcall/coreclr/JIT/Directed/tailcall/tailcall.il new file mode 100644 index 0000000000..7b87620a3b --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Directed/tailcall/tailcall.il @@ -0,0 +1,316 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + + +.assembly extern mscorlib { } + +.assembly tailcall { } + +.class interface private abstract auto ansi IFace1 +{ + .method public hidebysig newslot abstract virtual + instance int32 Recurse3(int32 depth) cil managed + { + } + + .method public hidebysig newslot abstract virtual + instance int32 Recurse4(int32 depth, + object o1, + object o2) cil managed + { + } + +} + +.class public auto ansi beforefieldinit Class1 + extends [mscorlib]System.Object + implements IFace1 +{ + .field private static int32 MaxDepth + .field private static int32 Expected + .field private int32 'value' + .method public hidebysig instance int32 + Recurse1(int32 depth) cil managed + { + .maxstack 5 + IL_0000: ldarg.1 + IL_0001: brtrue.s IL_000a + + IL_0003: ldarg.0 + IL_0004: ldfld int32 Class1::'value' + IL_0009: ret + + IL_000a: ldarg.0 + IL_000b: dup + IL_000c: ldfld int32 Class1::'value' + IL_0011: ldarg.1 + IL_0012: add + IL_0013: stfld int32 Class1::'value' + IL_0018: ldarg.1 + IL_0019: ldc.i4 0x80 + IL_001e: rem + IL_001f: ldc.i4.s 43 + IL_0021: bne.un.s IL_002d + + IL_0023: ldarg.0 + IL_0024: ldarg.1 + IL_0025: ldc.i4.1 + IL_0026: sub + IL_0027: tail. callvirt instance int32 Class1::Recurse3(int32) + IL_002c: ret + + IL_002d: ldarg.0 + IL_002e: ldarg.1 + IL_002f: ldc.i4.1 + IL_0030: sub + IL_0031: ldarg.1 + IL_0032: box [mscorlib]System.Int32 + IL_0037: ldarg.1 + IL_0038: ldc.i4.1 + IL_0039: add + IL_003a: box [mscorlib]System.Int32 + IL_003f: tail. call instance int32 Class1::Recurse2(int32, + object, + object) + IL_0044: ret + } + + .method public hidebysig instance int32 + Recurse2(int32 depth, + object o1, + object o2) cil managed + { + .maxstack 4 + .locals init (string V_0) + IL_0000: ldarg.1 + IL_0001: brtrue.s IL_000a + + IL_0003: ldarg.0 + IL_0004: ldfld int32 Class1::'value' + IL_0009: ret + + IL_000a: ldarg.1 + IL_000b: ldsfld int32 Class1::MaxDepth + IL_0010: ldc.i4.s 10 + IL_0012: div + IL_0013: rem + IL_0014: ldc.i4.s 100 + IL_0016: bne.un.s IL_0051 + + IL_0018: call string [mscorlib]System.Environment::get_StackTrace() + IL_001d: stloc.0 + IL_001e: ldloc.0 + IL_001f: ldstr "Main" + IL_0024: callvirt instance int32 [mscorlib]System.String::IndexOf(string) + IL_0029: ldc.i4.m1 + IL_002a: bne.un.s IL_004c + + IL_002c: ldstr "Unexpected stack trace: " + IL_0031: ldloc.0 + IL_0032: call string [mscorlib]System.String::Concat(string, + string) + IL_0037: call void [mscorlib]System.Console::WriteLine(string) + IL_003c: ldstr "Test Failed" + IL_0041: call void [mscorlib]System.Console::WriteLine(string) + IL_0046: ldc.i4.0 + IL_0047: call void [mscorlib]System.Environment::Exit(int32) + IL_004c: call void [mscorlib]System.GC::Collect() + IL_0051: ldarg.0 + IL_0052: dup + IL_0053: ldfld int32 Class1::'value' + IL_0058: ldarg.2 + IL_0059: unbox [mscorlib]System.Int32 + IL_005e: ldind.i4 + IL_005f: ldarg.3 + IL_0060: unbox [mscorlib]System.Int32 + IL_0065: ldind.i4 + IL_0066: add + IL_0067: add + IL_0068: stfld int32 Class1::'value' + IL_006d: ldarg.0 + IL_006e: ldarg.1 + IL_006f: ldc.i4.1 + IL_0070: sub + IL_0071: tail. callvirt instance int32 IFace1::Recurse3(int32) + IL_0076: ret + } + + .method public hidebysig newslot virtual + instance int32 Recurse3(int32 depth) cil managed + { + .maxstack 8 + IL_0000: ldarg.1 + IL_0001: brtrue.s IL_000a + + IL_0003: ldarg.0 + IL_0004: ldfld int32 Class1::'value' + IL_0009: ret + + IL_000a: ldarg.1 + IL_000b: ldc.i4 0x80 + IL_0010: rem + IL_0011: ldc.i4.s 21 + IL_0013: bne.un.s IL_001f + + IL_0015: ldarg.0 + IL_0016: ldarg.1 + IL_0017: ldc.i4.1 + IL_0018: sub + IL_0019: tail. call instance int32 Class1::Recurse1(int32) + IL_001e: ret + + IL_001f: ldarg.0 + IL_0020: ldarg.1 + IL_0021: ldc.i4.1 + IL_0022: sub + IL_0023: ldarg.1 + IL_0024: ldc.i4.1 + IL_0025: add + IL_0026: box [mscorlib]System.Int32 + IL_002b: ldarg.1 + IL_002c: ldc.i4.2 + IL_002d: add + IL_002e: box [mscorlib]System.Int32 + IL_0033: tail. callvirt instance int32 IFace1::Recurse4(int32, + object, + object) + IL_0038: ret + } + + .method public hidebysig newslot virtual + instance int32 Recurse4(int32 depth, + object o1, + object o2) cil managed + { + .maxstack 4 + .locals init (string V_0) + IL_0000: ldarg.1 + IL_0001: brtrue.s IL_000a + + IL_0003: ldarg.0 + IL_0004: ldfld int32 Class1::'value' + IL_0009: ret + + IL_000a: ldarg.1 + IL_000b: ldsfld int32 Class1::MaxDepth + IL_0010: ldc.i4.s 10 + IL_0012: div + IL_0013: rem + IL_0014: ldc.i4 0xc8 + IL_0019: bne.un.s IL_0054 + + IL_001b: call void [mscorlib]System.GC::Collect() + IL_0020: call string [mscorlib]System.Environment::get_StackTrace() + IL_0025: stloc.0 + IL_0026: ldloc.0 + IL_0027: ldstr "Main" + IL_002c: callvirt instance int32 [mscorlib]System.String::IndexOf(string) + IL_0031: ldc.i4.m1 + IL_0032: bne.un.s IL_0054 + + IL_0034: ldstr "Unexpected stack trace: " + IL_0039: ldloc.0 + IL_003a: call string [mscorlib]System.String::Concat(string, + string) + IL_003f: call void [mscorlib]System.Console::WriteLine(string) + IL_0044: ldstr "Test Failed" + IL_0049: call void [mscorlib]System.Console::WriteLine(string) + IL_004e: ldc.i4.0 + IL_004f: call void [mscorlib]System.Environment::Exit(int32) + IL_0054: ldarg.0 + IL_0055: dup + IL_0056: ldfld int32 Class1::'value' + IL_005b: ldarg.2 + IL_005c: unbox [mscorlib]System.Int32 + IL_0061: ldind.i4 + IL_0062: ldarg.3 + IL_0063: unbox [mscorlib]System.Int32 + IL_0068: ldind.i4 + IL_0069: add + IL_006a: add + IL_006b: stfld int32 Class1::'value' + IL_0070: ldarg.0 + IL_0071: ldarg.1 + IL_0072: ldc.i4.1 + IL_0073: sub + IL_0074: tail. call instance int32 Class1::Recurse1(int32) + IL_0079: ret + } + + .method public hidebysig static int32 Main() cil managed + { + .entrypoint + .maxstack 3 + .locals init (class Class1 V_0, + object[] V_1) + IL_0000: ldstr "Test Start" + IL_0005: call void [mscorlib]System.Console::WriteLine(string) + IL_000a: newobj instance void Class1::.ctor() + IL_000f: stloc.0 + IL_0010: ldloc.0 + IL_0011: ldsfld int32 Class1::MaxDepth + IL_0016: callvirt instance int32 Class1::Recurse1(int32) + IL_001b: pop + IL_001c: ldloc.0 + IL_001d: ldfld int32 Class1::'value' + IL_0022: ldsfld int32 Class1::Expected + IL_0027: beq.s IL_006e + + IL_0029: ldc.i4.4 + IL_002a: newarr [mscorlib]System.Object + IL_002f: stloc.1 + IL_0030: ldloc.1 + IL_0031: ldc.i4.0 + IL_0032: ldstr "Expected result: " + IL_0037: stelem.ref + IL_0038: ldloc.1 + IL_0039: ldc.i4.1 + IL_003a: ldc.i4.1 + IL_003b: box [mscorlib]System.Int32 + IL_0040: stelem.ref + IL_0041: ldloc.1 + IL_0042: ldc.i4.2 + IL_0043: ldstr " Actual result: " + IL_0048: stelem.ref + IL_0049: ldloc.1 + IL_004a: ldc.i4.3 + IL_004b: ldloc.0 + IL_004c: ldfld int32 Class1::'value' + IL_0051: box [mscorlib]System.Int32 + IL_0056: stelem.ref + IL_0057: ldloc.1 + IL_0058: call string [mscorlib]System.String::Concat(object[]) + IL_005d: call void [mscorlib]System.Console::WriteLine(string) + IL_0062: ldstr "Test Failed" + IL_0067: call void [mscorlib]System.Console::WriteLine(string) + IL_006c: ldc.i4.0 + IL_006d: ret + + IL_006e: ldstr "Test SUCCESS" + IL_0073: call void [mscorlib]System.Console::WriteLine(string) + IL_0078: ldc.i4.s 100 + IL_007a: ret + } + + .method private hidebysig specialname rtspecialname static + void .cctor() cil managed + { + .maxstack 8 + IL_0000: ldc.i4 0x100000 + IL_0005: stsfld int32 Class1::MaxDepth + IL_000a: ldc.i4 0x280000 + IL_000f: stsfld int32 Class1::Expected + IL_0014: ret + } + + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } + +} diff --git a/mono/tests/tailcall/coreclr/JIT/Directed/zeroinit/tail.il b/mono/tests/tailcall/coreclr/JIT/Directed/zeroinit/tail.il new file mode 100644 index 0000000000..28941324d9 --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Directed/zeroinit/tail.il @@ -0,0 +1,134 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly tail { } +.class private auto ansi beforefieldinit AA + extends [mscorlib]System.Object +{ + .method private hidebysig static void Callee1(int64& B) cil managed + { + // Code size 7 (0x7) + .maxstack 2 + .locals init (int64 V_0) + ldarg.0 + ldloca.s 0 + ldind.i8 + stind.i8 + ret + } // end of method AA::Callee1 + + .method private hidebysig static void Caller1(int64& A, + int64& B) cil managed + { + .maxstack 2 + .locals init (int64 V_0) + ldarg.0 + ldloca.s 0 + ldind.i8 + stind.i8 + ldarg.1 + tail. call void AA::Callee1(int64&) + ret + } // end of method AA::Caller1 + + .method private hidebysig static int64 + Callee2() cil managed + { + // Code size 9 (0x9) + .maxstack 1 + .locals init (int64 V_0) + ldloca.s 0 + ldind.i8 + ret + } // end of method AA::Callee2 + + .method private hidebysig static int64 + Caller2() cil managed + { + // Code size 15 (0xf) + .maxstack 2 + .locals init (int64 V_0) + ldloca.s 0 + ldind.i8 + brfalse.s IL_JMP + newobj instance void [mscorlib]System.Exception::.ctor() + throw + IL_JMP: + jmp int64 AA::Callee2() + } // end of method AA::Caller2 + + .method private hidebysig static int32 + Main() cil managed + { + .entrypoint + // Code size 81 (0x51) + .maxstack 2 + .locals init (int64 V_0, + int64 V_1, + int32 V_2) + IL_0000: ldc.i4.0 + IL_0001: conv.i8 + IL_0002: stloc.0 + IL_0003: ldc.i4.0 + IL_0004: conv.i8 + IL_0005: stloc.1 + IL_0006: ldloca.s V_0 + IL_0008: ldloca.s V_1 + IL_000a: call void AA::Caller1(int64&, + int64&) + IL_000f: ldloc.0 + IL_0010: ldc.i4.0 + IL_0011: conv.i8 + IL_0012: bne.un.s IL_0019 + + IL_0014: ldloc.1 + IL_0015: ldc.i4.0 + IL_0016: conv.i8 + IL_0017: beq.s IL_0028 + + IL_0019: ldstr "Error 101" + IL_001e: call void [mscorlib]System.Console::WriteLine(string) + IL_0023: ldc.i4.s 101 + IL_0025: stloc.2 + IL_0026: br.s IL_004f + + IL_0028: call int64 AA::Caller2() + IL_002d: ldc.i4.0 + IL_002e: conv.i8 + IL_002f: beq.s IL_0040 + + IL_0031: ldstr "Error 102" + IL_0036: call void [mscorlib]System.Console::WriteLine(string) + IL_003b: ldc.i4.s 102 + IL_003d: stloc.2 + IL_003e: br.s IL_004f + + IL_0040: ldstr "Passed" + IL_0045: call void [mscorlib]System.Console::WriteLine(string) + IL_004a: ldc.i4.s 100 + IL_004c: stloc.2 + IL_004d: br.s IL_004f + + IL_004f: ldloc.2 + IL_0050: ret + } // end of method AA::Main + + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method AA::.ctor + +} // end of class AA + + +// ============================================================= + +//*********** DISASSEMBLY COMPLETE *********************** +// WARNING: Created Win32 resource file tail.res diff --git a/mono/tests/tailcall/coreclr/JIT/IL_Conformance/Old/Base/tailcall.il b/mono/tests/tailcall/coreclr/JIT/IL_Conformance/Old/Base/tailcall.il new file mode 100644 index 0000000000..b270f7374b --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/IL_Conformance/Old/Base/tailcall.il @@ -0,0 +1,88 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } + +.assembly tailcall.exe { } + +.method public static int32 main(string[]) { +.locals (class [mscorlib]System.IO.TextWriter,class _tailcall) +.entrypoint + call class [mscorlib]System.IO.TextWriter [mscorlib]System.Console::get_Out() + stloc 0 + newobj instance void _tailcall::.ctor() + stloc 1 + + ldloc 1 + callvirt instance int32 _tailcall::method1() + + ldc.i4 0x1234 + bne.un fail + +pass: + ldloc 0 + ldstr "TAILCALL Tests PASS." + + + callvirt instance void [mscorlib]System.IO.TextWriter::WriteLine(string) + ldc.i4 100 + br end +fail: + ldloc 0 + ldstr "!!! FAILURE !!! - TAILCALL TESTS FAIL - !!! FAILURE !!!" + + + + + callvirt instance void [mscorlib]System.IO.TextWriter::WriteLine(string) + ldc.i4 0x0 + br end +end: + ret +} + + +.class public _tailcall { +.method public void .ctor() { + +.maxstack 10 + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + call class [mscorlib]System.IO.TextWriter [mscorlib]System.Console::get_Out() + ldstr "TAILCALL test initialized." + + + callvirt instance void [mscorlib]System.IO.TextWriter::WriteLine(string) + ret +} + +.method public int32 method1() { +.locals (int32,string) + + call class [mscorlib]System.IO.TextWriter [mscorlib]System.Console::get_Out() + ldstr "Beginning Test." + + + callvirt instance void [mscorlib]System.IO.TextWriter::WriteLine(string) + + ldarg 0 //this ptr + tail. + callvirt instance int32 _tailcall::method2() + ret + +} + +.method public int32 method2() { +.locals () + + call class [mscorlib]System.IO.TextWriter [mscorlib]System.Console::get_Out() + ldstr "Method2 has been called." + + + callvirt instance void [mscorlib]System.IO.TextWriter::WriteLine(string) + ldc.i4 0x1234 + ret //we should return from here to main. + +} +} diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/Boxing/boxunbox/tailcall.il b/mono/tests/tailcall/coreclr/JIT/Methodical/Boxing/boxunbox/tailcall.il new file mode 100644 index 0000000000..d7e8554e51 --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/Boxing/boxunbox/tailcall.il @@ -0,0 +1,209 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly 'tailcall' { } +.namespace JitTest +{ + .class private auto ansi beforefieldinit App + extends [mscorlib]System.Object + { + .method private hidebysig static int64 + Test(bool path) cil managed + { + .maxstack 4 + .locals (int32 V_0) + IL_0000: ldc.i4.s 100 + IL_0002: stloc.0 + IL_0003: ldloc.0 + ldarg.0 + brfalse IL_000f + IL_0004: box [mscorlib]System.Int32 + IL_0009: unbox [mscorlib]System.Int32 + IL_000e: ldind.i4 + IL_000f: conv.r4 + ldarg.0 + brfalse IL_01c8 + IL_0010: box [mscorlib]System.Single + IL_0015: unbox [mscorlib]System.Single + IL_001a: ldind.r4 + IL_001b: conv.i1 + IL_001c: box [mscorlib]System.SByte + ldarg.0 + brfalse IL_002c + IL_0021: unbox [mscorlib]System.SByte + IL_0026: ldind.i1 + IL_0027: box [mscorlib]System.SByte + IL_002c: unbox [mscorlib]System.SByte + IL_0031: ldind.i1 + IL_0032: conv.i4 + IL_0038: box [mscorlib]System.IntPtr + IL_003d: unbox [mscorlib]System.IntPtr + ldarg.0 + brfalse IL_00e0 + IL_0042: ldobj [mscorlib]System.IntPtr + IL_004c: conv.u1 + IL_004d: box [mscorlib]System.Byte + IL_0052: unbox [mscorlib]System.Byte + IL_0057: ldind.u1 + IL_0058: conv.i1 + IL_0059: box [mscorlib]System.SByte + IL_005e: unbox [mscorlib]System.SByte + IL_0063: ldind.i1 + IL_0064: conv.i8 + IL_0065: box [mscorlib]System.UInt64 + IL_006a: unbox [mscorlib]System.UInt64 + IL_006f: ldind.i8 + conv.i + IL_0075: box [mscorlib]System.IntPtr + IL_007a: unbox [mscorlib]System.IntPtr + IL_007f: ldobj [mscorlib]System.IntPtr + IL_0089: conv.u8 + ldarg.0 + brfalse IL_00c6 + IL_008a: box [mscorlib]System.UInt64 + IL_008f: unbox [mscorlib]System.UInt64 + IL_0094: ldind.i8 + IL_0095: conv.u1 + IL_0096: box [mscorlib]System.Byte + IL_009b: unbox [mscorlib]System.Byte + IL_00a0: ldind.u1 + IL_00a1: conv.u8 + IL_00a2: box [mscorlib]System.Int64 + IL_00a7: unbox [mscorlib]System.Int64 + IL_00ac: ldind.i8 + IL_00ad: conv.i1 + IL_00ae: box [mscorlib]System.SByte + IL_00b3: unbox [mscorlib]System.SByte + IL_00b8: ldind.i1 + IL_00b9: conv.u4 + IL_00ba: box [mscorlib]System.UInt32 + IL_00bf: unbox [mscorlib]System.UInt32 + IL_00c4: ldind.u4 + IL_00c5: conv.u8 + IL_00c6: box [mscorlib]System.Int64 + IL_00cb: unbox [mscorlib]System.Int64 + IL_00d0: ldind.i8 + conv.u + IL_00d6: box [mscorlib]System.UIntPtr + IL_00db: unbox [mscorlib]System.UIntPtr + IL_00e0: ldobj [mscorlib]System.UIntPtr + IL_00ea: conv.r.un + IL_00eb: conv.r4 + IL_00ec: box [mscorlib]System.Single + IL_00f1: unbox [mscorlib]System.Single + IL_00f6: ldind.r4 + IL_00f7: conv.i1 + IL_00f8: box [mscorlib]System.SByte + IL_00fd: unbox [mscorlib]System.SByte + IL_0102: ldind.i1 + IL_0103: box [mscorlib]System.SByte + IL_0108: unbox [mscorlib]System.SByte + IL_010d: ldind.i1 + IL_010e: conv.i4 + IL_0114: box [mscorlib]System.IntPtr + IL_0119: unbox [mscorlib]System.IntPtr + IL_011e: ldobj [mscorlib]System.IntPtr + IL_0128: conv.u1 + IL_0129: box [mscorlib]System.Byte + IL_012e: unbox [mscorlib]System.Byte + IL_0133: ldind.u1 + IL_0134: conv.i1 + IL_0135: box [mscorlib]System.SByte + IL_013a: unbox [mscorlib]System.SByte + IL_013f: ldind.i1 + IL_0140: conv.i8 + IL_0141: box [mscorlib]System.UInt64 + IL_0146: unbox [mscorlib]System.UInt64 + IL_014b: ldind.i8 + conv.i + IL_0151: box [mscorlib]System.IntPtr + IL_0156: unbox [mscorlib]System.IntPtr + IL_015b: ldobj [mscorlib]System.IntPtr + IL_0165: conv.u8 + IL_0166: box [mscorlib]System.UInt64 + IL_016b: unbox [mscorlib]System.UInt64 + IL_0170: ldind.i8 + IL_0171: conv.u1 + ldarg.0 + brfalse IL_018a + IL_0172: box [mscorlib]System.Byte + IL_0177: unbox [mscorlib]System.Byte + IL_017c: ldind.u1 + IL_017d: conv.u8 + IL_017e: box [mscorlib]System.Int64 + IL_0183: unbox [mscorlib]System.Int64 + IL_0188: ldind.i8 + IL_0189: conv.i1 + IL_018a: box [mscorlib]System.SByte + IL_018f: unbox [mscorlib]System.SByte + IL_0194: ldind.i1 + IL_0195: conv.u4 + IL_0196: box [mscorlib]System.UInt32 + IL_019b: unbox [mscorlib]System.UInt32 + IL_01a0: ldind.u4 + IL_01a1: conv.u8 + IL_01a2: box [mscorlib]System.Int64 + IL_01a7: unbox [mscorlib]System.Int64 + IL_01ac: ldind.i8 + conv.u + IL_01b2: box [mscorlib]System.UIntPtr + IL_01b7: unbox [mscorlib]System.UIntPtr + IL_01bc: ldobj [mscorlib]System.UIntPtr + IL_01c6: conv.r.un + IL_01c7: conv.r8 + IL_01c8: box [mscorlib]System.Double + IL_01cd: unbox [mscorlib]System.Double + IL_01d2: ldind.r8 + IL_01d3: ldc.r8 100. + IL_01dc: beq.s IL_END + + IL_01de: ldstr "Loss of precision or unbox error" + IL_01e3: newobj instance void [mscorlib]System.Exception::.ctor(string) + IL_01e8: throw + + IL_END: + ldc.i8 100 + ldarg.0 + brfalse.s IL_RET + pop + ldc.i4.0 + tail. call int64 JitTest.App::Test(bool) + IL_RET: ret + } // end of method App::Test + + .method private hidebysig static int32 + Main() cil managed + { + .entrypoint + .maxstack 4 + .locals (int32 V_0) + IL_0000: ldc.i4.0 + IL_0001: call int64 JitTest.App::Test(bool) + IL_0006: ldc.i4.1 + IL_0007: call int64 JitTest.App::Test(bool) + pop + pop + IL_000c: ldstr "=== TEST PASSED ===" + IL_0011: call void [mscorlib]System.Console::WriteLine(string) + IL_0016: ldc.i4.s 100 + IL_0018: stloc.0 + IL_0019: br.s IL_001b + + IL_001b: ldloc.0 + IL_001c: ret + } // end of method App::Main + + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method App::.ctor + + } // end of class App + +} // end of namespace JitTest diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/Boxing/misc/tailjump.il b/mono/tests/tailcall/coreclr/JIT/Methodical/Boxing/misc/tailjump.il new file mode 100644 index 0000000000..0e93d1d229 --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/Boxing/misc/tailjump.il @@ -0,0 +1,156 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly 'test' { } +.namespace BoxTest +{ + .class auto ansi Test extends [mscorlib]System.Object + { + .method family hidebysig instance class System.Object + Fibonacci(class System.Object num, + class System.Object flag) il managed + { + // Code size 48 (0x30) + .maxstack 8 + IL_0000: ldarg.2 + IL_0001: unbox [mscorlib]System.Boolean + IL_0006: ldind.i1 + IL_0007: brfalse.s IL_0012 + + IL_0009: ldarg.0 + IL_000a: ldarg.1 + IL_000b: ldarg.2 + IL_000c: tail. call instance class System.Object BoxTest.Test::Fibonacci2(class System.Object, + class System.Object) + IL_0011: ret + + IL_0012: ldarg.1 + IL_0013: unbox [mscorlib]System.Int32 + IL_0018: ldind.i4 + IL_0019: ldc.i4.2 + IL_001a: rem + IL_001b: ldc.i4.0 + IL_001c: bne.un.s IL_0027 + + jmp instance class System.Object BoxTest.Test::Fibonacci2(class System.Object, + class System.Object) + + IL_0027: + jmp instance class System.Object BoxTest.Test::Fibonacci2(class System.Object, + class System.Object) + } // end of method 'Test::Fibonacci' + + .method family hidebysig instance class System.Object + Fibonacci2(class System.Object num, + class System.Object flag) il managed + { + // Code size 129 (0x81) + .maxstack 4 + .locals ([0] int32 N, + [1] int32 V_1, + [2] bool V_2) + IL_0000: ldarg.1 + IL_0001: unbox [mscorlib]System.Int32 + IL_0006: ldind.i4 + IL_0007: ldc.i4.1 + IL_0008: bgt.s IL_0014 + + IL_000a: ldarg.1 + IL_000b: unbox [mscorlib]System.Int32 + IL_0010: ldind.i4 + IL_0011: stloc.0 + IL_0012: br.s IL_005a + + IL_0014: ldarg.0 + IL_0015: ldarg.1 + IL_0016: unbox [mscorlib]System.Int32 + IL_001b: ldind.i4 + IL_001c: ldc.i4.2 + IL_001d: sub + IL_001e: stloc.1 + IL_001f: ldloc.s V_1 + IL_0021: box[mscorlib]System.Int32 + IL_0026: ldc.i4.0 + IL_0027: stloc.2 + IL_0028: ldloc.s V_2 + IL_002a: box[mscorlib]System.Boolean + IL_002f: call instance class System.Object BoxTest.Test::Fibonacci(class System.Object, + class System.Object) + IL_0034: unbox [mscorlib]System.Int32 + IL_0039: ldind.i4 + IL_003a: ldarg.0 + IL_003b: ldarg.1 + IL_003c: unbox [mscorlib]System.Int32 + IL_0041: ldind.i4 + IL_0042: ldc.i4.1 + IL_0043: sub + IL_0044: stloc.1 + IL_0045: ldloc.s V_1 + IL_0047: box[mscorlib]System.Int32 + IL_004c: ldarg.2 + IL_004d: call instance class System.Object BoxTest.Test::Fibonacci(class System.Object, + class System.Object) + IL_0052: unbox [mscorlib]System.Int32 + IL_0057: ldind.i4 + IL_0058: add + IL_0059: stloc.0 + IL_005a: ldarg.2 + IL_005b: unbox [mscorlib]System.Boolean + IL_0060: ldind.i1 + IL_0061: brfalse.s IL_0079 + + IL_0063: ldloca.s N + IL_0065: call instance class System.String [mscorlib]System.Int32::ToString() + IL_006a: ldstr " " + IL_006f: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0074: call void [mscorlib]System.Console::Write(class System.String) + IL_0079: ldloc.s N + IL_007b: box[mscorlib]System.Int32 + IL_0080: ret + } // end of method 'Test::Fibonacci2' + + .method private hidebysig static int32 + Main() il managed + { + .entrypoint + // Code size 47 (0x2f) + .maxstack 3 + .locals ([0] int32 V_0, + [1] bool V_1) + IL_0000: newobj instance void BoxTest.Test::.ctor() + IL_0005: ldc.i4.s 20 + IL_0007: stloc.0 + IL_0008: ldloc.s V_0 + IL_000a: box[mscorlib]System.Int32 + IL_000f: ldc.i4.1 + IL_0010: stloc.1 + IL_0011: ldloc.s V_1 + IL_0013: box[mscorlib]System.Boolean + IL_0018: call instance class System.Object BoxTest.Test::Fibonacci(class System.Object, + class System.Object) + IL_001d: pop + IL_001e: call void [mscorlib]System.Console::WriteLine() + IL_0023: ldstr "*** PASSED ***" + IL_0028: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_002d: ldc.i4 0x64 + IL_002e: ret + } // end of method 'Test::Main' + + .method public hidebysig specialname rtspecialname + instance void .ctor() il managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method 'Test::.ctor' + + } // end of class 'Test' + +} // end of namespace 'BoxTest' + +//*********** DISASSEMBLY COMPLETE *********************** diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/Invoke/SEH/catchfault_tail.il b/mono/tests/tailcall/coreclr/JIT/Methodical/Invoke/SEH/catchfault_tail.il new file mode 100644 index 0000000000..ca8a70943e --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/Invoke/SEH/catchfault_tail.il @@ -0,0 +1,257 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + + +.assembly extern mscorlib { } + +.assembly 'catchfault_tail'// as "catchfault_tail" +{ +} + +.namespace JitTest +{ + .class private auto ansi Test1 + extends ['mscorlib']System.Object + { + .field private static bool globalFlag + .field private static bool globalFlag2 + .method private hidebysig static bool + TestTryCatch(int32 recurseLevel) il managed + { + // Code size 72 (0x48) + .maxstack 3 + .locals (int32[] V_0, + bool V_1) + IL_0000: ldarg.0 + IL_0001: ldc.i4.1 + IL_0002: ble.s IL_003f + + .try + { + IL_0004: ldsfld bool JitTest.Test1::globalFlag + IL_0009: ldc.i4.0 + IL_000a: ceq + IL_000c: dup + IL_000d: stsfld bool JitTest.Test1::globalFlag + IL_0012: brfalse.s IL_001f + + IL_0014: ldarg.0 + IL_0015: ldc.i4.2 + IL_0016: sub + IL_0017: call bool JitTest.Test1::TestTryCatch(int32) + IL_001c: stloc.1 + IL_001d: leave.s IL_0046 + + IL_001f: ldnull + IL_0020: stloc.0 + IL_0021: ldloc.0 + IL_0022: ldc.i4.0 + IL_0023: ldc.i4.0 + IL_0024: stelem.i4 + IL_0025: ldstr "Shouldn't have reached here." + IL_002a: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_002f: newobj instance void ['mscorlib']System.Exception::.ctor() + IL_0034: throw + + } // end .try + catch ['mscorlib']System.NullReferenceException + { + IL_0035: pop + IL_0036: ldarg.0 + IL_0037: call bool JitTest.Test1::Test(int32) + IL_003c: stloc.1 + IL_003d: leave.s IL_0046 + + } // end handler + IL_003f: ldarg.0 + IL_0040: ldc.i4.0 + IL_0041: ceq + IL_0043: stloc.1 + IL_0044: br.s IL_0046 + + IL_0046: ldloc.1 + IL_0047: ret + } // end of method 'Test1::TestTryCatch' + + .method private hidebysig static bool + TestTryFinally(int32 recurseLevel) il managed + { + // Code size 79 (0x4f) + .maxstack 3 + .locals (bool V_0, + int32[] V_1, + bool V_2) + IL_0000: ldarg.0 + IL_0001: ldc.i4.1 + IL_0002: ble.s IL_0046 + + IL_0004: ldc.i4.0 + IL_0005: stloc.0 + .try + { + .try + { + IL_0006: ldsfld bool JitTest.Test1::globalFlag + IL_000b: ldc.i4.0 + IL_000c: ceq + IL_000e: dup + IL_000f: stsfld bool JitTest.Test1::globalFlag + IL_0014: brfalse.s IL_0021 + + IL_0016: ldarg.0 + IL_0017: ldc.i4.2 + IL_0018: sub + IL_0019: call bool JitTest.Test1::TestTryCatch(int32) + IL_001e: stloc.2 + IL_001f: leave.s IL_004d + + IL_0021: ldnull + IL_0022: stloc.1 + IL_0023: ldloc.1 + IL_0024: ldc.i4.0 + IL_0025: ldc.i4.0 + IL_0026: stelem.i4 + IL_0027: ldstr "Shouldn't have reached here." + IL_002c: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_0031: newobj instance void ['mscorlib']System.Exception::.ctor() + IL_0036: throw + + } // end .try + fault + { + IL_0037: ldarg.0 + IL_0038: call bool JitTest.Test1::Test(int32) + IL_003d: stloc.0 + IL_003e: endfinally + } // end handler + } // end .try + catch ['mscorlib']System.NullReferenceException + { + IL_003f: pop + IL_0040: leave.s IL_0042 + + } // end handler + IL_0042: ldloc.0 + IL_0043: stloc.2 + IL_0044: br.s IL_004d + + IL_0046: ldarg.0 + IL_0047: ldc.i4.0 + IL_0048: ceq + IL_004a: stloc.2 + IL_004b: br.s IL_004d + + IL_004d: ldloc.2 + IL_004e: ret + } // end of method 'Test1::TestTryFinally' + + .method private hidebysig static bool + Test(int32 recurseLevel) il managed + { + // Code size 36 (0x24) + .maxstack 2 + .locals (bool V_0) + IL_0000: ldsfld bool JitTest.Test1::globalFlag2 + IL_0005: ldc.i4.0 + IL_0006: ceq + IL_0008: dup + IL_0009: stsfld bool JitTest.Test1::globalFlag2 + IL_000e: brfalse.s IL_0019 + + ldarg.0 + tail. call bool JitTest.Test1::TestTryCatch(int32) + ret + + IL_0019: ldarg.0 + tail. call bool JitTest.Test1::TestTryFinally(int32) + ret + } // end of method 'Test1::Test' + + .method private hidebysig static int32 + Main() il managed + { + .entrypoint + // Code size 97 (0x61) + .maxstack 1 + .locals (int32 V_0) + .try + { + IL_0000: ldc.i4.s 15 + IL_0002: call bool JitTest.Test1::TestTryCatch(int32) + IL_0007: brtrue.s IL_0012 + + IL_0009: ldc.i4.s 18 + IL_000b: call bool JitTest.Test1::TestTryCatch(int32) + IL_0010: brtrue.s IL_0020 + + IL_0012: ldstr "try...catch test failed." + IL_0017: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_001c: ldc.i4.1 + IL_001d: stloc.0 + IL_001e: leave.s IL_005f + + IL_0020: ldc.i4.s 19 + IL_0022: call bool JitTest.Test1::TestTryFinally(int32) + IL_0027: brtrue.s IL_0032 + + IL_0029: ldc.i4.s 12 + IL_002b: call bool JitTest.Test1::TestTryFinally(int32) + IL_0030: brtrue.s IL_0040 + + IL_0032: ldstr "try...finally test failed." + IL_0037: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_003c: ldc.i4.2 + IL_003d: stloc.0 + IL_003e: leave.s IL_005f + + IL_0040: leave.s IL_0051 + + } // end .try + catch ['mscorlib']System.Exception + { + IL_0042: pop + IL_0043: ldstr "Failed w/ exception" + IL_0048: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_004d: ldc.i4.m1 + IL_004e: stloc.0 + IL_004f: leave.s IL_005f + + } // end handler + IL_0051: ldstr "Passed" + IL_0056: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_005b: ldc.i4 0x64 + IL_005c: stloc.0 + IL_005d: br.s IL_005f + + IL_005f: ldloc.0 + IL_0060: ret + } // end of method 'Test1::Main' + + .method public hidebysig specialname rtspecialname static + void .cctor() il managed + { + // Code size 13 (0xd) + .maxstack 8 + IL_0000: ldc.i4.0 + IL_0001: stsfld bool JitTest.Test1::globalFlag + IL_0006: ldc.i4.1 + IL_0007: stsfld bool JitTest.Test1::globalFlag2 + IL_000c: ret + } // end of method 'Test1::.cctor' + + .method public hidebysig specialname rtspecialname + instance void .ctor() il managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void ['mscorlib']System.Object::.ctor() + IL_0006: ret + } // end of method 'Test1::.ctor' + + } // end of class 'Test1' + +} // end of namespace 'JitTest' + +//*********** DISASSEMBLY COMPLETE *********************** diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/Invoke/SEH/catchfinally_tail.il b/mono/tests/tailcall/coreclr/JIT/Methodical/Invoke/SEH/catchfinally_tail.il new file mode 100644 index 0000000000..64d0211715 --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/Invoke/SEH/catchfinally_tail.il @@ -0,0 +1,265 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } + +.assembly 'catchfinally_tail'// as "catchfinally_tail" +{ +} +.module 'catchfinally_tail.exe' +// MVID: {CCB52291-4072-427C-8C14-2780C164EB2B} +.namespace JitTest +{ + .class private auto ansi Test1 + extends ['mscorlib']System.Object + { + .field private static bool globalFlag + .field private static bool globalFlag2 + .method private hidebysig static bool + TestTryCatch(int32 recurseLevel) il managed + { + // Code size 72 (0x48) + .maxstack 3 + .locals (int32[] V_0, + bool V_1) + IL_0000: ldarg.0 + IL_0001: ldc.i4.1 + IL_0002: ble.s IL_003f + + .try + { + IL_0004: ldsfld bool JitTest.Test1::globalFlag + IL_0009: ldc.i4.0 + IL_000a: ceq + IL_000c: dup + IL_000d: stsfld bool JitTest.Test1::globalFlag + IL_0012: brfalse.s IL_001f + + IL_0014: ldarg.0 + IL_0015: ldc.i4.2 + IL_0016: sub + IL_0017: call bool JitTest.Test1::TestTryCatch(int32) + IL_001c: stloc.1 + IL_001d: leave.s IL_0046 + + IL_001f: ldnull + IL_0020: stloc.0 + IL_0021: ldloc.0 + IL_0022: ldc.i4.0 + IL_0023: ldc.i4.0 + IL_0024: stelem.i4 + IL_0025: ldstr "Shouldn't have reached here." + IL_002a: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_002f: newobj instance void ['mscorlib']System.Exception::.ctor() + IL_0034: throw + + } // end .try + catch ['mscorlib']System.NullReferenceException + { + IL_0035: pop + IL_0036: ldarg.0 + IL_0037: call bool JitTest.Test1::Test(int32) + IL_003c: stloc.1 + IL_003d: leave.s IL_0046 + + } // end handler + IL_003f: ldarg.0 + IL_0040: ldc.i4.0 + IL_0041: ceq + IL_0043: stloc.1 + IL_0044: br.s IL_0046 + + IL_0046: ldloc.1 + IL_0047: ret + } // end of method 'Test1::TestTryCatch' + + .method private hidebysig static bool + TestTryFinally(int32 recurseLevel) il managed + { + // Code size 86 (0x56) + .maxstack 3 + .locals (bool V_0, + bool V_1, + int32[] V_2, + bool V_3) + IL_0000: ldarg.0 + IL_0001: ldc.i4.1 + IL_0002: ble.s IL_004d + + IL_0004: ldc.i4.0 + IL_0005: stloc.0 + .try + { + IL_0006: ldc.i4.0 + IL_0007: stloc.1 + .try + { + IL_0008: ldsfld bool JitTest.Test1::globalFlag + IL_000d: ldc.i4.0 + IL_000e: ceq + IL_0010: dup + IL_0011: stsfld bool JitTest.Test1::globalFlag + IL_0016: brfalse.s IL_0023 + + IL_0018: ldarg.0 + IL_0019: ldc.i4.2 + IL_001a: sub + IL_001b: call bool JitTest.Test1::Test(int32) + IL_0020: stloc.3 + IL_0021: leave.s IL_0054 + + IL_0023: ldc.i4.1 + IL_0024: stloc.1 + IL_0025: ldnull + IL_0026: stloc.2 + IL_0027: ldloc.2 + IL_0028: ldc.i4.0 + IL_0029: ldc.i4.0 + IL_002a: stelem.i4 + IL_002b: ldstr "Shouldn't have reached here." + IL_0030: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_0035: newobj instance void ['mscorlib']System.Exception::.ctor() + IL_003a: throw + + } // end .try + finally + { + IL_003b: ldloc.1 + IL_003c: brfalse.s IL_0045 + + IL_003e: ldarg.0 + IL_003f: call bool JitTest.Test1::TestTryCatch(int32) + IL_0044: stloc.0 + IL_0045: endfinally + } // end handler + } // end .try + catch ['mscorlib']System.NullReferenceException + { + IL_0046: pop + IL_0047: leave.s IL_0049 + + } // end handler + IL_0049: ldloc.0 + IL_004a: stloc.3 + IL_004b: br.s IL_0054 + + IL_004d: ldarg.0 + IL_004e: ldc.i4.0 + IL_004f: ceq + IL_0051: stloc.3 + IL_0052: br.s IL_0054 + + IL_0054: ldloc.3 + IL_0055: ret + } // end of method 'Test1::TestTryFinally' + + .method private hidebysig static bool + Test(int32 recurseLevel) il managed + { + // Code size 36 (0x24) + .maxstack 2 + .locals (bool V_0) + IL_0000: ldsfld bool JitTest.Test1::globalFlag2 + IL_0005: ldc.i4.0 + IL_0006: ceq + IL_0008: dup + IL_0009: stsfld bool JitTest.Test1::globalFlag2 + IL_000e: brfalse.s IL_0019 + + IL_0010: ldarg.0 + tail. call bool JitTest.Test1::TestTryCatch(int32) + ret + + IL_0019: ldarg.0 + tail. call bool JitTest.Test1::TestTryFinally(int32) + ret + } // end of method 'Test1::Test' + + .method private hidebysig static int32 + Main() il managed + { + .entrypoint + // Code size 97 (0x61) + .maxstack 1 + .locals (int32 V_0) + .try + { + IL_0000: ldc.i4.s 15 + IL_0002: call bool JitTest.Test1::TestTryCatch(int32) + IL_0007: brtrue.s IL_0012 + + IL_0009: ldc.i4.s 18 + IL_000b: call bool JitTest.Test1::TestTryCatch(int32) + IL_0010: brtrue.s IL_0020 + + IL_0012: ldstr "try...catch test failed." + IL_0017: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_001c: ldc.i4.1 + IL_001d: stloc.0 + IL_001e: leave.s IL_005f + + IL_0020: ldc.i4.s 19 + IL_0022: call bool JitTest.Test1::TestTryFinally(int32) + IL_0027: brtrue.s IL_0032 + + IL_0029: ldc.i4.s 12 + IL_002b: call bool JitTest.Test1::TestTryFinally(int32) + IL_0030: brtrue.s IL_0040 + + IL_0032: ldstr "try...finally test failed." + IL_0037: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_003c: ldc.i4.2 + IL_003d: stloc.0 + IL_003e: leave.s IL_005f + + IL_0040: leave.s IL_0051 + + } // end .try + catch ['mscorlib']System.Exception + { + IL_0042: pop + IL_0043: ldstr "Failed w/ exception" + IL_0048: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_004d: ldc.i4.m1 + IL_004e: stloc.0 + IL_004f: leave.s IL_005f + + } // end handler + IL_0051: ldstr "Passed" + IL_0056: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_005b: ldc.i4 0x64 + IL_005c: stloc.0 + IL_005d: br.s IL_005f + + IL_005f: ldloc.0 + IL_0060: ret + } // end of method 'Test1::Main' + + .method public hidebysig specialname rtspecialname static + void .cctor() il managed + { + // Code size 13 (0xd) + .maxstack 8 + IL_0000: ldc.i4.0 + IL_0001: stsfld bool JitTest.Test1::globalFlag + IL_0006: ldc.i4.1 + IL_0007: stsfld bool JitTest.Test1::globalFlag2 + IL_000c: ret + } // end of method 'Test1::.cctor' + + .method public hidebysig specialname rtspecialname + instance void .ctor() il managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void ['mscorlib']System.Object::.ctor() + IL_0006: ret + } // end of method 'Test1::.ctor' + + } // end of class 'Test1' + +} // end of namespace 'JitTest' + +//*********** DISASSEMBLY COMPLETE *********************** diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/Invoke/fptr/recurse_tail_call.il b/mono/tests/tailcall/coreclr/JIT/Methodical/Invoke/fptr/recurse_tail_call.il new file mode 100644 index 0000000000..152d6a84ba --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/Invoke/fptr/recurse_tail_call.il @@ -0,0 +1,121 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + + +.assembly extern mscorlib { } + +.assembly 'recurse'// as "recurse" +{ + + // .custom instance void ['mscorlib']System.Diagnostics.DebuggableAttribute::.ctor(bool, + // bool) = ( 01 00 00 01 00 00 ) + + +} +.module 'recurse.exe' +// MVID: {885F4995-E80A-480B-BB9B-30139BED90E1} +.namespace TestCase +{ + .class private auto ansi Test extends ['mscorlib']System.Object + { + .method private hidebysig static int32 + Fact1(int32& arg, + int32& result) il managed + { + // Code size 38 (0x26) + .maxstack 3 + IL_0000: ldarg.0 + IL_0001: ldind.i4 + IL_0002: ldc.i4.1 + IL_0003: bgt.s IL_0005 + + ldc.i4 0x12345 + br end_of_method + + IL_0005: ldarg.1 + IL_0006: dup + IL_0007: ldind.i4 + IL_0008: ldarg.0 + IL_0009: ldind.i4 + IL_000a: mul + IL_000b: stind.i4 + IL_000c: ldarg.0 + IL_000d: dup + IL_000e: ldind.i4 + IL_000f: ldc.i4.1 + IL_0010: sub + IL_0011: stind.i4 + + ldarg.0 + ldarg.1 + tail. call int32 TestCase.Test::Fact1(int32&, int32&) + + end_of_method: + ret + + } // end of method 'Test::Fact1' + + .method private hidebysig static int32 + Main() il managed + { + .entrypoint + // Code size 72 (0x48) + .maxstack 2 + .locals (int32 V_0, + int32 V_1, + int32 V_2) + IL_0000: ldc.i4.6 + IL_0001: stloc.0 + IL_0002: ldc.i4.1 + IL_0003: stloc.1 + IL_0004: ldloca.s V_0 + IL_0006: ldloca.s V_1 + IL_0008: call int32 TestCase.Test::Fact1(int32&, + int32&) + IL_000d: ldc.i4 0x12345 + IL_0012: beq.s IL_0022 + + IL_0014: ldstr "FAILED" + IL_0019: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_001e: ldc.i4.1 + IL_001f: stloc.2 + IL_0020: br.s IL_0046 + + IL_0022: ldloc.1 + IL_0023: ldc.i4 0x2d0 + IL_0028: beq.s IL_0038 + + IL_002a: ldstr "FAILED" + IL_002f: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_0034: ldc.i4.2 + IL_0035: stloc.2 + IL_0036: br.s IL_0046 + + IL_0038: ldstr "PASSED" + IL_003d: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_0042: ldc.i4 0x64 + IL_0043: stloc.2 + IL_0044: br.s IL_0046 + + IL_0046: ldloc.2 + IL_0047: ret + IL_0048: + } // end of method 'Test::Main' + + .method public hidebysig specialname rtspecialname + instance void .ctor() il managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void ['mscorlib']System.Object::.ctor() + IL_0006: ret + IL_0007: + } // end of method 'Test::.ctor' + + } // end of class 'Test' + +} // end of namespace 'TestCase' + +//*********** DISASSEMBLY COMPLETE *********************** diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/Invoke/fptr/recurse_tail_calli.il b/mono/tests/tailcall/coreclr/JIT/Methodical/Invoke/fptr/recurse_tail_calli.il new file mode 100644 index 0000000000..f8eb7c5753 --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/Invoke/fptr/recurse_tail_calli.il @@ -0,0 +1,119 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } + +.assembly 'recurse'// as "recurse" +{ + + // .custom instance void ['mscorlib']System.Diagnostics.DebuggableAttribute::.ctor(bool, + // bool) = ( 01 00 00 01 00 00 ) + + +} +.module 'recurse.exe' + +.namespace TestCase +{ + .class private auto ansi Test extends ['mscorlib']System.Object + { + .method private hidebysig static int32 + Fact1(int32& arg, + int32& result) il managed + { + // Code size 38 (0x26) + .maxstack 3 + IL_0000: ldarg.0 + IL_0001: ldind.i4 + IL_0002: ldc.i4.1 + IL_0003: bgt.s IL_0005 + + ldc.i4 0x12345 + br end_of_method + + IL_0005: ldarg.1 + IL_0006: dup + IL_0007: ldind.i4 + IL_0008: ldarg.0 + IL_0009: ldind.i4 + IL_000a: mul + IL_000b: stind.i4 + IL_000c: ldarg.0 + IL_000d: dup + IL_000e: ldind.i4 + IL_000f: ldc.i4.1 + IL_0010: sub + IL_0011: stind.i4 + + ldarg.0 + ldarg.1 + ldftn int32 TestCase.Test::Fact1(int32&, int32&) + tail. calli int32 (int32&, int32&) + + end_of_method: + ret + + } // end of method 'Test::Fact1' + + .method private hidebysig static int32 + Main() il managed + { + .entrypoint + // Code size 72 (0x48) + .maxstack 2 + .locals (int32 V_0, + int32 V_1, + int32 V_2) + IL_0000: ldc.i4.6 + IL_0001: stloc.0 + IL_0002: ldc.i4.1 + IL_0003: stloc.1 + IL_0004: ldloca.s V_0 + IL_0006: ldloca.s V_1 + IL_0008: call int32 TestCase.Test::Fact1(int32&, + int32&) + IL_000d: ldc.i4 0x12345 + IL_0012: beq.s IL_0022 + + IL_0014: ldstr "FAILED" + IL_0019: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_001e: ldc.i4.1 + IL_001f: stloc.2 + IL_0020: br.s IL_0046 + + IL_0022: ldloc.1 + IL_0023: ldc.i4 0x2d0 + IL_0028: beq.s IL_0038 + + IL_002a: ldstr "FAILED" + IL_002f: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_0034: ldc.i4.2 + IL_0035: stloc.2 + IL_0036: br.s IL_0046 + + IL_0038: ldstr "PASSED" + IL_003d: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_0042: ldc.i4 0x64 + IL_0043: stloc.2 + IL_0044: br.s IL_0046 + + IL_0046: ldloc.2 + IL_0047: ret + IL_0048: + } // end of method 'Test::Main' + + .method public hidebysig specialname rtspecialname + instance void .ctor() il managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void ['mscorlib']System.Object::.ctor() + IL_0006: ret + IL_0007: + } // end of method 'Test::.ctor' + + } // end of class 'Test' + +} // end of namespace 'TestCase' diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/nonvirtualcall/tailcall.il b/mono/tests/tailcall/coreclr/JIT/Methodical/nonvirtualcall/tailcall.il new file mode 100644 index 0000000000..7730c351f2 --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/nonvirtualcall/tailcall.il @@ -0,0 +1,704 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + + +.assembly extern mscorlib +{ +} +.assembly tailcall +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) + .hash algorithm 0x00008004 + .ver 0:0:0:0 +} + + +// =============== CLASS MEMBERS DECLARATION =================== + +.class public abstract auto ansi beforefieldinit Test.Base + extends [mscorlib]System.Object +{ + .method public hidebysig newslot abstract virtual + instance string AbstractFinal() cil managed + { + } // end of method Base::AbstractFinal + + .method public hidebysig newslot abstract virtual + instance string AbstractOverrideFinal() cil managed + { + } // end of method Base::AbstractOverrideFinal + + .method public hidebysig newslot abstract virtual + instance string AbstractOverrideOverride() cil managed + { + } // end of method Base::AbstractOverrideOverride + + .method public hidebysig newslot abstract virtual + instance string AbstractOverrideNil() cil managed + { + } // end of method Base::AbstractOverrideNil + + .method public hidebysig newslot virtual + instance string VirtualFinal() cil managed + { + // Code size 11 (0xb) + .maxstack 1 + .locals init (string V_0) + IL_0000: nop + IL_0001: ldstr "Base.VirtualFinal" + IL_0006: stloc.0 + IL_0007: br.s IL_0009 + + IL_0009: ldloc.0 + IL_000a: ret + } // end of method Base::VirtualFinal + + .method public hidebysig newslot virtual + instance string VirtualNilFinal() cil managed + { + // Code size 11 (0xb) + .maxstack 1 + .locals init (string V_0) + IL_0000: nop + IL_0001: ldstr "Base.VirtualNilFinal" + IL_0006: stloc.0 + IL_0007: br.s IL_0009 + + IL_0009: ldloc.0 + IL_000a: ret + } // end of method Base::VirtualNilFinal + + .method public hidebysig newslot virtual + instance string VirtualOverrideFinal() cil managed + { + // Code size 11 (0xb) + .maxstack 1 + .locals init (string V_0) + IL_0000: nop + IL_0001: ldstr "Base.VirtualOverrideFinal" + IL_0006: stloc.0 + IL_0007: br.s IL_0009 + + IL_0009: ldloc.0 + IL_000a: ret + } // end of method Base::VirtualOverrideFinal + + .method public hidebysig newslot virtual + instance string VirtualNilOverride() cil managed + { + // Code size 11 (0xb) + .maxstack 1 + .locals init (string V_0) + IL_0000: nop + IL_0001: ldstr "Base.VirtualNilOverride" + IL_0006: stloc.0 + IL_0007: br.s IL_0009 + + IL_0009: ldloc.0 + IL_000a: ret + } // end of method Base::VirtualNilOverride + + .method public hidebysig newslot virtual + instance string VirtualNilNil() cil managed + { + // Code size 11 (0xb) + .maxstack 1 + .locals init (string V_0) + IL_0000: nop + IL_0001: ldstr "Base.VirtualNilNil" + IL_0006: stloc.0 + IL_0007: br.s IL_0009 + + IL_0009: ldloc.0 + IL_000a: ret + } // end of method Base::VirtualNilNil + + .method public hidebysig newslot virtual + instance string VirtualOverrideOverride() cil managed + { + // Code size 11 (0xb) + .maxstack 1 + .locals init (string V_0) + IL_0000: nop + IL_0001: ldstr "Base.VirtualOverrideOverride" + IL_0006: stloc.0 + IL_0007: br.s IL_0009 + + IL_0009: ldloc.0 + IL_000a: ret + } // end of method Base::VirtualOverrideOverride + + .method public hidebysig newslot virtual + instance string VirtualOverrideNil() cil managed + { + // Code size 11 (0xb) + .maxstack 1 + .locals init (string V_0) + IL_0000: nop + IL_0001: ldstr "Base.VirtualOverrideNil" + IL_0006: stloc.0 + IL_0007: br.s IL_0009 + + IL_0009: ldloc.0 + IL_000a: ret + } // end of method Base::VirtualOverrideNil + + .method family hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method Base::.ctor + +} // end of class Test.Base + +.class public auto ansi beforefieldinit Test.Child + extends Test.Base +{ + .method public hidebysig virtual final + instance string AbstractFinal() cil managed + { + // Code size 11 (0xb) + .maxstack 1 + .locals init (string V_0) + IL_0000: nop + IL_0001: ldstr "Child.AbstractFinal" + IL_0006: stloc.0 + IL_0007: br.s IL_0009 + + IL_0009: ldloc.0 + IL_000a: ret + } // end of method Child::AbstractFinal + + .method public hidebysig instance string + CallAbstractFinal() cil managed + { + // Code size 12 (0xc) + .maxstack 1 + .locals init (string V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: tail. call instance string Test.Child::AbstractFinal() + IL_000b: ret + } // end of method Child::CallAbstractFinal + + .method public hidebysig virtual instance string + AbstractOverrideFinal() cil managed + { + // Code size 11 (0xb) + .maxstack 1 + .locals init (string V_0) + IL_0000: nop + IL_0001: ldstr "Child.AbstractOverrideFinal" + IL_0006: stloc.0 + IL_0007: br.s IL_0009 + + IL_0009: ldloc.0 + IL_000a: ret + } // end of method Child::AbstractOverrideFinal + + .method public hidebysig virtual instance string + AbstractOverrideOverride() cil managed + { + // Code size 11 (0xb) + .maxstack 1 + .locals init (string V_0) + IL_0000: nop + IL_0001: ldstr "Child.AbstractOverrideOverride" + IL_0006: stloc.0 + IL_0007: br.s IL_0009 + + IL_0009: ldloc.0 + IL_000a: ret + } // end of method Child::AbstractOverrideOverride + + .method public hidebysig virtual instance string + AbstractOverrideNil() cil managed + { + // Code size 11 (0xb) + .maxstack 1 + .locals init (string V_0) + IL_0000: nop + IL_0001: ldstr "Child.AbstractOverrideNil" + IL_0006: stloc.0 + IL_0007: br.s IL_0009 + + IL_0009: ldloc.0 + IL_000a: ret + } // end of method Child::AbstractOverrideNil + + .method public hidebysig instance string + CallAbstractOverrideNil() cil managed + { + // Code size 12 (0xc) + .maxstack 1 + .locals init (string V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: tail. call instance string Test.Child::AbstractOverrideNil() + IL_000b: ret + } // end of method Child::CallAbstractOverrideNil + + .method public hidebysig virtual final + instance string VirtualFinal() cil managed + { + // Code size 11 (0xb) + .maxstack 1 + .locals init (string V_0) + IL_0000: nop + IL_0001: ldstr "Child.VirtualFinal" + IL_0006: stloc.0 + IL_0007: br.s IL_0009 + + IL_0009: ldloc.0 + IL_000a: ret + } // end of method Child::VirtualFinal + + .method public hidebysig instance string + CallVirtualFinal() cil managed + { + // Code size 12 (0xc) + .maxstack 1 + .locals init (string V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: tail. call instance string Test.Child::VirtualFinal() + IL_000b: ret + } // end of method Child::tail. callualFinal + + .method public hidebysig virtual instance string + VirtualOverrideFinal() cil managed + { + // Code size 11 (0xb) + .maxstack 1 + .locals init (string V_0) + IL_0000: nop + IL_0001: ldstr "Child.VirtualOverrideFinal" + IL_0006: stloc.0 + IL_0007: br.s IL_0009 + + IL_0009: ldloc.0 + IL_000a: ret + } // end of method Child::VirtualOverrideFinal + + .method public hidebysig virtual instance string + VirtualOverrideOverride() cil managed + { + // Code size 11 (0xb) + .maxstack 1 + .locals init (string V_0) + IL_0000: nop + IL_0001: ldstr "Child.VirtualOverrideOverride" + IL_0006: stloc.0 + IL_0007: br.s IL_0009 + + IL_0009: ldloc.0 + IL_000a: ret + } // end of method Child::VirtualOverrideOverride + + .method public hidebysig virtual instance string + VirtualOverrideNil() cil managed + { + // Code size 11 (0xb) + .maxstack 1 + .locals init (string V_0) + IL_0000: nop + IL_0001: ldstr "Child.VirtualOverrideNil" + IL_0006: stloc.0 + IL_0007: br.s IL_0009 + + IL_0009: ldloc.0 + IL_000a: ret + } // end of method Child::VirtualOverrideNil + + .method public hidebysig instance string + CallVirtualOverrideNil() cil managed + { + // Code size 12 (0xc) + .maxstack 1 + .locals init (string V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: tail. call instance string Test.Child::VirtualOverrideNil() + IL_000b: ret + } // end of method Child::tail. callualOverrideNil + + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void Test.Base::.ctor() + IL_0006: ret + } // end of method Child::.ctor + +} // end of class Test.Child + +.class public auto ansi beforefieldinit Test.GrandChild + extends Test.Child +{ + .method public hidebysig virtual final + instance string AbstractOverrideFinal() cil managed + { + // Code size 11 (0xb) + .maxstack 1 + .locals init (string V_0) + IL_0000: nop + IL_0001: ldstr "GrandChild.AbstractOverrideFinal" + IL_0006: stloc.0 + IL_0007: br.s IL_0009 + + IL_0009: ldloc.0 + IL_000a: ret + } // end of method GrandChild::AbstractOverrideFinal + + .method public hidebysig instance string + CallAbstractOverrideFinal() cil managed + { + // Code size 12 (0xc) + .maxstack 1 + .locals init (string V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: tail. call instance string Test.GrandChild::AbstractOverrideFinal() + IL_000b: ret + } // end of method GrandChild::CallAbstractOverrideFinal + + .method public hidebysig virtual instance string + AbstractOverrideOverride() cil managed + { + // Code size 11 (0xb) + .maxstack 1 + .locals init (string V_0) + IL_0000: nop + IL_0001: ldstr "GrandChild.AbstractOverrideOverride" + IL_0006: stloc.0 + IL_0007: br.s IL_0009 + + IL_0009: ldloc.0 + IL_000a: ret + } // end of method GrandChild::AbstractOverrideOverride + + .method public hidebysig instance string + CallAbstractOverrideOverride() cil managed + { + // Code size 12 (0xc) + .maxstack 1 + .locals init (string V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: tail. call instance string Test.GrandChild::AbstractOverrideOverride() + IL_000b: ret + } // end of method GrandChild::CallAbstractOverrideOverride + + .method public hidebysig virtual final + instance string VirtualNilFinal() cil managed + { + // Code size 11 (0xb) + .maxstack 1 + .locals init (string V_0) + IL_0000: nop + IL_0001: ldstr "GrandChild.VirtualNilFinal" + IL_0006: stloc.0 + IL_0007: br.s IL_0009 + + IL_0009: ldloc.0 + IL_000a: ret + } // end of method GrandChild::VirtualNilFinal + + .method public hidebysig instance string + CallVirtualNilFinal() cil managed + { + // Code size 12 (0xc) + .maxstack 1 + .locals init (string V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: tail. call instance string Test.GrandChild::VirtualNilFinal() + IL_000b: ret + } // end of method GrandChild::tail. callualNilFinal + + .method public hidebysig virtual final + instance string VirtualOverrideFinal() cil managed + { + // Code size 11 (0xb) + .maxstack 1 + .locals init (string V_0) + IL_0000: nop + IL_0001: ldstr "GrandChild.VirtualOverrideFinal" + IL_0006: stloc.0 + IL_0007: br.s IL_0009 + + IL_0009: ldloc.0 + IL_000a: ret + } // end of method GrandChild::VirtualOverrideFinal + + .method public hidebysig instance string + CallVirtualOverrideFinal() cil managed + { + // Code size 12 (0xc) + .maxstack 1 + .locals init (string V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: tail. call instance string Test.GrandChild::VirtualOverrideFinal() + IL_000b: ret + } // end of method GrandChild::tail. callualOverrideFinal + + .method public hidebysig virtual instance string + VirtualOverrideOverride() cil managed + { + // Code size 11 (0xb) + .maxstack 1 + .locals init (string V_0) + IL_0000: nop + IL_0001: ldstr "GrandChild.VirtualOverrideOverride" + IL_0006: stloc.0 + IL_0007: br.s IL_0009 + + IL_0009: ldloc.0 + IL_000a: ret + } // end of method GrandChild::VirtualOverrideOverride + + .method public hidebysig instance string + CallVirtualOverrideOverride() cil managed + { + // Code size 12 (0xc) + .maxstack 1 + .locals init (string V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: tail. call instance string Test.GrandChild::VirtualOverrideOverride() + IL_000b: ret + } // end of method GrandChild::tail. callualOverrideOverride + + .method public hidebysig virtual instance string + VirtualNilOverride() cil managed + { + // Code size 11 (0xb) + .maxstack 1 + .locals init (string V_0) + IL_0000: nop + IL_0001: ldstr "GrandChild.VirtualNilOverride" + IL_0006: stloc.0 + IL_0007: br.s IL_0009 + + IL_0009: ldloc.0 + IL_000a: ret + } // end of method GrandChild::VirtualNilOverride + + .method public hidebysig instance string + CallVirtualNilOverride() cil managed + { + // Code size 12 (0xc) + .maxstack 1 + .locals init (string V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: tail. call instance string Test.GrandChild::VirtualNilOverride() + IL_000b: ret + } // end of method GrandChild::tail. callualNilOverride + + .method public hidebysig instance void + TestGrandChild() cil managed + { + // Code size 149 (0x95) + .maxstack 2 + IL_0000: nop + IL_0001: ldstr "Call from inside GrandChild" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldstr "Child.AbstractFinal" + IL_0011: ldarg.0 + IL_0012: call instance string Test.Child::CallAbstractFinal() + IL_0017: call void Test.Assert::AreEqual(string, + string) + IL_001c: nop + IL_001d: ldstr "GrandChild.AbstractOverrideFinal" + IL_0022: ldarg.0 + IL_0023: call instance string Test.GrandChild::CallAbstractOverrideFinal() + IL_0028: call void Test.Assert::AreEqual(string, + string) + IL_002d: nop + IL_002e: ldstr "GrandChild.AbstractOverrideOverride" + IL_0033: ldarg.0 + IL_0034: call instance string Test.GrandChild::CallAbstractOverrideOverride() + IL_0039: call void Test.Assert::AreEqual(string, + string) + IL_003e: nop + IL_003f: ldstr "Child.AbstractOverrideNil" + IL_0044: ldarg.0 + IL_0045: call instance string Test.Child::CallAbstractOverrideNil() + IL_004a: call void Test.Assert::AreEqual(string, + string) + IL_004f: nop + IL_0050: ldstr "Child.VirtualFinal" + IL_0055: ldarg.0 + IL_0056: call instance string Test.Child::CallVirtualFinal() + IL_005b: call void Test.Assert::AreEqual(string, + string) + IL_0060: nop + IL_0061: ldstr "GrandChild.VirtualOverrideFinal" + IL_0066: ldarg.0 + IL_0067: call instance string Test.GrandChild::CallVirtualOverrideFinal() + IL_006c: call void Test.Assert::AreEqual(string, + string) + IL_0071: nop + IL_0072: ldstr "GrandChild.VirtualOverrideOverride" + IL_0077: ldarg.0 + IL_0078: call instance string Test.GrandChild::CallVirtualOverrideOverride() + IL_007d: call void Test.Assert::AreEqual(string, + string) + IL_0082: nop + IL_0083: ldstr "Child.VirtualOverrideNil" + IL_0088: ldarg.0 + IL_0089: call instance string Test.Child::CallVirtualOverrideNil() + IL_008e: call void Test.Assert::AreEqual(string, + string) + IL_0093: nop + IL_0094: ret + } // end of method GrandChild::TestGrandChild + + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void Test.Child::.ctor() + IL_0006: ret + } // end of method GrandChild::.ctor + +} // end of class Test.GrandChild + +.class public abstract auto ansi sealed beforefieldinit Test.Program + extends [mscorlib]System.Object +{ + .method public hidebysig static void CallFromInsideGrandChild() cil managed + { + // Code size 15 (0xf) + .maxstack 1 + .locals init (class Test.GrandChild V_0) + IL_0000: nop + IL_0001: newobj instance void Test.GrandChild::.ctor() + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: tail. call instance void Test.GrandChild::TestGrandChild() + IL_000e: ret + } // end of method Program::CallFromInsideGrandChild + + .method public hidebysig static int32 Main(string[] args) cil managed + { + .entrypoint + // Code size 52 (0x34) + .maxstack 1 + .locals init (class [mscorlib]System.Exception V_0, + int32 V_1) + IL_0000: nop + .try + { + IL_0001: nop + IL_0002: call void Test.Program::CallFromInsideGrandChild() + IL_0007: nop + IL_0008: ldstr "Test SUCCESS" + IL_000d: call void [mscorlib]System.Console::WriteLine(string) + IL_0012: nop + IL_0013: ldc.i4.s 100 + IL_0015: stloc.1 + IL_0016: leave.s IL_0031 + + } // end .try + catch [mscorlib]System.Exception + { + IL_0018: stloc.0 + IL_0019: nop + IL_001a: ldloc.0 + IL_001b: call void [mscorlib]System.Console::WriteLine(object) + IL_0020: nop + IL_0021: ldstr "Test FAILED" + IL_0026: call void [mscorlib]System.Console::WriteLine(string) + IL_002b: nop + IL_002c: ldc.i4.s 101 + IL_002e: stloc.1 + IL_002f: leave.s IL_0031 + + } // end handler + IL_0031: nop + IL_0032: ldloc.1 + IL_0033: ret + } // end of method Program::Main + +} // end of class Test.Program + +.class public abstract auto ansi sealed beforefieldinit Test.Assert + extends [mscorlib]System.Object +{ + .method public hidebysig static void AreEqual(string left, + string right) cil managed + { + // Code size 85 (0x55) + .maxstack 3 + .locals init (string V_0, + bool V_1) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: call bool [mscorlib]System.String::IsNullOrEmpty(string) + IL_0007: ldc.i4.0 + IL_0008: ceq + IL_000a: stloc.1 + IL_000b: ldloc.1 + IL_000c: brtrue.s IL_0019 + + IL_000e: ldstr "left" + IL_0013: newobj instance void [mscorlib]System.ArgumentNullException::.ctor(string) + IL_0018: throw + + IL_0019: ldarg.1 + IL_001a: call bool [mscorlib]System.String::IsNullOrEmpty(string) + IL_001f: ldc.i4.0 + IL_0020: ceq + IL_0022: stloc.1 + IL_0023: ldloc.1 + IL_0024: brtrue.s IL_0031 + + IL_0026: ldstr "right" + IL_002b: newobj instance void [mscorlib]System.ArgumentNullException::.ctor(string) + IL_0030: throw + + IL_0031: ldarg.0 + IL_0032: ldarg.1 + IL_0033: call bool [mscorlib]System.String::op_Inequality(string, + string) + IL_0038: ldc.i4.0 + IL_0039: ceq + IL_003b: stloc.1 + IL_003c: ldloc.1 + IL_003d: brtrue.s IL_0054 + + IL_003f: nop + IL_0040: ldstr "[[{0}]] != [[{1}]]" + IL_0045: ldarg.0 + IL_0046: ldarg.1 + IL_0047: call string [mscorlib]System.String::Format(string, + object, + object) + IL_004c: stloc.0 + IL_004d: ldloc.0 + IL_004e: newobj instance void [mscorlib]System.Exception::.ctor(string) + IL_0053: throw + + IL_0054: ret + } // end of method Assert::AreEqual + +} // end of class Test.Assert + + +// ============================================================= + +// *********** DISASSEMBLY COMPLETE *********************** +// WARNING: Created Win32 resource file nonvirtualcalls_tailcall.res diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/Desktop/thread-race.cs b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/Desktop/thread-race.cs new file mode 100644 index 0000000000..9746d34790 --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/Desktop/thread-race.cs @@ -0,0 +1,106 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Threading; +using System.Runtime.CompilerServices; + +internal class Repro +{ + private static volatile bool s_threadsCompleted; + private static volatile Mutex s_myMutex; + private static volatile int[] s_threadSum; + + public static int Main() + { + ThreadStart ts = new ThreadStart(FibThread); + Thread t1 = new Thread(ts); + Thread t2 = new Thread(ts); + Thread t3 = new Thread(ts); + long threadValue; + + s_threadsCompleted = false; + s_threadSum = new int[3]; + s_threadSum[0] = 0; + s_threadSum[1] = 0; + s_threadSum[2] = 0; + s_myMutex = new Mutex(); + + t1.Start(); + t2.Start(); + t3.Start(); + + while (!s_threadsCompleted) + { + GC.Collect(); + } + + t1.Join(); + t2.Join(); + t3.Join(); + + threadValue = (s_threadSum[0] + s_threadSum[1] + s_threadSum[2]); + + if (((long)54018518 * 3) != threadValue) + { + Console.WriteLine("FALSE: {0} != {1}", ((long)439201 * 3), threadValue); + return 0; + } + else + { + Console.WriteLine("PASS"); + return 100; + } + } + + public static void FibThread() + { + int sum = 0; + const int length = 35; + + for (int i = 0; i <= length; i++) + { + sum += fib(0, i); + Console.WriteLine("" + i + ": " + sum); + } + + s_threadsCompleted = true; + + s_myMutex.WaitOne(); + if (0 == s_threadSum[0]) s_threadSum[0] = sum; + if (0 == s_threadSum[1]) s_threadSum[1] = sum; + if (0 == s_threadSum[2]) s_threadSum[2] = sum; + s_myMutex.ReleaseMutex(); + } + + public static int fib(int sum, int num) + { + if (num <= 2) + { + return simple(sum, num); + } + + return fib(fib(sum, num - 1), num - 2); + } + + public static int simple(int sum, int num) + { + if (num == 0) + { + return sum + 0; + } + + if (num == 1) + { + return sum + 1; + } + + if (num == 2) + { + return sum + 3; + } + + return 555555; + } +} diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/compat_enum.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/compat_enum.il new file mode 100644 index 0000000000..e2ce29c5af --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/compat_enum.il @@ -0,0 +1,73 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly compat_enum { } +.namespace JitTest +{ + .class private auto ansi serializable sealed TestEnum extends [mscorlib]System.Enum + { + .field public specialname rtspecialname int32 value__ + .field public static literal value class JitTest.TestEnum v = int32(0x00000000) + .field public static literal value class JitTest.TestEnum w = int32(0x00000001) + } + .class private auto ansi beforefieldinit TestClass extends [mscorlib]System.Object + { + .method private hidebysig static value class JitTest.TestEnum callee() il managed + { + .maxstack 8 + .locals (value class JitTest.TestEnum V_0) + ldc.i4.1 + stloc.0 + ldloc.0 + ret + } + .method private hidebysig static int32 caller() il managed + { + // Code size 10 (0xa) + .maxstack 8 + tail. call value class JitTest.TestEnum JitTest.TestClass::callee() + ret + } // end of method TestClass::caller + + .method private hidebysig static + int32 Main() il managed + { + .entrypoint + // Code size 40 (0x28) + .maxstack 2 + .locals (int32 V_0) + IL_0000: call int32 JitTest.TestClass::caller() + IL_0005: ldc.i4.1 + IL_0006: bne.un.s IL_0017 + + IL_0008: ldstr "passed" + IL_000d: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_0012: ldc.i4.s 100 + IL_0014: stloc.0 + IL_0015: br.s IL_0026 + + IL_0017: ldstr "failed" + IL_001c: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_0021: ldc.i4.s 101 + IL_0023: stloc.0 + IL_0024: br.s IL_0026 + + IL_0026: ldloc.0 + IL_0027: ret + } // end of method TestClass::Main + + .method public hidebysig specialname rtspecialname + instance void .ctor() il managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method TestClass::.ctor + + } // end of class TestClass + +} // end of namespace JitTest diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/compat_i2_bool.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/compat_i2_bool.il new file mode 100644 index 0000000000..c0b47da1b1 --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/compat_i2_bool.il @@ -0,0 +1,110 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } + +.assembly compat_i2_bool { } + +.namespace JitTest +{ + .class private auto ansi beforefieldinit Test + extends [mscorlib]System.Object + { + .method private hidebysig static + int16 Method1() il managed + { + // Code size 93 (0x5d) + .maxstack 8 + IL_0000: call void [mscorlib]System.GC::Collect() + IL_0005: call void [mscorlib]System.GC::Collect() + IL_000a: call void [mscorlib]System.GC::Collect() + IL_000f: call void [mscorlib]System.GC::Collect() + IL_0014: call void [mscorlib]System.GC::Collect() + IL_0019: call void [mscorlib]System.GC::Collect() + IL_001e: call void [mscorlib]System.GC::Collect() + IL_0023: call void [mscorlib]System.GC::Collect() + IL_0028: call void [mscorlib]System.GC::Collect() + IL_002d: call void [mscorlib]System.GC::Collect() + IL_0032: call void [mscorlib]System.GC::Collect() + IL_0037: call void [mscorlib]System.GC::Collect() + IL_003c: call void [mscorlib]System.GC::Collect() + IL_0041: call void [mscorlib]System.GC::Collect() + IL_0046: call void [mscorlib]System.GC::Collect() + IL_004b: call void [mscorlib]System.GC::Collect() + IL_0050: call void [mscorlib]System.GC::Collect() + IL_0055: call void [mscorlib]System.GC::Collect() + IL_005a: ldc.i4.s 10 + IL_005c: ret + } // end of method Test::Method1 + + .method private hidebysig static + bool Method2() il managed + { + // Code size 98 (0x62) + .maxstack 8 + IL_0000: call void [mscorlib]System.GC::Collect() + IL_0005: call void [mscorlib]System.GC::Collect() + IL_000a: call void [mscorlib]System.GC::Collect() + IL_000f: call void [mscorlib]System.GC::Collect() + IL_0014: call void [mscorlib]System.GC::Collect() + IL_0019: call void [mscorlib]System.GC::Collect() + IL_001e: call void [mscorlib]System.GC::Collect() + IL_0023: call void [mscorlib]System.GC::Collect() + IL_0028: call void [mscorlib]System.GC::Collect() + IL_002d: call void [mscorlib]System.GC::Collect() + IL_0032: call void [mscorlib]System.GC::Collect() + IL_0037: call void [mscorlib]System.GC::Collect() + IL_003c: call void [mscorlib]System.GC::Collect() + IL_0041: call void [mscorlib]System.GC::Collect() + IL_0046: call void [mscorlib]System.GC::Collect() + IL_004b: call void [mscorlib]System.GC::Collect() + IL_0050: call void [mscorlib]System.GC::Collect() + IL_0055: call void [mscorlib]System.GC::Collect() + IL_005a: tail. + IL_005c: call int16 JitTest.Test::Method1() + IL_0061: ret + } // end of method Test::Method2 + + .method private hidebysig static + int32 Main() il managed + { + .entrypoint + // Code size 40 (0x28) + .maxstack 2 + .locals (int32 V_0) + IL_0000: call bool JitTest.Test::Method2() + IL_0005: ldc.i4.s 10 + IL_0007: beq.s IL_0017 + + IL_0009: ldstr "failed" + IL_000e: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_0013: ldc.i4.1 + IL_0014: stloc.0 + IL_0015: br.s IL_0026 + + IL_0017: ldstr "passed" + IL_001c: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_0021: ldc.i4.s 100 + IL_0023: stloc.0 + IL_0024: br.s IL_0026 + + IL_0026: ldloc.0 + IL_0027: ret + } // end of method Test::Main + + .method public hidebysig specialname rtspecialname + instance void .ctor() il managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method Test::.ctor + + } // end of class Test + +} // end of namespace JitTest + +//*********** DISASSEMBLY COMPLETE *********************** diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/compat_i4_i1.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/compat_i4_i1.il new file mode 100644 index 0000000000..b066cd493d --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/compat_i4_i1.il @@ -0,0 +1,106 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly compat_i4_i1 { } +.namespace JitTest +{ + .class private auto ansi beforefieldinit Test + extends [mscorlib]System.Object + { + .method private hidebysig static + int32 Method1() il managed + { + // Code size 93 (0x5d) + .maxstack 8 + IL_0000: call void [mscorlib]System.GC::Collect() + IL_0005: call void [mscorlib]System.GC::Collect() + IL_000a: call void [mscorlib]System.GC::Collect() + IL_000f: call void [mscorlib]System.GC::Collect() + IL_0014: call void [mscorlib]System.GC::Collect() + IL_0019: call void [mscorlib]System.GC::Collect() + IL_001e: call void [mscorlib]System.GC::Collect() + IL_0023: call void [mscorlib]System.GC::Collect() + IL_0028: call void [mscorlib]System.GC::Collect() + IL_002d: call void [mscorlib]System.GC::Collect() + IL_0032: call void [mscorlib]System.GC::Collect() + IL_0037: call void [mscorlib]System.GC::Collect() + IL_003c: call void [mscorlib]System.GC::Collect() + IL_0041: call void [mscorlib]System.GC::Collect() + IL_0046: call void [mscorlib]System.GC::Collect() + IL_004b: call void [mscorlib]System.GC::Collect() + IL_0050: call void [mscorlib]System.GC::Collect() + IL_0055: call void [mscorlib]System.GC::Collect() + IL_005a: ldc.i4.s 10 + IL_005c: ret + } // end of method Test::Method1 + + .method private hidebysig static + int8 Method2() il managed + { + // Code size 98 (0x62) + .maxstack 8 + IL_0000: call void [mscorlib]System.GC::Collect() + IL_0005: call void [mscorlib]System.GC::Collect() + IL_000a: call void [mscorlib]System.GC::Collect() + IL_000f: call void [mscorlib]System.GC::Collect() + IL_0014: call void [mscorlib]System.GC::Collect() + IL_0019: call void [mscorlib]System.GC::Collect() + IL_001e: call void [mscorlib]System.GC::Collect() + IL_0023: call void [mscorlib]System.GC::Collect() + IL_0028: call void [mscorlib]System.GC::Collect() + IL_002d: call void [mscorlib]System.GC::Collect() + IL_0032: call void [mscorlib]System.GC::Collect() + IL_0037: call void [mscorlib]System.GC::Collect() + IL_003c: call void [mscorlib]System.GC::Collect() + IL_0041: call void [mscorlib]System.GC::Collect() + IL_0046: call void [mscorlib]System.GC::Collect() + IL_004b: call void [mscorlib]System.GC::Collect() + IL_0050: call void [mscorlib]System.GC::Collect() + IL_0055: call void [mscorlib]System.GC::Collect() + IL_005a: tail. + IL_005c: call int32 JitTest.Test::Method1() + IL_0061: ret + } // end of method Test::Method2 + + .method private hidebysig static + int32 Main() il managed + { + .entrypoint + // Code size 40 (0x28) + .maxstack 2 + .locals (int32 V_0) + IL_0000: call int8 JitTest.Test::Method2() + IL_0005: ldc.i4.s 10 + IL_0007: beq.s IL_0017 + + IL_0009: ldstr "failed" + IL_000e: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_0013: ldc.i4.1 + IL_0014: stloc.0 + IL_0015: br.s IL_0026 + + IL_0017: ldstr "passed" + IL_001c: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_0021: ldc.i4.s 100 + IL_0023: stloc.0 + IL_0024: br.s IL_0026 + + IL_0026: ldloc.0 + IL_0027: ret + } // end of method Test::Main + + .method public hidebysig specialname rtspecialname + instance void .ctor() il managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method Test::.ctor + + } // end of class Test + +} // end of namespace JitTest diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/compat_i4_u.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/compat_i4_u.il new file mode 100644 index 0000000000..1ba8be982d --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/compat_i4_u.il @@ -0,0 +1,106 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly compat_i4_u { } +.namespace JitTest +{ + .class private auto ansi beforefieldinit Test + extends [mscorlib]System.Object + { + .method private hidebysig static + int32 Method1() il managed + { + // Code size 93 (0x5d) + .maxstack 8 + IL_0000: call void [mscorlib]System.GC::Collect() + IL_0005: call void [mscorlib]System.GC::Collect() + IL_000a: call void [mscorlib]System.GC::Collect() + IL_000f: call void [mscorlib]System.GC::Collect() + IL_0014: call void [mscorlib]System.GC::Collect() + IL_0019: call void [mscorlib]System.GC::Collect() + IL_001e: call void [mscorlib]System.GC::Collect() + IL_0023: call void [mscorlib]System.GC::Collect() + IL_0028: call void [mscorlib]System.GC::Collect() + IL_002d: call void [mscorlib]System.GC::Collect() + IL_0032: call void [mscorlib]System.GC::Collect() + IL_0037: call void [mscorlib]System.GC::Collect() + IL_003c: call void [mscorlib]System.GC::Collect() + IL_0041: call void [mscorlib]System.GC::Collect() + IL_0046: call void [mscorlib]System.GC::Collect() + IL_004b: call void [mscorlib]System.GC::Collect() + IL_0050: call void [mscorlib]System.GC::Collect() + IL_0055: call void [mscorlib]System.GC::Collect() + IL_005a: ldc.i4.s 10 + IL_005c: ret + } // end of method Test::Method1 + + .method private hidebysig static + native unsigned int Method2() il managed + { + // Code size 98 (0x62) + .maxstack 8 + IL_0000: call void [mscorlib]System.GC::Collect() + IL_0005: call void [mscorlib]System.GC::Collect() + IL_000a: call void [mscorlib]System.GC::Collect() + IL_000f: call void [mscorlib]System.GC::Collect() + IL_0014: call void [mscorlib]System.GC::Collect() + IL_0019: call void [mscorlib]System.GC::Collect() + IL_001e: call void [mscorlib]System.GC::Collect() + IL_0023: call void [mscorlib]System.GC::Collect() + IL_0028: call void [mscorlib]System.GC::Collect() + IL_002d: call void [mscorlib]System.GC::Collect() + IL_0032: call void [mscorlib]System.GC::Collect() + IL_0037: call void [mscorlib]System.GC::Collect() + IL_003c: call void [mscorlib]System.GC::Collect() + IL_0041: call void [mscorlib]System.GC::Collect() + IL_0046: call void [mscorlib]System.GC::Collect() + IL_004b: call void [mscorlib]System.GC::Collect() + IL_0050: call void [mscorlib]System.GC::Collect() + IL_0055: call void [mscorlib]System.GC::Collect() + IL_005a: tail. + IL_005c: call int32 JitTest.Test::Method1() + IL_0061: ret + } // end of method Test::Method2 + + .method private hidebysig static + int32 Main() il managed + { + .entrypoint + // Code size 40 (0x28) + .maxstack 2 + .locals (int32 V_0) + IL_0000: call native unsigned int JitTest.Test::Method2() + IL_0005: ldc.i4.s 10 + IL_0007: beq.s IL_0017 + + IL_0009: ldstr "failed" + IL_000e: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_0013: ldc.i4.1 + IL_0014: stloc.0 + IL_0015: br.s IL_0026 + + IL_0017: ldstr "passed" + IL_001c: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_0021: ldc.i4.s 100 + IL_0023: stloc.0 + IL_0024: br.s IL_0026 + + IL_0026: ldloc.0 + IL_0027: ret + } // end of method Test::Main + + .method public hidebysig specialname rtspecialname + instance void .ctor() il managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method Test::.ctor + + } // end of class Test + +} // end of namespace JitTest diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/compat_i_u2.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/compat_i_u2.il new file mode 100644 index 0000000000..656386e5e3 --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/compat_i_u2.il @@ -0,0 +1,108 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly compat_i_u2 { } +.namespace JitTest +{ + .class private auto ansi beforefieldinit Test + extends [mscorlib]System.Object + { + .method private hidebysig static + native int Method1() il managed + { + // Code size 93 (0x5d) + .maxstack 8 + IL_0000: call void [mscorlib]System.GC::Collect() + IL_0005: call void [mscorlib]System.GC::Collect() + IL_000a: call void [mscorlib]System.GC::Collect() + IL_000f: call void [mscorlib]System.GC::Collect() + IL_0014: call void [mscorlib]System.GC::Collect() + IL_0019: call void [mscorlib]System.GC::Collect() + IL_001e: call void [mscorlib]System.GC::Collect() + IL_0023: call void [mscorlib]System.GC::Collect() + IL_0028: call void [mscorlib]System.GC::Collect() + IL_002d: call void [mscorlib]System.GC::Collect() + IL_0032: call void [mscorlib]System.GC::Collect() + IL_0037: call void [mscorlib]System.GC::Collect() + IL_003c: call void [mscorlib]System.GC::Collect() + IL_0041: call void [mscorlib]System.GC::Collect() + IL_0046: call void [mscorlib]System.GC::Collect() + IL_004b: call void [mscorlib]System.GC::Collect() + IL_0050: call void [mscorlib]System.GC::Collect() + IL_0055: call void [mscorlib]System.GC::Collect() + IL_005a: ldc.i4.s 10 + IL_005c: ret + } // end of method Test::Method1 + + .method private hidebysig static + unsigned int16 Method2() il managed + { + // Code size 98 (0x62) + .maxstack 8 + IL_0000: call void [mscorlib]System.GC::Collect() + IL_0005: call void [mscorlib]System.GC::Collect() + IL_000a: call void [mscorlib]System.GC::Collect() + IL_000f: call void [mscorlib]System.GC::Collect() + IL_0014: call void [mscorlib]System.GC::Collect() + IL_0019: call void [mscorlib]System.GC::Collect() + IL_001e: call void [mscorlib]System.GC::Collect() + IL_0023: call void [mscorlib]System.GC::Collect() + IL_0028: call void [mscorlib]System.GC::Collect() + IL_002d: call void [mscorlib]System.GC::Collect() + IL_0032: call void [mscorlib]System.GC::Collect() + IL_0037: call void [mscorlib]System.GC::Collect() + IL_003c: call void [mscorlib]System.GC::Collect() + IL_0041: call void [mscorlib]System.GC::Collect() + IL_0046: call void [mscorlib]System.GC::Collect() + IL_004b: call void [mscorlib]System.GC::Collect() + IL_0050: call void [mscorlib]System.GC::Collect() + IL_0055: call void [mscorlib]System.GC::Collect() + IL_005a: tail. + IL_005c: call native int JitTest.Test::Method1() + IL_0061: ret + } // end of method Test::Method2 + + .method private hidebysig static + int32 Main() il managed + { + .entrypoint + // Code size 40 (0x28) + .maxstack 2 + .locals (int32 V_0) + IL_0000: call unsigned int16 JitTest.Test::Method2() + IL_0005: ldc.i4.s 10 + IL_0007: beq.s IL_0017 + + IL_0009: ldstr "failed" + IL_000e: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_0013: ldc.i4.1 + IL_0014: stloc.0 + IL_0015: br.s IL_0026 + + IL_0017: ldstr "passed" + IL_001c: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_0021: ldc.i4.s 100 + IL_0023: stloc.0 + IL_0024: br.s IL_0026 + + IL_0026: ldloc.0 + IL_0027: ret + } // end of method Test::Main + + .method public hidebysig specialname rtspecialname + instance void .ctor() il managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method Test::.ctor + + } // end of class Test + +} // end of namespace JitTest + +//*********** DISASSEMBLY COMPLETE *********************** diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/compat_obj.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/compat_obj.il new file mode 100644 index 0000000000..163b7ba33d --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/compat_obj.il @@ -0,0 +1,87 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly compat_obj { } +.namespace JitTest +{ + .class public auto ansi beforefieldinit BaseClass + extends [mscorlib]System.Object + { + .method public hidebysig static + class JitTest.BaseClass caller(bool which) il managed + { + // Code size 18 (0x12) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: brfalse.s IL_000a + + IL_0003: newobj instance void JitTest.BaseClass::.ctor() + IL_0008: br.s IL_0011 + + IL_000a: tail. + IL_000c: call class JitTest.DerivedClass JitTest.DerivedClass::callee() + IL_0011: ret + } // end of method BaseClass::caller + + .method public hidebysig specialname rtspecialname + instance void .ctor() il managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method BaseClass::.ctor + + } // end of class BaseClass + + .class public auto ansi beforefieldinit DerivedClass + extends JitTest.BaseClass + { + .method public hidebysig static + class JitTest.DerivedClass callee() il managed + { + // Code size 6 (0x6) + .maxstack 8 + IL_0000: newobj instance void JitTest.DerivedClass::.ctor() + IL_0005: ret + } // end of method DerivedClass::callee + + .method public hidebysig static + int32 Main() il managed + { + .entrypoint + // Code size 39 (0x27) + .maxstack 1 + .locals (int32 V_0) + IL_0000: ldc.i4.0 + IL_0001: call class JitTest.BaseClass JitTest.BaseClass::caller(bool) + IL_0006: call void [mscorlib]System.Console::WriteLine(class System.Object) + IL_000b: ldc.i4.1 + IL_000c: call class JitTest.BaseClass JitTest.BaseClass::caller(bool) + IL_0011: call void [mscorlib]System.Console::WriteLine(class System.Object) + IL_0016: ldstr "passed" + IL_001b: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_0020: ldc.i4.s 100 + IL_0022: stloc.0 + IL_0023: br.s IL_0025 + + IL_0025: ldloc.0 + IL_0026: ret + } // end of method DerivedClass::Main + + .method public hidebysig specialname rtspecialname + instance void .ctor() il managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void JitTest.BaseClass::.ctor() + IL_0006: ret + } // end of method DerivedClass::.ctor + + } // end of class DerivedClass + +} // end of namespace JitTest diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/compat_r4_r8.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/compat_r4_r8.il new file mode 100644 index 0000000000..97b51de176 --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/compat_r4_r8.il @@ -0,0 +1,101 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly compat_r4_r8 { } +.namespace JitTest +{ + .class private auto ansi beforefieldinit Test + extends [mscorlib]System.Object + { + .method private hidebysig static + float32 Method1() il managed + { + .maxstack 8 + IL_0000: call void [mscorlib]System.GC::Collect() + IL_0005: call void [mscorlib]System.GC::Collect() + IL_000a: call void [mscorlib]System.GC::Collect() + IL_000f: call void [mscorlib]System.GC::Collect() + IL_0014: call void [mscorlib]System.GC::Collect() + IL_0019: call void [mscorlib]System.GC::Collect() + IL_001e: call void [mscorlib]System.GC::Collect() + IL_0023: call void [mscorlib]System.GC::Collect() + IL_0028: call void [mscorlib]System.GC::Collect() + IL_002d: call void [mscorlib]System.GC::Collect() + IL_0032: call void [mscorlib]System.GC::Collect() + IL_0037: call void [mscorlib]System.GC::Collect() + IL_003c: call void [mscorlib]System.GC::Collect() + IL_0041: call void [mscorlib]System.GC::Collect() + IL_0046: call void [mscorlib]System.GC::Collect() + IL_004b: call void [mscorlib]System.GC::Collect() + IL_0050: call void [mscorlib]System.GC::Collect() + IL_0055: call void [mscorlib]System.GC::Collect() + IL_005a: ldc.r4 10. + IL_005f: ret + } + + .method private hidebysig static + float64 Method2() il managed + { + .maxstack 8 + IL_0000: call void [mscorlib]System.GC::Collect() + IL_0005: call void [mscorlib]System.GC::Collect() + IL_000a: call void [mscorlib]System.GC::Collect() + IL_000f: call void [mscorlib]System.GC::Collect() + IL_0014: call void [mscorlib]System.GC::Collect() + IL_0019: call void [mscorlib]System.GC::Collect() + IL_001e: call void [mscorlib]System.GC::Collect() + IL_0023: call void [mscorlib]System.GC::Collect() + IL_0028: call void [mscorlib]System.GC::Collect() + IL_002d: call void [mscorlib]System.GC::Collect() + IL_0032: call void [mscorlib]System.GC::Collect() + IL_0037: call void [mscorlib]System.GC::Collect() + IL_003c: call void [mscorlib]System.GC::Collect() + IL_0041: call void [mscorlib]System.GC::Collect() + IL_0046: call void [mscorlib]System.GC::Collect() + IL_004b: call void [mscorlib]System.GC::Collect() + IL_0050: call void [mscorlib]System.GC::Collect() + IL_0055: call void [mscorlib]System.GC::Collect() + IL_005a: tail. + IL_005c: call float32 JitTest.Test::Method1() + IL_0061: ret + } + + .method private hidebysig static + int32 Main() il managed + { + .entrypoint + .maxstack 8 + .locals (int32 V_0) + IL_0000: call float64 JitTest.Test::Method2() + IL_0005: dup + IL_0006: ldc.r8 10. + IL_000f: beq.s IL_001a + + IL_0011: call void [mscorlib]System.Console::WriteLine(float64) + IL_0016: ldc.i4.1 + IL_0017: stloc.0 + IL_0018: br.s IL_002a + + IL_001a: pop + IL_001b: ldstr "passed" + IL_0020: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_0025: ldc.i4.s 100 + IL_0027: stloc.0 + IL_0028: br.s IL_002a + + IL_002a: ldloc.0 + IL_002b: ret + } + + .method public hidebysig specialname rtspecialname + instance void .ctor() il managed + { + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } + } +} diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/compat_r4_r8_inl.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/compat_r4_r8_inl.il new file mode 100644 index 0000000000..b323c21be5 --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/compat_r4_r8_inl.il @@ -0,0 +1,67 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly compat_r4_r8_inl { } +.namespace JitTest +{ + .class private auto ansi beforefieldinit Test + extends [mscorlib]System.Object + { + .method private hidebysig static + float32 Method1() il managed + { + .maxstack 8 + IL_0000: ldc.r4 10. + IL_0005: ret + } + + .method private hidebysig static + float64 Method2() il managed + { + .maxstack 8 + IL_0000: tail. + IL_0002: call float32 JitTest.Test::Method1() + IL_0007: ret + } + + .method private hidebysig static + int32 Main() il managed + { + .entrypoint + .maxstack 8 + .locals (int32 V_0) + IL_0000: call float64 JitTest.Test::Method2() + IL_0005: dup + IL_0006: ldc.r8 10. + IL_000f: beq.s IL_001a + + IL_0011: call void [mscorlib]System.Console::WriteLine(float64) + IL_0016: ldc.i4.1 + IL_0017: stloc.0 + IL_0018: br.s IL_002a + + IL_001a: pop + IL_001b: ldstr "passed" + IL_0020: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_0025: ldc.i4.s 100 + IL_0027: stloc.0 + IL_0028: br.s IL_002a + + IL_002a: ldloc.0 + IL_002b: ret + } + + .method public hidebysig specialname rtspecialname + instance void .ctor() il managed + { + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } + + } + +} diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/compat_r8_r4.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/compat_r8_r4.il new file mode 100644 index 0000000000..156a6b28d4 --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/compat_r8_r4.il @@ -0,0 +1,101 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly compat_r8_r4 { } +.namespace JitTest +{ + .class private auto ansi beforefieldinit Test + extends [mscorlib]System.Object + { + .method private hidebysig static + float64 Method1() il managed + { + .maxstack 8 + IL_0000: call void [mscorlib]System.GC::Collect() + IL_0005: call void [mscorlib]System.GC::Collect() + IL_000a: call void [mscorlib]System.GC::Collect() + IL_000f: call void [mscorlib]System.GC::Collect() + IL_0014: call void [mscorlib]System.GC::Collect() + IL_0019: call void [mscorlib]System.GC::Collect() + IL_001e: call void [mscorlib]System.GC::Collect() + IL_0023: call void [mscorlib]System.GC::Collect() + IL_0028: call void [mscorlib]System.GC::Collect() + IL_002d: call void [mscorlib]System.GC::Collect() + IL_0032: call void [mscorlib]System.GC::Collect() + IL_0037: call void [mscorlib]System.GC::Collect() + IL_003c: call void [mscorlib]System.GC::Collect() + IL_0041: call void [mscorlib]System.GC::Collect() + IL_0046: call void [mscorlib]System.GC::Collect() + IL_004b: call void [mscorlib]System.GC::Collect() + IL_0050: call void [mscorlib]System.GC::Collect() + IL_0055: call void [mscorlib]System.GC::Collect() + IL_005a: ldc.r8 10. + IL_0063: ret + } + + .method private hidebysig static + float32 Method2() il managed + { + .maxstack 8 + IL_0000: call void [mscorlib]System.GC::Collect() + IL_0005: call void [mscorlib]System.GC::Collect() + IL_000a: call void [mscorlib]System.GC::Collect() + IL_000f: call void [mscorlib]System.GC::Collect() + IL_0014: call void [mscorlib]System.GC::Collect() + IL_0019: call void [mscorlib]System.GC::Collect() + IL_001e: call void [mscorlib]System.GC::Collect() + IL_0023: call void [mscorlib]System.GC::Collect() + IL_0028: call void [mscorlib]System.GC::Collect() + IL_002d: call void [mscorlib]System.GC::Collect() + IL_0032: call void [mscorlib]System.GC::Collect() + IL_0037: call void [mscorlib]System.GC::Collect() + IL_003c: call void [mscorlib]System.GC::Collect() + IL_0041: call void [mscorlib]System.GC::Collect() + IL_0046: call void [mscorlib]System.GC::Collect() + IL_004b: call void [mscorlib]System.GC::Collect() + IL_0050: call void [mscorlib]System.GC::Collect() + IL_0055: call void [mscorlib]System.GC::Collect() + IL_005a: tail. + IL_005c: call float64 JitTest.Test::Method1() + IL_0061: ret + } + + .method private hidebysig static + int32 Main() il managed + { + .entrypoint + .maxstack 8 + .locals (int32 V_0) + IL_0000: call float32 JitTest.Test::Method2() + IL_0005: dup + IL_0006: ldc.r4 10. + IL_000b: beq.s IL_0016 + + IL_000d: call void [mscorlib]System.Console::WriteLine(float32) + IL_0012: ldc.i4.1 + IL_0013: stloc.0 + IL_0014: br.s IL_0026 + + IL_0016: pop + IL_0017: ldstr "passed" + IL_001c: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_0021: ldc.i4.s 100 + IL_0023: stloc.0 + IL_0024: br.s IL_0026 + + IL_0026: ldloc.0 + IL_0027: ret + } + + .method public hidebysig specialname rtspecialname + instance void .ctor() il managed + { + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } + } +} diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/compat_r8_r4_inl.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/compat_r8_r4_inl.il new file mode 100644 index 0000000000..2261fb888e --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/compat_r8_r4_inl.il @@ -0,0 +1,65 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly compat_r8_r4_inl { } +.namespace JitTest +{ + .class private auto ansi beforefieldinit Test + extends [mscorlib]System.Object + { + .method private hidebysig static + float64 Method1() il managed + { + .maxstack 8 + IL_0000: ldc.r8 10. + IL_0009: ret + } + + .method private hidebysig static + float32 Method2() il managed + { + .maxstack 8 + IL_0000: tail. + IL_0002: call float64 JitTest.Test::Method1() + IL_0007: ret + } + + .method private hidebysig static + int32 Main() il managed + { + .entrypoint + .maxstack 8 + .locals (int32 V_0) + IL_0000: call float32 JitTest.Test::Method2() + IL_0005: dup + IL_0006: ldc.r4 10. + IL_000b: beq.s IL_0016 + + IL_000d: call void [mscorlib]System.Console::WriteLine(float32) + IL_0012: ldc.i4.1 + IL_0013: stloc.0 + IL_0014: br.s IL_0026 + + IL_0016: pop + IL_0017: ldstr "passed" + IL_001c: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_0021: ldc.i4.s 100 + IL_0023: stloc.0 + IL_0024: br.s IL_0026 + + IL_0026: ldloc.0 + IL_0027: ret + } + + .method public hidebysig specialname rtspecialname + instance void .ctor() il managed + { + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } + } +} diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/compat_v.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/compat_v.il new file mode 100644 index 0000000000..eca7c3be17 --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/compat_v.il @@ -0,0 +1,82 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly compat_v { } +.namespace JitTest +{ + .class public sequential ansi sealed beforefieldinit BaseStruct + extends [mscorlib]System.ValueType + { + .pack 1 + .size 1024 + .method public hidebysig static + value class JitTest.BaseStruct + caller(bool which) il managed + { + // Code size 22 (0x16) + .maxstack 1 + .locals (value class JitTest.BaseStruct V_0, + value class JitTest.BaseStruct V_1) + IL_0000: ldarg.0 + IL_0001: brfalse.s IL_000e + + IL_0003: ldloca.s V_1 + IL_0005: initobj JitTest.BaseStruct + IL_000b: ldloc.1 + IL_000c: br.s IL_0015 + + IL_000e: tail. + IL_0010: call value class JitTest.BaseStruct JitTest.BaseStruct::callee() + IL_0015: ret + } // end of method BaseStruct::caller + + .method public hidebysig static + value class JitTest.BaseStruct + callee() il managed + { + // Code size 14 (0xe) + .maxstack 1 + .locals (value class JitTest.BaseStruct V_0, + value class JitTest.BaseStruct V_1) + IL_0000: ldloca.s V_1 + IL_0002: initobj JitTest.BaseStruct + IL_0008: ldloc.1 + IL_0009: stloc.0 + IL_000a: br.s IL_000c + + IL_000c: ldloc.0 + IL_000d: ret + } // end of method BaseStruct::callee + + .method public hidebysig static + int32 Main() il managed + { + .entrypoint + // Code size 55 (0x37) + .maxstack 1 + .locals (int32 V_0) + IL_0000: ldc.i4.0 + IL_0001: call value class JitTest.BaseStruct JitTest.BaseStruct::caller(bool) + //IL_0006: stloc.1 + //IL_0007: ldloc.s V_1 + IL_0009: box JitTest.BaseStruct + IL_000e: call void [mscorlib]System.Console::WriteLine(class System.Object) + IL_0013: ldc.i4.1 + IL_0014: call value class JitTest.BaseStruct JitTest.BaseStruct::caller(bool) + //IL_0019: stloc.1 + //IL_001a: ldloc.s V_1 + IL_001c: box JitTest.BaseStruct + IL_0021: call void [mscorlib]System.Console::WriteLine(class System.Object) + IL_0026: ldstr "passed" + IL_002b: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_0030: ldc.i4.s 100 + ret + } // end of method BaseStruct::Main + + } // end of class BaseStruct + +} // end of namespace JitTest + +//*********** DISASSEMBLY COMPLETE *********************** diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/deep_array.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/deep_array.il new file mode 100644 index 0000000000..962c2ba3de --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/deep_array.il @@ -0,0 +1,936 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly deep_array { } +.namespace JitTest +{ + .class public auto ansi beforefieldinit TestClass extends [mscorlib]System.Object + { +//-----BEGIN AUTO GENERATED CODE-----// +.method private hidebysig static class [mscorlib]System.String Method0(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 2 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method1(int32[]) + ldstr " 2" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method1(int32[]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method1(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 3 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method2(int32[]) + ldstr " 3" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method2(int32[]) +} +.method private hidebysig static class [mscorlib]System.String Method2(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 4 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method3(int32[]) + ldstr " 4" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method3(int32[]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method3(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 5 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method4(int32[]) + ldstr " 5" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method4(int32[]) +} +.method private hidebysig static class [mscorlib]System.String Method4(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 6 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method5(int32[]) + ldstr " 6" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method5(int32[]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method5(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 7 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method6(int32[]) + ldstr " 7" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method6(int32[]) +} +.method private hidebysig static class [mscorlib]System.String Method6(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 8 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method7(int32[]) + ldstr " 8" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method7(int32[]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method7(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 9 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method8(int32[]) + ldstr " 9" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method8(int32[]) +} +.method private hidebysig static class [mscorlib]System.String Method8(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 10 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method9(int32[]) + ldstr " 10" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method9(int32[]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method9(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 11 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method10(int32[]) + ldstr " 11" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method10(int32[]) +} +.method private hidebysig static class [mscorlib]System.String Method10(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 12 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method11(int32[]) + ldstr " 12" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method11(int32[]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method11(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 13 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method12(int32[]) + ldstr " 13" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method12(int32[]) +} +.method private hidebysig static class [mscorlib]System.String Method12(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 14 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method13(int32[]) + ldstr " 14" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method13(int32[]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method13(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 15 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method14(int32[]) + ldstr " 15" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method14(int32[]) +} +.method private hidebysig static class [mscorlib]System.String Method14(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 16 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method15(int32[]) + ldstr " 16" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method15(int32[]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method15(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 17 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method16(int32[]) + ldstr " 17" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method16(int32[]) +} +.method private hidebysig static class [mscorlib]System.String Method16(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 18 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method17(int32[]) + ldstr " 18" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method17(int32[]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method17(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 19 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method18(int32[]) + ldstr " 19" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method18(int32[]) +} +.method private hidebysig static class [mscorlib]System.String Method18(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 20 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method19(int32[]) + ldstr " 20" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method19(int32[]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method19(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 21 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method20(int32[]) + ldstr " 21" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method20(int32[]) +} +.method private hidebysig static class [mscorlib]System.String Method20(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 22 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method21(int32[]) + ldstr " 22" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method21(int32[]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method21(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 23 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method22(int32[]) + ldstr " 23" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method22(int32[]) +} +.method private hidebysig static class [mscorlib]System.String Method22(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 24 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method23(int32[]) + ldstr " 24" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method23(int32[]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method23(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 25 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method24(int32[]) + ldstr " 25" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method24(int32[]) +} +.method private hidebysig static class [mscorlib]System.String Method24(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 26 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method25(int32[]) + ldstr " 26" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method25(int32[]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method25(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 27 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method26(int32[]) + ldstr " 27" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method26(int32[]) +} +.method private hidebysig static class [mscorlib]System.String Method26(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 28 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method27(int32[]) + ldstr " 28" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method27(int32[]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method27(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 29 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method28(int32[]) + ldstr " 29" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method28(int32[]) +} +.method private hidebysig static class [mscorlib]System.String Method28(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 30 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method29(int32[]) + ldstr " 30" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method29(int32[]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method29(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 31 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method30(int32[]) + ldstr " 31" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method30(int32[]) +} +.method private hidebysig static class [mscorlib]System.String Method30(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 32 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method31(int32[]) + ldstr " 32" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method31(int32[]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method31(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 33 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method32(int32[]) + ldstr " 33" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method32(int32[]) +} +.method private hidebysig static class [mscorlib]System.String Method32(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 34 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method33(int32[]) + ldstr " 34" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method33(int32[]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method33(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 35 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method34(int32[]) + ldstr " 35" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method34(int32[]) +} +.method private hidebysig static class [mscorlib]System.String Method34(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 36 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method35(int32[]) + ldstr " 36" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method35(int32[]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method35(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 37 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method36(int32[]) + ldstr " 37" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method36(int32[]) +} +.method private hidebysig static class [mscorlib]System.String Method36(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 38 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method37(int32[]) + ldstr " 38" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method37(int32[]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method37(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 39 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method38(int32[]) + ldstr " 39" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method38(int32[]) +} +.method private hidebysig static class [mscorlib]System.String Method38(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 40 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method39(int32[]) + ldstr " 40" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method39(int32[]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method39(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 41 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method40(int32[]) + ldstr " 41" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method40(int32[]) +} +.method private hidebysig static class [mscorlib]System.String Method40(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 42 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method41(int32[]) + ldstr " 42" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method41(int32[]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method41(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 43 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method42(int32[]) + ldstr " 43" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method42(int32[]) +} +.method private hidebysig static class [mscorlib]System.String Method42(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 44 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method43(int32[]) + ldstr " 44" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method43(int32[]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method43(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 45 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method44(int32[]) + ldstr " 45" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method44(int32[]) +} +.method private hidebysig static class [mscorlib]System.String Method44(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 46 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method45(int32[]) + ldstr " 46" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method45(int32[]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method45(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 47 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method46(int32[]) + ldstr " 47" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method46(int32[]) +} +.method private hidebysig static class [mscorlib]System.String Method46(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 48 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method47(int32[]) + ldstr " 48" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method47(int32[]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method47(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 49 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method48(int32[]) + ldstr " 49" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method48(int32[]) +} +.method private hidebysig static class [mscorlib]System.String Method48(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 50 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method49(int32[]) + ldstr " 50" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method49(int32[]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method49(int32[]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4.0 + ldelem.i4 + ldc.i4 51 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method50(int32[]) + ldstr " 51" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method50(int32[]) +} +//-----END AUTO GENERATED CODE-----// + + .method private hidebysig static class System.String Method50(int32[]) il managed + { + .maxstack 8 + ldnull + ret + } + + .method private hidebysig static + int32 Main() il managed + { + .entrypoint + // Code size 78 (0x4e) + .maxstack 8 + .locals (int32[]) + ldc.i4.1 + newarr int32 + stloc.0 + + ldloc.0 + ldc.i4.0 + ldc.i4.2 + stelem.i4 + +IL_0007: + ldloc.0 + call class System.String JitTest.TestClass::Method0(int32[]) + brtrue IL_0027 + + ldloc.0 + ldc.i4.0 + ldelem.i4 + call void [mscorlib]System.Console::Write(int32) + ldstr " - prime!" + call void [mscorlib]System.Console::WriteLine(class System.String) + +IL_0027: + ldloc.0 + ldc.i4.0 + ldloc.0 + ldc.i4.0 + ldelem.i4 + ldc.i4.1 + add + stelem.i4 + + ldloc.0 + ldc.i4.0 + ldelem.i4 + ldc.i4 0x64 + ceq + brfalse IL_0007 + + ldloc.0 + ldc.i4.0 + ldelem.i4 + ret + } // end of method TestClass::Main + + .method public hidebysig specialname rtspecialname + instance void .ctor(int32 A_0) il managed + { + // Code size 14 (0xe) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_000d: ret + } // end of method TestClass::.ctor + + } // end of class TestClass + +} // end of namespace JitTest + +//*********** DISASSEMBLY COMPLETE *********************** diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/deep_array_nz.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/deep_array_nz.il new file mode 100644 index 0000000000..93209068fc --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/deep_array_nz.il @@ -0,0 +1,935 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly deep_array_nz { } +.namespace JitTest +{ + .class public auto ansi beforefieldinit TestClass extends [mscorlib]System.Object + { +//-----BEGIN AUTO GENERATED CODE-----// +.method private hidebysig static class [mscorlib]System.String Method0(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 2 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method1(int32[100...]) + ldstr " 2" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method1(int32[100...]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method1(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 3 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method2(int32[100...]) + ldstr " 3" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method2(int32[100...]) +} +.method private hidebysig static class [mscorlib]System.String Method2(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 4 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method3(int32[100...]) + ldstr " 4" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method3(int32[100...]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method3(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 5 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method4(int32[100...]) + ldstr " 5" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method4(int32[100...]) +} +.method private hidebysig static class [mscorlib]System.String Method4(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 6 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method5(int32[100...]) + ldstr " 6" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method5(int32[100...]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method5(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 7 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method6(int32[100...]) + ldstr " 7" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method6(int32[100...]) +} +.method private hidebysig static class [mscorlib]System.String Method6(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 8 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method7(int32[100...]) + ldstr " 8" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method7(int32[100...]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method7(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 9 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method8(int32[100...]) + ldstr " 9" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method8(int32[100...]) +} +.method private hidebysig static class [mscorlib]System.String Method8(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 10 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method9(int32[100...]) + ldstr " 10" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method9(int32[100...]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method9(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 11 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method10(int32[100...]) + ldstr " 11" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method10(int32[100...]) +} +.method private hidebysig static class [mscorlib]System.String Method10(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 12 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method11(int32[100...]) + ldstr " 12" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method11(int32[100...]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method11(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 13 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method12(int32[100...]) + ldstr " 13" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method12(int32[100...]) +} +.method private hidebysig static class [mscorlib]System.String Method12(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 14 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method13(int32[100...]) + ldstr " 14" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method13(int32[100...]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method13(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 15 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method14(int32[100...]) + ldstr " 15" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method14(int32[100...]) +} +.method private hidebysig static class [mscorlib]System.String Method14(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 16 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method15(int32[100...]) + ldstr " 16" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method15(int32[100...]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method15(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 17 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method16(int32[100...]) + ldstr " 17" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method16(int32[100...]) +} +.method private hidebysig static class [mscorlib]System.String Method16(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 18 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method17(int32[100...]) + ldstr " 18" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method17(int32[100...]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method17(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 19 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method18(int32[100...]) + ldstr " 19" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method18(int32[100...]) +} +.method private hidebysig static class [mscorlib]System.String Method18(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 20 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method19(int32[100...]) + ldstr " 20" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method19(int32[100...]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method19(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 21 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method20(int32[100...]) + ldstr " 21" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method20(int32[100...]) +} +.method private hidebysig static class [mscorlib]System.String Method20(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 22 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method21(int32[100...]) + ldstr " 22" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method21(int32[100...]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method21(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 23 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method22(int32[100...]) + ldstr " 23" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method22(int32[100...]) +} +.method private hidebysig static class [mscorlib]System.String Method22(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 24 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method23(int32[100...]) + ldstr " 24" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method23(int32[100...]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method23(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 25 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method24(int32[100...]) + ldstr " 25" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method24(int32[100...]) +} +.method private hidebysig static class [mscorlib]System.String Method24(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 26 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method25(int32[100...]) + ldstr " 26" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method25(int32[100...]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method25(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 27 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method26(int32[100...]) + ldstr " 27" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method26(int32[100...]) +} +.method private hidebysig static class [mscorlib]System.String Method26(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 28 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method27(int32[100...]) + ldstr " 28" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method27(int32[100...]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method27(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 29 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method28(int32[100...]) + ldstr " 29" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method28(int32[100...]) +} +.method private hidebysig static class [mscorlib]System.String Method28(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 30 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method29(int32[100...]) + ldstr " 30" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method29(int32[100...]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method29(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 31 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method30(int32[100...]) + ldstr " 31" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method30(int32[100...]) +} +.method private hidebysig static class [mscorlib]System.String Method30(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 32 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method31(int32[100...]) + ldstr " 32" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method31(int32[100...]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method31(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 33 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method32(int32[100...]) + ldstr " 33" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method32(int32[100...]) +} +.method private hidebysig static class [mscorlib]System.String Method32(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 34 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method33(int32[100...]) + ldstr " 34" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method33(int32[100...]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method33(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 35 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method34(int32[100...]) + ldstr " 35" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method34(int32[100...]) +} +.method private hidebysig static class [mscorlib]System.String Method34(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 36 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method35(int32[100...]) + ldstr " 36" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method35(int32[100...]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method35(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 37 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method36(int32[100...]) + ldstr " 37" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method36(int32[100...]) +} +.method private hidebysig static class [mscorlib]System.String Method36(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 38 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method37(int32[100...]) + ldstr " 38" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method37(int32[100...]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method37(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 39 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method38(int32[100...]) + ldstr " 39" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method38(int32[100...]) +} +.method private hidebysig static class [mscorlib]System.String Method38(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 40 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method39(int32[100...]) + ldstr " 40" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method39(int32[100...]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method39(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 41 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method40(int32[100...]) + ldstr " 41" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method40(int32[100...]) +} +.method private hidebysig static class [mscorlib]System.String Method40(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 42 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method41(int32[100...]) + ldstr " 42" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method41(int32[100...]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method41(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 43 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method42(int32[100...]) + ldstr " 43" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method42(int32[100...]) +} +.method private hidebysig static class [mscorlib]System.String Method42(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 44 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method43(int32[100...]) + ldstr " 44" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method43(int32[100...]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method43(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 45 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method44(int32[100...]) + ldstr " 45" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method44(int32[100...]) +} +.method private hidebysig static class [mscorlib]System.String Method44(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 46 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method45(int32[100...]) + ldstr " 46" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method45(int32[100...]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method45(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 47 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method46(int32[100...]) + ldstr " 47" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method46(int32[100...]) +} +.method private hidebysig static class [mscorlib]System.String Method46(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 48 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method47(int32[100...]) + ldstr " 48" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method47(int32[100...]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method47(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 49 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method48(int32[100...]) + ldstr " 49" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method48(int32[100...]) +} +.method private hidebysig static class [mscorlib]System.String Method48(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 50 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method49(int32[100...]) + ldstr " 50" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + tail. call class [mscorlib]System.String JitTest.TestClass::Method49(int32[100...]) + ret +} +.method private hidebysig static class [mscorlib]System.String Method49(int32[100...]) il managed { + .maxstack 8 + ldarg.0 + dup + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 51 + rem + brtrue.s REM + call class [mscorlib]System.String JitTest.TestClass::Method50(int32[100...]) + ldstr " 51" + call class [mscorlib]System.String [mscorlib]System.String::Concat(class [mscorlib]System.String, class [mscorlib]System.String) + ret +REM: + pop + jmp class [mscorlib]System.String JitTest.TestClass::Method50(int32[100...]) +} +//-----END AUTO GENERATED CODE-----// + + .method private hidebysig static class System.String Method50(int32[100...]) il managed + { + .maxstack 8 + ldnull + ret + } + + .method private hidebysig static + int32 Main() il managed + { + .entrypoint + // Code size 78 (0x4e) + .maxstack 8 + .locals (int32[100...]) + ldc.i4 100 + ldc.i4.1 + newobj instance void int32[100...]::.ctor(int32, int32) + stloc.0 + + ldloc.0 + ldc.i4 100 + ldc.i4.2 + call instance void int32[100...]::Set(int32, int32) + +IL_0007: + ldloc.0 + call class System.String JitTest.TestClass::Method0(int32[100...]) + brtrue IL_0027 + + ldloc.0 + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + call void [mscorlib]System.Console::Write(int32) + ldstr " - prime!" + call void [mscorlib]System.Console::WriteLine(class System.String) + +IL_0027: + ldloc.0 + ldc.i4 100 + ldloc.0 + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4.1 + add + call instance void int32[100...]::Set(int32, int32) + + ldloc.0 + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ldc.i4 0x64 + ceq + brfalse IL_0007 + + ldloc.0 + ldc.i4 100 + call instance int32 int32[100...]::Get(int32) + ret + } // end of method TestClass::Main + + .method public hidebysig specialname rtspecialname + instance void .ctor(int32 A_0) il managed + { + // Code size 14 (0xe) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_000d: ret + } // end of method TestClass::.ctor + + } // end of class TestClass + +} // end of namespace JitTest diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/deep_gc.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/deep_gc.il new file mode 100644 index 0000000000..87ddd94fd1 --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/deep_gc.il @@ -0,0 +1,1198 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly deep_gc { } +.namespace JitTest +{ + .class public auto ansi beforefieldinit TestClass + extends [mscorlib]System.Object + { + .field public int32 m_fld + .method private hidebysig static + class System.String Method0(class JitTest.TestClass A_0) il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x2 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method1(class JitTest.TestClass) + IL_0014: ldstr " 2" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call class System.String JitTest.TestClass::Method1(class JitTest.TestClass) + IL_0026: ret + } // end of method TestClass::Method0 + + .method private hidebysig static + class System.String Method1(class JitTest.TestClass A_0) il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x3 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method2(class JitTest.TestClass) + IL_0014: ldstr " 3" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp class System.String JitTest.TestClass::Method2(class JitTest.TestClass) + } // end of method TestClass::Method1 + + .method private hidebysig static + class System.String Method2(class JitTest.TestClass A_0) il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x4 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method3(class JitTest.TestClass) + IL_0014: ldstr " 4" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call class System.String JitTest.TestClass::Method3(class JitTest.TestClass) + IL_0026: ret + } // end of method TestClass::Method2 + + .method private hidebysig static + class System.String Method3(class JitTest.TestClass A_0) il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x5 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method4(class JitTest.TestClass) + IL_0014: ldstr " 5" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp class System.String JitTest.TestClass::Method4(class JitTest.TestClass) + } // end of method TestClass::Method3 + + .method private hidebysig static + class System.String Method4(class JitTest.TestClass A_0) il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x6 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method5(class JitTest.TestClass) + IL_0014: ldstr " 6" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call class System.String JitTest.TestClass::Method5(class JitTest.TestClass) + IL_0026: ret + } // end of method TestClass::Method4 + + .method private hidebysig static + class System.String Method5(class JitTest.TestClass A_0) il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x7 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method6(class JitTest.TestClass) + IL_0014: ldstr " 7" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp class System.String JitTest.TestClass::Method6(class JitTest.TestClass) + } // end of method TestClass::Method5 + + .method private hidebysig static + class System.String Method6(class JitTest.TestClass A_0) il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x8 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method7(class JitTest.TestClass) + IL_0014: ldstr " 8" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call class System.String JitTest.TestClass::Method7(class JitTest.TestClass) + IL_0026: ret + } // end of method TestClass::Method6 + + .method private hidebysig static + class System.String Method7(class JitTest.TestClass A_0) il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x9 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method8(class JitTest.TestClass) + IL_0014: ldstr " 9" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp class System.String JitTest.TestClass::Method8(class JitTest.TestClass) + } // end of method TestClass::Method7 + + .method private hidebysig static + class System.String Method8(class JitTest.TestClass A_0) il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0xa + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method9(class JitTest.TestClass) + IL_0014: ldstr " 10" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call class System.String JitTest.TestClass::Method9(class JitTest.TestClass) + IL_0026: ret + } // end of method TestClass::Method8 + + .method private hidebysig static + class System.String Method9(class JitTest.TestClass A_0) il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0xb + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method10(class JitTest.TestClass) + IL_0014: ldstr " 11" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp class System.String JitTest.TestClass::Method10(class JitTest.TestClass) + } // end of method TestClass::Method9 + + .method private hidebysig static + class System.String Method10(class JitTest.TestClass A_0) il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0xc + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method11(class JitTest.TestClass) + IL_0014: ldstr " 12" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call class System.String JitTest.TestClass::Method11(class JitTest.TestClass) + IL_0026: ret + } // end of method TestClass::Method10 + + .method private hidebysig static + class System.String Method11(class JitTest.TestClass A_0) il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0xd + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method12(class JitTest.TestClass) + IL_0014: ldstr " 13" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp class System.String JitTest.TestClass::Method12(class JitTest.TestClass) + } // end of method TestClass::Method11 + + .method private hidebysig static + class System.String Method12(class JitTest.TestClass A_0) il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0xe + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method13(class JitTest.TestClass) + IL_0014: ldstr " 14" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call class System.String JitTest.TestClass::Method13(class JitTest.TestClass) + IL_0026: ret + } // end of method TestClass::Method12 + + .method private hidebysig static + class System.String Method13(class JitTest.TestClass A_0) il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0xf + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method14(class JitTest.TestClass) + IL_0014: ldstr " 15" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp class System.String JitTest.TestClass::Method14(class JitTest.TestClass) + } // end of method TestClass::Method13 + + .method private hidebysig static + class System.String Method14(class JitTest.TestClass A_0) il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x10 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method15(class JitTest.TestClass) + IL_0014: ldstr " 16" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call class System.String JitTest.TestClass::Method15(class JitTest.TestClass) + IL_0026: ret + } // end of method TestClass::Method14 + + .method private hidebysig static + class System.String Method15(class JitTest.TestClass A_0) il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x11 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method16(class JitTest.TestClass) + IL_0014: ldstr " 17" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp class System.String JitTest.TestClass::Method16(class JitTest.TestClass) + } // end of method TestClass::Method15 + + .method private hidebysig static + class System.String Method16(class JitTest.TestClass A_0) il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x12 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method17(class JitTest.TestClass) + IL_0014: ldstr " 18" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call class System.String JitTest.TestClass::Method17(class JitTest.TestClass) + IL_0026: ret + } // end of method TestClass::Method16 + + .method private hidebysig static + class System.String Method17(class JitTest.TestClass A_0) il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x13 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method18(class JitTest.TestClass) + IL_0014: ldstr " 19" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp class System.String JitTest.TestClass::Method18(class JitTest.TestClass) + } // end of method TestClass::Method17 + + .method private hidebysig static + class System.String Method18(class JitTest.TestClass A_0) il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x14 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method19(class JitTest.TestClass) + IL_0014: ldstr " 20" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call class System.String JitTest.TestClass::Method19(class JitTest.TestClass) + IL_0026: ret + } // end of method TestClass::Method18 + + .method private hidebysig static + class System.String Method19(class JitTest.TestClass A_0) il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x15 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method20(class JitTest.TestClass) + IL_0014: ldstr " 21" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp class System.String JitTest.TestClass::Method20(class JitTest.TestClass) + } // end of method TestClass::Method19 + + .method private hidebysig static + class System.String Method20(class JitTest.TestClass A_0) il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x16 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method21(class JitTest.TestClass) + IL_0014: ldstr " 22" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call class System.String JitTest.TestClass::Method21(class JitTest.TestClass) + IL_0026: ret + } // end of method TestClass::Method20 + + .method private hidebysig static + class System.String Method21(class JitTest.TestClass A_0) il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x17 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method22(class JitTest.TestClass) + IL_0014: ldstr " 23" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp class System.String JitTest.TestClass::Method22(class JitTest.TestClass) + } // end of method TestClass::Method21 + + .method private hidebysig static + class System.String Method22(class JitTest.TestClass A_0) il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x18 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method23(class JitTest.TestClass) + IL_0014: ldstr " 24" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call class System.String JitTest.TestClass::Method23(class JitTest.TestClass) + IL_0026: ret + } // end of method TestClass::Method22 + + .method private hidebysig static + class System.String Method23(class JitTest.TestClass A_0) il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x19 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method24(class JitTest.TestClass) + IL_0014: ldstr " 25" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp class System.String JitTest.TestClass::Method24(class JitTest.TestClass) + } // end of method TestClass::Method23 + + .method private hidebysig static + class System.String Method24(class JitTest.TestClass A_0) il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x1a + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method25(class JitTest.TestClass) + IL_0014: ldstr " 26" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call class System.String JitTest.TestClass::Method25(class JitTest.TestClass) + IL_0026: ret + } // end of method TestClass::Method24 + + .method private hidebysig static + class System.String Method25(class JitTest.TestClass A_0) il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x1b + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method26(class JitTest.TestClass) + IL_0014: ldstr " 27" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp class System.String JitTest.TestClass::Method26(class JitTest.TestClass) + } // end of method TestClass::Method25 + + .method private hidebysig static + class System.String Method26(class JitTest.TestClass A_0) il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x1c + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method27(class JitTest.TestClass) + IL_0014: ldstr " 28" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call class System.String JitTest.TestClass::Method27(class JitTest.TestClass) + IL_0026: ret + } // end of method TestClass::Method26 + + .method private hidebysig static + class System.String Method27(class JitTest.TestClass A_0) il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x1d + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method28(class JitTest.TestClass) + IL_0014: ldstr " 29" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp class System.String JitTest.TestClass::Method28(class JitTest.TestClass) + } // end of method TestClass::Method27 + + .method private hidebysig static + class System.String Method28(class JitTest.TestClass A_0) il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x1e + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method29(class JitTest.TestClass) + IL_0014: ldstr " 30" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call class System.String JitTest.TestClass::Method29(class JitTest.TestClass) + IL_0026: ret + } // end of method TestClass::Method28 + + .method private hidebysig static + class System.String Method29(class JitTest.TestClass A_0) il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x1f + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method30(class JitTest.TestClass) + IL_0014: ldstr " 31" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp class System.String JitTest.TestClass::Method30(class JitTest.TestClass) + } // end of method TestClass::Method29 + + .method private hidebysig static + class System.String Method30(class JitTest.TestClass A_0) il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x20 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method31(class JitTest.TestClass) + IL_0014: ldstr " 32" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call class System.String JitTest.TestClass::Method31(class JitTest.TestClass) + IL_0026: ret + } // end of method TestClass::Method30 + + .method private hidebysig static + class System.String Method31(class JitTest.TestClass A_0) il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x21 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method32(class JitTest.TestClass) + IL_0014: ldstr " 33" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp class System.String JitTest.TestClass::Method32(class JitTest.TestClass) + } // end of method TestClass::Method31 + + .method private hidebysig static + class System.String Method32(class JitTest.TestClass A_0) il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x22 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method33(class JitTest.TestClass) + IL_0014: ldstr " 34" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call class System.String JitTest.TestClass::Method33(class JitTest.TestClass) + IL_0026: ret + } // end of method TestClass::Method32 + + .method private hidebysig static + class System.String Method33(class JitTest.TestClass A_0) il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x23 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method34(class JitTest.TestClass) + IL_0014: ldstr " 35" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp class System.String JitTest.TestClass::Method34(class JitTest.TestClass) + } // end of method TestClass::Method33 + + .method private hidebysig static + class System.String Method34(class JitTest.TestClass A_0) il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x24 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method35(class JitTest.TestClass) + IL_0014: ldstr " 36" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call class System.String JitTest.TestClass::Method35(class JitTest.TestClass) + IL_0026: ret + } // end of method TestClass::Method34 + + .method private hidebysig static + class System.String Method35(class JitTest.TestClass A_0) il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x25 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method36(class JitTest.TestClass) + IL_0014: ldstr " 37" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp class System.String JitTest.TestClass::Method36(class JitTest.TestClass) + } // end of method TestClass::Method35 + + .method private hidebysig static + class System.String Method36(class JitTest.TestClass A_0) il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x26 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method37(class JitTest.TestClass) + IL_0014: ldstr " 38" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call class System.String JitTest.TestClass::Method37(class JitTest.TestClass) + IL_0026: ret + } // end of method TestClass::Method36 + + .method private hidebysig static + class System.String Method37(class JitTest.TestClass A_0) il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x27 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method38(class JitTest.TestClass) + IL_0014: ldstr " 39" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp class System.String JitTest.TestClass::Method38(class JitTest.TestClass) + } // end of method TestClass::Method37 + + .method private hidebysig static + class System.String Method38(class JitTest.TestClass A_0) il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x28 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method39(class JitTest.TestClass) + IL_0014: ldstr " 40" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call class System.String JitTest.TestClass::Method39(class JitTest.TestClass) + IL_0026: ret + } // end of method TestClass::Method38 + + .method private hidebysig static + class System.String Method39(class JitTest.TestClass A_0) il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x29 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method40(class JitTest.TestClass) + IL_0014: ldstr " 41" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp class System.String JitTest.TestClass::Method40(class JitTest.TestClass) + } // end of method TestClass::Method39 + + .method private hidebysig static + class System.String Method40(class JitTest.TestClass A_0) il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x2a + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method41(class JitTest.TestClass) + IL_0014: ldstr " 42" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call class System.String JitTest.TestClass::Method41(class JitTest.TestClass) + IL_0026: ret + } // end of method TestClass::Method40 + + .method private hidebysig static + class System.String Method41(class JitTest.TestClass A_0) il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x2b + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method42(class JitTest.TestClass) + IL_0014: ldstr " 43" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp class System.String JitTest.TestClass::Method42(class JitTest.TestClass) + } // end of method TestClass::Method41 + + .method private hidebysig static + class System.String Method42(class JitTest.TestClass A_0) il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x2c + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method43(class JitTest.TestClass) + IL_0014: ldstr " 44" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call class System.String JitTest.TestClass::Method43(class JitTest.TestClass) + IL_0026: ret + } // end of method TestClass::Method42 + + .method private hidebysig static + class System.String Method43(class JitTest.TestClass A_0) il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x2d + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method44(class JitTest.TestClass) + IL_0014: ldstr " 45" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp class System.String JitTest.TestClass::Method44(class JitTest.TestClass) + } // end of method TestClass::Method43 + + .method private hidebysig static + class System.String Method44(class JitTest.TestClass A_0) il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x2e + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method45(class JitTest.TestClass) + IL_0014: ldstr " 46" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call class System.String JitTest.TestClass::Method45(class JitTest.TestClass) + IL_0026: ret + } // end of method TestClass::Method44 + + .method private hidebysig static + class System.String Method45(class JitTest.TestClass A_0) il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x2f + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method46(class JitTest.TestClass) + IL_0014: ldstr " 47" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp class System.String JitTest.TestClass::Method46(class JitTest.TestClass) + } // end of method TestClass::Method45 + + .method private hidebysig static + class System.String Method46(class JitTest.TestClass A_0) il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x30 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method47(class JitTest.TestClass) + IL_0014: ldstr " 48" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call class System.String JitTest.TestClass::Method47(class JitTest.TestClass) + IL_0026: ret + } // end of method TestClass::Method46 + + .method private hidebysig static + class System.String Method47(class JitTest.TestClass A_0) il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x31 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method48(class JitTest.TestClass) + IL_0014: ldstr " 49" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp class System.String JitTest.TestClass::Method48(class JitTest.TestClass) + } // end of method TestClass::Method47 + + .method private hidebysig static + class System.String Method48(class JitTest.TestClass A_0) il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x32 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method49(class JitTest.TestClass) + IL_0014: ldstr " 50" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call class System.String JitTest.TestClass::Method49(class JitTest.TestClass) + IL_0026: ret + } // end of method TestClass::Method48 + + .method private hidebysig static + class System.String Method49(class JitTest.TestClass A_0) il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x33 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call class System.String JitTest.TestClass::Method50(class JitTest.TestClass) + IL_0014: ldstr " 51" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp class System.String JitTest.TestClass::Method50(class JitTest.TestClass) + } // end of method TestClass::Method49 + + .method private hidebysig static + class System.String Method50(class JitTest.TestClass A_0) il managed + { + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: ret + } // end of method TestClass::Method50 + + .method private hidebysig static + int32 Main() il managed + { + .entrypoint + // Code size 78 (0x4e) + .maxstack 8 + .locals (class JitTest.TestClass V_0) + IL_0000: ldc.i4.2 + IL_0001: newobj instance void JitTest.TestClass::.ctor(int32) + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: call class System.String JitTest.TestClass::Method0(class JitTest.TestClass) + IL_000d: brtrue IL_0027 + + IL_0012: ldloc.0 + IL_0013: ldfld int32 JitTest.TestClass::m_fld + IL_0018: call void [mscorlib]System.Console::Write(int32) + IL_001d: ldstr " - prime!" + IL_0022: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_0027: ldloc.0 + IL_0028: dup + IL_0029: ldfld int32 JitTest.TestClass::m_fld + IL_002e: ldc.i4.1 + IL_002f: add + IL_0030: stfld int32 JitTest.TestClass::m_fld + IL_0035: ldloc.0 + IL_0036: ldfld int32 JitTest.TestClass::m_fld + IL_003b: ldc.i4 0x64 + IL_0040: ceq + IL_0042: brfalse IL_0007 + + IL_0047: ldloc.0 + IL_0048: ldfld int32 JitTest.TestClass::m_fld + IL_004d: ret + } // end of method TestClass::Main + + .method public hidebysig specialname rtspecialname + instance void .ctor(int32 A_0) il managed + { + // Code size 14 (0xe) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ldarg.0 + IL_0007: ldarg.1 + IL_0008: stfld int32 JitTest.TestClass::m_fld + IL_000d: ret + } // end of method TestClass::.ctor + + } // end of class TestClass + +} // end of namespace JitTest diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/deep_inst.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/deep_inst.il new file mode 100644 index 0000000000..547e56c56d --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/deep_inst.il @@ -0,0 +1,1200 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly deep_inst { } +.namespace JitTest +{ + .class public auto ansi beforefieldinit TestClass + extends [mscorlib]System.Object + { + .field public int32 m_fld + .method private hidebysig instance class System.String + Method0() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x2 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method1() + IL_0014: ldstr " 2" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method1() + IL_0026: ret + } // end of method TestClass::Method0 + + .method private hidebysig instance class System.String + Method1() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x3 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method2() + IL_0014: ldstr " 3" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method2() + } // end of method TestClass::Method1 + + .method private hidebysig instance class System.String + Method2() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x4 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method3() + IL_0014: ldstr " 4" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method3() + IL_0026: ret + } // end of method TestClass::Method2 + + .method private hidebysig instance class System.String + Method3() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x5 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method4() + IL_0014: ldstr " 5" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method4() + } // end of method TestClass::Method3 + + .method private hidebysig instance class System.String + Method4() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x6 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method5() + IL_0014: ldstr " 6" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method5() + IL_0026: ret + } // end of method TestClass::Method4 + + .method private hidebysig instance class System.String + Method5() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x7 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method6() + IL_0014: ldstr " 7" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method6() + } // end of method TestClass::Method5 + + .method private hidebysig instance class System.String + Method6() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x8 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method7() + IL_0014: ldstr " 8" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method7() + IL_0026: ret + } // end of method TestClass::Method6 + + .method private hidebysig instance class System.String + Method7() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x9 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method8() + IL_0014: ldstr " 9" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method8() + } // end of method TestClass::Method7 + + .method private hidebysig instance class System.String + Method8() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0xa + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method9() + IL_0014: ldstr " 10" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method9() + IL_0026: ret + } // end of method TestClass::Method8 + + .method private hidebysig instance class System.String + Method9() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0xb + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method10() + IL_0014: ldstr " 11" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method10() + } // end of method TestClass::Method9 + + .method private hidebysig instance class System.String + Method10() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0xc + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method11() + IL_0014: ldstr " 12" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method11() + IL_0026: ret + } // end of method TestClass::Method10 + + .method private hidebysig instance class System.String + Method11() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0xd + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method12() + IL_0014: ldstr " 13" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method12() + } // end of method TestClass::Method11 + + .method private hidebysig instance class System.String + Method12() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0xe + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method13() + IL_0014: ldstr " 14" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method13() + IL_0026: ret + } // end of method TestClass::Method12 + + .method private hidebysig instance class System.String + Method13() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0xf + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method14() + IL_0014: ldstr " 15" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method14() + } // end of method TestClass::Method13 + + .method private hidebysig instance class System.String + Method14() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x10 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method15() + IL_0014: ldstr " 16" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method15() + IL_0026: ret + } // end of method TestClass::Method14 + + .method private hidebysig instance class System.String + Method15() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x11 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method16() + IL_0014: ldstr " 17" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method16() + } // end of method TestClass::Method15 + + .method private hidebysig instance class System.String + Method16() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x12 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method17() + IL_0014: ldstr " 18" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method17() + IL_0026: ret + } // end of method TestClass::Method16 + + .method private hidebysig instance class System.String + Method17() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x13 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method18() + IL_0014: ldstr " 19" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method18() + } // end of method TestClass::Method17 + + .method private hidebysig instance class System.String + Method18() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x14 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method19() + IL_0014: ldstr " 20" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method19() + IL_0026: ret + } // end of method TestClass::Method18 + + .method private hidebysig instance class System.String + Method19() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x15 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method20() + IL_0014: ldstr " 21" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method20() + } // end of method TestClass::Method19 + + .method private hidebysig instance class System.String + Method20() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x16 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method21() + IL_0014: ldstr " 22" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method21() + IL_0026: ret + } // end of method TestClass::Method20 + + .method private hidebysig instance class System.String + Method21() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x17 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method22() + IL_0014: ldstr " 23" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method22() + } // end of method TestClass::Method21 + + .method private hidebysig instance class System.String + Method22() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x18 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method23() + IL_0014: ldstr " 24" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method23() + IL_0026: ret + } // end of method TestClass::Method22 + + .method private hidebysig instance class System.String + Method23() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x19 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method24() + IL_0014: ldstr " 25" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method24() + } // end of method TestClass::Method23 + + .method private hidebysig instance class System.String + Method24() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x1a + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method25() + IL_0014: ldstr " 26" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method25() + IL_0026: ret + } // end of method TestClass::Method24 + + .method private hidebysig instance class System.String + Method25() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x1b + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method26() + IL_0014: ldstr " 27" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method26() + } // end of method TestClass::Method25 + + .method private hidebysig instance class System.String + Method26() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x1c + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method27() + IL_0014: ldstr " 28" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method27() + IL_0026: ret + } // end of method TestClass::Method26 + + .method private hidebysig instance class System.String + Method27() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x1d + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method28() + IL_0014: ldstr " 29" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method28() + } // end of method TestClass::Method27 + + .method private hidebysig instance class System.String + Method28() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x1e + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method29() + IL_0014: ldstr " 30" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method29() + IL_0026: ret + } // end of method TestClass::Method28 + + .method private hidebysig instance class System.String + Method29() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x1f + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method30() + IL_0014: ldstr " 31" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method30() + } // end of method TestClass::Method29 + + .method private hidebysig instance class System.String + Method30() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x20 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method31() + IL_0014: ldstr " 32" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method31() + IL_0026: ret + } // end of method TestClass::Method30 + + .method private hidebysig instance class System.String + Method31() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x21 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method32() + IL_0014: ldstr " 33" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method32() + } // end of method TestClass::Method31 + + .method private hidebysig instance class System.String + Method32() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x22 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method33() + IL_0014: ldstr " 34" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method33() + IL_0026: ret + } // end of method TestClass::Method32 + + .method private hidebysig instance class System.String + Method33() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x23 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method34() + IL_0014: ldstr " 35" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method34() + } // end of method TestClass::Method33 + + .method private hidebysig instance class System.String + Method34() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x24 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method35() + IL_0014: ldstr " 36" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method35() + IL_0026: ret + } // end of method TestClass::Method34 + + .method private hidebysig instance class System.String + Method35() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x25 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method36() + IL_0014: ldstr " 37" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method36() + } // end of method TestClass::Method35 + + .method private hidebysig instance class System.String + Method36() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x26 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method37() + IL_0014: ldstr " 38" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method37() + IL_0026: ret + } // end of method TestClass::Method36 + + .method private hidebysig instance class System.String + Method37() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x27 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method38() + IL_0014: ldstr " 39" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method38() + } // end of method TestClass::Method37 + + .method private hidebysig instance class System.String + Method38() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x28 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method39() + IL_0014: ldstr " 40" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method39() + IL_0026: ret + } // end of method TestClass::Method38 + + .method private hidebysig instance class System.String + Method39() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x29 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method40() + IL_0014: ldstr " 41" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method40() + } // end of method TestClass::Method39 + + .method private hidebysig instance class System.String + Method40() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x2a + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method41() + IL_0014: ldstr " 42" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method41() + IL_0026: ret + } // end of method TestClass::Method40 + + .method private hidebysig instance class System.String + Method41() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x2b + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method42() + IL_0014: ldstr " 43" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method42() + } // end of method TestClass::Method41 + + .method private hidebysig instance class System.String + Method42() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x2c + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method43() + IL_0014: ldstr " 44" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method43() + IL_0026: ret + } // end of method TestClass::Method42 + + .method private hidebysig instance class System.String + Method43() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x2d + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method44() + IL_0014: ldstr " 45" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method44() + } // end of method TestClass::Method43 + + .method private hidebysig instance class System.String + Method44() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x2e + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method45() + IL_0014: ldstr " 46" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method45() + IL_0026: ret + } // end of method TestClass::Method44 + + .method private hidebysig instance class System.String + Method45() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x2f + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method46() + IL_0014: ldstr " 47" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method46() + } // end of method TestClass::Method45 + + .method private hidebysig instance class System.String + Method46() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x30 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method47() + IL_0014: ldstr " 48" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method47() + IL_0026: ret + } // end of method TestClass::Method46 + + .method private hidebysig instance class System.String + Method47() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x31 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method48() + IL_0014: ldstr " 49" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method48() + } // end of method TestClass::Method47 + + .method private hidebysig instance class System.String + Method48() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x32 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method49() + IL_0014: ldstr " 50" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method49() + IL_0026: ret + } // end of method TestClass::Method48 + + .method private hidebysig instance class System.String + Method49() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x33 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method50() + IL_0014: ldstr " 51" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method50() + } // end of method TestClass::Method49 + + .method private hidebysig instance class System.String + Method50() il managed + { + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: ret + } // end of method TestClass::Method50 + + .method private hidebysig static + int32 Main() il managed + { + .entrypoint + // Code size 78 (0x4e) + .maxstack 8 + .locals (class JitTest.TestClass V_0) + IL_0000: ldc.i4.2 + IL_0001: newobj instance void JitTest.TestClass::.ctor(int32) + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: call instance class System.String JitTest.TestClass::Method0() + IL_000d: brtrue IL_0027 + + IL_0012: ldloc.0 + IL_0013: ldfld int32 JitTest.TestClass::m_fld + IL_0018: call void [mscorlib]System.Console::Write(int32) + IL_001d: ldstr " - prime!" + IL_0022: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_0027: ldloc.0 + IL_0028: dup + IL_0029: ldfld int32 JitTest.TestClass::m_fld + IL_002e: ldc.i4.1 + IL_002f: add + IL_0030: stfld int32 JitTest.TestClass::m_fld + IL_0035: ldloc.0 + IL_0036: ldfld int32 JitTest.TestClass::m_fld + IL_003b: ldc.i4 0x64 + IL_0040: ceq + IL_0042: brfalse IL_0007 + + IL_0047: ldloc.0 + IL_0048: ldfld int32 JitTest.TestClass::m_fld + IL_004d: ret + } // end of method TestClass::Main + + .method public hidebysig specialname rtspecialname + instance void .ctor(int32 A_0) il managed + { + // Code size 14 (0xe) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ldarg.0 + IL_0007: ldarg.1 + IL_0008: stfld int32 JitTest.TestClass::m_fld + IL_000d: ret + } // end of method TestClass::.ctor + + } // end of class TestClass + +} // end of namespace JitTest + +//*********** DISASSEMBLY COMPLETE *********************** diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/deep_value.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/deep_value.il new file mode 100644 index 0000000000..e9b83c3b30 --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/deep_value.il @@ -0,0 +1,1275 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly deep_value { } +.namespace JitTest +{ + .class public auto ansi sealed ValueClass + extends [mscorlib]System.ValueType + { + .field public int32 m_fld + } // end of class ValueClass + + .class public auto ansi beforefieldinit TestClass + extends [mscorlib]System.Object + { + .method private hidebysig static + class System.String Method0(value class JitTest.ValueClass A_0) il managed + { + // Code size 52 (0x34) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x2 + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method1(value class JitTest.ValueClass) + IL_001c: ldstr " 2" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: ldobj JitTest.ValueClass + IL_002c: tail. + IL_002e: call class System.String JitTest.TestClass::Method1(value class JitTest.ValueClass) + IL_0033: ret + } // end of method TestClass::Method0 + + .method private hidebysig static + class System.String Method1(value class JitTest.ValueClass A_0) il managed + { + // Code size 45 (0x2d) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x3 + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method2(value class JitTest.ValueClass) + IL_001c: ldstr " 3" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: pop + IL_0028: jmp class System.String JitTest.TestClass::Method2(value class JitTest.ValueClass) + } // end of method TestClass::Method1 + + .method private hidebysig static + class System.String Method2(value class JitTest.ValueClass A_0) il managed + { + // Code size 52 (0x34) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x4 + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method3(value class JitTest.ValueClass) + IL_001c: ldstr " 4" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: ldobj JitTest.ValueClass + IL_002c: tail. + IL_002e: call class System.String JitTest.TestClass::Method3(value class JitTest.ValueClass) + IL_0033: ret + } // end of method TestClass::Method2 + + .method private hidebysig static + class System.String Method3(value class JitTest.ValueClass A_0) il managed + { + // Code size 45 (0x2d) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x5 + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method4(value class JitTest.ValueClass) + IL_001c: ldstr " 5" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: pop + IL_0028: jmp class System.String JitTest.TestClass::Method4(value class JitTest.ValueClass) + } // end of method TestClass::Method3 + + .method private hidebysig static + class System.String Method4(value class JitTest.ValueClass A_0) il managed + { + // Code size 52 (0x34) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x6 + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method5(value class JitTest.ValueClass) + IL_001c: ldstr " 6" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: ldobj JitTest.ValueClass + IL_002c: tail. + IL_002e: call class System.String JitTest.TestClass::Method5(value class JitTest.ValueClass) + IL_0033: ret + } // end of method TestClass::Method4 + + .method private hidebysig static + class System.String Method5(value class JitTest.ValueClass A_0) il managed + { + // Code size 45 (0x2d) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x7 + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method6(value class JitTest.ValueClass) + IL_001c: ldstr " 7" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: pop + IL_0028: jmp class System.String JitTest.TestClass::Method6(value class JitTest.ValueClass) + } // end of method TestClass::Method5 + + .method private hidebysig static + class System.String Method6(value class JitTest.ValueClass A_0) il managed + { + // Code size 52 (0x34) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x8 + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method7(value class JitTest.ValueClass) + IL_001c: ldstr " 8" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: ldobj JitTest.ValueClass + IL_002c: tail. + IL_002e: call class System.String JitTest.TestClass::Method7(value class JitTest.ValueClass) + IL_0033: ret + } // end of method TestClass::Method6 + + .method private hidebysig static + class System.String Method7(value class JitTest.ValueClass A_0) il managed + { + // Code size 45 (0x2d) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x9 + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method8(value class JitTest.ValueClass) + IL_001c: ldstr " 9" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: pop + IL_0028: jmp class System.String JitTest.TestClass::Method8(value class JitTest.ValueClass) + } // end of method TestClass::Method7 + + .method private hidebysig static + class System.String Method8(value class JitTest.ValueClass A_0) il managed + { + // Code size 52 (0x34) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0xa + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method9(value class JitTest.ValueClass) + IL_001c: ldstr " 10" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: ldobj JitTest.ValueClass + IL_002c: tail. + IL_002e: call class System.String JitTest.TestClass::Method9(value class JitTest.ValueClass) + IL_0033: ret + } // end of method TestClass::Method8 + + .method private hidebysig static + class System.String Method9(value class JitTest.ValueClass A_0) il managed + { + // Code size 45 (0x2d) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0xb + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method10(value class JitTest.ValueClass) + IL_001c: ldstr " 11" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: pop + IL_0028: jmp class System.String JitTest.TestClass::Method10(value class JitTest.ValueClass) + } // end of method TestClass::Method9 + + .method private hidebysig static + class System.String Method10(value class JitTest.ValueClass A_0) il managed + { + // Code size 52 (0x34) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0xc + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method11(value class JitTest.ValueClass) + IL_001c: ldstr " 12" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: ldobj JitTest.ValueClass + IL_002c: tail. + IL_002e: call class System.String JitTest.TestClass::Method11(value class JitTest.ValueClass) + IL_0033: ret + } // end of method TestClass::Method10 + + .method private hidebysig static + class System.String Method11(value class JitTest.ValueClass A_0) il managed + { + // Code size 45 (0x2d) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0xd + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method12(value class JitTest.ValueClass) + IL_001c: ldstr " 13" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: pop + IL_0028: jmp class System.String JitTest.TestClass::Method12(value class JitTest.ValueClass) + } // end of method TestClass::Method11 + + .method private hidebysig static + class System.String Method12(value class JitTest.ValueClass A_0) il managed + { + // Code size 52 (0x34) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0xe + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method13(value class JitTest.ValueClass) + IL_001c: ldstr " 14" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: ldobj JitTest.ValueClass + IL_002c: tail. + IL_002e: call class System.String JitTest.TestClass::Method13(value class JitTest.ValueClass) + IL_0033: ret + } // end of method TestClass::Method12 + + .method private hidebysig static + class System.String Method13(value class JitTest.ValueClass A_0) il managed + { + // Code size 45 (0x2d) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0xf + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method14(value class JitTest.ValueClass) + IL_001c: ldstr " 15" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: pop + IL_0028: jmp class System.String JitTest.TestClass::Method14(value class JitTest.ValueClass) + } // end of method TestClass::Method13 + + .method private hidebysig static + class System.String Method14(value class JitTest.ValueClass A_0) il managed + { + // Code size 52 (0x34) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x10 + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method15(value class JitTest.ValueClass) + IL_001c: ldstr " 16" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: ldobj JitTest.ValueClass + IL_002c: tail. + IL_002e: call class System.String JitTest.TestClass::Method15(value class JitTest.ValueClass) + IL_0033: ret + } // end of method TestClass::Method14 + + .method private hidebysig static + class System.String Method15(value class JitTest.ValueClass A_0) il managed + { + // Code size 45 (0x2d) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x11 + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method16(value class JitTest.ValueClass) + IL_001c: ldstr " 17" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: pop + IL_0028: jmp class System.String JitTest.TestClass::Method16(value class JitTest.ValueClass) + } // end of method TestClass::Method15 + + .method private hidebysig static + class System.String Method16(value class JitTest.ValueClass A_0) il managed + { + // Code size 52 (0x34) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x12 + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method17(value class JitTest.ValueClass) + IL_001c: ldstr " 18" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: ldobj JitTest.ValueClass + IL_002c: tail. + IL_002e: call class System.String JitTest.TestClass::Method17(value class JitTest.ValueClass) + IL_0033: ret + } // end of method TestClass::Method16 + + .method private hidebysig static + class System.String Method17(value class JitTest.ValueClass A_0) il managed + { + // Code size 45 (0x2d) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x13 + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method18(value class JitTest.ValueClass) + IL_001c: ldstr " 19" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: pop + IL_0028: jmp class System.String JitTest.TestClass::Method18(value class JitTest.ValueClass) + } // end of method TestClass::Method17 + + .method private hidebysig static + class System.String Method18(value class JitTest.ValueClass A_0) il managed + { + // Code size 52 (0x34) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x14 + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method19(value class JitTest.ValueClass) + IL_001c: ldstr " 20" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: ldobj JitTest.ValueClass + IL_002c: tail. + IL_002e: call class System.String JitTest.TestClass::Method19(value class JitTest.ValueClass) + IL_0033: ret + } // end of method TestClass::Method18 + + .method private hidebysig static + class System.String Method19(value class JitTest.ValueClass A_0) il managed + { + // Code size 45 (0x2d) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x15 + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method20(value class JitTest.ValueClass) + IL_001c: ldstr " 21" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: pop + IL_0028: jmp class System.String JitTest.TestClass::Method20(value class JitTest.ValueClass) + } // end of method TestClass::Method19 + + .method private hidebysig static + class System.String Method20(value class JitTest.ValueClass A_0) il managed + { + // Code size 52 (0x34) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x16 + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method21(value class JitTest.ValueClass) + IL_001c: ldstr " 22" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: ldobj JitTest.ValueClass + IL_002c: tail. + IL_002e: call class System.String JitTest.TestClass::Method21(value class JitTest.ValueClass) + IL_0033: ret + } // end of method TestClass::Method20 + + .method private hidebysig static + class System.String Method21(value class JitTest.ValueClass A_0) il managed + { + // Code size 45 (0x2d) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x17 + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method22(value class JitTest.ValueClass) + IL_001c: ldstr " 23" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: pop + IL_0028: jmp class System.String JitTest.TestClass::Method22(value class JitTest.ValueClass) + } // end of method TestClass::Method21 + + .method private hidebysig static + class System.String Method22(value class JitTest.ValueClass A_0) il managed + { + // Code size 52 (0x34) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x18 + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method23(value class JitTest.ValueClass) + IL_001c: ldstr " 24" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: ldobj JitTest.ValueClass + IL_002c: tail. + IL_002e: call class System.String JitTest.TestClass::Method23(value class JitTest.ValueClass) + IL_0033: ret + } // end of method TestClass::Method22 + + .method private hidebysig static + class System.String Method23(value class JitTest.ValueClass A_0) il managed + { + // Code size 45 (0x2d) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x19 + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method24(value class JitTest.ValueClass) + IL_001c: ldstr " 25" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: pop + IL_0028: jmp class System.String JitTest.TestClass::Method24(value class JitTest.ValueClass) + } // end of method TestClass::Method23 + + .method private hidebysig static + class System.String Method24(value class JitTest.ValueClass A_0) il managed + { + // Code size 52 (0x34) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x1a + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method25(value class JitTest.ValueClass) + IL_001c: ldstr " 26" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: ldobj JitTest.ValueClass + IL_002c: tail. + IL_002e: call class System.String JitTest.TestClass::Method25(value class JitTest.ValueClass) + IL_0033: ret + } // end of method TestClass::Method24 + + .method private hidebysig static + class System.String Method25(value class JitTest.ValueClass A_0) il managed + { + // Code size 45 (0x2d) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x1b + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method26(value class JitTest.ValueClass) + IL_001c: ldstr " 27" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: pop + IL_0028: jmp class System.String JitTest.TestClass::Method26(value class JitTest.ValueClass) + } // end of method TestClass::Method25 + + .method private hidebysig static + class System.String Method26(value class JitTest.ValueClass A_0) il managed + { + // Code size 52 (0x34) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x1c + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method27(value class JitTest.ValueClass) + IL_001c: ldstr " 28" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: ldobj JitTest.ValueClass + IL_002c: tail. + IL_002e: call class System.String JitTest.TestClass::Method27(value class JitTest.ValueClass) + IL_0033: ret + } // end of method TestClass::Method26 + + .method private hidebysig static + class System.String Method27(value class JitTest.ValueClass A_0) il managed + { + // Code size 45 (0x2d) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x1d + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method28(value class JitTest.ValueClass) + IL_001c: ldstr " 29" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: pop + IL_0028: jmp class System.String JitTest.TestClass::Method28(value class JitTest.ValueClass) + } // end of method TestClass::Method27 + + .method private hidebysig static + class System.String Method28(value class JitTest.ValueClass A_0) il managed + { + // Code size 52 (0x34) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x1e + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method29(value class JitTest.ValueClass) + IL_001c: ldstr " 30" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: ldobj JitTest.ValueClass + IL_002c: tail. + IL_002e: call class System.String JitTest.TestClass::Method29(value class JitTest.ValueClass) + IL_0033: ret + } // end of method TestClass::Method28 + + .method private hidebysig static + class System.String Method29(value class JitTest.ValueClass A_0) il managed + { + // Code size 45 (0x2d) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x1f + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method30(value class JitTest.ValueClass) + IL_001c: ldstr " 31" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: pop + IL_0028: jmp class System.String JitTest.TestClass::Method30(value class JitTest.ValueClass) + } // end of method TestClass::Method29 + + .method private hidebysig static + class System.String Method30(value class JitTest.ValueClass A_0) il managed + { + // Code size 52 (0x34) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x20 + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method31(value class JitTest.ValueClass) + IL_001c: ldstr " 32" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: ldobj JitTest.ValueClass + IL_002c: tail. + IL_002e: call class System.String JitTest.TestClass::Method31(value class JitTest.ValueClass) + IL_0033: ret + } // end of method TestClass::Method30 + + .method private hidebysig static + class System.String Method31(value class JitTest.ValueClass A_0) il managed + { + // Code size 45 (0x2d) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x21 + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method32(value class JitTest.ValueClass) + IL_001c: ldstr " 33" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: pop + IL_0028: jmp class System.String JitTest.TestClass::Method32(value class JitTest.ValueClass) + } // end of method TestClass::Method31 + + .method private hidebysig static + class System.String Method32(value class JitTest.ValueClass A_0) il managed + { + // Code size 52 (0x34) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x22 + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method33(value class JitTest.ValueClass) + IL_001c: ldstr " 34" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: ldobj JitTest.ValueClass + IL_002c: tail. + IL_002e: call class System.String JitTest.TestClass::Method33(value class JitTest.ValueClass) + IL_0033: ret + } // end of method TestClass::Method32 + + .method private hidebysig static + class System.String Method33(value class JitTest.ValueClass A_0) il managed + { + // Code size 45 (0x2d) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x23 + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method34(value class JitTest.ValueClass) + IL_001c: ldstr " 35" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: pop + IL_0028: jmp class System.String JitTest.TestClass::Method34(value class JitTest.ValueClass) + } // end of method TestClass::Method33 + + .method private hidebysig static + class System.String Method34(value class JitTest.ValueClass A_0) il managed + { + // Code size 52 (0x34) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x24 + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method35(value class JitTest.ValueClass) + IL_001c: ldstr " 36" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: ldobj JitTest.ValueClass + IL_002c: tail. + IL_002e: call class System.String JitTest.TestClass::Method35(value class JitTest.ValueClass) + IL_0033: ret + } // end of method TestClass::Method34 + + .method private hidebysig static + class System.String Method35(value class JitTest.ValueClass A_0) il managed + { + // Code size 45 (0x2d) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x25 + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method36(value class JitTest.ValueClass) + IL_001c: ldstr " 37" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: pop + IL_0028: jmp class System.String JitTest.TestClass::Method36(value class JitTest.ValueClass) + } // end of method TestClass::Method35 + + .method private hidebysig static + class System.String Method36(value class JitTest.ValueClass A_0) il managed + { + // Code size 52 (0x34) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x26 + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method37(value class JitTest.ValueClass) + IL_001c: ldstr " 38" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: ldobj JitTest.ValueClass + IL_002c: tail. + IL_002e: call class System.String JitTest.TestClass::Method37(value class JitTest.ValueClass) + IL_0033: ret + } // end of method TestClass::Method36 + + .method private hidebysig static + class System.String Method37(value class JitTest.ValueClass A_0) il managed + { + // Code size 45 (0x2d) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x27 + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method38(value class JitTest.ValueClass) + IL_001c: ldstr " 39" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: pop + IL_0028: jmp class System.String JitTest.TestClass::Method38(value class JitTest.ValueClass) + } // end of method TestClass::Method37 + + .method private hidebysig static + class System.String Method38(value class JitTest.ValueClass A_0) il managed + { + // Code size 52 (0x34) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x28 + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method39(value class JitTest.ValueClass) + IL_001c: ldstr " 40" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: ldobj JitTest.ValueClass + IL_002c: tail. + IL_002e: call class System.String JitTest.TestClass::Method39(value class JitTest.ValueClass) + IL_0033: ret + } // end of method TestClass::Method38 + + .method private hidebysig static + class System.String Method39(value class JitTest.ValueClass A_0) il managed + { + // Code size 45 (0x2d) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x29 + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method40(value class JitTest.ValueClass) + IL_001c: ldstr " 41" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: pop + IL_0028: jmp class System.String JitTest.TestClass::Method40(value class JitTest.ValueClass) + } // end of method TestClass::Method39 + + .method private hidebysig static + class System.String Method40(value class JitTest.ValueClass A_0) il managed + { + // Code size 52 (0x34) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x2a + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method41(value class JitTest.ValueClass) + IL_001c: ldstr " 42" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: ldobj JitTest.ValueClass + IL_002c: tail. + IL_002e: call class System.String JitTest.TestClass::Method41(value class JitTest.ValueClass) + IL_0033: ret + } // end of method TestClass::Method40 + + .method private hidebysig static + class System.String Method41(value class JitTest.ValueClass A_0) il managed + { + // Code size 45 (0x2d) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x2b + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method42(value class JitTest.ValueClass) + IL_001c: ldstr " 43" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: pop + IL_0028: jmp class System.String JitTest.TestClass::Method42(value class JitTest.ValueClass) + } // end of method TestClass::Method41 + + .method private hidebysig static + class System.String Method42(value class JitTest.ValueClass A_0) il managed + { + // Code size 52 (0x34) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x2c + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method43(value class JitTest.ValueClass) + IL_001c: ldstr " 44" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: ldobj JitTest.ValueClass + IL_002c: tail. + IL_002e: call class System.String JitTest.TestClass::Method43(value class JitTest.ValueClass) + IL_0033: ret + } // end of method TestClass::Method42 + + .method private hidebysig static + class System.String Method43(value class JitTest.ValueClass A_0) il managed + { + // Code size 45 (0x2d) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x2d + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method44(value class JitTest.ValueClass) + IL_001c: ldstr " 45" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: pop + IL_0028: jmp class System.String JitTest.TestClass::Method44(value class JitTest.ValueClass) + } // end of method TestClass::Method43 + + .method private hidebysig static + class System.String Method44(value class JitTest.ValueClass A_0) il managed + { + // Code size 52 (0x34) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x2e + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method45(value class JitTest.ValueClass) + IL_001c: ldstr " 46" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: ldobj JitTest.ValueClass + IL_002c: tail. + IL_002e: call class System.String JitTest.TestClass::Method45(value class JitTest.ValueClass) + IL_0033: ret + } // end of method TestClass::Method44 + + .method private hidebysig static + class System.String Method45(value class JitTest.ValueClass A_0) il managed + { + // Code size 45 (0x2d) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x2f + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method46(value class JitTest.ValueClass) + IL_001c: ldstr " 47" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: pop + IL_0028: jmp class System.String JitTest.TestClass::Method46(value class JitTest.ValueClass) + } // end of method TestClass::Method45 + + .method private hidebysig static + class System.String Method46(value class JitTest.ValueClass A_0) il managed + { + // Code size 52 (0x34) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x30 + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method47(value class JitTest.ValueClass) + IL_001c: ldstr " 48" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: ldobj JitTest.ValueClass + IL_002c: tail. + IL_002e: call class System.String JitTest.TestClass::Method47(value class JitTest.ValueClass) + IL_0033: ret + } // end of method TestClass::Method46 + + .method private hidebysig static + class System.String Method47(value class JitTest.ValueClass A_0) il managed + { + // Code size 45 (0x2d) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x31 + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method48(value class JitTest.ValueClass) + IL_001c: ldstr " 49" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: pop + IL_0028: jmp class System.String JitTest.TestClass::Method48(value class JitTest.ValueClass) + } // end of method TestClass::Method47 + + .method private hidebysig static + class System.String Method48(value class JitTest.ValueClass A_0) il managed + { + // Code size 52 (0x34) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x32 + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method49(value class JitTest.ValueClass) + IL_001c: ldstr " 50" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: ldobj JitTest.ValueClass + IL_002c: tail. + IL_002e: call class System.String JitTest.TestClass::Method49(value class JitTest.ValueClass) + IL_0033: ret + } // end of method TestClass::Method48 + + .method private hidebysig static + class System.String Method49(value class JitTest.ValueClass A_0) il managed + { + // Code size 45 (0x2d) + .maxstack 8 + IL_0000: ldarga A_0 + IL_0004: dup + IL_0005: ldfld int32 JitTest.ValueClass::m_fld + IL_000a: ldc.i4 0x33 + IL_000f: rem + IL_0010: brtrue.s IL_0027 + + IL_0012: ldobj JitTest.ValueClass + IL_0017: call class System.String JitTest.TestClass::Method50(value class JitTest.ValueClass) + IL_001c: ldstr " 51" + IL_0021: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0026: ret + + IL_0027: pop + IL_0028: jmp class System.String JitTest.TestClass::Method50(value class JitTest.ValueClass) + } // end of method TestClass::Method49 + + .method private hidebysig static + class System.String Method50(value class JitTest.ValueClass A_0) il managed + { + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: ret + } // end of method TestClass::Method50 + + .method private hidebysig static + int32 Main() il managed + { + .entrypoint + // Code size 93 (0x5d) + .maxstack 8 + .locals init (value class JitTest.ValueClass V_0) + IL_0000: ldloca V_0 + IL_0004: ldc.i4.2 + IL_0005: stfld int32 JitTest.ValueClass::m_fld + IL_000a: ldloc.0 + IL_000b: call class System.String JitTest.TestClass::Method0(value class JitTest.ValueClass) + IL_0010: brtrue IL_002d + + IL_0015: ldloca V_0 + IL_0019: ldfld int32 JitTest.ValueClass::m_fld + IL_001e: call void [mscorlib]System.Console::Write(int32) + IL_0023: ldstr " - prime!" + IL_0028: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_002d: ldloca V_0 + IL_0031: dup + IL_0032: ldfld int32 JitTest.ValueClass::m_fld + IL_0037: ldc.i4.1 + IL_0038: add + IL_0039: stfld int32 JitTest.ValueClass::m_fld + IL_003e: ldloca V_0 + IL_0042: ldfld int32 JitTest.ValueClass::m_fld + IL_0047: ldc.i4 0x64 + IL_004c: ceq + IL_004e: brfalse IL_000a + + IL_0053: ldloca V_0 + IL_0057: ldfld int32 JitTest.ValueClass::m_fld + IL_005c: ret + } // end of method TestClass::Main + + .method public hidebysig specialname rtspecialname + instance void .ctor() il managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method TestClass::.ctor + + } // end of class TestClass + +} // end of namespace JitTest diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/deep_virt.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/deep_virt.il new file mode 100644 index 0000000000..0b51d515ea --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/deep_virt.il @@ -0,0 +1,1198 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly deep_virt { } +.namespace JitTest +{ + .class public auto ansi beforefieldinit TestClass + extends [mscorlib]System.Object + { + .field public int32 m_fld + .method private hidebysig virtual + instance class System.String Method0() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x2 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method1() + IL_0014: ldstr " 2" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method1() + IL_0026: ret + } // end of method TestClass::Method0 + + .method private hidebysig virtual + instance class System.String Method1() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x3 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method2() + IL_0014: ldstr " 3" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method2() + } // end of method TestClass::Method1 + + .method private hidebysig virtual + instance class System.String Method2() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x4 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method3() + IL_0014: ldstr " 4" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method3() + IL_0026: ret + } // end of method TestClass::Method2 + + .method private hidebysig virtual + instance class System.String Method3() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x5 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method4() + IL_0014: ldstr " 5" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method4() + } // end of method TestClass::Method3 + + .method private hidebysig virtual + instance class System.String Method4() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x6 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method5() + IL_0014: ldstr " 6" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method5() + IL_0026: ret + } // end of method TestClass::Method4 + + .method private hidebysig virtual + instance class System.String Method5() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x7 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method6() + IL_0014: ldstr " 7" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method6() + } // end of method TestClass::Method5 + + .method private hidebysig virtual + instance class System.String Method6() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x8 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method7() + IL_0014: ldstr " 8" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method7() + IL_0026: ret + } // end of method TestClass::Method6 + + .method private hidebysig virtual + instance class System.String Method7() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x9 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method8() + IL_0014: ldstr " 9" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method8() + } // end of method TestClass::Method7 + + .method private hidebysig virtual + instance class System.String Method8() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0xa + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method9() + IL_0014: ldstr " 10" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method9() + IL_0026: ret + } // end of method TestClass::Method8 + + .method private hidebysig virtual + instance class System.String Method9() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0xb + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method10() + IL_0014: ldstr " 11" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method10() + } // end of method TestClass::Method9 + + .method private hidebysig virtual + instance class System.String Method10() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0xc + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method11() + IL_0014: ldstr " 12" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method11() + IL_0026: ret + } // end of method TestClass::Method10 + + .method private hidebysig virtual + instance class System.String Method11() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0xd + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method12() + IL_0014: ldstr " 13" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method12() + } // end of method TestClass::Method11 + + .method private hidebysig virtual + instance class System.String Method12() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0xe + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method13() + IL_0014: ldstr " 14" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method13() + IL_0026: ret + } // end of method TestClass::Method12 + + .method private hidebysig virtual + instance class System.String Method13() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0xf + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method14() + IL_0014: ldstr " 15" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method14() + } // end of method TestClass::Method13 + + .method private hidebysig virtual + instance class System.String Method14() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x10 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method15() + IL_0014: ldstr " 16" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method15() + IL_0026: ret + } // end of method TestClass::Method14 + + .method private hidebysig virtual + instance class System.String Method15() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x11 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method16() + IL_0014: ldstr " 17" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method16() + } // end of method TestClass::Method15 + + .method private hidebysig virtual + instance class System.String Method16() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x12 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method17() + IL_0014: ldstr " 18" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method17() + IL_0026: ret + } // end of method TestClass::Method16 + + .method private hidebysig virtual + instance class System.String Method17() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x13 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method18() + IL_0014: ldstr " 19" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method18() + } // end of method TestClass::Method17 + + .method private hidebysig virtual + instance class System.String Method18() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x14 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method19() + IL_0014: ldstr " 20" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method19() + IL_0026: ret + } // end of method TestClass::Method18 + + .method private hidebysig virtual + instance class System.String Method19() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x15 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method20() + IL_0014: ldstr " 21" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method20() + } // end of method TestClass::Method19 + + .method private hidebysig virtual + instance class System.String Method20() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x16 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method21() + IL_0014: ldstr " 22" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method21() + IL_0026: ret + } // end of method TestClass::Method20 + + .method private hidebysig virtual + instance class System.String Method21() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x17 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method22() + IL_0014: ldstr " 23" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method22() + } // end of method TestClass::Method21 + + .method private hidebysig virtual + instance class System.String Method22() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x18 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method23() + IL_0014: ldstr " 24" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method23() + IL_0026: ret + } // end of method TestClass::Method22 + + .method private hidebysig virtual + instance class System.String Method23() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x19 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method24() + IL_0014: ldstr " 25" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method24() + } // end of method TestClass::Method23 + + .method private hidebysig virtual + instance class System.String Method24() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x1a + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method25() + IL_0014: ldstr " 26" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method25() + IL_0026: ret + } // end of method TestClass::Method24 + + .method private hidebysig virtual + instance class System.String Method25() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x1b + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method26() + IL_0014: ldstr " 27" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method26() + } // end of method TestClass::Method25 + + .method private hidebysig virtual + instance class System.String Method26() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x1c + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method27() + IL_0014: ldstr " 28" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method27() + IL_0026: ret + } // end of method TestClass::Method26 + + .method private hidebysig virtual + instance class System.String Method27() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x1d + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method28() + IL_0014: ldstr " 29" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method28() + } // end of method TestClass::Method27 + + .method private hidebysig virtual + instance class System.String Method28() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x1e + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method29() + IL_0014: ldstr " 30" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method29() + IL_0026: ret + } // end of method TestClass::Method28 + + .method private hidebysig virtual + instance class System.String Method29() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x1f + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method30() + IL_0014: ldstr " 31" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method30() + } // end of method TestClass::Method29 + + .method private hidebysig virtual + instance class System.String Method30() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x20 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method31() + IL_0014: ldstr " 32" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method31() + IL_0026: ret + } // end of method TestClass::Method30 + + .method private hidebysig virtual + instance class System.String Method31() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x21 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method32() + IL_0014: ldstr " 33" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method32() + } // end of method TestClass::Method31 + + .method private hidebysig virtual + instance class System.String Method32() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x22 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method33() + IL_0014: ldstr " 34" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method33() + IL_0026: ret + } // end of method TestClass::Method32 + + .method private hidebysig virtual + instance class System.String Method33() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x23 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method34() + IL_0014: ldstr " 35" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method34() + } // end of method TestClass::Method33 + + .method private hidebysig virtual + instance class System.String Method34() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x24 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method35() + IL_0014: ldstr " 36" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method35() + IL_0026: ret + } // end of method TestClass::Method34 + + .method private hidebysig virtual + instance class System.String Method35() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x25 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method36() + IL_0014: ldstr " 37" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method36() + } // end of method TestClass::Method35 + + .method private hidebysig virtual + instance class System.String Method36() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x26 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method37() + IL_0014: ldstr " 38" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method37() + IL_0026: ret + } // end of method TestClass::Method36 + + .method private hidebysig virtual + instance class System.String Method37() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x27 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method38() + IL_0014: ldstr " 39" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method38() + } // end of method TestClass::Method37 + + .method private hidebysig virtual + instance class System.String Method38() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x28 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method39() + IL_0014: ldstr " 40" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method39() + IL_0026: ret + } // end of method TestClass::Method38 + + .method private hidebysig virtual + instance class System.String Method39() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x29 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method40() + IL_0014: ldstr " 41" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method40() + } // end of method TestClass::Method39 + + .method private hidebysig virtual + instance class System.String Method40() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x2a + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method41() + IL_0014: ldstr " 42" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method41() + IL_0026: ret + } // end of method TestClass::Method40 + + .method private hidebysig virtual + instance class System.String Method41() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x2b + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method42() + IL_0014: ldstr " 43" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method42() + } // end of method TestClass::Method41 + + .method private hidebysig virtual + instance class System.String Method42() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x2c + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method43() + IL_0014: ldstr " 44" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method43() + IL_0026: ret + } // end of method TestClass::Method42 + + .method private hidebysig virtual + instance class System.String Method43() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x2d + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method44() + IL_0014: ldstr " 45" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method44() + } // end of method TestClass::Method43 + + .method private hidebysig virtual + instance class System.String Method44() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x2e + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method45() + IL_0014: ldstr " 46" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method45() + IL_0026: ret + } // end of method TestClass::Method44 + + .method private hidebysig virtual + instance class System.String Method45() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x2f + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method46() + IL_0014: ldstr " 47" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method46() + } // end of method TestClass::Method45 + + .method private hidebysig virtual + instance class System.String Method46() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x30 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method47() + IL_0014: ldstr " 48" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method47() + IL_0026: ret + } // end of method TestClass::Method46 + + .method private hidebysig virtual + instance class System.String Method47() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x31 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method48() + IL_0014: ldstr " 49" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method48() + } // end of method TestClass::Method47 + + .method private hidebysig virtual + instance class System.String Method48() il managed + { + // Code size 39 (0x27) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x32 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method49() + IL_0014: ldstr " 50" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: tail. + IL_0021: call instance class System.String JitTest.TestClass::Method49() + IL_0026: ret + } // end of method TestClass::Method48 + + .method private hidebysig virtual + instance class System.String Method49() il managed + { + // Code size 37 (0x25) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: dup + IL_0002: ldfld int32 JitTest.TestClass::m_fld + IL_0007: ldc.i4 0x33 + IL_000c: rem + IL_000d: brtrue.s IL_001f + + IL_000f: call instance class System.String JitTest.TestClass::Method50() + IL_0014: ldstr " 51" + IL_0019: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_001e: ret + + IL_001f: pop + IL_0020: jmp instance class System.String JitTest.TestClass::Method50() + } // end of method TestClass::Method49 + + .method private hidebysig virtual + instance class System.String Method50() il managed + { + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldnull + IL_0001: ret + } // end of method TestClass::Method50 + + .method private hidebysig static + int32 Main() il managed + { + .entrypoint + // Code size 78 (0x4e) + .maxstack 8 + .locals (class JitTest.TestClass V_0) + IL_0000: ldc.i4.2 + IL_0001: newobj instance void JitTest.TestClass::.ctor(int32) + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: callvirt instance class System.String JitTest.TestClass::Method0() + IL_000d: brtrue IL_0027 + + IL_0012: ldloc.0 + IL_0013: ldfld int32 JitTest.TestClass::m_fld + IL_0018: call void [mscorlib]System.Console::Write(int32) + IL_001d: ldstr " - prime!" + IL_0022: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_0027: ldloc.0 + IL_0028: dup + IL_0029: ldfld int32 JitTest.TestClass::m_fld + IL_002e: ldc.i4.1 + IL_002f: add + IL_0030: stfld int32 JitTest.TestClass::m_fld + IL_0035: ldloc.0 + IL_0036: ldfld int32 JitTest.TestClass::m_fld + IL_003b: ldc.i4 0x64 + IL_0040: ceq + IL_0042: brfalse IL_0007 + + IL_0047: ldloc.0 + IL_0048: ldfld int32 JitTest.TestClass::m_fld + IL_004d: ret + } // end of method TestClass::Main + + .method public hidebysig specialname rtspecialname + instance void .ctor(int32 A_0) il managed + { + // Code size 14 (0xe) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ldarg.0 + IL_0007: ldarg.1 + IL_0008: stfld int32 JitTest.TestClass::m_fld + IL_000d: ret + } // end of method TestClass::.ctor + + } // end of class TestClass + +} // end of namespace JitTest diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/gcval.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/gcval.il new file mode 100644 index 0000000000..07c1d22a1c --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/gcval.il @@ -0,0 +1,79 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly gcval { } +.namespace JitTest +{ + .class private sequential ansi sealed beforefieldinit LargeVT + extends [mscorlib]System.ValueType + { + .field private int32[] 'value' + .method private hidebysig static value class JitTest.LargeVT + callee(int32 retcode) il managed + { + // Code size 33 (0x21) + .maxstack 8 + .locals (value class JitTest.LargeVT lv) + ldloca.s lv + initobj JitTest.LargeVT + ldloca.s lv + ldc.i4.1 + newarr [mscorlib]System.Int32 + dup + ldc.i4.0 + ldarg.0 + stelem.i4 + stfld int32[] JitTest.LargeVT::'value' + ldloc.0 + ret + } // end of method LargeVT::callee + + .method private hidebysig static value class JitTest.LargeVT + caller(int32 retcode) il managed + { + // Code size 11 (0xb) + .maxstack 8 + ldarg.0 + tail. call value class JitTest.LargeVT JitTest.LargeVT::callee(int32) + ret + } // end of method LargeVT::caller + + .method private hidebysig static int32 + Main() il managed + { + .entrypoint + // Code size 46 (0x2e) + .maxstack 2 + .locals (int32 V_0, + int32 V_1, + value class JitTest.LargeVT V_2) + IL_0000: ldc.i4.s 100 + IL_0002: call value class JitTest.LargeVT JitTest.LargeVT::caller(int32) + IL_0007: stloc.2 + IL_0008: ldloca.s V_2 + IL_000a: ldfld int32[] JitTest.LargeVT::'value' + IL_000f: ldc.i4.0 + IL_0010: ldelem.i4 + IL_0011: stloc.0 + IL_0012: ldloc.0 + IL_0013: ldc.i4.s 100 + IL_0015: beq.s IL_001e + + IL_0017: ldstr "failed" + IL_001c: br.s IL_0023 + + IL_001e: ldstr "passed" + IL_0023: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_0028: ldloc.0 + IL_0029: stloc.1 + IL_002a: br.s IL_002c + + IL_002c: ldloc.1 + IL_002d: ret + } // end of method LargeVT::Main + + } // end of class LargeVT + +} // end of namespace JitTest diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/gcval_nested.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/gcval_nested.il new file mode 100644 index 0000000000..953f2a347e --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/gcval_nested.il @@ -0,0 +1,93 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly gcval { } +.namespace JitTest +{ + .class private sequential ansi sealed beforefieldinit LargeVT + extends [mscorlib]System.ValueType + { + .field private int32[] 'value' + .field private valuetype JitTest.LargeVT[] next + + .method private hidebysig static value class JitTest.LargeVT + callee(int32 retcode) il managed + { + // Code size 33 (0x21) + .maxstack 8 + .locals (value class JitTest.LargeVT lv) + ldloca lv + initobj JitTest.LargeVT + ldloca lv + + ldc.i4.1 + newarr value class JitTest.LargeVT + dup + ldc.i4.0 + ldelema value class JitTest.LargeVT + dup + initobj JitTest.LargeVT + ldc.i4.1 + newarr [mscorlib]System.Int32 + dup + ldc.i4.0 + ldarg.0 + stelem.i4 + stfld int32[] JitTest.LargeVT::'value' + + stfld valuetype JitTest.LargeVT[] JitTest.LargeVT::next + ldloc.0 + ret + } // end of method LargeVT::callee + + .method private hidebysig static value class JitTest.LargeVT + caller(int32 retcode) il managed + { + // Code size 11 (0xb) + .maxstack 8 + ldarg.0 + tail. call value class JitTest.LargeVT JitTest.LargeVT::callee(int32) + ret + } // end of method LargeVT::caller + + .method private hidebysig static int32 + Main() il managed + { + .entrypoint + // Code size 46 (0x2e) + .maxstack 2 + .locals (int32 V_0, + int32 V_1, + value class JitTest.LargeVT V_2) + ldc.i4.s 100 + call value class JitTest.LargeVT JitTest.LargeVT::caller(int32) + stloc.2 + ldloca.s V_2 + ldfld value class JitTest.LargeVT[] JitTest.LargeVT::next + ldc.i4.0 + ldelema value class JitTest.LargeVT + ldfld int32[] JitTest.LargeVT::'value' + + ldc.i4.0 + ldelem.i4 + stloc.0 + ldloc.0 + ldc.i4.s 100 + beq.s IL_001e + + ldstr "failed" + br.s IL_0023 + + IL_001e: ldstr "passed" + IL_0023: call void [mscorlib]System.Console::WriteLine(class System.String) + ldloc.0 + stloc.1 + ldloc.1 + ret + } // end of method LargeVT::Main + + } // end of class LargeVT + +} // end of namespace JitTest diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/gcval_sideeffect.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/gcval_sideeffect.il new file mode 100644 index 0000000000..f7c9303ddd --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/gcval_sideeffect.il @@ -0,0 +1,82 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly gcval_sideeffect { } +.namespace JitTest +{ + .class private sequential ansi sealed beforefieldinit LargeVT + extends [mscorlib]System.ValueType + { + .field private int32[] 'value' + .method private hidebysig static value class JitTest.LargeVT + callee(int32 retcode) il managed + { + // Code size 33 (0x21) + .maxstack 8 + .locals (value class JitTest.LargeVT lv) + ldloca.s lv + initobj JitTest.LargeVT + ldloca.s lv + ldc.i4.1 + newarr [mscorlib]System.Int32 + dup + ldc.i4.0 + ldarg.0 + stelem.i4 + stfld int32[] JitTest.LargeVT::'value' + ldloc.0 + ldloca lv + ldnull + stfld int32[] JitTest.LargeVT::'value' + ret + } // end of method LargeVT::callee + + .method private hidebysig static value class JitTest.LargeVT + caller(int32 retcode) il managed + { + // Code size 11 (0xb) + .maxstack 8 + ldarg.0 + tail. call value class JitTest.LargeVT JitTest.LargeVT::callee(int32) + ret + } // end of method LargeVT::caller + + .method private hidebysig static int32 + Main() il managed + { + .entrypoint + // Code size 46 (0x2e) + .maxstack 2 + .locals (int32 V_0, + int32 V_1, + value class JitTest.LargeVT V_2) + IL_0000: ldc.i4.s 100 + IL_0002: call value class JitTest.LargeVT JitTest.LargeVT::caller(int32) + IL_0007: stloc.2 + IL_0008: ldloca.s V_2 + IL_000a: ldfld int32[] JitTest.LargeVT::'value' + IL_000f: ldc.i4.0 + IL_0010: ldelem.i4 + IL_0011: stloc.0 + IL_0012: ldloc.0 + IL_0013: ldc.i4.s 100 + IL_0015: beq.s IL_001e + + IL_0017: ldstr "failed" + IL_001c: br.s IL_0023 + + IL_001e: ldstr "passed" + IL_0023: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_0028: ldloc.0 + IL_0029: stloc.1 + IL_002a: br.s IL_002c + + IL_002c: ldloc.1 + IL_002d: ret + } // end of method LargeVT::Main + + } // end of class LargeVT + +} // end of namespace JitTest diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/pointer.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/pointer.il new file mode 100644 index 0000000000..052a7ccf24 --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/pointer.il @@ -0,0 +1,96 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly pointer { } +.field public static int32 temp at D_00004000 +.method public static class System.String + rems(int32* n, + int32* m) il managed +{ + .maxstack 2 + IL_0000: ldarg.1 + IL_0001: ldind.i4 + IL_0002: ldc.i4.1 + IL_0003: bne.un.s IL_0007 + + IL_0005: ldnull + IL_0006: ret + + IL_0007: ldarg.1 + IL_0008: ldind.i4 + IL_0009: ldc.i4.1 + IL_000a: sub + IL_000b: stsfld int32 temp + IL_0010: ldarg.0 + IL_0011: ldind.i4 + IL_0012: ldarg.1 + IL_0013: ldind.i4 + IL_0014: rem + IL_0015: brtrue.s IL_003a + + IL_0017: ldarg.0 + IL_0018: ldsflda int32 temp + IL_001d: call class System.String rems(int32*, + int32*) + IL_0022: ldstr " " + IL_0027: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_002c: ldarg.1 + IL_002d: call instance class System.String [mscorlib]System.Int32::ToString() + IL_0032: tail. + IL_0034: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0039: ret + + IL_003a: ldarg.0 + IL_003b: ldsflda int32 temp + IL_0040: tail. + IL_0042: call class System.String rems(int32*, + int32*) + IL_0047: ret +} + +.method public static int32 main() il managed +{ + .entrypoint + .maxstack 2 + .locals (int32 V_0, + int32 V_1) + IL_0000: ldc.i4.2 + IL_0001: stloc.0 + IL_0002: br.s IL_0008 + + IL_0004: ldloc.0 + IL_0005: ldc.i4.1 + IL_0006: add + IL_0007: stloc.0 + IL_0008: ldloc.0 + IL_0009: ldc.i4 0x3e8 + IL_000e: bge.s IL_0037 + + IL_0010: ldloc.0 + IL_0011: ldc.i4.1 + IL_0012: sub + IL_0013: stloc.1 + IL_0014: ldloca.s V_0 + IL_0016: ldloca.s V_1 + IL_0018: call class System.String rems(int32*, + int32*) + IL_001d: brtrue.s IL_0035 + + IL_001f: ldloca.s V_0 + IL_0021: call instance class System.String [mscorlib]System.Int32::ToString() + IL_0026: call void [mscorlib]System.Console::Write(class System.String) + IL_002b: ldstr " " + IL_0030: call void [mscorlib]System.Console::Write(class System.String) + IL_0035: br.s IL_0004 + + IL_0037: call void [mscorlib]System.Console::WriteLine() + IL_003c: ldc.i4 0x64 + ret +} + +.data D_00004000 = bytearray ( + 00 00 00 00) diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/pointer_i.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/pointer_i.il new file mode 100644 index 0000000000..57a7d52999 --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/pointer_i.il @@ -0,0 +1,97 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly pointer_i { } +.field public static int32 temp at D_00004000 +.method public static class System.String + rems(int32* n, + int32* m) il managed +{ + .maxstack 8 + IL_0000: ldarg.1 + IL_0001: ldind.i4 + IL_0002: ldc.i4.1 + IL_0003: bne.un.s IL_0007 + + IL_0005: ldnull + IL_0006: ret + + IL_0007: ldarg.1 + IL_0008: ldind.i4 + IL_0009: ldc.i4.1 + IL_000a: sub + IL_000b: stsfld int32 temp + IL_0010: ldarg.0 + IL_0011: ldind.i4 + IL_0012: ldarg.1 + IL_0013: ldind.i4 + IL_0014: rem + IL_0015: brtrue.s IL_003b + + IL_0017: ldarg.0 + IL_0018: ldsflda int32 temp + IL_001d: call class System.String rems(int32*, + int32*) + IL_0022: ldstr " " + IL_0027: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_002c: ldarg.1 + ldind.i4 + box int32 + IL_002d: callvirt instance class System.String [mscorlib]System.Object::ToString() + ldftn class System.String [mscorlib]System.String::Concat(class System.String, class System.String) + calli class System.String(class System.String, class System.String) + IL_003a: ret + + IL_003b: ldarg.0 + IL_003c: ldsflda int32 temp + IL_0041: ldftn class System.String rems(int32*, + int32*) + IL_0047: calli class System.String(int32*,int32*) + IL_004e: ret +} + +.method public static int32 main() il managed +{ + .entrypoint + .maxstack 2 + .locals (int32 V_0, + int32 V_1) + IL_0000: ldc.i4.2 + IL_0001: stloc.0 + IL_0002: br.s IL_0008 + + IL_0004: ldloc.0 + IL_0005: ldc.i4.1 + IL_0006: add + IL_0007: stloc.0 + IL_0008: ldloc.0 + IL_0009: ldc.i4 0x3e8 + IL_000e: bge.s IL_0037 + + IL_0010: ldloc.0 + IL_0011: ldc.i4.1 + IL_0012: sub + IL_0013: stloc.1 + IL_0014: ldloca.s V_0 + IL_0016: ldloca.s V_1 + IL_0018: call class System.String rems(int32*, + int32*) + IL_001d: brtrue.s IL_0035 + + IL_001f: ldloca.s V_0 + IL_0021: call instance class System.String [mscorlib]System.Int32::ToString() + IL_0026: call void [mscorlib]System.Console::Write(class System.String) + IL_002b: ldstr " " + IL_0030: call void [mscorlib]System.Console::Write(class System.String) + IL_0035: br.s IL_0004 + + IL_0037: call void [mscorlib]System.Console::WriteLine() + ldc.i4 0x64 + ret +} + +.data D_00004000 = bytearray ( + 00 00 00 00) diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/recurse_ep.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/recurse_ep.il new file mode 100644 index 0000000000..8b2d68f509 --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/recurse_ep.il @@ -0,0 +1,80 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly recurse_ep { } +.namespace JitTest +{ + .class private auto ansi beforefieldinit Test + extends [mscorlib]System.Object + { + .field private static int32 m + .field private static int32 n + .method private hidebysig static + int32 Main() il managed + { + .entrypoint + // Code size 93 (0x5d) + .maxstack 4 + .locals (int32 V_0) + IL_0000: ldsfld int32 JitTest.Test::n + IL_0005: ldc.i4.1 + IL_0006: bne.un.s IL_003d + + IL_0008: ldsfld int32 JitTest.Test::m + IL_000d: ldc.i4 0x375f00 + IL_0012: bne.un.s IL_0021 + + IL_0014: ldstr "PASSED: 10! == 3628800" + IL_0019: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_001e: ldc.i4.s 100 + IL_0020: ret + + IL_0021: ldstr "FAILED: 10! != " + IL_0026: ldsflda int32 JitTest.Test::m + IL_002b: call instance class System.String [mscorlib]System.Int32::ToString() + IL_0030: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0035: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_003a: ldc.i4.s 101 + IL_003c: ret + + IL_003d: ldsfld int32 JitTest.Test::m + IL_0042: ldsfld int32 JitTest.Test::n + IL_0047: dup + IL_0048: ldc.i4.1 + IL_0049: sub + IL_004a: stsfld int32 JitTest.Test::n + IL_004f: mul + IL_0050: stsfld int32 JitTest.Test::m + IL_0055: tail. + IL_0057: call int32 JitTest.Test::Main() + IL_005c: ret + } // end of method Test::Main + + .method private hidebysig specialname rtspecialname static + void .cctor() il managed + { + // Code size 14 (0xe) + .maxstack 8 + IL_0000: ldc.i4.1 + IL_0001: stsfld int32 JitTest.Test::m + IL_0006: ldc.i4.s 10 + IL_0008: stsfld int32 JitTest.Test::n + IL_000d: ret + } // end of method Test::.cctor + + .method public hidebysig specialname rtspecialname + instance void .ctor() il managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method Test::.ctor + + } // end of class Test + +} // end of namespace JitTest diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/recurse_ep_void.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/recurse_ep_void.il new file mode 100644 index 0000000000..4d780e2de7 --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/recurse_ep_void.il @@ -0,0 +1,78 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly recurse_ep_void { } +.namespace JitTest +{ + .class private auto ansi beforefieldinit Test + extends [mscorlib]System.Object + { + .field private static int32 m + .field private static int32 n + .method private hidebysig static + void Main() il managed + { + .entrypoint + .maxstack 4 + .locals (int32 V_0) + IL_0000: ldsfld int32 JitTest.Test::n + IL_0005: ldc.i4.1 + IL_0006: bne.un.s IL_0049 + + IL_0008: ldsfld int32 JitTest.Test::m + IL_000d: ldc.i4 0x375f00 + IL_0012: bne.un.s IL_0025 + + IL_0014: ldstr "PASSED: 10! == 3628800" + IL_0019: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_001e: ldc.i4 0x64 + IL_0023: br.s IL_0043 + + IL_0025: ldstr "FAILED: 10! != " + IL_002a: ldsflda int32 JitTest.Test::m + IL_002f: call instance class System.String [mscorlib]System.Int32::ToString() + IL_0034: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0039: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_003e: ldc.i4 0x65 + IL_0043: call void [mscorlib]System.Environment::Exit(int32) + IL_0048: ret + + IL_0049: ldsfld int32 JitTest.Test::m + IL_004e: ldsfld int32 JitTest.Test::n + IL_0053: dup + IL_0054: ldc.i4.1 + IL_0055: sub + IL_0056: stsfld int32 JitTest.Test::n + IL_005b: mul + IL_005c: stsfld int32 JitTest.Test::m + IL_0061: tail. + IL_0063: call void JitTest.Test::Main() + IL_0068: ret + } + + .method private hidebysig specialname rtspecialname static + void .cctor() il managed + { + .maxstack 8 + IL_0000: ldc.i4.1 + IL_0001: stsfld int32 JitTest.Test::m + IL_0006: ldc.i4.s 10 + IL_0008: stsfld int32 JitTest.Test::n + IL_000d: ret + } + + .method public hidebysig specialname rtspecialname + instance void .ctor() il managed + { + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } + + } + +} diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/reference_i.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/reference_i.il new file mode 100644 index 0000000000..9861ffa1be --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/reference_i.il @@ -0,0 +1,106 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly reference_i { } +.method public static class System.String + rems(int32& n, + int32& m) il managed +{ + // Code size 93 (0x5d) + .maxstack 8 + .locals (int32[] V_0) + IL_0000: ldarg.1 + IL_0001: ldind.i4 + IL_0002: ldc.i4.1 + IL_0003: bne.un.s IL_0007 + + IL_0005: ldnull + IL_0006: ret + + IL_0007: ldc.i4.1 + IL_0008: newarr int32 + IL_000d: stloc.0 + IL_000e: ldloc.0 + IL_000f: ldc.i4.0 + IL_0010: ldarg.1 + IL_0011: ldind.i4 + IL_0012: ldc.i4.1 + IL_0013: sub + IL_0014: stelem.i4 + IL_0015: ldarg.0 + IL_0016: ldind.i4 + IL_0017: ldarg.1 + IL_0018: ldind.i4 + IL_0019: rem + IL_001a: brtrue.s IL_0047 + + IL_001c: ldarg.0 + IL_001d: ldloc.0 + IL_001e: ldc.i4.0 + IL_001f: ldelema int32 + IL_0024: call class System.String rems(int32&, + int32&) + IL_0029: ldstr " " + IL_002e: call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_0033: ldarg.1 + IL_0034: call instance class System.String [mscorlib]System.Int32::ToString() + IL_0039: ldftn class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + IL_003f: tail. + IL_0041: calli class System.String(class System.String,class System.String) + IL_0046: ret + + IL_0047: ldarg.0 + IL_0048: ldloc.0 + IL_0049: ldc.i4.0 + IL_004a: ldelema int32 + IL_004f: ldftn class System.String rems(int32&, + int32&) + IL_0055: tail. + IL_0057: calli class System.String(int32&,int32&) + IL_005c: ret +} // end of global method rems + +.method public static int32 main() il managed +{ + .entrypoint + // Code size 66 (0x42) + .maxstack 2 + .locals (int32 V_0, + int32 V_1) + IL_0000: ldc.i4.2 + IL_0001: stloc.0 + IL_0002: br.s IL_0008 + + IL_0004: ldloc.0 + IL_0005: ldc.i4.1 + IL_0006: add + IL_0007: stloc.0 + IL_0008: ldloc.0 + IL_0009: ldc.i4 0x3e8 + IL_000e: bge.s IL_0037 + + IL_0010: ldloc.0 + IL_0011: ldc.i4.1 + IL_0012: sub + IL_0013: stloc.1 + IL_0014: ldloca.s V_0 + IL_0016: ldloca.s V_1 + IL_0018: call class System.String rems(int32&, + int32&) + IL_001d: brtrue.s IL_0035 + + IL_001f: ldloca.s V_0 + IL_0021: call instance class System.String [mscorlib]System.Int32::ToString() + IL_0026: call void [mscorlib]System.Console::Write(class System.String) + IL_002b: ldstr " " + IL_0030: call void [mscorlib]System.Console::Write(class System.String) + IL_0035: br.s IL_0004 + + IL_0037: call void [mscorlib]System.Console::WriteLine() + IL_003c: ldc.i4 0x64 + IL_0041: ret +} // end of global method main diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/test_2a.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/test_2a.il new file mode 100644 index 0000000000..e89d7d0176 --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/test_2a.il @@ -0,0 +1,84 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly test_2a { } +.namespace JitTest +{ + .class private auto ansi beforefieldinit Test + extends [mscorlib]System.Object + { + .field private static int32 m + .field private static int32 n + .method private hidebysig static int32 Main() il managed + { + .entrypoint + .maxstack 4 + .locals (int32 V_0) + ldc.i4.1 + call void [mscorlib]System.Environment::set_ExitCode(int32) + ldsfld int32 JitTest.Test::n + ldc.i4.1 + bne.un.s IL_0047 + + ldsfld int32 JitTest.Test::m + ldc.i4 0x375f00 + bne.un.s IL_0029 + + ldstr "PASSED: 10! == 3628800" + call void [mscorlib]System.Console::WriteLine(class System.String) + ldc.i4.s 100 + ret + +OUT: + tail. call int32 JitTest.Test::Main() + ret + +IL_0029: + ldstr "FAILED: 10! != " + ldsflda int32 JitTest.Test::m + call instance class System.String [mscorlib]System.Int32::ToString() + call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + call void [mscorlib]System.Console::WriteLine(class System.String) + ldc.i4.s 101 + ret + +IL_0047: + ldsfld int32 JitTest.Test::m + ldsfld int32 JitTest.Test::n + dup + ldc.i4.1 + sub + stsfld int32 JitTest.Test::n + mul + stsfld int32 JitTest.Test::m + br.s OUT + } // end of method Test::Main + + .method private hidebysig specialname rtspecialname static + void .cctor() il managed + { + // Code size 14 (0xe) + .maxstack 8 + IL_0000: ldc.i4.1 + IL_0001: stsfld int32 JitTest.Test::m + IL_0006: ldc.i4.s 10 + IL_0008: stsfld int32 JitTest.Test::n + IL_000d: ret + } // end of method Test::.cctor + + .method public hidebysig specialname rtspecialname + instance void .ctor() il managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method Test::.ctor + + } // end of class Test + +} // end of namespace JitTest diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/test_2b.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/test_2b.il new file mode 100644 index 0000000000..76db2af62f --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/test_2b.il @@ -0,0 +1,88 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } + +.assembly test_2b { } + +.namespace JitTest +{ + .class private auto ansi beforefieldinit Test + extends [mscorlib]System.Object + { + .field private static int32 m + .field private static int32 n + .method private hidebysig static int32 Main() il managed + { + .entrypoint + .maxstack 4 + .locals (int32 V_0) + ldc.i4.1 + call void [mscorlib]System.Environment::set_ExitCode(int32) + ldsfld int32 JitTest.Test::n + ldc.i4.1 + bne.un.s IL_0047 + + ldsfld int32 JitTest.Test::m + ldc.i4 0x375f00 + bne.un.s IL_0029 + + ldstr "PASSED: 10! == 3628800" + call void [mscorlib]System.Console::WriteLine(class System.String) + ldc.i4.s 100 + ret + +IL_0029: + ldstr "FAILED: 10! != " + ldsflda int32 JitTest.Test::m + call instance class System.String [mscorlib]System.Int32::ToString() + call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + call void [mscorlib]System.Console::WriteLine(class System.String) + ldc.i4.s 101 + ret + +IL_0047: + ldsfld int32 JitTest.Test::n + ldc.i4.1 + beq MERGE + + ldsfld int32 JitTest.Test::m + ldsfld int32 JitTest.Test::n + dup + ldc.i4.1 + sub + stsfld int32 JitTest.Test::n + mul + stsfld int32 JitTest.Test::m +MERGE: + tail. call int32 JitTest.Test::Main() + ret + } // end of method Test::Main + + .method private hidebysig specialname rtspecialname static + void .cctor() il managed + { + // Code size 14 (0xe) + .maxstack 8 + IL_0000: ldc.i4.1 + IL_0001: stsfld int32 JitTest.Test::m + IL_0006: ldc.i4.s 10 + IL_0008: stsfld int32 JitTest.Test::n + IL_000d: ret + } // end of method Test::.cctor + + .method public hidebysig specialname rtspecialname + instance void .ctor() il managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method Test::.ctor + + } // end of class Test + +} // end of namespace JitTest diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/test_2c.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/test_2c.il new file mode 100644 index 0000000000..f49f4f6d07 --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/test_2c.il @@ -0,0 +1,90 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly test_2c { } +.namespace JitTest +{ + .class private auto ansi beforefieldinit Test + extends [mscorlib]System.Object + { + .field private static int32 m + .field private static int32 n + .method private hidebysig static int32 Main() il managed + { + .entrypoint + .maxstack 4 + .locals (int32 V_0) + ldc.i4.1 + call void [mscorlib]System.Environment::set_ExitCode(int32) + ldsfld int32 JitTest.Test::n + ldc.i4.1 + bne.un.s IL_0047 + + ldsfld int32 JitTest.Test::m + ldc.i4 0x375f00 + bne.un.s IL_0029 + + ldstr "PASSED: 10! == 3628800" + call void [mscorlib]System.Console::WriteLine(class System.String) + ldc.i4.s 100 + br.s RET + +IL_0029: + ldstr "FAILED: 10! != " + ldsflda int32 JitTest.Test::m + call instance class System.String [mscorlib]System.Int32::ToString() + call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + call void [mscorlib]System.Console::WriteLine(class System.String) + ldc.i4.s 101 + br.s RET + +IL_0047: + nop + ldsfld int32 JitTest.Test::n + ldc.i4.1 + beq MERGE + + ldsfld int32 JitTest.Test::m + ldsfld int32 JitTest.Test::n + dup + ldc.i4.1 + sub + stsfld int32 JitTest.Test::n + mul + stsfld int32 JitTest.Test::m +MERGE: + tail. call int32 JitTest.Test::Main() +RET: + ret + } // end of method Test::Main + + .method private hidebysig specialname rtspecialname static + void .cctor() il managed + { + // Code size 14 (0xe) + .maxstack 8 + IL_0000: ldc.i4.1 + IL_0001: stsfld int32 JitTest.Test::m + IL_0006: ldc.i4.s 10 + IL_0008: stsfld int32 JitTest.Test::n + IL_000d: ret + } // end of method Test::.cctor + + .method public hidebysig specialname rtspecialname + instance void .ctor() il managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method Test::.ctor + + } // end of class Test + +} // end of namespace JitTest + +//*********** DISASSEMBLY COMPLETE *********************** diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/test_3b.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/test_3b.il new file mode 100644 index 0000000000..e493c94705 --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/test_3b.il @@ -0,0 +1,82 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly test_3b { } +.namespace JitTest +{ + .class private value sealed ansi beforefieldinit ValueClass + extends [mscorlib]System.ValueType + { + .field public float64 m_fld + } + .class private auto ansi beforefieldinit TestClass + extends [mscorlib]System.Object + { + .method private hidebysig static + int32 TestFunc2(value class JitTest.ValueClass) il managed + { + // Code size 10 (0xa) + .maxstack 8 + .locals init (int32 V_0) + sizeof value class JitTest.ValueClass + localloc + ldarg.0 + stobj value class JitTest.ValueClass + ldc.i4.0 + ret + } // end of method TestClass::TestFunc2 + + .method private hidebysig static + int32 TestFunc1() il managed + { + // Code size 22 (0x16) + .maxstack 8 + sizeof value class JitTest.ValueClass + localloc + dup + initobj value class JitTest.ValueClass + ldobj value class JitTest.ValueClass + tail. + call int32 JitTest.TestClass::TestFunc2(value class JitTest.ValueClass) + ret + } // end of method TestClass::TestFunc1 + + .method private hidebysig static + int32 Main() il managed + { + .entrypoint + // Code size 38 (0x26) + .maxstack 1 + .locals (int32 V_0) + IL_0000: call int32 JitTest.TestClass::TestFunc1() + IL_0005: brfalse.s IL_0015 + + IL_0007: ldstr "failed" + IL_000c: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_0011: ldc.i4.1 + IL_0012: stloc.0 + IL_0013: br.s IL_0024 + + IL_0015: ldstr "passed" + IL_001a: call void [mscorlib]System.Console::WriteLine(class System.String) + IL_001f: ldc.i4.s 100 + IL_0021: stloc.0 + IL_0022: br.s IL_0024 + + IL_0024: ldloc.0 + IL_0025: ret + } // end of method TestClass::Main + + .method public hidebysig specialname rtspecialname + instance void .ctor() il managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method TestClass::.ctor + } // end of class TestClass +} diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/test_implicit.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/test_implicit.il new file mode 100644 index 0000000000..a6dfc7b0fa --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/test_implicit.il @@ -0,0 +1,336 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } + +.assembly tailcall { } + +.class public auto ansi beforefieldinit Class1 + extends [mscorlib]System.Object +{ + .field private static int32 MaxDepth + .field private int32 'value' + .method public hidebysig instance int32 + Recurse1(int32 depth) cil managed + { + .maxstack 5 + .locals init (int32 V_0) + IL_0000: ldarg.1 + IL_0001: brtrue.s IL_000c + + IL_0003: ldarg.0 + IL_0004: ldfld int32 Class1::'value' + IL_0009: stloc.0 + IL_000a: br.s IL_004b + + IL_000c: ldarg.0 + IL_000d: dup + IL_000e: ldfld int32 Class1::'value' + IL_0013: ldarg.1 + IL_0014: add + IL_0015: stfld int32 Class1::'value' + IL_001a: ldarg.1 + IL_001b: ldc.i4 0x80 + IL_0020: rem + IL_0021: ldc.i4.s 43 + IL_0023: bne.un.s IL_0031 + + IL_0025: ldarg.0 + IL_0026: ldarg.1 + IL_0027: ldc.i4.1 + IL_0028: sub + IL_0029: tail. callvirt instance int32 Class1::Recurse3(int32) +ret + IL_002e: stloc.0 + IL_002f: br.s IL_004b + + IL_0031: ldarg.0 + IL_0032: ldarg.1 + IL_0033: ldc.i4.1 + IL_0034: sub + IL_0035: ldarg.1 + IL_0036: box [mscorlib]System.Int32 + IL_003b: ldarg.1 + IL_003c: ldc.i4.1 + IL_003d: add + IL_003e: box [mscorlib]System.Int32 + IL_0043: tail. call instance int32 Class1::Recurse2(int32, + object, + object) +ret + IL_0048: stloc.0 + IL_0049: br.s IL_004b + + IL_004b: ldloc.0 + IL_004c: ret + } + + .method public hidebysig instance int32 + Recurse2(int32 depth, + object o1, + object o2) cil managed + { + .maxstack 4 + .locals init (string V_0, + int32 V_1) + IL_0000: ldarg.1 + IL_0001: brtrue.s IL_000c + + IL_0003: ldarg.0 + IL_0004: ldfld int32 Class1::'value' + IL_0009: stloc.1 + IL_000a: br.s IL_007b + + IL_000c: ldarg.1 + IL_000d: ldsfld int32 Class1::MaxDepth + IL_0012: ldc.i4.s 10 + IL_0014: div + IL_0015: rem + IL_0016: ldc.i4.s 100 + IL_0018: bne.un.s IL_0053 + + IL_001a: call string [mscorlib]System.Environment::get_StackTrace() + IL_001f: stloc.0 + IL_0020: ldloc.0 + IL_0021: ldstr "Main" + IL_0026: callvirt instance int32 [mscorlib]System.String::IndexOf(string) + IL_002b: ldc.i4.m1 + IL_002c: bne.un.s IL_004e + + IL_002e: ldstr "Unexpected stack trace: " + IL_0033: ldloc.0 + IL_0034: call string [mscorlib]System.String::Concat(string, + string) + IL_0039: call void [mscorlib]System.Console::WriteLine(string) + IL_003e: ldstr "Test Failed" + IL_0043: call void [mscorlib]System.Console::WriteLine(string) + IL_0048: ldc.i4.0 + IL_0049: call void [mscorlib]System.Environment::Exit(int32) + IL_004e: call void [mscorlib]System.GC::Collect() + IL_0053: ldarg.0 + IL_0054: dup + IL_0055: ldfld int32 Class1::'value' + IL_005a: ldarg.2 + IL_005b: unbox [mscorlib]System.Int32 + IL_0060: ldind.i4 + IL_0061: ldarg.3 + IL_0062: unbox [mscorlib]System.Int32 + IL_0067: ldind.i4 + IL_0068: add + IL_0069: add + IL_006a: stfld int32 Class1::'value' + IL_006f: ldarg.0 + IL_0070: ldarg.1 + IL_0071: ldc.i4.1 + IL_0072: sub + IL_0073: tail. callvirt instance int32 Class1::Recurse3(int32) +ret + IL_0078: stloc.1 + IL_0079: br.s IL_007b + + IL_007b: ldloc.1 + IL_007c: ret + } + + .method public hidebysig newslot virtual + instance int32 Recurse3(int32 depth) cil managed + { + .maxstack 5 + .locals init (int32 V_0) + IL_0000: ldarg.1 + IL_0001: brtrue.s IL_000c + + IL_0003: ldarg.0 + IL_0004: ldfld int32 Class1::'value' + IL_0009: stloc.0 + IL_000a: br.s IL_003f + + IL_000c: ldarg.1 + IL_000d: ldc.i4 0x80 + IL_0012: rem + IL_0013: ldc.i4.s 21 + IL_0015: bne.un.s IL_0023 + + IL_0017: ldarg.0 + IL_0018: ldarg.1 + IL_0019: ldc.i4.1 + IL_001a: sub + IL_001b: tail. call instance int32 Class1::Recurse1(int32) +ret + IL_0020: stloc.0 + IL_0021: br.s IL_003f + + IL_0023: ldarg.0 + IL_0024: ldarg.1 + IL_0025: ldc.i4.1 + IL_0026: sub + IL_0027: ldarg.1 + IL_0028: ldc.i4.1 + IL_0029: add + IL_002a: box [mscorlib]System.Int32 + IL_002f: ldarg.1 + IL_0030: ldc.i4.2 + IL_0031: add + IL_0032: box [mscorlib]System.Int32 + IL_0037: tail. callvirt instance int32 Class1::Recurse4(int32, + object, + object) +ret + IL_003c: stloc.0 + IL_003d: br.s IL_003f + + IL_003f: ldloc.0 + IL_0040: ret + } + + .method public hidebysig newslot virtual + instance int32 Recurse4(int32 depth, + object o1, + object o2) cil managed + { + .maxstack 4 + .locals init (string V_0, + int32 V_1) + IL_0000: ldarg.1 + IL_0001: brtrue.s IL_000c + + IL_0003: ldarg.0 + IL_0004: ldfld int32 Class1::'value' + IL_0009: stloc.1 + IL_000a: br.s IL_007e + + IL_000c: ldarg.1 + IL_000d: ldsfld int32 Class1::MaxDepth + IL_0012: ldc.i4.s 10 + IL_0014: div + IL_0015: rem + IL_0016: ldc.i4 0xc8 + IL_001b: bne.un.s IL_0056 + + IL_001d: call void [mscorlib]System.GC::Collect() + IL_0022: call string [mscorlib]System.Environment::get_StackTrace() + IL_0027: stloc.0 + IL_0028: ldloc.0 + IL_0029: ldstr "Main" + IL_002e: callvirt instance int32 [mscorlib]System.String::IndexOf(string) + IL_0033: ldc.i4.m1 + IL_0034: bne.un.s IL_0056 + + IL_0036: ldstr "Unexpected stack trace: " + IL_003b: ldloc.0 + IL_003c: call string [mscorlib]System.String::Concat(string, + string) + IL_0041: call void [mscorlib]System.Console::WriteLine(string) + IL_0046: ldstr "Test Failed" + IL_004b: call void [mscorlib]System.Console::WriteLine(string) + IL_0050: ldc.i4.0 + IL_0051: call void [mscorlib]System.Environment::Exit(int32) + IL_0056: ldarg.0 + IL_0057: dup + IL_0058: ldfld int32 Class1::'value' + IL_005d: ldarg.2 + IL_005e: unbox [mscorlib]System.Int32 + IL_0063: ldind.i4 + IL_0064: ldarg.3 + IL_0065: unbox [mscorlib]System.Int32 + IL_006a: ldind.i4 + IL_006b: add + IL_006c: add + IL_006d: stfld int32 Class1::'value' + IL_0072: ldarg.0 + IL_0073: ldarg.1 + IL_0074: ldc.i4.1 + IL_0075: sub + IL_0076: tail. call instance int32 Class1::Recurse1(int32) +ret + IL_007b: stloc.1 + IL_007c: br.s IL_007e + + IL_007e: ldloc.1 + IL_007f: ret + } + + .method public hidebysig static int32 Main() cil managed + { + .entrypoint + .maxstack 3 + .locals init (class Class1 V_0, + int32 V_1, + int32 V_2, + object[] V_3) + IL_0000: ldstr "Test Start" + IL_0005: call void [mscorlib]System.Console::WriteLine(string) + IL_000a: newobj instance void Class1::.ctor() + IL_000f: stloc.0 + IL_0010: ldloc.0 + IL_0011: ldsfld int32 Class1::MaxDepth + IL_0016: callvirt instance int32 Class1::Recurse1(int32) + IL_001b: pop + IL_001c: ldc.i4 41963520 + IL_001d: stloc.1 + IL_001e: ldloc.0 + IL_001f: ldfld int32 Class1::'value' + IL_0024: ldloc.1 + IL_0025: beq.s IL_006e + + IL_0027: ldc.i4.4 + IL_0028: newarr [mscorlib]System.Object + IL_002d: stloc.3 + IL_002e: ldloc.3 + IL_002f: ldc.i4.0 + IL_0030: ldstr "Expected result: " + IL_0035: stelem.ref + IL_0036: ldloc.3 + IL_0037: ldc.i4.1 + IL_0038: ldc.i4.1 + IL_0039: box [mscorlib]System.Int32 + IL_003e: stelem.ref + IL_003f: ldloc.3 + IL_0040: ldc.i4.2 + IL_0041: ldstr " Actual result: " + IL_0046: stelem.ref + IL_0047: ldloc.3 + IL_0048: ldc.i4.3 + IL_0049: ldloc.0 + IL_004a: ldfld int32 Class1::'value' + IL_004f: box [mscorlib]System.Int32 + IL_0054: stelem.ref + IL_0055: ldloc.3 + IL_0056: call string [mscorlib]System.String::Concat(object[]) + IL_005b: call void [mscorlib]System.Console::WriteLine(string) + IL_0060: ldstr "Test Failed" + IL_0065: call void [mscorlib]System.Console::WriteLine(string) + IL_006a: ldc.i4.0 + IL_006b: stloc.2 + IL_006c: br.s IL_007d + + IL_006e: ldstr "Test Passed" + IL_0073: call void [mscorlib]System.Console::WriteLine(string) + IL_0078: ldc.i4.s 100 + IL_007a: stloc.2 + IL_007b: br.s IL_007d + + IL_007d: ldloc.2 + IL_007e: ret + } + + .method private hidebysig specialname rtspecialname static + void .cctor() cil managed + { + .maxstack 8 + IL_0000: ldc.i4 0x2000 + IL_0005: stsfld int32 Class1::MaxDepth + IL_000a: ret + } + + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } + +} diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/test_mutual_rec.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/test_mutual_rec.il new file mode 100644 index 0000000000..252e780200 --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/test_mutual_rec.il @@ -0,0 +1,204 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly test_mutual_rec { } +.namespace JitTest +{ + .class private auto ansi beforefieldinit Test + extends [mscorlib]System.Object + { + .field private static int32 m + .field private static int32 n + .method private hidebysig static int32 Main() il managed + { + .entrypoint + .maxstack 4 + .locals (int32 V_0) + ldc.i4.1 + call void [mscorlib]System.Environment::set_ExitCode(int32) + ldsfld int32 JitTest.Test::n + ldc.i4.1 + bne.un.s IL_0047 + + ldsfld int32 JitTest.Test::m + ldc.i4 0x375f00 + bne.un.s IL_0029 + + ldstr "PASSED: 10! == 3628800" + call void [mscorlib]System.Console::WriteLine(class System.String) + ldc.i4.s 100 + ret + +IL_0029: + ldstr "FAILED: 10! != " + ldsflda int32 JitTest.Test::m + call instance class System.String [mscorlib]System.Int32::ToString() + call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + call void [mscorlib]System.Console::WriteLine(class System.String) + ldc.i4.s 101 + ret + +IL_0047: + ldsfld int32 JitTest.Test::m + ldsfld int32 JitTest.Test::n + dup + ldc.i4.1 + sub + stsfld int32 JitTest.Test::n + mul + stsfld int32 JitTest.Test::m + + ldsfld int32 JitTest.Test::n + ldc.i4.3 + rem + switch (CASE1, CASE2) + ldftn int32 JitTest.Test::Main() + br.s MERGE1 +CASE1: + ldftn int32 JitTest.Test::Main1() + br.s MERGE1 +CASE2: + ldftn int32 JitTest.Test::Main2() +MERGE1: + tail. calli int32() + ret + } // end of method Test::Main + .method private hidebysig static int32 Main1() il managed + { + .maxstack 4 + .locals (int32 V_0) + ldc.i4.1 + call void [mscorlib]System.Environment::set_ExitCode(int32) + ldsfld int32 JitTest.Test::n + ldc.i4.1 + bne.un.s IL_0047 + + ldsfld int32 JitTest.Test::m + ldc.i4 0x375f00 + bne.un.s IL_0029 + + ldstr "PASSED: 10! == 3628800" + call void [mscorlib]System.Console::WriteLine(class System.String) + ldc.i4.s 100 + ret + +IL_0029: + ldstr "FAILED: 10! != " + ldsflda int32 JitTest.Test::m + call instance class System.String [mscorlib]System.Int32::ToString() + call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + call void [mscorlib]System.Console::WriteLine(class System.String) + ldc.i4.s 101 + ret + +IL_0047: + ldsfld int32 JitTest.Test::m + ldsfld int32 JitTest.Test::n + dup + ldc.i4.1 + sub + stsfld int32 JitTest.Test::n + mul + stsfld int32 JitTest.Test::m + + ldsfld int32 JitTest.Test::n + ldc.i4.3 + rem + switch (CASE1, CASE2) + ldftn int32 JitTest.Test::Main() + br.s MERGE1 +CASE1: + ldftn int32 JitTest.Test::Main1() + br.s MERGE1 +CASE2: + ldftn int32 JitTest.Test::Main2() +MERGE1: + tail. calli int32() + ret + } // end of method Test::Main + .method private hidebysig static int32 Main2() il managed + { + .maxstack 4 + .locals (int32 V_0) + ldc.i4.1 + call void [mscorlib]System.Environment::set_ExitCode(int32) + ldsfld int32 JitTest.Test::n + ldc.i4.1 + bne.un.s IL_0047 + + ldsfld int32 JitTest.Test::m + ldc.i4 0x375f00 + bne.un.s IL_0029 + + ldstr "PASSED: 10! == 3628800" + call void [mscorlib]System.Console::WriteLine(class System.String) + ldc.i4.s 100 + ret + +IL_0029: + ldstr "FAILED: 10! != " + ldsflda int32 JitTest.Test::m + call instance class System.String [mscorlib]System.Int32::ToString() + call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + call void [mscorlib]System.Console::WriteLine(class System.String) + ldc.i4.s 101 + ret + +IL_0047: + ldsfld int32 JitTest.Test::m + ldsfld int32 JitTest.Test::n + dup + ldc.i4.1 + sub + stsfld int32 JitTest.Test::n + mul + stsfld int32 JitTest.Test::m + + ldsfld int32 JitTest.Test::n + ldc.i4.3 + rem + switch (CASE1, CASE2) + ldftn int32 JitTest.Test::Main() + br.s MERGE1 +CASE1: + ldftn int32 JitTest.Test::Main1() + br.s MERGE1 +CASE2: + ldftn int32 JitTest.Test::Main2() +MERGE1: + tail. calli int32() + ret + } // end of method Test::Main + + .method private hidebysig specialname rtspecialname static + void .cctor() il managed + { + // Code size 14 (0xe) + .maxstack 8 + IL_0000: ldc.i4.1 + IL_0001: stsfld int32 JitTest.Test::m + IL_0006: ldc.i4.s 10 + IL_0008: stsfld int32 JitTest.Test::n + IL_000d: ret + } // end of method Test::.cctor + + .method public hidebysig specialname rtspecialname + instance void .ctor() il managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method Test::.ctor + + } // end of class Test + +} // end of namespace JitTest + +//*********** DISASSEMBLY COMPLETE *********************** diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/test_switch.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/test_switch.il new file mode 100644 index 0000000000..6e9da8b3b1 --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/test_switch.il @@ -0,0 +1,118 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly test_switch { } +.namespace JitTest +{ + .class private auto ansi beforefieldinit Test + extends [mscorlib]System.Object + { + .field private static int32 m + .field private static int32 n + .method private hidebysig static int32 Main1() il managed + { + .maxstack 4 + tail. call int32 JitTest.Test::Main2() + ret + } + .method private hidebysig static int32 Main2() il managed + { + .maxstack 4 + tail. call int32 JitTest.Test::Main3() + ret + } + .method private hidebysig static int32 Main3() il managed + { + .maxstack 4 + tail. call int32 JitTest.Test::Main() + ret + } + .method private hidebysig static int32 Main() il managed + { + .entrypoint + .maxstack 4 + .locals (int32 V_0) + ldc.i4.1 + call void [mscorlib]System.Environment::set_ExitCode(int32) + ldsfld int32 JitTest.Test::n + ldc.i4.1 + bne.un.s IL_0047 + + ldsfld int32 JitTest.Test::m + ldc.i4 0x375f00 + bne.un.s IL_0029 + + ldstr "PASSED: 10! == 3628800" + call void [mscorlib]System.Console::WriteLine(class System.String) + ldc.i4.s 100 + ret + +IL_0029: + ldstr "FAILED: 10! != " + ldsflda int32 JitTest.Test::m + call instance class System.String [mscorlib]System.Int32::ToString() + call class System.String [mscorlib]System.String::Concat(class System.String, class System.String) + call void [mscorlib]System.Console::WriteLine(class System.String) + ldc.i4.s 101 + ret + +IL_0047: + ldsfld int32 JitTest.Test::n + ldc.i4.1 + beq MERGE + + ldsfld int32 JitTest.Test::m + ldsfld int32 JitTest.Test::n + dup + ldc.i4.1 + sub + stsfld int32 JitTest.Test::n + mul + stsfld int32 JitTest.Test::m +MERGE: + ldsfld int32 JitTest.Test::n + switch (CASE1, CASE2, CASE3) + ldftn int32 JitTest.Test::Main() + br.s MERGE1 +CASE1: + ldftn int32 JitTest.Test::Main1() + br.s MERGE1 +CASE2: + ldftn int32 JitTest.Test::Main2() + br.s MERGE1 +CASE3: + ldftn int32 JitTest.Test::Main3() +MERGE1: + tail. calli int32() + ret + } // end of method Test::Main + + .method private hidebysig specialname rtspecialname static + void .cctor() il managed + { + // Code size 14 (0xe) + .maxstack 8 + IL_0000: ldc.i4.1 + IL_0001: stsfld int32 JitTest.Test::m + IL_0006: ldc.i4.s 10 + IL_0008: stsfld int32 JitTest.Test::n + IL_000d: ret + } // end of method Test::.cctor + + .method public hidebysig specialname rtspecialname + instance void .ctor() il managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method Test::.ctor + + } // end of class Test + +} // end of namespace JitTest + +//*********** DISASSEMBLY COMPLETE *********************** diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/test_virt.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/test_virt.il new file mode 100644 index 0000000000..e86d5b32df --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/test_virt.il @@ -0,0 +1,90 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly test_virt { } +.namespace JitTest +{ + .class private auto ansi beforefieldinit TestClass extends [mscorlib]System.Object + { + .field private static int32 m + .field private static int32 n + .method private hidebysig virtual instance int32 Main() il managed + { + .maxstack 4 + .locals (int32 V_0) + ldc.i4.1 + call void [mscorlib]System.Environment::set_ExitCode(int32) + ldsfld int32 JitTest.TestClass::n + ldc.i4.1 + bne.un.s IL_0047 + + ldsfld int32 JitTest.TestClass::m + ldc.i4 0x375f00 + bne.un.s IL_0029 + + ldstr "PASSED: 10! == 3628800" + call void [mscorlib]System.Console::WriteLine(class System.String) + ldc.i4.s 100 + ret + +IL_0029: + ldstr "FAILED: 10! != " + ldsflda int32 JitTest.TestClass::m + call instance class System.String [mscorlib]System.Int32::ToString() + call class System.String [mscorlib]System.String::Concat(class System.String, + class System.String) + call void [mscorlib]System.Console::WriteLine(class System.String) + ldc.i4.s 101 + ret + +IL_0047: + ldsfld int32 JitTest.TestClass::m + ldsfld int32 JitTest.TestClass::n + dup + ldc.i4.1 + sub + stsfld int32 JitTest.TestClass::n + mul + stsfld int32 JitTest.TestClass::m + ldarg.0 + tail. call instance int32 JitTest.TestClass::Main() + ret + } // end of method Test::Main + + .method private hidebysig static int32 Main1() il managed + { + .entrypoint + .maxstack 4 + newobj instance void JitTest.TestClass::.ctor() + tail. callvirt instance int32 JitTest.TestClass::Main() + ret + } + .method private hidebysig specialname rtspecialname static + void .cctor() il managed + { + // Code size 14 (0xe) + .maxstack 8 + IL_0000: ldc.i4.1 + IL_0001: stsfld int32 JitTest.TestClass::m + IL_0006: ldc.i4.s 10 + IL_0008: stsfld int32 JitTest.TestClass::n + IL_000d: ret + } // end of method Test::.cctor + + .method public hidebysig specialname rtspecialname + instance void .ctor() il managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method Test::.ctor + + } // end of class Test + +} // end of namespace JitTest + +//*********** DISASSEMBLY COMPLETE *********************** diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/test_void.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/test_void.il new file mode 100644 index 0000000000..65721a8084 --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall/test_void.il @@ -0,0 +1,77 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly test_void { } +.namespace JitTest +{ + .class private auto ansi beforefieldinit Test extends [mscorlib]System.Object + { + .field private static int32 m + .field private static int32 n + .method private hidebysig static void Main() il managed + { + .entrypoint + .maxstack 4 + .locals (int32 V_0) + ldsfld int32 JitTest.Test::n + ldc.i4.1 + bne.un.s IL_0047 + + ldsfld int32 JitTest.Test::m + ldc.i4 0x375f00 + bne.un.s IL_0029 + + ldstr "PASSED: 10! == 3628800" + call void [mscorlib]System.Console::WriteLine(class System.String) + ldc.i4.s 100 + call void [mscorlib]System.Environment::Exit(int32) + ret + +IL_0029: + ldstr "FAILED: 10! != " + ldsflda int32 JitTest.Test::m + call instance class System.String [mscorlib]System.Int32::ToString() + call class System.String [mscorlib]System.String::Concat(class System.String, class System.String) + call void [mscorlib]System.Console::WriteLine(class System.String) + ldc.i4.s 101 + call void [mscorlib]System.Environment::Exit(int32) + ret + +IL_0047: + ldsfld int32 JitTest.Test::m + ldsfld int32 JitTest.Test::n + dup + ldc.i4.1 + sub + stsfld int32 JitTest.Test::n + mul + stsfld int32 JitTest.Test::m + tail. call void JitTest.Test::Main() + ret + } + + .method private hidebysig specialname rtspecialname static + void .cctor() il managed + { + .maxstack 8 + IL_0000: ldc.i4.1 + IL_0001: stsfld int32 JitTest.Test::m + IL_0006: ldc.i4.s 10 + IL_0008: stsfld int32 JitTest.Test::n + IL_000d: ret + } + + .method public hidebysig specialname rtspecialname + instance void .ctor() il managed + { + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } + + } + +} diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall_v4/delegateParamCallTarget.cs b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall_v4/delegateParamCallTarget.cs new file mode 100644 index 0000000000..dafbc79314 --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall_v4/delegateParamCallTarget.cs @@ -0,0 +1,50 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/* + * When generating the code for a tail call, the JIT was not careful to preserve any stack-based parameters used in the computation of the call target address if it is a simple indirection (like in the case of delgate.Invoke). + * Thus, in the case where an outgoing argument overwrites the same slot as the incoming delegate, the new value is used in the indirection to compute the target address. + * The fix is to not hoist any parameter uses when we hoist the indirection onto the call, and instead use tmpvars. This leaves the use of the parameter above the assignment to the slot for the outgoing tail call. In this one example it actually made the code better. + * + * Expected output: + * Accomplice + * Passed + * + * Actual output: + * Accomplice + * Failed + */ + +using System; + +public delegate int DoIt(int a, int b, int c, DoIt d); + +internal class Repro +{ + private int DoItWrong(int a, int b, int c, DoIt d) + { + Console.WriteLine("Failed"); + return -1; + } + + private int DoItRight(int a, int b, int c, DoIt d) + { + Console.WriteLine("Pass"); + return 100; + } + + private int Accomplice(int a, int b, int c, DoIt d) + { + Console.WriteLine("Accomplice"); + DoIt d2 = this.DoItWrong; + return d(a, b, c, d2); + } + + public static int Main() + { + Repro r = new Repro(); + DoIt d = r.DoItRight; + return r.Accomplice(1, 2, 3, d); + } +} diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall_v4/delegateTail.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall_v4/delegateTail.il new file mode 100644 index 0000000000..1dcd53c660 --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall_v4/delegateTail.il @@ -0,0 +1,214 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + + + +.assembly extern mscorlib +{ + .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) + .ver 4:0:0:0 +} +.assembly extern System.Runtime +{ + .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) + .ver 4:0:0:0 +} +.assembly repro +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) + .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 + 63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) + .hash algorithm 0x00008004 + .ver 0:0:0:0 +} +.module repro.exe +.imagebase 0x00400000 +.file alignment 0x00000200 +.stackreserve 0x00100000 +.subsystem 0x0003 +.corflags 0x00000001 + + + +.class public auto ansi sealed beforefieldinit Closure + extends [mscorlib]System.Object +{ + .field public initonly object[] Constants + .field public initonly object[] Locals + .method public hidebysig specialname rtspecialname + instance void .ctor(object[] constants, + object[] locals) cil managed + { + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ldarg.0 + IL_0007: ldarg.1 + IL_0008: stfld object[] Closure::Constants + IL_000d: ldarg.0 + IL_000e: ldarg.2 + IL_000f: stfld object[] Closure::Locals + IL_0014: ret + } + + .method public hidebysig instance object + FImpl(object o1, + object o2, + object o3, + object o4, + object o5, + object o6, + object o7, + object o8, + object o9) cil managed + { + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld object[] Closure::Constants + IL_0006: ldc.i4.0 + IL_0007: ldelem.ref + IL_0008: castclass string[] + IL_000d: ret + } + + .method public hidebysig instance object + GImpl(int32 i1, + int32 i2, + int32 i3, + int32 i4, + int32 i5, + int32 i6, + int32 i7, + int32 i8, + int32 i9) cil managed + { + .maxstack 10 + IL_0000: ldarg.0 + IL_0001: ldfld object[] Closure::Constants + IL_0006: ldc.i4.0 + IL_0007: ldelem.ref + IL_0008: castclass class [mscorlib]System.Func`10 + IL_000d: ldarg.1 + IL_000e: box [mscorlib]System.Int32 + IL_0013: ldarg.2 + IL_0014: box [mscorlib]System.Int32 + IL_0019: ldarg.3 + IL_001a: box [mscorlib]System.Int32 + IL_001f: ldarg.s i4 + IL_0021: box [mscorlib]System.Int32 + IL_0026: ldarg.s i5 + IL_0028: box [mscorlib]System.Int32 + IL_002d: ldarg.s i6 + IL_002f: box [mscorlib]System.Int32 + IL_0034: ldarg.s i7 + IL_0036: box [mscorlib]System.Int32 + IL_003b: ldarg.s i8 + IL_003d: box [mscorlib]System.Int32 + IL_0042: ldarg.s i9 + IL_0044: box [mscorlib]System.Int32 + IL_0049: tail. + callvirt instance !9 class [mscorlib]System.Func`10::Invoke(!0, + !1, + !2, + !3, + !4, + !5, + !6, + !7, + !8) + IL_004f: ret + } + +} + +.class private abstract auto ansi sealed beforefieldinit Repro + extends [mscorlib]System.Object +{ + .method private hidebysig static int32 Main() cil managed + { + .entrypoint + .maxstack 10 + .locals init (class [mscorlib]System.Func`10 V_0, + class [mscorlib]System.Func`10 V_1, + object[] V_2, + string[] V_3, + object[] V_4) + IL_0000: ldc.i4.1 + IL_0001: newarr [mscorlib]System.Object + IL_0006: stloc.2 + IL_0007: ldloc.2 + IL_0008: ldc.i4.0 + IL_0009: ldc.i4.1 + IL_000a: newarr [mscorlib]System.String + IL_000f: stloc.3 + IL_0010: ldloc.3 + IL_0011: ldc.i4.0 + IL_0012: ldstr "a" + IL_0017: stelem.ref + IL_0018: ldloc.3 + IL_0019: stelem.ref + IL_001a: ldloc.2 + IL_001b: ldnull + IL_001c: newobj instance void Closure::.ctor(object[], + object[]) + IL_0021: ldftn instance object Closure::FImpl(object, + object, + object, + object, + object, + object, + object, + object, + object) + IL_0027: newobj instance void class [mscorlib]System.Func`10::.ctor(object, + native int) + IL_002c: stloc.0 + IL_002d: ldc.i4.1 + IL_002e: newarr [mscorlib]System.Object + IL_0033: stloc.s V_4 + IL_0035: ldloc.s V_4 + IL_0037: ldc.i4.0 + IL_0038: ldloc.0 + IL_0039: stelem.ref + IL_003a: ldloc.s V_4 + IL_003c: ldnull + IL_003d: newobj instance void Closure::.ctor(object[], + object[]) + IL_0042: ldftn instance object Closure::GImpl(int32, + int32, + int32, + int32, + int32, + int32, + int32, + int32, + int32) + IL_0048: newobj instance void class [mscorlib]System.Func`10::.ctor(object, + native int) + IL_004d: stloc.1 + IL_004e: ldloc.1 + IL_004f: ldc.i4.1 + IL_0050: ldc.i4.2 + IL_0051: ldc.i4.3 + IL_0052: ldc.i4.4 + IL_0053: ldc.i4.5 + IL_0054: ldc.i4.6 + IL_0055: ldc.i4.7 + IL_0056: ldc.i4.8 + IL_0057: ldc.i4.s 9 + IL_0059: callvirt instance !9 class [mscorlib]System.Func`10::Invoke(!0, + !1, + !2, + !3, + !4, + !5, + !6, + !7, + !8) + IL_005e: pop +ldc.i4 100 + IL_005f: ret + } + +} diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall_v4/hijacking.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall_v4/hijacking.il new file mode 100644 index 0000000000..6e380c380d --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall_v4/hijacking.il @@ -0,0 +1,352 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly hijacking +{ +} + +.class private sequential ansi sealed beforefieldinit ForceHelper + extends [mscorlib]System.ValueType +{ + .field public valuetype ForceHelper* me + .field public int64 counter +} // end of class ForceHelper + +.class private auto ansi beforefieldinit Repro + extends [mscorlib]System.Object +{ + .field private bool modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile) stop + .field private bool failed + .field private int64 counts + .field private int64 gc + .method private hidebysig instance void + TailHelper1(valuetype ForceHelper h) cil managed + { + // Code size 123 (0x7b) + .maxstack 3 + IL_0000: ldarga.s h + IL_0002: dup + IL_0003: ldfld int64 ForceHelper::counter + IL_0008: ldc.i4.1 + IL_0009: conv.i8 + IL_000a: add + IL_000b: stfld int64 ForceHelper::counter + IL_0010: ldarg.0 + IL_0011: volatile. + IL_0013: ldfld bool modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile) Repro::stop + IL_0018: brfalse.s IL_002e + + IL_001a: ldarg.0 + IL_001b: ldflda int64 Repro::counts + IL_0020: ldarga.s h + IL_0022: ldfld int64 ForceHelper::counter + IL_0027: call int64 [mscorlib]System.Threading.Interlocked::Add(int64&, + int64) + IL_002c: pop + IL_002d: ret + + IL_002e: ldarga.s h + IL_0030: conv.u + IL_0031: ldarga.s h + IL_0033: ldfld valuetype ForceHelper* ForceHelper::me + IL_0038: beq.s IL_0073 + + IL_003a: ldarga.s h + IL_003c: ldfld int64 ForceHelper::counter + IL_0041: ldc.i4.1 + IL_0042: conv.i8 + IL_0043: ble.s IL_0069 + + IL_0045: ldarg.0 + IL_0046: ldc.i4.1 + IL_0047: stfld bool Repro::failed + IL_004c: ldarg.0 + IL_004d: ldc.i4.1 + IL_004e: volatile. + IL_0050: stfld bool modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile) Repro::stop + IL_0055: ldarg.0 + IL_0056: ldflda int64 Repro::counts + IL_005b: ldarga.s h + IL_005d: ldfld int64 ForceHelper::counter + IL_0062: call int64 [mscorlib]System.Threading.Interlocked::Add(int64&, + int64) + IL_0067: pop + IL_0068: ret + + IL_0069: ldarga.s h + IL_006b: ldarga.s h + IL_006d: conv.u + IL_006e: stfld valuetype ForceHelper* ForceHelper::me + IL_0073: ldarg.0 + IL_0074: ldarg.1 + IL_0075: tail. call instance void Repro::TailHelper2(valuetype ForceHelper) + IL_007a: ret + } // end of method Repro::TailHelper1 + + .method private hidebysig instance void + TailHelper2(valuetype ForceHelper h) cil managed + { + // Code size 123 (0x7b) + .maxstack 3 + IL_0000: ldarga.s h + IL_0002: dup + IL_0003: ldfld int64 ForceHelper::counter + IL_0008: ldc.i4.1 + IL_0009: conv.i8 + IL_000a: add + IL_000b: stfld int64 ForceHelper::counter + IL_0010: ldarg.0 + IL_0011: volatile. + IL_0013: ldfld bool modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile) Repro::stop + IL_0018: brfalse.s IL_002e + + IL_001a: ldarg.0 + IL_001b: ldflda int64 Repro::counts + IL_0020: ldarga.s h + IL_0022: ldfld int64 ForceHelper::counter + IL_0027: call int64 [mscorlib]System.Threading.Interlocked::Add(int64&, + int64) + IL_002c: pop + IL_002d: ret + + IL_002e: ldarga.s h + IL_0030: conv.u + IL_0031: ldarga.s h + IL_0033: ldfld valuetype ForceHelper* ForceHelper::me + IL_0038: beq.s IL_0073 + + IL_003a: ldarga.s h + IL_003c: ldfld int64 ForceHelper::counter + IL_0041: ldc.i4.1 + IL_0042: conv.i8 + IL_0043: ble.s IL_0069 + + IL_0045: ldarg.0 + IL_0046: ldc.i4.1 + IL_0047: stfld bool Repro::failed + IL_004c: ldarg.0 + IL_004d: ldc.i4.1 + IL_004e: volatile. + IL_0050: stfld bool modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile) Repro::stop + IL_0055: ldarg.0 + IL_0056: ldflda int64 Repro::counts + IL_005b: ldarga.s h + IL_005d: ldfld int64 ForceHelper::counter + IL_0062: call int64 [mscorlib]System.Threading.Interlocked::Add(int64&, + int64) + IL_0067: pop + IL_0068: ret + + IL_0069: ldarga.s h + IL_006b: ldarga.s h + IL_006d: conv.u + IL_006e: stfld valuetype ForceHelper* ForceHelper::me + IL_0073: ldarg.0 + IL_0074: ldarg.1 + IL_0075: tail. call instance void Repro::TailHelper1(valuetype ForceHelper) + IL_007a: ret + } // end of method Repro::TailHelper2 + + .method private hidebysig instance void + TailCallThread() cil managed + { + // Code size 16 (0x10) + .maxstack 2 + .locals init (valuetype ForceHelper V_0) + IL_0000: ldloca.s V_0 + IL_0002: initobj ForceHelper + IL_0008: ldarg.0 + IL_0009: ldloc.0 + IL_000a: tail. call instance void Repro::TailHelper1(valuetype ForceHelper) + IL_000f: ret + } // end of method Repro::TailCallThread + + .method private hidebysig instance void + Collector() cil managed + { + // Code size 33 (0x21) + .maxstack 8 + IL_0000: br.s IL_0016 + + IL_0002: call void [mscorlib]System.GC::Collect() + IL_0007: ldarg.0 + IL_0008: dup + IL_0009: ldfld int64 Repro::gc + IL_000e: ldc.i4.1 + IL_000f: conv.i8 + IL_0010: add + IL_0011: stfld int64 Repro::gc + IL_0016: ldarg.0 + IL_0017: volatile. + IL_0019: ldfld bool modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile) Repro::stop + IL_001e: brfalse.s IL_0002 + + IL_0020: ret + } // end of method Repro::Collector + + .method private hidebysig static int32 + Main() cil managed + { + .entrypoint + // Code size 300 (0x12c) + .maxstack 5 + .locals init (class Repro V_0, + class [mscorlib]System.Threading.Thread[] V_1, + class [mscorlib]System.Threading.Thread V_2, + int32 V_3, + class [mscorlib]System.Threading.Thread V_4, + class [mscorlib]System.Threading.Thread[] V_5, + class [mscorlib]System.Threading.Thread[] V_6, + int32 V_7, + class [mscorlib]System.Threading.Thread[] V_8, + int32 V_9) + IL_0000: newobj instance void Repro::.ctor() + IL_0005: stloc.0 + IL_0006: ldc.i4.4 + IL_0007: newarr [mscorlib]System.Threading.Thread + IL_000c: stloc.s V_5 + IL_000e: ldloc.s V_5 + IL_0010: ldc.i4.0 + IL_0011: ldloc.0 + IL_0012: ldftn instance void Repro::Collector() + IL_0018: newobj instance void [mscorlib]System.Threading.ThreadStart::.ctor(object, + native int) + IL_001d: newobj instance void [mscorlib]System.Threading.Thread::.ctor(class [mscorlib]System.Threading.ThreadStart) + IL_0022: stelem.ref + IL_0023: ldloc.s V_5 + IL_0025: ldc.i4.1 + IL_0026: ldloc.0 + IL_0027: ldftn instance void Repro::TailCallThread() + IL_002d: newobj instance void [mscorlib]System.Threading.ThreadStart::.ctor(object, + native int) + IL_0032: newobj instance void [mscorlib]System.Threading.Thread::.ctor(class [mscorlib]System.Threading.ThreadStart) + IL_0037: stelem.ref + IL_0038: ldloc.s V_5 + IL_003a: ldc.i4.2 + IL_003b: ldloc.0 + IL_003c: ldftn instance void Repro::TailCallThread() + IL_0042: newobj instance void [mscorlib]System.Threading.ThreadStart::.ctor(object, + native int) + IL_0047: newobj instance void [mscorlib]System.Threading.Thread::.ctor(class [mscorlib]System.Threading.ThreadStart) + IL_004c: stelem.ref + IL_004d: ldloc.s V_5 + IL_004f: ldc.i4.3 + IL_0050: ldloc.0 + IL_0051: ldftn instance void Repro::TailCallThread() + IL_0057: newobj instance void [mscorlib]System.Threading.ThreadStart::.ctor(object, + native int) + IL_005c: newobj instance void [mscorlib]System.Threading.Thread::.ctor(class [mscorlib]System.Threading.ThreadStart) + IL_0061: stelem.ref + IL_0062: ldloc.s V_5 + IL_0064: stloc.1 + IL_0065: ldloc.1 + IL_0066: stloc.s V_6 + IL_0068: ldc.i4.0 + IL_0069: stloc.s V_7 + IL_006b: br.s IL_007f + + IL_006d: ldloc.s V_6 + IL_006f: ldloc.s V_7 + IL_0071: ldelem.ref + IL_0072: stloc.2 + IL_0073: ldloc.2 + IL_0074: callvirt instance void [mscorlib]System.Threading.Thread::Start() + IL_0079: ldloc.s V_7 + IL_007b: ldc.i4.1 + IL_007c: add + IL_007d: stloc.s V_7 + IL_007f: ldloc.s V_7 + IL_0081: ldloc.s V_6 + IL_0083: ldlen + IL_0084: conv.i4 + IL_0085: blt.s IL_006d + + IL_0087: ldc.i4.0 + IL_0088: stloc.3 + IL_0089: br.s IL_00a3 + + IL_008b: ldc.i4 0x3e8 + IL_0090: call void [mscorlib]System.Threading.Thread::Sleep(int32) + IL_0095: ldloc.0 + IL_0096: volatile. + IL_0098: ldfld bool modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile) Repro::stop + IL_009d: brtrue.s IL_00a8 + + IL_009f: ldloc.3 + IL_00a0: ldc.i4.1 + IL_00a1: add + IL_00a2: stloc.3 + IL_00a3: ldloc.3 + IL_00a4: ldc.i4.s 60 + IL_00a6: blt.s IL_008b + + IL_00a8: ldloc.0 + IL_00a9: ldc.i4.1 + IL_00aa: volatile. + IL_00ac: stfld bool modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile) Repro::stop + IL_00b1: ldloc.1 + IL_00b2: stloc.s V_8 + IL_00b4: ldc.i4.0 + IL_00b5: stloc.s V_9 + IL_00b7: br.s IL_00cd + + IL_00b9: ldloc.s V_8 + IL_00bb: ldloc.s V_9 + IL_00bd: ldelem.ref + IL_00be: stloc.s V_4 + IL_00c0: ldloc.s V_4 + IL_00c2: callvirt instance void [mscorlib]System.Threading.Thread::Join() + IL_00c7: ldloc.s V_9 + IL_00c9: ldc.i4.1 + IL_00ca: add + IL_00cb: stloc.s V_9 + IL_00cd: ldloc.s V_9 + IL_00cf: ldloc.s V_8 + IL_00d1: ldlen + IL_00d2: conv.i4 + IL_00d3: blt.s IL_00b9 + + IL_00d5: ldstr "Executed {0} GCs" + IL_00da: ldloc.0 + IL_00db: ldfld int64 Repro::gc + IL_00e0: box [mscorlib]System.Int64 + IL_00e5: call void [mscorlib]System.Console::WriteLine(string, + object) + IL_00ea: ldloc.0 + IL_00eb: ldfld bool Repro::failed + IL_00f0: brfalse.s IL_010a + + IL_00f2: ldstr "Executed {0} tail calls before failing" + IL_00f7: ldloc.0 + IL_00f8: ldfld int64 Repro::counts + IL_00fd: box [mscorlib]System.Int64 + IL_0102: call void [mscorlib]System.Console::WriteLine(string, + object) + IL_0107: ldc.i4.s 101 + IL_0109: ret + + IL_010a: ldstr "Executed {0} tail calls" + IL_010f: ldloc.0 + IL_0110: ldfld int64 Repro::counts + IL_0115: box [mscorlib]System.Int64 + IL_011a: call void [mscorlib]System.Console::WriteLine(string, + object) + IL_011f: ldstr "PASS" + IL_0124: call void [mscorlib]System.Console::WriteLine(string) + IL_0129: ldc.i4.s 100 + IL_012b: ret + } // end of method Repro::Main + + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method Repro::.ctor + +} // end of class Repro diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall_v4/smallFrame.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall_v4/smallFrame.il new file mode 100644 index 0000000000..84853eea08 --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall_v4/smallFrame.il @@ -0,0 +1,352 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } + +.assembly retbuf_bug { } + +.class private sequential ansi sealed beforefieldinit RetBuff + extends [mscorlib]System.ValueType +{ + .field public uint64 l1 + .field public uint64 l2 +} // end of class RetBuff + +.class private abstract auto ansi sealed beforefieldinit RetBufferBug + extends [mscorlib]System.Object +{ + .field private static int32 s_i + .field private static int32 s_j + .field private static int32 s_k + .field private static int32 s_l + .field private static int32 s_m + .field private static int32 s_n + .field private static int32 s_o + .field private static int32 s_p + .method private hidebysig static int32 + Main() cil managed + { + .entrypoint + // Code size 408 (0x198) + .maxstack 2 + .locals init ([0] int32 result, + [1] int32 i, + [2] int32 j, + [3] int32 k, + [4] int32 l, + [5] int32 m, + [6] int32 n, + [7] int32 o, + [8] int32 p) + .language '{3F5162F8-07C6-11D3-9053-00C04FA302A1}', '{994B45C4-E6E9-11D2-903F-00C04FA302A1}', '{5A869D0B-6611-11D3-BD2A-0000F80849BD}' + //.line 26,26 : 3,20 'c:\\tests\\dev10\\604601\\retbuf_bug.cs' + IL_0000: ldc.i4.s 100 + IL_0002: stloc.0 + //.line 27,27 : 3,11 '' + IL_0003: ldc.i4.0 + IL_0004: stsfld int32 RetBufferBug::s_i + //.line 28,28 : 3,11 '' + IL_0009: ldc.i4.0 + IL_000a: stsfld int32 RetBufferBug::s_j + //.line 29,29 : 3,11 '' + IL_000f: ldc.i4.0 + IL_0010: stsfld int32 RetBufferBug::s_k + //.line 30,30 : 8,18 '' + IL_0015: ldc.i4.0 + IL_0016: stloc.1 + //.line 16707566,16707566 : 0,0 '' + IL_0017: br IL_016e + + //.line 32,32 : 4,12 '' + IL_001c: ldloc.1 + IL_001d: stsfld int32 RetBufferBug::s_i + //.line 33,33 : 9,19 '' + IL_0022: ldc.i4.0 + IL_0023: stloc.2 + //.line 16707566,16707566 : 0,0 '' + IL_0024: br IL_0163 + + //.line 35,35 : 5,13 '' + IL_0029: ldloc.2 + IL_002a: stsfld int32 RetBufferBug::s_j + //.line 36,36 : 10,20 '' + IL_002f: ldc.i4.0 + IL_0030: stloc.3 + //.line 16707566,16707566 : 0,0 '' + IL_0031: br IL_0158 + + //.line 38,38 : 6,14 '' + IL_0036: ldloc.3 + IL_0037: stsfld int32 RetBufferBug::s_k + //.line 39,39 : 8,18 '' + IL_003c: ldc.i4.0 + IL_003d: stloc.s l + //.line 16707566,16707566 : 0,0 '' + IL_003f: br IL_014c + + //.line 41,41 : 4,12 '' + IL_0044: ldloc.s l + IL_0046: stsfld int32 RetBufferBug::s_l + //.line 42,42 : 9,19 '' + IL_004b: ldc.i4.0 + IL_004c: stloc.s m + //.line 16707566,16707566 : 0,0 '' + IL_004e: br IL_013e + + //.line 44,44 : 5,13 '' + IL_0053: ldloc.s m + IL_0055: stsfld int32 RetBufferBug::s_m + //.line 45,45 : 10,20 '' + IL_005a: ldc.i4.0 + IL_005b: stloc.s n + //.line 16707566,16707566 : 0,0 '' + IL_005d: br IL_0130 + + //.line 47,47 : 6,14 '' + IL_0062: ldloc.s n + IL_0064: stsfld int32 RetBufferBug::s_n + //.line 48,48 : 8,18 '' + IL_0069: ldc.i4.0 + IL_006a: stloc.s o + //.line 16707566,16707566 : 0,0 '' + IL_006c: br IL_0122 + + //.line 50,50 : 4,12 '' + IL_0071: ldloc.s o + IL_0073: stsfld int32 RetBufferBug::s_o + //.line 51,51 : 9,19 '' + IL_0078: ldc.i4.0 + IL_0079: stloc.s p + //.line 16707566,16707566 : 0,0 '' + IL_007b: br IL_0114 + + //.line 53,53 : 5,13 '' + IL_0080: ldloc.s p + IL_0082: stsfld int32 RetBufferBug::s_p + //.line 54,54 : 5,18 '' + IL_0087: call void RetBufferBug::TailCaller() + //.line 55,55 : 5,18 '' + IL_008c: ldsfld int32 RetBufferBug::s_i + IL_0091: ldloc.1 + IL_0092: beq.s IL_009c + + //.line 57,57 : 6,18 '' + IL_0094: ldc.i4.s 99 + IL_0096: stloc.0 + //.line 58,58 : 6,16 '' + IL_0097: br IL_0186 + + //.line 60,60 : 5,18 '' + IL_009c: ldsfld int32 RetBufferBug::s_j + IL_00a1: ldloc.2 + IL_00a2: beq.s IL_00ac + + //.line 62,62 : 6,18 '' + IL_00a4: ldc.i4.s 98 + IL_00a6: stloc.0 + //.line 63,63 : 6,16 '' + IL_00a7: br IL_0186 + + //.line 65,65 : 5,18 '' + IL_00ac: ldsfld int32 RetBufferBug::s_k + IL_00b1: ldloc.3 + IL_00b2: beq.s IL_00bc + + //.line 67,67 : 6,18 '' + IL_00b4: ldc.i4.s 97 + IL_00b6: stloc.0 + //.line 68,68 : 6,16 '' + IL_00b7: br IL_0186 + + //.line 70,70 : 5,18 '' + IL_00bc: ldsfld int32 RetBufferBug::s_l + IL_00c1: ldloc.s l + IL_00c3: beq.s IL_00cd + + //.line 72,72 : 6,18 '' + IL_00c5: ldc.i4.s 96 + IL_00c7: stloc.0 + //.line 73,73 : 6,16 '' + IL_00c8: br IL_0186 + + //.line 75,75 : 5,18 '' + IL_00cd: ldsfld int32 RetBufferBug::s_m + IL_00d2: ldloc.s m + IL_00d4: beq.s IL_00de + + //.line 77,77 : 6,18 '' + IL_00d6: ldc.i4.s 95 + IL_00d8: stloc.0 + //.line 78,78 : 6,16 '' + IL_00d9: br IL_0186 + + //.line 80,80 : 5,18 '' + IL_00de: ldsfld int32 RetBufferBug::s_n + IL_00e3: ldloc.s n + IL_00e5: beq.s IL_00ef + + //.line 82,82 : 6,18 '' + IL_00e7: ldc.i4.s 94 + IL_00e9: stloc.0 + //.line 83,83 : 6,16 '' + IL_00ea: br IL_0186 + + //.line 85,85 : 5,18 '' + IL_00ef: ldsfld int32 RetBufferBug::s_o + IL_00f4: ldloc.s o + IL_00f6: beq.s IL_0100 + + //.line 87,87 : 6,18 '' + IL_00f8: ldc.i4.s 93 + IL_00fa: stloc.0 + //.line 88,88 : 6,16 '' + IL_00fb: br IL_0186 + + //.line 90,90 : 5,18 '' + IL_0100: ldsfld int32 RetBufferBug::s_p + IL_0105: ldloc.s p + IL_0107: beq.s IL_010e + + //.line 92,92 : 6,18 '' + IL_0109: ldc.i4.s 94 + IL_010b: stloc.0 + //.line 93,93 : 6,16 '' + IL_010c: br.s IL_0186 + + //.line 51,51 : 27,30 '' + IL_010e: ldloc.s p + IL_0110: ldc.i4.1 + IL_0111: add + IL_0112: stloc.s p + //.line 51,51 : 20,25 '' + IL_0114: ldloc.s p + IL_0116: ldc.i4.7 + IL_0117: blt IL_0080 + + //.line 48,48 : 26,29 '' + IL_011c: ldloc.s o + IL_011e: ldc.i4.1 + IL_011f: add + IL_0120: stloc.s o + //.line 48,48 : 19,24 '' + IL_0122: ldloc.s o + IL_0124: ldc.i4.7 + IL_0125: blt IL_0071 + + //.line 45,45 : 28,31 '' + IL_012a: ldloc.s n + IL_012c: ldc.i4.1 + IL_012d: add + IL_012e: stloc.s n + //.line 45,45 : 21,26 '' + IL_0130: ldloc.s n + IL_0132: ldc.i4.7 + IL_0133: blt IL_0062 + + //.line 42,42 : 27,30 '' + IL_0138: ldloc.s m + IL_013a: ldc.i4.1 + IL_013b: add + IL_013c: stloc.s m + //.line 42,42 : 20,25 '' + IL_013e: ldloc.s m + IL_0140: ldc.i4.7 + IL_0141: blt IL_0053 + + //.line 39,39 : 26,29 '' + IL_0146: ldloc.s l + IL_0148: ldc.i4.1 + IL_0149: add + IL_014a: stloc.s l + //.line 39,39 : 19,24 '' + IL_014c: ldloc.s l + IL_014e: ldc.i4.7 + IL_014f: blt IL_0044 + + //.line 36,36 : 28,31 '' + IL_0154: ldloc.3 + IL_0155: ldc.i4.1 + IL_0156: add + IL_0157: stloc.3 + //.line 36,36 : 21,26 '' + IL_0158: ldloc.3 + IL_0159: ldc.i4.7 + IL_015a: blt IL_0036 + + //.line 33,33 : 27,30 '' + IL_015f: ldloc.2 + IL_0160: ldc.i4.1 + IL_0161: add + IL_0162: stloc.2 + //.line 33,33 : 20,25 '' + IL_0163: ldloc.2 + IL_0164: ldc.i4.7 + IL_0165: blt IL_0029 + + //.line 30,30 : 26,29 '' + IL_016a: ldloc.1 + IL_016b: ldc.i4.1 + IL_016c: add + IL_016d: stloc.1 + //.line 30,30 : 19,24 '' + IL_016e: ldloc.1 + IL_016f: ldc.i4.7 + IL_0170: blt IL_001c + + //.line 103,103 : 3,21 '' + IL_0175: ldloc.0 + IL_0176: ldc.i4.s 100 + IL_0178: bne.un.s IL_0186 + + //.line 105,105 : 4,30 '' + IL_017a: ldstr "Pass" + IL_017f: call void [mscorlib]System.Console::WriteLine(string) + //.line 106,106 : 4,18 '' + IL_0184: ldloc.0 + IL_0185: ret + + //.line 109,109 : 3,44 '' + IL_0186: ldstr "Failed: {0}" + IL_018b: ldloc.0 + IL_018c: box [mscorlib]System.Int32 + IL_0191: call void [mscorlib]System.Console::WriteLine(string, + object) + //.line 110,110 : 3,17 '' + IL_0196: ldloc.0 + IL_0197: ret + } // end of method RetBufferBug::Main + + .method private hidebysig static void TailCaller() cil managed + { + // Code size 7 (0x7) + .maxstack 8 + //.line 114,114 : 3,16 '' +// tail. // tail.call, pop, ret sequence is never valid for .NET Core (but is accepted by .NET x64) + IL_0000: call valuetype RetBuff RetBufferBug::TailCallee() + IL_0005: pop + //.line 115,115 : 2,3 '' + IL_0006: ret + } // end of method RetBufferBug::TailCaller + + .method private hidebysig static valuetype RetBuff + TailCallee() cil managed + { + // Code size 31 (0x1f) + .maxstack 2 + .locals init ([0] valuetype RetBuff result) + //.line 119,119 : 3,25 '' + IL_0000: ldloca.s result + IL_0002: ldc.i4 0xbadf00d + IL_0007: conv.i8 + IL_0008: stfld uint64 RetBuff::l1 + //.line 120,120 : 3,36 '' + IL_000d: ldloca.s result + IL_000f: ldc.i8 0x123456789abcdeef + IL_0018: stfld uint64 RetBuff::l2 + //.line 121,121 : 3,17 '' + IL_001d: ldloc.0 + IL_001e: ret + } // end of method RetBufferBug::TailCallee + +} // end of class RetBufferBug diff --git a/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall_v4/tailcall_AV.il b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall_v4/tailcall_AV.il new file mode 100644 index 0000000000..b6e671fb53 --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Methodical/tailcall_v4/tailcall_AV.il @@ -0,0 +1,181 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } + +.assembly o { } +.module o.exe +// MVID: {E5624CCE-2F8F-498D-8C7E-6479B0B6CEC7} +.imagebase 0x00400000 +.file alignment 0x00000200 +.stackreserve 0x00100000 +.subsystem 0x0003 // WINDOWS_CUI +.corflags 0x00000001 // ILONLY +// Image base: 0x0000000000970000 + + +// =============== CLASS MEMBERS DECLARATION =================== + +.class private auto ansi beforefieldinit TCS.TailCallStructs + extends [mscorlib]System.Object +{ + .method public hidebysig static void Head_0() cil managed noinlining + { + // Code size 33 (0x21) + .maxstack 2 + .locals init (int32 V_0, + valuetype CSCreate.MB1 V_1) + IL_0000: ldc.i4.0 + IL_0001: stloc.0 + IL_0002: ldloca.s V_1 + IL_0004: initobj CSCreate.MB1 + IL_000a: ldloca.s V_1 + IL_000c: ldc.i4.1 + IL_000d: stfld uint8 CSCreate.MB1::b0 + IL_0012: ldloc.1 + IL_0013: ldloca.s V_0 + IL_0015: call void TCS.TailCallStructs::Caller_0(valuetype CSCreate.MB1, + int32&) + IL_001a: ldloc.0 + IL_001b: call void [mscorlib]System.Console::WriteLine(int32) + IL_0020: ret + } // end of method TailCallStructs::Head_0 + + .method public hidebysig static void Caller_0(valuetype CSCreate.MB1 mbs0, + int32& result) cil managed noinlining + { + // Code size 18 (0x12) + .maxstack 2 + .locals init (typedref V_0) + IL_0000: ldarga.s mbs0 + IL_0002: mkrefany CSCreate.MB1 + IL_0007: stloc.0 + IL_0008: ldarg.1 + IL_0009: ldloc.0 + IL_000a: tail. + IL_000c: call void TCS.TailCallStructs::Callee_0(int32&, + typedref) + IL_0011: ret + } // end of method TailCallStructs::Caller_0 + + .method public hidebysig static void Callee_0(int32& result, + typedref tr0) cil managed noinlining + { + // Code size 37 (0x25) + .maxstack 3 + .locals init (valuetype CSCreate.MB1 V_0) + IL_0000: ldarg.1 + IL_0001: refanyval CSCreate.MB1 + IL_0006: ldobj CSCreate.MB1 + IL_000b: stloc.0 + IL_000c: ldloca.s V_0 + IL_000e: ldfld uint8 CSCreate.MB1::b0 + IL_0013: call void [mscorlib]System.Console::WriteLine(int32) + IL_0018: ldarg.0 + IL_0019: dup + IL_001a: ldind.i4 + IL_001b: ldloca.s V_0 + IL_001d: ldfld uint8 CSCreate.MB1::b0 + IL_0022: add + IL_0023: stind.i4 + IL_0024: ret + } // end of method TailCallStructs::Callee_0 + + .method public hidebysig static int32 Main() cil managed + { + .entrypoint + // Code size 26 (0x1a) + .maxstack 8 + IL_0000: call void TCS.TailCallStructs::Head_0() +ldc.i4 100 + IL_0019: ret + } // end of method TailCallStructs::Main + + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method TailCallStructs::.ctor + +} // end of class TCS.TailCallStructs + +.class private sequential ansi sealed beforefieldinit CSCreate.MB1 + extends [mscorlib]System.ValueType +{ + .field public uint8 b0 +} // end of class CSCreate.MB1 + +.class private sequential ansi sealed beforefieldinit CSCreate.MB2 + extends [mscorlib]System.ValueType +{ + .field public uint8 b0 + .field public uint8 b1 +} // end of class CSCreate.MB2 + +.class private sequential ansi sealed beforefieldinit CSCreate.MB3 + extends [mscorlib]System.ValueType +{ + .field public uint8 b0 + .field public uint8 b1 + .field public uint8 b2 +} // end of class CSCreate.MB3 + +.class private sequential ansi sealed beforefieldinit CSCreate.MB4 + extends [mscorlib]System.ValueType +{ + .field public uint8 b0 + .field public uint8 b1 + .field public uint8 b2 + .field public uint8 b3 +} // end of class CSCreate.MB4 + +.class private sequential ansi sealed beforefieldinit CSCreate.MB5 + extends [mscorlib]System.ValueType +{ + .field public uint8 b0 + .field public uint8 b1 + .field public uint8 b2 + .field public uint8 b3 + .field public uint8 b4 +} // end of class CSCreate.MB5 + +.class private sequential ansi sealed beforefieldinit CSCreate.MB6 + extends [mscorlib]System.ValueType +{ + .field public uint8 b0 + .field public uint8 b1 + .field public uint8 b2 + .field public uint8 b3 + .field public uint8 b4 + .field public uint8 b5 +} // end of class CSCreate.MB6 + +.class private sequential ansi sealed beforefieldinit CSCreate.MB7 + extends [mscorlib]System.ValueType +{ + .field public uint8 b0 + .field public uint8 b1 + .field public uint8 b2 + .field public uint8 b3 + .field public uint8 b4 + .field public uint8 b5 + .field public uint8 b6 +} // end of class CSCreate.MB7 + +.class private sequential ansi sealed beforefieldinit CSCreate.MB8 + extends [mscorlib]System.ValueType +{ + .field public uint8 b0 + .field public uint8 b1 + .field public uint8 b2 + .field public uint8 b3 + .field public uint8 b4 + .field public uint8 b5 + .field public uint8 b6 + .field public uint8 b7 +} // end of class CSCreate.MB8 diff --git a/mono/tests/tailcall/coreclr/JIT/Regression/VS-ia64-JIT/V1.2-M02/b102844/tailcallcalli.il b/mono/tests/tailcall/coreclr/JIT/Regression/VS-ia64-JIT/V1.2-M02/b102844/tailcallcalli.il new file mode 100644 index 0000000000..21be65fdbf --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/Regression/VS-ia64-JIT/V1.2-M02/b102844/tailcallcalli.il @@ -0,0 +1,83 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly bug { } + +.namespace JitTest +{ + .class private auto ansi Test + extends [mscorlib]System.Object + { + .method private hidebysig static void + DoStuff(method void *() A_0) cil managed + { + // Code size 9 (0x9) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: tail. + IL_0003: calli void() + IL_0008: ret + } // end of method Test::DoStuff + + .method private hidebysig static method void *() + RetStuff() cil managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldftn void JitTest.Test::DummyMethod() + IL_0006: ret + } // end of method Test::RetStuff + + .method private hidebysig static void + DummyMethod() cil managed + { + // Code size 11 (0xb) + .maxstack 8 + IL_0000: ldstr "Looks good." + IL_0005: call void [mscorlib]System.Console::WriteLine(string) + IL_000a: ret + } // end of method Test::DummyMethod + + .method private hidebysig static void + TestMain() cil managed + { + // Code size 36 (0x24) + .maxstack 4 + .locals (int32 V_0) + IL_0000: ldftn void JitTest.Test::DummyMethod() + IL_0006: ldftn void JitTest.Test::DoStuff(method void *()) + IL_000c: calli void(method void *()) + IL_0011: ldftn method void *() JitTest.Test::RetStuff() + IL_0017: calli method void *()() + IL_001c: tail. + IL_001e: calli void() + IL_0023: ret + } // end of method Test::TestMain + + .method private hidebysig static int32 + Main() cil managed + { + .entrypoint + // Code size 17 (0x11) + .maxstack 4 + IL_0000: ldftn void JitTest.Test::TestMain() + IL_0006: calli void() + IL_000b: ldc.i4 0x64 + IL_0010: ret + } // end of method Test::Main + + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method Test::.ctor + + } // end of class Test + +} // end of namespace JitTest diff --git a/mono/tests/tailcall/coreclr/JIT/opt/ETW/TailCallCases.il b/mono/tests/tailcall/coreclr/JIT/opt/ETW/TailCallCases.il new file mode 100644 index 0000000000..5b1dba982b --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/opt/ETW/TailCallCases.il @@ -0,0 +1,266 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } + +.assembly TailCallCases +{ + // --- The following custom attribute is added automatically, do not uncomment ------- + // .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 03 00 00 00 00 00 ) + + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) + .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx + 63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows. + .hash algorithm 0x00008004 + .ver 4:0:20225:0 +} +.module TailCallCases.exe +// MVID: {E63A46BE-A0B6-41DA-82A6-56B3E895EC8C} +.imagebase 0x00400000 +.file alignment 0x00000200 +.stackreserve 0x00100000 +.subsystem 0x0003 // WINDOWS_CUI +.corflags 0x00000001 // ILONLY +// Image base: 0x00000000000B0000 + + +// =============== CLASS MEMBERS DECLARATION =================== + +.class private sequential ansi sealed beforefieldinit ETW.threeByteStruct + extends [mscorlib]System.ValueType +{ + .field public uint8 x + .field public uint8 y + .field public uint8 z + .method public hidebysig specialname rtspecialname + instance void .ctor(uint8 s, + uint8 t, + uint8 u) cil managed + { + // Code size 22 (0x16) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: stfld uint8 ETW.threeByteStruct::x + IL_0007: ldarg.0 + IL_0008: ldarg.2 + IL_0009: stfld uint8 ETW.threeByteStruct::y + IL_000e: ldarg.0 + IL_000f: ldarg.3 + IL_0010: stfld uint8 ETW.threeByteStruct::z + IL_0015: ret + } // end of method threeByteStruct::.ctor + + .method public hidebysig specialname rtspecialname + instance void .ctor(valuetype ETW.threeByteStruct s) cil managed + { + // Code size 40 (0x28) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarga.s s + IL_0003: ldfld uint8 ETW.threeByteStruct::x + IL_0008: stfld uint8 ETW.threeByteStruct::x + IL_000d: ldarg.0 + IL_000e: ldarga.s s + IL_0010: ldfld uint8 ETW.threeByteStruct::y + IL_0015: stfld uint8 ETW.threeByteStruct::y + IL_001a: ldarg.0 + IL_001b: ldarga.s s + IL_001d: ldfld uint8 ETW.threeByteStruct::z + IL_0022: stfld uint8 ETW.threeByteStruct::z + IL_0027: ret + } // end of method threeByteStruct::.ctor + +} // end of class ETW.threeByteStruct + +.class private auto ansi beforefieldinit ETW.TailCallETW + extends [mscorlib]System.Object +{ + .method private hidebysig static int32 + optimized(int32 x) cil managed + { + // Code size 8 (0x8) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.1 + IL_0002: tail. call int32 ETW.TailCallETW::recursiveHelper(int32, + int32) + IL_0007: ret + } // end of method TailCallETW::optimized + + .method private hidebysig static int32 + recursive(int32 x) cil managed + { + // Code size 8 (0x8) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.1 + IL_0002: tail. call int32 ETW.TailCallETW::recursiveHelper(int32, + int32) + IL_0007: ret + } // end of method TailCallETW::recursive + + .method private hidebysig static int32 + recursiveHelper(int32 x, + int32 result) cil managed + { + // Code size 18 (0x12) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.1 + IL_0002: beq.s IL_0010 + + IL_0004: ldarg.0 + IL_0005: ldc.i4.1 + IL_0006: sub + IL_0007: ldarg.0 + IL_0008: ldarg.1 + IL_0009: mul + IL_000a: tail. call int32 ETW.TailCallETW::recursiveHelper(int32, + int32) + IL_000f: ret + + IL_0010: ldarg.1 + IL_0011: ret + } // end of method TailCallETW::recursiveHelper + + .method private hidebysig static int32 + helper(valuetype ETW.threeByteStruct s) cil managed + { + // Code size 8 (0x8) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.1 + IL_0002: tail. call int32 ETW.TailCallETW::helperHelper(valuetype ETW.threeByteStruct, + int32) + IL_0007: ret + } // end of method TailCallETW::helper + + .method private hidebysig static int32 + helperHelper(valuetype ETW.threeByteStruct s, + int32 result) cil managed + { + // Code size 52 (0x34) + .maxstack 3 + .locals init ([0] valuetype ETW.threeByteStruct sMinus1) + IL_0000: ldloca.s sMinus1 + IL_0002: ldarg.0 + IL_0003: call instance void ETW.threeByteStruct::.ctor(valuetype ETW.threeByteStruct) + IL_0008: ldloca.s sMinus1 + IL_000a: dup + IL_000b: ldfld uint8 ETW.threeByteStruct::x + IL_0010: ldc.i4.1 + IL_0011: sub + IL_0012: conv.u1 + IL_0013: stfld uint8 ETW.threeByteStruct::x + IL_0018: ldarga.s s + IL_001a: ldfld uint8 ETW.threeByteStruct::x + IL_001f: ldc.i4.1 + IL_0020: beq.s IL_0032 + + IL_0022: ldloc.0 + IL_0023: ldarga.s s + IL_0025: ldfld uint8 ETW.threeByteStruct::x + IL_002a: ldarg.1 + IL_002b: mul + IL_002c: tail. call int32 ETW.TailCallETW::helperHelper(valuetype ETW.threeByteStruct, + int32) + IL_0031: ret + + IL_0032: ldarg.1 + IL_0033: ret + } // end of method TailCallETW::helperHelper + + .method private hidebysig static int32 + failed(int32 x) cil managed synchronized + { + // Code size 8 (0x8) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.1 + IL_0002: tail. call int32 ETW.TailCallETW::failedHelper(int32, + int32) + IL_0007: ret + } // end of method TailCallETW::failed + + .method private hidebysig static int32 + failedHelper(int32 x, + int32 result) cil managed + { + // Code size 18 (0x12) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.1 + IL_0002: beq.s IL_0010 + + IL_0004: ldarg.0 + IL_0005: ldc.i4.1 + IL_0006: sub + IL_0007: ldarg.0 + IL_0008: ldarg.1 + IL_0009: mul + IL_000a: tail. call int32 ETW.TailCallETW::failedHelper(int32, + int32) + IL_000f: ret + + IL_0010: ldarg.1 + IL_0011: ret + } // end of method TailCallETW::failedHelper + + .method private hidebysig static int32 + Main() cil managed + { + .entrypoint + // Code size 103 (0x67) + .maxstack 4 + .locals init ([0] int32 x, + [1] valuetype ETW.threeByteStruct s) + IL_0000: ldc.i4.s 10 + IL_0002: stloc.0 + IL_0003: ldloca.s s + IL_0005: ldc.i4.s 10 + IL_0007: ldc.i4.s 11 + IL_0009: ldc.i4.s 12 + IL_000b: call instance void ETW.threeByteStruct::.ctor(uint8, + uint8, + uint8) + IL_0010: ldstr "Recursive gives: {0}" + IL_0015: ldloc.0 + IL_0016: call int32 ETW.TailCallETW::recursive(int32) + IL_001b: box [mscorlib]System.Int32 + IL_0020: call void [mscorlib]System.Console::WriteLine(string, + object) + IL_0025: ldstr "Optimized gives: {0}" + IL_002a: ldloc.0 + IL_002b: call int32 ETW.TailCallETW::optimized(int32) + IL_0030: box [mscorlib]System.Int32 + IL_0035: call void [mscorlib]System.Console::WriteLine(string, + object) + IL_003a: ldstr "Helper gives: {0}" + IL_003f: ldloc.1 + IL_0040: call int32 ETW.TailCallETW::helper(valuetype ETW.threeByteStruct) + IL_0045: box [mscorlib]System.Int32 + IL_004a: call void [mscorlib]System.Console::WriteLine(string, + object) + IL_004f: ldstr "Failed gives: {0}" + IL_0054: ldloc.0 + IL_0055: call int32 ETW.TailCallETW::failed(int32) + IL_005a: box [mscorlib]System.Int32 + IL_005f: call void [mscorlib]System.Console::WriteLine(string, + object) + IL_0064: ldc.i4.s 100 + IL_0066: ret + } // end of method TailCallETW::Main + + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method TailCallETW::.ctor + +} // end of class ETW.TailCallETW diff --git a/mono/tests/tailcall/coreclr/JIT/opt/FastTailCall/FastTailCallCandidates.cs b/mono/tests/tailcall/coreclr/JIT/opt/FastTailCall/FastTailCallCandidates.cs new file mode 100644 index 0000000000..50bd682c1e --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/opt/FastTailCall/FastTailCallCandidates.cs @@ -0,0 +1,1165 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +//////////////////////////////////////////////////////////////////////////////// +// Types +//////////////////////////////////////////////////////////////////////////////// + +public class FastTailCallCandidates +{ + //////////////////////////////////////////////////////////////////////////// + // Globals + //////////////////////////////////////////////////////////////////////////// + + public static int s_ret_value = 100; + + //////////////////////////////////////////////////////////////////////////// + // Helpers + //////////////////////////////////////////////////////////////////////////// + + /// + /// Check the return value of the test and set s_ret_value if incorrect + /// + public static void CheckOutput(int code) + { + // If there has been a previous failure then do not reset the first + // failure this will be the return value. + if (s_ret_value != 100) + { + return; + } + + if (code != 100) + { + s_ret_value = code; + } + } + + /// + /// Run each individual test case + /// + /// + /// + /// If you add any new test case scenarios please use reuse code and follow + /// the pattern below. Please increment the return value so it + /// is easy to determine in the future which scenario is failing. + /// + public static int Tester(int a) + { + CheckOutput(SimpleTestCase()); + CheckOutput(IntegerArgs(10, 11, 12, 13, 14, 15)); + CheckOutput(FloatArgs(10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f)); + CheckOutput(IntAndFloatArgs(10, 11, 12, 13, 14, 15, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f)); + CheckOutput(CallerGithubIssue12468(1, 2, 3, 4, 5, 6, 7, 8, new StructSizeSixteenNotExplicit(1, 2))); + CheckOutput(DoNotFastTailCallSimple(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14)); + CheckOutput(StackBasedCaller(16, new StructSizeTwentyFour(1, 2, 3))); + CheckOutput(CallerSimpleHFACase(new HFASize32(1.0, 2.0, 3.0, 4.0), 1.0, 2.0, 3.0, 4.0)); + CheckOutput(CallerHFACaseWithStack(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, new HFASize32(1.0, 2.0, 3.0, 4.0))); + CheckOutput(CallerHFACaseCalleeOnly(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0)); + CheckOutput(CallerHFaCaseCalleeStackArgs(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)); + CheckOutput(DoubleCountRetBuffCaller(1)); + + return s_ret_value; + + } + + //////////////////////////////////////////////////////////////////////////// + // Simple fast tail call case + //////////////////////////////////////////////////////////////////////////// + + /// + /// Simple fast tail call case. + /// + /// + /// + /// This is mostly supposed to be a smoke test. It can also be seen as a + /// constant + /// + /// Return 100 is a pass. + /// + /// + public static int SimpleTestCase(int retValue = 10) + { + retValue += 1; + + if (retValue == 100) + { + return retValue; + } + else + { + return SimpleTestCase(retValue); + } + } + + //////////////////////////////////////////////////////////////////////////// + // Integer args + //////////////////////////////////////////////////////////////////////////// + + /// + /// Simple fast tail call case that includes integer args + /// + /// + /// + /// Return 100 is a pass. + /// Return 101 is a failure. + /// + /// + public static int IntegerArgs(int arg1, + int arg2, + int arg3, + int arg4, + int arg5, + int arg6, + int retValue = 10) + { + retValue += 1; + + if (retValue == 100) + { + if (arg1 != 10 || + arg2 != 11 || + arg3 != 12 || + arg4 != 13 || + arg5 != 14 || + arg6 != 15) + { + return 101; + } + + return retValue; + } + else + { + return IntegerArgs(arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + retValue); + } + } + + //////////////////////////////////////////////////////////////////////////// + // Float args + //////////////////////////////////////////////////////////////////////////// + + /// + /// Simple fast tail call case that includes floating point args + /// + /// + /// + /// Return 100 is a pass. + /// Return 102 is a failure. + /// + /// + public static int FloatArgs(float arg1, + float arg2, + float arg3, + float arg4, + float arg5, + float arg6, + int retValue = 10) + { + retValue += 1; + + if (retValue == 100) + { + if (arg1 != 10.0f || + arg2 != 11.0f || + arg3 != 12.0f || + arg4 != 13.0f || + arg5 != 14.0f || + arg6 != 15.0f) + { + return 102; + } + + return retValue; + } + else + { + return FloatArgs(arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + retValue); + } + } + + //////////////////////////////////////////////////////////////////////////// + // Integer and Float args + //////////////////////////////////////////////////////////////////////////// + + /// + /// Simple fast tail call case that includes integer and floating point args + /// + /// + /// + /// Return 100 is a pass. + /// Return 103 is a failure. + /// + /// + public static int IntAndFloatArgs(int argi1, + int argi2, + int argi3, + int argi4, + int argi5, + int argi6, + float argf1, + float argf2, + float argf3, + float argf4, + float argf5, + float argf6, + int retValue = 10) + { + retValue += 1; + + if (retValue == 100) + { + if (argi1 != 10 || + argi2 != 11 || + argi3 != 12 || + argi4 != 13 || + argi5 != 14 || + argi6 != 15 || + argf1 != 10.0f || + argf2 != 11.0f || + argf3 != 12.0f || + argf4 != 13.0f || + argf5 != 14.0f || + argf6 != 15.0f) + { + return 103; + } + + return retValue; + } + else + { + return IntAndFloatArgs(argi1, + argi2, + argi3, + argi4, + argi5, + argi6, + argf1, + argf2, + argf3, + argf4, + argf5, + argf6, + retValue); + } + } + + /// + /// Decision not to tail call. See DoNotFastTailCallSimple for more info + /// + public static int DoNotFastTailCallHelper(int one, + int two, + int three, + int four, + int five, + int six, + int seven, + int eight, + int nine, + int ten, + int eleven, + int twelve, + int thirteen, + int fourteen) + { + if (one == 1) + { + two = one + two; + } + + if (two == 3) + { + three = two + three; + } + + if (three == 6) + { + four = four + three; + } + + if (four != 10) + { + return 104; + } + + if (five != 5) + { + return 104; + } + + if (six != 6) + { + return 104; + } + + if (seven != 7) + { + return 104; + } + + if (eight != 8) + { + return 104; + } + + if (nine != 9) + { + return 104; + } + + if (ten != 10) + { + return 104; + } + + if (eleven != 11) + { + return 104; + } + + if (twelve != 12) + { + return 104; + } + + if (thirteen != 13) + { + return 104; + } + + if (fourteen != 14) + { + return 104; + } + + return 100; + } + + /// + /// Decision not to tail call. + /// + /// + /// + /// The callee has 6 int register arguments on x64 linux. + /// With 8 * 8 (64) bytes stack size + /// + /// Return 100 is a pass. + /// Return 104 is a failure. + /// + /// + public static int DoNotFastTailCallSimple(float one, + float two, + float three, + float four, + float five, + float six, + float seven, + float eight, + int first, + int second, + int third, + int fourth, + int fifth, + int sixth) + { + if (one % 2 == 0) + { + return DoNotFastTailCallHelper((int) two, + (int) one, + (int) three, + (int) four, + (int) five, + (int) six, + (int) seven, + (int) eight, + first, + second, + third, + fourth, + fifth, + sixth); // Cannot fast tail call + } + else + { + return DoNotFastTailCallHelper((int) one, + (int) two, + (int) three, + (int) four, + (int) five, + (int) six, + (int) seven, + (int) eight, + first, + second, + third, + fourth, + fifth, + sixth); // Cannot fast tail call + } + } + + //////////////////////////////////////////////////////////////////////////// + // HFAs + //////////////////////////////////////////////////////////////////////////// + + public struct HFASize16 + { + public double a; + public double b; + + public HFASize16(double a, double b) + { + this.a = a; + this.b = b; + } + } + + public struct HFASize24 + { + public double a; + public double b; + public double c; + + public HFASize24(double a, double b, double c) + { + this.a = a; + this.b = b; + this.c = c; + } + } + + public struct HFASize32 + { + public double a; + public double b; + public double c; + public double d; + + public HFASize32(double a, double b, double c, double d) + { + this.a = a; + this.b = b; + this.c = c; + this.d = d; + } + } + + /// + /// Possible to fast tail call only on arm64. See CallerSimpleHFACase for + /// more information. + /// + public static int CalleeSimpleHFACase(double one, + double two, + double three, + double four, + double five, + double six, + double seven, + double eight) + { + int count = 0; + for (double i = 0; i < one; ++i) + { + if (i % 2 == 0) + { + ++count; + } + } + + if (count == 1) + { + return 100; + } + + else + { + return 107; + } + } + + /// + /// Possible to fast tail call only on arm64 + /// + /// + /// + /// This test case is really only interesting on arm64 + /// + /// Arm64: + /// caller has 8 register arguments and no stack space + /// callee has 8 register arguments and no stack space + /// + /// x64 Linux: + /// caller has 4 register arguments and 64 bytes of stack space + /// callee has 8 register arguments + /// + /// Arm64 and linux x64 can both fast tail call + /// + /// Return 100 is a pass. + /// Return 107 is a failure. + /// + /// + public static int CallerSimpleHFACase(HFASize32 s1, + double one, + double two, + double three, + double four) + { + if (one % 2 == 0) + { + double a = one * 100; + double b = one + 1100; + return CalleeSimpleHFACase(one, + two, + three, + four, + a, + b, + one, + two); + } + else + { + double b = one + 1599; + double a = one + 16; + return CalleeSimpleHFACase(two, + one, + three, + four, + a, + b, + two, + one); + } + } + + /// + /// Possible to fast tail call only on arm64. See CallerHFACaseWithStack + /// for more information. + /// + public static int CalleeHFAStackSpace(double one, + double two, + double three, + double four, + double five, + double six, + double seven, + double eight, + double nine, + double ten) + { + int count = 0; + for (double i = 0; i < one; ++i) + { + if (i % 2 == 0) + { + ++count; + } + } + + if (count == 1) + { + return 100; + } + + else + { + return 108; + } + } + + /// + /// Possible to fast tail call only on arm64 + /// + /// + /// + /// This test case is really only interesting on arm64 + /// + /// Arm64: + /// caller has 8 register arguments and 32 bytes of stack space + /// callee has 8 register arguments and 16 bytes of stack space + /// + /// x64 linix: + /// caller has 8 register arguments and 32 bytes of stack space + /// callee has 8 register arguments and 16 bytes of stack space + /// + /// Arm64 can fast tail call while x64 linux will not. + /// Note that this is due to a bug in LowerFastTailCall that assumes + /// nCallerArgs <= nCalleeArgs + /// + /// Return 100 is a pass. + /// Return 108 is a failure. + /// + /// + public static int CallerHFACaseWithStack(double one, + double two, + double three, + double four, + double five, + double six, + double seven, + double eight, + HFASize32 s1) + { + if (one % 2 == 0) + { + double a = one * 100; + double b = one + 1100; + return CalleeHFAStackSpace(one, + two, + three, + four, + a, + b, + five, + six, + seven, + eight); + } + else + { + double b = one + 1599; + double a = one + 16; + return CalleeHFAStackSpace(one, + two, + three, + four, + a, + b, + six, + five, + seven, + eight); + } + } + + /// + /// Possible to fast tail call only on arm64. See CallerHFACaseCalleeOnly + /// for more information. + /// + public static int CalleeWithHFA(double one, + double two, + double three, + double four, + HFASize32 s1) + { + int count = 0; + for (double i = 0; i < one; ++i) + { + if (i % 2 == 0) + { + ++count; + } + } + + if (count == 1) + { + return 100; + } + + else + { + return 109; + } + } + + /// + /// Possible to fast tail call only on arm64 + /// + /// + /// + /// This test case is really only interesting on arm64 + /// + /// Arm64: + /// caller has 8 register arguments + /// callee has 8 register arguments + /// + /// x64 Linux: + /// caller has 8 register arguments + /// callee has 4 register arguments and 32 bytes of stack space + /// + /// Arm64 can fast tail call while x64 linux cannot + /// + /// Return 100 is a pass. + /// Return 109 is a failure. + /// + /// + public static int CallerHFACaseCalleeOnly(double one, + double two, + double three, + double four, + double five, + double six, + double seven, + double eight) + { + if (one % 2 == 0) + { + double a = one * 100; + double b = one + 1100; + return CalleeWithHFA(one, + a, + b, + four, + new HFASize32(a, b, five, six)); + } + else + { + double b = one + 1599; + double a = one + 16; + return CalleeWithHFA(one, + b, + a, + four, + new HFASize32(a, b, five, six)); + } + } + + /// + /// Possible to fast tail call on all targets. See + /// CallerHFaCaseCalleeStackArgs for info. + /// + /// + public static int CalleeWithStackHFA(double one, + double two, + double three, + double four, + double five, + double six, + double seven, + double eight, + HFASize16 s1) + { + int count = 0; + for (double i = 0; i < one; ++i) + { + if (i % 2 == 0) + { + ++count; + } + } + + if (count == 1) + { + return 100; + } + + else + { + return 110; + } + } + + /// + /// Possible to fast tail call on all targets + /// + /// + /// + /// This test case is really only interesting on arm64 and Linux x64 + /// because the decision to fast tail call will be reported as false. + /// + /// On arm64 this is because callee has stack args and has an hfa arg. + /// While on x64 Linux this is because the callee has stack args and has + /// a special 16 byte struct. + /// + /// Arm64: + /// caller has 8 register arguments and 16 bytes of stack space + /// callee has 8 register arguments and 16 bytes of stack space + /// + /// x64 Linux: + /// caller has 8 register arguments and 16 bytes of stack space + /// callee has 8 register arguments and 16 bytes of stack space + /// + /// Arm64 can fast tail call while x64 linux cannot. Note that this is + /// due to an implementation limitation. fgCanFastTail call relies on + /// fgMorphArgs, but fgMorphArgs relies on fgCanfast tail call. Therefore, + /// fgCanFastTailCall will not fast tail call if there is a 16 byte + /// struct and stack usage. + /// + /// Return 100 is a pass. + /// Return 110 is a failure. + /// + /// + public static int CallerHFaCaseCalleeStackArgs(double one, + double two, + double three, + double four, + double five, + double six, + double seven, + double eight, + double nine, + double ten) + { + if (one % 2 == 0) + { + double a = one * 100; + double b = one + 1100; + return CalleeWithStackHFA(one, + a, + b, + four, + five, + six, + seven, + eight, + new HFASize16(a, b)); + } + else + { + double b = one + 1599; + double a = one + 16; + return CalleeWithStackHFA(one, + a, + b, + four, + five, + six, + seven, + eight, + new HFASize16(a, b)); + } + } + + //////////////////////////////////////////////////////////////////////////// + // Stack Based args. + //////////////////////////////////////////////////////////////////////////// + + public struct StructSizeEightNotExplicit + { + public long a; + + public StructSizeEightNotExplicit(long a) + { + this.a = a; + } + } + + public struct StructSizeEightIntNotExplicit + { + public int a; + public int b; + + public StructSizeEightIntNotExplicit(int a, int b) + { + this.a = a; + this.b = b; + } + } + + public struct StructSizeSixteenNotExplicit + { + public long a; + public long b; + + public StructSizeSixteenNotExplicit(long a, long b) + { + this.a = a; + this.b = b; + } + + } + + /// + /// Possible to fast tail call. See CallerGithubIssue12468 for more info. + /// + public static int CalleeGithubIssue12468(int one, + int two, + int three, + int four, + int five, + int six, + int seven, + int eight, + StructSizeEightNotExplicit s1, + StructSizeEightNotExplicit s2) + { + int count = 0; + for (int i = 0; i < s1.a; ++i) + { + if (i % 10 == 0) + { + ++count; + } + } + + if (count == 160) + { + return 100; + } + + else + { + return 106; + } + } + + /// + /// Possible to fast tail call + /// + /// + /// + /// Caller has 6 register arguments and 1 stack argument (size 16) + /// Callee has 6 register arguments and 2 stack arguments (size 16) + /// + /// It is possible to fast tail call but will not due to a bug in + /// LowerFastTailCall which assumes nCallerArgs <= nCalleeArgs + /// + /// + /// Return 100 is a pass. + /// Return 106 is a failure. + /// + /// + public static int CallerGithubIssue12468(int one, + int two, + int three, + int four, + int five, + int six, + int seven, + int eight, + StructSizeSixteenNotExplicit s1) + { + if (one % 2 == 0) + { + long a = one * 100; + long b = one + 1100; + return CalleeGithubIssue12468(two, + one, + three, + four, + five, + six, + seven, + eight, + new StructSizeEightNotExplicit(a), + new StructSizeEightNotExplicit(b)); + } + else + { + long b = one + 1599; + long a = one + 16; + return CalleeGithubIssue12468(one, + two, + three, + four, + five, + six, + seven, + eight, + new StructSizeEightNotExplicit(b), + new StructSizeEightNotExplicit(a)); + } + } + + [StructLayout(LayoutKind.Explicit, Size=8, CharSet=CharSet.Ansi)] + public struct StructSizeThirtyTwo + { + [FieldOffset(0)] public int a; + [FieldOffset(8)] public int b; + [FieldOffset(16)] public int c; + [FieldOffset(24)] public int d; + + public StructSizeThirtyTwo(int a, int b, int c, int d) + { + this.a = a; + this.b = b; + this.c = c; + this.d = d; + } + }; + + [StructLayout(LayoutKind.Explicit, Size=8, CharSet=CharSet.Ansi)] + public struct StructSizeTwentyFour + { + [FieldOffset(0)] public int a; + [FieldOffset(8)] public int b; + [FieldOffset(16)] public int c; + + public StructSizeTwentyFour(int a, int b, int c) + { + this.a = a; + this.b = b; + this.c = c; + } + } + + /// + /// Decision to fast tail call. See StackBasedCaller for more + /// information. + /// + public static int StackBasedCallee(int a, int b, StructSizeThirtyTwo sstt) + { + int count = 0; + for (int i = 0; i < sstt.a; ++i) + { + if (i % 10 == 0) + { + ++count; + } + } + + if (count == 160) + { + return 100; + } + + else + { + return 105; + } + } + + /// + /// Decision to fast tail call + /// + /// + /// + /// On x64 linux this will not fast tail call. + /// + /// The caller has one stack argument of size 24 + /// The callee has one stack argument of size 32 + /// + /// On Arm64 this will fast tail call + /// + /// Both caller and callee have two register args. + /// + /// Return 100 is a pass. + /// Return 105 is a failure. + /// + /// + public static int StackBasedCaller(int i, StructSizeTwentyFour sstf) + { + if (i % 2 == 0) + { + int a = i * 100; + int b = i + 1100; + return StackBasedCallee(a, b, new StructSizeThirtyTwo(a, b, b, a)); + } + else + { + int b = i + 829; + int a = i + 16; + return StackBasedCallee(b, a, new StructSizeThirtyTwo(b, a, a, b)); + } + } + + /// + /// Decision to fast tail call. See DoubleCountRetBuffCaller for more + /// information. + /// + public static StructSizeThirtyTwo DoubleCountRetBuffCallee(StructSizeEightIntNotExplicit sstf, + StructSizeEightIntNotExplicit sstf2, + StructSizeEightIntNotExplicit sstf3, + StructSizeEightIntNotExplicit sstf4, + StructSizeEightIntNotExplicit sstf5) + { + int a = sstf.a; + int b = sstf.b; + + StructSizeThirtyTwo retVal = new StructSizeThirtyTwo(b, a, a, b); + + int count = 0; + for (int i = 0; i < b; ++i) + { + if (i % 2 == 0) + { + ++count; + } + } + + return retVal; + } + + /// + /// Decision to fast tail call. See DoubleCountRetBuffCaller for more + /// information. + /// + public static StructSizeThirtyTwo DoubleCountRetBuffCallerWrapper(int a, int b) + { + if (a % 2 == 0) + { + StructSizeEightIntNotExplicit eightBytes = new StructSizeEightIntNotExplicit(a, a); + a = 1; + b = b + 2; + return DoubleCountRetBuffCallee(eightBytes, eightBytes, eightBytes, eightBytes, eightBytes); + } + else + { + StructSizeEightIntNotExplicit eightBytes = new StructSizeEightIntNotExplicit(b, b); + a = 4; + b = b + 1; + return DoubleCountRetBuffCallee(eightBytes, eightBytes, eightBytes, eightBytes, eightBytes); + } + } + + /// + /// Decision to fast tail call + /// + /// + /// + /// On x64 linux this will fast tail call. + /// + /// The caller uses 3 integer registers (2 args, one ret buf) + /// The callee uses 6 integer registers (5 args, one ret buf) + /// + /// Return 100 is a pass. + /// Return 112 is a failure. + /// + /// + public static int DoubleCountRetBuffCaller(int i) + { + if (i % 2 == 0) + { + StructSizeThirtyTwo retVal = DoubleCountRetBuffCallerWrapper(4, 2); + + if (retVal.b == 4.0) + { + return 100; + } + else + { + return 112; + } + } + else + { + StructSizeThirtyTwo retVal = DoubleCountRetBuffCallerWrapper(3, 1); + + if (retVal.b == 1.0) + { + return 100; + } + else + { + return 112; + } + } + } + + //////////////////////////////////////////////////////////////////////////// + // Main + //////////////////////////////////////////////////////////////////////////// + + public static int Main() + { + return Tester(1); + } +} \ No newline at end of file diff --git a/mono/tests/tailcall/coreclr/JIT/opt/FastTailCall/FastTailCallInlining.cs b/mono/tests/tailcall/coreclr/JIT/opt/FastTailCall/FastTailCallInlining.cs new file mode 100644 index 0000000000..81ffd72d88 --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/opt/FastTailCall/FastTailCallInlining.cs @@ -0,0 +1,39 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.CompilerServices; + +public class Test +{ + public static int Main() + { + A(2); + return 100; + } + + public static void A(int i) + { + if (i > 0) + { + B(--i); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void B(int i) + { + C(i); + A(--i); + } + + public static void C(int i) + { + Console.WriteLine("In C"); + if (i==0) + { + Console.WriteLine("In C"); + } + } +} diff --git a/mono/tests/tailcall/coreclr/JIT/opt/FastTailCall/GitHubIssue12479.cs b/mono/tests/tailcall/coreclr/JIT/opt/FastTailCall/GitHubIssue12479.cs new file mode 100644 index 0000000000..0887e9af5f --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/opt/FastTailCall/GitHubIssue12479.cs @@ -0,0 +1,94 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +public class GitHubIssue12479 +{ + public static int callee(int one, + int two, + int three, + int four, + int five, + int six, + int seven, + int eight) + { + int count = 0; + + // Make sure this is not inlined. + for (int i = 0; i < one; ++i) + { + if (i % 4 == 0) ++count; + } + + return count; + } + + // Linux (x64): Eight incoming arguments, all passed in registers + // + // nCallerArgs: 8, stackSize: 0 bytes + public static int caller(float one, + float two, + float three, + float four, + float five, + float six, + float seven, + float eight) + { + if (one % 2 == 0) + { + // Eight outgoing arguments, six passed in registers, two on the stack. + // + // nCalleeArgs: 8, stackSize: 8 bytes + // + // This is a fast tail call candidate that should not be fast tail called + // because the callee's stack size will be larger than the caller's + return callee((int) two, + (int) one, + (int) eight, + (int) five, + (int) four, + (int) seven, + (int) six, + (int) three); + } + else + { + // Eight outgoing arguments, six passed in registers, two on the stack. + // + // nCalleeArgs: 8, stackSize: 8 bytes + // + // This is a fast tail call candidate that should not be fast tail called + // because the callee's stack size will be larger than the caller's + return callee((int) one, + (int) two, + (int) three, + (int) four, + (int) five, + (int) six, + (int) seven, + (int) eight); + } + + + } + + public static int Main() + { + // We have 8 floating args on unix. + int a = caller(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f); + + if (a == 1) + { + return 100; + } + + else + { + return 101; + } + } +} \ No newline at end of file diff --git a/mono/tests/tailcall/coreclr/JIT/opt/FastTailCall/StackFixup.cs b/mono/tests/tailcall/coreclr/JIT/opt/FastTailCall/StackFixup.cs new file mode 100644 index 0000000000..eaf095032a --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/opt/FastTailCall/StackFixup.cs @@ -0,0 +1,74 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +using System; + +public struct A +{ + public short a; + public short b; +} + +class TailCallStructPassing +{ + public static int bar(int count, A temp) + { + if (count < 100) + { + return count; + } + + else + { + count -= 100; + return bar(count, temp); + } + } + + public static int foo(A temp, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m, int n, int o, int p, int q, int r, int s, int t, int u, int v, int w, int decision, int count) + { + if (decision < 100) + { + return foo(temp, w, v, u, t, s, r, q, p, o, n, m, l, k, j, i, h, g, f, e, d, c, b, 500, 15); + } + + else + { + return bar(count, temp); + } + } + + public static int foo(int decision, int count, int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m, int n, int o, int p, int q, int r, int s, int t, int u, int v, int w, int x, int y, int z, A temp) + { + if (decision < 100) + { + return foo(temp, w, v, u, t, s, r, q, p, o, n, m, l, k, j, i, h, g, f, e, d, c, b, 500, 15); + } + + else + { + return bar(count, temp); + } + } + + public static int Main() + { + A temp = new A(); + temp.a = 50; + temp.b = 100; + + int ret = foo(50, 19000, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, temp); + + temp.a = (short)ret; + + if (temp.a == 15) + { + return 100; + } + + else + { + return -1; + } + } +} \ No newline at end of file diff --git a/mono/tests/tailcall/coreclr/JIT/opt/FastTailCall/StructPassingSimple.cs b/mono/tests/tailcall/coreclr/JIT/opt/FastTailCall/StructPassingSimple.cs new file mode 100644 index 0000000000..13ca0cbc48 --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/opt/FastTailCall/StructPassingSimple.cs @@ -0,0 +1,38 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +using System; + +// 10 byte struct +public struct A +{ + public int a; + public int b; + public short c; +} + +class TailCallStructPassingSimple +{ + // Simple tail call candidate that would be ignored on Arm64 and amd64 Unix + // due to https://github.com/dotnet/coreclr/issues/2666 + public static int ImplicitTailCallTenByteStruct(A a, int count=1000) + { + if (count-- == 0) + { + return 100; + } + + return ImplicitTailCallTenByteStruct(a, count); + } + + public static int Main() + { + A temp = new A(); + temp.a = 50; + temp.b = 500; + temp.c = 62; + + int ret = ImplicitTailCallTenByteStruct(temp); + return ret; + } +} \ No newline at end of file diff --git a/mono/tests/tailcall/coreclr/JIT/opt/Loops/SearchLoopTail.cs b/mono/tests/tailcall/coreclr/JIT/opt/Loops/SearchLoopTail.cs new file mode 100644 index 0000000000..10be60c021 --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/opt/Loops/SearchLoopTail.cs @@ -0,0 +1,160 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// Test for tail merging/duplication of search loops returning constants. + +using System.Runtime.CompilerServices; + +namespace N +{ + public static class C + { + [MethodImpl(MethodImplOptions.NoInlining)] + static bool HasPrimeUnderTwenty(int first, int last) + { + for (int n = first; n <= last; ++n) + { + if (n == 2) return true; + if (n == 3) return true; + if (n == 5) return true; + if (n == 7) return true; + if (n == 11) return true; + if (n == 13) return true; + if (n == 17) return true; + if (n == 19) return true; + } + + return false; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int Distance_abCD(string s) + { + int c_index = 0; + bool sawA = false; + bool sawB = false; + int index = 0; + + foreach (char c in s) + { + if (c == 'A') sawA = true; + if (c == 'B') + { + if (!sawA) return -1; + sawB = true; + } + if (c == 'C') + { + if (!sawB) return -1; + c_index = index; + } + if (c == 'D') + { + if (c_index == 0) return -1; + return (index - c_index); + } + ++index; + } + + return -1; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool TrueFalseOr(int[] input) + { + int n = 0, m = 0; + for (int i = 0; i < input.Length; ++i) + { + m = n; + n = input[i]; + if (n < 7) + return true; + if (n > 22) + return false; + if (n == 12) + return (m == 5); + } + + return (n == 9 || m == 13); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool TrueFalseAnd(int[] input) + { + int n = 0, m = 0; + for (int i = 0; i < input.Length; ++i) + { + m = n; + n = input[i]; + if (n < 7) + return true; + if (n > 22) + return false; + if (n == 12) + return (m == 5); + } + + return (n == 9 && m == 13); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool FalseTrueOr(int[] input) + { + int n = 0, m = 0; + for (int i = 0; i < input.Length; ++i) + { + m = n; + n = input[i]; + if (n < 7) + return false; + if (n > 22) + return true; + if (n == 12) + return (m == 5); + } + + return (n == 9 || m == 13); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool FalseTrueAnd(int[] input) + { + int n = 0, m = 0; + for (int i = 0; i < input.Length; ++i) + { + m = n; + n = input[i]; + if (n < 7) + return false; + if (n > 22) + return true; + if (n == 12) + return (m == 5); + } + + return (n == 9 && m == 13); + } + + public static int Main(string[] args) + { + if (HasPrimeUnderTwenty(22, 36) || !HasPrimeUnderTwenty(-1, 4)) + { + return -1; + } + + if ((Distance_abCD("xxxxAyyyyBzyzyzC1234D") != 5) || (Distance_abCD("nnABmmDC") != -1)) + { + return -1; + } + + int[] inputs = new int[] { 8, 20, 11, 13, 15 }; + if (!TrueFalseOr(inputs) || TrueFalseAnd(inputs) || !FalseTrueOr(inputs) || FalseTrueAnd(inputs)) + { + return -1; + } + + return 100; + } + } +} diff --git a/mono/tests/tailcall/coreclr/JIT/opt/Tailcall/TailcallVerifyTransparentLibraryWithPrefix.il b/mono/tests/tailcall/coreclr/JIT/opt/Tailcall/TailcallVerifyTransparentLibraryWithPrefix.il new file mode 100644 index 0000000000..ca789a673f --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/opt/Tailcall/TailcallVerifyTransparentLibraryWithPrefix.il @@ -0,0 +1,468 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + + + +// Metadata version: v2.0.50727 +.assembly extern mscorlib +{ + .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. + .ver 2:0:0:0 +} + +.module TailcallVerifyTransparentLibraryWithPrefix.dll +// MVID: {A0DB04B7-B678-4A57-9EEC-D55E6443C758} +.imagebase 0x00400000 +.file alignment 0x00000200 +.stackreserve 0x00100000 +.subsystem 0x0003 // WINDOWS_CUI +.corflags 0x00000001 // ILONLY +// Image base: 0x00F50000 + + +// =============== CLASS MEMBERS DECLARATION =================== + +.class public auto ansi beforefieldinit TailcallVerify.Condition22 + extends [mscorlib]System.Object +{ + .field private static int32 modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile) zero + .field private static int32 Result + .method public hidebysig static int32 Test1() cil managed nooptimization + { + // Code size 95 (0x5f) + .maxstack 3 + .locals init ([0] class [mscorlib]System.Exception e) + IL_0000: ldstr "Executing Condition22.Test1 - Caller(SecurityTran" + + "sparent): Arguments: None - ReturnType: void; Callee(SecurityCritical):" + + " Arguments: 0 - ReturnType: Int32" + IL_0005: call void [mscorlib]System.Console::WriteLine(string) + IL_000a: ldc.i4.s 100 + IL_000c: stsfld int32 TailcallVerify.Condition22::Result + .try + { + IL_0011: call void TailcallVerify.Condition22::Caller1() + IL_0016: leave.s IL_0035 + + } // end .try + catch [mscorlib]System.Exception + { + IL_0018: stloc.0 + IL_0019: ldloc.0 + IL_001a: isinst [mscorlib]System.MethodAccessException + IL_001f: brfalse.s IL_002a + + IL_0021: ldc.i4.s 100 + IL_0023: stsfld int32 TailcallVerify.Condition22::Result + IL_0028: br.s IL_0033 + + IL_002a: ldc.i4.s 101 + IL_002c: stsfld int32 TailcallVerify.Condition22::Result + IL_0031: rethrow + IL_0033: leave.s IL_0035 + + } // end handler + IL_0035: ldstr "Execution finished - Test " + IL_003a: ldsfld int32 TailcallVerify.Condition22::Result + IL_003f: ldc.i4.s 100 + IL_0041: beq.s IL_004a + + IL_0043: ldstr "FAILED" + IL_0048: br.s IL_004f + + IL_004a: ldstr "PASSED" + IL_004f: call string [mscorlib]System.String::Concat(string, + string) + IL_0054: call void [mscorlib]System.Console::WriteLine(string) + IL_0059: ldsfld int32 TailcallVerify.Condition22::Result + IL_005e: ret + } // end of method Condition22::Test1 + + .method private hidebysig static void Caller1() cil managed + { + // Code size 53 (0x35) + .maxstack 8 + IL_0000: ldc.i4.0 + IL_0001: newobj instance void [mscorlib]System.Diagnostics.StackFrame::.ctor(bool) + IL_0006: callvirt instance class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Diagnostics.StackFrame::GetMethod() + IL_000b: callvirt instance string [mscorlib]System.Reflection.MemberInfo::get_Name() + IL_0010: ldstr "Caller" + IL_0015: callvirt instance int32 [mscorlib]System.String::IndexOf(string) + IL_001a: ldc.i4.m1 + IL_001b: bne.un.s IL_002e + + IL_001d: ldstr "Failed, Method was inlined..." + IL_0022: call void [mscorlib]System.Console::WriteLine(string) + IL_0027: ldc.i4.s 101 + IL_0029: stsfld int32 TailcallVerify.Condition22::Result + IL_002e: tail. call void TailcallVerify.Condition22::Callee1() + IL_0034: ret + } // end of method Condition22::Caller1 + + .method private hidebysig static void + Callee1() cil managed noinlining + { + .custom instance void [mscorlib]System.Security.SecurityCriticalAttribute::.ctor() = ( 01 00 00 00 ) + // Code size 22 (0x16) + .maxstack 2 + .locals init ([0] int32 i) + IL_0000: ldstr "in Condition22.Callee1....." + IL_0005: call void [mscorlib]System.Console::WriteLine(string) + IL_000a: ldc.i4.1 + IL_000b: volatile. + IL_000d: ldsfld int32 modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile) TailcallVerify.Condition22::zero + IL_0012: div + IL_0013: stloc.0 + IL_0015: ret + } // end of method Condition22::Callee1 + + .method public hidebysig static int32 Test2() cil managed nooptimization + { + .custom instance void [mscorlib]System.Security.SecurityCriticalAttribute::.ctor() = ( 01 00 00 00 ) + // Code size 153 (0x99) + .maxstack 3 + .locals init ([0] class [mscorlib]System.Exception e) + IL_0000: ldstr "Executing Condition22.Test2 - Caller: Arguments: " + + "None - ReturnType: void; Callee: Arguments: 0 - ReturnType: Int32" + IL_0005: call void [mscorlib]System.Console::WriteLine(string) + IL_000a: ldc.i4.s 100 + IL_000c: stsfld int32 TailcallVerify.Condition22::Result + .try + { + IL_0011: call void TailcallVerify.Condition22::Caller2() + IL_0016: leave.s IL_006f + + } // end .try + catch [mscorlib]System.Exception + { + IL_0018: stloc.0 + IL_0019: ldloc.0 + IL_001a: isinst [mscorlib]System.DivideByZeroException + IL_001f: brtrue.s IL_002a + + IL_0021: ldc.i4.s 101 + IL_0023: stsfld int32 TailcallVerify.Condition22::Result + IL_0028: rethrow + IL_002a: ldloc.0 + IL_002b: callvirt instance string [mscorlib]System.Exception::get_StackTrace() + IL_0030: ldstr "Caller" + IL_0035: callvirt instance int32 [mscorlib]System.String::IndexOf(string) + IL_003a: ldc.i4.m1 + IL_003b: beq.s IL_006d + + IL_003d: ldstr "FAILED: Found the word 'Caller' in the stacktrace." + IL_0042: call void [mscorlib]System.Console::WriteLine(string) + IL_0047: ldstr "------------------------------------------------" + IL_004c: call void [mscorlib]System.Console::WriteLine(string) + IL_0051: call void [mscorlib]System.Console::WriteLine() + IL_0056: ldloc.0 + IL_0057: callvirt instance string [mscorlib]System.Exception::get_StackTrace() + IL_005c: call void [mscorlib]System.Console::WriteLine(string) + IL_0061: call void [mscorlib]System.Console::WriteLine() + IL_0066: ldc.i4.s 101 + IL_0068: stsfld int32 TailcallVerify.Condition22::Result + IL_006d: leave.s IL_006f + + } // end handler + IL_006f: ldstr "Execution finished - Test " + IL_0074: ldsfld int32 TailcallVerify.Condition22::Result + IL_0079: ldc.i4.s 100 + IL_007b: beq.s IL_0084 + + IL_007d: ldstr "FAILED" + IL_0082: br.s IL_0089 + + IL_0084: ldstr "PASSED" + IL_0089: call string [mscorlib]System.String::Concat(string, + string) + IL_008e: call void [mscorlib]System.Console::WriteLine(string) + IL_0093: ldsfld int32 TailcallVerify.Condition22::Result + IL_0098: ret + } // end of method Condition22::Test2 + + .method private hidebysig static void Caller2() cil managed + { + .custom instance void [mscorlib]System.Security.SecurityCriticalAttribute::.ctor() = ( 01 00 00 00 ) + // Code size 53 (0x35) + .maxstack 8 + IL_0000: ldc.i4.0 + IL_0001: newobj instance void [mscorlib]System.Diagnostics.StackFrame::.ctor(bool) + IL_0006: callvirt instance class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Diagnostics.StackFrame::GetMethod() + IL_000b: callvirt instance string [mscorlib]System.Reflection.MemberInfo::get_Name() + IL_0010: ldstr "Caller" + IL_0015: callvirt instance int32 [mscorlib]System.String::IndexOf(string) + IL_001a: ldc.i4.m1 + IL_001b: bne.un.s IL_002e + + IL_001d: ldstr "Failed, Method was inlined..." + IL_0022: call void [mscorlib]System.Console::WriteLine(string) + IL_0027: ldc.i4.s 101 + IL_0029: stsfld int32 TailcallVerify.Condition22::Result +// tail. // tail.call, pop, ret sequence is never valid for .NET Core (but is accepted by .NET x64) + IL_002e: call int32 TailcallVerify.Condition22::Callee2() + IL_0033: pop + IL_0034: ret + } // end of method Condition22::Caller2 + + .method private hidebysig static int32 + Callee2() cil managed noinlining + { + // Code size 12 (0xc) + .maxstack 2 + .locals init ([0] int32 i) + IL_0000: ldc.i4.1 + IL_0001: volatile. + IL_0003: ldsfld int32 modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile) TailcallVerify.Condition22::zero + IL_0008: div + IL_0009: stloc.0 + IL_000a: ldloc.0 + IL_000b: ret + } // end of method Condition22::Callee2 + + .method public hidebysig static int32 Test3() cil managed nooptimization + { + // Code size 160 (0xa0) + .maxstack 3 + .locals init ([0] class TailcallVerify.Condition22 con, + [1] class [mscorlib]System.Exception e) + IL_0000: ldstr "Executing Condition22.Test3 - Caller: Arguments: " + + "None - ReturnType: void; Callee (virtual call): Arguments: 0 - ReturnTy" + + "pe: Int32" + IL_0005: call void [mscorlib]System.Console::WriteLine(string) + IL_000a: ldc.i4.s 100 + IL_000c: stsfld int32 TailcallVerify.Condition22::Result + .try + { + IL_0011: newobj instance void TailcallVerify.Condition22::.ctor() + IL_0016: stloc.0 + IL_0017: ldloc.0 + IL_0018: callvirt instance void TailcallVerify.Condition22::Caller3() + IL_001d: leave.s IL_0076 + + } // end .try + catch [mscorlib]System.Exception + { + IL_001f: stloc.1 + IL_0020: ldloc.1 + IL_0021: isinst [mscorlib]System.DivideByZeroException + IL_0026: brtrue.s IL_0031 + + IL_0028: ldc.i4.s 101 + IL_002a: stsfld int32 TailcallVerify.Condition22::Result + IL_002f: rethrow + IL_0031: ldloc.1 + IL_0032: callvirt instance string [mscorlib]System.Exception::get_StackTrace() + IL_0037: ldstr "Caller" + IL_003c: callvirt instance int32 [mscorlib]System.String::IndexOf(string) + IL_0041: ldc.i4.m1 + IL_0042: bne.un.s IL_0074 + + IL_0044: ldstr "FAILED: Did not found the word 'Caller' in the sta" + + "cktrace. Since the assembly is transparent, a tailcall should not be al" + + "lowed." + IL_0049: call void [mscorlib]System.Console::WriteLine(string) + IL_004e: ldstr "------------------------------------------------" + IL_0053: call void [mscorlib]System.Console::WriteLine(string) + IL_0058: call void [mscorlib]System.Console::WriteLine() + IL_005d: ldloc.1 + IL_005e: callvirt instance string [mscorlib]System.Exception::get_StackTrace() + IL_0063: call void [mscorlib]System.Console::WriteLine(string) + IL_0068: call void [mscorlib]System.Console::WriteLine() + IL_006d: ldc.i4.s 101 + IL_006f: stsfld int32 TailcallVerify.Condition22::Result + IL_0074: leave.s IL_0076 + + } // end handler + IL_0076: ldstr "Execution finished - Test " + IL_007b: ldsfld int32 TailcallVerify.Condition22::Result + IL_0080: ldc.i4.s 100 + IL_0082: beq.s IL_008b + + IL_0084: ldstr "FAILED" + IL_0089: br.s IL_0090 + + IL_008b: ldstr "PASSED" + IL_0090: call string [mscorlib]System.String::Concat(string, + string) + IL_0095: call void [mscorlib]System.Console::WriteLine(string) + IL_009a: ldsfld int32 TailcallVerify.Condition22::Result + IL_009f: ret + } // end of method Condition22::Test3 + + .method private hidebysig instance void + Caller3() cil managed + { + // Code size 54 (0x36) + .maxstack 8 + IL_0000: ldc.i4.0 + IL_0001: newobj instance void [mscorlib]System.Diagnostics.StackFrame::.ctor(bool) + IL_0006: callvirt instance class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Diagnostics.StackFrame::GetMethod() + IL_000b: callvirt instance string [mscorlib]System.Reflection.MemberInfo::get_Name() + IL_0010: ldstr "Caller" + IL_0015: callvirt instance int32 [mscorlib]System.String::IndexOf(string) + IL_001a: ldc.i4.m1 + IL_001b: bne.un.s IL_002e + + IL_001d: ldstr "Failed, Method was inlined..." + IL_0022: call void [mscorlib]System.Console::WriteLine(string) + IL_0027: ldc.i4.s 101 + IL_0029: stsfld int32 TailcallVerify.Condition22::Result + IL_002e: ldarg.0 +// tail. // tail.call, pop, ret sequence is never valid for .NET Core (but is accepted by .NET x64) + IL_002f: callvirt instance int32 TailcallVerify.Condition22::Callee3() + IL_0034: pop + IL_0035: ret + } // end of method Condition22::Caller3 + + .method family hidebysig newslot virtual + instance int32 Callee3() cil managed noinlining + { + // Code size 12 (0xc) + .maxstack 2 + .locals init ([0] int32 i) + IL_0000: ldc.i4.1 + IL_0001: volatile. + IL_0003: ldsfld int32 modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile) TailcallVerify.Condition22::zero + IL_0008: div + IL_0009: stloc.0 + IL_000a: ldloc.0 + IL_000b: ret + } // end of method Condition22::Callee3 + + .method public hidebysig static int32 Test4() cil managed nooptimization + { + // Code size 160 (0xa0) + .maxstack 3 + .locals init ([0] class TailcallVerify.Condition22 con, + [1] class [mscorlib]System.Exception e) + IL_0000: ldstr "Executing Condition22.Test4 - Caller: Arguments: " + + "None - ReturnType: void; Callee(regular call instruction): Arguments: 0" + + " - ReturnType: Int32" + IL_0005: call void [mscorlib]System.Console::WriteLine(string) + IL_000a: ldc.i4.s 100 + IL_000c: stsfld int32 TailcallVerify.Condition22::Result + .try + { + IL_0011: newobj instance void TailcallVerify.Condition22::.ctor() + IL_0016: stloc.0 + IL_0017: ldloc.0 + IL_0018: callvirt instance void TailcallVerify.Condition22::Caller4() + IL_001d: leave.s IL_0076 + + } // end .try + catch [mscorlib]System.Exception + { + IL_001f: stloc.1 + IL_0020: ldloc.1 + IL_0021: isinst [mscorlib]System.DivideByZeroException + IL_0026: brtrue.s IL_0031 + + IL_0028: ldc.i4.s 101 + IL_002a: stsfld int32 TailcallVerify.Condition22::Result + IL_002f: rethrow + IL_0031: ldloc.1 + IL_0032: callvirt instance string [mscorlib]System.Exception::get_StackTrace() + IL_0037: ldstr "Caller" + IL_003c: callvirt instance int32 [mscorlib]System.String::IndexOf(string) + IL_0041: ldc.i4.m1 + IL_0042: beq.s IL_0074 + + IL_0044: ldstr "FAILED: Found the word 'Caller' in the stacktrace." + IL_0049: call void [mscorlib]System.Console::WriteLine(string) + IL_004e: ldstr "------------------------------------------------" + IL_0053: call void [mscorlib]System.Console::WriteLine(string) + IL_0058: call void [mscorlib]System.Console::WriteLine() + IL_005d: ldloc.1 + IL_005e: callvirt instance string [mscorlib]System.Exception::get_StackTrace() + IL_0063: call void [mscorlib]System.Console::WriteLine(string) + IL_0068: call void [mscorlib]System.Console::WriteLine() + IL_006d: ldc.i4.s 101 + IL_006f: stsfld int32 TailcallVerify.Condition22::Result + IL_0074: leave.s IL_0076 + + } // end handler + IL_0076: ldstr "Execution finished - Test " + IL_007b: ldsfld int32 TailcallVerify.Condition22::Result + IL_0080: ldc.i4.s 100 + IL_0082: beq.s IL_008b + + IL_0084: ldstr "FAILED" + IL_0089: br.s IL_0090 + + IL_008b: ldstr "PASSED" + IL_0090: call string [mscorlib]System.String::Concat(string, + string) + IL_0095: call void [mscorlib]System.Console::WriteLine(string) + IL_009a: ldsfld int32 TailcallVerify.Condition22::Result + IL_009f: ret + } // end of method Condition22::Test4 + + .method private hidebysig instance void + Caller4() cil managed + { + // Code size 54 (0x36) + .maxstack 8 + IL_0000: ldc.i4.0 + IL_0001: newobj instance void [mscorlib]System.Diagnostics.StackFrame::.ctor(bool) + IL_0006: callvirt instance class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Diagnostics.StackFrame::GetMethod() + IL_000b: callvirt instance string [mscorlib]System.Reflection.MemberInfo::get_Name() + IL_0010: ldstr "Caller" + IL_0015: callvirt instance int32 [mscorlib]System.String::IndexOf(string) + IL_001a: ldc.i4.m1 + IL_001b: bne.un.s IL_002e + + IL_001d: ldstr "Failed, Method was inlined..." + IL_0022: call void [mscorlib]System.Console::WriteLine(string) + IL_0027: ldc.i4.s 101 + IL_0029: stsfld int32 TailcallVerify.Condition22::Result + IL_002e: ldarg.0 + IL_002f: tail. call instance void TailcallVerify.Condition22::Callee4() + //IL_0034: pop + IL_0035: ret + } // end of method Condition22::Caller4 + + .method private hidebysig instance void + Callee4() cil managed noinlining + { + // Code size 12 (0xc) + .maxstack 2 + .locals init ([0] int32 i) + IL_0000: ldc.i4.1 + IL_0001: volatile. + IL_0003: ldsfld int32 modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile) TailcallVerify.Condition22::zero + IL_0008: div + IL_0009: stloc.0 + //IL_000a: ldloc.0 + IL_000b: ret + } // end of method Condition22::Callee4 + + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method Condition22::.ctor + + .method private hidebysig specialname rtspecialname static + void .cctor() cil managed + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldc.i4.0 + IL_0001: volatile. + IL_0003: stsfld int32 modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile) TailcallVerify.Condition22::zero + IL_0008: ldc.i4.s 100 + IL_000a: stsfld int32 TailcallVerify.Condition22::Result + IL_000f: ret + } // end of method Condition22::.cctor + +} // end of class TailcallVerify.Condition22 + + +// ============================================================= + +// *********** DISASSEMBLY COMPLETE *********************** +// WARNING: Created Win32 resource file TailcallVerifyTransparentLibraryWithPrefix.res diff --git a/mono/tests/tailcall/coreclr/JIT/opt/Tailcall/TailcallVerifyVerifiableLibraryWithPrefix.il b/mono/tests/tailcall/coreclr/JIT/opt/Tailcall/TailcallVerifyVerifiableLibraryWithPrefix.il new file mode 100644 index 0000000000..686fad63cb --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/opt/Tailcall/TailcallVerifyVerifiableLibraryWithPrefix.il @@ -0,0 +1,168 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + + +// Metadata version: v2.0.50727 +.assembly extern mscorlib +{ + .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. + .ver 2:0:0:0 +} + +.module TailcallVerifyVerifiableLibraryWithPrefix.dll +// MVID: {F8D503A0-BC73-40CC-B951-B9AA2545825B} +.imagebase 0x00400000 +.file alignment 0x00000200 +.stackreserve 0x00100000 +.subsystem 0x0003 // WINDOWS_CUI +.corflags 0x00000001 // ILONLY +// Image base: 0x00F50000 + + +// =============== CLASS MEMBERS DECLARATION =================== + +.class public auto ansi beforefieldinit TailcallVerify.Condition23 + extends [mscorlib]System.Object +{ + .field private static int32 modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile) zero + .field private static int32 Result + .method public hidebysig static int32 Test1() cil managed nooptimization + { + // Code size 161 (0xa1) + .maxstack 3 + .locals init ([0] class TailcallVerify.Condition23 con, + [1] class [mscorlib]System.Exception e) + IL_0000: ldstr "Executing Condition23.Test1 - Caller: Arguments: N" + + "one - ReturnType: void; Callee (virtual call): Arguments: 0 - ReturnTyp" + + "e: Int32" + IL_0005: call void [mscorlib]System.Console::WriteLine(string) + IL_000a: ldc.i4.s 100 + IL_000c: stsfld int32 TailcallVerify.Condition23::Result + .try + { + IL_0011: newobj instance void TailcallVerify.Condition23::.ctor() + IL_0016: stloc.0 + IL_0017: ldloc.0 + IL_0018: callvirt instance int32 TailcallVerify.Condition23::Caller1() + IL_001d: pop + IL_001e: leave.s IL_0077 + + } // end .try + catch [mscorlib]System.Exception + { + IL_0020: stloc.1 + IL_0021: ldloc.1 + IL_0022: isinst [mscorlib]System.DivideByZeroException + IL_0027: brtrue.s IL_0032 + + IL_0029: ldc.i4.s 101 + IL_002b: stsfld int32 TailcallVerify.Condition23::Result + IL_0030: rethrow + IL_0032: ldloc.1 + IL_0033: callvirt instance string [mscorlib]System.Exception::get_StackTrace() + IL_0038: ldstr "Caller" + IL_003d: callvirt instance int32 [mscorlib]System.String::IndexOf(string) + IL_0042: ldc.i4.m1 + IL_0043: bne.un.s IL_0075 + + IL_0045: ldstr "FAILED: Did not found the word 'Caller' in the sta" + + "cktrace. Since the assembly is transparent, a tailcall should not be al" + + "lowed." + IL_004a: call void [mscorlib]System.Console::WriteLine(string) + IL_004f: ldstr "------------------------------------------------" + IL_0054: call void [mscorlib]System.Console::WriteLine(string) + IL_0059: call void [mscorlib]System.Console::WriteLine() + IL_005e: ldloc.1 + IL_005f: callvirt instance string [mscorlib]System.Exception::get_StackTrace() + IL_0064: call void [mscorlib]System.Console::WriteLine(string) + IL_0069: call void [mscorlib]System.Console::WriteLine() + IL_006e: ldc.i4.s 101 + IL_0070: stsfld int32 TailcallVerify.Condition23::Result + IL_0075: leave.s IL_0077 + + } // end handler + IL_0077: ldstr "Execution finished - Test " + IL_007c: ldsfld int32 TailcallVerify.Condition23::Result + IL_0081: ldc.i4.s 100 + IL_0083: beq.s IL_008c + + IL_0085: ldstr "FAILED" + IL_008a: br.s IL_0091 + + IL_008c: ldstr "PASSED" + IL_0091: call string [mscorlib]System.String::Concat(string, + string) + IL_0096: call void [mscorlib]System.Console::WriteLine(string) + IL_009b: ldsfld int32 TailcallVerify.Condition23::Result + IL_00a0: ret + } // end of method Condition23::Test1 + + .method private hidebysig instance int32 + Caller1() cil managed + { + // Code size 53 (0x35) + .maxstack 8 + IL_0000: ldc.i4.0 + IL_0001: newobj instance void [mscorlib]System.Diagnostics.StackFrame::.ctor(bool) + IL_0006: callvirt instance class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Diagnostics.StackFrame::GetMethod() + IL_000b: callvirt instance string [mscorlib]System.Reflection.MemberInfo::get_Name() + IL_0010: ldstr "Caller" + IL_0015: callvirt instance int32 [mscorlib]System.String::IndexOf(string) + IL_001a: ldc.i4.m1 + IL_001b: bne.un.s IL_002e + + IL_001d: ldstr "Failed, Method was inlined..." + IL_0022: call void [mscorlib]System.Console::WriteLine(string) + IL_0027: ldc.i4.s 101 + IL_0029: stsfld int32 TailcallVerify.Condition23::Result + IL_002e: ldarg.0 + IL_002f: tail. callvirt instance int32 TailcallVerify.Condition23::Callee1() + IL_0034: ret + } // end of method Condition23::Caller1 + + .method family hidebysig newslot virtual + instance int32 Callee1() cil managed noinlining + { + // Code size 12 (0xc) + .maxstack 2 + .locals init ([0] int32 i) + IL_0000: ldc.i4.1 + IL_0001: volatile. + IL_0003: ldsfld int32 modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile) TailcallVerify.Condition23::zero + IL_0008: div + IL_0009: stloc.0 + IL_000a: ldloc.0 + IL_000b: ret + } // end of method Condition23::Callee1 + + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method Condition23::.ctor + + .method private hidebysig specialname rtspecialname static + void .cctor() cil managed + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldc.i4.0 + IL_0001: volatile. + IL_0003: stsfld int32 modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile) TailcallVerify.Condition23::zero + IL_0008: ldc.i4.s 100 + IL_000a: stsfld int32 TailcallVerify.Condition23::Result + IL_000f: ret + } // end of method Condition23::.cctor + +} // end of class TailcallVerify.Condition23 + + +// ============================================================= + +// *********** DISASSEMBLY COMPLETE *********************** +// WARNING: Created Win32 resource file TailcallVerifyVerifiableLibraryWithPrefix.res diff --git a/mono/tests/tailcall/coreclr/JIT/opt/Tailcall/TailcallVerifyWithPrefix.il.REMOVED.git-id b/mono/tests/tailcall/coreclr/JIT/opt/Tailcall/TailcallVerifyWithPrefix.il.REMOVED.git-id new file mode 100644 index 0000000000..94ade7f91b --- /dev/null +++ b/mono/tests/tailcall/coreclr/JIT/opt/Tailcall/TailcallVerifyWithPrefix.il.REMOVED.git-id @@ -0,0 +1 @@ +6c44b8de574ce50ea93840b3a6971e2d0a7ee539 \ No newline at end of file diff --git a/mono/tests/tailcall/fsharp.il.REMOVED.git-id b/mono/tests/tailcall/fsharp.il.REMOVED.git-id new file mode 100644 index 0000000000..6726f4fd7d --- /dev/null +++ b/mono/tests/tailcall/fsharp.il.REMOVED.git-id @@ -0,0 +1 @@ +021f8c278311580baaa1d6ce4b086a1fdb4c6469 \ No newline at end of file diff --git a/mono/tests/taili1.il b/mono/tests/taili1.il new file mode 100755 index 0000000000..a72364b85a --- /dev/null +++ b/mono/tests/taili1.il @@ -0,0 +1,84 @@ +.assembly extern mscorlib { } +.assembly tailcall1 { } +.class A extends [mscorlib]System.Object { +.method public hidebysig static int32 taili1() cil managed noinlining { +.entrypoint +.maxstack 3 +.locals init (uint8 V_0) +ldloca.s V_0 +conv.u +ldc.i4.0 +conv.i8 +ldc.i4.8 +call int32 A::taili2(uint8*, int64, int32) +ret +} +.method private hidebysig static int32 taili2(uint8* root_stack, int64 diff_stack, int32 counter) cil managed noinlining { +.maxstack 4 +.locals init (uint8 V_0) +ldarg.2 +ldc.i4.0 +ble.s IL_0016 +ldarg.0 +ldloca.s V_0 +conv.u +ldarg.0 +sub +ldc.i4.1 +div +conv.i8 +ldarg.2 +ldc.i4.1 +sub +ldftn int32 A::taili2(uint8*, int64, int32) +tail. calli int32 (uint8*, int64, int32) +ret +IL_0016: ldarg.0 +ldloca.s V_0 +conv.u +ldarg.1 +ldstr "taili1" +call int32 A::check(uint8*, uint8*, int64, string) +ret +} +.method private hidebysig static int32 check(uint8* root_stack, uint8* local, int64 diff_stack, string name) cil managed noinlining { +.maxstack 8 +ldarg.1 +ldarg.0 +sub +ldc.i4.1 +div +conv.i8 +ldarg.2 +beq.s IL_0026 +ldstr "{0} failure {1}" +ldarg.3 +ldarg.0 +ldarg.1 +sub +ldc.i4.1 +div +conv.i8 +box [mscorlib]System.Int64 +call string [mscorlib]System.String::Format(string, object, object) +call void [mscorlib]System.Console::WriteLine(string) +ldc.i4.1 +ret +IL_0026: ldstr "{0} success" +ldarg.3 +call string [mscorlib]System.String::Format(string, object) +call void [mscorlib]System.Console::WriteLine(string) +ldc.i4.0 +ret +} +.method private hidebysig static int32 check(int64 root_stack, uint8* local, int64 diff_stack, string name) cil managed noinlining { +.maxstack 8 +ldarg.0 +conv.u +ldarg.1 +ldarg.2 +ldarg.3 +call int32 A::check(uint8*, uint8*, int64, string) +ret +} +} diff --git a/mono/tests/test-runner.cs b/mono/tests/test-runner.cs index de8e58709c..8dcef6644c 100644 --- a/mono/tests/test-runner.cs +++ b/mono/tests/test-runner.cs @@ -17,6 +17,7 @@ using System.Globalization; using System.Xml; using System.Text; using System.Text.RegularExpressions; +using System.Linq; #if !FULL_AOT_DESKTOP && !MOBILE using Mono.Unix.Native; @@ -53,6 +54,7 @@ public class TestRunner bool verbose = false; string testsuiteName = null; string inputFile = null; + int repeat = 1; string disabled_tests = null; string runtime = "mono"; @@ -158,6 +160,17 @@ public class TestRunner } else if (args [i] == "--verbose") { verbose = true; i ++; + } else if (args [i] == "--repeat") { + if (i + 1 >= args.Length) { + Console.WriteLine ("Missing argument to --repeat command line option."); + return 1; + } + repeat = Int32.Parse (args [i + 1]); + if (repeat <= 1) { + Console.WriteLine ("Invalid argument to --repeat command line option, should be > 1"); + return 1; + } + i += 2; } else { Console.WriteLine ("Unknown command line option: '" + args [i] + "'."); return 1; @@ -182,14 +195,30 @@ public class TestRunner var tests = new List (); if (!String.IsNullOrEmpty (inputFile)) { - tests.AddRange (File.ReadAllLines (inputFile)); + foreach (string l in File.ReadAllLines (inputFile)) { + for (int r = 0; r < repeat; ++r) + tests.Add (l); + } } else { // The remaining arguments are the tests for (int j = i; j < args.Length; ++j) - if (!disabled.ContainsKey (args [j])) - tests.Add (args [j]); + if (!disabled.ContainsKey (args [j])) { + for (int r = 0; r < repeat; ++r) + tests.Add (args [j]); + } } + if (!tests.Any ()) { + Console.WriteLine ("No tests selected, exiting."); + return 0; + } + + /* If tests are repeated, we don't want the same test to run consecutively, so we need to randomise their order. + * But to ease reproduction of certain order-based bugs (if and only if test A and B execute at the same time), + * we want to use a constant seed so the tests always run in the same order. */ + var random = new Random (0); + tests = tests.OrderBy (t => random.Next ()).ToList (); + var passed = new List (); var failed = new List (); var timedout = new List (); diff --git a/mono/tests/testing_gac/Makefile.in b/mono/tests/testing_gac/Makefile.in index fa4fd3a2bf..ed73e0b77a 100644 --- a/mono/tests/testing_gac/Makefile.in +++ b/mono/tests/testing_gac/Makefile.in @@ -87,8 +87,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs README ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -197,6 +195,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -215,7 +214,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -229,7 +227,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -343,7 +340,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ diff --git a/mono/tests/valuetype-equals.cs b/mono/tests/valuetype-equals.cs index 243023fd64..cd676061ec 100644 --- a/mono/tests/valuetype-equals.cs +++ b/mono/tests/valuetype-equals.cs @@ -61,6 +61,10 @@ struct DoubleStruct { public DoubleStruct (double x) { this.x = x; } } +unsafe struct PointerStruct { + int* x; + public PointerStruct (int* x) { this.x = x; } +} public class Driver { static void AssertEqual (object a, object b) { @@ -73,7 +77,7 @@ public class Driver { throw new Exception (String.Format ("must not be equal {0} {1}", a, b)); } - public static int Main () { + public static unsafe int Main () { AssertEqual (new BoolStruct (true), new BoolStruct (true)); AssertNotEqual (new BoolStruct (false), new BoolStruct (true)); @@ -130,6 +134,11 @@ public class Driver { AssertNotEqual (new DoubleStruct (44), new DoubleStruct (1)); AssertNotEqual (new DoubleStruct (0), new DoubleStruct (55)); + AssertEqual (new PointerStruct ((int*)(IntPtr)13), new PointerStruct ((int*)(IntPtr)13)); + AssertEqual (new PointerStruct ((int*)(IntPtr)0), new PointerStruct ((int*)(IntPtr)0)); + AssertNotEqual (new PointerStruct ((int*)(IntPtr)44), new PointerStruct ((int*)(IntPtr)1)); + AssertNotEqual (new PointerStruct ((int*)(IntPtr)0), new PointerStruct ((int*)(IntPtr)55)); + return 0; } } diff --git a/mono/tests/vtail1.il b/mono/tests/vtail1.il new file mode 100755 index 0000000000..51da700755 --- /dev/null +++ b/mono/tests/vtail1.il @@ -0,0 +1,92 @@ +.assembly extern mscorlib { } +.assembly tailcall1 { } +.class A extends [mscorlib]System.Object { +.method public hidebysig specialname rtspecialname instance void .ctor() cil managed +{ +.maxstack 8 +ldarg.0 +call instance void [mscorlib]System.Object::.ctor() +ret +} +.method public hidebysig static int32 vtail1() cil managed noinlining { +.entrypoint +.maxstack 4 +.locals init (uint8 V_0) +newobj instance void A::.ctor() +ldloca.s V_0 +conv.u +ldc.i4.0 +conv.i8 +ldc.i4.5 +callvirt instance int32 A::vtail2(uint8*, int64, int32) +ret +} +.method public hidebysig newslot virtual instance int32 vtail2(uint8* root_stack, int64 diff_stack, int32 counter) cil managed noinlining { +.maxstack 5 +.locals init (uint8 V_0) +ldarg.3 +ldc.i4.0 +ble.s IL_0017 +ldarg.0 +ldarg.1 +ldloca.s V_0 +conv.u +ldarg.1 +sub +ldc.i4.1 +div +conv.i8 +ldarg.3 +ldc.i4.1 +sub +tail. callvirt instance int32 A::vtail2(uint8*, int64, int32) +ret +IL_0017: ldarg.1 +ldloca.s V_0 +conv.u +ldarg.2 +ldstr "vtail1" +call int32 A::check(uint8*, uint8*, int64, string) +ret +} +.method private hidebysig static int32 check(uint8* root_stack, uint8* local, int64 diff_stack, string name) cil managed noinlining { +.maxstack 8 +ldarg.1 +ldarg.0 +sub +ldc.i4.1 +div +conv.i8 +ldarg.2 +beq.s IL_0026 +ldstr "{0} failure {1}" +ldarg.3 +ldarg.0 +ldarg.1 +sub +ldc.i4.1 +div +conv.i8 +box [mscorlib]System.Int64 +call string [mscorlib]System.String::Format(string, object, object) +call void [mscorlib]System.Console::WriteLine(string) +ldc.i4.1 +ret +IL_0026: ldstr "{0} success" +ldarg.3 +call string [mscorlib]System.String::Format(string, object) +call void [mscorlib]System.Console::WriteLine(string) +ldc.i4.0 +ret +} +.method private hidebysig static int32 check(int64 root_stack, uint8* local, int64 diff_stack, string name) cil managed noinlining { +.maxstack 8 +ldarg.0 +conv.u +ldarg.1 +ldarg.2 +ldarg.3 +call int32 A::check(uint8*, uint8*, int64, string) +ret +} +} diff --git a/mono/tests/weak-fields.cs b/mono/tests/weak-fields.cs index 1bd8337c09..bfca78068f 100644 --- a/mono/tests/weak-fields.cs +++ b/mono/tests/weak-fields.cs @@ -1,5 +1,6 @@ using System; using System.Threading; +using MonoTests.Helpers; [AttributeUsage(AttributeTargets.Field)] public sealed class Weak2Attribute : Attribute @@ -32,36 +33,34 @@ public class Tests 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; + FinalizerHelpers.PerformNoPinAction (delegate () { + FinalizerHelpers.PerformNoPinAction (delegate () { + t.Obj = new Finalizable (); + t.Obj2 = new Finalizable (); + t.Obj3 = new Finalizable (); + t.Obj4 = retain = new Finalizable (); + retain.a = 0x1029458; + }); + GC.Collect (0); + GC.Collect (); + GC.WaitForPendingFinalizers (); + if (t.Obj != null) + Environment.Exit (1); + if (t.Obj2 != null) + Environment.Exit (2); + if (t.Obj3 == null) + Environment.Exit (3); + //overflow the nursery, make sure we fill it + for (int i = 0; i < 1000 * 1000 * 10; ++i) + new OneField (); + + if (retain.a != 0x1029458) + Environment.Exit (4); + + retain = null; }); - 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; diff --git a/mono/unit-tests/Makefile.am b/mono/unit-tests/Makefile.am index 536da6086a..8a6ce3ad99 100644 --- a/mono/unit-tests/Makefile.am +++ b/mono/unit-tests/Makefile.am @@ -22,7 +22,7 @@ endif test_cflags = $(AM_CFLAGS) $(SGEN_DEFINES) test_ldadd = libtestlib.la \ - $(LIBGC_LIBS) $(GLIB_LIBS) -lm $(LIBICONV) $(LLVMMONOF) + $(LIBGC_LIBS) $(GLIB_LIBS) -lm $(LLVMMONOF) if HOST_DARWIN test_ldflags = -framework CoreFoundation -framework Foundation endif @@ -32,7 +32,7 @@ sgen_libs = \ $(monodir)/mono/metadata/libmonoruntimesgen.la \ $(monodir)/mono/sgen/libmonosgen.la \ $(monodir)/mono/utils/libmonoutils.la \ - $(GLIB_LIBS) $(LIBICONV) + $(GLIB_LIBS) mini_libs = \ $(monodir)/mono/mini/libmini.la diff --git a/mono/unit-tests/Makefile.in b/mono/unit-tests/Makefile.in index e59c2f3720..7302ac78dc 100644 --- a/mono/unit-tests/Makefile.in +++ b/mono/unit-tests/Makefile.in @@ -100,8 +100,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/test-driver ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -131,8 +129,7 @@ am__DEPENDENCIES_1 = @LOADED_LLVM_FALSE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) \ @LOADED_LLVM_FALSE@ $(am__DEPENDENCIES_1) am__DEPENDENCIES_3 = libtestlib.la $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_2) + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) @CROSS_COMPILE_FALSE@@HOST_WIN32_FALSE@test_conc_hashtable_DEPENDENCIES = \ @CROSS_COMPILE_FALSE@@HOST_WIN32_FALSE@ $(am__DEPENDENCIES_3) test_conc_hashtable_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ @@ -152,8 +149,7 @@ am__test_mono_callspec_SOURCES_DIST = test-mono-callspec.c test_mono_callspec_OBJECTS = $(am_test_mono_callspec_OBJECTS) am__DEPENDENCIES_4 = $(monodir)/mono/metadata/libmonoruntimesgen.la \ $(monodir)/mono/sgen/libmonosgen.la \ - $(monodir)/mono/utils/libmonoutils.la $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) + $(monodir)/mono/utils/libmonoutils.la $(am__DEPENDENCIES_1) test_mono_callspec_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(test_mono_callspec_CFLAGS) $(CFLAGS) \ @@ -546,6 +542,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -564,7 +561,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -578,7 +574,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -692,7 +687,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ @@ -727,7 +721,7 @@ MCS = $(MCS_NO_LIB) @LOADED_LLVM_TRUE@LLVMMONOF = test_cflags = $(AM_CFLAGS) $(SGEN_DEFINES) test_ldadd = libtestlib.la \ - $(LIBGC_LIBS) $(GLIB_LIBS) -lm $(LIBICONV) $(LLVMMONOF) + $(LIBGC_LIBS) $(GLIB_LIBS) -lm $(LLVMMONOF) @HOST_DARWIN_TRUE@test_ldflags = -framework CoreFoundation -framework Foundation monodir = $(top_builddir) @@ -735,7 +729,7 @@ sgen_libs = \ $(monodir)/mono/metadata/libmonoruntimesgen.la \ $(monodir)/mono/sgen/libmonosgen.la \ $(monodir)/mono/utils/libmonoutils.la \ - $(GLIB_LIBS) $(LIBICONV) + $(GLIB_LIBS) mini_libs = $(monodir)/mono/mini/libmini.la $(am__append_1) @CROSS_COMPILE_FALSE@@HOST_WIN32_FALSE@noinst_LTLIBRARIES = libtestlib.la diff --git a/mono/utils/Makefile.am b/mono/utils/Makefile.am index 776b5d17e4..d9b0ba8948 100644 --- a/mono/utils/Makefile.am +++ b/mono/utils/Makefile.am @@ -113,7 +113,6 @@ monoutils_sources = \ mono-uri.h \ mono-stdlib.h \ valgrind.h \ - mach-support.c \ mach-support.h \ memcheck.h \ mono-context.c \ @@ -151,6 +150,8 @@ monoutils_sources = \ mono-threads-coop.h \ mono-tls.h \ mono-tls.c \ + mono-utils-debug.c \ + mono-utils-debug.h \ linux_magic.h \ mono-memory-model.h \ atomic.h \ diff --git a/mono/utils/Makefile.in.REMOVED.git-id b/mono/utils/Makefile.in.REMOVED.git-id index b7c323ba76..7bbc11d47d 100644 --- a/mono/utils/Makefile.in.REMOVED.git-id +++ b/mono/utils/Makefile.in.REMOVED.git-id @@ -1 +1 @@ -8471f144cad8961a50d4f165dd43257c42327f05 \ No newline at end of file +35bd901fd8fd0a57ad624389a8b542ac350a86c4 \ No newline at end of file diff --git a/mono/utils/atomic.h b/mono/utils/atomic.h index bbf79ebea4..c26f65b5e9 100755 --- a/mono/utils/atomic.h +++ b/mono/utils/atomic.h @@ -167,7 +167,7 @@ static inline void mono_atomic_store_i8 (volatile gint8 *dst, gint8 val) { #if (_MSC_VER >= 1600) - InterlockedExchange8 ((CHAR volatile *)dst, (CHAR)val); + _InterlockedExchange8 ((CHAR volatile *)dst, (CHAR)val); #else *dst = val; mono_memory_barrier (); diff --git a/mono/utils/dlmalloc.c.REMOVED.git-id b/mono/utils/dlmalloc.c.REMOVED.git-id index f0202735d7..5607724a2c 100644 --- a/mono/utils/dlmalloc.c.REMOVED.git-id +++ b/mono/utils/dlmalloc.c.REMOVED.git-id @@ -1 +1 @@ -296893ff2e7f2a77a8e7b5e46f4684d45421b8a4 \ No newline at end of file +39850671934fb48e88695894b26e470308a7f2ee \ No newline at end of file diff --git a/mono/utils/hazard-pointer.c b/mono/utils/hazard-pointer.c index 319ac6762e..86f8d211c0 100644 --- a/mono/utils/hazard-pointer.c +++ b/mono/utils/hazard-pointer.c @@ -106,13 +106,22 @@ mono_thread_small_id_alloc (void) hazard_table_size = HAZARD_TABLE_MAX_SIZE; #else gpointer page_addr; +#if defined(__PASE__) + /* + * HACK: allocating the table with none prot will cause i 7.1 + * to segfault when accessing or protecting it + */ + int table_prot = MONO_MMAP_READ | MONO_MMAP_WRITE; +#else + int table_prot = MONO_MMAP_NONE; +#endif int pagesize = mono_pagesize (); int num_pages = (hazard_table_size * sizeof (MonoThreadHazardPointers) + pagesize - 1) / pagesize; if (hazard_table == NULL) { hazard_table = (MonoThreadHazardPointers *volatile) mono_valloc (NULL, sizeof (MonoThreadHazardPointers) * HAZARD_TABLE_MAX_SIZE, - MONO_MMAP_NONE, MONO_MEM_ACCOUNT_HAZARD_POINTERS); + table_prot, MONO_MEM_ACCOUNT_HAZARD_POINTERS); } g_assert (hazard_table != NULL); diff --git a/mono/utils/jemalloc/Makefile.in b/mono/utils/jemalloc/Makefile.in index 401f3c0a2d..997cb07bc0 100644 --- a/mono/utils/jemalloc/Makefile.in +++ b/mono/utils/jemalloc/Makefile.in @@ -96,8 +96,6 @@ DIST_COMMON = $(top_srcdir)/scripts/submodules/versions.mk \ subdir = mono/utils/jemalloc ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -206,6 +204,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -224,7 +223,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -238,7 +236,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -352,7 +349,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ diff --git a/mono/utils/mach-support-amd64.c b/mono/utils/mach-support-amd64.c index ceef5f25e4..1e3b908679 100644 --- a/mono/utils/mach-support-amd64.c +++ b/mono/utils/mach-support-amd64.c @@ -22,37 +22,6 @@ //For reg numbers #include -/* Known offsets used for TLS storage*/ - -/* All OSX versions up to 10.8 */ -#define TLS_VECTOR_OFFSET_CATS 0x60 -#define TLS_VECTOR_OFFSET_10_9 0xe0 -#define TLS_VECTOR_OFFSET_10_11 0x100 - -/* This is 2 slots less than the known low */ -#define TLS_PROBE_LOW_WATERMARK 0x50 -/* This is 28 slots above the know high, which is more than the known high-low*/ -#define TLS_PROBE_HIGH_WATERMARK 0x200 - - -static int tls_vector_offset; - -void * -mono_mach_arch_get_ip (thread_state_t state) -{ - x86_thread_state64_t *arch_state = (x86_thread_state64_t *) state; - - return (void *) arch_state->__rip; -} - -void * -mono_mach_arch_get_sp (thread_state_t state) -{ - x86_thread_state64_t *arch_state = (x86_thread_state64_t *) state; - - return (void *) arch_state->__rsp; -} - int mono_mach_arch_get_mcontext_size () { @@ -160,64 +129,4 @@ mono_mach_arch_set_thread_states (thread_port_t thread, thread_state_t state, ma return ret; } -void * -mono_mach_get_tls_address_from_thread (pthread_t thread, pthread_key_t key) -{ - /* OSX stores TLS values in a hidden array inside the pthread_t structure - * They are keyed off a giant array from a known offset into the pointer. This value - * is baked into their pthread_getspecific implementation - */ - intptr_t *p = (intptr_t *)thread; - intptr_t **tsd = (intptr_t **) ((char*)p + tls_vector_offset); - g_assert (tls_vector_offset != -1); - - return (void *) &tsd [key]; -} - -void * -mono_mach_arch_get_tls_value_from_thread (pthread_t thread, guint32 key) -{ - return *(void**)mono_mach_get_tls_address_from_thread (thread, key); -} - -void -mono_mach_init (pthread_key_t key) -{ - int i; - void *old_value = pthread_getspecific (key); - void *canary = (void*)0xDEADBEEFu; - - pthread_key_create (&key, NULL); - g_assert (old_value != canary); - - pthread_setspecific (key, canary); - - /*First we probe for cats*/ - tls_vector_offset = TLS_VECTOR_OFFSET_CATS; - if (mono_mach_arch_get_tls_value_from_thread (pthread_self (), key) == canary) - goto ok; - - tls_vector_offset = TLS_VECTOR_OFFSET_10_9; - if (mono_mach_arch_get_tls_value_from_thread (pthread_self (), key) == canary) - goto ok; - - tls_vector_offset = TLS_VECTOR_OFFSET_10_11; - if (mono_mach_arch_get_tls_value_from_thread (pthread_self (), key) == canary) - goto ok; - - /*Fallback to scanning a large range of offsets*/ - for (i = TLS_PROBE_LOW_WATERMARK; i <= TLS_PROBE_HIGH_WATERMARK; i += 4) { - tls_vector_offset = i; - if (mono_mach_arch_get_tls_value_from_thread (pthread_self (), key) == canary) { - g_warning ("Found new TLS offset at %d", i); - goto ok; - } - } - - tls_vector_offset = -1; - g_warning ("could not discover the mach TLS offset"); -ok: - pthread_setspecific (key, old_value); -} - #endif diff --git a/mono/utils/mach-support-arm.c b/mono/utils/mach-support-arm.c index 649487ccc0..004b03cfd7 100644 --- a/mono/utils/mach-support-arm.c +++ b/mono/utils/mach-support-arm.c @@ -25,41 +25,6 @@ #define __darwin_mcontext __darwin_mcontext32 #endif -/* Known offsets used for TLS storage*/ - - -static const int known_tls_offsets[] = { - 0x48, /*Found on iOS 6 */ - 0xA4, - 0xA8, -}; - -#define TLS_PROBE_COUNT (sizeof (known_tls_offsets) / sizeof (int)) - -/* This is 2 slots less than the known low */ -#define TLS_PROBE_LOW_WATERMARK 0x40 -/* This is 24 slots above the know high, which is the same diff as the knowns high-low*/ -#define TLS_PROBE_HIGH_WATERMARK 0x108 - -static int tls_vector_offset; - -void * -mono_mach_arch_get_ip (thread_state_t state) -{ - /* Can't use unified_thread_state on !ARM64 since this has to compile on armv6 too */ - arm_thread_state_t *arch_state = (arm_thread_state_t *) state; - - return (void *) arch_state->__pc; -} - -void * -mono_mach_arch_get_sp (thread_state_t state) -{ - arm_thread_state_t *arch_state = (arm_thread_state_t *) state; - - return (void *) arch_state->__sp; -} - int mono_mach_arch_get_mcontext_size () { @@ -136,58 +101,4 @@ mono_mach_arch_set_thread_states (thread_port_t thread, thread_state_t state, ma #endif } -void * -mono_mach_get_tls_address_from_thread (pthread_t thread, pthread_key_t key) -{ - /* Mach stores TLS values in a hidden array inside the pthread_t structure - * They are keyed off a giant array from a known offset into the pointer. This value - * is baked into their pthread_getspecific implementation - */ - intptr_t *p = (intptr_t *) thread; - intptr_t **tsd = (intptr_t **) ((char*)p + tls_vector_offset); - g_assert (tls_vector_offset != -1); - - return (void *) &tsd [key]; -} - -void * -mono_mach_arch_get_tls_value_from_thread (pthread_t thread, guint32 key) -{ - return *(void**)mono_mach_get_tls_address_from_thread (thread, key); -} - -void -mono_mach_init (pthread_key_t key) -{ - int i; - void *old_value = pthread_getspecific (key); - void *canary = (void*)0xDEADBEEFu; - - pthread_key_create (&key, NULL); - g_assert (old_value != canary); - - pthread_setspecific (key, canary); - - /*First we probe for cats*/ - for (i = 0; i < TLS_PROBE_COUNT; ++i) { - tls_vector_offset = known_tls_offsets [i]; - if (mono_mach_arch_get_tls_value_from_thread (pthread_self (), key) == canary) - goto ok; - } - - /*Fallback to scanning a large range of offsets*/ - for (i = TLS_PROBE_LOW_WATERMARK; i <= TLS_PROBE_HIGH_WATERMARK; i += 4) { - tls_vector_offset = i; - if (mono_mach_arch_get_tls_value_from_thread (pthread_self (), key) == canary) { - g_warning ("Found new TLS offset at %d", i); - goto ok; - } - } - - tls_vector_offset = -1; - g_warning ("could not discover the mach TLS offset"); -ok: - pthread_setspecific (key, old_value); -} - #endif diff --git a/mono/utils/mach-support-arm64.c b/mono/utils/mach-support-arm64.c index 33c0769741..1fd2338e55 100644 --- a/mono/utils/mach-support-arm64.c +++ b/mono/utils/mach-support-arm64.c @@ -25,41 +25,6 @@ #define __darwin_mcontext __darwin_mcontext32 #endif -/* Known offsets used for TLS storage*/ - - -static const int known_tls_offsets[] = { - 0x48, /*Found on iOS 6 */ - 0xA4, - 0xA8, -}; - -#define TLS_PROBE_COUNT (sizeof (known_tls_offsets) / sizeof (int)) - -/* This is 2 slots less than the known low */ -#define TLS_PROBE_LOW_WATERMARK 0x40 -/* This is 24 slots above the know high, which is the same diff as the knowns high-low*/ -#define TLS_PROBE_HIGH_WATERMARK 0x108 - -static int tls_vector_offset; - -void * -mono_mach_arch_get_ip (thread_state_t state) -{ - /* Can't use unified_thread_state on !ARM64 since this has to compile on armv6 too */ - arm_unified_thread_state_t *arch_state = (arm_unified_thread_state_t *) state; - - return (void *) arch_state->ts_64.__pc; -} - -void * -mono_mach_arch_get_sp (thread_state_t state) -{ - arm_unified_thread_state_t *arch_state = (arm_unified_thread_state_t *) state; - - return (void *) arch_state->ts_64.__sp; -} - int mono_mach_arch_get_mcontext_size () { @@ -147,58 +112,4 @@ mono_mach_arch_set_thread_states (thread_port_t thread, thread_state_t state, ma return ret; } -void * -mono_mach_get_tls_address_from_thread (pthread_t thread, pthread_key_t key) -{ - /* Mach stores TLS values in a hidden array inside the pthread_t structure - * They are keyed off a giant array from a known offset into the pointer. This value - * is baked into their pthread_getspecific implementation - */ - intptr_t *p = (intptr_t *) thread; - intptr_t **tsd = (intptr_t **) ((char*)p + tls_vector_offset); - g_assert (tls_vector_offset != -1); - - return (void *) &tsd [key]; -} - -void * -mono_mach_arch_get_tls_value_from_thread (pthread_t thread, guint32 key) -{ - return *(void**)mono_mach_get_tls_address_from_thread (thread, key); -} - -void -mono_mach_init (pthread_key_t key) -{ - int i; - void *old_value = pthread_getspecific (key); - void *canary = (void*)0xDEADBEEFu; - - pthread_key_create (&key, NULL); - g_assert (old_value != canary); - - pthread_setspecific (key, canary); - - /*First we probe for cats*/ - for (i = 0; i < TLS_PROBE_COUNT; ++i) { - tls_vector_offset = known_tls_offsets [i]; - if (mono_mach_arch_get_tls_value_from_thread (pthread_self (), key) == canary) - goto ok; - } - - /*Fallback to scanning a large range of offsets*/ - for (i = TLS_PROBE_LOW_WATERMARK; i <= TLS_PROBE_HIGH_WATERMARK; i += 4) { - tls_vector_offset = i; - if (mono_mach_arch_get_tls_value_from_thread (pthread_self (), key) == canary) { - g_warning ("Found new TLS offset at %d", i); - goto ok; - } - } - - tls_vector_offset = -1; - g_warning ("could not discover the mach TLS offset"); -ok: - pthread_setspecific (key, old_value); -} - #endif diff --git a/mono/utils/mach-support-unknown.c b/mono/utils/mach-support-unknown.c index cc629bda2d..e6a929176b 100644 --- a/mono/utils/mach-support-unknown.c +++ b/mono/utils/mach-support-unknown.c @@ -17,18 +17,6 @@ #include "utils/mono-sigcontext.h" #include "mach-support.h" -void * -mono_mach_arch_get_ip (thread_state_t state) -{ - g_assert_not_reached (); -} - -void * -mono_mach_arch_get_sp (thread_state_t state) -{ - g_assert_not_reached (); -} - int mono_mach_arch_get_mcontext_size () { @@ -74,18 +62,7 @@ mono_mach_arch_get_thread_states (thread_port_t thread, thread_state_t state, ma kern_return_t mono_mach_arch_set_thread_states (thread_port_t thread, thread_state_t state, mach_msg_type_number_t count, thread_state_t fpstate, mach_msg_type_number_t fpcount) { - g_assert_not_reached (); -} - -void * -mono_mach_arch_get_tls_value_from_thread (pthread_t thread, guint32 key) -{ - g_assert_not_reached (); -} - -void -mono_mach_init (pthread_key_t key) -{ + g_assert_not_reached (); } #endif diff --git a/mono/utils/mach-support-x86.c b/mono/utils/mach-support-x86.c index d1e0a73492..e28ee66f9e 100644 --- a/mono/utils/mach-support-x86.c +++ b/mono/utils/mach-support-x86.c @@ -20,38 +20,6 @@ // For reg numbers #include -/* Known offsets used for TLS storage*/ - -/* All OSX versions up to 10.8 */ -#define TLS_VECTOR_OFFSET_CATS 0x48 -#define TLS_VECTOR_OFFSET_10_9 0xb0 -#define TLS_VECTOR_OFFSET_10_11 0x100 - - -/* This is 2 slots less than the known low */ -#define TLS_PROBE_LOW_WATERMARK 0x40 -/* This is 28 slots above the know high, which is more than the known high-low*/ -#define TLS_PROBE_HIGH_WATERMARK 0x120 - - -static int tls_vector_offset; - -void * -mono_mach_arch_get_ip (thread_state_t state) -{ - x86_thread_state32_t *arch_state = (x86_thread_state32_t *) state; - - return (void *) arch_state->__eip; -} - -void * -mono_mach_arch_get_sp (thread_state_t state) -{ - x86_thread_state32_t *arch_state = (x86_thread_state32_t *) state; - - return (void *) arch_state->__esp; -} - int mono_mach_arch_get_mcontext_size () { @@ -151,64 +119,4 @@ mono_mach_arch_set_thread_states (thread_port_t thread, thread_state_t state, ma #endif } -void * -mono_mach_get_tls_address_from_thread (pthread_t thread, pthread_key_t key) -{ - /* OSX stores TLS values in a hidden array inside the pthread_t structure - * They are keyed off a giant array from a known offset into the pointer. This value - * is baked into their pthread_getspecific implementation - */ - intptr_t *p = (intptr_t *) thread; - intptr_t **tsd = (intptr_t **) ((char*)p + tls_vector_offset); - g_assert (tls_vector_offset != -1); - - return (void *) &tsd [key]; -} - -void * -mono_mach_arch_get_tls_value_from_thread (pthread_t thread, guint32 key) -{ - return *(void**)mono_mach_get_tls_address_from_thread (thread, key); -} - -void -mono_mach_init (pthread_key_t key) -{ - int i; - void *old_value = pthread_getspecific (key); - void *canary = (void*)0xDEADBEEFu; - - pthread_key_create (&key, NULL); - g_assert (old_value != canary); - - pthread_setspecific (key, canary); - - /*First we probe for cats*/ - tls_vector_offset = TLS_VECTOR_OFFSET_CATS; - if (mono_mach_arch_get_tls_value_from_thread (pthread_self (), key) == canary) - goto ok; - - tls_vector_offset = TLS_VECTOR_OFFSET_10_9; - if (mono_mach_arch_get_tls_value_from_thread (pthread_self (), key) == canary) - goto ok; - - tls_vector_offset = TLS_VECTOR_OFFSET_10_11; - if (mono_mach_arch_get_tls_value_from_thread (pthread_self (), key) == canary) - goto ok; - - /*Fallback to scanning a large range of offsets*/ - for (i = TLS_PROBE_LOW_WATERMARK; i <= TLS_PROBE_HIGH_WATERMARK; i += 4) { - tls_vector_offset = i; - if (mono_mach_arch_get_tls_value_from_thread (pthread_self (), key) == canary) { - g_warning ("Found new TLS offset at %d", i); - goto ok; - } - } - - tls_vector_offset = -1; - g_warning ("could not discover the mach TLS offset"); -ok: - pthread_setspecific (key, old_value); -} - #endif diff --git a/mono/utils/mach-support.c b/mono/utils/mach-support.c deleted file mode 100644 index 4abfcfaa2c..0000000000 --- a/mono/utils/mach-support.c +++ /dev/null @@ -1,41 +0,0 @@ -/** - * \file - * mach support for x86 - * - * Authors: - * Geoff Norton (gnorton@novell.com) - * - * (C) 2010 Ximian, Inc. - */ - -#include -#if defined(__MACH__) -#include -#include -#include -#include -#include -#include - -#include - -#include "mach-support.h" - -kern_return_t -mono_mach_get_threads (thread_act_array_t *threads, guint32 *count) -{ - kern_return_t ret; - - do { - ret = task_threads (current_task (), threads, count); - } while (ret == KERN_ABORTED); - - return ret; -} - -kern_return_t -mono_mach_free_threads (thread_act_array_t threads, guint32 count) -{ - return vm_deallocate(current_task (), (vm_address_t) threads, sizeof (thread_t) * count); -} -#endif diff --git a/mono/utils/mach-support.h b/mono/utils/mach-support.h index 67b3a84cfc..0247db8bd1 100644 --- a/mono/utils/mach-support.h +++ b/mono/utils/mach-support.h @@ -24,14 +24,6 @@ typedef _STRUCT_MCONTEXT *mcontext_t; typedef _STRUCT_MCONTEXT64 *mcontext_t; #endif -// We need to define this here since we need _XOPEN_SOURCE for mono -// and the pthread header guards against this -extern pthread_t pthread_from_mach_thread_np(mach_port_t); - -void *mono_mach_arch_get_ip (thread_state_t state); -void *mono_mach_arch_get_sp (thread_state_t state); -void mono_mach_init (pthread_key_t key); - int mono_mach_arch_get_mcontext_size (void); void mono_mach_arch_thread_states_to_mcontext (thread_state_t state, thread_state_t fpstate, void *context); void mono_mach_arch_mcontext_to_thread_states (void *context, thread_state_t state, thread_state_t fpstate); @@ -40,12 +32,8 @@ void mono_mach_arch_thread_states_to_mono_context (thread_state_t state, thread_ /* FIXME: Should return size_t, not int. */ int mono_mach_arch_get_thread_state_size (void); int mono_mach_arch_get_thread_fpstate_size (void); -kern_return_t mono_mach_get_threads (thread_act_array_t *threads, guint32 *count); -kern_return_t mono_mach_free_threads (thread_act_array_t threads, guint32 count); kern_return_t mono_mach_arch_get_thread_states (thread_port_t thread, thread_state_t state, mach_msg_type_number_t *count, thread_state_t fpstate, mach_msg_type_number_t *fpcount); kern_return_t mono_mach_arch_set_thread_states (thread_port_t thread, thread_state_t state, mach_msg_type_number_t count, thread_state_t fpstate, mach_msg_type_number_t fpcount); -void *mono_mach_arch_get_tls_value_from_thread (pthread_t thread, guint32 key); -void *mono_mach_get_tls_address_from_thread (pthread_t thread, pthread_key_t key); #endif #endif /* __MONO_MACH_SUPPORT_H__ */ diff --git a/mono/utils/mono-context.c b/mono/utils/mono-context.c index 4dfbbb3416..f426685487 100644 --- a/mono/utils/mono-context.c +++ b/mono/utils/mono-context.c @@ -395,11 +395,24 @@ mono_monoctx_to_sigctx (MonoContext *mctx, void *ctx) #include #include +#ifdef HOST_WIN32 +#include +#endif + void mono_sigctx_to_monoctx (void *sigctx, MonoContext *mctx) { #ifdef MONO_CROSS_COMPILE g_assert_not_reached (); +#elif defined(HOST_WIN32) + CONTEXT *context = (CONTEXT*)sigctx; + + mctx->pc = context->Pc; + mctx->cpsr = context->Cpsr; + memcpy (&mctx->regs, &context->R0, sizeof (DWORD) * 16); + + /* Why are we only copying 16 registers?! There are 32! */ + memcpy (&mctx->fregs, &context->D, sizeof (double) * 16); #else arm_ucontext *my_uc = sigctx; @@ -418,6 +431,15 @@ mono_monoctx_to_sigctx (MonoContext *mctx, void *ctx) { #ifdef MONO_CROSS_COMPILE g_assert_not_reached (); +#elif defined(HOST_WIN32) + CONTEXT *context = (CONTEXT*)ctx; + + context->Pc = mctx->pc; + context->Cpsr = mctx->cpsr; + memcpy (&context->R0, &mctx->regs, sizeof (DWORD) * 16); + + /* Why are we only copying 16 registers?! There are 32! */ + memcpy (&context->D, &mctx->fregs, sizeof (double) * 16); #else arm_ucontext *my_uc = ctx; diff --git a/mono/utils/mono-context.h b/mono/utils/mono-context.h index c6ee591548..77909ab594 100644 --- a/mono/utils/mono-context.h +++ b/mono/utils/mono-context.h @@ -41,7 +41,7 @@ typedef __m128d MonoContextSimdReg; #elif defined(HOST_ANDROID) #define MONO_HAVE_SIMD_REG typedef struct _libc_xmmreg MonoContextSimdReg; -#elif defined(__linux__) +#elif defined(__linux__) || defined(__OpenBSD__) #define MONO_HAVE_SIMD_REG #include typedef __m128d MonoContextSimdReg; diff --git a/mono/utils/mono-dl-windows.c b/mono/utils/mono-dl-windows.c index ab26660fed..8dce945ae8 100644 --- a/mono/utils/mono-dl-windows.c +++ b/mono/utils/mono-dl-windows.c @@ -55,7 +55,11 @@ mono_dl_open_file (const char *file, int flags) #endif guint32 last_error = 0; +#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) hModule = LoadLibrary (file_utf16); +#else + hModule = LoadPackagedLibrary (file_utf16, NULL); +#endif if (!hModule) last_error = GetLastError (); @@ -68,7 +72,11 @@ mono_dl_open_file (const char *file, int flags) if (!hModule) SetLastError (last_error); } else { +#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) hModule = GetModuleHandle (NULL); +#else + g_error("Not supported"); +#endif } return hModule; } diff --git a/mono/utils/mono-error-internals.h b/mono/utils/mono-error-internals.h index a1aeb511af..f83e3a401e 100644 --- a/mono/utils/mono-error-internals.h +++ b/mono/utils/mono-error-internals.h @@ -5,8 +5,8 @@ #ifndef __MONO_ERROR_INTERNALS_H__ #define __MONO_ERROR_INTERNALS_H__ +#include #include "mono/utils/mono-compiler.h" -#include "mono/metadata/class-internals.h" /*Keep in sync with MonoError*/ typedef struct { @@ -32,9 +32,8 @@ typedef struct { const char *full_message; const char *full_message_with_fields; const char *first_argument; - const char *member_signature; - void *padding [2]; + void *padding [3]; } MonoErrorInternal; /* Invariant: the error strings are allocated in the mempool of the given image */ @@ -114,7 +113,9 @@ Different names indicate different scenarios, but the same code. #define return_if_nok(error) do { if (!is_ok ((error))) return; } while (0) #define return_val_if_nok(error,val) do { if (!is_ok ((error))) return (val); } while (0) -#define goto_if_nok(error,label) do { if (!is_ok ((error))) goto label; } while (0) +#define goto_if(expr, label) do { if (expr) goto label; } while (0) +#define goto_if_ok(error, label) goto_if (is_ok (error), label) +#define goto_if_nok(error, label) goto_if (!is_ok (error), label) /* Only use this in icalls */ #define return_val_and_set_pending_if_nok(error, value) \ @@ -150,12 +151,6 @@ mono_error_dup_strings (MonoError *error, gboolean dup_strings); void mono_error_set_error (MonoError *error, int error_code, const char *msg_format, ...) MONO_ATTR_FORMAT_PRINTF(3,4); -void -mono_error_set_assembly_load (MonoError *error, const char *assembly_name, const char *msg_format, ...) MONO_ATTR_FORMAT_PRINTF(3,4); - -void -mono_error_set_assembly_load_simple (MonoError *error, const char *assembly_name, gboolean refection_only); - void mono_error_set_type_load_class (MonoError *error, MonoClass *klass, const char *msg_format, ...) MONO_ATTR_FORMAT_PRINTF(3,4); @@ -165,18 +160,6 @@ mono_error_vset_type_load_class (MonoError *error, MonoClass *klass, const char void mono_error_set_type_load_name (MonoError *error, const char *type_name, const char *assembly_name, const char *msg_format, ...) MONO_ATTR_FORMAT_PRINTF(4,5); -void -mono_error_set_method_load (MonoError *oerror, MonoClass *klass, const char *method_name, const char *signature, const char *msg_format, ...); - -void -mono_error_set_field_load (MonoError *error, MonoClass *klass, const char *field_name, const char *msg_format, ...) MONO_ATTR_FORMAT_PRINTF(4,5); - -void -mono_error_set_bad_image (MonoError *error, MonoImage *image, const char *msg_format, ...) MONO_ATTR_FORMAT_PRINTF(3,4); - -void -mono_error_set_bad_image_name (MonoError *error, const char *file_name, const char *msg_format, ...) MONO_ATTR_FORMAT_PRINTF(3,4); - void mono_error_set_out_of_memory (MonoError *error, const char *msg_format, ...) MONO_ATTR_FORMAT_PRINTF(2,3); @@ -204,9 +187,6 @@ mono_error_set_not_supported (MonoError *error, const char *msg_format, ...) MON void mono_error_set_invalid_operation (MonoError *error, const char *msg_format, ...) MONO_ATTR_FORMAT_PRINTF(2,3); -void -mono_error_set_file_not_found (MonoError *error, const char *msg_format, ...) MONO_ATTR_FORMAT_PRINTF(2,3); - void mono_error_set_exception_instance (MonoError *error, MonoException *exc); @@ -234,4 +214,10 @@ mono_error_set_from_boxed (MonoError *error, const MonoErrorBoxed *from); const char* mono_error_get_exception_name (MonoError *oerror); +void +mono_error_set_specific (MonoError *error, int error_code, const char *missing_method); + +void +mono_error_set_first_argument (MonoError *oerror, const char *first_argument); + #endif diff --git a/mono/utils/mono-error.c b/mono/utils/mono-error.c index 89cd7d1088..e124c92dbb 100644 --- a/mono/utils/mono-error.c +++ b/mono/utils/mono-error.c @@ -53,7 +53,7 @@ mono_error_prepare (MonoErrorInternal *error) if (error->error_code != MONO_ERROR_NONE) return; - error->type_name = error->assembly_name = error->member_name = error->full_message = error->exception_name_space = error->exception_name = error->full_message_with_fields = error->first_argument = error->member_signature = NULL; + error->type_name = error->assembly_name = error->member_name = error->full_message = error->exception_name_space = error->exception_name = error->full_message_with_fields = error->first_argument = NULL; error->exn.klass = NULL; } @@ -75,7 +75,7 @@ get_type_name (MonoErrorInternal *error) return error->type_name; MonoClass *klass = get_class (error); if (klass) - return klass->name; + return m_class_get_name (klass); return ""; } @@ -85,8 +85,8 @@ get_assembly_name (MonoErrorInternal *error) if (error->assembly_name) return error->assembly_name; MonoClass *klass = get_class (error); - if (klass && klass->image) - return klass->image->name; + if (klass && m_class_get_image (klass)) + return m_class_get_image (klass)->name; return ""; } @@ -150,8 +150,7 @@ mono_error_cleanup (MonoError *oerror) g_free ((char*)error->exception_name_space); g_free ((char*)error->exception_name); g_free ((char*)error->first_argument); - g_free ((char*)error->member_signature); - error->type_name = error->assembly_name = error->member_name = error->exception_name_space = error->exception_name = error->first_argument = error->member_signature = NULL; + error->type_name = error->assembly_name = error->member_name = error->exception_name_space = error->exception_name = error->first_argument = NULL; error->exn.klass = NULL; } @@ -187,15 +186,24 @@ mono_error_get_message (MonoError *oerror) MonoErrorInternal *error = (MonoErrorInternal*)oerror; if (error->error_code == MONO_ERROR_NONE) return NULL; + + //Those are the simplified errors + switch (error->error_code) { + case MONO_ERROR_MISSING_METHOD: + case MONO_ERROR_BAD_IMAGE: + case MONO_ERROR_FILE_NOT_FOUND: + case MONO_ERROR_MISSING_FIELD: + return error->full_message; + } + if (error->full_message_with_fields) return error->full_message_with_fields; - error->full_message_with_fields = g_strdup_printf ("%s assembly:%s type:%s member:%s signature:%s", + error->full_message_with_fields = g_strdup_printf ("%s assembly:%s type:%s member:%s", error->full_message, get_assembly_name (error), get_type_name (error), - error->member_signature, - error->member_name ? error->member_name : ""); + error->member_name); return error->full_message_with_fields ? error->full_message_with_fields : error->full_message; } @@ -223,7 +231,6 @@ mono_error_dup_strings (MonoError *oerror, gboolean dup_strings) DUP_STR (exception_name_space); DUP_STR (exception_name); DUP_STR (first_argument); - DUP_STR (member_signature); } #undef DUP_STR } @@ -255,14 +262,6 @@ mono_error_set_member_name (MonoError *oerror, const char *member_name) error->member_name = member_name; } -static void -mono_error_set_member_signature (MonoError *oerror, const char *member_signature) -{ - MonoErrorInternal *error = (MonoErrorInternal*)oerror; - - error->member_signature = member_signature; -} - static void mono_error_set_type_name (MonoError *oerror, const char *type_name) { @@ -290,29 +289,6 @@ mono_error_set_corlib_exception (MonoError *oerror, const char *name_space, cons error->exception_name = name; } - -void -mono_error_set_assembly_load (MonoError *oerror, const char *assembly_name, const char *msg_format, ...) -{ - MonoErrorInternal *error = (MonoErrorInternal*)oerror; - mono_error_prepare (error); - - error->error_code = MONO_ERROR_FILE_NOT_FOUND; - mono_error_set_assembly_name (oerror, assembly_name); - - set_error_message (); -} - - -void -mono_error_set_assembly_load_simple (MonoError *oerror, const char *assembly_name, gboolean refection_only) -{ - if (refection_only) - mono_error_set_assembly_load (oerror, assembly_name, "Cannot resolve dependency to assembly because it has not been preloaded. When using the ReflectionOnly APIs, dependent assemblies must be pre-loaded or loaded on demand through the ReflectionOnlyAssemblyResolve event."); - else - mono_error_set_assembly_load (oerror, assembly_name, "Could not load file or assembly '%s' or one of its dependencies.", assembly_name); -} - void mono_error_set_type_load_class (MonoError *oerror, MonoClass *klass, const char *msg_format, ...) { @@ -350,51 +326,19 @@ mono_error_set_type_load_name (MonoError *oerror, const char *type_name, const c set_error_message (); } +/* + * Sets @error to be of type @error_code with message @message + * XXX only works for MONO_ERROR_MISSING_METHOD, MONO_ERROR_BAD_IMAGE, MONO_ERROR_FILE_NOT_FOUND and MONO_ERROR_MISSING_FIELD for now +*/ void -mono_error_set_method_load (MonoError *oerror, MonoClass *klass, const char *method_name, const char *signature, const char *msg_format, ...) +mono_error_set_specific (MonoError *oerror, int error_code, const char *message) { MonoErrorInternal *error = (MonoErrorInternal*)oerror; mono_error_prepare (error); - error->error_code = MONO_ERROR_MISSING_METHOD; - mono_error_set_class (oerror, klass); - mono_error_set_member_name (oerror, method_name); - mono_error_set_member_signature (oerror, signature); - set_error_message (); -} - -void -mono_error_set_field_load (MonoError *oerror, MonoClass *klass, const char *field_name, const char *msg_format, ...) -{ - MonoErrorInternal *error = (MonoErrorInternal*)oerror; - mono_error_prepare (error); - - error->error_code = MONO_ERROR_MISSING_FIELD; - mono_error_set_class (oerror, klass); - mono_error_set_member_name (oerror, field_name); - set_error_message (); -} - -void -mono_error_set_bad_image_name (MonoError *oerror, const char *assembly_name, const char *msg_format, ...) -{ - MonoErrorInternal *error = (MonoErrorInternal*)oerror; - mono_error_prepare (error); - - error->error_code = MONO_ERROR_BAD_IMAGE; - mono_error_set_assembly_name (oerror, assembly_name); - set_error_message (); -} - -void -mono_error_set_bad_image (MonoError *oerror, MonoImage *image, const char *msg_format, ...) -{ - MonoErrorInternal *error = (MonoErrorInternal*)oerror; - mono_error_prepare (error); - - error->error_code = MONO_ERROR_BAD_IMAGE; - error->assembly_name = image ? mono_image_get_name (image) : ""; - set_error_message (); + error->error_code = error_code; + error->full_message = message; + error->flags |= MONO_ERROR_FREE_STRINGS; } void @@ -473,20 +417,6 @@ mono_error_set_invalid_operation (MonoError *oerror, const char *msg_format, ... va_end (args); } -/** - * mono_error_set_file_not_found: - * - * System.IO.FileNotFoundException - */ -void -mono_error_set_file_not_found (MonoError *oerror, const char *msg_format, ...) -{ - va_list args; - va_start (args, msg_format); - mono_error_set_generic_errorv (oerror, "System.IO", "FileNotFoundException", msg_format, args); - va_end (args); -} - void mono_error_set_invalid_program (MonoError *oerror, const char *msg_format, ...) { @@ -601,7 +531,7 @@ get_type_name_as_mono_string (MonoErrorInternal *error, MonoDomain *domain, Mono } else { MonoClass *klass = get_class (error); if (klass) { - char *name = mono_type_full_name (&klass->byval_arg); + char *name = mono_type_full_name (m_class_get_byval_arg (klass)); if (name) { res = string_new_cleanup (domain, name); g_free (name); @@ -623,6 +553,13 @@ set_message_on_exception (MonoException *exception, MonoErrorInternal *error, Mo mono_error_set_out_of_memory (error_out, "Could not allocate exception object"); } +MonoExceptionHandle +mono_error_prepare_exception_handle (MonoError *oerror, MonoError *error_out) +// Can fail with out-of-memory +{ + return MONO_HANDLE_NEW (MonoException, mono_error_prepare_exception (oerror, error_out)); +} + /*Can fail with out-of-memory*/ MonoException* mono_error_prepare_exception (MonoError *oerror, MonoError *error_out) @@ -630,7 +567,7 @@ mono_error_prepare_exception (MonoError *oerror, MonoError *error_out) MonoErrorInternal *error = (MonoErrorInternal*)oerror; MonoException* exception = NULL; - MonoString *assembly_name = NULL, *type_name = NULL, *method_name = NULL, *field_name = NULL, *msg = NULL; + MonoString *assembly_name = NULL, *type_name = NULL; MonoDomain *domain = mono_domain_get (); error_init (error_out); @@ -640,60 +577,16 @@ mono_error_prepare_exception (MonoError *oerror, MonoError *error_out) return NULL; case MONO_ERROR_MISSING_METHOD: - if ((error->type_name || error->exn.klass) && error->member_name) { - type_name = get_type_name_as_mono_string (error, domain, error_out); - if (!mono_error_ok (error_out)) - break; - - method_name = string_new_cleanup (domain, error->member_name); - if (!method_name) { - mono_error_set_out_of_memory (error_out, "Could not allocate method name"); - break; - } - - MonoString *signature = NULL; - if (error->member_signature) { - signature = string_new_cleanup (domain, error->member_signature); - if (!signature) { - mono_error_set_out_of_memory (error_out, "Could not allocate signature"); - break; - } - } - - MonoString *message = NULL; - if (error->full_message && strlen (error->full_message) > 0) { - message = string_new_cleanup (domain, error->full_message); - if (!message) { - mono_error_set_out_of_memory (error_out, "Could not allocate message"); - break; - } - } - exception = mono_exception_from_name_four_strings_checked (mono_defaults.corlib, "System", "MissingMethodException", type_name, method_name, signature, message, error_out); - if (exception) - set_message_on_exception (exception, error, error_out); - } else { - exception = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MissingMethodException", error->full_message); - } + exception = mono_corlib_exception_new_with_args ("System", "MissingMethodException", error->full_message, error->first_argument, error_out); + break; + case MONO_ERROR_BAD_IMAGE: + exception = mono_corlib_exception_new_with_args ("System", "BadImageFormatException", error->full_message, error->first_argument, error_out); + break; + case MONO_ERROR_FILE_NOT_FOUND: + exception = mono_corlib_exception_new_with_args ("System.IO", "FileNotFoundException", error->full_message, error->first_argument, error_out); break; - case MONO_ERROR_MISSING_FIELD: - if ((error->type_name || error->exn.klass) && error->member_name) { - type_name = get_type_name_as_mono_string (error, domain, error_out); - if (!mono_error_ok (error_out)) - break; - - field_name = string_new_cleanup (domain, error->member_name); - if (!field_name) { - mono_error_set_out_of_memory (error_out, "Could not allocate field name"); - break; - } - - exception = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "MissingFieldException", type_name, field_name, error_out); - if (exception) - set_message_on_exception (exception, error, error_out); - } else { - exception = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MissingFieldException", error->full_message); - } + exception = mono_corlib_exception_new_with_args ("System", "MissingFieldException", error->full_message, error->first_argument, error_out); break; case MONO_ERROR_TYPE_LOAD: @@ -720,37 +613,11 @@ mono_error_prepare_exception (MonoError *oerror, MonoError *error_out) } break; - case MONO_ERROR_FILE_NOT_FOUND: - case MONO_ERROR_BAD_IMAGE: - if (error->assembly_name) { - msg = string_new_cleanup (domain, error->full_message); - if (!msg) { - mono_error_set_out_of_memory (error_out, "Could not allocate message"); - break; - } - - if (error->assembly_name) { - assembly_name = string_new_cleanup (domain, error->assembly_name); - if (!assembly_name) { - mono_error_set_out_of_memory (error_out, "Could not allocate assembly name"); - break; - } - } - - if (error->error_code == MONO_ERROR_FILE_NOT_FOUND) - exception = mono_exception_from_name_two_strings_checked (mono_get_corlib (), "System.IO", "FileNotFoundException", msg, assembly_name, error_out); - else - exception = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "BadImageFormatException", msg, assembly_name, error_out); - } else { - if (error->error_code == MONO_ERROR_FILE_NOT_FOUND) - exception = mono_exception_from_name_msg (mono_get_corlib (), "System.IO", "FileNotFoundException", error->full_message); - else - exception = mono_exception_from_name_msg (mono_defaults.corlib, "System", "BadImageFormatException", error->full_message); - } - break; - case MONO_ERROR_OUT_OF_MEMORY: - exception = mono_get_exception_out_of_memory (); + if (domain) + exception = domain->out_of_memory_ex; + if (!exception) + exception = mono_get_exception_out_of_memory (); break; case MONO_ERROR_ARGUMENT: @@ -819,6 +686,36 @@ Convert this MonoError to an exception if it's faulty or return NULL. The error object is cleant after. */ +MonoExceptionHandle +mono_error_convert_to_exception_handle (MonoError *target_error) +{ + ERROR_DECL (error); + + HANDLE_FUNCTION_ENTER () + + MonoExceptionHandle ex = MONO_HANDLE_NEW (MonoException, NULL); + + /* Mempool stored error shouldn't be cleaned up */ + g_assert (!is_boxed ((MonoErrorInternal*)target_error)); + + if (mono_error_ok (target_error)) + goto exit; + + ex = mono_error_prepare_exception_handle (target_error, error); + if (!mono_error_ok (error)) { + ERROR_DECL_VALUE (second_chance); + /*Try to produce the exception for the second error. FIXME maybe we should log about the original one*/ + ex = mono_error_prepare_exception_handle (error, &second_chance); + + g_assert (mono_error_ok (&second_chance)); /*We can't reasonable handle double faults, maybe later.*/ + mono_error_cleanup (error); + } + mono_error_cleanup (target_error); + +exit: + HANDLE_FUNCTION_RETURN_REF (MonoException, ex) +} + MonoException* mono_error_convert_to_exception (MonoError *target_error) { @@ -889,7 +786,6 @@ mono_error_box (const MonoError *ierror, MonoImage *image) DUP_STR (full_message); DUP_STR (full_message_with_fields); DUP_STR (first_argument); - DUP_STR (member_signature); to->exn.klass = from->exn.klass; #undef DUP_STR @@ -936,9 +832,16 @@ mono_error_set_from_boxed (MonoError *oerror, const MonoErrorBoxed *box) DUP_STR (full_message); DUP_STR (full_message_with_fields); DUP_STR (first_argument); - DUP_STR (member_signature); to->exn.klass = from->exn.klass; #undef DUP_STR return (to->flags & MONO_ERROR_INCOMPLETE) == 0 ; } + +void +mono_error_set_first_argument (MonoError *oerror, const char *first_argument) +{ + MonoErrorInternal* to = (MonoErrorInternal*)oerror; + to->first_argument = g_strdup (first_argument); + to->flags |= MONO_ERROR_FREE_STRINGS; +} diff --git a/mono/utils/mono-filemap.c b/mono/utils/mono-filemap.c index 416ca2625d..3fe31d7776 100644 --- a/mono/utils/mono-filemap.c +++ b/mono/utils/mono-filemap.c @@ -57,7 +57,7 @@ int mono_file_map_fd (MonoFileMap *fmap) { #ifdef WIN32 - return fileno ((FILE*)fmap); + return _fileno ((FILE*)fmap); #else return (int)(size_t)fmap; #endif diff --git a/mono/utils/mono-hwcap-arm.c b/mono/utils/mono-hwcap-arm.c index a44f43ac9e..b4de27ee1d 100644 --- a/mono/utils/mono-hwcap-arm.c +++ b/mono/utils/mono-hwcap-arm.c @@ -94,6 +94,31 @@ mono_hwcap_arch_init (void) } /* TODO: Find a way to detect features like Thumb and VFP. */ +#elif defined (_WIN32) + /* From MSDN: + * Windows on ARM presumes that it is running on an ARMv7 architecture at all times. + * Floating-point support in the form of VFPv3-D32 or later must be present in hardware. + * The VFP must support both single-precision and double-precision floating-point in hardware. + * + * The Windows runtime does not support emulation of floating-point to enable running on non-VFP hardware. + * Advanced SIMD Extensions (NEON) support—this includes both integer and floating-point operations—must also be present in hardware. + * No run-time support for emulation is provided. + * + * Integer divide support (UDIV/SDIV) is strongly recommended but not required. + * Platforms that lack integer divide support may incur a performance penalty because + * these operations have to be trapped and possibly patched. + * + * The instruction set for Windows on ARM is strictly limited to Thumb-2. + * All code executed on this platform is expected to start and remain in Thumb mode at all times. + */ + mono_hwcap_arm_is_v5 = TRUE; + mono_hwcap_arm_is_v6 = TRUE; + mono_hwcap_arm_is_v7 = TRUE; + mono_hwcap_arm_has_vfp = TRUE; + mono_hwcap_arm_has_vfp3 = TRUE; + mono_hwcap_arm_has_vfp3_d16 = TRUE; + mono_hwcap_arm_has_thumb = TRUE; + mono_hwcap_arm_has_thumb2 = TRUE; #else /* We can't use the auxiliary vector on Android due to * permissions, so fall back to /proc/cpuinfo. We also diff --git a/mono/utils/mono-hwcap-ppc.c b/mono/utils/mono-hwcap-ppc.c index c3adc8a18b..a371a2d854 100644 --- a/mono/utils/mono-hwcap-ppc.c +++ b/mono/utils/mono-hwcap-ppc.c @@ -62,16 +62,27 @@ mono_hwcap_arch_init (void) mono_hwcap_ppc_has_multiple_ls_units = TRUE; } #elif defined(_AIX) - /* - * FIXME: ensure these are valid, and we match Linux ones - */ - mono_hwcap_ppc_is_isa_2x = __power_4_andup() ? TRUE : FALSE; - mono_hwcap_ppc_is_isa_64 = __cpu64() ? TRUE: FALSE; + if (__cpu64()) + mono_hwcap_ppc_is_isa_64 = TRUE; + if (__power_4_andup()) + mono_hwcap_ppc_is_isa_2x = TRUE; + if (__power_5_andup()) + mono_hwcap_ppc_has_icache_snoop = TRUE; + /* not on POWER8 */ + if (__power_4() || __power_5() || __power_6() || __power_7()) + mono_hwcap_ppc_has_multiple_ls_units = TRUE; /* * I dont see a way to get extended POWER6 and the PV_6_1 * def seems to be trigged on the POWER6 here despite not * having these extended instructions, so POWER7 it is */ - mono_hwcap_ppc_has_move_fpr_gpr = __power_7_andup() ? TRUE : FALSE; + /* + * WARNING: reports that this doesn't actually work, try + * to re-enable after more investigation + */ + /* + if (__power_7_andup()) + mono_hwcap_ppc_has_move_fpr_gpr = TRUE; + */ #endif } diff --git a/mono/utils/mono-hwcap-x86.c b/mono/utils/mono-hwcap-x86.c index 7a4b859a8e..4e103e0c1d 100644 --- a/mono/utils/mono-hwcap-x86.c +++ b/mono/utils/mono-hwcap-x86.c @@ -147,7 +147,7 @@ mono_hwcap_arch_init (void) } } -#if defined(HAVE_UNISTD_H) +#if defined(HAVE_UNISTD_H) && defined(HAVE_ACCESS) mono_hwcap_x86_is_xen = !access ("/proc/xen", F_OK); #endif } diff --git a/mono/utils/mono-linked-list-set.h b/mono/utils/mono-linked-list-set.h index ca441ffc48..890f0cad8d 100644 --- a/mono/utils/mono-linked-list-set.h +++ b/mono/utils/mono-linked-list-set.h @@ -61,7 +61,7 @@ MONO_API gpointer mono_lls_get_hazardous_pointer_with_mask (gpointer volatile *pp, MonoThreadHazardPointers *hp, int hazard_index); static inline gboolean -mono_lls_filter_accept_all (gpointer elem) +mono_lls_filter_accept_all (gpointer elem, gpointer dummy) { return TRUE; } @@ -70,13 +70,13 @@ mono_lls_filter_accept_all (gpointer elem) * These macros assume that no other threads are actively modifying the list. */ -#define MONO_LLS_FOREACH_FILTERED(list, type, elem, filter) \ +#define MONO_LLS_FOREACH_FILTERED(list, type, elem, filter, ...) \ do { \ MonoLinkedListSet *list__ = (list); \ for (MonoLinkedListSetNode *cur__ = list__->head; cur__; cur__ = (MonoLinkedListSetNode *) mono_lls_pointer_unmask (cur__->next)) { \ if (!mono_lls_pointer_get_mark (cur__->next)) { \ type *elem = (type *) cur__; \ - if (filter (elem)) { + if (filter (elem, __VA_ARGS__)) { #define MONO_LLS_FOREACH_END \ } \ @@ -85,18 +85,18 @@ mono_lls_filter_accept_all (gpointer elem) } while (0); #define MONO_LLS_FOREACH(list, type, elem) \ - MONO_LLS_FOREACH_FILTERED ((list), type, elem, mono_lls_filter_accept_all) + MONO_LLS_FOREACH_FILTERED ((list), type, elem, mono_lls_filter_accept_all, NULL) /* * These macros can be used while other threads are potentially modifying the * list, but they only provide a snapshot of the list as a result. * * NOTE: Do NOT break out of the loop through any other means than a break - * statement, as other ways of breaking the loop will skip past important - * cleanup work. + * statement, as other ways of breaking the loop (return, goto, etc) will skip + * past important cleanup work. */ -#define MONO_LLS_FOREACH_FILTERED_SAFE(list, type, elem, filter) \ +#define MONO_LLS_FOREACH_FILTERED_SAFE(list, type, elem, filter, ...) \ do { \ /* NOTE: Keep this macro's code in sync with the mono_lls_find () logic. */ \ MonoLinkedListSet *list__ = (list); \ @@ -125,7 +125,7 @@ mono_lls_filter_accept_all (gpointer elem) progress__ = TRUE; \ hkey__ = ckey__; \ type *elem = (type *) cur__; \ - if (filter (elem)) { \ + if (filter (elem, __VA_ARGS__)) { \ gboolean broke__ = TRUE; \ gboolean done__ = FALSE; \ do { \ @@ -169,6 +169,6 @@ mono_lls_filter_accept_all (gpointer elem) } while (0); #define MONO_LLS_FOREACH_SAFE(list, type, elem) \ - MONO_LLS_FOREACH_FILTERED_SAFE ((list), type, elem, mono_lls_filter_accept_all) + MONO_LLS_FOREACH_FILTERED_SAFE ((list), type, elem, mono_lls_filter_accept_all, NULL) #endif /* __MONO_SPLIT_ORDERED_LIST_H__ */ diff --git a/mono/utils/mono-merp.c b/mono/utils/mono-merp.c index 98b853fe75..7750997d78 100644 --- a/mono/utils/mono-merp.c +++ b/mono/utils/mono-merp.c @@ -90,7 +90,7 @@ typedef struct { gboolean log; } MerpOptions; -MerpOptions config; +static MerpOptions config; static void append_merp_arch (GString *output, MerpArch arch) @@ -114,7 +114,8 @@ append_merp_arch (GString *output, MerpArch arch) } static MerpArch -get_merp_arch () { +get_merp_arch (void) +{ #ifdef TARGET_X86 return MerpArchx86; #elif defined(TARGET_AMD64) @@ -272,9 +273,10 @@ mono_encode_merp (GString *output, MERPStruct *merp) static void mono_arch_memory_info (size_t *resOut, size_t *vmOut) { - struct task_basic_info t_info = {0}; + struct task_basic_info t_info; + memset (&t_info, 0, sizeof (t_info)); mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT; - task_name_t task = mach_task_self(); + task_name_t task = mach_task_self (); task_info(task, TASK_BASIC_INFO, (task_info_t) &t_info, &t_info_count); @@ -292,7 +294,6 @@ write_file (GString *str, const char *fileName) fclose (outfile); } - /* * This struct is the wire protocol between MERP * and mono @@ -309,12 +310,14 @@ typedef struct { } MerpRequest; static void -send_mach_message (mach_port_t *mach_port) { - task_name_t task = mach_task_self(); +send_mach_message (mach_port_t *mach_port) +{ + task_name_t task = mach_task_self (); // Setup request MerpRequest req; - req.head.msgh_bits = MACH_MSGH_BITS_COMPLEX| MACH_MSGH_BITS(19, 0); + memset (&req, 0, sizeof (req)); + req.head.msgh_bits = MACH_MSGH_BITS_COMPLEX | MACH_MSGH_BITS(19, 0); req.task.name = task; req.task.disposition = 19; req.task.type = MACH_MSG_PORT_DESCRIPTOR; @@ -336,7 +339,8 @@ send_mach_message (mach_port_t *mach_port) { } static void -connect_to_merp (const char *serviceName, mach_port_t *merp_port) { +connect_to_merp (const char *serviceName, mach_port_t *merp_port) +{ // // Create process to launch merp gui application const char *argvOpen[] = {"/usr/bin/open", "-a", config.merpGUIPath, NULL}; int status = posix_spawn(NULL, "/usr/bin/open", NULL, NULL, (char *const*)(argvOpen), NULL); @@ -348,7 +352,7 @@ connect_to_merp (const char *serviceName, mach_port_t *merp_port) { // BOOTSTRAP_UNKNOWN_SERVICE is returned while the service doesn't exist. // We rely on MERP to make the service with serviceName for us kern_return_t kernErr = bootstrap_look_up(bootstrap_port, serviceName, merp_port); - while (true) { + while (TRUE) { for (int i = 0; BOOTSTRAP_UNKNOWN_SERVICE == kernErr && i < 5000; i++) kernErr = bootstrap_look_up(bootstrap_port, serviceName, merp_port); @@ -446,7 +450,8 @@ mono_merp_invoke (pid_t crashed_pid, intptr_t thread_pointer, const char *signal // This unique service name is used to communicate with merp over mach service ports char *serviceName = g_strdup_printf ("com.mono.merp.%.8x", crashed_pid); - MERPStruct merp = {0}; + MERPStruct merp; + memset (&merp, 0, sizeof (merp)); mono_init_merp (serviceName, signal, crashed_pid, thread_pointer, &merp); GString *output = g_string_new (""); @@ -468,15 +473,15 @@ mono_merp_disable (void) if (!config.enable_merp) return; - g_free (config.appBundleID); - g_free (config.appSignature); - g_free (config.appVersion); - g_free (config.merpGUIPath); - memset ((void *)&config, 0, sizeof (MerpOptions)); + g_free ((char*)config.appBundleID); // cast away const + g_free ((char*)config.appSignature); + g_free ((char*)config.appVersion); + g_free ((char*)config.merpGUIPath); + memset (&config, 0, sizeof (config)); } void -mono_merp_enable (char *appBundleID, char *appSignature, char *appVersion, char *merpGUIPath) +mono_merp_enable (const char *appBundleID, const char *appSignature, const char *appVersion, const char *merpGUIPath) { g_assert (!config.enable_merp); @@ -497,4 +502,3 @@ mono_merp_enabled (void) } #endif // TARGET_OSX - diff --git a/mono/utils/mono-merp.h b/mono/utils/mono-merp.h index dd61ca12db..c81f4e77b0 100644 --- a/mono/utils/mono-merp.h +++ b/mono/utils/mono-merp.h @@ -28,7 +28,7 @@ void mono_merp_disable (void); * See MERP documentation for information on the bundle ID, signature, and version fields */ void -mono_merp_enable (char *appBundleID, char *appSignature, char *appVersion, char *merpGUIPath); +mono_merp_enable (const char *appBundleID, const char *appSignature, const char *appVersion, const char *merpGUIPath); /** * Whether the MERP-based handler is registered diff --git a/mono/utils/mono-mmap-internals.h b/mono/utils/mono-mmap-internals.h index 8831c8bdad..42fa8a3f8c 100644 --- a/mono/utils/mono-mmap-internals.h +++ b/mono/utils/mono-mmap-internals.h @@ -13,13 +13,13 @@ #include "mono-compiler.h" void * -malloc_shared_area (int pid); +mono_malloc_shared_area (int pid); char* -aligned_address (char *mem, size_t size, size_t alignment); +mono_aligned_address (char *mem, size_t size, size_t alignment); void -account_mem (MonoMemAccountType type, ssize_t size); +mono_account_mem (MonoMemAccountType type, ssize_t size); gboolean mono_valloc_can_alloc (size_t size); diff --git a/mono/utils/mono-mmap-windows.c b/mono/utils/mono-mmap-windows.c index 0ae90eee3b..2759862bbe 100644 --- a/mono/utils/mono-mmap-windows.c +++ b/mono/utils/mono-mmap-windows.c @@ -76,7 +76,7 @@ mono_valloc (void *addr, size_t length, int flags, MonoMemAccountType type) ptr = VirtualAlloc (addr, length, mflags, prot); - account_mem (type, (ssize_t)length); + mono_account_mem (type, (ssize_t)length); return ptr; } @@ -94,12 +94,12 @@ mono_valloc_aligned (size_t length, size_t alignment, int flags, MonoMemAccountT if (!mono_valloc_can_alloc (length)) return NULL; - aligned = aligned_address (mem, length, alignment); + aligned = mono_aligned_address (mem, length, alignment); aligned = VirtualAlloc (aligned, length, MEM_COMMIT, prot); g_assert (aligned); - account_mem (type, (ssize_t)length); + mono_account_mem (type, (ssize_t)length); return aligned; } @@ -117,7 +117,7 @@ mono_vfree (void *addr, size_t length, MonoMemAccountType type) g_assert (res); - account_mem (type, -(ssize_t)length); + mono_account_mem (type, -(ssize_t)length); return 0; } @@ -190,7 +190,7 @@ void* mono_shared_area (void) { if (!malloced_shared_area) - malloced_shared_area = malloc_shared_area (0); + malloced_shared_area = mono_malloc_shared_area (0); /* get the pid here */ return malloced_shared_area; } diff --git a/mono/utils/mono-mmap.c b/mono/utils/mono-mmap.c index 2171f6ebd0..dc802c4697 100644 --- a/mono/utils/mono-mmap.c +++ b/mono/utils/mono-mmap.c @@ -61,7 +61,7 @@ typedef struct { } SAreaHeader; void* -malloc_shared_area (int pid) +mono_malloc_shared_area (int pid) { int size = mono_pagesize (); SAreaHeader *sarea = (SAreaHeader *) g_malloc0 (size); @@ -74,7 +74,7 @@ malloc_shared_area (int pid) } char* -aligned_address (char *mem, size_t size, size_t alignment) +mono_aligned_address (char *mem, size_t size, size_t alignment) { char *aligned = (char*)((size_t)(mem + (alignment - 1)) & ~(alignment - 1)); g_assert (aligned >= mem && aligned + size <= mem + size + alignment && !((size_t)aligned & (alignment - 1))); @@ -86,7 +86,7 @@ static size_t total_allocation_count; static size_t alloc_limit; void -account_mem (MonoMemAccountType type, ssize_t size) +mono_account_mem (MonoMemAccountType type, ssize_t size) { mono_atomic_fetch_add_word (&allocation_count [type], size); mono_atomic_fetch_add_word (&total_allocation_count, size); @@ -242,7 +242,7 @@ mono_valloc (void *addr, size_t length, int flags, MonoMemAccountType type) if (ptr == MAP_FAILED) return NULL; - account_mem (type, (ssize_t)length); + mono_account_mem (type, (ssize_t)length); return ptr; } @@ -262,7 +262,7 @@ mono_vfree (void *addr, size_t length, MonoMemAccountType type) res = munmap (addr, length); END_CRITICAL_SECTION; - account_mem (type, -(ssize_t)length); + mono_account_mem (type, -(ssize_t)length); return res; } @@ -501,7 +501,7 @@ mono_shared_area (void) if (shared_area_disabled ()) { if (!malloced_shared_area) - malloced_shared_area = malloc_shared_area (0); + malloced_shared_area = mono_malloc_shared_area (0); /* get the pid here */ return malloced_shared_area; } @@ -521,7 +521,7 @@ mono_shared_area (void) * even if it means the data can't be read by other processes */ if (fd == -1) - return malloc_shared_area (pid); + return mono_malloc_shared_area (pid); if (ftruncate (fd, size) != 0) { shm_unlink (buf); close (fd); @@ -533,7 +533,7 @@ mono_shared_area (void) if (res == MAP_FAILED) { shm_unlink (buf); close (fd); - return malloc_shared_area (pid); + return mono_malloc_shared_area (pid); } /* we don't need the file descriptor anymore */ close (fd); @@ -614,7 +614,7 @@ void* mono_shared_area (void) { if (!malloced_shared_area) - malloced_shared_area = malloc_shared_area (getpid ()); + malloced_shared_area = mono_malloc_shared_area (getpid ()); /* get the pid here */ return malloced_shared_area; } @@ -659,7 +659,7 @@ mono_valloc_aligned (size_t size, size_t alignment, int flags, MonoMemAccountTyp if (!mem) return NULL; - aligned = aligned_address (mem, size, alignment); + aligned = mono_aligned_address (mem, size, alignment); if (aligned > mem) mono_vfree (mem, aligned - mem, type); diff --git a/mono/utils/mono-os-wait-win32.c b/mono/utils/mono-os-wait-win32.c index 43ca85e3f5..8ec2163de6 100644 --- a/mono/utils/mono-os-wait-win32.c +++ b/mono/utils/mono-os-wait-win32.c @@ -152,6 +152,8 @@ mono_win32_wait_for_multiple_objects_ex (DWORD count, CONST HANDLE *handles, BOO return result; } +#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) + DWORD mono_win32_signal_object_and_wait (HANDLE toSignal, HANDLE toWait, DWORD timeout, BOOL alertable) { @@ -173,6 +175,8 @@ mono_win32_signal_object_and_wait (HANDLE toSignal, HANDLE toWait, DWORD timeout return result; } +#endif + #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) DWORD mono_win32_msg_wait_for_multiple_objects_ex (DWORD count, CONST HANDLE *handles, DWORD timeout, DWORD wakeMask, DWORD flags) diff --git a/mono/utils/mono-proclib.c b/mono/utils/mono-proclib.c index 1340b9db01..191ee1dc1f 100644 --- a/mono/utils/mono-proclib.c +++ b/mono/utils/mono-proclib.c @@ -32,8 +32,10 @@ #ifdef HAVE_SYS_SYSCTL_H #include #endif +#ifdef HAVE_SYS_RESOURCE_H #include #endif +#endif #if defined(__HAIKU__) #include #endif @@ -519,7 +521,7 @@ get_user_hz (void) { static int user_hz = 0; if (user_hz == 0) { -#ifdef _SC_CLK_TCK +#if defined (_SC_CLK_TCK) && defined (HAVE_SYSCONF) user_hz = sysconf (_SC_CLK_TCK); #endif if (user_hz == 0) @@ -778,7 +780,7 @@ mono_cpu_count (void) * [5] https://github.com/dotnet/coreclr/blob/7058273693db2555f127ce16e6b0c5b40fb04867/src/pal/src/misc/sysinfo.cpp#L148 */ -#ifdef _SC_NPROCESSORS_CONF +#if defined (_SC_NPROCESSORS_CONF) && defined (HAVE_SYSCONF) { int count = sysconf (_SC_NPROCESSORS_CONF); if (count > 0) @@ -795,7 +797,7 @@ mono_cpu_count (void) return CPU_COUNT (&set); } #endif -#ifdef _SC_NPROCESSORS_ONLN +#if defined (_SC_NPROCESSORS_ONLN) && defined (HAVE_SYSCONF) { int count = sysconf (_SC_NPROCESSORS_ONLN); if (count > 0) @@ -930,6 +932,7 @@ gint32 mono_cpu_usage (MonoCpuUsageState *prev) { gint32 cpu_usage = 0; +#ifdef HAVE_GETRUSAGE gint64 cpu_total_time; gint64 cpu_busy_time; struct rusage resource_usage; @@ -957,7 +960,7 @@ mono_cpu_usage (MonoCpuUsageState *prev) if (cpu_total_time > 0 && cpu_busy_time > 0) cpu_usage = (gint32)(cpu_busy_time * 100 / cpu_total_time); - +#endif return cpu_usage; } #endif /* !HOST_WIN32 */ diff --git a/mono/utils/mono-stdlib.c b/mono/utils/mono-stdlib.c index 3685dcb996..d055b04a6d 100644 --- a/mono/utils/mono-stdlib.c +++ b/mono/utils/mono-stdlib.c @@ -35,7 +35,8 @@ mono_mkstemp (char *templ) len = strlen (templ); do { - t = mktemp (templ); + t = g_mktemp (templ); + if (t == NULL) { errno = EINVAL; return -1; @@ -45,7 +46,7 @@ mono_mkstemp (char *templ) return -1; } - ret = open (templ, O_RDWR | O_BINARY | O_CREAT | O_EXCL, 0600); + ret = g_open (templ, O_RDWR | O_BINARY | O_CREAT | O_EXCL, 0600); if (ret == -1) { if (errno != EEXIST) return -1; diff --git a/mono/utils/mono-threads-coop.c b/mono/utils/mono-threads-coop.c index 1b9849fe5a..ecacffc40d 100644 --- a/mono/utils/mono-threads-coop.c +++ b/mono/utils/mono-threads-coop.c @@ -426,7 +426,7 @@ mono_threads_assert_gc_unsafe_region (void) } gboolean -mono_threads_is_coop_enabled (void) +mono_threads_are_safepoints_enabled (void) { #if defined(USE_COOP_GC) return TRUE; @@ -455,7 +455,7 @@ mono_threads_is_blocking_transition_enabled (void) void mono_threads_coop_init (void) { - if (!mono_threads_is_coop_enabled () && !mono_threads_is_blocking_transition_enabled ()) + if (!mono_threads_are_safepoints_enabled () && !mono_threads_is_blocking_transition_enabled ()) return; mono_counters_register ("Coop Reset Blocking", MONO_COUNTER_GC | MONO_COUNTER_INT, &coop_reset_blocking_count); @@ -473,13 +473,13 @@ mono_threads_coop_init (void) void mono_threads_coop_begin_global_suspend (void) { - if (mono_threads_is_coop_enabled ()) + if (mono_threads_are_safepoints_enabled ()) mono_polling_required = 1; } void mono_threads_coop_end_global_suspend (void) { - if (mono_threads_is_coop_enabled ()) + if (mono_threads_are_safepoints_enabled ()) mono_polling_required = 0; } diff --git a/mono/utils/mono-threads-coop.h b/mono/utils/mono-threads-coop.h index 9937c78414..8e24a36106 100644 --- a/mono/utils/mono-threads-coop.h +++ b/mono/utils/mono-threads-coop.h @@ -26,7 +26,7 @@ extern volatile size_t mono_polling_required; /* Runtime consumable API */ gboolean -mono_threads_is_coop_enabled (void); +mono_threads_are_safepoints_enabled (void); gboolean mono_threads_is_blocking_transition_enabled (void); diff --git a/mono/utils/mono-threads-debug.h b/mono/utils/mono-threads-debug.h index c14acab00e..b983d1b6a1 100644 --- a/mono/utils/mono-threads-debug.h +++ b/mono/utils/mono-threads-debug.h @@ -9,7 +9,7 @@ #define MOSTLY_ASYNC_SAFE_PRINTF(...) do { \ char __buff[1024]; __buff [0] = '\0'; \ g_snprintf (__buff, sizeof (__buff), __VA_ARGS__); \ - write (1, __buff, (guint32)strlen (__buff)); \ + g_write (1, __buff, (guint32)strlen (__buff)); \ } while (0) #if 1 diff --git a/mono/utils/mono-threads-posix-signals.c b/mono/utils/mono-threads-posix-signals.c index b39277393f..c1e29c6856 100644 --- a/mono/utils/mono-threads-posix-signals.c +++ b/mono/utils/mono-threads-posix-signals.c @@ -68,6 +68,8 @@ abort_signal_get (void) { #if defined(HOST_ANDROID) return SIGTTIN; +#elif defined (__OpenBSD__) + return SIGUSR1; #elif defined (SIGRTMIN) static int abort_signum = -1; if (abort_signum == -1) diff --git a/mono/utils/mono-threads-posix.c b/mono/utils/mono-threads-posix.c index 6804024e15..d1cc9091bf 100644 --- a/mono/utils/mono-threads-posix.c +++ b/mono/utils/mono-threads-posix.c @@ -125,7 +125,7 @@ mono_threads_platform_exit (gsize exit_code) } int -mono_threads_get_max_stack_size (void) +ves_icall_System_Threading_Thread_SystemMaxStackSize (MonoError *error) { struct rlimit lim; @@ -161,7 +161,24 @@ mono_threads_pthread_kill (MonoThreadInfo *info, int signum) g_error ("pthread_kill () is not supported by this platform"); #endif - if (result && result != ESRCH) + /* + * ESRCH just means the thread is gone; this is usually not fatal. + * + * ENOTSUP can occur if we try to send signals (e.g. for sampling) to Grand + * Central Dispatch threads on Apple platforms. This is kinda bad, but + * since there's really nothing we can do about it, we just ignore it and + * move on. + * + * All other error codes are ill-documented and usually stem from various + * OS-specific idiosyncracies. We want to know about these, so fail loudly. + * One example is EAGAIN on Linux, which indicates a signal queue overflow. + */ + if (result && + result != ESRCH +#if defined (__MACH__) && defined (ENOTSUP) + && result != ENOTSUP +#endif + ) g_error ("%s: pthread_kill failed with error %d - potential kernel OOM or signal queue overflow", __func__, result); return result; diff --git a/mono/utils/mono-threads-wasm.c b/mono/utils/mono-threads-wasm.c index 040903b048..e0528f67ce 100644 --- a/mono/utils/mono-threads-wasm.c +++ b/mono/utils/mono-threads-wasm.c @@ -34,7 +34,7 @@ wasm_get_stack_size (void) int -mono_threads_get_max_stack_size (void) +ves_icall_System_Threading_Thread_SystemMaxStackSize (MonoError *error) { return wasm_get_stack_size (); } diff --git a/mono/utils/mono-threads-windows.c b/mono/utils/mono-threads-windows.c index 5a55af2057..d86300afb8 100644 --- a/mono/utils/mono-threads-windows.c +++ b/mono/utils/mono-threads-windows.c @@ -29,13 +29,12 @@ mono_threads_suspend_begin_async_suspend (MonoThreadInfo *info, gboolean interru HANDLE handle; DWORD result; - handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id); + handle = info->native_handle; g_assert (handle); result = SuspendThread (handle); THREADS_SUSPEND_DEBUG ("SUSPEND %p -> %d\n", (void*)id, ret); if (result == (DWORD)-1) { - CloseHandle (handle); return FALSE; } @@ -48,7 +47,6 @@ mono_threads_suspend_begin_async_suspend (MonoThreadInfo *info, gboolean interru CONTEXT context; context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL; if (!GetThreadContext (handle, &context)) { - CloseHandle (handle); return FALSE; } @@ -57,7 +55,6 @@ mono_threads_suspend_begin_async_suspend (MonoThreadInfo *info, gboolean interru mono_threads_add_to_pending_operation_set (info); result = ResumeThread (handle); g_assert (result == 1); - CloseHandle (handle); THREADS_SUSPEND_DEBUG ("FAILSAFE RESUME/1 %p -> %d\n", (void*)id, 0); //XXX interrupt_kernel doesn't make sense in this case as the target is not in a syscall return TRUE; @@ -71,7 +68,6 @@ mono_threads_suspend_begin_async_suspend (MonoThreadInfo *info, gboolean interru THREADS_SUSPEND_DEBUG ("FAILSAFE RESUME/2 %p -> %d\n", (void*)info->native_handle, 0); } - CloseHandle (handle); return TRUE; } @@ -86,15 +82,9 @@ mono_threads_suspend_check_suspend_result (MonoThreadInfo *info) void mono_threads_suspend_abort_syscall (MonoThreadInfo *info) { - DWORD id = mono_thread_info_get_tid (info); - HANDLE handle; - - handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id); - g_assert (handle); - - mono_win32_abort_wait (info, handle, id); - - CloseHandle (handle); + DWORD id = mono_thread_info_get_tid(info); + g_assert (info->native_handle); + mono_win32_abort_wait (info, info->native_handle, id); } gboolean @@ -104,9 +94,10 @@ mono_threads_suspend_begin_async_resume (MonoThreadInfo *info) HANDLE handle; DWORD result; - handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id); + handle = info->native_handle; g_assert (handle); - + +#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) if (info->async_target) { MonoContext ctx; CONTEXT context; @@ -119,7 +110,6 @@ mono_threads_suspend_begin_async_resume (MonoThreadInfo *info) context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL; if (!GetThreadContext (handle, &context)) { - CloseHandle (handle); return FALSE; } @@ -131,13 +121,14 @@ mono_threads_suspend_begin_async_resume (MonoThreadInfo *info) context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL; res = SetThreadContext (handle, &context); if (!res) { - CloseHandle (handle); return FALSE; } } +#else + g_error ("Not implemented due to lack of SetThreadContext"); +#endif result = ResumeThread (handle); - CloseHandle (handle); return result != (DWORD)-1; } @@ -146,11 +137,20 @@ mono_threads_suspend_begin_async_resume (MonoThreadInfo *info) void mono_threads_suspend_register (MonoThreadInfo *info) { + BOOL success; + HANDLE currentThreadHandle = NULL; + + success = DuplicateHandle (GetCurrentProcess (), GetCurrentThread (), GetCurrentProcess (), ¤tThreadHandle, 0, FALSE, DUPLICATE_SAME_ACCESS); + g_assertf (success, "Failed to duplicate current thread handle"); + + info->native_handle = currentThreadHandle; } void mono_threads_suspend_free (MonoThreadInfo *info) { + CloseHandle (info->native_handle); + info->native_handle = NULL; } void @@ -242,6 +242,12 @@ mono_native_thread_join_handle (HANDLE thread_handle, gboolean close_handle) return res != WAIT_FAILED; } +/* + * Can't OpenThread on UWP until SDK 15063 (our minspec today is 10240), + * but this function doesn't seem to be used on Windows anyway + */ +#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) + gboolean mono_native_thread_join (MonoNativeThreadId tid) { @@ -253,6 +259,8 @@ mono_native_thread_join (MonoNativeThreadId tid) return mono_native_thread_join_handle (handle, TRUE); } +#endif + #if HAVE_DECL___READFSDWORD==0 static MONO_ALWAYS_INLINE unsigned long long __readfsdword (unsigned long offset) @@ -269,7 +277,7 @@ void mono_threads_platform_get_stack_bounds (guint8 **staddr, size_t *stsize) { MEMORY_BASIC_INFORMATION meminfo; -#ifdef _WIN64 +#if defined(_WIN64) || defined(_M_ARM) /* win7 apis */ NT_TIB* tib = (NT_TIB*)NtCurrentTeb(); guint8 *stackTop = (guint8*)tib->StackBase; @@ -356,7 +364,7 @@ mono_threads_platform_exit (gsize exit_code) } int -mono_threads_get_max_stack_size (void) +ves_icall_System_Threading_Thread_SystemMaxStackSize (MonoError *error) { //FIXME return INT_MAX; diff --git a/mono/utils/mono-threads.c b/mono/utils/mono-threads.c index 2e58745174..ff5897c22e 100644 --- a/mono/utils/mono-threads.c +++ b/mono/utils/mono-threads.c @@ -117,7 +117,7 @@ mono_threads_notify_initiator_of_resume (MonoThreadInfo* info) static gboolean begin_async_suspend (MonoThreadInfo *info, gboolean interrupt_kernel) { - if (mono_threads_is_coop_enabled ()) { + if (mono_threads_are_safepoints_enabled ()) { /* There's nothing else to do after we async request the thread to suspend */ mono_threads_add_to_pending_operation_set (info); return TRUE; @@ -129,7 +129,7 @@ begin_async_suspend (MonoThreadInfo *info, gboolean interrupt_kernel) static gboolean check_async_suspend (MonoThreadInfo *info) { - if (mono_threads_is_coop_enabled ()) { + if (mono_threads_are_safepoints_enabled ()) { /* Async suspend can't async fail on coop */ return TRUE; } @@ -140,7 +140,7 @@ check_async_suspend (MonoThreadInfo *info) static void resume_async_suspended (MonoThreadInfo *info) { - if (mono_threads_is_coop_enabled ()) + if (mono_threads_are_safepoints_enabled ()) g_assert_not_reached (); g_assert (mono_threads_suspend_begin_async_resume (info)); @@ -217,7 +217,7 @@ dump_threads (void) MOSTLY_ASYNC_SAFE_PRINTF ("\t0x*07\t- blocking (GOOD)\n"); MOSTLY_ASYNC_SAFE_PRINTF ("\t0x?08\t- blocking with pending suspend (GOOD)\n"); - FOREACH_THREAD_SAFE (info) { + FOREACH_THREAD_SAFE_ALL (info) { #ifdef TARGET_MACH char thread_name [256] = { 0 }; pthread_getname_np (mono_thread_info_get_tid (info), thread_name, 255); @@ -597,37 +597,7 @@ mono_thread_info_list_head (void) return &thread_list; } -/** - * mono_threads_attach_tools_thread - * - * Attach the current thread as a tool thread. DON'T USE THIS FUNCTION WITHOUT READING ALL DISCLAIMERS. - * - * A tools thread is a very special kind of thread that needs access to core runtime facilities but should - * not be counted as a regular thread for high order facilities such as executing managed code or accessing - * the managed heap. - * - * This is intended only to tools such as a profiler than needs to be able to use our lock-free support when - * doing things like resolving backtraces in their background processing thread. - */ -void -mono_threads_attach_tools_thread (void) -{ - MonoThreadInfo *info; - - /* Must only be called once */ - g_assert (!mono_native_tls_get_value (thread_info_key)); - - while (!mono_threads_inited) { - mono_thread_info_usleep (10); - } - - info = mono_thread_info_attach (); - g_assert (info); - - info->tools_thread = TRUE; -} - -MonoThreadInfo* +MonoThreadInfo * mono_thread_info_attach (void) { MonoThreadInfo *info; @@ -741,6 +711,27 @@ thread_info_key_dtor (void *arg) } #endif +MonoThreadInfoFlags +mono_thread_info_get_flags (MonoThreadInfo *info) +{ + return mono_atomic_load_i32 (&info->flags); +} + +void +mono_thread_info_set_flags (MonoThreadInfoFlags flags) +{ + MonoThreadInfo *info = mono_thread_info_current (); + MonoThreadInfoFlags old = mono_atomic_load_i32 (&info->flags); + + if (threads_callbacks.thread_flags_changing) + threads_callbacks.thread_flags_changing (old, flags); + + mono_atomic_store_i32 (&info->flags, flags); + + if (threads_callbacks.thread_flags_changed) + threads_callbacks.thread_flags_changed (old, flags); +} + void mono_thread_info_init (size_t info_size) { @@ -783,10 +774,6 @@ mono_thread_info_init (size_t info_size) mono_threads_coop_init (); mono_threads_platform_init (); -#if defined(__MACH__) - mono_mach_init (thread_info_key); -#endif - mono_threads_inited = TRUE; g_assert (sizeof (MonoNativeThreadId) <= sizeof (uintptr_t)); @@ -1045,7 +1032,7 @@ mono_thread_info_safe_suspend_and_run (MonoNativeThreadId id, gboolean interrupt mono_threads_wait_pending_operations (); break; case KeepSuspended: - g_assert (!mono_threads_is_coop_enabled ()); + g_assert (!mono_threads_are_safepoints_enabled ()); break; default: g_error ("Invalid suspend_and_run callback return value %d", result); @@ -1067,7 +1054,7 @@ currently used only to deliver exceptions. void mono_thread_info_setup_async_call (MonoThreadInfo *info, void (*target_func)(void*), void *user_data) { - if (!mono_threads_is_coop_enabled ()) { + if (!mono_threads_are_safepoints_enabled ()) { /* In non-coop mode, an async call can only be setup on an async suspended thread, but in coop mode, a thread * may be in blocking state, and will execute the async call when leaving the safepoint, leaving a gc safe * region or entering a gc unsafe region */ diff --git a/mono/utils/mono-threads.h b/mono/utils/mono-threads.h index ade9380d51..d3b3223c44 100644 --- a/mono/utils/mono-threads.h +++ b/mono/utils/mono-threads.h @@ -148,18 +148,43 @@ enum { typedef struct _MonoThreadInfoInterruptToken MonoThreadInfoInterruptToken; +/* + * These flags control how the rest of the runtime will see and interact with + * a thread. + */ +typedef enum { + /* + * No flags means it's a normal thread that takes part in all runtime + * functionality. + */ + MONO_THREAD_INFO_FLAGS_NONE = 0, + /* + * The thread will not be suspended by the STW machinery. The thread is not + * allowed to allocate or access managed memory at all, nor execute managed + * code. + */ + MONO_THREAD_INFO_FLAGS_NO_GC = 1, + /* + * The thread will not be subject to profiler sampling signals. + */ + MONO_THREAD_INFO_FLAGS_NO_SAMPLE = 2, +} MonoThreadInfoFlags; + typedef struct { MonoLinkedListSetNode node; guint32 small_id; /*Used by hazard pointers */ - MonoNativeThreadHandle native_handle; /* Valid on mach and android */ + MonoNativeThreadHandle native_handle; /* Valid on mach, android and Windows */ int thread_state; + /* + * Must not be changed directly, and especially not by other threads. Use + * mono_thread_info_get/set_flags () to manipulate this. + */ + volatile gint32 flags; + /*Tells if this thread was created by the runtime or not.*/ gboolean runtime_thread; - /* Tells if this thread should be ignored or not by runtime services such as GC and profiling */ - gboolean tools_thread; - /* Max stack bounds, all valid addresses must be between [stack_start_limit, stack_end[ */ void *stack_start_limit, *stack_end; @@ -255,6 +280,10 @@ typedef struct { void (*thread_detach_with_lock)(THREAD_INFO_TYPE *info); gboolean (*ip_in_critical_region) (MonoDomain *domain, gpointer ip); gboolean (*thread_in_critical_region) (THREAD_INFO_TYPE *info); + + // Called on the affected thread. + void (*thread_flags_changing) (MonoThreadInfoFlags old, MonoThreadInfoFlags new_); + void (*thread_flags_changed) (MonoThreadInfoFlags old, MonoThreadInfoFlags new_); } MonoThreadInfoCallbacks; typedef struct { @@ -272,26 +301,41 @@ typedef enum { typedef SuspendThreadResult (*MonoSuspendThreadCallback) (THREAD_INFO_TYPE *info, gpointer user_data); -static inline gboolean -mono_threads_filter_tools_threads (THREAD_INFO_TYPE *info) -{ - return !((MonoThreadInfo*)info)->tools_thread; -} +MONO_API MonoThreadInfoFlags +mono_thread_info_get_flags (THREAD_INFO_TYPE *info); /* -Requires the world to be stoped -*/ -#define FOREACH_THREAD(thread) \ - MONO_LLS_FOREACH_FILTERED (mono_thread_info_list_head (), THREAD_INFO_TYPE, thread, mono_threads_filter_tools_threads) + * Sets the thread info flags for the current thread. This function may invoke + * callbacks containing arbitrary code (e.g. locks) so it must be assumed to be + * async unsafe. + */ +MONO_API void +mono_thread_info_set_flags (MonoThreadInfoFlags flags); + +static inline gboolean +mono_threads_filter_exclude_flags (THREAD_INFO_TYPE *info, MonoThreadInfoFlags flags) +{ + return !(mono_thread_info_get_flags (info) & flags); +} + +/* Normal iteration; requires the world to be stopped. */ + +#define FOREACH_THREAD_ALL(thread) \ + MONO_LLS_FOREACH_FILTERED (mono_thread_info_list_head (), THREAD_INFO_TYPE, thread, mono_lls_filter_accept_all, NULL) + +#define FOREACH_THREAD_EXCLUDE(thread, not_flags) \ + MONO_LLS_FOREACH_FILTERED (mono_thread_info_list_head (), THREAD_INFO_TYPE, thread, mono_threads_filter_exclude_flags, not_flags) #define FOREACH_THREAD_END \ MONO_LLS_FOREACH_END -/* -Snapshot iteration. -*/ -#define FOREACH_THREAD_SAFE(thread) \ - MONO_LLS_FOREACH_FILTERED_SAFE (mono_thread_info_list_head (), THREAD_INFO_TYPE, thread, mono_threads_filter_tools_threads) +/* Snapshot iteration; can be done anytime but is slower. */ + +#define FOREACH_THREAD_SAFE_ALL(thread) \ + MONO_LLS_FOREACH_FILTERED_SAFE (mono_thread_info_list_head (), THREAD_INFO_TYPE, thread, mono_lls_filter_accept_all, NULL) + +#define FOREACH_THREAD_SAFE_EXCLUDE(thread, not_flags) \ + MONO_LLS_FOREACH_FILTERED_SAFE (mono_thread_info_list_head (), THREAD_INFO_TYPE, thread, mono_threads_filter_exclude_flags, not_flags) #define FOREACH_THREAD_SAFE_END \ MONO_LLS_FOREACH_SAFE_END @@ -436,7 +480,7 @@ gboolean mono_thread_info_is_live (THREAD_INFO_TYPE *info); int -mono_threads_get_max_stack_size (void); +ves_icall_System_Threading_Thread_SystemMaxStackSize (MonoError *error); MonoThreadHandle* mono_threads_open_thread_handle (MonoThreadHandle *handle); @@ -444,10 +488,6 @@ mono_threads_open_thread_handle (MonoThreadHandle *handle); void mono_threads_close_thread_handle (MonoThreadHandle *handle); -MONO_API void -mono_threads_attach_tools_thread (void); - - #if !defined(HOST_WIN32) /*Use this instead of pthread_kill */ diff --git a/mono/utils/mono-time.c b/mono/utils/mono-time.c index a3c6151a08..6866a94e89 100644 --- a/mono/utils/mono-time.c +++ b/mono/utils/mono-time.c @@ -151,7 +151,7 @@ mono_msec_boottime (void) gint64 retval = 0; /* clock_gettime () is found by configure on Apple builds, but its only present from ios 10, macos 10.12, tvos 10 and watchos 3 */ -#if (defined(HAVE_CLOCK_MONOTONIC_COARSE) || defined(HAVE_CLOCK_MONOTONIC)) && !(defined(TARGET_IOS) || defined(TARGET_OSX) || defined(TARGET_WATCHOS) || defined(TARGET_TVOS)) +#if !defined (TARGET_WASM) && ((defined(HAVE_CLOCK_MONOTONIC_COARSE) || defined(HAVE_CLOCK_MONOTONIC)) && !(defined(TARGET_IOS) || defined(TARGET_OSX) || defined(TARGET_WATCHOS) || defined(TARGET_TVOS))) clockid_t clockType = #if HAVE_CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC_COARSE; /* good enough resolution, fastest speed */ @@ -219,7 +219,8 @@ mono_100ns_ticks (void) timebase.denom *= 100; /* we return 100ns ticks */ } return now * timebase.numer / timebase.denom; -#elif defined(CLOCK_MONOTONIC) +#elif defined(CLOCK_MONOTONIC) && !defined(__PASE__) + /* !__PASE__ is defined because i 7.1 doesn't have clock_getres */ struct timespec tspec; static struct timespec tspec_freq = {0}; static int can_use_clock = 0; diff --git a/mono/utils/mono-tls.h b/mono/utils/mono-tls.h index b87ede880b..a7950d8f5b 100644 --- a/mono/utils/mono-tls.h +++ b/mono/utils/mono-tls.h @@ -36,6 +36,19 @@ typedef enum { #include +/* +* These APIs were added back in Windows SDK 14393. Let's redirect them to +* Fls* APIs on older SDKs just like Windows 8.1 headers do +*/ +#if G_HAVE_API_SUPPORT(HAVE_UWP_WINAPI_SUPPORT) +#if WINDOWS_SDK_BUILD_VERSION < 14393 +#define TlsAlloc() FlsAlloc(NULL) +#define TlsGetValue FlsGetValue +#define TlsSetValue FlsSetValue +#define TlsFree FlsFree +#endif +#endif + #define MonoNativeTlsKey DWORD #define mono_native_tls_alloc(key,destructor) ((*(key) = TlsAlloc ()) != TLS_OUT_OF_INDEXES && destructor == NULL) #define mono_native_tls_free TlsFree diff --git a/mono/utils/mono-utils-debug.c b/mono/utils/mono-utils-debug.c new file mode 100644 index 0000000000..acc4115c4b --- /dev/null +++ b/mono/utils/mono-utils-debug.c @@ -0,0 +1,114 @@ +/* mono-utils-debug.c + * + * Copyright 2018 Microsoft + * Licensed under the MIT license. See LICENSE file in the project root for full license information. +*/ + +#include +#include +#include "mono-utils-debug.h" + +#if defined (_WIN32) + +#include + +gboolean +mono_is_usermode_native_debugger_present (void) +{ + // This is just a few instructions and no syscall. It is very fast. + // Kernel debugger is detected otherwise and is also useful for usermode debugging. + // Mono managed debugger is detected otherwise. + return IsDebuggerPresent () ? TRUE : FALSE; +} + +#else + +#include +#include +#include +#if defined (__APPLE__) +#include +#endif +#if defined (__NetBSD__) +#include +#endif + +static gboolean +mono_is_usermode_native_debugger_present_slow (void) +// PAL_IsDebuggerPresent +// based closely on with some local cleanup: +// https://github.com/dotnet/coreclr/blob/master/src/pal/src/init/pal.cpp +// https://raw.githubusercontent.com/dotnet/coreclr/f1c9dac3e2db2397e01cd2da3e8aaa4f81a80013/src/pal/src/init/pal.cpp +{ +#if defined (__APPLE__) + + struct kinfo_proc info; + size_t size = sizeof (info); + memset (&info, 0, size); + int mib [4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid () }; + return sysctl (mib, sizeof (mib) / sizeof (*mib), &info, &size, NULL, 0) == 0 + && (info.kp_proc.p_flag & P_TRACED) != 0; + +#elif defined (__linux__) + + int const status_fd = open ("/proc/self/status", O_RDONLY); + if (status_fd == -1) + return FALSE; + + char buf [4098]; + buf [0] = '\n'; // consider if the first line + buf [1] = 0; // clear out garbage + ssize_t const num_read = read (status_fd, &buf [1], sizeof(buf) - 2); + close (status_fd); + static const char TracerPid [ ] = "\nTracerPid:"; + if (num_read <= sizeof (TracerPid)) + return FALSE; + + buf [num_read + 1] = 0; + char const * const tracer_pid = strstr (buf, TracerPid); + return tracer_pid && atoi (tracer_pid + sizeof (TracerPid) - 1); + +#elif defined (__NetBSD__) + + kvm_t * const kd = kvm_open (NULL, NULL, NULL, KVM_NO_FILES, "kvm_open"); + if (!kd) + return FALSE; + int count = 0; + struct kinfo_proc const * const info = kvm_getprocs (kd, KERN_PROC_PID, getpid (), &count); + gboolean const traced = info && count > 0 && (info->kp_proc.p_slflag & PSL_TRACED); + kvm_close (kd); + return traced; + +#else + return FALSE; // FIXME Other operating systems. +#endif +} + +// Cache because it is slow. +static gchar mono_is_usermode_native_debugger_present_cache; // 0:uninitialized 1:true 2:false + +gboolean +mono_is_usermode_native_debugger_present (void) +{ + if (mono_is_usermode_native_debugger_present_cache == 0) { + int er = errno; + mono_is_usermode_native_debugger_present_cache = mono_is_usermode_native_debugger_present_slow () ? 1 : 2; + errno = er; + } + return mono_is_usermode_native_debugger_present_cache == 1; +} + +#endif // fast uncached Window vs. slow cached the rest + +#if 0 // test + +int +#ifdef _MSC_VER +__cdecl +#endif +main () +{ + printf ("mono_usermode_native_debugger_present:%d\n", mono_is_usermode_native_debugger_present ()); +} + +#endif diff --git a/mono/utils/mono-utils-debug.h b/mono/utils/mono-utils-debug.h new file mode 100644 index 0000000000..5466e90277 --- /dev/null +++ b/mono/utils/mono-utils-debug.h @@ -0,0 +1,12 @@ +/* mono-utils-debug.h + * + * Copyright 2018 Microsoft + * Licensed under the MIT license. See LICENSE file in the project root for full license information. +*/ + +G_BEGIN_DECLS + +gboolean +mono_is_usermode_native_debugger_present (void); + +G_END_DECLS diff --git a/mono/utils/networking-posix.c b/mono/utils/networking-posix.c index 95e3d7df58..7ccf6bf66e 100644 --- a/mono/utils/networking-posix.c +++ b/mono/utils/networking-posix.c @@ -39,8 +39,10 @@ get_address_from_sockaddr (struct sockaddr *sa) switch (sa->sa_family) { case AF_INET: return &((struct sockaddr_in*)sa)->sin_addr; +#ifdef HAVE_STRUCT_SOCKADDR_IN6 case AF_INET6: return &((struct sockaddr_in6*)sa)->sin6_addr; +#endif } return NULL; } @@ -95,9 +97,11 @@ mono_get_address_info (const char *hostname, int port, int flags, MonoAddressInf if (cur->family == PF_INET) { cur->address_len = sizeof (struct in_addr); cur->address.v4 = ((struct sockaddr_in*)res->ai_addr)->sin_addr; +#ifdef HAVE_STRUCT_SOCKADDR_IN6 } else if (cur->family == PF_INET6) { cur->address_len = sizeof (struct in6_addr); cur->address.v6 = ((struct sockaddr_in6*)res->ai_addr)->sin6_addr; +#endif } else { g_warning ("Cannot handle address family %d", cur->family); res = res->ai_next; diff --git a/mono/utils/networking.c b/mono/utils/networking.c index 104f3e5fa8..6f643dfd69 100644 --- a/mono/utils/networking.c +++ b/mono/utils/networking.c @@ -17,8 +17,10 @@ mono_address_size_for_family (int family) switch (family) { case AF_INET: return sizeof (struct in_addr); +#ifdef HAVE_STRUCT_SOCKADDR_IN6 case AF_INET6: return sizeof (struct in6_addr); +#endif } return 0; } @@ -53,6 +55,7 @@ mono_socket_address_init (MonoSocketAddress *sa, socklen_t *len, int family, con #if HAVE_SOCKADDR_IN_SIN_LEN sa->v4.sin_len = sizeof (*len); #endif +#ifdef HAVE_STRUCT_SOCKADDR_IN6 } else if (family == AF_INET6) { *len = sizeof (struct sockaddr_in6); @@ -61,6 +64,7 @@ mono_socket_address_init (MonoSocketAddress *sa, socklen_t *len, int family, con sa->v6.sin6_port = htons (port); #if HAVE_SOCKADDR_IN6_SIN_LEN sa->v6.sin6_len = sizeof (*len); +#endif #endif } else { g_error ("Cannot handle address family %d", family); diff --git a/mono/utils/networking.h b/mono/utils/networking.h index f9c5f63dbc..357c299339 100644 --- a/mono/utils/networking.h +++ b/mono/utils/networking.h @@ -54,7 +54,9 @@ struct _MonoAddressEntry { int address_len; union { struct in_addr v4; +#ifdef HAVE_STRUCT_SOCKADDR_IN6 struct in6_addr v6; +#endif } address; const char *canonical_name; MonoAddressEntry *next; @@ -67,7 +69,9 @@ typedef struct { typedef union { struct sockaddr_in v4; +#ifdef HAVE_STRUCT_SOCKADDR_IN6 struct sockaddr_in6 v6; +#endif struct sockaddr addr; } MonoSocketAddress; @@ -75,7 +79,9 @@ typedef struct { int family; union { struct in_addr v4; +#ifdef HAVE_STRUCT_SOCKADDR_IN6 struct in6_addr v6; +#endif } addr; } MonoAddress; diff --git a/mono/utils/os-event.h b/mono/utils/os-event.h index 9ab5524f0a..16a421aa62 100644 --- a/mono/utils/os-event.h +++ b/mono/utils/os-event.h @@ -8,6 +8,7 @@ #include #include +#include #include "mono-os-mutex.h" #ifndef MONO_INFINITE_WAIT @@ -35,22 +36,22 @@ struct _MonoOSEvent { #endif }; -void +MONO_API void mono_os_event_init (MonoOSEvent *event, gboolean initial); -void +MONO_API void mono_os_event_destroy (MonoOSEvent *event); -void +MONO_API void mono_os_event_set (MonoOSEvent *event); -void +MONO_API void mono_os_event_reset (MonoOSEvent *event); -MonoOSEventWaitRet +MONO_API MonoOSEventWaitRet mono_os_event_wait_one (MonoOSEvent *event, guint32 timeout, gboolean alertable); -MonoOSEventWaitRet +MONO_API MonoOSEventWaitRet mono_os_event_wait_multiple (MonoOSEvent **events, gsize nevents, gboolean waitall, guint32 timeout, gboolean alertable); #endif /* _MONO_UTILS_OS_EVENT_H_ */ diff --git a/mono/utils/w32api.h b/mono/utils/w32api.h index 1d582fb945..45544c78fc 100644 --- a/mono/utils/w32api.h +++ b/mono/utils/w32api.h @@ -51,7 +51,7 @@ typedef struct pollfd { } WSAPOLLFD, *PWSAPOLLFD, *LPWSAPOLLFD; #endif -#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) +#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) #include #endif diff --git a/msvc/Makefile.in b/msvc/Makefile.in index adc5f22bfd..29186a5b3e 100644 --- a/msvc/Makefile.in +++ b/msvc/Makefile.in @@ -83,8 +83,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs README ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -193,6 +191,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -211,7 +210,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -225,7 +223,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -339,7 +336,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ diff --git a/msvc/monograph.vcxproj b/msvc/monograph.vcxproj index 022665893f..29ca2e961b 100644 --- a/msvc/monograph.vcxproj +++ b/msvc/monograph.vcxproj @@ -1,4 +1,4 @@ - + @@ -105,7 +105,7 @@ false - $(MONO_LIBMONO_LIB);%(AdditionalDependencies) + $(MONO_STATIC_LIBMONO_LIB);%(AdditionalDependencies) %(AdditionalLibraryDirectories) Console @@ -130,7 +130,7 @@ Console - $(MONO_LIBMONO_LIB);%(AdditionalDependencies) + $(MONO_STATIC_LIBMONO_LIB);%(AdditionalDependencies) @@ -151,7 +151,7 @@ false - $(MONO_LIBMONO_LIB);%(AdditionalDependencies) + $(MONO_STATIC_LIBMONO_LIB);%(AdditionalDependencies) %(AdditionalLibraryDirectories) Console @@ -175,7 +175,7 @@ %(AdditionalLibraryDirectories) Console - $(MONO_LIBMONO_LIB);%(AdditionalDependencies) + $(MONO_STATIC_LIBMONO_LIB);%(AdditionalDependencies) @@ -183,14 +183,11 @@ - - {158073ed-99ae-4196-9edc-ddb2344f8466} - - - {675f4175-ffb1-480d-ad36-f397578844d4} + + {cb0d9e92-293c-439c-9ac7-c5f59b6e0772} - \ No newline at end of file + diff --git a/po/Makefile.in b/po/Makefile.in index 7abd322749..cc0b96e6e5 100644 --- a/po/Makefile.in +++ b/po/Makefile.in @@ -83,8 +83,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -253,6 +251,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -271,7 +270,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -285,7 +283,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -399,7 +396,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ diff --git a/po/mcs/de.gmo b/po/mcs/de.gmo index f5037c57b9..f77d7a81a3 100644 Binary files a/po/mcs/de.gmo and b/po/mcs/de.gmo differ diff --git a/po/mcs/de.po.REMOVED.git-id b/po/mcs/de.po.REMOVED.git-id index 67a77adb21..21fc37a865 100644 --- a/po/mcs/de.po.REMOVED.git-id +++ b/po/mcs/de.po.REMOVED.git-id @@ -1 +1 @@ -5cfca2be02cef78e925d1f7d284af1dffde28c84 \ No newline at end of file +1feb31f7be151e30f54404ea43f8cb670125e6f1 \ No newline at end of file diff --git a/po/mcs/es.gmo b/po/mcs/es.gmo index b0237c1de7..5c2e8d12c8 100644 Binary files a/po/mcs/es.gmo and b/po/mcs/es.gmo differ diff --git a/po/mcs/es.po.REMOVED.git-id b/po/mcs/es.po.REMOVED.git-id index 19a64e4ba1..99d25bdabf 100644 --- a/po/mcs/es.po.REMOVED.git-id +++ b/po/mcs/es.po.REMOVED.git-id @@ -1 +1 @@ -fdcafc9a2566dfed6da64051eef4e8b7dc351dd4 \ No newline at end of file +a3efed81e06c4045f08edc76a1b5b7af275e32df \ No newline at end of file diff --git a/po/mcs/ja.gmo b/po/mcs/ja.gmo index 7977c5886f..cb709131dc 100644 Binary files a/po/mcs/ja.gmo and b/po/mcs/ja.gmo differ diff --git a/po/mcs/ja.po.REMOVED.git-id b/po/mcs/ja.po.REMOVED.git-id index 4c15382787..353f7047b0 100644 --- a/po/mcs/ja.po.REMOVED.git-id +++ b/po/mcs/ja.po.REMOVED.git-id @@ -1 +1 @@ -8d51085657f341ea331c7c5e1e4815b1b32a6167 \ No newline at end of file +a5eb1ed04234970cdf14f5187748ec38dcd94c13 \ No newline at end of file diff --git a/po/mcs/mcs.pot b/po/mcs/mcs.pot index 9b4ff72424..951371a5f0 100644 --- a/po/mcs/mcs.pot +++ b/po/mcs/mcs.pot @@ -6,9 +6,9 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: mono 5.12.0.234\n" +"Project-Id-Version: mono 5.14.0.78\n" "Report-Msgid-Bugs-To: http://www.mono-project.com/Bugs\n" -"POT-Creation-Date: 2018-05-09 08:18+0000\n" +"POT-Creation-Date: 2018-05-10 08:12+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -482,146 +482,146 @@ msgstr "" msgid "`{0}' is obsolete: `{1}'" msgstr "" -#: mcs/mcs/cs-tokenizer.cs:845 +#: mcs/mcs/cs-tokenizer.cs:844 msgid "" "The `partial' modifier can be used only immediately before `class', " "`struct', `interface', or `void' keyword" msgstr "" -#: mcs/mcs/cs-tokenizer.cs:2131 +#: mcs/mcs/cs-tokenizer.cs:2136 #, csharp-format msgid "Unrecognized escape sequence `\\{0}'" msgstr "" -#: mcs/mcs/cs-tokenizer.cs:2150 +#: mcs/mcs/cs-tokenizer.cs:2155 msgid "Unrecognized escape sequence" msgstr "" -#: mcs/mcs/cs-tokenizer.cs:2415 +#: mcs/mcs/cs-tokenizer.cs:2420 msgid "Filename, single-line comment or end-of-line expected" msgstr "" -#: mcs/mcs/cs-tokenizer.cs:2463 +#: mcs/mcs/cs-tokenizer.cs:2468 msgid "Missing identifier to pre-processor directive" msgstr "" -#: mcs/mcs/cs-tokenizer.cs:2473 mcs/mcs/cs-tokenizer.cs:2477 +#: mcs/mcs/cs-tokenizer.cs:2478 mcs/mcs/cs-tokenizer.cs:2482 #, csharp-format msgid "Identifier expected: {0}" msgstr "" -#: mcs/mcs/cs-tokenizer.cs:3077 +#: mcs/mcs/cs-tokenizer.cs:3082 msgid "Integral constant is too large" msgstr "" -#: mcs/mcs/cs-tokenizer.cs:3082 +#: mcs/mcs/cs-tokenizer.cs:3087 msgid "Invalid number" msgstr "" -#: mcs/mcs/cs-tokenizer.cs:3087 +#: mcs/mcs/cs-tokenizer.cs:3092 msgid "Invalid preprocessor directive" msgstr "" -#: mcs/mcs/cs-tokenizer.cs:3094 +#: mcs/mcs/cs-tokenizer.cs:3099 #, csharp-format msgid "Unexpected processor directive ({0})" msgstr "" -#: mcs/mcs/cs-tokenizer.cs:3100 +#: mcs/mcs/cs-tokenizer.cs:3105 msgid "" "Cannot define or undefine preprocessor symbols after first token in file" msgstr "" -#: mcs/mcs/cs-tokenizer.cs:3106 +#: mcs/mcs/cs-tokenizer.cs:3111 msgid "" "Preprocessor directives must appear as the first non-whitespace character on " "a line" msgstr "" -#: mcs/mcs/cs-tokenizer.cs:3111 +#: mcs/mcs/cs-tokenizer.cs:3116 msgid "Single-line comment or end-of-line expected" msgstr "" -#: mcs/mcs/cs-tokenizer.cs:3156 mcs/mcs/cs-tokenizer.cs:4394 +#: mcs/mcs/cs-tokenizer.cs:3161 mcs/mcs/cs-tokenizer.cs:4399 msgid "Expected `#endif' directive" msgstr "" -#: mcs/mcs/cs-tokenizer.cs:3189 mcs/mcs/cs-tokenizer.cs:3210 -#: mcs/mcs/cs-tokenizer.cs:3241 mcs/mcs/cs-tokenizer.cs:4392 +#: mcs/mcs/cs-tokenizer.cs:3194 mcs/mcs/cs-tokenizer.cs:3215 +#: mcs/mcs/cs-tokenizer.cs:3246 mcs/mcs/cs-tokenizer.cs:4397 msgid "#endregion directive expected" msgstr "" -#: mcs/mcs/cs-tokenizer.cs:3290 +#: mcs/mcs/cs-tokenizer.cs:3295 msgid "Wrong preprocessor directive" msgstr "" -#: mcs/mcs/cs-tokenizer.cs:3302 +#: mcs/mcs/cs-tokenizer.cs:3307 #, csharp-format msgid "#error: '{0}'" msgstr "" -#: mcs/mcs/cs-tokenizer.cs:3320 +#: mcs/mcs/cs-tokenizer.cs:3325 msgid "The line number specified for #line directive is missing or invalid" msgstr "" -#: mcs/mcs/cs-tokenizer.cs:3374 mcs/mcs/cs-tokenizer.cs:4094 +#: mcs/mcs/cs-tokenizer.cs:3379 mcs/mcs/cs-tokenizer.cs:4099 msgid "Newline in constant" msgstr "" -#: mcs/mcs/cs-tokenizer.cs:3401 +#: mcs/mcs/cs-tokenizer.cs:3406 msgid "Unterminated string literal" msgstr "" -#: mcs/mcs/cs-tokenizer.cs:3445 mcs/mcs/cs-tokenizer.cs:3476 +#: mcs/mcs/cs-tokenizer.cs:3450 mcs/mcs/cs-tokenizer.cs:3481 #, csharp-format msgid "Unexpected character `\\{0}'" msgstr "" -#: mcs/mcs/cs-tokenizer.cs:3492 +#: mcs/mcs/cs-tokenizer.cs:3497 msgid "Identifier too long (limit is 512 chars)" msgstr "" -#: mcs/mcs/cs-tokenizer.cs:3839 +#: mcs/mcs/cs-tokenizer.cs:3844 msgid "A single-line comment may not be used in an interpolated string" msgstr "" -#: mcs/mcs/cs-tokenizer.cs:3909 +#: mcs/mcs/cs-tokenizer.cs:3914 msgid "End-of-file found, '*/' expected" msgstr "" -#: mcs/mcs/cs-tokenizer.cs:4006 +#: mcs/mcs/cs-tokenizer.cs:4011 msgid "Missing close delimiter `}' for interpolated expression" msgstr "" -#: mcs/mcs/cs-tokenizer.cs:4027 +#: mcs/mcs/cs-tokenizer.cs:4032 msgid "Keyword, identifier, or string expected after verbatim specifier: @" msgstr "" -#: mcs/mcs/cs-tokenizer.cs:4064 +#: mcs/mcs/cs-tokenizer.cs:4069 #, csharp-format msgid "Unexpected character `{0}'" msgstr "" -#: mcs/mcs/cs-tokenizer.cs:4089 +#: mcs/mcs/cs-tokenizer.cs:4094 msgid "Empty character literal" msgstr "" -#: mcs/mcs/cs-tokenizer.cs:4110 +#: mcs/mcs/cs-tokenizer.cs:4115 msgid "Too many characters in character literal" msgstr "" -#: mcs/mcs/cs-tokenizer.cs:4220 mcs/mcs/cs-tokenizer.cs:4283 +#: mcs/mcs/cs-tokenizer.cs:4225 mcs/mcs/cs-tokenizer.cs:4288 #, csharp-format msgid "" "A `{0}' character may only be escaped by doubling `{0}{0}' in an " "interpolated string" msgstr "" -#: mcs/mcs/cs-tokenizer.cs:4261 +#: mcs/mcs/cs-tokenizer.cs:4266 msgid "Empty interpolated expression format specifier" msgstr "" -#: mcs/mcs/cs-tokenizer.cs:4263 +#: mcs/mcs/cs-tokenizer.cs:4268 msgid "" "A interpolated expression format specifier may not contain trailing " "whitespace" @@ -3727,7 +3727,7 @@ msgstr "" msgid "A goto case is only valid inside a switch statement" msgstr "" -#: mcs/mcs/statement.cs:1813 mcs/mcs/statement.cs:7008 +#: mcs/mcs/statement.cs:1813 mcs/mcs/statement.cs:7016 msgid "The type caught or thrown must be derived from System.Exception" msgstr "" @@ -3865,50 +3865,50 @@ msgstr "" msgid "`{0}' is not a reference type as required by the lock statement" msgstr "" -#: mcs/mcs/statement.cs:6597 +#: mcs/mcs/statement.cs:6605 msgid "The type of locals declared in a fixed statement must be a pointer type" msgstr "" -#: mcs/mcs/statement.cs:6677 +#: mcs/mcs/statement.cs:6685 msgid "" "The right hand side of a fixed statement assignment may not be a cast " "expression" msgstr "" -#: mcs/mcs/statement.cs:6682 +#: mcs/mcs/statement.cs:6690 msgid "" "You cannot use the fixed statement to take the address of an already fixed " "expression" msgstr "" -#: mcs/mcs/statement.cs:6868 +#: mcs/mcs/statement.cs:6876 msgid "" "The `await' operator cannot be used in the filter expression of a catch " "clause" msgstr "" -#: mcs/mcs/statement.cs:7483 +#: mcs/mcs/statement.cs:7491 #, csharp-format msgid "" "A previous catch clause already catches all exceptions of this or a super " "type `{0}'" msgstr "" -#: mcs/mcs/statement.cs:7720 +#: mcs/mcs/statement.cs:7728 #, csharp-format msgid "" "`{0}': type used in a using statement must be implicitly convertible to " "`System.IDisposable'" msgstr "" -#: mcs/mcs/statement.cs:8136 +#: mcs/mcs/statement.cs:8144 #, csharp-format msgid "" "foreach statement requires that the return type `{0}' of `{1}' must have a " "suitable public MoveNext method and public Current property" msgstr "" -#: mcs/mcs/statement.cs:8180 +#: mcs/mcs/statement.cs:8188 #, csharp-format msgid "" "foreach statement cannot operate on variables of type `{0}' because it " @@ -3916,22 +3916,22 @@ msgid "" "implementation" msgstr "" -#: mcs/mcs/statement.cs:8201 +#: mcs/mcs/statement.cs:8209 msgid "Use of default literal is not valid in this context" msgstr "" -#: mcs/mcs/statement.cs:8204 +#: mcs/mcs/statement.cs:8212 #, csharp-format msgid "" "foreach statement cannot operate on variables of type `{0}' because it does " "not contain a definition for `{1}' or is inaccessible" msgstr "" -#: mcs/mcs/statement.cs:8442 +#: mcs/mcs/statement.cs:8450 msgid "Use of null is not valid in this context" msgstr "" -#: mcs/mcs/statement.cs:8454 +#: mcs/mcs/statement.cs:8462 #, csharp-format msgid "Foreach statement cannot operate on a `{0}'" msgstr "" diff --git a/po/mcs/pt_BR.gmo b/po/mcs/pt_BR.gmo index ba1ff5ee55..4849066b6d 100644 Binary files a/po/mcs/pt_BR.gmo and b/po/mcs/pt_BR.gmo differ diff --git a/po/mcs/pt_BR.po.REMOVED.git-id b/po/mcs/pt_BR.po.REMOVED.git-id index ca02ad010d..8dca32ed05 100644 --- a/po/mcs/pt_BR.po.REMOVED.git-id +++ b/po/mcs/pt_BR.po.REMOVED.git-id @@ -1 +1 @@ -bb5de2c19e14e3962de0b173b6195c64eb9783bb \ No newline at end of file +cf44471948c1623f4f40e3443ef244a0001b69c0 \ No newline at end of file diff --git a/runtime/Makefile.in b/runtime/Makefile.in index da376b97da..e2bb1bc1d9 100644 --- a/runtime/Makefile.in +++ b/runtime/Makefile.in @@ -106,8 +106,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(srcdir)/monodis-wrapper.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -217,6 +215,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -235,7 +234,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -249,7 +247,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -363,7 +360,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ diff --git a/samples/Makefile.in b/samples/Makefile.in index 2bd28b129e..e6813c25bf 100644 --- a/samples/Makefile.in +++ b/samples/Makefile.in @@ -83,8 +83,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -193,6 +191,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -211,7 +210,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -225,7 +223,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -339,7 +336,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ diff --git a/scripts/Makefile.in b/scripts/Makefile.in index a790c78d7f..71eb89e512 100644 --- a/scripts/Makefile.in +++ b/scripts/Makefile.in @@ -86,8 +86,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(srcdir)/mono-find-requires.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -225,6 +223,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -243,7 +242,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -257,7 +255,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -371,7 +368,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ diff --git a/scripts/update_submodules.sh b/scripts/update_submodules.sh index 83ec6d392a..bd5d7fc487 100755 --- a/scripts/update_submodules.sh +++ b/scripts/update_submodules.sh @@ -1,7 +1,7 @@ #!/bin/sh SUBMODULE_ERROR='Could not recursively update all git submodules. You may experience compilation problems if some submodules are out of date' SUBMODULE_OK='Git submodules updated successfully' -if test -d .git; then \ +if test -e .git; then \ (git submodule update --init --recursive && echo $SUBMODULE_OK) \ || (git submodule init && git submodule update --recursive && echo $SUBMODULE_OK) \ || (git submodule init && git submodule update && echo $SUBMODULE_ERROR) \ diff --git a/support/Makefile.am b/support/Makefile.am index f34e707130..c318c01902 100644 --- a/support/Makefile.am +++ b/support/Makefile.am @@ -59,10 +59,10 @@ MPH_UNIX_SOURCE = \ if HOST_WIN32 MPH_SOURCE = $(MPH_C_SOURCE) -MPH_LIBS = $(GLIB_LIBS) $(LIBICONV) +MPH_LIBS = $(GLIB_LIBS) else MPH_SOURCE = $(MPH_C_SOURCE) $(MPH_UNIX_SOURCE) -MPH_LIBS = $(GLIB_LIBS) $(LIBICONV) +MPH_LIBS = $(GLIB_LIBS) endif MINIZIP_SOURCE = \ @@ -125,7 +125,7 @@ libMonoSupportW_la_SOURCES = \ supportw.h libMonoSupportW_la_LIBADD = \ - $(GLIB_LIBS) $(LIBICONV) + $(GLIB_LIBS) # # Use this target to refresh the values in map.[ch] diff --git a/support/Makefile.in b/support/Makefile.in index 116ccc124a..318c643de2 100644 --- a/support/Makefile.in +++ b/support/Makefile.in @@ -84,8 +84,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs $(top_srcdir)/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -127,10 +125,8 @@ am__uninstall_files_from_dir = { \ am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) am__DEPENDENCIES_1 = -@HOST_WIN32_FALSE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) \ -@HOST_WIN32_FALSE@ $(am__DEPENDENCIES_1) -@HOST_WIN32_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) \ -@HOST_WIN32_TRUE@ $(am__DEPENDENCIES_1) +@HOST_WIN32_FALSE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) +@HOST_WIN32_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) libMonoPosixHelper_la_DEPENDENCIES = $(am__DEPENDENCIES_2) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) am__libMonoPosixHelper_la_SOURCES_DIST = errno.c map.c map.h mph.h \ @@ -171,8 +167,7 @@ libMonoPosixHelper_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_CFLAGS) $(CFLAGS) $(libMonoPosixHelper_la_LDFLAGS) \ $(LDFLAGS) -o $@ @BUILD_SUPPORT_TRUE@am_libMonoPosixHelper_la_rpath = -rpath $(libdir) -libMonoSupportW_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) +libMonoSupportW_la_DEPENDENCIES = $(am__DEPENDENCIES_1) am_libMonoSupportW_la_OBJECTS = supportw.lo support-heap.lo libMonoSupportW_la_OBJECTS = $(am_libMonoSupportW_la_OBJECTS) libMonoSupportW_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ @@ -316,6 +311,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -334,7 +330,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -348,7 +343,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -462,7 +456,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ @@ -539,8 +532,8 @@ MPH_UNIX_SOURCE = \ @HOST_WIN32_FALSE@MPH_SOURCE = $(MPH_C_SOURCE) $(MPH_UNIX_SOURCE) @HOST_WIN32_TRUE@MPH_SOURCE = $(MPH_C_SOURCE) -@HOST_WIN32_FALSE@MPH_LIBS = $(GLIB_LIBS) $(LIBICONV) -@HOST_WIN32_TRUE@MPH_LIBS = $(GLIB_LIBS) $(LIBICONV) +@HOST_WIN32_FALSE@MPH_LIBS = $(GLIB_LIBS) +@HOST_WIN32_TRUE@MPH_LIBS = $(GLIB_LIBS) MINIZIP_SOURCE = \ minizip/crypt.h \ minizip/ioapi.c \ @@ -597,7 +590,7 @@ libMonoSupportW_la_SOURCES = \ supportw.h libMonoSupportW_la_LIBADD = \ - $(GLIB_LIBS) $(LIBICONV) + $(GLIB_LIBS) all: all-am diff --git a/support/nl.c b/support/nl.c index 88babdae39..33a4a3b8e6 100644 --- a/support/nl.c +++ b/support/nl.c @@ -365,12 +365,6 @@ CloseNLSocket (gpointer sock) return close (GPOINTER_TO_INT (sock)); } #else -int -GetNLSocket (void) -{ - return -1; -} - int ReadEvents (gpointer sock, gpointer buffer, gint32 count, gint32 size) { diff --git a/support/sys-mman.c b/support/sys-mman.c index ad74ef2ad0..30b9897154 100644 --- a/support/sys-mman.c +++ b/support/sys-mman.c @@ -17,7 +17,7 @@ /* For mincore () */ #define _DARWIN_C_SOURCE #endif -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__OpenBSD__) /* For mincore () */ #define __BSD_VISIBLE 1 #endif diff --git a/tools/Makefile.in b/tools/Makefile.in index b694c9579d..e2832f802c 100644 --- a/tools/Makefile.in +++ b/tools/Makefile.in @@ -83,8 +83,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -253,6 +251,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -271,7 +270,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -285,7 +283,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -399,7 +396,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ diff --git a/tools/locale-builder/Makefile.in b/tools/locale-builder/Makefile.in index 89de6e59a1..17d59da631 100644 --- a/tools/locale-builder/Makefile.in +++ b/tools/locale-builder/Makefile.in @@ -83,8 +83,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs README ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -193,6 +191,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -211,7 +210,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -225,7 +223,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -339,7 +336,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ diff --git a/tools/monograph/Makefile.am b/tools/monograph/Makefile.am index 9e92e76342..714c242285 100644 --- a/tools/monograph/Makefile.am +++ b/tools/monograph/Makefile.am @@ -8,11 +8,11 @@ runtime_lib=$(top_builddir)/mono/mini/$(LIBMONO_LA) $(static_libs) else static_libs= \ $(top_builddir)/mono/metadata/libmonoruntimesgen.la \ + $(top_builddir)/mono/sgen/libmonosgen.la \ $(top_builddir)/mono/utils/libmonoutils.la \ - $(GLIB_LIBS) $(LIBICONV) \ - $(LIBGC_STATIC_LIBS) + $(GLIB_LIBS) -runtime_lib=$(top_builddir)/mono/mini/$(LIBMONO_LA) $(static_libs) +runtime_lib=$(static_libs) endif if DISABLE_EXECUTABLES @@ -35,11 +35,10 @@ monograph_LDADD = \ $(runtime_lib) \ $(GLIB_LIBS) \ $(LLVM_LIBS) \ - $(LIBICONV) \ -lm if HOST_DARWIN -monograph_LDFLAGS=-framework CoreFoundation +monograph_LDFLAGS=-framework CoreFoundation -framework Foundation endif GRAPHS=System.Object System.Enum System.Attribute System.ValueType System.Reflection.MemberInfo diff --git a/tools/monograph/Makefile.in b/tools/monograph/Makefile.in index 0dbdbb8db2..d4827293d4 100644 --- a/tools/monograph/Makefile.in +++ b/tools/monograph/Makefile.in @@ -85,8 +85,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs $(top_srcdir)/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -104,16 +102,14 @@ monograph_SOURCES = monograph.c monograph_OBJECTS = monograph.$(OBJEXT) am__DEPENDENCIES_1 = @DISABLE_EXECUTABLES_FALSE@am__DEPENDENCIES_2 = $(top_builddir)/mono/metadata/libmonoruntimesgen.la \ +@DISABLE_EXECUTABLES_FALSE@ $(top_builddir)/mono/sgen/libmonosgen.la \ @DISABLE_EXECUTABLES_FALSE@ $(top_builddir)/mono/utils/libmonoutils.la \ -@DISABLE_EXECUTABLES_FALSE@ $(am__DEPENDENCIES_1) \ -@DISABLE_EXECUTABLES_FALSE@ $(am__DEPENDENCIES_1) \ @DISABLE_EXECUTABLES_FALSE@ $(am__DEPENDENCIES_1) -@DISABLE_EXECUTABLES_FALSE@am__DEPENDENCIES_3 = $(top_builddir)/mono/mini/$(LIBMONO_LA) \ -@DISABLE_EXECUTABLES_FALSE@ $(am__DEPENDENCIES_2) +@DISABLE_EXECUTABLES_FALSE@am__DEPENDENCIES_3 = $(am__DEPENDENCIES_2) @DISABLE_EXECUTABLES_TRUE@am__DEPENDENCIES_3 = $(top_builddir)/mono/mini/$(LIBMONO_LA) \ @DISABLE_EXECUTABLES_TRUE@ $(am__DEPENDENCIES_2) monograph_DEPENDENCIES = $(am__DEPENDENCIES_3) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) + $(am__DEPENDENCIES_1) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent @@ -254,6 +250,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -272,7 +269,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -286,7 +282,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -400,7 +395,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ @@ -420,13 +414,13 @@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -@DISABLE_EXECUTABLES_FALSE@runtime_lib = $(top_builddir)/mono/mini/$(LIBMONO_LA) $(static_libs) +@DISABLE_EXECUTABLES_FALSE@runtime_lib = $(static_libs) @DISABLE_EXECUTABLES_TRUE@runtime_lib = $(top_builddir)/mono/mini/$(LIBMONO_LA) $(static_libs) @DISABLE_EXECUTABLES_FALSE@static_libs = \ @DISABLE_EXECUTABLES_FALSE@ $(top_builddir)/mono/metadata/libmonoruntimesgen.la \ +@DISABLE_EXECUTABLES_FALSE@ $(top_builddir)/mono/sgen/libmonosgen.la \ @DISABLE_EXECUTABLES_FALSE@ $(top_builddir)/mono/utils/libmonoutils.la \ -@DISABLE_EXECUTABLES_FALSE@ $(GLIB_LIBS) $(LIBICONV) \ -@DISABLE_EXECUTABLES_FALSE@ $(LIBGC_STATIC_LIBS) +@DISABLE_EXECUTABLES_FALSE@ $(GLIB_LIBS) AM_CPPFLAGS = \ -I$(top_srcdir) \ @@ -436,10 +430,9 @@ monograph_LDADD = \ $(runtime_lib) \ $(GLIB_LIBS) \ $(LLVM_LIBS) \ - $(LIBICONV) \ -lm -@HOST_DARWIN_TRUE@monograph_LDFLAGS = -framework CoreFoundation +@HOST_DARWIN_TRUE@monograph_LDFLAGS = -framework CoreFoundation -framework Foundation GRAPHS = System.Object System.Enum System.Attribute System.ValueType System.Reflection.MemberInfo OUT = $(GRAPHS:=.jpeg) all: all-am diff --git a/tools/monograph/monograph.c b/tools/monograph/monograph.c index 4d3cb83706..13fce57c6c 100644 --- a/tools/monograph/monograph.c +++ b/tools/monograph/monograph.c @@ -10,7 +10,10 @@ #include "mono/metadata/mono-endian.h" #include "mono/metadata/appdomain.h" /* mono_init */ #include "mono/metadata/debug-helpers.h" +#include "mono/utils/checked-build.h" #include "mono/utils/mono-compiler.h" +#include "mono/utils/mono-counters.h" +#include "mono/utils/mono-threads.h" static FILE *output; static int include_namespace = 0; @@ -26,9 +29,9 @@ void __nacl_suspend_thread_if_needed() {} static void output_type_edge (MonoClass *first, MonoClass *second) { if (include_namespace) - fprintf (output, "\t\"%s.%s\" -> \"%s.%s\"\n", first->name_space, first->name, second->name_space, second->name); + fprintf (output, "\t\"%s.%s\" -> \"%s.%s\"\n", mono_class_get_namespace (first), mono_class_get_name (first), mono_class_get_namespace (second), mono_class_get_name (second)); else - fprintf (output, "\t\"%s\" -> \"%s\"\n", first->name, second->name); + fprintf (output, "\t\"%s\" -> \"%s\"\n", mono_class_get_name (first), mono_class_get_name (second)); } static void @@ -42,7 +45,7 @@ print_subtypes (MonoImage *image, MonoClass *class, int depth) { t = mono_image_get_table_info (image, MONO_TABLE_TYPEDEF); - token = mono_metadata_token_index (class->type_token); + token = mono_metadata_token_index (mono_class_get_type_token (class)); token <<= MONO_TYPEDEFORREF_BITS; token |= MONO_TYPEDEFORREF_TYPEDEF; @@ -83,7 +86,7 @@ type_graph (MonoImage *image, const char* cname) { fprintf (output, "%s", graph_properties); child = class; /* go back and print the parents for the node as well: not sure it's a good idea */ - for (parent = class->parent; parent; parent = parent->parent) { + for (parent = mono_class_get_parent (class); parent; parent = mono_class_get_parent (parent)) { output_type_edge (parent, child); child = parent; } @@ -119,7 +122,7 @@ interface_graph (MonoImage *image, const char* cname) { fprintf (output, "digraph interface {\n"); fprintf (output, "%s", graph_properties); /* TODO: handle inetrface defined in one image and class defined in another. */ - token = mono_metadata_token_index (class->type_token); + token = mono_metadata_token_index (mono_class_get_type_token (class)); token <<= MONO_TYPEDEFORREF_BITS; token |= MONO_TYPEDEFORREF_TYPEDEF; for (i = 0; i < mono_table_info_get_rows (intf); ++i) { @@ -133,7 +136,7 @@ interface_graph (MonoImage *image, const char* cname) { } fprintf (output, "}\n"); if (verbose && !count) - g_print ("No class implements %s.%s\n", class->name_space, class->name); + g_print ("No class implements %s.%s\n", mono_class_get_namespace (class), mono_class_get_name (class)); } @@ -259,7 +262,7 @@ method_stats (MonoMethod *method) { case MonoInlineType: if (i == MONO_CEE_CASTCLASS || i == MONO_CEE_ISINST) { guint32 token = read32 (ip + 1); - MonoClass *k = mono_class_get (method->klass->image, token); + MonoClass *k = mono_class_get (mono_class_get_image (method->klass), token); if (k && mono_class_get_flags (k) & TYPE_ATTRIBUTE_SEALED) cast_sealed++; if (k && mono_class_get_flags (k) & TYPE_ATTRIBUTE_INTERFACE) @@ -361,7 +364,7 @@ method_stats (MonoMethod *method) { break; case MonoInlineMethod: if (i == MONO_CEE_CALLVIRT) { - MonoMethod *cm = mono_get_method (method->klass->image, read32 (ip + 1), NULL); + MonoMethod *cm = mono_get_method (mono_class_get_image (method->klass), read32 (ip + 1), NULL); if (cm && !(cm->flags & METHOD_ATTRIBUTE_VIRTUAL)) nonvirt_callvirt++; if (cm && (mono_class_get_flags (cm->klass) & TYPE_ATTRIBUTE_INTERFACE)) @@ -434,10 +437,10 @@ type_stats (MonoClass *klass) { num_ifaces++; return; } - parent = klass->parent; + parent = mono_class_get_parent (klass); while (parent) { depth++; - parent = parent->parent; + parent = mono_class_get_parent (parent); } if (pdepth_array_next >= pdepth_array_size) { pdepth_array_size *= 2; @@ -527,7 +530,7 @@ type_size_stats (MonoClass *klass) mono_method_header_get_code (header, &size, &maxs); code_size += size; } - g_print ("%s.%s: code: %d\n", klass->name_space, klass->name, code_size); + g_print ("%s.%s: code: %d\n", mono_class_get_namespace (klass), mono_class_get_name (klass), code_size); } static void @@ -555,10 +558,10 @@ get_signature (MonoMethod *method) { return result; res = g_string_new (""); - if (include_namespace && *(method->klass->name_space)) - g_string_append_printf (res, "%s.", method->klass->name_space); + if (include_namespace && *mono_class_get_namespace (method->klass)) + g_string_append_printf (res, "%s.", mono_class_get_namespace (method->klass)); result = mono_signature_get_desc (mono_method_signature (method), include_namespace); - g_string_append_printf (res, "%s:%s(%s)", method->klass->name, method->name, result); + g_string_append_printf (res, "%s:%s(%s)", mono_class_get_name (method->klass), method->name, result); g_free (result); g_hash_table_insert (hash, method, res->str); @@ -666,7 +669,7 @@ print_method (MonoMethod *method, int depth) { ip++; token = read32 (ip); ip += 4; - called = mono_get_method (method->klass->image, token, NULL); + called = mono_get_method (mono_class_get_image (method->klass), token, NULL); if (!called) break; /* warn? */ if (g_hash_table_lookup (hash, called)) @@ -1069,6 +1072,11 @@ enum { GRAPH_STATS }; +static void +thread_state_init (MonoThreadUnwindState *ctx) +{ +} + /* * TODO: * * virtual method calls as explained above @@ -1093,6 +1101,7 @@ main (int argc, char *argv[]) { int graphtype = GRAPH_TYPES; int callneato = 0; int i; + MonoThreadInfoRuntimeCallbacks ticallbacks; output = stdout; @@ -1132,6 +1141,12 @@ main (int argc, char *argv[]) { aname = argv [i]; if (argc > i + 1) cname = argv [i + 1]; + CHECKED_MONO_INIT (); + mono_counters_init (); + mono_tls_init_runtime_keys (); + memset (&ticallbacks, 0, sizeof (ticallbacks)); + ticallbacks.thread_state_init = thread_state_init; + mono_thread_info_runtime_init (&ticallbacks); if (aname) { mono_init_from_assembly (argv [0], aname); assembly = mono_assembly_open (aname, NULL); diff --git a/tools/pedump/Makefile.am b/tools/pedump/Makefile.am index fab3205791..0f49c067a4 100644 --- a/tools/pedump/Makefile.am +++ b/tools/pedump/Makefile.am @@ -22,8 +22,7 @@ pedump_LDADD = \ $(top_builddir)/mono/utils/libmonoutils.la \ $(LLVM_LIBS) \ $(LLVM_LDFLAGS) \ - $(GLIB_LIBS) \ - $(LIBICONV) + $(GLIB_LIBS) if HOST_DARWIN pedump_LDFLAGS=-framework CoreFoundation -framework Foundation diff --git a/tools/pedump/Makefile.in b/tools/pedump/Makefile.in index b516ac2ae2..d699507a13 100644 --- a/tools/pedump/Makefile.in +++ b/tools/pedump/Makefile.in @@ -85,8 +85,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs $(top_srcdir)/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -108,7 +106,7 @@ pedump_DEPENDENCIES = \ $(top_builddir)/mono/sgen/libmonosgen.la \ $(top_builddir)/mono/utils/libmonoutils.la \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) + $(am__DEPENDENCIES_1) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent @@ -249,6 +247,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -267,7 +266,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -281,7 +279,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -395,7 +392,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ @@ -425,8 +421,7 @@ pedump_LDADD = \ $(top_builddir)/mono/utils/libmonoutils.la \ $(LLVM_LIBS) \ $(LLVM_LDFLAGS) \ - $(GLIB_LIBS) \ - $(LIBICONV) + $(GLIB_LIBS) @HOST_DARWIN_TRUE@pedump_LDFLAGS = -framework CoreFoundation -framework Foundation all: all-am diff --git a/tools/pedump/pedump.c b/tools/pedump/pedump.c index 5769142553..d06455720b 100644 --- a/tools/pedump/pedump.c +++ b/tools/pedump/pedump.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -375,7 +376,7 @@ dump_verify_info (MonoImage *image, int flags, gboolean valid_only) errors = mono_method_verify (method, flags); if (errors) { MonoClass *klass = mono_method_get_class (method); - char *name = mono_type_full_name (&klass->byval_arg); + char *name = mono_type_full_name (m_class_get_byval_arg (klass)); if (mono_method_signature (method) == NULL) { g_print ("In method: %s::%s(ERROR)\n", name, mono_method_get_name (method)); } else { @@ -527,7 +528,7 @@ verify_image_file (const char *fname) if (mono_class_has_failure (klass)) { ERROR_DECL (type_load_error); mono_error_set_for_class_failure (type_load_error, klass); - printf ("Could not initialize class(0x%08x) %s.%s due to %s\n", token, klass->name_space, klass->name, mono_error_get_message (type_load_error)); + printf ("Could not initialize class(0x%08x) %s.%s due to %s\n", token, m_class_get_name_space (klass), m_class_get_name (klass), mono_error_get_message (type_load_error)); mono_error_cleanup (type_load_error); ++count; } @@ -536,7 +537,7 @@ verify_image_file (const char *fname) if (mono_class_has_failure (klass)) { ERROR_DECL (type_load_error); mono_error_set_for_class_failure (type_load_error, klass); - printf ("Could not initialize vtable of class(0x%08x) %s.%s due to %s\n", token, klass->name_space, klass->name, mono_error_get_message (type_load_error)); + printf ("Could not initialize vtable of class(0x%08x) %s.%s due to %s\n", token, m_class_get_name_space (klass), m_class_get_name (klass), mono_error_get_message (type_load_error)); mono_error_cleanup (type_load_error); ++count; } diff --git a/tools/sgen/Makefile.am b/tools/sgen/Makefile.am index c14346f088..040d5bac83 100644 --- a/tools/sgen/Makefile.am +++ b/tools/sgen/Makefile.am @@ -16,4 +16,4 @@ sgen_grep_binprot_SOURCES = \ sgen-entry-stream.h sgen_grep_binprot_LDADD = \ - $(GLIB_LIBS) $(LIBICONV) libsgen-grep-binprot.a libsgen-grep-binprot32p.a libsgen-grep-binprot64p.a + $(GLIB_LIBS) libsgen-grep-binprot.a libsgen-grep-binprot32p.a libsgen-grep-binprot64p.a diff --git a/tools/sgen/Makefile.in b/tools/sgen/Makefile.in index 2bde5c536c..3a8314f07a 100644 --- a/tools/sgen/Makefile.in +++ b/tools/sgen/Makefile.in @@ -86,8 +86,6 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs $(top_srcdir)/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ @@ -129,8 +127,8 @@ am_sgen_grep_binprot_OBJECTS = sgen-grep-binprot-main.$(OBJEXT) \ sgen_grep_binprot_OBJECTS = $(am_sgen_grep_binprot_OBJECTS) am__DEPENDENCIES_1 = sgen_grep_binprot_DEPENDENCIES = $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) libsgen-grep-binprot.a \ - libsgen-grep-binprot32p.a libsgen-grep-binprot64p.a + libsgen-grep-binprot.a libsgen-grep-binprot32p.a \ + libsgen-grep-binprot64p.a AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent @@ -274,6 +272,7 @@ G_GUINT64_FORMAT = @G_GUINT64_FORMAT@ G_HAVE_ISO_VARARGS = @G_HAVE_ISO_VARARGS@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_MSGFMT = @HAVE_MSGFMT@ +HAVE_NINJA = @HAVE_NINJA@ HOST_CC = @HOST_CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ @@ -292,7 +291,6 @@ LIBC = @LIBC@ LIBGC_CPPFLAGS = @LIBGC_CPPFLAGS@ LIBGC_LIBS = @LIBGC_LIBS@ LIBGC_STATIC_LIBS = @LIBGC_STATIC_LIBS@ -LIBICONV = @LIBICONV@ LIBMONO_LA = @LIBMONO_LA@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -306,7 +304,6 @@ LLVM_LIBS = @LLVM_LIBS@ LN_S = @LN_S@ LTCOMPILE = @LTCOMPILE@ LTCXXCOMPILE = @LTCXXCOMPILE@ -LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ @@ -420,7 +417,6 @@ mkdir_p = @mkdir_p@ mono_build_root = @mono_build_root@ mono_cfg_dir = @mono_cfg_dir@ mono_runtime = @mono_runtime@ -ninja = @ninja@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ @@ -454,7 +450,7 @@ sgen_grep_binprot_SOURCES = \ sgen-entry-stream.h sgen_grep_binprot_LDADD = \ - $(GLIB_LIBS) $(LIBICONV) libsgen-grep-binprot.a libsgen-grep-binprot32p.a libsgen-grep-binprot64p.a + $(GLIB_LIBS) libsgen-grep-binprot.a libsgen-grep-binprot32p.a libsgen-grep-binprot64p.a all: all-am diff --git a/winconfig.h b/winconfig.h index 3d9313f5be..145b0c13c3 100644 --- a/winconfig.h +++ b/winconfig.h @@ -595,6 +595,9 @@ /* Defined as strtok_s in eglib-config.hw */ #define HAVE_STRTOK_R 1 +/* Define to 1 if you have the `access' function. */ +#define HAVE_ACCESS 1 + /* Have a working sigaltstack */ /* #undef HAVE_WORKING_SIGALTSTACK */