diff --git a/Directory.Build.props b/Directory.Build.props index 7e5c028ecfa209..084308a0dd1fc1 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -192,6 +192,8 @@ false false + + false true + true true diff --git a/build.sh b/build.sh index befbb3bb08957f..9df7f38ad7163f 100755 --- a/build.sh +++ b/build.sh @@ -26,7 +26,7 @@ scriptroot="$( cd -P "$( dirname "$source" )" && pwd )" if is_cygwin_or_mingw; then # if bash shell running on Windows (not WSL), # pass control to batch build script. - "$scriptroot/build.cmd" $@ + "$scriptroot/build.cmd" "$@" else - "$scriptroot/eng/build.sh" $@ + "$scriptroot/eng/build.sh" "$@" fi diff --git a/docs/area-owners.md b/docs/area-owners.md index 2aeaa8770f42dd..ce2dd4d59101e5 100644 --- a/docs/area-owners.md +++ b/docs/area-owners.md @@ -42,7 +42,7 @@ Note: Editing this file doesn't update the mapping used by `@dotnet-policy-servi | area-Extensions-Primitives | @ericstj | @dotnet/area-extensions-primitives | | | area-GC-coreclr | @mangod9 | @Maoni0 | | | area-GC-mono | @mangod9 | @mangod9 | @BrzVlad to consult | -| area-Host | @agocke | @jeffschwMSFT @elinor-fung @vsadov | Issues with dotnet.exe including bootstrapping, framework detection, hostfxr.dll and hostpolicy.dll | +| area-Host | @agocke | @jeffschwMSFT @elinor-fung | Issues with dotnet.exe including bootstrapping, framework detection, hostfxr.dll and hostpolicy.dll | | area-HostModel | @agocke | @elinor-fung | | | area-ILTools-coreclr | @JulieLeeMSFT | @BruceForstall @dotnet/jit-contrib | | | area-Infrastructure | @agocke | @jeffschwMSFT @MichaelSimons | | @@ -133,7 +133,7 @@ Note: Editing this file doesn't update the mapping used by `@dotnet-policy-servi | area-System.Text.Encodings.Web | @ericstj | @dotnet/area-system-text-encodings-web | | | area-System.Text.Json | @jeffhandley | @dotnet/area-system-text-json | | | area-System.Text.RegularExpressions | @ericstj | @dotnet/area-system-text-regularexpressions | Consultants: @stephentoub | -| area-System.Threading | @mangod9 | @kouvel | | +| area-System.Threading | @mangod9 | @kouvel @vsadov | | | area-System.Threading.Channels | @jeffhandley | @dotnet/area-system-threading-channels | Consultants: @stephentoub | | area-System.Threading.RateLimiting | @rafikiassumani-msft | @BrennanConroy @halter73 | | | area-System.Threading.Tasks | @jeffhandley | @dotnet/area-system-threading-tasks | Consultants: @stephentoub | @@ -146,7 +146,7 @@ Note: Editing this file doesn't update the mapping used by `@dotnet-policy-servi | area-Tracing-mono | @tommcdon | @tommcdon @thaystg | | | area-TypeSystem-coreclr | @steveisok | @davidwrighton @MichalStrehovsky @janvorli @mangod9 @dotnet/area-type-system-and-startup | | | area-UWP | @tommcdon | @dotnet/area-uwp | UWP-specific issues including Microsoft.NETCore.UniversalWindowsPlatform and Microsoft.Net.UWPCoreRuntimeSdk | -| area-VM-coreclr | @mangod9 | @mangod9 | | +| area-VM-coreclr | @mangod9 | @mangod9 @vsadov | | | area-VM-meta-mono | @steveisok | @vitek-karas | | | area-VM-reflection-mono | @steveisok | @vitek-karas | MonoVM-specific reflection and reflection-emit issues | | area-VM-threading-mono | @mangod9 | @steveisok | | diff --git a/eng/Publishing.props b/eng/Publishing.props index 8050b1279ee3c8..beba39632cf7ef 100644 --- a/eng/Publishing.props +++ b/eng/Publishing.props @@ -15,7 +15,7 @@ We can't use NETCoreSdkRuntimeIdentifier here as the Arcade SDK projects don't import the .NET SDK. Instead, just make sure we include the assets targeting "not the output rid", which will catch the host assets. --> - + <_HostArtifact Include="$(ArtifactsPackagesDir)**\runtime.*.Microsoft.NETCore.ILAsm.*.nupkg" Exclude="$(ArtifactsPackagesDir)**\runtime.$(OutputRID).Microsoft.NETCore.ILAsm.*.nupkg" /> @@ -51,7 +51,7 @@ This ensures that we don't produce these files in the "Repo source build" builds, but we do produce them in both the VMR and the runtime official build. --> - + true true @@ -89,12 +89,12 @@ DependsOnTargets="GetNonStableProductVersion" BeforeTargets="PublishToAzureDevOpsArtifacts" AfterTargets="GenerateChecksumsFromArtifacts"> - + - + $(OutputRID) - true + true true diff --git a/eng/Subsets.props b/eng/Subsets.props index 96c5cf476590ee..4aa019b3c8499b 100644 --- a/eng/Subsets.props +++ b/eng/Subsets.props @@ -83,7 +83,7 @@ - + true diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 24fbe6c2292204..041d9b1b75ab9c 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,5 +1,5 @@ - + https://github.com/dotnet/icu @@ -41,91 +41,91 @@ https://github.com/dotnet/llvm-project da5dd054a531e6fea65643b7e754285b73eab433 - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + a4d6fdc935d5da12efb00a0b3b693ff1439e0b41 - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + a4d6fdc935d5da12efb00a0b3b693ff1439e0b41 - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + a4d6fdc935d5da12efb00a0b3b693ff1439e0b41 - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + a4d6fdc935d5da12efb00a0b3b693ff1439e0b41 - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + a4d6fdc935d5da12efb00a0b3b693ff1439e0b41 - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + a4d6fdc935d5da12efb00a0b3b693ff1439e0b41 - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + a4d6fdc935d5da12efb00a0b3b693ff1439e0b41 - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + a4d6fdc935d5da12efb00a0b3b693ff1439e0b41 - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + a4d6fdc935d5da12efb00a0b3b693ff1439e0b41 - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + a4d6fdc935d5da12efb00a0b3b693ff1439e0b41 - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + a4d6fdc935d5da12efb00a0b3b693ff1439e0b41 - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + a4d6fdc935d5da12efb00a0b3b693ff1439e0b41 - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + a4d6fdc935d5da12efb00a0b3b693ff1439e0b41 - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + a4d6fdc935d5da12efb00a0b3b693ff1439e0b41 - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + a4d6fdc935d5da12efb00a0b3b693ff1439e0b41 - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + a4d6fdc935d5da12efb00a0b3b693ff1439e0b41 - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + a4d6fdc935d5da12efb00a0b3b693ff1439e0b41 - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + a4d6fdc935d5da12efb00a0b3b693ff1439e0b41 - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + a4d6fdc935d5da12efb00a0b3b693ff1439e0b41 - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + a4d6fdc935d5da12efb00a0b3b693ff1439e0b41 - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + a4d6fdc935d5da12efb00a0b3b693ff1439e0b41 https://github.com/dotnet/runtime-assets @@ -263,33 +263,33 @@ https://github.com/dotnet/llvm-project da5dd054a531e6fea65643b7e754285b73eab433 - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + a4d6fdc935d5da12efb00a0b3b693ff1439e0b41 - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + a4d6fdc935d5da12efb00a0b3b693ff1439e0b41 - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + a4d6fdc935d5da12efb00a0b3b693ff1439e0b41 - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + a4d6fdc935d5da12efb00a0b3b693ff1439e0b41 - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + a4d6fdc935d5da12efb00a0b3b693ff1439e0b41 - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + a4d6fdc935d5da12efb00a0b3b693ff1439e0b41 - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + a4d6fdc935d5da12efb00a0b3b693ff1439e0b41 https://github.com/dotnet/xharness @@ -303,9 +303,9 @@ https://github.com/dotnet/xharness e85bb14e85357ab678c2bcb0b6f2bac634fdd49b - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + a4d6fdc935d5da12efb00a0b3b693ff1439e0b41 https://dev.azure.com/dnceng/internal/_git/dotnet-optimization @@ -331,29 +331,29 @@ https://github.com/dotnet/runtime-assets 1cfc6ba21d0377b51f17eac4fdc2557f7b1e8693 - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + a4d6fdc935d5da12efb00a0b3b693ff1439e0b41 - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + a4d6fdc935d5da12efb00a0b3b693ff1439e0b41 - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + a4d6fdc935d5da12efb00a0b3b693ff1439e0b41 - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + a4d6fdc935d5da12efb00a0b3b693ff1439e0b41 - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + a4d6fdc935d5da12efb00a0b3b693ff1439e0b41 - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + a4d6fdc935d5da12efb00a0b3b693ff1439e0b41 https://dev.azure.com/dnceng/internal/_git/dotnet-optimization diff --git a/eng/Versions.props b/eng/Versions.props index 6fe9ec30dcc4b7..71a5cdd5a741ff 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -12,7 +12,7 @@ 7.0.20 6.0.36 preview - 5 + 6 false release @@ -36,17 +36,17 @@ - 10.0.0-preview.25260.104 + 10.0.0-preview.25270.108 - 5.0.0-1.25260.104 + 5.0.0-1.25270.108 - 5.0.0-1.25260.104 - 5.0.0-1.25260.104 - 5.0.0-1.25260.104 + 5.0.0-1.25270.108 + 5.0.0-1.25270.108 + 5.0.0-1.25270.108 - 10.0.100-preview.5.25260.104 + 10.0.100-preview.5.25270.108 - 10.0.0-beta.25260.104 - 10.0.0-beta.25260.104 - 10.0.0-beta.25260.104 - 10.0.0-beta.25260.104 - 2.9.2-beta.25260.104 - 10.0.0-beta.25260.104 - 2.9.2-beta.25260.104 - 10.0.0-beta.25260.104 - 10.0.0-beta.25260.104 - 10.0.0-beta.25260.104 - 10.0.0-beta.25260.104 - 10.0.0-beta.25260.104 - 10.0.0-beta.25260.104 - 10.0.0-beta.25260.104 - 10.0.0-beta.25260.104 - 10.0.0-beta.25260.104 + 10.0.0-beta.25270.108 + 10.0.0-beta.25270.108 + 10.0.0-beta.25270.108 + 10.0.0-beta.25270.108 + 2.9.2-beta.25270.108 + 10.0.0-beta.25270.108 + 2.9.2-beta.25270.108 + 10.0.0-beta.25270.108 + 10.0.0-beta.25270.108 + 10.0.0-beta.25270.108 + 10.0.0-beta.25270.108 + 10.0.0-beta.25270.108 + 10.0.0-beta.25270.108 + 10.0.0-beta.25270.108 + 10.0.0-beta.25270.108 + 10.0.0-beta.25270.108 1.4.0 6.0.0-preview.1.102 - 10.0.0-preview.5.25260.104 + 10.0.0-preview.5.25270.108 6.0.0 - 10.0.0-preview.5.25260.104 - 10.0.0-preview.5.25260.104 + 10.0.0-preview.5.25270.108 + 10.0.0-preview.5.25270.108 6.0.0 4.6.1 @@ -128,16 +128,16 @@ 8.0.0 8.0.1 5.0.0 - 10.0.0-preview.5.25260.104 - 10.0.0-preview.5.25260.104 + 10.0.0-preview.5.25270.108 + 10.0.0-preview.5.25270.108 6.0.0 5.0.0 5.0.0 5.0.0 7.0.0 - 10.0.0-preview.5.25260.104 + 10.0.0-preview.5.25270.108 7.0.0 - 10.0.0-preview.5.25260.104 + 10.0.0-preview.5.25270.108 8.0.0 4.5.1 @@ -180,7 +180,7 @@ 2.0.0 17.10.0-beta1.24272.1 - 2.0.0-beta5.25260.104 + 2.0.0-beta5.25270.108 3.1.16 2.1.0 2.0.3 @@ -226,7 +226,7 @@ 9.0.0-preview-20241010.1 - 0.11.5-alpha.25260.104 + 0.11.5-alpha.25270.108 10.0.0-preview.5.25261.1 @@ -258,7 +258,7 @@ Note: when the name is updated, make sure to update dependency name in eng/pipelines/common/xplat-setup.yml like - DarcDependenciesChanged.Microsoft_NET_Workload_Emscripten_Current_Manifest-10_0_100_Transport --> - 10.0.100-preview.5.25260.104 + 10.0.100-preview.5.25270.108 $(MicrosoftNETWorkloadEmscriptenCurrentManifest100100TransportVersion) 1.1.87-gba258badda diff --git a/eng/build.sh b/eng/build.sh index 6a82dc2cbb917a..9c55c01ffa7dfe 100755 --- a/eng/build.sh +++ b/eng/build.sh @@ -153,9 +153,9 @@ showSubsetHelp() "$scriptroot/common/build.sh" "-restore" "-build" "/p:Subset=help" "/clp:nosummary /tl:false" } -arguments='' +arguments=() cmakeargs='' -extraargs='' +extraargs=() crossBuild=0 portableBuild=1 bootstrap=0 @@ -178,7 +178,7 @@ while [[ $# > 0 ]]; do exit 0 fi - arguments="$arguments /p:Subset=$1" + arguments+=("/p:Subset=$1") shift 1 continue fi @@ -201,7 +201,7 @@ while [[ $# > 0 ]]; do showSubsetHelp exit 0 fi - arguments="$arguments /p:Subset=$2" + arguments+=("/p:Subset=$2") shift 2 fi ;; @@ -241,7 +241,7 @@ while [[ $# > 0 ]]; do exit 1 ;; esac - arguments="$arguments -configuration $val" + arguments+=("-configuration" "$val") shift 2 ;; @@ -251,7 +251,7 @@ while [[ $# > 0 ]]; do exit 1 fi val="$(echo "$2" | tr "[:upper:]" "[:lower:]")" - arguments="$arguments /p:BuildTargetFramework=$val" + arguments+=("/p:BuildTargetFramework=$val") shift 2 ;; @@ -306,12 +306,12 @@ while [[ $# > 0 ]]; do exit 1 ;; esac - arguments="$arguments /p:TargetOS=$os" + arguments+=("/p:TargetOS=$os") shift 2 ;; -pack) - arguments="$arguments --pack /p:BuildAllConfigurations=true" + arguments+=("--pack" "/p:BuildAllConfigurations=true") shift 1 ;; @@ -320,17 +320,17 @@ while [[ $# > 0 ]]; do echo "No test scope supplied. See help (--help) for supported test scope values." 1>&2 exit 1 fi - arguments="$arguments /p:TestScope=$2" + arguments+=("/p:TestScope=$2") shift 2 ;; -testnobuild) - arguments="$arguments /p:TestNoBuild=true" + arguments+=("/p:TestNoBuild=true") shift 1 ;; -coverage) - arguments="$arguments /p:Coverage=true" + arguments+=("/p:Coverage=true") shift 1 ;; @@ -350,7 +350,7 @@ while [[ $# > 0 ]]; do exit 1 ;; esac - arguments="$arguments /p:RuntimeConfiguration=$val" + arguments+=("/p:RuntimeConfiguration=$val") shift 2 ;; @@ -370,12 +370,12 @@ while [[ $# > 0 ]]; do exit 1 ;; esac - arguments="$arguments /p:RuntimeFlavor=$val" + arguments+=("/p:RuntimeFlavor=$val") shift 2 ;; -usemonoruntime) - arguments="$arguments /p:PrimaryRuntimeFlavor=Mono" + arguments+=("/p:PrimaryRuntimeFlavor=Mono") shift 1 ;; @@ -395,7 +395,7 @@ while [[ $# > 0 ]]; do exit 1 ;; esac - arguments="$arguments /p:LibrariesConfiguration=$val" + arguments+=("/p:LibrariesConfiguration=$val") shift 2 ;; @@ -415,25 +415,25 @@ while [[ $# > 0 ]]; do exit 1 ;; esac - arguments="$arguments /p:HostConfiguration=$val" + arguments+=("/p:HostConfiguration=$val") shift 2 ;; -cross) crossBuild=1 - arguments="$arguments /p:CrossBuild=True" + arguments+=("/p:CrossBuild=True") shift 1 ;; *crossbuild=true*) crossBuild=1 - extraargs="$extraargs $1" + extraargs+=("$1") shift 1 ;; -clang*) compiler="${opt/#-/}" # -clang-9 => clang-9 or clang-9 => (unchanged) - arguments="$arguments /p:Compiler=$compiler /p:CppCompilerAndLinker=$compiler" + arguments+=("/p:Compiler=$compiler" "/p:CppCompilerAndLinker=$compiler") shift 1 ;; @@ -448,7 +448,7 @@ while [[ $# > 0 ]]; do -gcc*) compiler="${opt/#-/}" # -gcc-9 => gcc-9 or gcc-9 => (unchanged) - arguments="$arguments /p:Compiler=$compiler /p:CppCompilerAndLinker=$compiler" + arguments+=("/p:Compiler=$compiler" "/p:CppCompilerAndLinker=$compiler") shift 1 ;; @@ -457,7 +457,7 @@ while [[ $# > 0 ]]; do echo "No value for outputrid is supplied. See help (--help) for supported values." 1>&2 exit 1 fi - arguments="$arguments /p:OutputRID=$(echo "$2" | tr "[:upper:]" "[:lower:]")" + arguments+=("/p:OutputRID=$(echo "$2" | tr "[:upper:]" "[:lower:]")") shift 2 ;; @@ -469,7 +469,7 @@ while [[ $# > 0 ]]; do passedPortable="$(echo "$2" | tr "[:upper:]" "[:lower:]")" if [ "$passedPortable" = false ]; then portableBuild=0 - arguments="$arguments /p:PortableBuild=false" + arguments+=("/p:PortableBuild=false") fi shift 2 ;; @@ -481,7 +481,7 @@ while [[ $# > 0 ]]; do fi passedKeepNativeSymbols="$(echo "$2" | tr "[:upper:]" "[:lower:]")" if [ "$passedKeepNativeSymbols" = true ]; then - arguments="$arguments /p:KeepNativeSymbols=true" + arguments+=("/p:KeepNativeSymbols=true") fi shift 2 ;; @@ -489,30 +489,30 @@ while [[ $# > 0 ]]; do -ninja) if [ -z ${2+x} ]; then - arguments="$arguments /p:Ninja=true" + arguments+=("/p:Ninja=true") shift 1 else ninja="$(echo "$2" | tr "[:upper:]" "[:lower:]")" if [ "$ninja" = true ]; then - arguments="$arguments /p:Ninja=true" + arguments+=("/p:Ninja=true") shift 2 elif [ "$ninja" = false ]; then - arguments="$arguments /p:Ninja=false" + arguments+=("/p:Ninja=false") shift 2 else - arguments="$arguments /p:Ninja=true" + arguments+=("/p:Ninja=true") shift 1 fi fi ;; -pgoinstrument) - arguments="$arguments /p:PgoInstrument=true" + arguments+=("/p:PgoInstrument=true") shift 1 ;; -use-bootstrap) - arguments="$arguments /p:UseBootstrap=true" + arguments+=("/p:UseBootstrap=true") shift 1 ;; @@ -526,30 +526,30 @@ while [[ $# > 0 ]]; do echo "No value for -fsanitize is supplied. See help (--help) for supported values." 1>&2 exit 1 fi - arguments="$arguments /p:EnableNativeSanitizers=$2" + arguments+=("/p:EnableNativeSanitizers=$2") shift 2 ;; -fsanitize=*) sanitizers="${opt/#-fsanitize=/}" # -fsanitize=address => address - arguments="$arguments /p:EnableNativeSanitizers=$sanitizers" + arguments+=("/p:EnableNativeSanitizers=$sanitizers") shift 2 ;; -verbose) - arguments="$arguments /p:CoreclrVerbose=true" + arguments+=("/p:CoreclrVerbose=true") shift 1 ;; *) - extraargs="$extraargs $1" + extraargs+=("$1") shift 1 ;; esac done if [ ${#actInt[@]} -eq 0 ]; then - arguments="-restore -build $arguments" + arguments=("-restore" "-build" "${arguments[@]}") fi if [[ "$os" == "browser" ]]; then @@ -566,11 +566,11 @@ if [[ "$os" == "wasi" ]]; then fi if [[ "${TreatWarningsAsErrors:-}" == "false" ]]; then - arguments="$arguments -warnAsError false" + arguments+=("-warnAsError" "false") fi # disable terminal logger for now: https://github.com/dotnet/runtime/issues/97211 -arguments="$arguments -tl:false" +arguments+=("-tl:false") initDistroRid "$os" "$arch" "$crossBuild" @@ -581,23 +581,31 @@ export DOTNETSDK_ALLOW_TARGETING_PACK_CACHING=0 # URL-encode space (%20) to avoid quoting issues until the msbuild call in /eng/common/tools.sh. # In *proj files (XML docs), URL-encoded string are rendered in their decoded form. cmakeargs="${cmakeargs// /%20}" -arguments="$arguments /p:TargetArchitecture=$arch /p:BuildArchitecture=$hostArch" -arguments="$arguments /p:CMakeArgs=\"$cmakeargs\" $extraargs" +arguments+=("/p:TargetArchitecture=$arch" "/p:BuildArchitecture=$hostArch") +arguments+=("/p:CMakeArgs=\"$cmakeargs\"" "${extraargs[@]}") if [[ "$bootstrap" == "1" ]]; then # Strip build actions other than -restore and -build from the arguments for the bootstrap build. - bootstrapArguments="$arguments" - for flag in --sign --publish --pack --test -sign -publish -pack -test; do - bootstrapArguments="${bootstrapArguments//$flag/}" + bootstrapArguments=() + for argument in "${arguments[@]}"; do + add=1 + for flag in --sign --publish --pack --test -sign -publish -pack -test; do + if [[ "$argument" == "$flag" ]]; then + add=0 + fi + done + if [[ $add == 1 ]]; then + bootstrapArguments+=("$argument") + fi done - "$scriptroot/common/build.sh" $bootstrapArguments /p:Subset=bootstrap -bl:$scriptroot/../artifacts/log/bootstrap.binlog + "$scriptroot/common/build.sh" "${bootstrapArguments[@]}" /p:Subset=bootstrap -bl:$scriptroot/../artifacts/log/bootstrap.binlog # Remove artifacts from the bootstrap build so the product build is a "clean" build. echo "Cleaning up artifacts from bootstrap build..." rm -r "$scriptroot/../artifacts/bin" # Remove all directories in obj except for the source-built-upstream-cache directory to avoid breaking SourceBuild. find "$scriptroot/../artifacts/obj" -mindepth 1 -maxdepth 1 ! -name 'source-built-upstream-cache' -exec rm -rf {} + - arguments="$arguments /p:UseBootstrap=true" + arguments+=("/p:UseBootstrap=true") fi -"$scriptroot/common/build.sh" $arguments +"$scriptroot/common/build.sh" "${arguments[@]}" diff --git a/eng/common/build.ps1 b/eng/common/build.ps1 index 6b3be1916fcaf5..ae2309e312d789 100644 --- a/eng/common/build.ps1 +++ b/eng/common/build.ps1 @@ -127,7 +127,7 @@ function Build { /p:Deploy=$deploy ` /p:Test=$test ` /p:Pack=$pack ` - /p:DotNetBuildRepo=$productBuild ` + /p:DotNetBuild=$productBuild ` /p:IntegrationTest=$integrationTest ` /p:PerformanceTest=$performanceTest ` /p:Sign=$sign ` diff --git a/eng/common/build.sh b/eng/common/build.sh index 36fba82a37930d..da906da202626d 100755 --- a/eng/common/build.sh +++ b/eng/common/build.sh @@ -129,14 +129,14 @@ while [[ $# > 0 ]]; do -pack) pack=true ;; - -sourcebuild|-sb) + -sourcebuild|-source-build|-sb) build=true source_build=true product_build=true restore=true pack=true ;; - -productBuild|-pb) + -productbuild|-product-build|-pb) build=true product_build=true restore=true @@ -241,7 +241,7 @@ function Build { /p:RepoRoot="$repo_root" \ /p:Restore=$restore \ /p:Build=$build \ - /p:DotNetBuildRepo=$product_build \ + /p:DotNetBuild=$product_build \ /p:DotNetBuildSourceOnly=$source_build \ /p:Rebuild=$rebuild \ /p:Test=$test \ diff --git a/eng/common/core-templates/steps/source-build.yml b/eng/common/core-templates/steps/source-build.yml index f2a0f347fdd67a..0dde553c3ebfbb 100644 --- a/eng/common/core-templates/steps/source-build.yml +++ b/eng/common/core-templates/steps/source-build.yml @@ -51,13 +51,12 @@ steps: ${{ coalesce(parameters.platform.buildScript, './build.sh') }} --ci \ --configuration $buildConfig \ --restore --build --pack -bl \ + --source-build \ ${{ parameters.platform.buildArguments }} \ $internalRuntimeDownloadArgs \ $targetRidArgs \ $baseRidArgs \ $portableBuildArgs \ - /p:DotNetBuildSourceOnly=true \ - /p:DotNetBuildRepo=true \ displayName: Build - template: /eng/common/core-templates/steps/publish-pipeline-artifacts.yml diff --git a/eng/common/darc-init.sh b/eng/common/darc-init.sh index 36dbd45e1ce866..e889f439b8dc99 100755 --- a/eng/common/darc-init.sh +++ b/eng/common/darc-init.sh @@ -68,7 +68,7 @@ function InstallDarcCli { fi fi - local arcadeServicesSource="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json" + local arcadeServicesSource="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json" echo "Installing Darc CLI version $darcVersion..." echo "You may need to restart your command shell if this is the first dotnet tool you have installed." diff --git a/eng/common/templates/steps/vmr-sync.yml b/eng/common/templates/steps/vmr-sync.yml new file mode 100644 index 00000000000000..599afb6186b8fd --- /dev/null +++ b/eng/common/templates/steps/vmr-sync.yml @@ -0,0 +1,207 @@ +### These steps synchronize new code from product repositories into the VMR (https://github.com/dotnet/dotnet). +### They initialize the darc CLI and pull the new updates. +### Changes are applied locally onto the already cloned VMR (located in $vmrPath). + +parameters: +- name: targetRef + displayName: Target revision in dotnet/ to synchronize + type: string + default: $(Build.SourceVersion) + +- name: vmrPath + displayName: Path where the dotnet/dotnet is checked out to + type: string + default: $(Agent.BuildDirectory)/vmr + +- name: additionalSyncs + displayName: Optional list of package names whose repo's source will also be synchronized in the local VMR, e.g. NuGet.Protocol + type: object + default: [] + +steps: +- checkout: vmr + displayName: Clone dotnet/dotnet + path: vmr + clean: true + +- checkout: self + displayName: Clone $(Build.Repository.Name) + path: repo + fetchDepth: 0 + +# This step is needed so that when we get a detached HEAD / shallow clone, +# we still pull the commit into the temporary repo clone to use it during the sync. +# Also unshallow the clone so that forwardflow command would work. +- script: | + git branch repo-head + git rev-parse HEAD + displayName: Label PR commit + workingDirectory: $(Agent.BuildDirectory)/repo + +- script: | + vmr_sha=$(grep -oP '(?<=Sha=")[^"]*' $(Agent.BuildDirectory)/repo/eng/Version.Details.xml) + echo "##vso[task.setvariable variable=vmr_sha]$vmr_sha" + displayName: Obtain the vmr sha from Version.Details.xml (Unix) + condition: ne(variables['Agent.OS'], 'Windows_NT') + workingDirectory: $(Agent.BuildDirectory)/repo + +- powershell: | + [xml]$xml = Get-Content -Path $(Agent.BuildDirectory)/repo/eng/Version.Details.xml + $vmr_sha = $xml.SelectSingleNode("//Source").Sha + Write-Output "##vso[task.setvariable variable=vmr_sha]$vmr_sha" + displayName: Obtain the vmr sha from Version.Details.xml (Windows) + condition: eq(variables['Agent.OS'], 'Windows_NT') + workingDirectory: $(Agent.BuildDirectory)/repo + +- script: | + git fetch --all + git checkout $(vmr_sha) + displayName: Checkout VMR at correct sha for repo flow + workingDirectory: ${{ parameters.vmrPath }} + +- script: | + git config --global user.name "dotnet-maestro[bot]" + git config --global user.email "dotnet-maestro[bot]@users.noreply.github.com" + displayName: Set git author to dotnet-maestro[bot] + workingDirectory: ${{ parameters.vmrPath }} + +- script: | + ./eng/common/vmr-sync.sh \ + --vmr ${{ parameters.vmrPath }} \ + --tmp $(Agent.TempDirectory) \ + --azdev-pat '$(dn-bot-all-orgs-code-r)' \ + --ci \ + --debug + + if [ "$?" -ne 0 ]; then + echo "##vso[task.logissue type=error]Failed to synchronize the VMR" + exit 1 + fi + displayName: Sync repo into VMR (Unix) + condition: ne(variables['Agent.OS'], 'Windows_NT') + workingDirectory: $(Agent.BuildDirectory)/repo + +- script: | + git config --global diff.astextplain.textconv echo + git config --system core.longpaths true + displayName: Configure Windows git (longpaths, astextplain) + condition: eq(variables['Agent.OS'], 'Windows_NT') + +- powershell: | + ./eng/common/vmr-sync.ps1 ` + -vmr ${{ parameters.vmrPath }} ` + -tmp $(Agent.TempDirectory) ` + -azdevPat '$(dn-bot-all-orgs-code-r)' ` + -ci ` + -debugOutput + + if ($LASTEXITCODE -ne 0) { + echo "##vso[task.logissue type=error]Failed to synchronize the VMR" + exit 1 + } + displayName: Sync repo into VMR (Windows) + condition: eq(variables['Agent.OS'], 'Windows_NT') + workingDirectory: $(Agent.BuildDirectory)/repo + +- ${{ if eq(variables['Build.Reason'], 'PullRequest') }}: + - task: CopyFiles@2 + displayName: Collect failed patches + condition: failed() + inputs: + SourceFolder: '$(Agent.TempDirectory)' + Contents: '*.patch' + TargetFolder: '$(Build.ArtifactStagingDirectory)/FailedPatches' + + - publish: '$(Build.ArtifactStagingDirectory)/FailedPatches' + artifact: $(System.JobDisplayName)_FailedPatches + displayName: Upload failed patches + condition: failed() + +- ${{ each assetName in parameters.additionalSyncs }}: + # The vmr-sync script ends up staging files in the local VMR so we have to commit those + - script: + git commit --allow-empty -am "Forward-flow $(Build.Repository.Name)" + displayName: Commit local VMR changes + workingDirectory: ${{ parameters.vmrPath }} + + - script: | + set -ex + + echo "Searching for details of asset ${{ assetName }}..." + + # Use darc to get dependencies information + dependencies=$(./.dotnet/dotnet darc get-dependencies --name '${{ assetName }}' --ci) + + # Extract repository URL and commit hash + repository=$(echo "$dependencies" | grep 'Repo:' | sed 's/Repo:[[:space:]]*//' | head -1) + + if [ -z "$repository" ]; then + echo "##vso[task.logissue type=error]Asset ${{ assetName }} not found in the dependency list" + exit 1 + fi + + commit=$(echo "$dependencies" | grep 'Commit:' | sed 's/Commit:[[:space:]]*//' | head -1) + + echo "Updating the VMR from $repository / $commit..." + cd .. + git clone $repository ${{ assetName }} + cd ${{ assetName }} + git checkout $commit + git branch "sync/$commit" + + ./eng/common/vmr-sync.sh \ + --vmr ${{ parameters.vmrPath }} \ + --tmp $(Agent.TempDirectory) \ + --azdev-pat '$(dn-bot-all-orgs-code-r)' \ + --ci \ + --debug + + if [ "$?" -ne 0 ]; then + echo "##vso[task.logissue type=error]Failed to synchronize the VMR" + exit 1 + fi + displayName: Sync ${{ assetName }} into (Unix) + condition: ne(variables['Agent.OS'], 'Windows_NT') + workingDirectory: $(Agent.BuildDirectory)/repo + + - powershell: | + $ErrorActionPreference = 'Stop' + + Write-Host "Searching for details of asset ${{ assetName }}..." + + $dependencies = .\.dotnet\dotnet darc get-dependencies --name '${{ assetName }}' --ci + + $repository = $dependencies | Select-String -Pattern 'Repo:\s+([^\s]+)' | Select-Object -First 1 + $repository -match 'Repo:\s+([^\s]+)' | Out-Null + $repository = $matches[1] + + if ($repository -eq $null) { + Write-Error "Asset ${{ assetName }} not found in the dependency list" + exit 1 + } + + $commit = $dependencies | Select-String -Pattern 'Commit:\s+([^\s]+)' | Select-Object -First 1 + $commit -match 'Commit:\s+([^\s]+)' | Out-Null + $commit = $matches[1] + + Write-Host "Updating the VMR from $repository / $commit..." + cd .. + git clone $repository ${{ assetName }} + cd ${{ assetName }} + git checkout $commit + git branch "sync/$commit" + + .\eng\common\vmr-sync.ps1 ` + -vmr ${{ parameters.vmrPath }} ` + -tmp $(Agent.TempDirectory) ` + -azdevPat '$(dn-bot-all-orgs-code-r)' ` + -ci ` + -debugOutput + + if ($LASTEXITCODE -ne 0) { + echo "##vso[task.logissue type=error]Failed to synchronize the VMR" + exit 1 + } + displayName: Sync ${{ assetName }} into (Windows) + condition: ne(variables['Agent.OS'], 'Windows_NT') + workingDirectory: $(Agent.BuildDirectory)/repo diff --git a/eng/common/templates/vmr-build-pr.yml b/eng/common/templates/vmr-build-pr.yml new file mode 100644 index 00000000000000..670cf32c3bd1fa --- /dev/null +++ b/eng/common/templates/vmr-build-pr.yml @@ -0,0 +1,33 @@ +trigger: none +pr: + branches: + include: + - main + - release/* + paths: + exclude: + - documentation/* + - README.md + - CODEOWNERS + +variables: +- template: /eng/common/templates/variables/pool-providers.yml@self + +- name: skipComponentGovernanceDetection # we run CG on internal builds only + value: true + +- name: Codeql.Enabled # we run CodeQL on internal builds only + value: false + +resources: + repositories: + - repository: vmr + type: github + name: dotnet/dotnet + endpoint: dotnet + +stages: +- template: /eng/pipelines/templates/stages/vmr-build.yml@vmr + parameters: + isBuiltFromVmr: false + scope: lite diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1 index 7373e5305465d7..5f40a3f8238a8b 100644 --- a/eng/common/tools.ps1 +++ b/eng/common/tools.ps1 @@ -68,8 +68,6 @@ $ErrorActionPreference = 'Stop' # True if the build is a product build [bool]$productBuild = if (Test-Path variable:productBuild) { $productBuild } else { $false } -[String[]]$properties = if (Test-Path variable:properties) { $properties } else { @() } - function Create-Directory ([string[]] $path) { New-Item -Path $path -Force -ItemType 'Directory' | Out-Null } @@ -853,7 +851,7 @@ function MSBuild-Core() { # When running on Azure Pipelines, override the returned exit code to avoid double logging. # Skip this when the build is a child of the VMR orchestrator build. - if ($ci -and $env:SYSTEM_TEAMPROJECT -ne $null -and !$productBuild -and -not($properties -like "*DotNetBuildRepo=true*")) { + if ($ci -and $env:SYSTEM_TEAMPROJECT -ne $null -and !$productBuild) { Write-PipelineSetResult -Result "Failed" -Message "msbuild execution failed." # Exiting with an exit code causes the azure pipelines task to log yet another "noise" error # The above Write-PipelineSetResult will cause the task to be marked as failure without adding yet another error diff --git a/eng/common/tools.sh b/eng/common/tools.sh index cc007b1f15ad05..25f5932eee982a 100755 --- a/eng/common/tools.sh +++ b/eng/common/tools.sh @@ -507,7 +507,7 @@ function MSBuild-Core { # When running on Azure Pipelines, override the returned exit code to avoid double logging. # Skip this when the build is a child of the VMR orchestrator build. - if [[ "$ci" == true && -n ${SYSTEM_TEAMPROJECT:-} && "$product_build" != true && "$properties" != *"DotNetBuildRepo=true"* ]]; then + if [[ "$ci" == true && -n ${SYSTEM_TEAMPROJECT:-} && "$product_build" != true ]]; then Write-PipelineSetResult -result "Failed" -message "msbuild execution failed." # Exiting with an exit code causes the azure pipelines task to log yet another "noise" error # The above Write-PipelineSetResult will cause the task to be marked as failure without adding yet another error diff --git a/eng/common/vmr-sync.ps1 b/eng/common/vmr-sync.ps1 new file mode 100755 index 00000000000000..8c3c91ce8dede9 --- /dev/null +++ b/eng/common/vmr-sync.ps1 @@ -0,0 +1,138 @@ +<# +.SYNOPSIS + +This script is used for synchronizing the current repository into a local VMR. +It pulls the current repository's code into the specified VMR directory for local testing or +Source-Build validation. + +.DESCRIPTION + +The tooling used for synchronization will clone the VMR repository into a temporary folder if +it does not already exist. These clones can be reused in future synchronizations, so it is +recommended to dedicate a folder for this to speed up re-runs. + +.EXAMPLE + Synchronize current repository into a local VMR: + ./vmr-sync.ps1 -vmrDir "$HOME/repos/dotnet" -tmpDir "$HOME/repos/tmp" + +.PARAMETER tmpDir +Required. Path to the temporary folder where repositories will be cloned + +.PARAMETER vmrBranch +Optional. Branch of the 'dotnet/dotnet' repo to synchronize. The VMR will be checked out to this branch + +.PARAMETER azdevPat +Optional. Azure DevOps PAT to use for cloning private repositories. + +.PARAMETER vmrDir +Optional. Path to the dotnet/dotnet repository. When null, gets cloned to the temporary folder + +.PARAMETER debugOutput +Optional. Enables debug logging in the darc vmr command. + +.PARAMETER ci +Optional. Denotes that the script is running in a CI environment. +#> +param ( + [Parameter(Mandatory=$true, HelpMessage="Path to the temporary folder where repositories will be cloned")] + [string][Alias('t', 'tmp')]$tmpDir, + [string][Alias('b', 'branch')]$vmrBranch, + [string]$remote, + [string]$azdevPat, + [string][Alias('v', 'vmr')]$vmrDir, + [switch]$ci, + [switch]$debugOutput +) + +function Fail { + Write-Host "> $($args[0])" -ForegroundColor 'Red' +} + +function Highlight { + Write-Host "> $($args[0])" -ForegroundColor 'Cyan' +} + +$verbosity = 'verbose' +if ($debugOutput) { + $verbosity = 'debug' +} +# Validation + +if (-not $tmpDir) { + Fail "Missing -tmpDir argument. Please specify the path to the temporary folder where the repositories will be cloned" + exit 1 +} + +# Sanitize the input + +if (-not $vmrDir) { + $vmrDir = Join-Path $tmpDir 'dotnet' +} + +if (-not (Test-Path -Path $tmpDir -PathType Container)) { + New-Item -ItemType Directory -Path $tmpDir | Out-Null +} + +# Prepare the VMR + +if (-not (Test-Path -Path $vmrDir -PathType Container)) { + Highlight "Cloning 'dotnet/dotnet' into $vmrDir.." + git clone https://github.com/dotnet/dotnet $vmrDir + + if ($vmrBranch) { + git -C $vmrDir switch -c $vmrBranch + } +} +else { + if ((git -C $vmrDir diff --quiet) -eq $false) { + Fail "There are changes in the working tree of $vmrDir. Please commit or stash your changes" + exit 1 + } + + if ($vmrBranch) { + Highlight "Preparing $vmrDir" + git -C $vmrDir checkout $vmrBranch + git -C $vmrDir pull + } +} + +Set-StrictMode -Version Latest + +# Prepare darc + +Highlight 'Installing .NET, preparing the tooling..' +. .\eng\common\tools.ps1 +$dotnetRoot = InitializeDotNetCli -install:$true +$dotnet = "$dotnetRoot\dotnet.exe" +& "$dotnet" tool restore + +Highlight "Starting the synchronization of VMR.." + +# Synchronize the VMR +$darcArgs = ( + "darc", "vmr", "forwardflow", + "--tmp", $tmpDir, + "--$verbosity", + $vmrDir +) + +if ($ci) { + $darcArgs += ("--ci") +} + +if ($azdevPat) { + $darcArgs += ("--azdev-pat", $azdevPat) +} + +& "$dotnet" $darcArgs + +if ($LASTEXITCODE -eq 0) { + Highlight "Synchronization succeeded" +} +else { + Fail "Synchronization of repo to VMR failed!" + Fail "'$vmrDir' is left in its last state (re-run of this script will reset it)." + Fail "Please inspect the logs which contain path to the failing patch file (use -debugOutput to get all the details)." + Fail "Once you make changes to the conflicting VMR patch, commit it locally and re-run this script." + exit 1 +} diff --git a/eng/common/vmr-sync.sh b/eng/common/vmr-sync.sh new file mode 100755 index 00000000000000..86d77ccf5b4822 --- /dev/null +++ b/eng/common/vmr-sync.sh @@ -0,0 +1,205 @@ +#!/bin/bash + +### This script is used for synchronizing the current repository into a local VMR. +### It pulls the current repository's code into the specified VMR directory for local testing or +### Source-Build validation. +### +### The tooling used for synchronization will clone the VMR repository into a temporary folder if +### it does not already exist. These clones can be reused in future synchronizations, so it is +### recommended to dedicate a folder for this to speed up re-runs. +### +### USAGE: +### Synchronize current repository into a local VMR: +### ./vmr-sync.sh --tmp "$HOME/repos/tmp" "$HOME/repos/dotnet" +### +### Options: +### -t, --tmp, --tmp-dir PATH +### Required. Path to the temporary folder where repositories will be cloned +### +### -b, --branch, --vmr-branch BRANCH_NAME +### Optional. Branch of the 'dotnet/dotnet' repo to synchronize. The VMR will be checked out to this branch +### +### --debug +### Optional. Turns on the most verbose logging for the VMR tooling +### +### --remote name:URI +### Optional. Additional remote to use during the synchronization +### This can be used to synchronize to a commit from a fork of the repository +### Example: 'runtime:https://github.com/yourfork/runtime' +### +### --azdev-pat +### Optional. Azure DevOps PAT to use for cloning private repositories. +### +### -v, --vmr, --vmr-dir PATH +### Optional. Path to the dotnet/dotnet repository. When null, gets cloned to the temporary folder + +source="${BASH_SOURCE[0]}" + +# resolve $source until the file is no longer a symlink +while [[ -h "$source" ]]; do + scriptroot="$( cd -P "$( dirname "$source" )" && pwd )" + source="$(readlink "$source")" + # if $source was a relative symlink, we need to resolve it relative to the path where the + # symlink file was located + [[ $source != /* ]] && source="$scriptroot/$source" +done +scriptroot="$( cd -P "$( dirname "$source" )" && pwd )" + +function print_help () { + sed -n '/^### /,/^$/p' "$source" | cut -b 5- +} + +COLOR_RED=$(tput setaf 1 2>/dev/null || true) +COLOR_CYAN=$(tput setaf 6 2>/dev/null || true) +COLOR_CLEAR=$(tput sgr0 2>/dev/null || true) +COLOR_RESET=uniquesearchablestring +FAILURE_PREFIX='> ' + +function fail () { + echo "${COLOR_RED}$FAILURE_PREFIX${1//${COLOR_RESET}/${COLOR_RED}}${COLOR_CLEAR}" >&2 +} + +function highlight () { + echo "${COLOR_CYAN}$FAILURE_PREFIX${1//${COLOR_RESET}/${COLOR_CYAN}}${COLOR_CLEAR}" +} + +tmp_dir='' +vmr_dir='' +vmr_branch='' +additional_remotes='' +verbosity=verbose +azdev_pat='' +ci=false + +while [[ $# -gt 0 ]]; do + opt="$(echo "$1" | tr "[:upper:]" "[:lower:]")" + case "$opt" in + -t|--tmp|--tmp-dir) + tmp_dir=$2 + shift + ;; + -v|--vmr|--vmr-dir) + vmr_dir=$2 + shift + ;; + -b|--branch|--vmr-branch) + vmr_branch=$2 + shift + ;; + --remote) + additional_remotes="$additional_remotes $2" + shift + ;; + --azdev-pat) + azdev_pat=$2 + shift + ;; + --ci) + ci=true + ;; + -d|--debug) + verbosity=debug + ;; + -h|--help) + print_help + exit 0 + ;; + *) + fail "Invalid argument: $1" + print_help + exit 1 + ;; + esac + + shift +done + +# Validation + +if [[ -z "$tmp_dir" ]]; then + fail "Missing --tmp-dir argument. Please specify the path to the temporary folder where the repositories will be cloned" + exit 1 +fi + +# Sanitize the input + +if [[ -z "$vmr_dir" ]]; then + vmr_dir="$tmp_dir/dotnet" +fi + +if [[ ! -d "$tmp_dir" ]]; then + mkdir -p "$tmp_dir" +fi + +if [[ "$verbosity" == "debug" ]]; then + set -x +fi + +# Prepare the VMR + +if [[ ! -d "$vmr_dir" ]]; then + highlight "Cloning 'dotnet/dotnet' into $vmr_dir.." + git clone https://github.com/dotnet/dotnet "$vmr_dir" + + if [[ -n "$vmr_branch" ]]; then + git -C "$vmr_dir" switch -c "$vmr_branch" + fi +else + if ! git -C "$vmr_dir" diff --quiet; then + fail "There are changes in the working tree of $vmr_dir. Please commit or stash your changes" + exit 1 + fi + + if [[ -n "$vmr_branch" ]]; then + highlight "Preparing $vmr_dir" + git -C "$vmr_dir" checkout "$vmr_branch" + git -C "$vmr_dir" pull + fi +fi + +set -e + +# Prepare darc + +highlight 'Installing .NET, preparing the tooling..' +source "./eng/common/tools.sh" +InitializeDotNetCli true +dotnetDir=$( cd ./.dotnet/; pwd -P ) +dotnet=$dotnetDir/dotnet +"$dotnet" tool restore + +highlight "Starting the synchronization of VMR.." +set +e + +if [[ -n "$additional_remotes" ]]; then + additional_remotes="--additional-remotes $additional_remotes" +fi + +if [[ -n "$azdev_pat" ]]; then + azdev_pat="--azdev-pat $azdev_pat" +fi + +ci_arg='' +if [[ "$ci" == "true" ]]; then + ci_arg="--ci" +fi + +# Synchronize the VMR + +"$dotnet" darc vmr forwardflow \ + --tmp "$tmp_dir" \ + $azdev_pat \ + --$verbosity \ + $ci_arg \ + $additional_remotes \ + "$vmr_dir" + +if [[ $? == 0 ]]; then + highlight "Synchronization succeeded" +else + fail "Synchronization of repo to VMR failed!" + fail "'$vmr_dir' is left in its last state (re-run of this script will reset it)." + fail "Please inspect the logs which contain path to the failing patch file (use --debug to get all the details)." + fail "Once you make changes to the conflicting VMR patch, commit it locally and re-run this script." + exit 1 +fi diff --git a/eng/native/signing/auth.json b/eng/native/signing/auth.json index 6d0230d8b63f75..a467bd95b55536 100644 --- a/eng/native/signing/auth.json +++ b/eng/native/signing/auth.json @@ -1,23 +1,20 @@ { "Version" : "1.0.0", - "AuthenticationType" : "AAD_CERT", + "AuthenticationType" : "AAD_MSI_WIF", "TenantId" : "975f013f-7f24-47e8-a7d3-abc4752bf346", "ClientId" : "22346933-af99-4e94-97d5-7fa1dcf4bba6", - "AuthCert" : - { - "SubjectName" : "CN=22346933-af99-4e94-97d5-7fa1dcf4bba6.microsoft.com", - "StoreLocation" : "CurrentUser", - "StoreName": "My", - "SendX5c" : "true", - "WithAzureRegion": false - }, + "EsrpClientId": "22346933-af99-4e94-97d5-7fa1dcf4bba6", "RequestSigningCert" : { "GetCertFromKeyVault" : true, "KeyVaultName": "clrdiag-esrp-pme", "KeyVaultCertName": "dac-dnceng-esrpclient-cert", "SendX5c": false, - "WithAzureRegion": false + "WithAzureRegion": false, + "StoreLocation": null, + "StoreName": null, + "SubjectName": null }, - "OAuthToken": null + "OAuthToken": null, + "FederatedTokenData": {} } diff --git a/eng/pipelines/common/templates/pipeline-with-resources.yml b/eng/pipelines/common/templates/pipeline-with-resources.yml index 85ed39a18a5ee3..eece5b6e50e5c3 100644 --- a/eng/pipelines/common/templates/pipeline-with-resources.yml +++ b/eng/pipelines/common/templates/pipeline-with-resources.yml @@ -64,10 +64,10 @@ extends: ROOTFS_DIR: /crossrootfs/x86 linux_x64_dev_innerloop: - image: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04 + image: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-24.04 linux_musl_x64_dev_innerloop: - image: mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.19-WithNode + image: mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.21-amd64 linux_x64_sanitizer: image: mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-net10.0-cross-amd64-sanitizer @@ -76,7 +76,7 @@ extends: # Used to test RHEL compatibility: CentOS Stream is upstream of RHEL SourceBuild_centos_x64: - image: mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream9 + image: mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream-10-amd64 # Used to test RHEL compatibility: Alma Linux is downstream of RHEL SourceBuild_linux_x64: @@ -106,7 +106,7 @@ extends: image: mcr.microsoft.com/dotnet-buildtools/prereqs:debian-12-gcc15-amd64 linux_x64_llvmaot: - image: mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream8 + image: mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream-10-amd64 browser_wasm: image: mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-net10.0-webassembly-amd64 diff --git a/eng/pipelines/coreclr/templates/install-diagnostic-certs.yml b/eng/pipelines/coreclr/templates/install-diagnostic-certs.yml deleted file mode 100644 index 32fb99b3590ba3..00000000000000 --- a/eng/pipelines/coreclr/templates/install-diagnostic-certs.yml +++ /dev/null @@ -1,39 +0,0 @@ -parameters: - isOfficialBuild: false - certNames: [] - vaultName: '' - azureSubscription: '' - scriptRoot: '$(Build.SourcesDirectory)' - -steps: -- ${{ if and(eq(parameters.isOfficialBuild, true), ne(variables['Build.Reason'], 'PullRequest'), or(startswith(variables['Build.SourceBranch'], 'refs/heads/release/'), startswith(variables['Build.SourceBranch'], 'refs/heads/internal/release/'), startswith(variables['Build.SourceBranch'], 'refs/heads/reltest/')), not(endsWith(variables['Build.SourceBranch'], '-staging'))) }}: - - task: AzureKeyVault@2 - inputs: - azureSubscription: ${{ parameters.azureSubscription }} - KeyVaultName: ${{ parameters.vaultName }} - SecretsFilter: ${{ join(',', parameters.certNames) }} - displayName: 'Download secrets: Diagnostic Certificates' - - - task: NuGetCommand@2 - displayName: Install ESRPClient Tool - inputs: - command: 'custom' - arguments: 'install microsoft.esrpclient - -Source https://dnceng.pkgs.visualstudio.com/_packaging/MicroBuildToolset/nuget/v3/index.json - -DependencyVersion Highest -OutputDirectory $(Build.StagingDirectory)' - - - powershell: | - eng/pipelines/install-diagnostic-certs.ps1 "${{ join(',', parameters.certNames) }}" - $esrpclient = Get-ChildItem -Path '$(Build.StagingDirectory)\microsoft.esrpclient*' -Filter esrpclient.exe -Recurse | Select-Object -First 1 | select -ExpandProperty FullName - - if ($esrpclient -eq $null) { - throw "Failed to find esrpclient.exe in $(Build.StagingDirectory)" - } - - $signArgs = "/p:DotNetEsrpToolPath=$esrpclient" - echo "##vso[task.setvariable variable=_SignDiagnosticFilesArgs;]$signArgs" - displayName: 'Install diagnostic certificates' - workingDirectory: ${{ parameters.scriptRoot }} - env: - ${{ each cert in parameters.certNames }}: - ${{ cert }}: $(${{ cert }}) diff --git a/eng/pipelines/coreclr/templates/remove-diagnostic-certs.yml b/eng/pipelines/coreclr/templates/remove-diagnostic-certs.yml deleted file mode 100644 index c510ea8f177cf7..00000000000000 --- a/eng/pipelines/coreclr/templates/remove-diagnostic-certs.yml +++ /dev/null @@ -1,11 +0,0 @@ -parameters: - isOfficialBuild: false - scriptRoot: '$(Build.SourcesDirectory)' - -steps: -- ${{ if and(eq(parameters.isOfficialBuild, true), ne(variables['Build.Reason'], 'PullRequest'), or(startswith(variables['Build.SourceBranch'], 'refs/heads/release/'), startswith(variables['Build.SourceBranch'], 'refs/heads/internal/release/'), startswith(variables['Build.SourceBranch'], 'refs/heads/reltest/')), not(endsWith(variables['Build.SourceBranch'], '-staging'))) }}: - - powershell: | - eng/pipelines/remove-diagnostic-certs.ps1 "$(DacCertificateThumbprints)" - workingDirectory: ${{ parameters.scriptRoot }} - displayName: 'Remove Diagnostic Certificates' - condition: always() diff --git a/eng/pipelines/extra-platforms/runtime-extra-platforms-android.yml b/eng/pipelines/extra-platforms/runtime-extra-platforms-android.yml index 7b9d41475f30e0..417241706c4c91 100644 --- a/eng/pipelines/extra-platforms/runtime-extra-platforms-android.yml +++ b/eng/pipelines/extra-platforms/runtime-extra-platforms-android.yml @@ -83,3 +83,34 @@ jobs: parameters: creator: dotnet-bot testRunNamePrefixSuffix: Mono_$(_BuildConfig) + +# +# Android devices +# Build the whole product using CoreCLR and run libraries tests +# +- template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/common/global-build-job.yml + helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml + buildConfig: Release + runtimeFlavor: coreclr + platforms: + - android_arm64 + variables: + # map dependencies variables to local variables + - name: librariesContainsChange + value: $[ stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_libraries.containsChange'] ] + - name: coreclrContainsChange + value: $[ stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_coreclr.containsChange'] ] + jobParameters: + testGroup: innerloop + nameSuffix: AllSubsets_CoreCLR + isExtraPlatforms: ${{ parameters.isExtraPlatformsBuild }} + buildArgs: -s clr.runtime+clr.alljits+clr.corelib+clr.nativecorelib+clr.tools+clr.packages+libs+libs.tests+host+packs -c $(_BuildConfig) /p:ArchiveTests=true $(_runSmokeTestsOnlyArg) + timeoutInMinutes: 480 + # extra steps, run tests + postBuildSteps: + - template: /eng/pipelines/libraries/helix.yml + parameters: + creator: dotnet-bot + testRunNamePrefixSuffix: CoreCLR_$(_BuildConfig) diff --git a/eng/pipelines/extra-platforms/runtime-extra-platforms-androidemulator.yml b/eng/pipelines/extra-platforms/runtime-extra-platforms-androidemulator.yml index 4badaf93186c0b..b7b3774f0b5a35 100644 --- a/eng/pipelines/extra-platforms/runtime-extra-platforms-androidemulator.yml +++ b/eng/pipelines/extra-platforms/runtime-extra-platforms-androidemulator.yml @@ -118,3 +118,34 @@ jobs: parameters: creator: dotnet-bot testRunNamePrefixSuffix: Mono_$(_BuildConfig) + +# +# Android emulators +# Build the whole product using CoreCLR and run libraries tests +# +- template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/common/global-build-job.yml + helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml + buildConfig: Release + runtimeFlavor: coreclr + platforms: + - android_x64 + variables: + # map dependencies variables to local variables + - name: librariesContainsChange + value: $[ stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_libraries.containsChange'] ] + - name: coreclrContainsChange + value: $[ stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_coreclr.containsChange'] ] + jobParameters: + testGroup: innerloop + nameSuffix: AllSubsets_CoreCLR + isExtraPlatforms: ${{ parameters.isExtraPlatformsBuild }} + buildArgs: -s clr.runtime+clr.alljits+clr.corelib+clr.nativecorelib+clr.tools+clr.packages+libs+libs.tests+host+packs -c $(_BuildConfig) /p:ArchiveTests=true $(_runSmokeTestsOnlyArg) + timeoutInMinutes: 240 + # extra steps, run tests + postBuildSteps: + - template: /eng/pipelines/libraries/helix.yml + parameters: + creator: dotnet-bot + testRunNamePrefixSuffix: CoreCLR_$(_BuildConfig) diff --git a/eng/pipelines/install-diagnostic-certs.ps1 b/eng/pipelines/install-diagnostic-certs.ps1 deleted file mode 100644 index 74d3c43f75739a..00000000000000 --- a/eng/pipelines/install-diagnostic-certs.ps1 +++ /dev/null @@ -1,32 +0,0 @@ -[CmdletBinding()] -param( - [string] - [Parameter(Mandatory)] - $certList -) -# Required for the pipeline logging functions -$ci = $true -. $PSScriptRoot/../common/pipeline-logging-functions.ps1 - -$certs = $certList -split ',' -$thumbprints = @() -$certCollection = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2Collection -foreach ($cert in $certs) -{ - $certBytes = [System.Convert]::FromBase64String($(Get-Item "Env:$cert").Value) - $certCollection.Import($certBytes,$null, [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::PersistKeySet) -} - -foreach ($cert in $certCollection) -{ - Write-Host "Installed certificate '$($cert.Thumbprint)' with subject: '$($cert.Subject)'" - $thumbprints += $cert.Thumbprint -} - -$store = Get-Item -Path Cert:\CurrentUser\My -$store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite) -$store.AddRange($certCollection) -$store.Close() - -Write-PipelineSetVariable -name "DacCertificateThumbprints" -Value "$($thumbprints -join ',')" -IsMultiJobVariable $false -Write-Host "Successfully installed diagnostic certificates" diff --git a/eng/pipelines/remove-diagnostic-certs.ps1 b/eng/pipelines/remove-diagnostic-certs.ps1 deleted file mode 100644 index 3ebea9f3e287ae..00000000000000 --- a/eng/pipelines/remove-diagnostic-certs.ps1 +++ /dev/null @@ -1,22 +0,0 @@ -[CmdletBinding()] -param( - [string] - [Parameter(Mandatory)] - $thumbprintList -) - -$thumbprints = $thumbprintList -split ',' -$store = Get-Item -Path Cert:\CurrentUser\My -$store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite) -foreach ($thumbprint in $thumbprints) -{ - $cert = $store.Certificates.Find([System.Security.Cryptography.X509Certificates.X509FindType]::FindByThumbprint, $thumbprint, $false) - if ($null -eq $cert) - { - Write-Host "Certificate with thumbprint '$thumbprint' not found in the user store." - } - $store.RemoveRange($cert) - Write-Host "Removed certificate '$thumbprint'" -} -$store.Close() -Write-Host "Successfully removed diagnostic certificates" diff --git a/eng/pipelines/runtime.yml b/eng/pipelines/runtime.yml index 7e1da71244461b..8ab3d80a4da963 100644 --- a/eng/pipelines/runtime.yml +++ b/eng/pipelines/runtime.yml @@ -956,7 +956,7 @@ extends: jobParameters: testGroup: innerloop nameSuffix: AllSubsets_CoreCLR - buildArgs: -s clr.runtime+clr.alljits+clr.corelib+clr.nativecorelib+clr.tools+clr.packages+libs++libs.tests+host+packs -c $(_BuildConfig) /p:ArchiveTests=true /p:TestAssemblies=false + buildArgs: -s clr.runtime+clr.alljits+clr.corelib+clr.nativecorelib+clr.tools+clr.packages+libs+libs.tests+host+packs -c $(_BuildConfig) /p:ArchiveTests=true /p:RunSmokeTestsOnly=true timeoutInMinutes: 480 condition: >- or( diff --git a/eng/testing/AndroidRunnerTemplate.cmd b/eng/testing/AndroidRunnerTemplate.cmd new file mode 100644 index 00000000000000..a1535a9e2b6e52 --- /dev/null +++ b/eng/testing/AndroidRunnerTemplate.cmd @@ -0,0 +1,47 @@ +@ECHO OFF +setlocal enabledelayedexpansion + +SET EXECUTION_DIR=%~dp0 +SET ASSEMBLY_NAME=%1 +SET TARGET_ARCH=%2 +SET TARGET_OS=%3 +SET TEST_NAME=%4 +SET REPO_ROOT=%5 + +:Arg_Loop +if "%6" == "" goto ArgsDone +set "__AdditionalArgs=!__AdditionalArgs! %6"&shift&goto Arg_Loop +:ArgsDone + +SET "XHARNESS_OUT=%EXECUTION_DIR%xharness-output" + +cd %EXECUTION_DIR% + +:lock +MKDIR androidtests.lock 2>NUL +IF "%errorlevel%" NEQ "0" ( + ping -n 6 127.0.0.1 >NUL + GOTO :lock +) + +IF [%XHARNESS_CLI_PATH%] NEQ [] ( + :: When running in CI, we only have the .NET runtime available + :: We need to call the XHarness CLI DLL directly via dotnet exec + SET HARNESS_RUNNER=%REPO_ROOT%dotnet.cmd exec "%XHARNESS_CLI_PATH%" +) ELSE ( + SET HARNESS_RUNNER=%REPO_ROOT%dotnet.cmd xharness +) + +%HARNESS_RUNNER% android test --instrumentation="net.dot.MonoRunner" --package-name="net.dot.%ASSEMBLY_NAME%" --app="%EXECUTION_DIR%bin\%TEST_NAME%.apk" --output-directory="%XHARNESS_OUT%" --timeout=1800 %__AdditionalArgs% + +SET EXIT_CODE=%ERRORLEVEL% + +ECHO XHarness artifacts: %XHARNESS_OUT% + +RMDIR /Q androidtests.lock 2>NUL +EXIT /B %EXIT_CODE% + +:: ========== FUNCTIONS ========== +:NORMALIZEPATH + SET RETVAL=%~f1 + EXIT /B diff --git a/eng/testing/tests.android.targets b/eng/testing/tests.android.targets index 3c3eb46fa28ebd..4144799c78f908 100644 --- a/eng/testing/tests.android.targets +++ b/eng/testing/tests.android.targets @@ -3,7 +3,7 @@ $(BundleTestAppTargets);BundleTestAndroidApp - + @@ -12,6 +12,10 @@ AndroidBuild + + $(DefineConstants);SINGLE_FILE_TEST_RUNNER + + @@ -22,7 +26,7 @@ AndroidTestRunner.dll - + $(PublishDir) $(BundleDir) @@ -44,7 +48,7 @@ <_InternalForceInterpret>true <_IsNative>true - + <_PublishAssemblies Include="$(PublishDir)\**\*.dll" Exclude="$(PublishDir)\**\*.resources.dll" /> <_SatelliteAssemblies Include="$(PublishDir)\**\*.resources.dll" /> @@ -73,4 +77,4 @@ - \ No newline at end of file + diff --git a/eng/testing/tests.targets b/eng/testing/tests.targets index 4ffbd60c365dc0..f05b4aa2a67c7b 100644 --- a/eng/testing/tests.targets +++ b/eng/testing/tests.targets @@ -1,14 +1,15 @@ - true - false + true + false RunnerTemplate.cmd RunnerTemplate.sh AppleHelixRunnerTemplate.sh AppleRunnerTemplate.sh - AndroidRunnerTemplate.sh + AndroidRunnerTemplate.sh + AndroidRunnerTemplate.cmd WasiRunnerTemplate.sh WasiRunnerTemplate.cmd WasmRunnerTemplate.sh @@ -172,7 +173,8 @@ TEST_ARCH=$(_AndroidArchitecture) "$(RunScriptOutputPath)" $(AssemblyName) $(TargetArchitecture) $(TargetOS) $(TestProjectName) $(RunTestsCommand) $(Configuration) $(AdditionalXHarnessArguments) - $(RunTestsCommand) $(AdditionalXHarnessArguments) + $(RunTestsCommand) $(AdditionalXHarnessArguments) + $(RunTestsCommand) $(RepoRoot) $(AdditionalXHarnessArguments) "$(RunScriptOutputPath)" $(JSEngine) $(AssemblyName).dll $(Scenario) diff --git a/global.json b/global.json index 8616c8a6541983..92dccfa062fa6a 100644 --- a/global.json +++ b/global.json @@ -1,18 +1,18 @@ { "sdk": { - "version": "10.0.100-preview.3.25201.16", + "version": "10.0.100-preview.5.25265.106", "allowPrerelease": true, "rollForward": "major" }, "tools": { - "dotnet": "10.0.100-preview.3.25201.16" + "dotnet": "10.0.100-preview.5.25265.106" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25260.104", - "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25260.104", - "Microsoft.DotNet.SharedFramework.Sdk": "10.0.0-beta.25260.104", + "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25270.108", + "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25270.108", + "Microsoft.DotNet.SharedFramework.Sdk": "10.0.0-beta.25270.108", "Microsoft.Build.NoTargets": "3.7.0", "Microsoft.Build.Traversal": "3.4.0", - "Microsoft.NET.Sdk.IL": "10.0.0-preview.5.25260.104" + "Microsoft.NET.Sdk.IL": "10.0.0-preview.5.25270.108" } } diff --git a/src/coreclr/.nuget/Microsoft.CrossOsDiag.Private.CoreCLR/Microsoft.CrossOsDiag.Private.CoreCLR.proj b/src/coreclr/.nuget/Microsoft.CrossOsDiag.Private.CoreCLR/Microsoft.CrossOsDiag.Private.CoreCLR.proj index d4f80483746781..a9e84b88cfdb18 100644 --- a/src/coreclr/.nuget/Microsoft.CrossOsDiag.Private.CoreCLR/Microsoft.CrossOsDiag.Private.CoreCLR.proj +++ b/src/coreclr/.nuget/Microsoft.CrossOsDiag.Private.CoreCLR/Microsoft.CrossOsDiag.Private.CoreCLR.proj @@ -8,7 +8,7 @@ In dotnet/runtime's official build, we'll extract the runtime packs to a specific directory and pass that here. In the VMR, we'll restore the runtime packs as NuGet packages. --> - + $(NuGetPackageRoot) @@ -24,7 +24,7 @@ - + diff --git a/src/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.cs index e0a24a42ef3223..8a10a83972b8ff 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.cs @@ -108,21 +108,5 @@ private static unsafe string[] InitializeCommandLineArgs(char* exePath, int argc // Used by VM internal static string? GetResourceStringLocal(string key) => SR.GetResourceString(key); - - /// Gets the number of milliseconds elapsed since the system started. - /// A 32-bit signed integer containing the amount of time in milliseconds that has passed since the last time the computer was started. - public static extern int TickCount - { - [MethodImpl(MethodImplOptions.InternalCall)] - get; - } - - /// Gets the number of milliseconds elapsed since the system started. - /// A 64-bit signed integer containing the amount of time in milliseconds that has passed since the last time the computer was started. - public static extern long TickCount64 - { - [MethodImpl(MethodImplOptions.InternalCall)] - get; - } } } diff --git a/src/coreclr/classlibnative/bcltype/system.cpp b/src/coreclr/classlibnative/bcltype/system.cpp index 30845baa04b0b3..30b215f6c9d344 100644 --- a/src/coreclr/classlibnative/bcltype/system.cpp +++ b/src/coreclr/classlibnative/bcltype/system.cpp @@ -32,24 +32,6 @@ #include - -FCIMPL0(UINT32, SystemNative::GetTickCount) -{ - FCALL_CONTRACT; - - return ::GetTickCount(); -} -FCIMPLEND; - -FCIMPL0(UINT64, SystemNative::GetTickCount64) -{ - FCALL_CONTRACT; - - return ::GetTickCount64(); -} -FCIMPLEND; - - extern "C" VOID QCALLTYPE Environment_Exit(INT32 exitcode) { QCALL_CONTRACT; diff --git a/src/coreclr/classlibnative/bcltype/system.h b/src/coreclr/classlibnative/bcltype/system.h index 89d25005364d6f..11b4939cc715ea 100644 --- a/src/coreclr/classlibnative/bcltype/system.h +++ b/src/coreclr/classlibnative/bcltype/system.h @@ -37,9 +37,6 @@ class SystemNative public: // Functions on the System.Environment class - static FCDECL0(UINT32, GetTickCount); - static FCDECL0(UINT64, GetTickCount64); - static FCDECL1(VOID,SetExitCode,INT32 exitcode); static FCDECL0(INT32, GetExitCode); diff --git a/src/coreclr/debug/createdump/config.h.in b/src/coreclr/debug/createdump/config.h.in index 792d8a5988bef9..ee8701be0cf9c0 100644 --- a/src/coreclr/debug/createdump/config.h.in +++ b/src/coreclr/debug/createdump/config.h.in @@ -4,5 +4,3 @@ #pragma once #cmakedefine HAVE_PROCESS_VM_READV -#cmakedefine01 HAVE_CLOCK_GETTIME_NSEC_NP -#cmakedefine01 HAVE_CLOCK_MONOTONIC diff --git a/src/coreclr/debug/createdump/configure.cmake b/src/coreclr/debug/createdump/configure.cmake index 4ba6320f4c9309..9587b3f75f392a 100644 --- a/src/coreclr/debug/createdump/configure.cmake +++ b/src/coreclr/debug/createdump/configure.cmake @@ -1,22 +1,3 @@ check_function_exists(process_vm_readv HAVE_PROCESS_VM_READV) -check_symbol_exists( - clock_gettime_nsec_np - time.h - HAVE_CLOCK_GETTIME_NSEC_NP) - -check_cxx_source_runs(" -#include -#include -#include - -int main() -{ - int ret; - struct timespec ts; - ret = clock_gettime(CLOCK_MONOTONIC, &ts); - - exit(ret); -}" HAVE_CLOCK_MONOTONIC) - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h) diff --git a/src/coreclr/debug/createdump/createdumpmain.cpp b/src/coreclr/debug/createdump/createdumpmain.cpp index 5f54b07d03dfaf..b3426a31d2aa99 100644 --- a/src/coreclr/debug/createdump/createdumpmain.cpp +++ b/src/coreclr/debug/createdump/createdumpmain.cpp @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. #include "createdump.h" +#include "minipal/time.h" #ifdef HOST_WINDOWS #define DEFAULT_DUMP_PATH "%TEMP%\\" @@ -45,8 +46,6 @@ bool g_diagnostics = false; bool g_diagnosticsVerbose = false; uint64_t g_ticksPerMS = 0; uint64_t g_startTime = 0; -uint64_t GetTickFrequency(); -uint64_t GetTimeStamp(); // // Common entry point @@ -198,8 +197,8 @@ int createdump_main(const int argc, const char* argv[]) return -1; } - g_ticksPerMS = GetTickFrequency() / 1000UL; - g_startTime = GetTimeStamp(); + g_ticksPerMS = minipal_hires_tick_frequency() / 1000UL; + g_startTime = minipal_hires_ticks(); TRACE("TickFrequency: %d ticks per ms\n", g_ticksPerMS); ArrayHolder tmpPath = new char[MAX_LONGPATH]; @@ -221,11 +220,11 @@ int createdump_main(const int argc, const char* argv[]) if (CreateDump(options)) { - printf_status("Dump successfully written in %llums\n", GetTimeStamp() - g_startTime); + printf_status("Dump successfully written in %llums\n", (minipal_hires_ticks() - g_startTime) / g_ticksPerMS); } else { - printf_error("Failure took %llums\n", GetTimeStamp() - g_startTime); + printf_error("Failure took %llums\n", (minipal_hires_ticks() - g_startTime) / g_ticksPerMS); exitCode = -1; } @@ -332,24 +331,6 @@ printf_error(const char* format, ...) va_end(args); } -uint64_t -GetTickFrequency() -{ - LARGE_INTEGER ret; - ZeroMemory(&ret, sizeof(LARGE_INTEGER)); - QueryPerformanceFrequency(&ret); - return ret.QuadPart; -} - -uint64_t -GetTimeStamp() -{ - LARGE_INTEGER ret; - ZeroMemory(&ret, sizeof(LARGE_INTEGER)); - QueryPerformanceCounter(&ret); - return ret.QuadPart / g_ticksPerMS; -} - #ifdef HOST_UNIX static void @@ -360,7 +341,7 @@ trace_prefix(const char* format, va_list args) { fprintf(g_stdout, "[createdump] "); } - fprintf(g_stdout, "%08" PRIx64 " ", GetTimeStamp()); + fprintf(g_stdout, "%08" PRIx64 " ", minipal_hires_ticks() / g_ticksPerMS); vfprintf(g_stdout, format, args); fflush(g_stdout); } diff --git a/src/coreclr/debug/createdump/createdumppal.cpp b/src/coreclr/debug/createdump/createdumppal.cpp index 88e57ef7e8541c..fa6856ef2edf25 100644 --- a/src/coreclr/debug/createdump/createdumppal.cpp +++ b/src/coreclr/debug/createdump/createdumppal.cpp @@ -96,52 +96,6 @@ UninitializePAL( } } -#define tccSecondsToNanoSeconds 1000000000 // 10^9 - -BOOL -PALAPI -QueryPerformanceCounter( - OUT LARGE_INTEGER* lpPerformanceCount) -{ -#if HAVE_CLOCK_GETTIME_NSEC_NP - lpPerformanceCount->QuadPart = (LONGLONG)clock_gettime_nsec_np(CLOCK_UPTIME_RAW); -#elif HAVE_CLOCK_MONOTONIC - struct timespec ts; - int result = clock_gettime(CLOCK_MONOTONIC, &ts); - if (result != 0) - { - return TRUE; - } - else - { - lpPerformanceCount->QuadPart = ((LONGLONG)(ts.tv_sec) * (LONGLONG)(tccSecondsToNanoSeconds)) + (LONGLONG)(ts.tv_nsec); - } -#else - #error "The createdump requires either mach_absolute_time() or clock_gettime(CLOCK_MONOTONIC) to be supported." -#endif - return TRUE; -} - -BOOL -PALAPI -QueryPerformanceFrequency( - OUT LARGE_INTEGER* lpFrequency) -{ -#if HAVE_CLOCK_GETTIME_NSEC_NP - lpFrequency->QuadPart = (LONGLONG)(tccSecondsToNanoSeconds); -#elif HAVE_CLOCK_MONOTONIC - // clock_gettime() returns a result in terms of nanoseconds rather than a count. This - // means that we need to either always scale the result by the actual resolution (to - // get a count) or we need to say the resolution is in terms of nanoseconds. We prefer - // the latter since it allows the highest throughput and should minimize error propagated - // to the user. - lpFrequency->QuadPart = (LONGLONG)(tccSecondsToNanoSeconds); -#else - #error "The createdump requires either mach_absolute_time() or clock_gettime(CLOCK_MONOTONIC) to be supported." -#endif - return TRUE; -} - #define TEMP_DIRECTORY_PATH "/tmp/" DWORD diff --git a/src/coreclr/dlls/mscordac/mscordac_unixexports.src b/src/coreclr/dlls/mscordac/mscordac_unixexports.src index 206ae4091b7c82..a0d5128a5f48de 100644 --- a/src/coreclr/dlls/mscordac/mscordac_unixexports.src +++ b/src/coreclr/dlls/mscordac/mscordac_unixexports.src @@ -113,8 +113,6 @@ nativeStringResourceTable_mscorrc #OutputDebugStringW #OpenEventW #OutputDebugStringA -#QueryPerformanceCounter -#QueryPerformanceFrequency #RaiseException #RaiseFailFastException #ReadFile diff --git a/src/coreclr/gc/CMakeLists.txt b/src/coreclr/gc/CMakeLists.txt index 56956ed25f0496..a7bdcfc633368d 100644 --- a/src/coreclr/gc/CMakeLists.txt +++ b/src/coreclr/gc/CMakeLists.txt @@ -85,12 +85,14 @@ if(CLR_CMAKE_HOST_WIN32) advapi32.lib) endif(CLR_CMAKE_HOST_WIN32) -set (GC_LINK_LIBRARIES ${GC_LINK_LIBRARIES} gc_pal) +set (GC_LINK_LIBRARIES + ${GC_LINK_LIBRARIES} + gc_pal + minipal) if(CLR_CMAKE_TARGET_ARCH_AMD64) list(APPEND GC_LINK_LIBRARIES gc_vxsort - minipal ) endif(CLR_CMAKE_TARGET_ARCH_AMD64) diff --git a/src/coreclr/gc/unix/config.gc.h.in b/src/coreclr/gc/unix/config.gc.h.in index dfc38aea6b8470..cf6902460b9725 100644 --- a/src/coreclr/gc/unix/config.gc.h.in +++ b/src/coreclr/gc/unix/config.gc.h.in @@ -17,7 +17,6 @@ #cmakedefine01 HAVE_SYSCTLBYNAME #cmakedefine01 HAVE_PTHREAD_CONDATTR_SETCLOCK #cmakedefine01 HAVE_CLOCK_GETTIME_NSEC_NP -#cmakedefine01 HAVE_CLOCK_MONOTONIC #cmakedefine01 HAVE_SCHED_GETAFFINITY #cmakedefine01 HAVE_SCHED_SETAFFINITY #cmakedefine01 HAVE_PTHREAD_SETAFFINITY_NP diff --git a/src/coreclr/gc/unix/configure.cmake b/src/coreclr/gc/unix/configure.cmake index 8d33b81a32f727..0cc66c3e4aecea 100644 --- a/src/coreclr/gc/unix/configure.cmake +++ b/src/coreclr/gc/unix/configure.cmake @@ -89,20 +89,6 @@ check_symbol_exists( time.h HAVE_CLOCK_GETTIME_NSEC_NP) -check_cxx_source_runs(" -#include -#include -#include - -int main() -{ - int ret; - struct timespec ts; - ret = clock_gettime(CLOCK_MONOTONIC, &ts); - - exit(ret); -}" HAVE_CLOCK_MONOTONIC) - check_symbol_exists( posix_madvise sys/mman.h diff --git a/src/coreclr/gc/unix/gcenv.unix.cpp b/src/coreclr/gc/unix/gcenv.unix.cpp index 5a199f4b7db69e..2eb8e1acdba73d 100644 --- a/src/coreclr/gc/unix/gcenv.unix.cpp +++ b/src/coreclr/gc/unix/gcenv.unix.cpp @@ -24,6 +24,7 @@ #include "gcconfig.h" #include "numasupport.h" #include +#include #if HAVE_SWAPCTL #include @@ -1449,22 +1450,7 @@ void GCToOSInterface::GetMemoryStatus(uint64_t restricted_limit, uint32_t* memor // The counter value int64_t GCToOSInterface::QueryPerformanceCounter() { -#if HAVE_CLOCK_GETTIME_NSEC_NP - return (int64_t)clock_gettime_nsec_np(CLOCK_UPTIME_RAW); -#elif HAVE_CLOCK_MONOTONIC - struct timespec ts; - int result = clock_gettime(CLOCK_MONOTONIC, &ts); - - if (result != 0) - { - assert(!"clock_gettime(CLOCK_MONOTONIC) failed"); - __UNREACHABLE(); - } - - return ((int64_t)(ts.tv_sec) * (int64_t)(tccSecondsToNanoSeconds)) + (int64_t)(ts.tv_nsec); -#else -#error " clock_gettime(CLOCK_MONOTONIC) or clock_gettime_nsec_np() must be supported." -#endif + return minipal_hires_ticks(); } // Get a frequency of the high precision performance counter @@ -1473,7 +1459,7 @@ int64_t GCToOSInterface::QueryPerformanceCounter() int64_t GCToOSInterface::QueryPerformanceFrequency() { // The counter frequency of gettimeofday is in microseconds. - return tccSecondsToNanoSeconds; + return minipal_hires_tick_frequency(); } // Get a time stamp with a low precision @@ -1481,42 +1467,7 @@ int64_t GCToOSInterface::QueryPerformanceFrequency() // Time stamp in milliseconds uint64_t GCToOSInterface::GetLowPrecisionTimeStamp() { - uint64_t retval = 0; - -#if HAVE_CLOCK_GETTIME_NSEC_NP - retval = clock_gettime_nsec_np(CLOCK_UPTIME_RAW) / tccMilliSecondsToNanoSeconds; -#elif HAVE_CLOCK_MONOTONIC - struct timespec ts; - -#if HAVE_CLOCK_MONOTONIC_COARSE - clockid_t clockType = CLOCK_MONOTONIC_COARSE; // good enough resolution, fastest speed -#else - clockid_t clockType = CLOCK_MONOTONIC; -#endif - - if (clock_gettime(clockType, &ts) != 0) - { -#if HAVE_CLOCK_MONOTONIC_COARSE - assert(!"clock_gettime(HAVE_CLOCK_MONOTONIC_COARSE) failed\n"); -#else - assert(!"clock_gettime(CLOCK_MONOTONIC) failed\n"); -#endif - } - - retval = (ts.tv_sec * tccSecondsToMilliSeconds) + (ts.tv_nsec / tccMilliSecondsToNanoSeconds); -#else - struct timeval tv; - if (gettimeofday(&tv, NULL) == 0) - { - retval = (tv.tv_sec * tccSecondsToMilliSeconds) + (tv.tv_usec / tccMilliSecondsToMicroSeconds); - } - else - { - assert(!"gettimeofday() failed\n"); - } -#endif - - return retval; + return (uint64_t)minipal_lowres_ticks(); } // Gets the total number of processors on the machine, not taking diff --git a/src/coreclr/ilasm/assembler.h b/src/coreclr/ilasm/assembler.h index b2b2d30a9c08dd..46a8119c073dd6 100644 --- a/src/coreclr/ilasm/assembler.h +++ b/src/coreclr/ilasm/assembler.h @@ -644,22 +644,22 @@ typedef FIFO MethodBodyList; struct Clockwork { - DWORD cBegin; - DWORD cEnd; - DWORD cParsBegin; - DWORD cParsEnd; - DWORD cMDInitBegin; - DWORD cMDInitEnd; - DWORD cMDEmitBegin; - DWORD cMDEmitEnd; - DWORD cMDEmit1; - DWORD cMDEmit2; - DWORD cMDEmit3; - DWORD cMDEmit4; - DWORD cRef2DefBegin; - DWORD cRef2DefEnd; - DWORD cFilegenBegin; - DWORD cFilegenEnd; + int64_t cBegin; + int64_t cEnd; + int64_t cParsBegin; + int64_t cParsEnd; + int64_t cMDInitBegin; + int64_t cMDInitEnd; + int64_t cMDEmitBegin; + int64_t cMDEmitEnd; + int64_t cMDEmit1; + int64_t cMDEmit2; + int64_t cMDEmit3; + int64_t cMDEmit4; + int64_t cRef2DefBegin; + int64_t cRef2DefEnd; + int64_t cFilegenBegin; + int64_t cFilegenEnd; }; struct TypeDefDescr diff --git a/src/coreclr/ilasm/ilasmpch.h b/src/coreclr/ilasm/ilasmpch.h index a6a62fe9ea814a..cbc5fd0b3d1d39 100644 --- a/src/coreclr/ilasm/ilasmpch.h +++ b/src/coreclr/ilasm/ilasmpch.h @@ -24,6 +24,7 @@ #include "mdfileformat.h" #include "stgpooli.h" +#include "minipal/time.h" #ifdef _EXPORT #undef _EXPORT diff --git a/src/coreclr/ilasm/main.cpp b/src/coreclr/ilasm/main.cpp index a7c824e4dfc397..da5fecb405b977 100644 --- a/src/coreclr/ilasm/main.cpp +++ b/src/coreclr/ilasm/main.cpp @@ -139,7 +139,7 @@ extern "C" int _cdecl wmain(int argc, _In_ WCHAR **argv) memset(pwzInputFiles,0,1024*sizeof(WCHAR*)); memset(pwzDeltaFiles,0,1024*sizeof(WCHAR*)); memset(&cw,0,sizeof(Clockwork)); - cw.cBegin = GetTickCount(); + cw.cBegin = minipal_lowres_ticks(); g_uConsoleCP = GetConsoleOutputCP(); memset(wzOutputFilename,0,sizeof(wzOutputFilename)); @@ -667,7 +667,7 @@ extern "C" int _cdecl wmain(int argc, _In_ WCHAR **argv) { int iFile; BOOL fAllFilesPresent = TRUE; - if(bClock) cw.cParsBegin = GetTickCount(); + if(bClock) cw.cParsBegin = minipal_lowres_ticks(); for(iFile = 0; iFile < NumFiles; iFile++) { uCodePage = CP_UTF8; @@ -723,7 +723,7 @@ extern "C" int _cdecl wmain(int argc, _In_ WCHAR **argv) delete pIn; } } // end for(iFile) - if(bClock) cw.cParsEnd = GetTickCount(); + if(bClock) cw.cParsEnd = minipal_lowres_ticks(); if ((pParser->Success() && fAllFilesPresent) || pAsm->OnErrGo) { HRESULT hr; @@ -746,7 +746,7 @@ extern "C" int _cdecl wmain(int argc, _In_ WCHAR **argv) } if(exitval == 0) // Write the output file { - if(bClock) cw.cFilegenEnd = GetTickCount(); + if(bClock) cw.cFilegenEnd = minipal_lowres_ticks(); if(pAsm->m_fReportProgress) pParser->msg("Writing PE file\n"); // Generate the file if (FAILED(hr = pAsm->m_pCeeFileGen->GenerateCeeFile(pAsm->m_pCeeFile))) @@ -764,7 +764,7 @@ extern "C" int _cdecl wmain(int argc, _In_ WCHAR **argv) pParser->msg("Failed to write PDB file, error code=0x%08X\n", hr); } } - if(bClock) cw.cEnd = GetTickCount(); + if(bClock) cw.cEnd = minipal_lowres_ticks(); if(exitval==0) { WCHAR wzNewOutputFilename[MAX_FILENAME_LENGTH+16]; @@ -854,21 +854,21 @@ extern "C" int _cdecl wmain(int argc, _In_ WCHAR **argv) if(bReportProgress) printf("Operation completed successfully\n"); if(bClock) { - printf("Timing (msec): Total run %d\n",(cw.cEnd-cw.cBegin)); - printf(" Startup %d\n",(cw.cParsBegin-cw.cBegin)); - printf(" - MD initialization %d\n",(cw.cMDInitEnd - cw.cMDInitBegin)); - printf(" Parsing %d\n",(cw.cParsEnd - cw.cParsBegin)); - printf(" Emitting MD %d\n",(cw.cMDEmitEnd - cw.cRef2DefEnd)+(cw.cRef2DefBegin - cw.cMDEmitBegin)); - //printf(" - global fixups %d\n",(cw.cMDEmit1 - cw.cMDEmitBegin)); - printf(" - SN sig alloc %d\n",(cw.cMDEmit2 - cw.cMDEmitBegin)); - printf(" - Classes,Methods,Fields %d\n",(cw.cRef2DefBegin - cw.cMDEmit2)); - printf(" - Events,Properties %d\n",(cw.cMDEmit3 - cw.cRef2DefEnd)); - printf(" - MethodImpls %d\n",(cw.cMDEmit4 - cw.cMDEmit3)); - printf(" - Manifest,CAs %d\n",(cw.cMDEmitEnd - cw.cMDEmit4)); - printf(" Ref to Def resolution %d\n",(cw.cRef2DefEnd - cw.cRef2DefBegin)); - printf(" Fixup and linking %d\n",(cw.cFilegenBegin - cw.cMDEmitEnd)); - printf(" CEE file generation %d\n",(cw.cFilegenEnd - cw.cFilegenBegin)); - printf(" PE file writing %d\n",(cw.cEnd - cw.cFilegenEnd)); + printf("Timing (msec): Total run %d\n",(int)(cw.cEnd-cw.cBegin)); + printf(" Startup %d\n",(int)(cw.cParsBegin-cw.cBegin)); + printf(" - MD initialization %d\n",(int)(cw.cMDInitEnd - cw.cMDInitBegin)); + printf(" Parsing %d\n",(int)(cw.cParsEnd - cw.cParsBegin)); + printf(" Emitting MD %d\n",(int)(cw.cMDEmitEnd - cw.cRef2DefEnd)+(int)(cw.cRef2DefBegin - cw.cMDEmitBegin)); + //printf(" - global fixups %d\n",(int)(cw.cMDEmit1 - cw.cMDEmitBegin)); + printf(" - SN sig alloc %d\n",(int)(cw.cMDEmit2 - cw.cMDEmitBegin)); + printf(" - Classes,Methods,Fields %d\n",(int)(cw.cRef2DefBegin - cw.cMDEmit2)); + printf(" - Events,Properties %d\n",(int)(cw.cMDEmit3 - cw.cRef2DefEnd)); + printf(" - MethodImpls %d\n",(int)(cw.cMDEmit4 - cw.cMDEmit3)); + printf(" - Manifest,CAs %d\n",(int)(cw.cMDEmitEnd - cw.cMDEmit4)); + printf(" Ref to Def resolution %d\n",(int)(cw.cRef2DefEnd - cw.cRef2DefBegin)); + printf(" Fixup and linking %d\n",(int)(cw.cFilegenBegin - cw.cMDEmitEnd)); + printf(" CEE file generation %d\n",(int)(cw.cFilegenEnd - cw.cFilegenBegin)); + printf(" PE file writing %d\n",(int)(cw.cEnd - cw.cFilegenEnd)); } } else diff --git a/src/coreclr/ilasm/writer.cpp b/src/coreclr/ilasm/writer.cpp index 1667f0fdea1abb..9b05cd6aa13692 100644 --- a/src/coreclr/ilasm/writer.cpp +++ b/src/coreclr/ilasm/writer.cpp @@ -28,7 +28,7 @@ HRESULT Assembler::InitMetaData() if(m_fInitialisedMetaData) return S_OK; - if(bClock) bClock->cMDInitBegin = GetTickCount(); + if(bClock) bClock->cMDInitBegin = minipal_lowres_ticks(); hr = MetaDataGetDispenser(CLSID_CorMetaDataDispenser, IID_IMetaDataDispenserEx2, (void **)&m_pDisp); @@ -93,7 +93,7 @@ HRESULT Assembler::InitMetaData() hr = S_OK; exit: - if(bClock) bClock->cMDInitEnd = GetTickCount(); + if(bClock) bClock->cMDInitEnd = minipal_lowres_ticks(); return hr; } /*********************************************************************************/ @@ -1172,7 +1172,7 @@ HRESULT Assembler::CreatePEFile(_In_ __nullterminated WCHAR *pwzOutputFilename) GUID deterministicGuid = GUID(); ULONG deterministicTimestamp = 0; - if(bClock) bClock->cMDEmitBegin = GetTickCount(); + if(bClock) bClock->cMDEmitBegin = minipal_lowres_ticks(); if(m_fReportProgress) printf("Creating PE file\n"); if (!m_pEmitter) { @@ -1185,7 +1185,7 @@ HRESULT Assembler::CreatePEFile(_In_ __nullterminated WCHAR *pwzOutputFilename) if(!OnErrGo) return E_FAIL; } - if(bClock) bClock->cMDEmit1 = GetTickCount(); + if(bClock) bClock->cMDEmit1 = minipal_lowres_ticks(); // Allocate space for a strong name signature if we're delay or full // signing the assembly. @@ -1200,7 +1200,7 @@ HRESULT Assembler::CreatePEFile(_In_ __nullterminated WCHAR *pwzOutputFilename) m_dwComImageFlags |= COMIMAGE_FLAGS_STRONGNAMESIGNED; } - if(bClock) bClock->cMDEmit2 = GetTickCount(); + if(bClock) bClock->cMDEmit2 = minipal_lowres_ticks(); if(m_VTFList.COUNT()==0) { @@ -1327,9 +1327,9 @@ HRESULT Assembler::CreatePEFile(_In_ __nullterminated WCHAR *pwzOutputFilename) } // All ref'ed items def'ed in this file are emitted, resolve member refs to member defs: - if(bClock) bClock->cRef2DefBegin = GetTickCount(); + if(bClock) bClock->cRef2DefBegin = minipal_lowres_ticks(); hr = ResolveLocalMemberRefs(); - if(bClock) bClock->cRef2DefEnd = GetTickCount(); + if(bClock) bClock->cRef2DefEnd = minipal_lowres_ticks(); if(FAILED(hr) &&(!OnErrGo)) goto exit; // Local member refs resolved, emit events, props and method impls @@ -1352,7 +1352,7 @@ HRESULT Assembler::CreatePEFile(_In_ __nullterminated WCHAR *pwzOutputFilename) pSearch->m_fNewMembers = FALSE; } } - if(bClock) bClock->cMDEmit3 = GetTickCount(); + if(bClock) bClock->cMDEmit3 = minipal_lowres_ticks(); if(m_MethodImplDList.COUNT()) { if(m_fReportProgress) report->msg("Method Implementations (total): %d\n",m_MethodImplDList.COUNT()); @@ -1362,7 +1362,7 @@ HRESULT Assembler::CreatePEFile(_In_ __nullterminated WCHAR *pwzOutputFilename) } } // Emit the rest of the metadata - if(bClock) bClock->cMDEmit4 = GetTickCount(); + if(bClock) bClock->cMDEmit4 = minipal_lowres_ticks(); hr = S_OK; if(m_pManifest) { @@ -1400,7 +1400,7 @@ HRESULT Assembler::CreatePEFile(_In_ __nullterminated WCHAR *pwzOutputFilename) delete pTDD; } } - if(bClock) bClock->cMDEmitEnd = GetTickCount(); + if(bClock) bClock->cMDEmitEnd = minipal_lowres_ticks(); hr = DoLocalMemberRefFixups(); if(FAILED(hr) &&(!OnErrGo)) goto exit; @@ -1709,7 +1709,7 @@ HRESULT Assembler::CreatePEFile(_In_ __nullterminated WCHAR *pwzOutputFilename) if (FAILED(hr)) goto exit; } - if(bClock) bClock->cFilegenBegin = GetTickCount(); + if(bClock) bClock->cFilegenBegin = minipal_lowres_ticks(); // actually output the meta-data if (FAILED(hr=m_pCeeFileGen->EmitMetaDataAt(m_pCeeFile, m_pEmitter, m_pILSection, metaDataOffset, metaData, metaDataSize))) goto exit; diff --git a/src/coreclr/inc/random.h b/src/coreclr/inc/random.h index 6a8d7001b20430..98d24d2f17834b 100644 --- a/src/coreclr/inc/random.h +++ b/src/coreclr/inc/random.h @@ -19,6 +19,7 @@ #define _CLRRANDOM_H_ #include +#include "minipal/time.h" // // Forbid the use of srand()/rand(), as these are globally shared facilities and our use of them would @@ -73,10 +74,7 @@ class CLRRandom void Init() { LIMITED_METHOD_CONTRACT; - LARGE_INTEGER time; - if (!QueryPerformanceCounter(&time)) - time.QuadPart = GetTickCount(); - Init((int)time.u.LowPart ^ GetCurrentThreadId() ^ GetCurrentProcessId()); + Init((int)minipal_hires_ticks() ^ GetCurrentThreadId() ^ GetCurrentProcessId()); } void Init(int Seed) diff --git a/src/coreclr/inc/utilcode.h b/src/coreclr/inc/utilcode.h index b94b6b45866a5c..d36b1627e611c9 100644 --- a/src/coreclr/inc/utilcode.h +++ b/src/coreclr/inc/utilcode.h @@ -729,8 +729,6 @@ void SplitPathInterior( #include "ostype.h" -#define CLRGetTickCount64() GetTickCount64() - // // Allocate free memory within the range [pMinAddr..pMaxAddr] using // ClrVirtualQuery to find free memory and ClrVirtualAlloc to allocate it. diff --git a/src/coreclr/interpreter/compiler.cpp b/src/coreclr/interpreter/compiler.cpp index b2ea69924dbdc6..9b3a3a809a26f8 100644 --- a/src/coreclr/interpreter/compiler.cpp +++ b/src/coreclr/interpreter/compiler.cpp @@ -1736,6 +1736,7 @@ int32_t InterpCompiler::GetDataItemIndexForHelperFtn(CorInfoHelpFunc ftn) size_t data = !direct ? (size_t)indirect | INTERP_INDIRECT_HELPER_TAG : (size_t)direct; + assert(data); return GetDataItemIndex((void*)data); } @@ -3710,6 +3711,45 @@ int InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo) break; } + case CEE_LDTOKEN: + { + AddIns(INTOP_LDTOKEN); + + CORINFO_RESOLVED_TOKEN resolvedToken; + ResolveToken(getU4LittleEndian(m_ip + 1), CORINFO_TOKENKIND_Ldtoken, &resolvedToken); + + CORINFO_CLASS_HANDLE clsHnd = m_compHnd->getTokenTypeAsHandle(&resolvedToken); + PushStackType(StackTypeVT, clsHnd); + m_pLastNewIns->SetDVar(m_pStackPointer[-1].var); + + // see jit/importer.cpp CEE_LDTOKEN + CorInfoHelpFunc helper; + if (resolvedToken.hClass) + { + helper = CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE; + m_pLastNewIns->data[0] = GetDataItemIndex(resolvedToken.hClass); + } + else if (resolvedToken.hMethod) + { + helper = CORINFO_HELP_METHODDESC_TO_STUBRUNTIMEMETHOD; + m_pLastNewIns->data[0] = GetDataItemIndex(resolvedToken.hMethod); + } + else if (resolvedToken.hField) + { + helper = CORINFO_HELP_FIELDDESC_TO_STUBRUNTIMEFIELD; + m_pLastNewIns->data[0] = GetDataItemIndex(resolvedToken.hField); + } + else + { + helper = CORINFO_HELP_FAIL_FAST; + assert(!"Token not resolved or resolved to unexpected type"); + } + + m_pLastNewIns->data[1] = GetDataItemIndexForHelperFtn(helper); + m_ip += 5; + break; + } + default: assert(0); break; diff --git a/src/coreclr/interpreter/interpretershared.h b/src/coreclr/interpreter/interpretershared.h index f4a93666f2906c..14b25f71c2c82f 100644 --- a/src/coreclr/interpreter/interpretershared.h +++ b/src/coreclr/interpreter/interpretershared.h @@ -16,6 +16,9 @@ struct InterpMethod { +#if DEBUG + InterpMethod *self; +#endif CORINFO_METHOD_HANDLE methodHnd; int32_t allocaSize; void** pDataItems; @@ -23,11 +26,23 @@ struct InterpMethod InterpMethod(CORINFO_METHOD_HANDLE methodHnd, int32_t allocaSize, void** pDataItems, bool initLocals) { +#if DEBUG + this->self = this; +#endif this->methodHnd = methodHnd; this->allocaSize = allocaSize; this->pDataItems = pDataItems; this->initLocals = initLocals; } + + bool CheckIntegrity() + { +#if DEBUG + return this->self == this; +#else + return true; +#endif + } }; #endif diff --git a/src/coreclr/interpreter/intops.def b/src/coreclr/interpreter/intops.def index 15cbdb336d8998..8f1a45f8611ae0 100644 --- a/src/coreclr/interpreter/intops.def +++ b/src/coreclr/interpreter/intops.def @@ -42,6 +42,8 @@ OPDEF(INTOP_STELEM_I8, "stelem.i8", 4, 0, 3, InterpOpNoArgs) OPDEF(INTOP_STELEM_R4, "stelem.r4", 4, 0, 3, InterpOpNoArgs) OPDEF(INTOP_STELEM_R8, "stelem.r8", 4, 0, 3, InterpOpNoArgs) +OPDEF(INTOP_LDTOKEN, "ldtoken", 4, 1, 0, InterpOpTwoInts) // [token data item] [conversion helper func] + OPDEF(INTOP_MOV_I4_I1, "mov.i4.i1", 3, 1, 1, InterpOpNoArgs) OPDEF(INTOP_MOV_I4_U1, "mov.i4.u1", 3, 1, 1, InterpOpNoArgs) OPDEF(INTOP_MOV_I4_I2, "mov.i4.i2", 3, 1, 1, InterpOpNoArgs) diff --git a/src/coreclr/jit/CMakeLists.txt b/src/coreclr/jit/CMakeLists.txt index f8167e8ae94241..1cfe40b6853a25 100644 --- a/src/coreclr/jit/CMakeLists.txt +++ b/src/coreclr/jit/CMakeLists.txt @@ -532,6 +532,7 @@ add_custom_target(jit_exports DEPENDS ${JIT_EXPORTS_FILE}) set(JIT_LINK_LIBRARIES utilcodestaticnohost + minipal ) set(JIT_ARCH_LINK_LIBRARIES diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index d085ef712a40fb..a4b3ae17b3d9f4 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -22,6 +22,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #include "stacklevelsetter.h" #include "patchpointinfo.h" #include "jitstd/algorithm.h" +#include "minipal/time.h" extern ICorJitHost* g_jitHost; @@ -9259,12 +9260,7 @@ void Compiler::PrintPerMethodLoopHoistStats() void Compiler::RecordStateAtEndOfInlining() { #if defined(DEBUG) - LARGE_INTEGER lpCycles; - BOOL result = QueryPerformanceCounter(&lpCycles); - if (result == TRUE) - { - m_compCyclesAtEndOfInlining = (int64_t)lpCycles.QuadPart; - } + m_compCyclesAtEndOfInlining = minipal_hires_ticks(); #endif // defined(DEBUG) } @@ -9277,21 +9273,13 @@ void Compiler::RecordStateAtEndOfCompilation() #if defined(DEBUG) m_compCycles = 0; - LARGE_INTEGER lpCycles; - BOOL result = QueryPerformanceCounter(&lpCycles); - if (result == TRUE) + int64_t lpCycles = minipal_hires_ticks(); + if (lpCycles > m_compCyclesAtEndOfInlining) { - if ((int64_t)lpCycles.QuadPart > m_compCyclesAtEndOfInlining) - { - LARGE_INTEGER lpFreq; - result = QueryPerformanceFrequency(&lpFreq); - if (result == TRUE) - { - m_compCycles = (int64_t)lpCycles.QuadPart - m_compCyclesAtEndOfInlining; - m_compCycles *= 1000000; - m_compCycles /= (int64_t)lpFreq.QuadPart; - } - } + int64_t lpFreq = minipal_hires_tick_frequency(); + m_compCycles = lpCycles - m_compCyclesAtEndOfInlining; + m_compCycles *= 1000000; + m_compCycles /= lpFreq; } #endif // defined(DEBUG) } diff --git a/src/coreclr/jit/fgopt.cpp b/src/coreclr/jit/fgopt.cpp index b38792a4a4e2fe..b0153c34413674 100644 --- a/src/coreclr/jit/fgopt.cpp +++ b/src/coreclr/jit/fgopt.cpp @@ -2734,42 +2734,20 @@ bool Compiler::fgOptimizeBranch(BasicBlock* bJump) newStmtList->SetPrevStmt(newLastStmt); } - // - // Reverse the sense of the compare - // - gtReverseCond(condTree); - // We need to update the following flags of the bJump block if they were set in the bDest block bJump->CopyFlags(bDest, BBF_COPY_PROPAGATE); // Update bbRefs and bbPreds // - // For now we set the likelihood of the new branch to match - // the likelihood of the old branch. - // - // This may or may not match the block weight adjustments we're - // making. All this becomes easier to reconcile once we rely on - // edge likelihoods more and have synthesis running. - // - // Until then we won't worry that edges and blocks are potentially - // out of sync. - // - FlowEdge* const destFalseEdge = bDest->GetFalseEdge(); - FlowEdge* const destTrueEdge = bDest->GetTrueEdge(); - - // bJump now falls through into the next block. - // Note that we're deriving the false edge's likelihood from 'destTrueEdge', - // because the comparison in 'bJump' is flipped. - // Similarly, we will derive the true edge's likelihood from 'destFalseEdge'. - // - FlowEdge* const falseEdge = fgAddRefPred(trueTarget, bJump, destTrueEdge); + FlowEdge* const falseEdge = bDest->GetFalseEdge(); + FlowEdge* const trueEdge = bDest->GetTrueEdge(); - // bJump now jumps to bDest's normal jump target - // fgRedirectTargetEdge(bJump, falseTarget); - bJump->GetTargetEdge()->setLikelihood(destFalseEdge->getLikelihood()); + bJump->GetTargetEdge()->setLikelihood(falseEdge->getLikelihood()); + + FlowEdge* const newTrueEdge = fgAddRefPred(trueTarget, bJump, trueEdge); - bJump->SetCond(bJump->GetTargetEdge(), falseEdge); + bJump->SetCond(newTrueEdge, bJump->GetTargetEdge()); // Update profile data // diff --git a/src/coreclr/jit/hwintrinsiclistarm64sve.h b/src/coreclr/jit/hwintrinsiclistarm64sve.h index 7038e725808909..06a09e0e2e2c61 100644 --- a/src/coreclr/jit/hwintrinsiclistarm64sve.h +++ b/src/coreclr/jit/hwintrinsiclistarm64sve.h @@ -310,7 +310,8 @@ HARDWARE_INTRINSIC(Sve, ZipLow, // SVE2 Intrinsics #define FIRST_NI_Sve2 NI_Sve2_BitwiseClearXor HARDWARE_INTRINSIC(Sve2, BitwiseClearXor, -1, 3, {INS_sve_bcax, INS_sve_bcax, INS_sve_bcax, INS_sve_bcax, INS_sve_bcax, INS_sve_bcax, INS_sve_bcax, INS_sve_bcax, INS_invalid, INS_invalid}, HW_Category_SIMD, HW_Flag_Scalable|HW_Flag_SpecialCodeGen|HW_Flag_HasRMWSemantics) -#define LAST_NI_Sve2 NI_Sve2_BitwiseClearXor +HARDWARE_INTRINSIC(Sve2, ShiftLeftAndInsert, -1, 3, {INS_sve_sli, INS_sve_sli, INS_sve_sli, INS_sve_sli, INS_sve_sli, INS_sve_sli, INS_sve_sli, INS_sve_sli, INS_invalid, INS_invalid}, HW_Category_ShiftLeftByImmediate, HW_Flag_Scalable|HW_Flag_HasImmediateOperand|HW_Flag_HasRMWSemantics) +#define LAST_NI_Sve2 NI_Sve2_ShiftLeftAndInsert // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // ISA Function name SIMD size NumArg Instructions Category Flags diff --git a/src/coreclr/jit/lowerarmarch.cpp b/src/coreclr/jit/lowerarmarch.cpp index e6b5c34181f673..38d6cb6cf6ba41 100644 --- a/src/coreclr/jit/lowerarmarch.cpp +++ b/src/coreclr/jit/lowerarmarch.cpp @@ -3827,6 +3827,7 @@ void Lowering::ContainCheckHWIntrinsic(GenTreeHWIntrinsic* node) case NI_Sve_ExtractVector: case NI_Sve_AddRotateComplex: case NI_Sve_TrigonometricMultiplyAddCoefficient: + case NI_Sve2_ShiftLeftAndInsert: assert(hasImmediateOperand); assert(varTypeIsIntegral(intrin.op3)); if (intrin.op3->IsCnsIntOrI()) diff --git a/src/coreclr/jit/objectalloc.cpp b/src/coreclr/jit/objectalloc.cpp index 49d93ece331a4c..78ca1537d26a56 100644 --- a/src/coreclr/jit/objectalloc.cpp +++ b/src/coreclr/jit/objectalloc.cpp @@ -43,6 +43,9 @@ ObjectAllocator::ObjectAllocator(Compiler* comp) , m_bitVecTraits(BitVecTraits(comp->lvaCount, comp)) , m_unknownSourceIndex(BAD_VAR_NUM) , m_HeapLocalToStackLocalMap(comp->getAllocator(CMK_ObjectAllocator)) + , m_ConnGraphAdjacencyMatrix(nullptr) + , m_StackAllocMaxSize(0) + , m_stackAllocationCount(0) , m_EnumeratorLocalToPseudoIndexMap(comp->getAllocator(CMK_ObjectAllocator)) , m_CloneMap(comp->getAllocator(CMK_ObjectAllocator)) , m_nextLocalIndex(0) @@ -1134,10 +1137,9 @@ ObjectAllocator::ObjectAllocationType ObjectAllocator::AllocationKind(GenTree* t bool ObjectAllocator::MorphAllocObjNodes() { - bool didStackAllocate = false; + m_stackAllocationCount = 0; m_PossiblyStackPointingPointers = BitVecOps::MakeEmpty(&m_bitVecTraits); m_DefinitelyStackPointingPointers = BitVecOps::MakeEmpty(&m_bitVecTraits); - const bool isReadyToRun = comp->IsReadyToRun(); for (BasicBlock* const block : comp->Blocks()) { @@ -1161,6 +1163,7 @@ bool ObjectAllocator::MorphAllocObjNodes() continue; } + const unsigned int lclNum = stmtExpr->AsLclVar()->GetLclNum(); GenTree* const data = stmtExpr->AsLclVar()->Data(); ObjectAllocationType const allocType = AllocationKind(data); @@ -1169,205 +1172,271 @@ bool ObjectAllocator::MorphAllocObjNodes() continue; } - bool canStack = false; - bool bashCall = false; - const char* onHeapReason = nullptr; - const unsigned int lclNum = stmtExpr->AsLclVar()->GetLclNum(); + AllocationCandidate c(block, stmt, stmtExpr, lclNum, allocType); + MorphAllocObjNode(c); + } + } - // Don't attempt to do stack allocations inside basic blocks that may be in a loop. - // - if (!IsObjectStackAllocationEnabled()) - { - onHeapReason = "[object stack allocation disabled]"; - canStack = false; - } - else if (basicBlockHasBackwardJump) - { - onHeapReason = "[alloc in loop]"; - canStack = false; - } - else + return (m_stackAllocationCount > 0); +} + +//------------------------------------------------------------------------ +// MorphAllocObjNode: Transform an allocation site, possibly into as stack allocation +// +// Arguments: +// candidate -- allocation candidate +// +// Return Value: +// True if candidate was stack allocated +// If false, candidate reason is updated to explain why not +// +void ObjectAllocator::MorphAllocObjNode(AllocationCandidate& candidate) +{ + const bool didStackAllocate = MorphAllocObjNodeHelper(candidate); + const unsigned lclNum = candidate.m_lclNum; + + if (didStackAllocate) + { + // We keep the set of possibly-stack-pointing pointers as a superset of the set of + // definitely-stack-pointing pointers. All definitely-stack-pointing pointers are in both + // sets. + MarkLclVarAsDefinitelyStackPointing(lclNum); + MarkLclVarAsPossiblyStackPointing(lclNum); + + // If this was conditionally escaping enumerator, establish a connection between this local + // and the enumeratorLocal we already allocated. This is needed because we do early rewriting + // in the conditional clone. + // + unsigned pseudoIndex = BAD_VAR_NUM; + if (m_EnumeratorLocalToPseudoIndexMap.TryGetValue(lclNum, &pseudoIndex)) + { + CloneInfo* info = nullptr; + if (m_CloneMap.Lookup(pseudoIndex, &info)) { - if (allocType == OAT_NEWARR) + if (info->m_willClone) { - assert(basicBlockHasNewArr); - - // R2R not yet supported - // - assert(!m_isR2R); - - //------------------------------------------------------------------------ - // We expect the following expression tree at this point - // For non-ReadyToRun: - // STMTx (IL 0x... ???) - // * STORE_LCL_VAR ref - // \--* CALL help ref - // +--* CNS_INT(h) long - // \--* CNS_INT long - // For ReadyToRun: - // STMTx (IL 0x... ???) - // * STORE_LCL_VAR ref - // \--* CALL help ref - // \--* CNS_INT long - //------------------------------------------------------------------------ - - bool isExact = false; - bool isNonNull = false; - CORINFO_CLASS_HANDLE clsHnd = - comp->gtGetHelperCallClassHandle(data->AsCall(), &isExact, &isNonNull); - GenTree* const len = data->AsCall()->gtArgs.GetUserArgByIndex(1)->GetNode(); - - assert(len != nullptr); - - unsigned int blockSize = 0; - comp->Metrics.NewArrayHelperCalls++; - - if (!isExact || !isNonNull) - { - onHeapReason = "[array type is either non-exact or null]"; - canStack = false; - } - else if (!len->IsCnsIntOrI()) - { - onHeapReason = "[non-constant size]"; - canStack = false; - } - else if (!CanAllocateLclVarOnStack(lclNum, clsHnd, allocType, len->AsIntCon()->IconValue(), - &blockSize, &onHeapReason)) - { - // reason set by the call - canStack = false; - } - else - { - JITDUMP("Allocating V%02u on the stack\n", lclNum); - canStack = true; - const unsigned int stackLclNum = - MorphNewArrNodeIntoStackAlloc(data->AsCall(), clsHnd, - (unsigned int)len->AsIntCon()->IconValue(), blockSize, block, - stmt); - - // Note we do not want to rewrite uses of the array temp, so we - // do not update m_HeapLocalToStackLocalMap. - // - comp->Metrics.StackAllocatedArrays++; - } + JITDUMP("Connecting stack allocated enumerator V%02u to its address var V%02u\n", lclNum, + info->m_enumeratorLocal); + AddConnGraphEdge(lclNum, info->m_enumeratorLocal); + MarkLclVarAsPossiblyStackPointing(info->m_enumeratorLocal); + MarkLclVarAsDefinitelyStackPointing(info->m_enumeratorLocal); } - else if (allocType == OAT_NEWOBJ) - { - assert(basicBlockHasNewObj); - //------------------------------------------------------------------------ - // We expect the following expression tree at this point - // STMTx (IL 0x... ???) - // * STORE_LCL_VAR ref - // \--* ALLOCOBJ ref - // \--* CNS_INT(h) long - //------------------------------------------------------------------------ - - CORINFO_CLASS_HANDLE clsHnd = data->AsAllocObj()->gtAllocObjClsHnd; - const bool isValueClass = comp->info.compCompHnd->isValueClass(clsHnd); - - if (isValueClass) - { - comp->Metrics.NewBoxedValueClassHelperCalls++; - } - else - { - comp->Metrics.NewRefClassHelperCalls++; - } + } + } - if (!CanAllocateLclVarOnStack(lclNum, clsHnd, allocType, 0, nullptr, &onHeapReason)) - { - // reason set by the call - canStack = false; - } - else - { - JITDUMP("Allocating V%02u on the stack\n", lclNum); - canStack = true; + if (candidate.m_bashCall) + { + candidate.m_statement->GetRootNode()->gtBashToNOP(); + } - ClassLayout* layout = nullptr; + comp->optMethodFlags |= OMF_HAS_OBJSTACKALLOC; + m_stackAllocationCount++; + } + else + { + assert(candidate.m_onHeapReason != nullptr); + JITDUMP("Allocating V%02u on the heap: %s\n", lclNum, candidate.m_onHeapReason); + if (candidate.m_allocType == OAT_NEWOBJ) + { + GenTree* const stmtExpr = candidate.m_tree; + GenTree* const oldData = stmtExpr->AsLclVar()->Data(); + GenTree* const newData = MorphAllocObjNodeIntoHelperCall(oldData->AsAllocObj()); + stmtExpr->AsLclVar()->Data() = newData; + stmtExpr->AddAllEffectsFlags(newData); + } - if (isValueClass) - { - CORINFO_CLASS_HANDLE boxedClsHnd = comp->info.compCompHnd->getTypeForBox(clsHnd); - assert(boxedClsHnd != NO_CLASS_HANDLE); - ClassLayout* structLayout = comp->typGetObjLayout(boxedClsHnd); - layout = GetBoxedLayout(structLayout); - comp->Metrics.StackAllocatedBoxedValueClasses++; - } - else - { - layout = comp->typGetObjLayout(clsHnd); - comp->Metrics.StackAllocatedRefClasses++; - } + if (IsTrackedLocal(lclNum)) + { + AddConnGraphEdgeIndex(LocalToIndex(lclNum), m_unknownSourceIndex); + } + } +} - const unsigned int stackLclNum = - MorphAllocObjNodeIntoStackAlloc(data->AsAllocObj(), layout, block, stmt); - m_HeapLocalToStackLocalMap.AddOrUpdate(lclNum, stackLclNum); +//------------------------------------------------------------------------ +// MorphAllocObjNodeHelper: See if we can stack allocate a GT_ALLOCOBJ or GT_NEWARR +// +// Arguments: +// candidate -- allocation candidate +// +// Return Value: +// True if candidate was stack allocated +// If false, candidate reason is updated to explain why not +// +bool ObjectAllocator::MorphAllocObjNodeHelper(AllocationCandidate& candidate) +{ + if (!IsObjectStackAllocationEnabled()) + { + candidate.m_onHeapReason = "[object stack allocation disabled]"; + return false; + } - bashCall = true; - } - } - } + // Don't attempt to do stack allocations inside basic blocks that may be in a loop. + // + if (candidate.m_block->HasFlag(BBF_BACKWARD_JUMP)) + { + candidate.m_onHeapReason = "[alloc in loop]"; + return false; + } - if (canStack) - { - // We keep the set of possibly-stack-pointing pointers as a superset of the set of - // definitely-stack-pointing pointers. All definitely-stack-pointing pointers are in both - // sets. - MarkLclVarAsDefinitelyStackPointing(lclNum); - MarkLclVarAsPossiblyStackPointing(lclNum); - - // If this was conditionally escaping enumerator, establish a connection between this local - // and the enumeratorLocal we already allocated. This is needed because we do early rewriting - // in the conditional clone. - // - unsigned pseudoIndex = BAD_VAR_NUM; - if (m_EnumeratorLocalToPseudoIndexMap.TryGetValue(lclNum, &pseudoIndex)) - { - CloneInfo* info = nullptr; - if (m_CloneMap.Lookup(pseudoIndex, &info)) - { - if (info->m_willClone) - { - JITDUMP("Connecting stack allocated enumerator V%02u to its address var V%02u\n", lclNum, - info->m_enumeratorLocal); - AddConnGraphEdge(lclNum, info->m_enumeratorLocal); - MarkLclVarAsPossiblyStackPointing(info->m_enumeratorLocal); - MarkLclVarAsDefinitelyStackPointing(info->m_enumeratorLocal); - } - } - } + switch (candidate.m_allocType) + { + case OAT_NEWARR: + return MorphAllocObjNodeHelperArr(candidate); + case OAT_NEWOBJ: + return MorphAllocObjNodeHelperObj(candidate); + default: + unreached(); + } +} - if (bashCall) - { - stmt->GetRootNode()->gtBashToNOP(); - } +//------------------------------------------------------------------------ +// MorphAllocObjNodeHelperObj: See if we can stack allocate a GT_NEWARR +// +// Arguments: +// candidate -- allocation candidate +// +// Return Value: +// True if candidate was stack allocated +// If false, candidate reason is updated to explain why not +// +bool ObjectAllocator::MorphAllocObjNodeHelperArr(AllocationCandidate& candidate) +{ + assert(candidate.m_block->HasFlag(BBF_HAS_NEWARR)); - comp->optMethodFlags |= OMF_HAS_OBJSTACKALLOC; - didStackAllocate = true; - } - else - { - assert(onHeapReason != nullptr); - JITDUMP("Allocating V%02u on the heap: %s\n", lclNum, onHeapReason); - if (allocType == OAT_NEWOBJ) - { - GenTree* const newData = MorphAllocObjNodeIntoHelperCall(data->AsAllocObj()); - stmtExpr->AsLclVar()->Data() = newData; - stmtExpr->AddAllEffectsFlags(newData); - } + // R2R not yet supported + // + if (m_isR2R) + { + candidate.m_onHeapReason = "[R2R array not yet supported]"; + return false; + } - if (IsTrackedLocal(lclNum)) - { - AddConnGraphEdgeIndex(LocalToIndex(lclNum), m_unknownSourceIndex); - } - } - } + GenTree* const data = candidate.m_tree->AsLclVar()->Data(); + + //------------------------------------------------------------------------ + // We expect the following expression tree at this point + // For non-ReadyToRun: + // STMTx (IL 0x... ???) + // * STORE_LCL_VAR ref + // \--* CALL help ref + // +--* CNS_INT(h) long + // \--* CNS_INT long + // For ReadyToRun: + // STMTx (IL 0x... ???) + // * STORE_LCL_VAR ref + // \--* CALL help ref + // \--* CNS_INT long + //------------------------------------------------------------------------ + + bool isExact = false; + bool isNonNull = false; + CORINFO_CLASS_HANDLE clsHnd = comp->gtGetHelperCallClassHandle(data->AsCall(), &isExact, &isNonNull); + GenTree* const len = data->AsCall()->gtArgs.GetUserArgByIndex(1)->GetNode(); + + assert(len != nullptr); + + unsigned int blockSize = 0; + comp->Metrics.NewArrayHelperCalls++; + + if (!isExact || !isNonNull) + { + candidate.m_onHeapReason = "[array type is either non-exact or null]"; + return false; + } + + if (!len->IsCnsIntOrI()) + { + candidate.m_onHeapReason = "[non-constant array size]"; + return false; + } + + if (!CanAllocateLclVarOnStack(candidate.m_lclNum, clsHnd, candidate.m_allocType, len->AsIntCon()->IconValue(), + &blockSize, &candidate.m_onHeapReason)) + { + // reason set by the call + return false; + } + + JITDUMP("Allocating V%02u on the stack\n", candidate.m_lclNum); + const unsigned int stackLclNum = + MorphNewArrNodeIntoStackAlloc(data->AsCall(), clsHnd, (unsigned int)len->AsIntCon()->IconValue(), blockSize, + candidate.m_block, candidate.m_statement); + + // Note we do not want to rewrite uses of the array temp, so we + // do not update m_HeapLocalToStackLocalMap. + // + comp->Metrics.StackAllocatedArrays++; + + return true; +} + +//------------------------------------------------------------------------ +// MorphAllocObjNodeHelperObj: See if we can stack allocate a GT_ALLOCOBJ +// +// Arguments: +// candidate -- allocation candidate +// +// Return Value: +// True if candidate was stack allocated +// If false, candidate reason is updated to explain why not +// +bool ObjectAllocator::MorphAllocObjNodeHelperObj(AllocationCandidate& candidate) +{ + assert(candidate.m_block->HasFlag(BBF_HAS_NEWOBJ)); + + //------------------------------------------------------------------------ + // We expect the following expression tree at this point + // STMTx (IL 0x... ???) + // * STORE_LCL_VAR ref + // \--* ALLOCOBJ ref + // \--* CNS_INT(h) long + //------------------------------------------------------------------------ + + unsigned const lclNum = candidate.m_lclNum; + GenTree* const data = candidate.m_tree->AsLclVar()->Data(); + CORINFO_CLASS_HANDLE clsHnd = data->AsAllocObj()->gtAllocObjClsHnd; + const bool isValueClass = comp->info.compCompHnd->isValueClass(clsHnd); + + if (isValueClass) + { + comp->Metrics.NewBoxedValueClassHelperCalls++; + } + else + { + comp->Metrics.NewRefClassHelperCalls++; } - return didStackAllocate; + if (!CanAllocateLclVarOnStack(lclNum, clsHnd, candidate.m_allocType, 0, nullptr, &candidate.m_onHeapReason)) + { + // reason set by the call + return false; + } + + JITDUMP("Allocating V%02u on the stack\n", lclNum); + + ClassLayout* layout = nullptr; + + if (isValueClass) + { + CORINFO_CLASS_HANDLE boxedClsHnd = comp->info.compCompHnd->getTypeForBox(clsHnd); + assert(boxedClsHnd != NO_CLASS_HANDLE); + ClassLayout* structLayout = comp->typGetObjLayout(boxedClsHnd); + layout = GetBoxedLayout(structLayout); + comp->Metrics.StackAllocatedBoxedValueClasses++; + } + else + { + layout = comp->typGetObjLayout(clsHnd); + comp->Metrics.StackAllocatedRefClasses++; + } + + const unsigned int stackLclNum = + MorphAllocObjNodeIntoStackAlloc(data->AsAllocObj(), layout, candidate.m_block, candidate.m_statement); + m_HeapLocalToStackLocalMap.AddOrUpdate(lclNum, stackLclNum); + + candidate.m_bashCall = true; + + return true; } //------------------------------------------------------------------------ diff --git a/src/coreclr/jit/objectalloc.h b/src/coreclr/jit/objectalloc.h index 13499b00fe9109..0b9d148a69ff91 100644 --- a/src/coreclr/jit/objectalloc.h +++ b/src/coreclr/jit/objectalloc.h @@ -114,7 +114,6 @@ typedef JitHashTable, unsigned> class ObjectAllocator final : public Phase { - typedef SmallHashTable LocalToLocalMap; enum ObjectAllocationType { OAT_NONE, @@ -122,6 +121,31 @@ class ObjectAllocator final : public Phase OAT_NEWARR }; + struct AllocationCandidate + { + AllocationCandidate( + BasicBlock* block, Statement* statement, GenTree* tree, unsigned lclNum, ObjectAllocationType allocType) + : m_block(block) + , m_statement(statement) + , m_tree(tree) + , m_lclNum(lclNum) + , m_allocType(allocType) + , m_onHeapReason(nullptr) + , m_bashCall(false) + { + } + + BasicBlock* const m_block; + Statement* const m_statement; + GenTree* const m_tree; + unsigned const m_lclNum; + ObjectAllocationType const m_allocType; + const char* m_onHeapReason; + bool m_bashCall; + }; + + typedef SmallHashTable LocalToLocalMap; + //=============================================================================== // Data members bool m_IsObjectStackAllocationEnabled; @@ -138,6 +162,7 @@ class ObjectAllocator final : public Phase LocalToLocalMap m_HeapLocalToStackLocalMap; BitSetShortLongRep* m_ConnGraphAdjacencyMatrix; unsigned int m_StackAllocMaxSize; + unsigned m_stackAllocationCount; // Info for conditionally-escaping locals LocalToLocalMap m_EnumeratorLocalToPseudoIndexMap; @@ -194,6 +219,10 @@ class ObjectAllocator final : public Phase void ComputeEscapingNodes(BitVecTraits* bitVecTraits, BitVec& escapingNodes); void ComputeStackObjectPointers(BitVecTraits* bitVecTraits); bool MorphAllocObjNodes(); + void MorphAllocObjNode(AllocationCandidate& candidate); + bool MorphAllocObjNodeHelper(AllocationCandidate& candidate); + bool MorphAllocObjNodeHelperArr(AllocationCandidate& candidate); + bool MorphAllocObjNodeHelperObj(AllocationCandidate& candidate); void RewriteUses(); GenTree* MorphAllocObjNodeIntoHelperCall(GenTreeAllocObj* allocObj); unsigned int MorphAllocObjNodeIntoStackAlloc(GenTreeAllocObj* allocObj, diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp index 3487c26015abfd..61e264a7df2ff5 100644 --- a/src/coreclr/jit/optimizer.cpp +++ b/src/coreclr/jit/optimizer.cpp @@ -2391,20 +2391,6 @@ PhaseStatus Compiler::optOptimizeFlow() modified |= fgExpandRarelyRunBlocks(); } - // Run branch optimizations for non-handler blocks. - assert(!fgFuncletsCreated); - for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->Next()) - { - if (block->hasHndIndex()) - { - assert(bbIsHandlerBeg(block)); - block = ehGetDsc(block->getHndIndex())->ebdHndLast; - continue; - } - - modified |= fgOptimizeBranch(block); - } - return modified ? PhaseStatus::MODIFIED_EVERYTHING : PhaseStatus::MODIFIED_NOTHING; } diff --git a/src/coreclr/jit/simd.cpp b/src/coreclr/jit/simd.cpp index a23c40b6939ef8..b55d3fb4e8584d 100644 --- a/src/coreclr/jit/simd.cpp +++ b/src/coreclr/jit/simd.cpp @@ -627,14 +627,11 @@ bool Compiler::areArrayElementsContiguous(GenTree* op1, GenTree* op2) GenTreeIndexAddr* op1IndexAddr = op1->AsIndir()->Addr()->AsIndexAddr(); GenTreeIndexAddr* op2IndexAddr = op2->AsIndir()->Addr()->AsIndexAddr(); + GenTree* op1ArrayRef = op1IndexAddr->Arr(); + GenTree* op2ArrayRef = op2IndexAddr->Arr(); + GenTree* op1IndexNode = op1IndexAddr->Index(); + GenTree* op2IndexNode = op2IndexAddr->Index(); - GenTree* op1ArrayRef = op1IndexAddr->Arr(); - GenTree* op2ArrayRef = op2IndexAddr->Arr(); - assert(op1ArrayRef->TypeGet() == TYP_REF); - assert(op2ArrayRef->TypeGet() == TYP_REF); - - GenTree* op1IndexNode = op1IndexAddr->Index(); - GenTree* op2IndexNode = op2IndexAddr->Index(); if ((op1IndexNode->OperGet() == GT_CNS_INT && op2IndexNode->OperGet() == GT_CNS_INT) && (op1IndexNode->AsIntCon()->gtIconVal + 1 == op2IndexNode->AsIntCon()->gtIconVal)) { diff --git a/src/coreclr/jit/utils.cpp b/src/coreclr/jit/utils.cpp index a9101620f3f2c8..44b7762d8407cd 100644 --- a/src/coreclr/jit/utils.cpp +++ b/src/coreclr/jit/utils.cpp @@ -23,6 +23,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #include "opcode.h" #include "jitstd/algorithm.h" +#include "minipal/time.h" /*****************************************************************************/ @@ -2196,22 +2197,15 @@ double CycleCount::ElapsedTime() bool PerfCounter::Start() { - bool result = QueryPerformanceFrequency(&beg) != 0; - if (!result) - { - return result; - } - freq = (double)beg.QuadPart / 1000.0; - (void)QueryPerformanceCounter(&beg); - return result; + freq = (double)minipal_hires_tick_frequency() / 1000.0; + beg = minipal_hires_ticks(); + return true; } // Return elapsed time from Start() in millis. double PerfCounter::ElapsedTime() { - LARGE_INTEGER li; - (void)QueryPerformanceCounter(&li); - return (double)(li.QuadPart - beg.QuadPart) / freq; + return (double)(minipal_hires_ticks() - beg) / freq; } #endif diff --git a/src/coreclr/jit/utils.h b/src/coreclr/jit/utils.h index 3d3ef423b44b9b..75edcb4d802848 100644 --- a/src/coreclr/jit/utils.h +++ b/src/coreclr/jit/utils.h @@ -785,11 +785,11 @@ class CycleCount bool GetCycles(uint64_t* time); }; -// Uses win API QueryPerformanceCounter/QueryPerformanceFrequency. +// Uses minipal/time.h class PerfCounter { - LARGE_INTEGER beg; - double freq; + int64_t beg; + double freq; public: // If the method returns false, any other query yield unpredictable results. diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InternalCalls.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InternalCalls.cs index 99964658199f0f..5909087c68708e 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InternalCalls.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InternalCalls.cs @@ -280,9 +280,6 @@ internal static extern unsafe IntPtr RhpCallPropagateExceptionCallback( [DllImport(Redhawk.BaseName)] internal static extern void RhpSignalFinalizationComplete(uint fCount, int observedFullGcCount); - [DllImport(Redhawk.BaseName)] - internal static extern ulong RhpGetTickCount64(); - // Enters a no GC region, possibly doing a blocking GC if there is not enough // memory available to satisfy the caller's request. [DllImport(Redhawk.BaseName)] diff --git a/src/coreclr/nativeaot/Runtime/CommonMacros.h b/src/coreclr/nativeaot/Runtime/CommonMacros.h index 426e0119209b9e..c174b06f17ccd4 100644 --- a/src/coreclr/nativeaot/Runtime/CommonMacros.h +++ b/src/coreclr/nativeaot/Runtime/CommonMacros.h @@ -6,6 +6,9 @@ #include "rhassert.h" #include +#ifdef PROFILE_STARTUP +#include +#endif #define EXTERN_C extern "C" @@ -323,7 +326,7 @@ enum STARTUP_TIMELINE_EVENT_ID #ifdef PROFILE_STARTUP extern uint64_t g_startupTimelineEvents[NUM_STARTUP_TIMELINE_EVENTS]; -#define STARTUP_TIMELINE_EVENT(eventid) g_startupTimelineEvents[eventid] = PalQueryPerformanceCounter(); +#define STARTUP_TIMELINE_EVENT(eventid) g_startupTimelineEvents[eventid] = (uint64_t)minipal_hires_ticks(); #else // PROFILE_STARTUP #define STARTUP_TIMELINE_EVENT(eventid) #endif // PROFILE_STARTUP diff --git a/src/coreclr/nativeaot/Runtime/GcStressControl.cpp b/src/coreclr/nativeaot/Runtime/GcStressControl.cpp index 3f9853a3ea3b1e..ad3d9dfdd9ae8d 100644 --- a/src/coreclr/nativeaot/Runtime/GcStressControl.cpp +++ b/src/coreclr/nativeaot/Runtime/GcStressControl.cpp @@ -25,6 +25,7 @@ #include "shash.h" #include "shash.inl" #include "GcStressControl.h" +#include "minipal/time.h" class GcStressControl @@ -70,7 +71,7 @@ class GcStressControl if (g_pRhConfig->GetGcStressSeed()) s_lGcStressRNGSeed = (uint32_t)g_pRhConfig->GetGcStressSeed(); else - s_lGcStressRNGSeed = (uint32_t)PalGetTickCount64(); + s_lGcStressRNGSeed = (uint32_t)minipal_lowres_ticks(); if (g_pRhConfig->GetGcStressFreqDenom()) s_lGcStressFreqDenom = (uint32_t)g_pRhConfig->GetGcStressFreqDenom(); diff --git a/src/coreclr/nativeaot/Runtime/MiscHelpers.cpp b/src/coreclr/nativeaot/Runtime/MiscHelpers.cpp index 530ec8403dde50..9fe749e23ed8c8 100644 --- a/src/coreclr/nativeaot/Runtime/MiscHelpers.cpp +++ b/src/coreclr/nativeaot/Runtime/MiscHelpers.cpp @@ -36,6 +36,7 @@ #include "RhConfig.h" #include #include +#include FCIMPL0(void, RhDebugBreak) { @@ -418,11 +419,6 @@ FCIMPL1(uint8_t *, RhGetCodeTarget, uint8_t * pCodeOrg) } FCIMPLEND -EXTERN_C uint64_t QCALLTYPE RhpGetTickCount64() -{ - return PalGetTickCount64(); -} - EXTERN_C int32_t QCALLTYPE RhpCalculateStackTraceWorker(void* pOutputBuffer, uint32_t outputBufferLength, void* pAddressInCurrentFrame); EXTERN_C int32_t QCALLTYPE RhpGetCurrentThreadStackTrace(void* pOutputBuffer, uint32_t outputBufferLength, void* pAddressInCurrentFrame) diff --git a/src/coreclr/nativeaot/Runtime/PalRedhawk.h b/src/coreclr/nativeaot/Runtime/PalRedhawk.h index adc2deaf208e5b..167570b165d199 100644 --- a/src/coreclr/nativeaot/Runtime/PalRedhawk.h +++ b/src/coreclr/nativeaot/Runtime/PalRedhawk.h @@ -283,7 +283,6 @@ REDHAWK_PALIMPORT void REDHAWK_PALAPI PalSleep(uint32_t milliseconds); REDHAWK_PALIMPORT UInt32_BOOL REDHAWK_PALAPI PalSwitchToThread(); REDHAWK_PALIMPORT UInt32_BOOL REDHAWK_PALAPI PalAreShadowStacksEnabled(); REDHAWK_PALIMPORT HANDLE REDHAWK_PALAPI PalCreateEventW(_In_opt_ LPSECURITY_ATTRIBUTES pEventAttributes, UInt32_BOOL manualReset, UInt32_BOOL initialState, _In_opt_z_ LPCWSTR pName); -REDHAWK_PALIMPORT uint64_t REDHAWK_PALAPI PalGetTickCount64(); REDHAWK_PALIMPORT HANDLE REDHAWK_PALAPI PalGetModuleHandleFromPointer(_In_ void* pointer); #ifdef TARGET_UNIX @@ -325,9 +324,6 @@ REDHAWK_PALIMPORT void REDHAWK_PALAPI PalAttachThread(void* thread); REDHAWK_PALIMPORT uint64_t PalGetCurrentOSThreadId(); -REDHAWK_PALIMPORT uint64_t PalQueryPerformanceCounter(); -REDHAWK_PALIMPORT uint64_t PalQueryPerformanceFrequency(); - REDHAWK_PALIMPORT void PalPrintFatalError(const char* message); REDHAWK_PALIMPORT char* PalCopyTCharAsChar(const TCHAR* toCopy); diff --git a/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.cpp b/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.cpp index 9b2bb852239647..20d557ec6f8e81 100644 --- a/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.cpp +++ b/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.cpp @@ -18,6 +18,7 @@ #endif #include +#include #include "gcenv.h" #include "thread.h" @@ -415,14 +416,14 @@ int64_t ep_rt_aot_perf_counter_query (void) { STATIC_CONTRACT_NOTHROW; - return (int64_t)PalQueryPerformanceCounter(); + return minipal_hires_ticks(); } int64_t ep_rt_aot_perf_frequency_query (void) { STATIC_CONTRACT_NOTHROW; - return (int64_t)PalQueryPerformanceFrequency(); + return minipal_hires_tick_frequency(); } int64_t diff --git a/src/coreclr/nativeaot/Runtime/eventpipeinternal.cpp b/src/coreclr/nativeaot/Runtime/eventpipeinternal.cpp index 01d251c46fc071..0fc3881c53476e 100644 --- a/src/coreclr/nativeaot/Runtime/eventpipeinternal.cpp +++ b/src/coreclr/nativeaot/Runtime/eventpipeinternal.cpp @@ -13,6 +13,7 @@ #include #include #include +#include "minipal/time.h" #ifdef FEATURE_PERFTRACING @@ -246,7 +247,7 @@ EXTERN_C UInt32_BOOL QCALLTYPE EventPipeInternal_GetSessionInfo(uint64_t session { pSessionInfo->StartTimeAsUTCFileTime = ep_session_get_session_start_time (pSession); pSessionInfo->StartTimeStamp = ep_session_get_session_start_timestamp(pSession); - pSessionInfo->TimeStampFrequency = PalQueryPerformanceFrequency(); + pSessionInfo->TimeStampFrequency = minipal_hires_tick_frequency(); retVal = true; } } diff --git a/src/coreclr/nativeaot/Runtime/startup.cpp b/src/coreclr/nativeaot/Runtime/startup.cpp index c53c99d8b73159..78c6429944df78 100644 --- a/src/coreclr/nativeaot/Runtime/startup.cpp +++ b/src/coreclr/nativeaot/Runtime/startup.cpp @@ -27,6 +27,7 @@ #include "RestrictedCallouts.h" #include "yieldprocessornormalized.h" #include +#include #ifdef FEATURE_PERFTRACING #include "EventPipeInterface.h" @@ -208,7 +209,7 @@ bool InitGSCookie() #endif // REVIEW: Need something better for PAL... - GSCookie val = (GSCookie)PalGetTickCount64(); + GSCookie val = (GSCookie)minipal_lowres_ticks(); #ifdef _DEBUG // In _DEBUG, always use the same value to make it easier to search for the cookie diff --git a/src/coreclr/nativeaot/Runtime/stressLog.cpp b/src/coreclr/nativeaot/Runtime/stressLog.cpp index c1461cd284de88..6c626eeef5a5dd 100644 --- a/src/coreclr/nativeaot/Runtime/stressLog.cpp +++ b/src/coreclr/nativeaot/Runtime/stressLog.cpp @@ -29,6 +29,7 @@ #include "threadstore.inl" #include "thread.inl" #include "volatile.h" +#include "minipal/time.h" #ifdef STRESS_LOG @@ -63,7 +64,7 @@ uint64_t getTimeStamp() #else // HOST_X86 uint64_t getTimeStamp() { - return PalQueryPerformanceCounter(); + return (uint64_t)minipal_hires_ticks(); } #endif // HOST_X86 else @@ -74,7 +75,7 @@ uint64_t getTimeStamp() */ uint64_t getTickFrequency() { - return PalQueryPerformanceFrequency(); + return (uint64_t)minipal_hires_tick_frequency(); } #endif // DACCESS_COMPILE diff --git a/src/coreclr/nativeaot/Runtime/thread.cpp b/src/coreclr/nativeaot/Runtime/thread.cpp index 0f269f23cbd58f..d4ed62a1881c5a 100644 --- a/src/coreclr/nativeaot/Runtime/thread.cpp +++ b/src/coreclr/nativeaot/Runtime/thread.cpp @@ -30,6 +30,7 @@ #include "RhConfig.h" #include "GcEnum.h" #include "NativeContext.h" +#include "minipal/time.h" #ifndef DACCESS_COMPILE @@ -40,7 +41,7 @@ static Thread* g_RuntimeInitializingThread; ee_alloc_context::PerThreadRandom::PerThreadRandom() { - minipal_xoshiro128pp_init(&random_state, (uint32_t)PalGetTickCount64()); + minipal_xoshiro128pp_init(&random_state, (uint32_t)minipal_lowres_ticks()); } thread_local ee_alloc_context::PerThreadRandom ee_alloc_context::t_random = PerThreadRandom(); diff --git a/src/coreclr/nativeaot/Runtime/unix/PalRedhawkUnix.cpp b/src/coreclr/nativeaot/Runtime/unix/PalRedhawkUnix.cpp index 94ad25ceab8bdb..5a7435a5df7528 100644 --- a/src/coreclr/nativeaot/Runtime/unix/PalRedhawkUnix.cpp +++ b/src/coreclr/nativeaot/Runtime/unix/PalRedhawkUnix.cpp @@ -730,15 +730,6 @@ REDHAWK_PALEXPORT bool REDHAWK_PALAPI PalStartEventPipeHelperThread(_In_ Backgro return PalStartBackgroundWork(callback, pCallbackContext, UInt32_FALSE); } -// Returns a 64-bit tick count with a millisecond resolution. It tries its best -// to return monotonically increasing counts and avoid being affected by changes -// to the system clock (either due to drift or due to explicit changes to system -// time). -REDHAWK_PALEXPORT uint64_t REDHAWK_PALAPI PalGetTickCount64() -{ - return GCToOSInterface::GetLowPrecisionTimeStamp(); -} - REDHAWK_PALEXPORT HANDLE REDHAWK_PALAPI PalGetModuleHandleFromPointer(_In_ void* pointer) { HANDLE moduleHandle = NULL; @@ -1207,16 +1198,6 @@ extern "C" void GetSystemTimeAsFileTime(FILETIME *lpSystemTimeAsFileTime) lpSystemTimeAsFileTime->dwHighDateTime = (uint32_t)(result >> 32); } -extern "C" uint64_t PalQueryPerformanceCounter() -{ - return GCToOSInterface::QueryPerformanceCounter(); -} - -extern "C" uint64_t PalQueryPerformanceFrequency() -{ - return GCToOSInterface::QueryPerformanceFrequency(); -} - extern "C" uint64_t PalGetCurrentOSThreadId() { return (uint64_t)minipal_get_current_thread_id(); diff --git a/src/coreclr/nativeaot/Runtime/unix/config.h.in b/src/coreclr/nativeaot/Runtime/unix/config.h.in index d5505b760c1f6f..3a5e1ef87b5dc3 100644 --- a/src/coreclr/nativeaot/Runtime/unix/config.h.in +++ b/src/coreclr/nativeaot/Runtime/unix/config.h.in @@ -20,8 +20,6 @@ #cmakedefine01 HAVE_SIGINFO_T #cmakedefine01 HAVE_LWP_SELF -#cmakedefine01 HAVE_CLOCK_MONOTONIC -#cmakedefine01 HAVE_CLOCK_MONOTONIC_COARSE #cmakedefine01 HAVE_CLOCK_GETTIME_NSEC_NP #cmakedefine01 HAVE_SCHED_GETAFFINITY diff --git a/src/coreclr/nativeaot/Runtime/unix/configure.cmake b/src/coreclr/nativeaot/Runtime/unix/configure.cmake index 39ce650e54a6d9..7cd0bf8ef7542e 100644 --- a/src/coreclr/nativeaot/Runtime/unix/configure.cmake +++ b/src/coreclr/nativeaot/Runtime/unix/configure.cmake @@ -59,34 +59,6 @@ int main(int argc, char **argv) return (int)_lwp_self(); }" HAVE_LWP_SELF) -check_cxx_source_runs(" -#include -#include -#include - -int main() -{ - int ret; - struct timespec ts; - ret = clock_gettime(CLOCK_MONOTONIC, &ts); - - exit(ret); -}" HAVE_CLOCK_MONOTONIC) - -check_cxx_source_runs(" -#include -#include -#include - -int main() -{ - int ret; - struct timespec ts; - ret = clock_gettime(CLOCK_MONOTONIC_COARSE, &ts); - - exit(ret); -}" HAVE_CLOCK_MONOTONIC_COARSE) - check_cxx_source_compiles(" #include diff --git a/src/coreclr/nativeaot/Runtime/windows/PalRedhawkCommon.cpp b/src/coreclr/nativeaot/Runtime/windows/PalRedhawkCommon.cpp index a805762b462166..801e1eab66d28c 100644 --- a/src/coreclr/nativeaot/Runtime/windows/PalRedhawkCommon.cpp +++ b/src/coreclr/nativeaot/Runtime/windows/PalRedhawkCommon.cpp @@ -102,8 +102,3 @@ REDHAWK_PALEXPORT int32_t PalGetModuleFileName(_Out_ const TCHAR** pModuleNameOu *pModuleNameOut = NULL; return 0; } - -REDHAWK_PALEXPORT uint64_t REDHAWK_PALAPI PalGetTickCount64() -{ - return GetTickCount64(); -} diff --git a/src/coreclr/nativeaot/Runtime/windows/PalRedhawkMinWin.cpp b/src/coreclr/nativeaot/Runtime/windows/PalRedhawkMinWin.cpp index 0b8b0cb6400325..fbab660b11f6f3 100644 --- a/src/coreclr/nativeaot/Runtime/windows/PalRedhawkMinWin.cpp +++ b/src/coreclr/nativeaot/Runtime/windows/PalRedhawkMinWin.cpp @@ -205,16 +205,6 @@ REDHAWK_PALEXPORT bool REDHAWK_PALAPI PalInit() return true; } -extern "C" uint64_t PalQueryPerformanceCounter() -{ - return GCToOSInterface::QueryPerformanceCounter(); -} - -extern "C" uint64_t PalQueryPerformanceFrequency() -{ - return GCToOSInterface::QueryPerformanceFrequency(); -} - extern "C" uint64_t PalGetCurrentOSThreadId() { return GetCurrentThreadId(); diff --git a/src/coreclr/nativeaot/Runtime/yieldprocessornormalized.cpp b/src/coreclr/nativeaot/Runtime/yieldprocessornormalized.cpp index efaf4e8bb20704..ae62fba4cb96d5 100644 --- a/src/coreclr/nativeaot/Runtime/yieldprocessornormalized.cpp +++ b/src/coreclr/nativeaot/Runtime/yieldprocessornormalized.cpp @@ -14,6 +14,7 @@ #include "slist.h" #include "volatile.h" #include "yieldprocessornormalized.h" +#include "minipal/time.h" #include "../../utilcode/yieldprocessornormalized.cpp" diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj index f687c6bb354546..251d8bfa97ecf6 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj @@ -281,9 +281,6 @@ Interop\Windows\OleAut32\Interop.VariantClear.cs - - Interop\Windows\Kernel32\Interop.GetTickCount64.cs - Interop\Windows\Kernel32\Interop.DynamicLoad.cs diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Environment.NativeAot.Unix.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Environment.NativeAot.Unix.cs index 98cb7225171172..f437f3a17cf027 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Environment.NativeAot.Unix.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Environment.NativeAot.Unix.cs @@ -9,8 +9,6 @@ namespace System { public static partial class Environment { - public static long TickCount64 => (long)RuntimeImports.RhpGetTickCount64(); - [DoesNotReturn] private static void ExitRaw() => Interop.Sys.Exit(s_latchedExitCode); } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Environment.NativeAot.Windows.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Environment.NativeAot.Windows.cs index 9aaa5980fc68db..0c47251b931e92 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Environment.NativeAot.Windows.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Environment.NativeAot.Windows.cs @@ -7,8 +7,6 @@ namespace System { public static partial class Environment { - public static long TickCount64 => (long)Interop.Kernel32.GetTickCount64(); - [DoesNotReturn] private static void ExitRaw() => Interop.Kernel32.ExitProcess(s_latchedExitCode); } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Environment.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Environment.NativeAot.cs index 777e4e99dba78e..20a3c46aeb5748 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Environment.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Environment.NativeAot.cs @@ -55,7 +55,5 @@ internal static void ShutdownCore() AppContext.OnProcessExit(); #endif } - - public static int TickCount => (int)TickCount64; } } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs index 64483dd95fa41e..fcd46519f2de4b 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs @@ -40,10 +40,6 @@ internal static partial class RuntimeImports [RuntimeImport(RuntimeLibrary, "RhGetRuntimeVersion")] internal static extern unsafe byte* RhGetRuntimeVersion(out int cbLength); - [LibraryImport(RuntimeLibrary)] - [SuppressGCTransition] - internal static partial ulong RhpGetTickCount64(); - [LibraryImport(RuntimeLibrary)] internal static partial IntPtr RhpGetCurrentThread(); diff --git a/src/coreclr/pal/inc/pal.h b/src/coreclr/pal/inc/pal.h index 01af26fce1a6cb..9cd5c81aa591f6 100644 --- a/src/coreclr/pal/inc/pal.h +++ b/src/coreclr/pal/inc/pal.h @@ -3145,30 +3145,6 @@ RaiseFailFastException( IN PCONTEXT pContextRecord, IN DWORD dwFlags); -PALIMPORT -DWORD -PALAPI -GetTickCount(); - -PALIMPORT -ULONGLONG -PALAPI -GetTickCount64(); - -PALIMPORT -BOOL -PALAPI -QueryPerformanceCounter( - OUT LARGE_INTEGER *lpPerformanceCount - ); - -PALIMPORT -BOOL -PALAPI -QueryPerformanceFrequency( - OUT LARGE_INTEGER *lpFrequency - ); - PALIMPORT BOOL PALAPI diff --git a/src/coreclr/pal/src/config.h.in b/src/coreclr/pal/src/config.h.in index d0197a724a4202..83a6e3be90e468 100644 --- a/src/coreclr/pal/src/config.h.in +++ b/src/coreclr/pal/src/config.h.in @@ -90,9 +90,6 @@ #cmakedefine01 HAVE_SCHED_GET_PRIORITY #cmakedefine01 HAVE_WORKING_GETTIMEOFDAY #cmakedefine01 HAVE_WORKING_CLOCK_GETTIME -#cmakedefine01 HAVE_CLOCK_MONOTONIC -#cmakedefine01 HAVE_CLOCK_MONOTONIC_COARSE -#cmakedefine01 HAVE_CLOCK_GETTIME_NSEC_NP #cmakedefine01 HAVE_CLOCK_THREAD_CPUTIME #cmakedefine01 HAVE_PTHREAD_CONDATTR_SETCLOCK #cmakedefine01 MMAP_ANON_IGNORES_PROTECTION @@ -118,8 +115,6 @@ #cmakedefine01 SET_SCHEDPARAM_NEEDS_PRIVS #define CHECK_TRACE_SPECIFIERS 0 -#define HAVE_GETHRTIME 0 -#define HAVE_READ_REAL_TIME 0 #define OPEN64_IS_USED_INSTEAD_OF_OPEN 0 #define PAL_IGNORE_NORMAL_THREAD_PRIORITY 0 #define SELF_SUSPEND_FAILS_WITH_NATIVE_SUSPENSION 0 diff --git a/src/coreclr/pal/src/configure.cmake b/src/coreclr/pal/src/configure.cmake index 122e1707bad0ff..1833e46fbf5d74 100644 --- a/src/coreclr/pal/src/configure.cmake +++ b/src/coreclr/pal/src/configure.cmake @@ -394,33 +394,6 @@ check_cxx_source_runs(" #include #include -int main() -{ - int ret; - struct timespec ts; - ret = clock_gettime(CLOCK_MONOTONIC_COARSE, &ts); - - exit(ret); -}" HAVE_CLOCK_MONOTONIC_COARSE) -set(CMAKE_REQUIRED_LIBRARIES) - -check_cxx_source_runs(" -#include -#include - -int main() -{ - int ret; - ret = clock_gettime_nsec_np(CLOCK_UPTIME_RAW); - exit((ret == 0) ? 1 : 0); -}" HAVE_CLOCK_GETTIME_NSEC_NP) - -set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_RT_LIBS}) -check_cxx_source_runs(" -#include -#include -#include - int main() { int ret; diff --git a/src/coreclr/pal/src/misc/perfjitdump.cpp b/src/coreclr/pal/src/misc/perfjitdump.cpp index 9040e13dadfd00..67dc6cbbdd1318 100644 --- a/src/coreclr/pal/src/misc/perfjitdump.cpp +++ b/src/coreclr/pal/src/misc/perfjitdump.cpp @@ -26,6 +26,7 @@ #include #include #include +#include "minipal/time.h" #include "../inc/llvm/ELF.h" @@ -90,9 +91,7 @@ namespace return static_cast(__rdtsc()); } #endif - LARGE_INTEGER result; - QueryPerformanceCounter(&result); - return result.QuadPart; + return (uint64_t)minipal_hires_ticks(); } @@ -190,9 +189,7 @@ struct PerfJitDumpState // will return a direct nanosecond value. If this isn't true, // then some other method will need to be used to implement GetTimeStampNS. // Validate this is true once in Start here. - LARGE_INTEGER freq; - QueryPerformanceFrequency(&freq); - if (freq.QuadPart != tccSecondsToNanoSeconds) + if (minipal_hires_tick_frequency() != tccSecondsToNanoSeconds) { _ASSERTE(!"QueryPerformanceFrequency does not return tccSecondsToNanoSeconds. Implement JITDUMP GetTimeStampNS directly for this platform.\n"); FatalError(); diff --git a/src/coreclr/pal/src/misc/time.cpp b/src/coreclr/pal/src/misc/time.cpp index 2774cb7f125b75..a7876453a6addf 100644 --- a/src/coreclr/pal/src/misc/time.cpp +++ b/src/coreclr/pal/src/misc/time.cpp @@ -118,109 +118,6 @@ GetSystemTime( PERF_EXIT(GetSystemTime); } -/*++ -Function: - GetTickCount - -The GetTickCount function retrieves the number of milliseconds that -have elapsed since the system was started. It is limited to the -resolution of the system timer. To obtain the system timer resolution, -use the GetSystemTimeAdjustment function. - -Parameters - -This function has no parameters. - -Return Values - -The return value is the number of milliseconds that have elapsed since -the system was started. - -In the PAL implementation the return value is the elapsed time since -the start of the epoch. - ---*/ -DWORD -PALAPI -GetTickCount( - VOID) -{ - DWORD retval = 0; - PERF_ENTRY(GetTickCount); - ENTRY("GetTickCount ()\n"); - - // Get the 64-bit count from GetTickCount64 and truncate the results. - retval = (DWORD) GetTickCount64(); - - LOGEXIT("GetTickCount returns DWORD %u\n", retval); - PERF_EXIT(GetTickCount); - return retval; -} - -BOOL -PALAPI -QueryPerformanceCounter( - OUT LARGE_INTEGER *lpPerformanceCount - ) -{ - BOOL retval = TRUE; - PERF_ENTRY(QueryPerformanceCounter); - ENTRY("QueryPerformanceCounter()\n"); - -#if HAVE_CLOCK_GETTIME_NSEC_NP - lpPerformanceCount->QuadPart = (LONGLONG)clock_gettime_nsec_np(CLOCK_UPTIME_RAW); -#elif HAVE_CLOCK_MONOTONIC - struct timespec ts; - int result = clock_gettime(CLOCK_MONOTONIC, &ts); - - if (result != 0) - { - ASSERT("clock_gettime(CLOCK_MONOTONIC) failed: %d\n", result); - retval = FALSE; - } - else - { - lpPerformanceCount->QuadPart = - ((LONGLONG)(ts.tv_sec) * (LONGLONG)(tccSecondsToNanoSeconds)) + (LONGLONG)(ts.tv_nsec); - } -#else - #error "The PAL requires either mach_absolute_time() or clock_gettime(CLOCK_MONOTONIC) to be supported." -#endif - - LOGEXIT("QueryPerformanceCounter\n"); - PERF_EXIT(QueryPerformanceCounter); - return retval; -} - -BOOL -PALAPI -QueryPerformanceFrequency( - OUT LARGE_INTEGER *lpFrequency - ) -{ - BOOL retval = TRUE; - PERF_ENTRY(QueryPerformanceFrequency); - ENTRY("QueryPerformanceFrequency()\n"); - -#if HAVE_CLOCK_GETTIME_NSEC_NP - lpFrequency->QuadPart = (LONGLONG)(tccSecondsToNanoSeconds); -#elif HAVE_CLOCK_MONOTONIC - // clock_gettime() returns a result in terms of nanoseconds rather than a count. This - // means that we need to either always scale the result by the actual resolution (to - // get a count) or we need to say the resolution is in terms of nanoseconds. We prefer - // the latter since it allows the highest throughput and should minimize error propagated - // to the user. - - lpFrequency->QuadPart = (LONGLONG)(tccSecondsToNanoSeconds); -#else - #error "The PAL requires either mach_absolute_time() or clock_gettime(CLOCK_MONOTONIC) to be supported." -#endif - - LOGEXIT("QueryPerformanceFrequency\n"); - PERF_EXIT(QueryPerformanceFrequency); - return retval; -} - /*++ Function: QueryThreadCycleTime @@ -259,58 +156,6 @@ QueryThreadCycleTime( return retval; } -/*++ -Function: - GetTickCount64 - -Returns a 64-bit tick count with a millisecond resolution. It tries its best -to return monotonically increasing counts and avoid being affected by changes -to the system clock (either due to drift or due to explicit changes to system -time). ---*/ -PALAPI -ULONGLONG -GetTickCount64() -{ - LONGLONG retval = 0; - -#if HAVE_CLOCK_GETTIME_NSEC_NP - return (LONGLONG)clock_gettime_nsec_np(CLOCK_UPTIME_RAW) / (LONGLONG)(tccMillieSecondsToNanoSeconds); -#elif HAVE_CLOCK_MONOTONIC || HAVE_CLOCK_MONOTONIC_COARSE - struct timespec ts; - -#if HAVE_CLOCK_MONOTONIC_COARSE - // CLOCK_MONOTONIC_COARSE has enough precision for GetTickCount but - // doesn't have the same overhead as CLOCK_MONOTONIC. This allows - // overall higher throughput. See dotnet/coreclr#2257 for more details. - - const clockid_t clockType = CLOCK_MONOTONIC_COARSE; -#else - const clockid_t clockType = CLOCK_MONOTONIC; -#endif - - int result = clock_gettime(clockType, &ts); - - if (result != 0) - { -#if HAVE_CLOCK_MONOTONIC_COARSE - ASSERT("clock_gettime(CLOCK_MONOTONIC_COARSE) failed: %d\n", result); -#else - ASSERT("clock_gettime(CLOCK_MONOTONIC) failed: %d\n", result); -#endif - retval = FALSE; - } - else - { - retval = ((LONGLONG)(ts.tv_sec) * (LONGLONG)(tccSecondsToMillieSeconds)) + ((LONGLONG)(ts.tv_nsec) / (LONGLONG)(tccMillieSecondsToNanoSeconds)); - } -#else - #error "The PAL requires either mach_absolute_time() or clock_gettime(CLOCK_MONOTONIC) to be supported." -#endif - - return (ULONGLONG)(retval); -} - /*++ Function: PAL_nanosleep diff --git a/src/coreclr/pal/src/synchobj/mutex.cpp b/src/coreclr/pal/src/synchobj/mutex.cpp index a259f76e0192c6..f23254612c555c 100644 --- a/src/coreclr/pal/src/synchobj/mutex.cpp +++ b/src/coreclr/pal/src/synchobj/mutex.cpp @@ -33,6 +33,7 @@ SET_DEFAULT_DEBUG_CHANNEL(SYNC); // some headers have code with asserts, so do t #include #include #include +#include "minipal/time.h" using namespace CorUnix; @@ -1497,7 +1498,7 @@ MutexTryAcquireLockResult NamedMutexProcessData::TryAcquireLock(SharedMemorySyst DWORD startTime = 0; if (timeoutMilliseconds != static_cast(-1) && timeoutMilliseconds != 0) { - startTime = GetTickCount(); + startTime = (DWORD)minipal_lowres_ticks(); } // Acquire the process lock. A file lock can only be acquired once per file descriptor, so to synchronize the threads of @@ -1626,7 +1627,7 @@ MutexTryAcquireLockResult NamedMutexProcessData::TryAcquireLock(SharedMemorySyst // Poll for the file lock do { - DWORD elapsedMilliseconds = GetTickCount() - startTime; + DWORD elapsedMilliseconds = (DWORD)minipal_lowres_ticks() - startTime; if (elapsedMilliseconds >= timeoutMilliseconds) { return MutexTryAcquireLockResult::TimedOut; diff --git a/src/coreclr/pal/tests/palsuite/CMakeLists.txt b/src/coreclr/pal/tests/palsuite/CMakeLists.txt index 93b9c0070ba18b..29aaeeb274f2f9 100644 --- a/src/coreclr/pal/tests/palsuite/CMakeLists.txt +++ b/src/coreclr/pal/tests/palsuite/CMakeLists.txt @@ -355,7 +355,6 @@ add_executable_clr(paltests miscellaneous/GetEnvironmentVariableW/test6/test6.cpp miscellaneous/GetLastError/test1/test.cpp miscellaneous/GetSystemInfo/test1/test.cpp - miscellaneous/GetTickCount/test1/test.cpp miscellaneous/InterlockedCompareExchange/test1/test.cpp miscellaneous/InterlockedCompareExchange/test2/test.cpp miscellaneous/InterlockedCompareExchange64/test1/test.cpp @@ -378,8 +377,6 @@ add_executable_clr(paltests #miscellaneous/IsBadWritePtr/test1/test.cpp #miscellaneous/IsBadWritePtr/test2/test2.cpp #miscellaneous/IsBadWritePtr/test3/test3.cpp - miscellaneous/queryperformancecounter/test1/test1.cpp - miscellaneous/queryperformancefrequency/test1/test1.cpp miscellaneous/SetEnvironmentVariableA/test1/test1.cpp miscellaneous/SetEnvironmentVariableA/test2/test2.cpp miscellaneous/SetEnvironmentVariableA/test3/test3.cpp diff --git a/src/coreclr/pal/tests/palsuite/common/palsuite.cpp b/src/coreclr/pal/tests/palsuite/common/palsuite.cpp index 34972558853c4f..030d8cc13cd6d6 100644 --- a/src/coreclr/pal/tests/palsuite/common/palsuite.cpp +++ b/src/coreclr/pal/tests/palsuite/common/palsuite.cpp @@ -12,6 +12,7 @@ #include "palsuite.h" +#include "minipal/time.h" const char* szTextFile = "text.txt"; @@ -53,13 +54,7 @@ char* convertC(const WCHAR * wString) UINT64 GetHighPrecisionTimeStamp(LARGE_INTEGER performanceFrequency) { - LARGE_INTEGER ts; - if (!QueryPerformanceCounter(&ts)) - { - Fail("ERROR: Unable to query performance counter!\n"); - } - - return ts.QuadPart / (performanceFrequency.QuadPart / 1000); + return (UINT64)minipal_hires_ticks(); } static const char* rgchPathDelim = "/"; @@ -223,4 +218,4 @@ DeleteFileW( } return FALSE; -} \ No newline at end of file +} diff --git a/src/coreclr/pal/tests/palsuite/common/palsuite.h b/src/coreclr/pal/tests/palsuite/common/palsuite.h index 9494daed71bebd..ed5766963533e8 100644 --- a/src/coreclr/pal/tests/palsuite/common/palsuite.h +++ b/src/coreclr/pal/tests/palsuite/common/palsuite.h @@ -25,6 +25,7 @@ typedef unsigned short char16_t; #include #include #include +#include #include #define PALTEST(testfunc, testname) \ diff --git a/src/coreclr/pal/tests/palsuite/compilableTests.txt b/src/coreclr/pal/tests/palsuite/compilableTests.txt index d9c36e4ab5d299..7883adf0809db7 100644 --- a/src/coreclr/pal/tests/palsuite/compilableTests.txt +++ b/src/coreclr/pal/tests/palsuite/compilableTests.txt @@ -271,7 +271,6 @@ miscellaneous/GetEnvironmentVariableW/test5/paltest_getenvironmentvariablew_test miscellaneous/GetEnvironmentVariableW/test6/paltest_getenvironmentvariablew_test6 miscellaneous/GetLastError/test1/paltest_getlasterror_test1 miscellaneous/GetSystemInfo/test1/paltest_getsysteminfo_test1 -miscellaneous/GetTickCount/test1/paltest_gettickcount_test1 miscellaneous/InterlockedCompareExchange/test1/paltest_interlockedcompareexchange_test1 miscellaneous/InterlockedCompareExchange/test2/paltest_interlockedcompareexchange_test2 miscellaneous/InterlockedCompareExchange64/test1/paltest_interlockedcompareexchange64_test1 @@ -289,8 +288,6 @@ miscellaneous/InterlockedIncrement/test1/paltest_interlockedincrement_test1 miscellaneous/InterlockedIncrement/test2/paltest_interlockedincrement_test2 miscellaneous/InterlockedIncrement64/test1/paltest_interlockedincrement64_test1 miscellaneous/InterlockedIncrement64/test2/paltest_interlockedincrement64_test2 -miscellaneous/queryperformancecounter/test1/paltest_queryperformancecounter_test1 -miscellaneous/queryperformancefrequency/test1/paltest_queryperformancefrequency_test1 miscellaneous/SetEnvironmentVariableA/test1/paltest_setenvironmentvariablea_test1 miscellaneous/SetEnvironmentVariableA/test2/paltest_setenvironmentvariablea_test2 miscellaneous/SetEnvironmentVariableA/test3/paltest_setenvironmentvariablea_test3 diff --git a/src/coreclr/pal/tests/palsuite/composite/object_management/event/nonshared/event.cpp b/src/coreclr/pal/tests/palsuite/composite/object_management/event/nonshared/event.cpp index bc521da91b3a15..fab380597d7386 100644 --- a/src/coreclr/pal/tests/palsuite/composite/object_management/event/nonshared/event.cpp +++ b/src/coreclr/pal/tests/palsuite/composite/object_management/event/nonshared/event.cpp @@ -142,7 +142,7 @@ PALTEST(composite_object_management_event_nonshared_paltest_event_nonshared, "co } /* Register the start time */ - dwStartTime = GetTickCount(); + dwStartTime = (DWORD)minipal_lowres_ticks(); processStats.relationId = RELATION_ID; processStats.processId = USE_PROCESS_COUNT; @@ -308,7 +308,7 @@ void PALAPI Run_Thread_event_nonshared (LPVOID lpParam) Fail("Error while waiting for StartTest Event@ thread %d, RC is %d, Error is %d\n", Id, dwWaitResult, GetLastError()); } - dwStartTime = GetTickCount(); + dwStartTime = (DWORD)minipal_lowres_ticks(); for( i = 0; i < REPEAT_COUNT; i++ ) { diff --git a/src/coreclr/pal/tests/palsuite/composite/object_management/event/nonshared/main.cpp b/src/coreclr/pal/tests/palsuite/composite/object_management/event/nonshared/main.cpp index 115632a833f43b..65a82a38ca0885 100644 --- a/src/coreclr/pal/tests/palsuite/composite/object_management/event/nonshared/main.cpp +++ b/src/coreclr/pal/tests/palsuite/composite/object_management/event/nonshared/main.cpp @@ -114,7 +114,7 @@ PALTEST(composite_object_management_event_nonshared_paltest_event_nonshared, "co } /* Register the start time */ - dwStartTime = GetTickCount(); + dwStartTime = (DWORD)minipal_lowres_ticks(); testStats.relationId = RELATION_ID; testStats.processCount = PROCESS_COUNT; testStats.threadCount = THREAD_COUNT; diff --git a/src/coreclr/pal/tests/palsuite/composite/object_management/event/shared/event.cpp b/src/coreclr/pal/tests/palsuite/composite/object_management/event/shared/event.cpp index 155d5e9bd9b452..26f528a3e80ff9 100644 --- a/src/coreclr/pal/tests/palsuite/composite/object_management/event/shared/event.cpp +++ b/src/coreclr/pal/tests/palsuite/composite/object_management/event/shared/event.cpp @@ -156,7 +156,7 @@ PALTEST(composite_object_management_event_shared_paltest_event_shared, "composit } /* Register the start time */ - dwStartTime = GetTickCount(); + dwStartTime = (DWORD)minipal_lowres_ticks(); processStats.relationId = RELATION_ID; processStats.processId = USE_PROCESS_COUNT; @@ -321,7 +321,7 @@ void PALAPI Run_Thread_event_shared (LPVOID lpParam) testStatus = FAIL; } - dwStartTime = GetTickCount(); + dwStartTime = (DWORD)minipal_lowres_ticks(); for( i = 0; i < REPEAT_COUNT; i++ ) { diff --git a/src/coreclr/pal/tests/palsuite/composite/object_management/event/shared/main.cpp b/src/coreclr/pal/tests/palsuite/composite/object_management/event/shared/main.cpp index cce500d10cbf15..32287705cbb91d 100644 --- a/src/coreclr/pal/tests/palsuite/composite/object_management/event/shared/main.cpp +++ b/src/coreclr/pal/tests/palsuite/composite/object_management/event/shared/main.cpp @@ -130,7 +130,7 @@ PALTEST(composite_object_management_event_shared_paltest_event_shared, "composit } /* Register the start time */ - dwStartTime = GetTickCount(); + dwStartTime = (DWORD)minipal_lowres_ticks(); testStats.relationId = RELATION_ID; testStats.processCount = PROCESS_COUNT; testStats.threadCount = THREAD_COUNT; diff --git a/src/coreclr/pal/tests/palsuite/composite/object_management/mutex/nonshared/main.cpp b/src/coreclr/pal/tests/palsuite/composite/object_management/mutex/nonshared/main.cpp index 4277e66e0821dc..3878df1fe9ef7b 100644 --- a/src/coreclr/pal/tests/palsuite/composite/object_management/mutex/nonshared/main.cpp +++ b/src/coreclr/pal/tests/palsuite/composite/object_management/mutex/nonshared/main.cpp @@ -115,7 +115,7 @@ PALTEST(composite_object_management_mutex_nonshared_paltest_mutex_nonshared, "co } /* Register the start time */ - dwStartTime = GetTickCount(); + dwStartTime = (DWORD)minipal_lowres_ticks(); testStats.relationId = RELATION_ID; testStats.processCount = PROCESS_COUNT; testStats.threadCount = THREAD_COUNT; diff --git a/src/coreclr/pal/tests/palsuite/composite/object_management/mutex/nonshared/mutex.cpp b/src/coreclr/pal/tests/palsuite/composite/object_management/mutex/nonshared/mutex.cpp index a3503dc4702da2..d22381c288313d 100644 --- a/src/coreclr/pal/tests/palsuite/composite/object_management/mutex/nonshared/mutex.cpp +++ b/src/coreclr/pal/tests/palsuite/composite/object_management/mutex/nonshared/mutex.cpp @@ -135,7 +135,7 @@ PALTEST(composite_object_management_mutex_nonshared_paltest_mutex_nonshared, "co } /* Register the start time */ - dwStartTime = GetTickCount(); + dwStartTime = (DWORD)minipal_lowres_ticks(); processStats.relationId = RELATION_ID; processStats.processId = USE_PROCESS_COUNT; @@ -289,7 +289,7 @@ void PALAPI Run_Thread_mutex_nonshared (LPVOID lpParam) testStatus = FAIL; } - dwStartTime = GetTickCount(); + dwStartTime = (DWORD)minipal_lowres_ticks(); for( i = 0; i < REPEAT_COUNT; i++ ) { diff --git a/src/coreclr/pal/tests/palsuite/composite/object_management/mutex/shared/main.cpp b/src/coreclr/pal/tests/palsuite/composite/object_management/mutex/shared/main.cpp index 3790785d065126..c42b95d9f5b381 100644 --- a/src/coreclr/pal/tests/palsuite/composite/object_management/mutex/shared/main.cpp +++ b/src/coreclr/pal/tests/palsuite/composite/object_management/mutex/shared/main.cpp @@ -132,7 +132,7 @@ PALTEST(composite_object_management_mutex_shared_paltest_mutex_shared, "composit } /* Register the start time */ - dwStartTime = GetTickCount(); + dwStartTime = (DWORD)minipal_lowres_ticks(); testStats.relationId = RELATION_ID; testStats.processCount = PROCESS_COUNT; testStats.threadCount = THREAD_COUNT; diff --git a/src/coreclr/pal/tests/palsuite/composite/object_management/mutex/shared/mutex.cpp b/src/coreclr/pal/tests/palsuite/composite/object_management/mutex/shared/mutex.cpp index 51400a99564ed7..8bc6645c04f4f1 100644 --- a/src/coreclr/pal/tests/palsuite/composite/object_management/mutex/shared/mutex.cpp +++ b/src/coreclr/pal/tests/palsuite/composite/object_management/mutex/shared/mutex.cpp @@ -156,7 +156,7 @@ PALTEST(composite_object_management_mutex_shared_paltest_mutex_shared, "composit } /* Register the start time */ - dwStartTime = GetTickCount(); + dwStartTime = (DWORD)minipal_lowres_ticks(); processStats.relationId = RELATION_ID; processStats.processId = USE_PROCESS_COUNT; @@ -306,7 +306,7 @@ void PALAPI Run_Thread_mutex_shared (LPVOID lpParam) testStatus = FAIL; } - dwStartTime = GetTickCount(); + dwStartTime = (DWORD)minipal_lowres_ticks(); for( i = 0; i < REPEAT_COUNT; i++ ) { diff --git a/src/coreclr/pal/tests/palsuite/composite/object_management/semaphore/nonshared/main.cpp b/src/coreclr/pal/tests/palsuite/composite/object_management/semaphore/nonshared/main.cpp index 99b0b2b2a55377..3075b29c2a6669 100644 --- a/src/coreclr/pal/tests/palsuite/composite/object_management/semaphore/nonshared/main.cpp +++ b/src/coreclr/pal/tests/palsuite/composite/object_management/semaphore/nonshared/main.cpp @@ -115,7 +115,7 @@ PALTEST(composite_object_management_semaphore_nonshared_paltest_semaphore_nonsha } /* Register the start time */ - dwStartTime = GetTickCount(); + dwStartTime = (DWORD)minipal_lowres_ticks(); testStats.relationId = RELATION_ID; testStats.processCount = PROCESS_COUNT; testStats.threadCount = THREAD_COUNT; diff --git a/src/coreclr/pal/tests/palsuite/composite/object_management/semaphore/nonshared/semaphore.cpp b/src/coreclr/pal/tests/palsuite/composite/object_management/semaphore/nonshared/semaphore.cpp index b37c1218d6431d..89616ad01d5a01 100644 --- a/src/coreclr/pal/tests/palsuite/composite/object_management/semaphore/nonshared/semaphore.cpp +++ b/src/coreclr/pal/tests/palsuite/composite/object_management/semaphore/nonshared/semaphore.cpp @@ -143,7 +143,7 @@ PALTEST(composite_object_management_semaphore_nonshared_paltest_semaphore_nonsha } /* Register the start time */ - dwStartTime = GetTickCount(); + dwStartTime = (DWORD)minipal_lowres_ticks(); processStats.relationId = RELATION_ID; processStats.processId = USE_PROCESS_COUNT; @@ -294,7 +294,7 @@ void PALAPI Run_Thread_semaphore_nonshared (LPVOID lpParam) Fail("Error while waiting for StartTest Event@ thread %d, RC is %d, Error is %d\n", Id, dwWaitResult, GetLastError()); } - dwStartTime = GetTickCount(); + dwStartTime = (DWORD)minipal_lowres_ticks(); for( i = 0; i < REPEAT_COUNT; i++ ) { diff --git a/src/coreclr/pal/tests/palsuite/composite/object_management/semaphore/shared/main.cpp b/src/coreclr/pal/tests/palsuite/composite/object_management/semaphore/shared/main.cpp index df1ea1f7bea361..e96e77abda1248 100644 --- a/src/coreclr/pal/tests/palsuite/composite/object_management/semaphore/shared/main.cpp +++ b/src/coreclr/pal/tests/palsuite/composite/object_management/semaphore/shared/main.cpp @@ -141,7 +141,7 @@ us anything over what we already have." } /* Register the start time */ - dwStartTime = GetTickCount(); + dwStartTime = (DWORD)minipal_lowres_ticks(); testStats.relationId = RELATION_ID; testStats.processCount = PROCESS_COUNT; testStats.threadCount = THREAD_COUNT; diff --git a/src/coreclr/pal/tests/palsuite/composite/object_management/semaphore/shared/semaphore.cpp b/src/coreclr/pal/tests/palsuite/composite/object_management/semaphore/shared/semaphore.cpp index bcad3c3ada4215..0fec6fef7e971c 100644 --- a/src/coreclr/pal/tests/palsuite/composite/object_management/semaphore/shared/semaphore.cpp +++ b/src/coreclr/pal/tests/palsuite/composite/object_management/semaphore/shared/semaphore.cpp @@ -155,7 +155,7 @@ PALTEST(composite_object_management_semaphore_shared_paltest_semaphore_shared, " } /* Register the start time */ - dwStartTime = GetTickCount(); + dwStartTime = (DWORD)minipal_lowres_ticks(); processStats.relationId = RELATION_ID; processStats.processId = USE_PROCESS_COUNT; @@ -306,7 +306,7 @@ void PALAPI Run_Thread_semaphore_shared (LPVOID lpParam) Fail("Error while waiting for StartTest Event@ thread %d, RC is %d, Error is %d\n", Id, dwWaitResult, GetLastError()); } - dwStartTime = GetTickCount(); + dwStartTime = (DWORD)minipal_lowres_ticks(); for( i = 0; i < REPEAT_COUNT; i++ ) { diff --git a/src/coreclr/pal/tests/palsuite/composite/synchronization/criticalsection/criticalsection.cpp b/src/coreclr/pal/tests/palsuite/composite/synchronization/criticalsection/criticalsection.cpp index 80dd3935d06217..5935e46f028fae 100644 --- a/src/coreclr/pal/tests/palsuite/composite/synchronization/criticalsection/criticalsection.cpp +++ b/src/coreclr/pal/tests/palsuite/composite/synchronization/criticalsection/criticalsection.cpp @@ -176,7 +176,7 @@ enterandleavecs( LPVOID lpParam ) } //Collect operation start time - dwStart = GetTickCount(); + dwStart = (DWORD)minipal_lowres_ticks(); //Operation starts loopcount times for(i = 0; i < loopcount; i++) @@ -193,7 +193,7 @@ enterandleavecs( LPVOID lpParam ) stats.operationsTotal++; } //collect operation end time - stats.operationTime = GetTickCount() - dwStart; + stats.operationTime = (DWORD)minipal_lowres_ticks() - dwStart; /*Trace("\n\n\n\nOperation Time %d\n", stats.operationTime); Trace("Operation Passed %d\n", stats.operationsPassed); @@ -258,7 +258,7 @@ processStats.processId = USE_PROCESS_COUNT; processStats.relationId = RELATION_ID; //Will change later //Start Process Time Capture -dwStart = GetTickCount(); +dwStart = (DWORD)minipal_lowres_ticks(); //setup file for thread result collection statisticsSize = sizeof(struct statistics); @@ -322,7 +322,7 @@ if ( WAIT_OBJECT_0 != WaitForMultipleObjects (THREAD_COUNT,hThread,TRUE, INFINIT //Get the end time of the process -processStats.operationTime = GetTickCount() - dwStart; +processStats.operationTime = (DWORD)minipal_lowres_ticks() - dwStart; //Write Process Result Contents to File if(hProcessFile!= NULL) diff --git a/src/coreclr/pal/tests/palsuite/composite/synchronization/criticalsection/mainWrapper.cpp b/src/coreclr/pal/tests/palsuite/composite/synchronization/criticalsection/mainWrapper.cpp index 529dddb3065e2b..99a1d0c5dad7f3 100644 --- a/src/coreclr/pal/tests/palsuite/composite/synchronization/criticalsection/mainWrapper.cpp +++ b/src/coreclr/pal/tests/palsuite/composite/synchronization/criticalsection/mainWrapper.cpp @@ -134,7 +134,7 @@ if(hFile == NULL) } //Start Process Time Capture -dwStart = GetTickCount(); +dwStart = (DWORD)minipal_lowres_ticks(); for( i = 0; i < USE_PROCESS_COUNT; i++ ) { @@ -216,7 +216,7 @@ for( i = 0; i < USE_PROCESS_COUNT; i++ ) } //Get the end time of the process -appStats.operationTime = GetTickCount() - dwStart; +appStats.operationTime = (DWORD)minipal_lowres_ticks() - dwStart; if( testReturnCode == PASS) { diff --git a/src/coreclr/pal/tests/palsuite/composite/wfmo/main.cpp b/src/coreclr/pal/tests/palsuite/composite/wfmo/main.cpp index 0e0684e5f4f07e..e12cb5d596b88e 100644 --- a/src/coreclr/pal/tests/palsuite/composite/wfmo/main.cpp +++ b/src/coreclr/pal/tests/palsuite/composite/wfmo/main.cpp @@ -127,7 +127,7 @@ PALTEST(composite_wfmo_paltest_composite_wfmo, "composite/wfmo/paltest_composite } /* Register the start time */ - dwStartTime = GetTickCount(); + dwStartTime = (DWORD)minipal_lowres_ticks(); testStats.relationId = 0; testStats.relationId = RELATION_ID; testStats.processCount = PROCESS_COUNT; diff --git a/src/coreclr/pal/tests/palsuite/composite/wfmo/mutex.cpp b/src/coreclr/pal/tests/palsuite/composite/wfmo/mutex.cpp index 82f59880c404de..ed5de0fafd16ea 100644 --- a/src/coreclr/pal/tests/palsuite/composite/wfmo/mutex.cpp +++ b/src/coreclr/pal/tests/palsuite/composite/wfmo/mutex.cpp @@ -146,7 +146,7 @@ PALTEST(composite_wfmo_paltest_composite_wfmo, "composite/wfmo/paltest_composite } /* Register the start time */ - dwStartTime = GetTickCount(); + dwStartTime = (DWORD)minipal_lowres_ticks(); processStats.relationId = RELATION_ID; processStats.processId = USE_PROCESS_COUNT; @@ -306,7 +306,7 @@ void PALAPI Run_Thread_composite_wfmo (LPVOID lpParam) } /* Register the start time */ - dwStartTime = GetTickCount(); + dwStartTime = (DWORD)minipal_lowres_ticks(); /* Run the tests repeat count times */ for( i = 0; i < REPEAT_COUNT; i++ ) diff --git a/src/coreclr/pal/tests/palsuite/issues.targets b/src/coreclr/pal/tests/palsuite/issues.targets index 67b5df72eeb336..a4381220bb96a0 100644 --- a/src/coreclr/pal/tests/palsuite/issues.targets +++ b/src/coreclr/pal/tests/palsuite/issues.targets @@ -18,10 +18,4 @@ - - - https://github.com/dotnet/runtime/issues/7639 - - - diff --git a/src/coreclr/pal/tests/palsuite/miscellaneous/GetTickCount/test1/test.cpp b/src/coreclr/pal/tests/palsuite/miscellaneous/GetTickCount/test1/test.cpp deleted file mode 100644 index f783ff878ceb8f..00000000000000 --- a/src/coreclr/pal/tests/palsuite/miscellaneous/GetTickCount/test1/test.cpp +++ /dev/null @@ -1,58 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -/*============================================================ -** -** Source: -** -** Source : test1.c -** -** Purpose: Test for GetTickCount() function -** -** -**=========================================================*/ - -#include - -PALTEST(miscellaneous_GetTickCount_test1_paltest_gettickcount_test1, "miscellaneous/GetTickCount/test1/paltest_gettickcount_test1") -{ - - DWORD FirstCount = 0; - DWORD SecondCount = 0; - - /* - * Initialize the PAL and return FAILURE if this fails - */ - - if(0 != (PAL_Initialize(argc, argv))) - { - return FAIL; - } - - /* Grab a FirstCount, then loop for a bit to make the clock increase */ - FirstCount = GetTickCount(); - - /* Make sure some time passes */ - Sleep(60); //Since the get tick count is accurate within 55 milliseconds. - - /* Get a second count */ - SecondCount = GetTickCount(); - - /* Make sure the second one is bigger than the first. - This isn't the best test, but it at least shows that it's returning a - DWORD which is increasing. - */ - - if(FirstCount >= SecondCount) - { - Fail("ERROR: The first time (%d) was greater/equal than the second time " - " (%d). The tick count should have increased.\n", - FirstCount,SecondCount); - } - - PAL_Terminate(); - return PASS; -} - - - diff --git a/src/coreclr/pal/tests/palsuite/miscellaneous/queryperformancecounter/test1/test1.cpp b/src/coreclr/pal/tests/palsuite/miscellaneous/queryperformancecounter/test1/test1.cpp deleted file mode 100644 index d14fa2fa2bb226..00000000000000 --- a/src/coreclr/pal/tests/palsuite/miscellaneous/queryperformancecounter/test1/test1.cpp +++ /dev/null @@ -1,106 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -/*============================================================ -** -** Source: test1.c -** -** Purpose: Test for QueryPerformanceCounter function -** -** -**=========================================================*/ - -/* Depends on: QueryPerformanceFrequency. */ - -#include - - -PALTEST(miscellaneous_queryperformancecounter_test1_paltest_queryperformancecounter_test1, "miscellaneous/queryperformancecounter/test1/paltest_queryperformancecounter_test1") -{ - /* Milliseconds of error which are acceptable Function execution time, etc. - FreeBSD has a "standard" resolution of 50ms for waiting operations, so we - must take that into account as well */ - DWORD AcceptableTimeError = 15; - - int i; - int NumIterations = 100; - DWORD AvgTimeDiff; - DWORD TimeDiff[100]; - DWORD TotalTimeDiff = 0; - DWORD SleepInterval = 50; - LARGE_INTEGER StartTime; - LARGE_INTEGER EndTime; - LARGE_INTEGER Freq; - - /* Initialize the PAL. - */ - - if(0 != (PAL_Initialize(argc, argv))) - { - return FAIL; - } - - /* Get the frequency of the High-Performance Counter, - * in order to convert counter time to milliseconds. - */ - if (!QueryPerformanceFrequency(&Freq)) - { - Fail("ERROR:%u:Unable to retrieve the frequency of the " - "high-resolution performance counter.\n", - GetLastError()); - } - - /* Perform this set of sleep timings a number of times. - */ - for(i=0; i < NumIterations; i++) - { - - /* Get the current counter value. - */ - if (!QueryPerformanceCounter(&StartTime)) - { - Fail("ERROR:%u:Unable to retrieve the current value of the " - "high-resolution performance counter.\n", - GetLastError()); - } - - /* Sleep a predetermined interval. - */ - Sleep(SleepInterval); - - /* Get the new current counter value. - */ - if (!QueryPerformanceCounter(&EndTime)) - { - Fail("ERROR:%u:Unable to retrieve the current value of the " - "high-resolution performance counter.\n", - GetLastError()); - } - - /* Determine elapsed time, in milliseconds. Compare the elapsed time - * with the sleep interval, and add to counter. - */ - TimeDiff[i] = (DWORD)(((EndTime.QuadPart - StartTime.QuadPart)*1000)/ - (Freq.QuadPart)); - TotalTimeDiff += TimeDiff[i] - SleepInterval; - - } - - /* Verify that the average of the difference between the performance - * counter and the sleep interval is within our acceptable range. - */ - AvgTimeDiff = TotalTimeDiff / NumIterations; - if (AvgTimeDiff > AcceptableTimeError) - { - Fail("ERROR: average diff %u acceptable %u.\n", - AvgTimeDiff, - AcceptableTimeError); - } - - /* Terminate the PAL. - */ - PAL_Terminate(); - return PASS; -} - - diff --git a/src/coreclr/pal/tests/palsuite/miscellaneous/queryperformancefrequency/test1/test1.cpp b/src/coreclr/pal/tests/palsuite/miscellaneous/queryperformancefrequency/test1/test1.cpp deleted file mode 100644 index 3e370ddafb10f6..00000000000000 --- a/src/coreclr/pal/tests/palsuite/miscellaneous/queryperformancefrequency/test1/test1.cpp +++ /dev/null @@ -1,58 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -/*============================================================ -** -** Source: test1.c -** -** Purpose: Test for QueryPerformanceFrequency function -** -** -**=========================================================*/ - -#include - -PALTEST(miscellaneous_queryperformancefrequency_test1_paltest_queryperformancefrequency_test1, "miscellaneous/queryperformancefrequency/test1/paltest_queryperformancefrequency_test1") -{ - - LARGE_INTEGER Freq; - - /* Initialize the PAL. - */ - - if(0 != (PAL_Initialize(argc, argv))) - { - return FAIL; - } - - /* Check the return value of the performance - * frequency, a value of zero indicates that - * either the call has failed or the - * high-resolution performance counter is not - * installed. - */ - if (!QueryPerformanceFrequency(&Freq)) - { - - Fail("ERROR:%u:Unable to retrieve the frequency of the " - "high-resolution performance counter.\n", - GetLastError()); - } - - - /* Check the return value the frequency the - * value should be non-zero. - */ - if (Freq.QuadPart == 0) - { - - Fail("ERROR: The frequency has been determined to be 0 " - "the frequency should be non-zero.\n"); - - } - - /* Terminate the PAL. - */ - PAL_Terminate(); - return PASS; -} diff --git a/src/coreclr/pal/tests/palsuite/paltestlist.txt b/src/coreclr/pal/tests/palsuite/paltestlist.txt index c5d87fb07b4eec..202816002d2361 100644 --- a/src/coreclr/pal/tests/palsuite/paltestlist.txt +++ b/src/coreclr/pal/tests/palsuite/paltestlist.txt @@ -226,7 +226,6 @@ miscellaneous/GetEnvironmentVariableW/test5/paltest_getenvironmentvariablew_test miscellaneous/GetEnvironmentVariableW/test6/paltest_getenvironmentvariablew_test6 miscellaneous/GetLastError/test1/paltest_getlasterror_test1 miscellaneous/GetSystemInfo/test1/paltest_getsysteminfo_test1 -miscellaneous/GetTickCount/test1/paltest_gettickcount_test1 miscellaneous/InterlockedCompareExchange/test1/paltest_interlockedcompareexchange_test1 miscellaneous/InterlockedCompareExchange/test2/paltest_interlockedcompareexchange_test2 miscellaneous/InterlockedCompareExchange64/test1/paltest_interlockedcompareexchange64_test1 @@ -243,8 +242,6 @@ miscellaneous/InterlockedIncrement/test1/paltest_interlockedincrement_test1 miscellaneous/InterlockedIncrement/test2/paltest_interlockedincrement_test2 miscellaneous/InterlockedIncrement64/test1/paltest_interlockedincrement64_test1 miscellaneous/InterlockedIncrement64/test2/paltest_interlockedincrement64_test2 -miscellaneous/queryperformancecounter/test1/paltest_queryperformancecounter_test1 -miscellaneous/queryperformancefrequency/test1/paltest_queryperformancefrequency_test1 miscellaneous/SetEnvironmentVariableA/test1/paltest_setenvironmentvariablea_test1 miscellaneous/SetEnvironmentVariableA/test2/paltest_setenvironmentvariablea_test2 miscellaneous/SetEnvironmentVariableA/test3/paltest_setenvironmentvariablea_test3 diff --git a/src/coreclr/pal/tests/palsuite/threading/NamedMutex/test1/namedmutex.cpp b/src/coreclr/pal/tests/palsuite/threading/NamedMutex/test1/namedmutex.cpp index bfc1018f8db5fa..340a83e67d2104 100644 --- a/src/coreclr/pal/tests/palsuite/threading/NamedMutex/test1/namedmutex.cpp +++ b/src/coreclr/pal/tests/palsuite/threading/NamedMutex/test1/namedmutex.cpp @@ -267,7 +267,7 @@ bool WaitForMutexToBeCreated(const char *testName, AutoCloseMutexHandle &m, cons { char eventName[MaxPathSize]; BuildName(testName, eventName, eventNamePrefix); - DWORD startTime = GetTickCount(); + DWORD startTime = (DWORD)minipal_lowres_ticks(); while (true) { m = TestOpenMutex(eventName); @@ -275,7 +275,7 @@ bool WaitForMutexToBeCreated(const char *testName, AutoCloseMutexHandle &m, cons { return true; } - if (GetTickCount() - startTime >= FailTimeoutMilliseconds) + if ((DWORD)minipal_lowres_ticks() - startTime >= FailTimeoutMilliseconds) { return false; } @@ -785,7 +785,7 @@ bool AbandonTests_Parent() // Since the child abandons the mutex, and a child process may not release the file lock on the shared memory file before // indicating completion to the parent, make sure to delete the shared memory file by repeatedly opening/closing the mutex // until the parent process becomes the last process to reference the mutex and closing it deletes the file. - DWORD startTime = GetTickCount(); + DWORD startTime = (DWORD)minipal_lowres_ticks(); while (true) { m.Close(); @@ -794,7 +794,7 @@ bool AbandonTests_Parent() break; } - TestAssert(GetTickCount() - startTime < FailTimeoutMilliseconds); + TestAssert((DWORD)minipal_lowres_ticks() - startTime < FailTimeoutMilliseconds); m = TestOpenMutex(BuildName(testName, name, NamePrefix)); } @@ -1182,7 +1182,7 @@ DWORD PALAPI StressTest(void *arg) { // Run the specified test continuously for the stress duration SIZE_T testIndex = reinterpret_cast(arg); - DWORD startTime = GetTickCount(); + DWORD startTime = (DWORD)minipal_lowres_ticks(); do { ++g_stressTestCounts[testIndex]; @@ -1193,7 +1193,7 @@ DWORD PALAPI StressTest(void *arg) } } while ( InterlockedCompareExchange(&g_stressResult, false, false) == true && - GetTickCount() - startTime < g_stressDurationMilliseconds); + (DWORD)minipal_lowres_ticks() - startTime < g_stressDurationMilliseconds); return 0; } diff --git a/src/coreclr/pal/tests/palsuite/threading/QueryThreadCycleTime/test1/test1.cpp b/src/coreclr/pal/tests/palsuite/threading/QueryThreadCycleTime/test1/test1.cpp index 2244d54e65e4b3..7f4f37e3e1c856 100644 --- a/src/coreclr/pal/tests/palsuite/threading/QueryThreadCycleTime/test1/test1.cpp +++ b/src/coreclr/pal/tests/palsuite/threading/QueryThreadCycleTime/test1/test1.cpp @@ -56,7 +56,7 @@ PALTEST(threading_QueryThreadCycleTime_test1_paltest_querythreadcycletime_test1, LONG64 x; /* Init is in milliseconds, so we will convert later */ - Init = (LONG64)GetTickCount(); + Init = minipal_lowres_ticks(); x = Init + 3; volatile int counter; do { @@ -65,8 +65,8 @@ PALTEST(threading_QueryThreadCycleTime_test1_paltest_querythreadcycletime_test1, // spin to consume CPU time } - } while (x > GetTickCount()); - Expected += (GetTickCount() - Init) * MSEC_TO_NSEC; + } while (x > minipal_lowres_ticks()); + Expected += (minipal_lowres_ticks() - Init) * MSEC_TO_NSEC; /* Get a second count */ if (!QueryThreadCycleTime(cThread, (PULONG64)&SecondCount)) { diff --git a/src/coreclr/pal/tests/palsuite/threading/Sleep/test2/sleep.cpp b/src/coreclr/pal/tests/palsuite/threading/Sleep/test2/sleep.cpp index a4e1b465af2c68..6fb148b681f2fd 100644 --- a/src/coreclr/pal/tests/palsuite/threading/Sleep/test2/sleep.cpp +++ b/src/coreclr/pal/tests/palsuite/threading/Sleep/test2/sleep.cpp @@ -8,8 +8,6 @@ ** Purpose: Test to establish whether the Sleep function stops the thread from ** executing for the specified times. ** -** Dependencies: GetTickCount -** ** **=========================================================*/ diff --git a/src/coreclr/pal/tests/palsuite/wasm/index.html b/src/coreclr/pal/tests/palsuite/wasm/index.html index 9ca90c2d7c976e..28dd69524bb356 100644 --- a/src/coreclr/pal/tests/palsuite/wasm/index.html +++ b/src/coreclr/pal/tests/palsuite/wasm/index.html @@ -16,11 +16,9 @@

PAL Tests WASM

"file_io/SetFilePointer/test7/paltest_setfilepointer_test7", // tries to allocate 4GB of memory in MEMFS when run with chromedriver "filemapping_memmgt/MapViewOfFile/test1/paltest_mapviewoffile_test1", // infinite loop and then chrome crashes "filemapping_memmgt/ProbeMemory/ProbeMemory_neg1/paltest_probememory_probememory_neg1", - "miscellaneous/GetTickCount", // blocks main thread "miscellaneous/InterlockedCompareExchange/test2/paltest_interlockedcompareexchange_test2", // MT test "miscellaneous/InterlockedDecrement/test2/paltest_interlockeddecrement_test2", // MT test "miscellaneous/InterlockedIncrement/test2/paltest_interlockedincrement_test2", // MT test - "miscellaneous/queryperformancecounter", // blocks main thread "threading/", // we're single-threaded // "threading/CriticalSectionFunctions/test8/paltest_criticalsectionfunctions_test8", // blocks main thread ]; diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/HeaderNode.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/HeaderNode.cs index b652563a9583d3..f010b4fd0934f0 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/HeaderNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/HeaderNode.cs @@ -129,13 +129,10 @@ public void Add(ReadyToRunSectionType id, DependencyNodeCore node, public override bool StaticDependenciesAreComputed => true; - public override ObjectNodeSection GetSection(NodeFactory factory) - { - if (factory.Target.IsWindows) - return ObjectNodeSection.ReadOnlyDataSection; - else - return ObjectNodeSection.DataSection; - } + // For R2R, we can put the header in the read-only section on non-Windows as well. Since we emit a PE image + // and do our own mapping, we don't need it to be writeable for the OS loader to handle absolute pointer relocs. + // Our R2R PE images group read-only data into the .text section, so this doesn't result in more work to map. + public override ObjectNodeSection GetSection(NodeFactory factory) => ObjectNodeSection.ReadOnlyDataSection; public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/R2RPEBuilder.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/R2RPEBuilder.cs index 672df8e84b5da4..7a8aa110e7ff5d 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/R2RPEBuilder.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/R2RPEBuilder.cs @@ -21,7 +21,7 @@ namespace ILCompiler.PEWriter /// metadata and IL and adding new code and data representing the R2R JITted code and /// additional runtime structures (R2R header and tables). /// - public class R2RPEBuilder : PEBuilder + public sealed class R2RPEBuilder : PEBuilder { /// /// Number of low-order RVA bits that must match file position on Linux. @@ -73,7 +73,7 @@ public SectionRVADelta(int startRVA, int endRVA, int deltaRVA) /// Name of the initialized data section. /// public const string SDataSectionName = ".sdata"; - + /// /// Name of the relocation section. /// @@ -94,11 +94,6 @@ public SectionRVADelta(int startRVA, int endRVA, int deltaRVA) /// private TargetDetails _target; - /// - /// Complete list of sections to emit into the output R2R executable. - /// - private ImmutableArray
_sections; - /// /// Callback to retrieve the runtime function table which needs setting to the /// ExceptionTable PE directory entry. @@ -112,28 +107,48 @@ public SectionRVADelta(int startRVA, int endRVA, int deltaRVA) /// private List _sectionRvaDeltas; - /// - /// Logical section start RVAs. When emitting R2R PE executables for Linux, we must - /// align RVA's so that their 'RVABitsToMatchFilePos' lowest-order bits match the - /// file position (otherwise memory mapping of the file fails and CoreCLR silently - /// switches over to runtime JIT). PEBuilder doesn't support this today so that we - /// must store the RVA's and post-process the produced PE by patching the section - /// headers in the PE header. - /// - private int[] _sectionRVAs; + private class SerializedSectionData + { + /// + /// Name of the section + /// + public string Name; - /// - /// Pointers to the location of the raw data. Needed to allow phyical file alignment - /// beyond 4KB. PEBuilder doesn't support this today so that we - /// must store the RVA's and post-process the produced PE by patching the section - /// headers in the PE header. - /// - private int[] _sectionPointerToRawData; + /// + /// Logical section start RVAs. When emitting R2R PE executables for Linux, we must + /// align RVA's so that their 'RVABitsToMatchFilePos' lowest-order bits match the + /// file position (otherwise memory mapping of the file fails and CoreCLR silently + /// switches over to runtime JIT). PEBuilder doesn't support this today so that we + /// must store the RVA's and post-process the produced PE by patching the section + /// headers in the PE header. + /// + public int RVA; + + /// + /// Pointers to the location of the raw data. Needed to allow phyical file alignment + /// beyond 4KB. PEBuilder doesn't support this today so that we + /// must store the RVA's and post-process the produced PE by patching the section + /// headers in the PE header. + /// + public int PointerToRawData; + + /// + /// Maximum of virtual and physical size for each section. + /// + public int RawSize; + + /// + /// Whether or not the section has been serialized - if the RVA, pointer to raw data, + /// and size have been set. + /// + public bool IsSerialized; + } /// - /// Maximum of virtual and physical size for each section. + /// List of possible sections to emit into the output R2R executable in the order in which + /// they are expected to be serialized. Data (aside from name) is set during serialization. /// - private int[] _sectionRawSizes; + private readonly SerializedSectionData[] _sectionData; /// /// R2R PE section builder & relocator. @@ -206,18 +221,13 @@ public R2RPEBuilder( PEHeaderConstants.SectionAlignment); } - ImmutableArray
.Builder sectionListBuilder = ImmutableArray.CreateBuilder
(); + List sectionData = new List(); foreach (SectionInfo sectionInfo in _sectionBuilder.GetSections()) { - ILCompiler.PEWriter.Section builderSection = _sectionBuilder.FindSection(sectionInfo.SectionName); - Debug.Assert(builderSection != null); - sectionListBuilder.Add(new Section(builderSection.Name, builderSection.Characteristics)); + sectionData.Add(new SerializedSectionData() { Name = sectionInfo.SectionName }); } - _sections = sectionListBuilder.ToImmutableArray(); - _sectionRVAs = new int[_sections.Length]; - _sectionPointerToRawData = new int[_sections.Length]; - _sectionRawSizes = new int[_sections.Length]; + _sectionData = sectionData.ToArray(); } public void SetCorHeader(ISymbolNode symbol, int headerSize) @@ -400,13 +410,17 @@ private void UpdateSectionRVAs(Stream outputStream) 16 * sizeof(long); // directory entries int sectionHeaderOffset = DosHeaderSize + PESignatureSize + COFFHeaderSize + peHeaderSize; - int sectionCount = _sectionRVAs.Length; + int sectionCount = _sectionData.Length; for (int sectionIndex = 0; sectionIndex < sectionCount; sectionIndex++) { + SerializedSectionData section = _sectionData[sectionIndex]; + if (!section.IsSerialized) + continue; + if (_customPESectionAlignment != 0) { // When _customPESectionAlignment is set, the physical and virtual sizes are the same - byte[] sizeBytes = BitConverter.GetBytes(_sectionRawSizes[sectionIndex]); + byte[] sizeBytes = BitConverter.GetBytes(section.RawSize); Debug.Assert(sizeBytes.Length == sizeof(int)); // Update VirtualSize @@ -424,7 +438,7 @@ private void UpdateSectionRVAs(Stream outputStream) // Update RVAs { outputStream.Seek(sectionHeaderOffset + SectionHeaderSize * sectionIndex + SectionHeaderRVAOffset, SeekOrigin.Begin); - byte[] rvaBytes = BitConverter.GetBytes(_sectionRVAs[sectionIndex]); + byte[] rvaBytes = BitConverter.GetBytes(section.RVA); Debug.Assert(rvaBytes.Length == sizeof(int)); outputStream.Write(rvaBytes, 0, rvaBytes.Length); } @@ -432,15 +446,25 @@ private void UpdateSectionRVAs(Stream outputStream) // Update pointer to raw data { outputStream.Seek(sectionHeaderOffset + SectionHeaderSize * sectionIndex + SectionHeaderPointerToRawDataOffset, SeekOrigin.Begin); - byte[] rawDataBytesBytes = BitConverter.GetBytes(_sectionPointerToRawData[sectionIndex]); + byte[] rawDataBytesBytes = BitConverter.GetBytes(section.PointerToRawData); Debug.Assert(rawDataBytesBytes.Length == sizeof(int)); outputStream.Write(rawDataBytesBytes, 0, rawDataBytesBytes.Length); } } // Patch SizeOfImage to point past the end of the last section + SerializedSectionData lastSection = null; + for (int i = sectionCount - 1; i >= 0; i--) + { + if (_sectionData[i].IsSerialized) + { + lastSection = _sectionData[i]; + break; + } + } + Debug.Assert(lastSection != null); outputStream.Seek(DosHeaderSize + PESignatureSize + COFFHeaderSize + OffsetOfSizeOfImage, SeekOrigin.Begin); - int sizeOfImage = AlignmentHelper.AlignUp(_sectionRVAs[sectionCount - 1] + _sectionRawSizes[sectionCount - 1], Header.SectionAlignment); + int sizeOfImage = AlignmentHelper.AlignUp(lastSection.RVA + lastSection.RawSize, Header.SectionAlignment); byte[] sizeOfImageBytes = BitConverter.GetBytes(sizeOfImage); Debug.Assert(sizeOfImageBytes.Length == sizeof(int)); outputStream.Write(sizeOfImageBytes, 0, sizeOfImageBytes.Length); @@ -557,14 +581,21 @@ private int RelocateRVA(int rva) ///
protected override ImmutableArray
CreateSections() { - return _sections; + ImmutableArray
.Builder sectionListBuilder = ImmutableArray.CreateBuilder
(); + foreach (SectionInfo sectionInfo in _sectionBuilder.GetSections()) + { + // Only include sections that have content. + if (!_sectionBuilder.HasContent(sectionInfo.SectionName)) + continue; + + sectionListBuilder.Add(new Section(sectionInfo.SectionName, sectionInfo.Characteristics)); + } + + return sectionListBuilder.ToImmutable(); } /// - /// Output the section with a given name. For sections existent in the source MSIL PE file - /// (.text, optionally .rsrc and .reloc), we first copy the content of the input MSIL PE file - /// and then call the section serialization callback to emit the extra content after the input - /// section content. + /// Output the section with a given name. /// /// Section name /// RVA and file location where the section will be put @@ -574,18 +605,33 @@ protected override BlobBuilder SerializeSection(string name, SectionLocation loc BlobBuilder sectionDataBuilder = null; int sectionStartRva = location.RelativeVirtualAddress; - int outputSectionIndex = _sections.Length - 1; - while (outputSectionIndex >= 0 && _sections[outputSectionIndex].Name != name) + int outputSectionIndex = _sectionData.Length - 1; + while (outputSectionIndex >= 0 && _sectionData[outputSectionIndex].Name != name) { outputSectionIndex--; } + if (outputSectionIndex < 0) + throw new ArgumentException($"Unknown section name: '{name}'", nameof(name)); + + Debug.Assert(_sectionBuilder.HasContent(name)); + SerializedSectionData outputSection = _sectionData[outputSectionIndex]; + SerializedSectionData previousSection = null; + for (int i = outputSectionIndex - 1; i >= 0; i--) + { + if (_sectionData[i].IsSerialized) + { + previousSection = _sectionData[i]; + break; + } + } + int injectedPadding = 0; if (_customPESectionAlignment != 0) { - if (outputSectionIndex > 0) + if (previousSection is not null) { - sectionStartRva = Math.Max(sectionStartRva, _sectionRVAs[outputSectionIndex - 1] + _sectionRawSizes[outputSectionIndex - 1]); + sectionStartRva = Math.Max(sectionStartRva, previousSection.RVA + previousSection.RawSize); } int newSectionStartRva = AlignmentHelper.AlignUp(sectionStartRva, _customPESectionAlignment); @@ -603,13 +649,13 @@ protected override BlobBuilder SerializeSection(string name, SectionLocation loc if (!_target.IsWindows) { const int RVAAlign = 1 << RVABitsToMatchFilePos; - if (outputSectionIndex > 0) + if (previousSection is not null) { - sectionStartRva = Math.Max(sectionStartRva, _sectionRVAs[outputSectionIndex - 1] + _sectionRawSizes[outputSectionIndex - 1]); + sectionStartRva = Math.Max(sectionStartRva, previousSection.RVA + previousSection.RawSize); // when assembly is stored in a singlefile bundle, an additional skew is introduced - // as the streams inside the bundle are not necessarily page aligned as we do not - // know the actual page size on the target system. + // as the streams inside the bundle are not necessarily page aligned as we do not + // know the actual page size on the target system. // We may need one page gap of unused VA space before the next section starts. // We will assume the page size is <= RVAAlign sectionStartRva += RVAAlign; @@ -622,36 +668,19 @@ protected override BlobBuilder SerializeSection(string name, SectionLocation loc location = new SectionLocation(sectionStartRva, location.PointerToRawData); } - if (outputSectionIndex >= 0) - { - _sectionRVAs[outputSectionIndex] = sectionStartRva; - _sectionPointerToRawData[outputSectionIndex] = location.PointerToRawData; - } + outputSection.RVA = sectionStartRva; + outputSection.PointerToRawData = location.PointerToRawData; BlobBuilder extraData = _sectionBuilder.SerializeSection(name, location); - if (extraData != null) - { - if (sectionDataBuilder == null) - { - // See above - there's a bug due to which LinkSuffix to an empty BlobBuilder screws up the blob content. - sectionDataBuilder = extraData; - } - else - { - sectionDataBuilder.LinkSuffix(extraData); - } - } - - // Make sure the section has at least 1 byte, otherwise the PE emitter goes mad, - // messes up the section map and corrups the output executable. + Debug.Assert(extraData != null); if (sectionDataBuilder == null) { - sectionDataBuilder = new BlobBuilder(); + // See above - there's a bug due to which LinkSuffix to an empty BlobBuilder screws up the blob content. + sectionDataBuilder = extraData; } - - if (sectionDataBuilder.Count == 0) + else { - sectionDataBuilder.WriteByte(0); + sectionDataBuilder.LinkSuffix(extraData); } int sectionRawSize = sectionDataBuilder.Count - injectedPadding; @@ -664,15 +693,13 @@ protected override BlobBuilder SerializeSection(string name, SectionLocation loc sectionRawSize = count; } - if (outputSectionIndex >= 0) - { - _sectionRawSizes[outputSectionIndex] = sectionRawSize; - } + outputSection.RawSize = sectionRawSize; + outputSection.IsSerialized = true; return sectionDataBuilder; } } - + /// /// Simple helper for filling in PE header information. /// diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/SectionBuilder.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/SectionBuilder.cs index e10348e562e1e0..f3ebd11aae868c 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/SectionBuilder.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/SectionBuilder.cs @@ -944,5 +944,22 @@ public void RelocateOutputFile( // Flush remaining PE file blocks after the last relocation relocationHelper.CopyRestOfFile(); } + + internal bool HasContent(string sectionName) + { + if (sectionName == R2RPEBuilder.ExportDataSectionName) + return _exportSymbols.Count > 0 && _dllNameForExportDirectoryTable != null; + + if (sectionName == R2RPEBuilder.RelocSectionName) + { + return _sections.Any( + s => s.PlacedObjectDataToRelocate.Any( + d => d.Relocs.Any( + r => Relocation.GetFileRelocationType(r.RelocType) != RelocType.IMAGE_REL_BASED_ABSOLUTE))); + } + + Section section = FindSection(sectionName); + return section != null && section.Content.Count > 0; + } } } diff --git a/src/coreclr/tools/superpmi/superpmi-shared/simpletimer.cpp b/src/coreclr/tools/superpmi/superpmi-shared/simpletimer.cpp index 3a21e77029e126..87fe784e1c784c 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/simpletimer.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/simpletimer.cpp @@ -4,18 +4,14 @@ #include "standardpch.h" #include "logging.h" #include "simpletimer.h" +#include "minipal/time.h" SimpleTimer::SimpleTimer() { - start.QuadPart = 0; - stop.QuadPart = 0; - - BOOL retVal = ::QueryPerformanceFrequency(&proc_freq); - if (retVal == FALSE) - { - LogDebug("SimpleTimer::SimpleTimer unable to QPF. error was 0x%08x", ::GetLastError()); - DEBUG_BREAK; - } + start = 0; + stop = 0; + + proc_freq = minipal_hires_tick_frequency(); } SimpleTimer::~SimpleTimer() @@ -24,22 +20,12 @@ SimpleTimer::~SimpleTimer() void SimpleTimer::Start() { - BOOL retVal = ::QueryPerformanceCounter(&start); - if (retVal == FALSE) - { - LogDebug("SimpleTimer::Start unable to QPC. error was 0x%08x", ::GetLastError()); - DEBUG_BREAK; - } + start = minipal_hires_ticks(); } void SimpleTimer::Stop() { - BOOL retVal = ::QueryPerformanceCounter(&stop); - if (retVal == FALSE) - { - LogDebug("SimpleTimer::Stop unable to QPC. error was 0x%08x", ::GetLastError()); - DEBUG_BREAK; - } + stop = minipal_hires_ticks(); } double SimpleTimer::GetMilliseconds() @@ -49,5 +35,5 @@ double SimpleTimer::GetMilliseconds() double SimpleTimer::GetSeconds() { - return ((stop.QuadPart - start.QuadPart) / (double)proc_freq.QuadPart); + return ((stop - start) / (double)proc_freq); } diff --git a/src/coreclr/tools/superpmi/superpmi-shared/simpletimer.h b/src/coreclr/tools/superpmi/superpmi-shared/simpletimer.h index 69fb8760584647..48aae5e12b0fff 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/simpletimer.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/simpletimer.h @@ -4,6 +4,8 @@ #ifndef _SimpleTimer #define _SimpleTimer +#include + class SimpleTimer { public: @@ -16,8 +18,8 @@ class SimpleTimer double GetSeconds(); private: - LARGE_INTEGER proc_freq; - LARGE_INTEGER start; - LARGE_INTEGER stop; + int64_t proc_freq; + int64_t start; + int64_t stop; }; #endif diff --git a/src/coreclr/utilcode/cycletimer.cpp b/src/coreclr/utilcode/cycletimer.cpp index 946c72b278e287..10118bfa83b694 100644 --- a/src/coreclr/utilcode/cycletimer.cpp +++ b/src/coreclr/utilcode/cycletimer.cpp @@ -8,6 +8,7 @@ #include "winwrap.h" #include "assert.h" #include "utilcode.h" +#include "minipal/time.h" bool CycleTimer::GetThreadCyclesS(uint64_t* cycles) { @@ -26,25 +27,21 @@ double CycleTimer::CyclesPerSecond() // Windows *does* allow you to translate QueryPerformanceCounter counts into time, // however. So we'll assume that the clock speed stayed constant, and measure both the // QPC counts and cycles of a short loop, to get a conversion factor. - LARGE_INTEGER lpFrequency; - if (!QueryPerformanceFrequency(&lpFrequency)) return 0.0; - // Otherwise... - LARGE_INTEGER qpcStart; + int64_t lpFrequency = minipal_hires_tick_frequency(); + int64_t qpcStart = minipal_hires_ticks(); uint64_t cycleStart; - if (!QueryPerformanceCounter(&qpcStart)) return 0.0; if (!GetThreadCyclesS(&cycleStart)) return 0.0; volatile int sum = 0; for (int k = 0; k < SampleLoopSize; k++) { sum += k; } - LARGE_INTEGER qpcEnd; - if (!QueryPerformanceCounter(&qpcEnd)) return 0.0; + int64_t qpcEnd = minipal_hires_ticks(); uint64_t cycleEnd; if (!GetThreadCyclesS(&cycleEnd)) return 0.0; - double qpcTicks = ((double)qpcEnd.QuadPart) - ((double)qpcStart.QuadPart); - double secs = (qpcTicks / ((double)lpFrequency.QuadPart)); + double qpcTicks = ((double)qpcEnd) - ((double)qpcStart); + double secs = (qpcTicks / ((double)lpFrequency)); double cycles = ((double)cycleEnd) - ((double)cycleStart); return cycles / secs; } diff --git a/src/coreclr/utilcode/stresslog.cpp b/src/coreclr/utilcode/stresslog.cpp index 8908f30a9e9110..e837e86712d789 100644 --- a/src/coreclr/utilcode/stresslog.cpp +++ b/src/coreclr/utilcode/stresslog.cpp @@ -15,6 +15,7 @@ #include "ex.h" #define DONOT_DEFINE_ETW_CALLBACK #include "eventtracebase.h" +#include "minipal/time.h" #if !defined(STRESS_LOG_READONLY) #ifdef HOST_WINDOWS @@ -58,15 +59,11 @@ uint64_t getTimeStamp() { } #else // HOST_X86 -uint64_t getTimeStamp() { +uint64_t getTimeStamp() +{ STATIC_CONTRACT_LEAF; - LARGE_INTEGER ret; - ZeroMemory(&ret, sizeof(LARGE_INTEGER)); - - QueryPerformanceCounter(&ret); - - return ret.QuadPart; + return (uint64_t)minipal_hires_ticks(); } #endif // HOST_X86 @@ -127,10 +124,7 @@ uint64_t getTickFrequency() */ uint64_t getTickFrequency() { - LARGE_INTEGER ret; - ZeroMemory(&ret, sizeof(LARGE_INTEGER)); - QueryPerformanceFrequency(&ret); - return ret.QuadPart; + return (uint64_t)minipal_hires_tick_frequency(); } #endif // HOST_X86 diff --git a/src/coreclr/vm/callstubgenerator.cpp b/src/coreclr/vm/callstubgenerator.cpp index 2394c5bacea3f1..30a70af7ace201 100644 --- a/src/coreclr/vm/callstubgenerator.cpp +++ b/src/coreclr/vm/callstubgenerator.cpp @@ -47,7 +47,7 @@ PCODE GPRegsRoutines[] = (PCODE)Load_RCX_RDX, // 01 (PCODE)Load_RCX_RDX_R8, // 02 (PCODE)Load_RCX_RDX_R8_R9, // 03 - (PCODE)0, // 10 + (PCODE)0, // 10 (PCODE)Load_RDX, // 11 (PCODE)Load_RDX_R8, // 12 (PCODE)Load_RDX_R8_R9, // 13 @@ -75,7 +75,7 @@ PCODE FPRegsRoutines[] = (PCODE)Load_XMM0_XMM1, // 01 (PCODE)Load_XMM0_XMM1_XMM2, // 02 (PCODE)Load_XMM0_XMM1_XMM2_XMM3, // 03 - (PCODE)0, // 10 + (PCODE)0, // 10 (PCODE)Load_XMM1, // 11 (PCODE)Load_XMM1_XMM2, // 12 (PCODE)Load_XMM1_XMM2_XMM3, // 13 @@ -121,7 +121,7 @@ PCODE GPRegsRoutines[] = (PCODE)Load_RDI_RSI_RDX_RCX, // 03 (PCODE)Load_RDI_RSI_RDX_RCX_R8, // 04 (PCODE)Load_RDI_RSI_RDX_RCX_R8_R9, // 05 - (PCODE)0, // 10 + (PCODE)0, // 10 (PCODE)Load_RSI, // 11 (PCODE)Load_RSI_RDX, // 12 (PCODE)Load_RSI_RDX_RCX, // 13 @@ -200,7 +200,7 @@ PCODE FPRegsRoutines[] = (PCODE)Load_XMM0_XMM1_XMM2_XMM3_XMM4_XMM5, // 05 (PCODE)Load_XMM0_XMM1_XMM2_XMM3_XMM4_XMM5_XMM6, // 06 (PCODE)Load_XMM0_XMM1_XMM2_XMM3_XMM4_XMM5_XMM6_XMM7,// 07 - (PCODE)0, // 10 + (PCODE)0, // 10 (PCODE)Load_XMM1, // 11 (PCODE)Load_XMM1_XMM2, // 12 (PCODE)Load_XMM1_XMM2_XMM3, // 13 @@ -321,7 +321,7 @@ PCODE GPRegsRoutines[] = (PCODE)Load_X0_X1_X2_X3_X4_X5, // 05 (PCODE)Load_X0_X1_X2_X3_X4_X5_X6, // 06 (PCODE)Load_X0_X1_X2_X3_X4_X5_X6_X7, // 07 - (PCODE)0, // 10 + (PCODE)0, // 10 (PCODE)Load_X1, // 11 (PCODE)Load_X1_X2, // 12 (PCODE)Load_X1_X2_X3, // 13 @@ -338,7 +338,7 @@ PCODE GPRegsRoutines[] = (PCODE)Load_X2_X3_X4_X5_X6, // 26 (PCODE)Load_X2_X3_X4_X5_X6_X7, // 27 (PCODE)0, // 30 - (PCODE)0, // 31 + (PCODE)0, // 31 (PCODE)0, // 32 (PCODE)Load_X3, // 33 (PCODE)Load_X3_X4, // 34 @@ -438,7 +438,7 @@ PCODE FPRegsRoutines[] = (PCODE)Load_D0_D1_D2_D3_D4_D5, // 05 (PCODE)Load_D0_D1_D2_D3_D4_D5_D6, // 06 (PCODE)Load_D0_D1_D2_D3_D4_D5_D6_D7, // 07 - (PCODE)0, // 10 + (PCODE)0, // 10 (PCODE)Load_D1, // 11 (PCODE)Load_D1_D2, // 12 (PCODE)Load_D1_D2_D3, // 13 @@ -455,7 +455,7 @@ PCODE FPRegsRoutines[] = (PCODE)Load_D2_D3_D4_D5_D6, // 26 (PCODE)Load_D2_D3_D4_D5_D6_D7, // 27 (PCODE)0, // 30 - (PCODE)0, // 31 + (PCODE)0, // 31 (PCODE)0, // 32 (PCODE)Load_D3, // 33 (PCODE)Load_D3_D4, // 34 @@ -590,7 +590,7 @@ CallStubHeader *CallStubGenerator::GenerateCallStub(MethodDesc *pMD, AllocMemTra ArgLocDesc argLocDesc; argIt.GetArgLoc(ofs, &argLocDesc); -#ifdef UNIX_AMD64_ABI +#ifdef UNIX_AMD64_ABI if (argIt.GetArgLocDescForStructInRegs() != NULL) { TypeHandle argTypeHandle; @@ -604,33 +604,43 @@ CallStubHeader *CallStubGenerator::GenerateCallStub(MethodDesc *pMD, AllocMemTra { ArgLocDesc argLocDescEightByte = {}; SystemVClassificationType eightByteType = pEEClass->GetEightByteClassification(i); - if (eightByteType == SystemVClassificationTypeInteger) - { - if (argLocDesc.m_cGenReg != 0) - { - argLocDescEightByte.m_cGenReg = 1; - argLocDescEightByte.m_idxGenReg = argLocDesc.m_idxGenReg++; - } - else - { - argLocDescEightByte.m_byteStackSize = 8; - argLocDescEightByte.m_byteStackIndex = argLocDesc.m_byteStackIndex; - argLocDesc.m_byteStackIndex += 8; - } - } - else if (eightByteType == SystemVClassificationTypeSSE) + switch (eightByteType) { - if (argLocDesc.m_cFloatReg != 0) + case SystemVClassificationTypeInteger: + case SystemVClassificationTypeIntegerReference: + case SystemVClassificationTypeIntegerByRef: { - argLocDescEightByte.m_cFloatReg = 1; - argLocDescEightByte.m_idxFloatReg = argLocDesc.m_idxFloatReg++; + if (argLocDesc.m_cGenReg != 0) + { + argLocDescEightByte.m_cGenReg = 1; + argLocDescEightByte.m_idxGenReg = argLocDesc.m_idxGenReg++; + } + else + { + argLocDescEightByte.m_byteStackSize = 8; + argLocDescEightByte.m_byteStackIndex = argLocDesc.m_byteStackIndex; + argLocDesc.m_byteStackIndex += 8; + } + break; } - else + case SystemVClassificationTypeSSE: { - argLocDescEightByte.m_byteStackSize = 8; - argLocDescEightByte.m_byteStackIndex = argLocDesc.m_byteStackIndex; - argLocDesc.m_byteStackIndex += 8; + if (argLocDesc.m_cFloatReg != 0) + { + argLocDescEightByte.m_cFloatReg = 1; + argLocDescEightByte.m_idxFloatReg = argLocDesc.m_idxFloatReg++; + } + else + { + argLocDescEightByte.m_byteStackSize = 8; + argLocDescEightByte.m_byteStackIndex = argLocDesc.m_byteStackIndex; + argLocDesc.m_byteStackIndex += 8; + } + break; } + default: + assert(!"Unhandled systemv classification for argument in GenerateCallStub"); + break; } ProcessArgument(argIt, argLocDescEightByte, pRoutines); } @@ -878,7 +888,7 @@ void CallStubGenerator::ProcessArgument(ArgIterator& argIt, ArgLocDesc& argLocDe } if (argLocDesc.m_cGenReg != 0) - { + { if (m_r1 == NoRange) // No active range yet { // Start a new range @@ -907,7 +917,7 @@ void CallStubGenerator::ProcessArgument(ArgIterator& argIt, ArgLocDesc& argLocDe // Start a new range m_x1 = argLocDesc.m_idxFloatReg; m_x2 = m_x1 + argLocDesc.m_cFloatReg - 1; - } + } else if (argLocDesc.m_idxFloatReg == m_x2 + 1) { // Extend an existing range @@ -929,7 +939,7 @@ void CallStubGenerator::ProcessArgument(ArgIterator& argIt, ArgLocDesc& argLocDe // Start a new range m_s1 = argLocDesc.m_byteStackIndex; m_s2 = m_s1 + argLocDesc.m_byteStackSize - 1; - } + } else if ((argLocDesc.m_byteStackIndex == m_s2 + 1) && (argLocDesc.m_byteStackSize >= 8)) { // Extend an existing range, but only if the argument is at least pointer size large. @@ -987,4 +997,4 @@ void CallStubGenerator::ProcessArgument(ArgIterator& argIt, ArgLocDesc& argLocDe #endif // UNIX_AMD64_ABI } -#endif // FEATURE_INTERPRETER \ No newline at end of file +#endif // FEATURE_INTERPRETER diff --git a/src/coreclr/vm/ceemain.cpp b/src/coreclr/vm/ceemain.cpp index 53f192d8bc976f..fb0ff126121562 100644 --- a/src/coreclr/vm/ceemain.cpp +++ b/src/coreclr/vm/ceemain.cpp @@ -163,6 +163,7 @@ #include "pgo.h" #include "pendingload.h" #include "cdacplatformmetadata.hpp" +#include "minipal/time.h" #ifndef TARGET_UNIX #include "dwreport.h" @@ -484,10 +485,10 @@ void InitGSCookie() void * pf = &__security_check_cookie; pf = NULL; - GSCookie val = (GSCookie)(__security_cookie ^ GetTickCount()); + GSCookie val = (GSCookie)(__security_cookie ^ minipal_lowres_ticks()); #else // !TARGET_UNIX // REVIEW: Need something better for PAL... - GSCookie val = (GSCookie)GetTickCount(); + GSCookie val = (GSCookie)minipal_lowres_ticks(); #endif // !TARGET_UNIX #ifdef _DEBUG @@ -839,36 +840,19 @@ void EEStartupHelper() #ifdef PROFILING_SUPPORTED // Initialize the profiling services. + // This must happen before Thread::HasStarted() that fires profiler notifications is called on the finalizer thread. hr = ProfilingAPIUtility::InitializeProfiling(); _ASSERTE(SUCCEEDED(hr)); IfFailGo(hr); #endif // PROFILING_SUPPORTED - InitializeExceptionHandling(); - - // - // Install our global exception filter - // - if (!InstallUnhandledExceptionFilter()) - { - IfFailGo(E_FAIL); - } - - // throws on error - SetupThread(); - -#ifdef DEBUGGING_SUPPORTED - // Notify debugger once the first thread is created to finish initialization. - if (g_pDebugInterface != NULL) - { - g_pDebugInterface->StartupPhase2(GetThread()); - } -#endif - - // This isn't done as part of InitializeGarbageCollector() above because - // debugger must be initialized before creating EE thread objects +#ifdef TARGET_WINDOWS + // Create the finalizer thread on windows earlier, as we will need to wait for + // the completion of its initialization part that initializes COM as that has to be done + // before the first Thread is attached. Thus we want to give the thread a bit more time. FinalizerThread::FinalizerThreadCreate(); +#endif InitPreStubManager(); @@ -882,8 +866,6 @@ void EEStartupHelper() // of the JIT helpers. InitJITHelpers1(); - SyncBlockCache::Attach(); - // Set up the sync block SyncBlockCache::Start(); @@ -898,6 +880,48 @@ void EEStartupHelper() IfFailGo(hr); + InitializeExceptionHandling(); + + // + // Install our global exception filter + // + if (!InstallUnhandledExceptionFilter()) + { + IfFailGo(E_FAIL); + } + +#ifdef TARGET_WINDOWS + // g_pGCHeap->Initialize() above could take nontrivial time, so by now the finalizer thread + // should have initialized FLS slot for thread cleanup notifications. + // And ensured that COM is initialized (must happen before allocating FLS slot). + // Make sure that this was done before we start creating Thread objects + // Ex: The call to SetupThread below will create and attach a Thread object. + // Event pipe might also do that. + FinalizerThread::WaitForFinalizerThreadStart(); +#endif + + // throws on error + _ASSERTE(GetThreadNULLOk() == NULL); + SetupThread(); + +#ifdef DEBUGGING_SUPPORTED + // Notify debugger once the first thread is created to finish initialization. + if (g_pDebugInterface != NULL) + { + g_pDebugInterface->StartupPhase2(GetThread()); + } +#endif + +#ifndef TARGET_WINDOWS + // This isn't done as part of InitializeGarbageCollector() above because + // debugger must be initialized before creating EE thread objects + FinalizerThread::FinalizerThreadCreate(); +#else + // On windows the finalizer thread is already partially created and is waiting + // right before doing HasStarted(). We will release it now. + FinalizerThread::EnableFinalization(); +#endif + #ifdef FEATURE_PERFTRACING // Finish setting up rest of EventPipe - specifically enable SampleProfiler if it was requested at startup. // SampleProfiler needs to cooperate with the GC which hasn't fully finished setting up in the first part of the @@ -957,12 +981,6 @@ void EEStartupHelper() g_MiniMetaDataBuffMaxSize, MEM_COMMIT, PAGE_READWRITE); #endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS -#ifdef TARGET_WINDOWS - // By now finalizer thread should have initialized FLS slot for thread cleanup notifications. - // And ensured that COM is initialized (must happen before allocating FLS slot). - // Make sure that this was done. - FinalizerThread::WaitForFinalizerThreadStart(); -#endif g_fEEStarted = TRUE; g_EEStartupStatus = S_OK; hr = S_OK; @@ -1764,6 +1782,8 @@ void InitFlsSlot() // thread - thread to attach static void OsAttachThread(void* thread) { + _ASSERTE(g_flsIndex != FLS_OUT_OF_INDEXES); + if (t_flsState == FLS_STATE_INVOKED) { _ASSERTE_ALL_BUILDS(!"Attempt to execute managed code after the .NET runtime thread state has been destroyed."); diff --git a/src/coreclr/vm/class.cpp b/src/coreclr/vm/class.cpp index 68349c9fe168c5..02ac7a99ecc63c 100644 --- a/src/coreclr/vm/class.cpp +++ b/src/coreclr/vm/class.cpp @@ -246,11 +246,6 @@ VOID EEClass::FixupFieldDescForEnC(MethodTable * pMT, EnCFieldDesc *pFD, mdField bmtEnumFields.dwNumInstanceFields = 1; } - // We shouldn't have to fill this in b/c we're not allowed to EnC value classes, or - // anything else with layout info associated with it. - // Provide 2, 1 placeholder and 1 for the actual field - see BuildMethodTableThrowing(). - LayoutRawFieldInfo layoutRawFieldInfos[2]; - // If not NULL, it means there are some by-value fields, and this contains an entry for each instance or static field, // which is NULL if not a by value field, and points to the EEClass of the field if a by value field. Instance fields // come first, statics come second. @@ -288,7 +283,6 @@ VOID EEClass::FixupFieldDescForEnC(MethodTable * pMT, EnCFieldDesc *pFD, mdField GCX_PREEMP(); unsigned totalDeclaredFieldSize = 0; builder.InitializeFieldDescs(pFD, - layoutRawFieldInfos, &bmtInternal, &genericsInfo, &bmtMetaData, diff --git a/src/coreclr/vm/class.h b/src/coreclr/vm/class.h index d95129ab096a00..3bf8417ef0cb0d 100644 --- a/src/coreclr/vm/class.h +++ b/src/coreclr/vm/class.h @@ -72,7 +72,6 @@ class EnCFieldDesc; class FieldDesc; class NativeFieldDescriptor; class EEClassNativeLayoutInfo; -struct LayoutRawFieldInfo; class MetaSig; class MethodDesc; class MethodDescChunk; @@ -126,7 +125,7 @@ class ExplicitFieldTrust }; //---------------------------------------------------------------------------------------------- -// This class is a helper for HandleExplicitLayout. To make it harder to introduce security holes +// This class is a helper for ValidateExplicitLayout. To make it harder to introduce security holes // into this function, we will manage all updates to the class's trust level through the ExplicitClassTrust // class. This abstraction enforces the rule that the overall class is only as trustworthy as // the least trustworthy field. @@ -175,7 +174,7 @@ class ExplicitClassTrust : private ExplicitFieldTrust }; //---------------------------------------------------------------------------------------------- -// This class is a helper for HandleExplicitLayout. To make it harder to introduce security holes +// This class is a helper for ValidateExplicitLayout. To make it harder to introduce security holes // into this function, this class will collect trust information about individual fields to be later // aggregated into the overall class level. // @@ -334,30 +333,13 @@ class SparseVTableMap //======================================================================= class EEClassLayoutInfo { - static VOID CollectLayoutFieldMetadataThrowing( - mdTypeDef cl, // cl of the NStruct being loaded - BYTE packingSize, // packing size (from @dll.struct) - BYTE nlType, // nltype (from @dll.struct) - BOOL fExplicitOffsets, // explicit offsets? - MethodTable *pParentMT, // the loaded superclass - ULONG cTotalFields, // total number of fields (instance and static) - HENUMInternal *phEnumField, // enumerator for fields - Module* pModule, // Module that defines the scope, loader and heap (for allocate FieldMarshalers) - const SigTypeContext *pTypeContext, // Type parameters for NStruct being loaded - EEClassLayoutInfo *pEEClassLayoutInfoOut, // caller-allocated structure to fill in. - LayoutRawFieldInfo *pInfoArrayOut, // caller-allocated array to fill in. Needs room for cTotalFields+1 elements - LoaderAllocator * pAllocator, - AllocMemTracker *pamTracker - ); - - friend class ClassLoader; - friend class EEClass; - friend class MethodTableBuilder; - UINT32 m_cbManagedSize; - public: - BYTE m_ManagedLargestAlignmentRequirementOfAllMembers; - + enum class LayoutType : BYTE + { + Auto = 0, // Make sure Auto is the default value as the default-constructed value represents the "auto layout" case + Sequential, + Explicit + }; private: enum { // TRUE if the GC layout of the class is bit-for-bit identical @@ -365,8 +347,8 @@ class EEClassLayoutInfo // (i.e. no internal reference fields, no ansi-unicode char conversions required, etc.) // Used to optimize marshaling. e_BLITTABLE = 0x01, - // Is this type also sequential in managed memory? - e_MANAGED_SEQUENTIAL = 0x02, + // unused = 0x02, + // When a sequential/explicit type has no fields, it is conceptually // zero-sized, but actually is 1 byte in length. This holds onto this // fact and allows us to revert the 1 byte of padding when another @@ -380,17 +362,16 @@ class EEClassLayoutInfo e_IS_OR_HAS_INT128_FIELD = 0x20, }; - BYTE m_bFlags; + LayoutType m_LayoutType; + + BYTE m_ManagedLargestAlignmentRequirementOfAllMembers; + + BYTE m_bFlags; // Packing size in bytes (1, 2, 4, 8 etc.) - BYTE m_cbPackingSize; + BYTE m_cbPackingSize; public: - UINT32 GetManagedSize() const - { - LIMITED_METHOD_CONTRACT; - return m_cbManagedSize; - } BOOL IsBlittable() const { @@ -398,10 +379,10 @@ class EEClassLayoutInfo return (m_bFlags & e_BLITTABLE) == e_BLITTABLE; } - BOOL IsManagedSequential() const + LayoutType GetLayoutType() const { LIMITED_METHOD_CONTRACT; - return (m_bFlags & e_MANAGED_SEQUENTIAL) == e_MANAGED_SEQUENTIAL; + return m_LayoutType; } // If true, this says that the type was originally zero-sized @@ -433,13 +414,18 @@ class EEClassLayoutInfo return (m_bFlags & e_IS_OR_HAS_INT128_FIELD) == e_IS_OR_HAS_INT128_FIELD; } + BYTE GetAlignmentRequirement() const + { + LIMITED_METHOD_CONTRACT; + return m_ManagedLargestAlignmentRequirementOfAllMembers; + } + BYTE GetPackingSize() const { LIMITED_METHOD_CONTRACT; return m_cbPackingSize; } - private: void SetIsBlittable(BOOL isBlittable) { LIMITED_METHOD_CONTRACT; @@ -447,40 +433,93 @@ class EEClassLayoutInfo : (m_bFlags & ~e_BLITTABLE); } - void SetIsManagedSequential(BOOL isManagedSequential) + void SetHasAutoLayoutField(BOOL hasAutoLayoutField) { LIMITED_METHOD_CONTRACT; - m_bFlags = isManagedSequential ? (m_bFlags | e_MANAGED_SEQUENTIAL) - : (m_bFlags & ~e_MANAGED_SEQUENTIAL); + m_bFlags = hasAutoLayoutField ? (m_bFlags | e_HAS_AUTO_LAYOUT_FIELD_IN_LAYOUT) + : (m_bFlags & ~e_HAS_AUTO_LAYOUT_FIELD_IN_LAYOUT); } - void SetIsZeroSized(BOOL isZeroSized) + void SetIsInt128OrHasInt128Fields(BOOL hasInt128Field) { LIMITED_METHOD_CONTRACT; - m_bFlags = isZeroSized ? (m_bFlags | e_ZERO_SIZED) - : (m_bFlags & ~e_ZERO_SIZED); + m_bFlags = hasInt128Field ? (m_bFlags | e_IS_OR_HAS_INT128_FIELD) + : (m_bFlags & ~e_IS_OR_HAS_INT128_FIELD); } void SetHasExplicitSize(BOOL hasExplicitSize) { LIMITED_METHOD_CONTRACT; m_bFlags = hasExplicitSize ? (m_bFlags | e_HAS_EXPLICIT_SIZE) - : (m_bFlags & ~e_HAS_EXPLICIT_SIZE); + : (m_bFlags & ~e_HAS_EXPLICIT_SIZE); } - void SetHasAutoLayoutField(BOOL hasAutoLayoutField) + void SetAlignmentRequirement(BYTE alignment) { LIMITED_METHOD_CONTRACT; - m_bFlags = hasAutoLayoutField ? (m_bFlags | e_HAS_AUTO_LAYOUT_FIELD_IN_LAYOUT) - : (m_bFlags & ~e_HAS_AUTO_LAYOUT_FIELD_IN_LAYOUT); + m_ManagedLargestAlignmentRequirementOfAllMembers = alignment; } - void SetIsInt128OrHasInt128Fields(BOOL hasInt128Field) + ULONG InitializeSequentialFieldLayout( + FieldDesc* pFields, + MethodTable** pByValueClassCache, + ULONG cFields, + BYTE packingSize, + ULONG classSizeInMetadata, + MethodTable* pParentMT + ); + + ULONG InitializeExplicitFieldLayout( + FieldDesc* pFields, + MethodTable** pByValueClassCache, + ULONG cFields, + BYTE packingSize, + ULONG classSizeInMetadata, + MethodTable* pParentMT, + Module* pModule, + mdTypeDef cl + ); + + private: + void SetIsZeroSized(BOOL isZeroSized) { LIMITED_METHOD_CONTRACT; - m_bFlags = hasInt128Field ? (m_bFlags | e_IS_OR_HAS_INT128_FIELD) - : (m_bFlags & ~e_IS_OR_HAS_INT128_FIELD); + m_bFlags = isZeroSized ? (m_bFlags | e_ZERO_SIZED) + : (m_bFlags & ~e_ZERO_SIZED); + } + + void SetPackingSize(BYTE cbPackingSize) + { + LIMITED_METHOD_CONTRACT; + m_cbPackingSize = cbPackingSize; } + + UINT32 SetInstanceBytesSize(UINT32 size) + { + LIMITED_METHOD_CONTRACT; + // Bump the managed size of the structure up to 1. + SetIsZeroSized(size == 0 ? TRUE : FALSE); + return size == 0 ? 1 : size; + } + + void SetLayoutType(LayoutType layoutType) + { + LIMITED_METHOD_CONTRACT; + m_LayoutType = layoutType; + } + public: + enum class NestedFieldFlags + { + support_use_as_flags = -1, + None = 0x0, + NonBlittable = 0x1, + GCPointer = 0x2, + Align8 = 0x4, + AutoLayout = 0x8, + Int128 = 0x10, + }; + + static NestedFieldFlags GetNestedFieldFlags(Module* pModule, FieldDesc *pFD, ULONG cFields, CorNativeLinkType nlType, MethodTable** pByValueClassCache); }; // @@ -1964,7 +2003,7 @@ inline BOOL EEClass::IsBlittable() inline BOOL EEClass::IsManagedSequential() { LIMITED_METHOD_CONTRACT; - return HasLayout() && GetLayoutInfo()->IsManagedSequential(); + return HasLayout() && GetLayoutInfo()->GetLayoutType() == EEClassLayoutInfo::LayoutType::Sequential; } inline BOOL EEClass::HasExplicitSize() diff --git a/src/coreclr/vm/classcompat.h b/src/coreclr/vm/classcompat.h index 8876334faa1674..a17d2a3719209e 100644 --- a/src/coreclr/vm/classcompat.h +++ b/src/coreclr/vm/classcompat.h @@ -42,7 +42,6 @@ class EEClass; class LayoutEEClass; class EnCFieldDesc; class FieldDesc; -struct LayoutRawFieldInfo; class MetaSig; class MethodDesc; class MethodDescChunk; diff --git a/src/coreclr/vm/classlayoutinfo.cpp b/src/coreclr/vm/classlayoutinfo.cpp index 0b0b54005cdba3..766f364e49c63b 100644 --- a/src/coreclr/vm/classlayoutinfo.cpp +++ b/src/coreclr/vm/classlayoutinfo.cpp @@ -4,222 +4,44 @@ #include "common.h" #include "class.h" #include "fieldmarshaler.h" +#include "enum_class_flags.h" #ifndef DACCESS_COMPILE +struct LayoutRawFieldInfo final +{ + mdFieldDef m_token; // mdMemberDefNil for end of array + RawFieldPlacementInfo m_placement; + NativeFieldDescriptor m_nfd; +}; + namespace { - void SetOffsetsAndSortFields( - IMDInternalImport* pInternalImport, - const mdTypeDef cl, - LayoutRawFieldInfo* pFieldInfoArray, - const ULONG cInstanceFields, - const BOOL fExplicitOffsets, - const UINT32 cbAdjustedParentLayoutNativeSize, - Module* pModule, - LayoutRawFieldInfo** pSortArrayOut - ) + bool TryGetParentLayoutInfo(MethodTable* pParentMT, UINT32* pSize, BYTE* pAlignment) { - HRESULT hr; - MD_CLASS_LAYOUT classlayout; - hr = pInternalImport->GetClassLayoutInit(cl, &classlayout); - if (FAILED(hr)) - { - COMPlusThrowHR(hr, BFA_CANT_GET_CLASSLAYOUT); - } - - LayoutRawFieldInfo* pfwalk = pFieldInfoArray; - mdFieldDef fd; - ULONG ulOffset; - while (SUCCEEDED(hr = pInternalImport->GetClassLayoutNext( - &classlayout, - &fd, - &ulOffset)) && - fd != mdFieldDefNil) - { - // watch for the last entry: must be mdFieldDefNil - while ((mdFieldDefNil != pfwalk->m_MD) && (pfwalk->m_MD < fd)) - pfwalk++; - - // if we haven't found a matching token, it must be a static field with layout -- ignore it - if (pfwalk->m_MD != fd) continue; - - if (fExplicitOffsets) - { - // ulOffset is the explicit offset - pfwalk->m_placement.m_offset = ulOffset; - pfwalk->m_sequence = (ULONG)-1; - - // Treat base class as an initial member. - if (!ClrSafeInt::addition(pfwalk->m_placement.m_offset, cbAdjustedParentLayoutNativeSize, pfwalk->m_placement.m_offset)) - COMPlusThrowOM(); - } - } - IfFailThrow(hr); - - LayoutRawFieldInfo** pSortArrayEnd = pSortArrayOut; - // now sort the array - if (!fExplicitOffsets) - { - // sort sequential by ascending sequence - for (ULONG i = 0; i < cInstanceFields; i++) - { - LayoutRawFieldInfo** pSortWalk = pSortArrayEnd; - while (pSortWalk != pSortArrayOut) - { - if (pFieldInfoArray[i].m_sequence >= (*(pSortWalk - 1))->m_sequence) - break; - - pSortWalk--; - } + if (!pParentMT || !pParentMT->HasLayout()) + return false; - // pSortWalk now points to the target location for new LayoutRawFieldInfo*. - MoveMemory(pSortWalk + 1, pSortWalk, (pSortArrayEnd - pSortWalk) * sizeof(LayoutRawFieldInfo*)); - *pSortWalk = &pFieldInfoArray[i]; - pSortArrayEnd++; - } - } - else // no sorting for explicit layout - { - for (ULONG i = 0; i < cInstanceFields; i++) - { - if (pFieldInfoArray[i].m_MD != mdFieldDefNil) - { - if (pFieldInfoArray[i].m_placement.m_offset == (UINT32)-1) - { - LPCUTF8 szFieldName; - if (FAILED(pInternalImport->GetNameOfFieldDef(pFieldInfoArray[i].m_MD, &szFieldName))) - { - szFieldName = "Invalid FieldDef record"; - } - pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, - cl, - szFieldName, - IDS_CLASSLOAD_NSTRUCT_EXPLICIT_OFFSET); - } - else if ((INT)pFieldInfoArray[i].m_placement.m_offset < 0) - { - LPCUTF8 szFieldName; - if (FAILED(pInternalImport->GetNameOfFieldDef(pFieldInfoArray[i].m_MD, &szFieldName))) - { - szFieldName = "Invalid FieldDef record"; - } - pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, - cl, - szFieldName, - IDS_CLASSLOAD_NSTRUCT_NEGATIVE_OFFSET); - } - } - - *pSortArrayEnd = &pFieldInfoArray[i]; - pSortArrayEnd++; - } + EEClassLayoutInfo* pLayoutInfo = pParentMT->GetLayoutInfo(); + // Treat base class as an initial member. + // If the parent was originally a zero-sized explicit type but + // got bumped up to a size of 1 for compatibility reasons, then + // we need to remove the padding, but ONLY for inheritance situations. + UINT32 size; + if (pLayoutInfo->IsZeroSized()) { + size = 0; } - } - - void CalculateSizeAndFieldOffsets( - const UINT32 parentSize, - ULONG numInstanceFields, - BOOL fExplicitOffsets, - LayoutRawFieldInfo* const* pSortedFieldInfoArray, // An array of pointers to LayoutRawFieldInfo's in ascending order when sequential layout. - ULONG classSizeInMetadata, - BYTE packingSize, - BYTE parentAlignmentRequirement, - BOOL limitToMaxInteropSize, - BYTE* pLargestAlignmentRequirementOut, - UINT32* pSizeOut - ) - { - UINT32 cbCurOffset = parentSize; - BYTE LargestAlignmentRequirement = max(1, min(packingSize, parentAlignmentRequirement)); - - // Start with the size inherited from the parent (if any). - uint32_t calcTotalSize = parentSize; - - LayoutRawFieldInfo* const* pSortWalk; - ULONG i; - for (pSortWalk = pSortedFieldInfoArray, i = numInstanceFields; i; i--, pSortWalk++) + else { - LayoutRawFieldInfo* pfwalk = *pSortWalk; - RawFieldPlacementInfo* placementInfo = &pfwalk->m_placement; - - BYTE alignmentRequirement = (BYTE)placementInfo->m_alignment; - - alignmentRequirement = min(alignmentRequirement, packingSize); - - LargestAlignmentRequirement = max(LargestAlignmentRequirement, alignmentRequirement); - - switch (alignmentRequirement) - { - case 1: - case 2: - case 4: - case 8: - case 16: - case 32: - case 64: - break; - default: - COMPlusThrowHR(COR_E_INVALIDPROGRAM, BFA_METADATA_CORRUPT); - } - - if (!fExplicitOffsets) - { - // Insert enough padding to align the current data member. - while (cbCurOffset % alignmentRequirement) - { - if (!ClrSafeInt::addition(cbCurOffset, 1, cbCurOffset)) - COMPlusThrowOM(); - } - - // if we overflow we will catch it below - placementInfo->m_offset = cbCurOffset; - cbCurOffset += placementInfo->m_size; - } - - uint32_t fieldEnd = placementInfo->m_offset + placementInfo->m_size; - if (fieldEnd < placementInfo->m_offset) - COMPlusThrowOM(); - - // size of the structure is the size of the last field. - if (fieldEnd > calcTotalSize) - calcTotalSize = fieldEnd; + size = pParentMT->GetNumInstanceFieldBytes(); } + *pSize = size; - if (classSizeInMetadata != 0) + if (pParentMT->IsManagedSequential() || (pParentMT->GetClass()->HasExplicitFieldOffsetLayout() && pParentMT->IsBlittable())) { - ULONG classSize; - if (!ClrSafeInt::addition(classSizeInMetadata, (ULONG)parentSize, classSize)) - COMPlusThrowOM(); - - // size must be large enough to accommodate layout. If not, we use the layout size instead. - calcTotalSize = max((uint32_t)classSize, calcTotalSize); + *pAlignment = pLayoutInfo->GetAlignmentRequirement(); } - else - { - // There was no class size given in metadata, so let's round up to a multiple of the alignment requirement - // to make array allocations of this structure simple to keep aligned. - calcTotalSize += (LargestAlignmentRequirement - calcTotalSize % LargestAlignmentRequirement) % LargestAlignmentRequirement; - - if (calcTotalSize % LargestAlignmentRequirement != 0) - { - if (!ClrSafeInt::addition(calcTotalSize, LargestAlignmentRequirement - (calcTotalSize % LargestAlignmentRequirement), calcTotalSize)) - COMPlusThrowOM(); - } - } - - // We'll cap the total native size at a (somewhat) arbitrary limit to ensure - // that we don't expose some overflow bug later on. - if (calcTotalSize >= MAX_SIZE_FOR_INTEROP && limitToMaxInteropSize) - COMPlusThrowOM(); - - // The packingSize acts as a ceiling on all individual alignment - // requirements so it follows that the largest alignment requirement - // is also capped. - _ASSERTE(LargestAlignmentRequirement <= packingSize); - - *pSizeOut = calcTotalSize; - *pLargestAlignmentRequirementOut = LargestAlignmentRequirement; + return true; } RawFieldPlacementInfo GetFieldPlacementInfo(CorElementType corElemType, TypeHandle pNestedType) @@ -295,6 +117,247 @@ namespace return placementInfo; } + void InitializeLayoutFieldInfoArray(FieldDesc* pFields, ULONG cFields, MethodTable** pByValueClassCache, BYTE packingSize, LayoutRawFieldInfo* pInfoArray, UINT32* pNumInstanceFields, BYTE* pAlignmentRequirement) + { + ULONG cInstanceFields = 0; + BYTE alignmentRequirement = 0; + for (ULONG i = 0; i < cFields; i++) + { + FieldDesc* pField = &pFields[i]; + if (pField->IsStatic()) + continue; + + cInstanceFields++; + CorElementType corElemType = pField->GetFieldType(); + TypeHandle typeHandleMaybe{}; + + if (corElemType == ELEMENT_TYPE_VALUETYPE) + { + typeHandleMaybe = pByValueClassCache[i]; + + corElemType = typeHandleMaybe.AsMethodTable()->GetInternalCorElementType(); + if (corElemType != ELEMENT_TYPE_VALUETYPE) + typeHandleMaybe = TypeHandle{}; + } + + pInfoArray[i].m_token = pField->GetMemberDef(); + pInfoArray[i].m_placement = GetFieldPlacementInfo(corElemType, typeHandleMaybe); + + BYTE fieldAlignmentRequirement = (BYTE)pInfoArray[i].m_placement.m_alignment; + + fieldAlignmentRequirement = min(fieldAlignmentRequirement, packingSize); + + alignmentRequirement = max(alignmentRequirement, fieldAlignmentRequirement); + + switch (fieldAlignmentRequirement) + { + case 1: + case 2: + case 4: + case 8: + case 16: + case 32: + case 64: + break; + default: + COMPlusThrowHR(COR_E_INVALIDPROGRAM, BFA_METADATA_CORRUPT); + } + } + + *pNumInstanceFields = cInstanceFields; + *pAlignmentRequirement = alignmentRequirement; + } + + void SetFieldOffsets(FieldDesc* pFields, ULONG cFields, LayoutRawFieldInfo* pInfoArray, ULONG cInstanceFields) + { + for (ULONG i = 0, iInstanceFieldInfo = 0; i < cFields; i++) + { + FieldDesc* pField = &pFields[i]; + if (pField->IsStatic()) + continue; + + // We should only be placing unplaced fields at this point. + _ASSERTE(pField->GetOffset() == FIELD_OFFSET_UNPLACED + || pField->GetOffset() == FIELD_OFFSET_UNPLACED_GC_PTR + || pField->GetOffset() == FIELD_OFFSET_VALUE_CLASS); + + _ASSERTE(iInstanceFieldInfo < cInstanceFields); + IfFailThrow(pField->SetOffset(pInfoArray[iInstanceFieldInfo++].m_placement.m_offset)); + } + } + + /// @brief Read the offsets for a type's fields from metadata for explicit layout. + /// @param pModule The module containing the type. + /// @param cl The metadata token of the type. + /// @param pFieldInfoArray The information about the instance fields of the type. + /// @param cInstanceFields The numer of instance fields in the type. + /// @param parentSize The size of the parent type's layout. + /// @return The end of the last field in this layout + UINT32 ReadOffsetsForExplicitLayout( + Module* pModule, + const mdTypeDef cl, + LayoutRawFieldInfo* pFieldInfoArray, + const ULONG cInstanceFields, + const UINT32 parentSize + ) + { + HRESULT hr; + MD_CLASS_LAYOUT classlayout; + IMDInternalImport* pInternalImport = pModule->GetMDImport(); + hr = pInternalImport->GetClassLayoutInit(cl, &classlayout); + if (FAILED(hr)) + { + COMPlusThrowHR(hr, BFA_CANT_GET_CLASSLAYOUT); + } + + LayoutRawFieldInfo* pfwalk = pFieldInfoArray; + mdFieldDef fd; + ULONG ulOffset; + UINT32 calcTotalSize = 0; + while (SUCCEEDED(hr = pInternalImport->GetClassLayoutNext( + &classlayout, + &fd, + &ulOffset)) && + fd != mdFieldDefNil) + { + // watch for the last entry: must be mdFieldDefNil + while ((mdFieldDefNil != pfwalk->m_token) && (pfwalk->m_token < fd)) + pfwalk++; + + // if we haven't found a matching token, either we have invalid metadata + // or the field doesn't have an entry. We'll error out in the next loop. + if (pfwalk->m_token != fd) continue; + + // ulOffset is the explicit offset + pfwalk->m_placement.m_offset = ulOffset; + + // Treat base class as an initial member. + if (!ClrSafeInt::addition(pfwalk->m_placement.m_offset, parentSize, pfwalk->m_placement.m_offset)) + COMPlusThrowOM(); + + uint32_t fieldEnd; + if (!ClrSafeInt::addition(pfwalk->m_placement.m_offset, pfwalk->m_placement.m_size, fieldEnd)) + COMPlusThrowOM(); + + // size of the structure is the size of the last field. + if (fieldEnd > calcTotalSize) + calcTotalSize = fieldEnd; + } + IfFailThrow(hr); + + for (ULONG i = 0; i < cInstanceFields; i++) + { + if (pFieldInfoArray[i].m_token != mdFieldDefNil) + { + if (pFieldInfoArray[i].m_placement.m_offset == (UINT32)-1) + { + LPCUTF8 szFieldName; + if (FAILED(pInternalImport->GetNameOfFieldDef(pFieldInfoArray[i].m_token, &szFieldName))) + { + szFieldName = "Invalid FieldDef record"; + } + pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, + cl, + szFieldName, + IDS_CLASSLOAD_NSTRUCT_EXPLICIT_OFFSET); + } + else if (pFieldInfoArray[i].m_placement.m_offset > INT32_MAX) + { + LPCUTF8 szFieldName; + if (FAILED(pInternalImport->GetNameOfFieldDef(pFieldInfoArray[i].m_token, &szFieldName))) + { + szFieldName = "Invalid FieldDef record"; + } + pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, + cl, + szFieldName, + IDS_CLASSLOAD_NSTRUCT_NEGATIVE_OFFSET); + } + } + } + + return calcTotalSize; + } + + /// @brief Calculate the offsets of the fields if they were to be laid out in sequential order at their alignment requirements. + /// @param pFieldInfoArray The information about the instance fields of the type. + /// @param cInstanceFields The numer of instance fields in the type. + /// @param parentSize The size of the parent type's layout. + /// @param packingSize The packing size of the type. + /// @return The end of the last field in this layout + ULONG CalculateOffsetsForSequentialLayout( + LayoutRawFieldInfo* pFieldInfoArray, + const ULONG numInstanceFields, + const UINT32 parentSize, + const BYTE packingSize + ) + { + _ASSERTE(packingSize != 0); + UINT32 cbCurOffset = parentSize; + + // Start with the size inherited from the parent (if any). + uint32_t calcTotalSize = parentSize; + + for (UINT32 i = 0; i < numInstanceFields; i++) + { + RawFieldPlacementInfo& placementInfo = pFieldInfoArray[i].m_placement; + + BYTE alignmentRequirement = min((BYTE)placementInfo.m_alignment, packingSize); + + // Insert enough padding to align the current data member. + if (!ClrSafeInt::addition(cbCurOffset, (alignmentRequirement - (cbCurOffset % alignmentRequirement)) % alignmentRequirement, cbCurOffset)) + COMPlusThrowOM(); + + placementInfo.m_offset = cbCurOffset; + + if (!ClrSafeInt::addition(cbCurOffset, placementInfo.m_size, cbCurOffset)) + { + COMPlusThrowOM(); + } + + // size of the structure is the size of the last field. + if (cbCurOffset > calcTotalSize) + calcTotalSize = cbCurOffset; + } + + return calcTotalSize; + } + + ULONG CalculateSizeWithMetadataSize( + const ULONG parentSize, + const UINT32 lastFieldEnd, + const ULONG classSizeInMetadata + ) + { + // If we have successfully fetched the class size from metadata, + // we'll try to use it. Add the parent size to the metadata size, + // so it represents the full size of the class. + ULONG classSize; + if (!ClrSafeInt::addition(classSizeInMetadata, (ULONG)parentSize, classSize)) + COMPlusThrowOM(); + + // size must be large enough to accommodate layout. If not, we use the layout size instead. + return max((uint32_t)classSize, lastFieldEnd); + } + + UINT32 AlignSize( + const UINT32 lastFieldEnd, + BYTE alignmentRequirement + ) + { + ULONG calcTotalSize = lastFieldEnd; + + // There was no class size given in metadata, so let's round up to a multiple of the alignment requirement + // to make array allocations of this structure simple to keep aligned. + if (calcTotalSize % alignmentRequirement != 0) + { + if (!ClrSafeInt::addition(calcTotalSize, (alignmentRequirement - (calcTotalSize % alignmentRequirement)) % alignmentRequirement, calcTotalSize)) + COMPlusThrowOM(); + } + + return calcTotalSize; + } + BOOL TypeHasGCPointers(CorElementType corElemType, TypeHandle pNestedType) { if (CorTypeInfo::IsPrimitiveType(corElemType) || corElemType == ELEMENT_TYPE_PTR || corElemType == ELEMENT_TYPE_FNPTR || @@ -334,7 +397,219 @@ namespace return FALSE; } -#ifdef UNIX_AMD64_ABI + ParseNativeTypeFlags NlTypeToNativeTypeFlags(CorNativeLinkType nlType) + { + ParseNativeTypeFlags nativeTypeFlags = ParseNativeTypeFlags::None; + if (nlType == nltAnsi) + nativeTypeFlags = ParseNativeTypeFlags::IsAnsi; + + return nativeTypeFlags; + } + +#ifdef FEATURE_DOUBLE_ALIGNMENT_HINT + //******************************************************************************* + // + // Heuristic to determine if we should have instances of this class 8 byte aligned + // + bool ShouldAlign8(ULONG dwR8Fields, ULONG dwTotalFields) + { + LIMITED_METHOD_CONTRACT; + + return dwR8Fields*2>dwTotalFields && dwR8Fields>=2; + } +#endif +} + +auto EEClassLayoutInfo::GetNestedFieldFlags(Module* pModule, FieldDesc *pFields, ULONG cFields, CorNativeLinkType nlType, MethodTable** pByValueClassCache) -> NestedFieldFlags +{ + STANDARD_VM_CONTRACT; + + NestedFieldFlags flags = NestedFieldFlags::None; + const ParseNativeTypeFlags nativeTypeFlags = NlTypeToNativeTypeFlags(nlType); + + ULONG numR8Fields = 0; + ULONG numInstanceFields = 0; + + for (ULONG i = 0; i < cFields; i++) + { + FieldDesc* pField = &pFields[i]; + if (pField->IsStatic()) + continue; + + numInstanceFields++; + CorElementType corElemType = pField->GetFieldType(); + TypeHandle typeHandleMaybe{}; + + if (corElemType == ELEMENT_TYPE_VALUETYPE) + { + typeHandleMaybe = pByValueClassCache[i]; + + corElemType = typeHandleMaybe.AsMethodTable()->GetInternalCorElementType(); + if (corElemType != ELEMENT_TYPE_VALUETYPE) + typeHandleMaybe = TypeHandle(); + } + + if (corElemType == ELEMENT_TYPE_R8) + { + numR8Fields++; + } + +#ifdef FEATURE_64BIT_ALIGNMENT + if (!typeHandleMaybe.IsNull() && typeHandleMaybe.GetMethodTable()->GetClass()->IsAlign8Candidate()) + { + flags |= NestedFieldFlags::Align8; + } + + if (corElemType == ELEMENT_TYPE_I8 + || corElemType == ELEMENT_TYPE_U8 + || corElemType == ELEMENT_TYPE_R8 + IN_TARGET_64BIT(|| corElemType == ELEMENT_TYPE_I || corElemType == ELEMENT_TYPE_U)) + { + flags |= NestedFieldFlags::Align8; + } +#endif + + if (!IsFieldBlittable(pModule, pField->GetMemberDef(), corElemType, typeHandleMaybe, nativeTypeFlags)) + { + flags |= NestedFieldFlags::NonBlittable; + } + + if (TypeHasGCPointers(corElemType, typeHandleMaybe)) + { + flags |= NestedFieldFlags::GCPointer; + } + + if (TypeHasAutoLayoutField(corElemType, typeHandleMaybe)) + { + flags |= NestedFieldFlags::AutoLayout; + } + + if (TypeHasInt128Field(corElemType, typeHandleMaybe)) + { + flags |= NestedFieldFlags::Int128; + } + } + +#ifdef FEATURE_DOUBLE_ALIGNMENT_HINT + if (ShouldAlign8(numR8Fields, numInstanceFields)) + { + flags |= NestedFieldFlags::Align8; + } +#endif + + return flags; +} + +ULONG EEClassLayoutInfo::InitializeSequentialFieldLayout( + FieldDesc* pFields, + MethodTable** pByValueClassCache, + ULONG cFields, + BYTE packingSize, + ULONG classSizeInMetadata, + MethodTable* pParentMT +) +{ + STANDARD_VM_CONTRACT; + + SetLayoutType(LayoutType::Sequential); + + UINT32 cbAdjustedParentLayoutSize; + BYTE parentAlignmentRequirement; + if (!TryGetParentLayoutInfo(pParentMT, &cbAdjustedParentLayoutSize, &parentAlignmentRequirement)) + { + cbAdjustedParentLayoutSize = 0; + parentAlignmentRequirement = 0; + } + + NewArrayHolder pInfoArray = new LayoutRawFieldInfo[cFields + 1]; + UINT32 numInstanceFields; + BYTE fieldsAlignmentRequirement; + InitializeLayoutFieldInfoArray(pFields, cFields, pByValueClassCache, packingSize, pInfoArray, &numInstanceFields, &fieldsAlignmentRequirement); + + BYTE alignmentRequirement = max(max(1, min(packingSize, parentAlignmentRequirement)), fieldsAlignmentRequirement); + + // The packingSize acts as a ceiling on all individual alignment + // requirements so it follows that the largest alignment requirement + // is also capped. + _ASSERTE(alignmentRequirement <= packingSize); + SetAlignmentRequirement(alignmentRequirement); + SetPackingSize(packingSize); + + UINT32 lastFieldEnd = CalculateOffsetsForSequentialLayout(pInfoArray, numInstanceFields, cbAdjustedParentLayoutSize, packingSize); + + SetFieldOffsets(pFields, cFields, pInfoArray, numInstanceFields); + + UINT32 managedSize; + if (classSizeInMetadata != 0) + { + managedSize = CalculateSizeWithMetadataSize(cbAdjustedParentLayoutSize, lastFieldEnd, classSizeInMetadata); + } + else + { + managedSize = AlignSize(lastFieldEnd, alignmentRequirement); + } + + return SetInstanceBytesSize(managedSize); +} + +ULONG EEClassLayoutInfo::InitializeExplicitFieldLayout( + FieldDesc* pFields, + MethodTable** pByValueClassCache, + ULONG cFields, + BYTE packingSize, + ULONG classSizeInMetadata, + MethodTable* pParentMT, + Module* pModule, + mdTypeDef cl +) +{ + STANDARD_VM_CONTRACT; + + SetLayoutType(LayoutType::Explicit); + + UINT32 cbAdjustedParentLayoutSize; + BYTE parentAlignmentRequirement; + if (!TryGetParentLayoutInfo(pParentMT, &cbAdjustedParentLayoutSize, &parentAlignmentRequirement)) + { + cbAdjustedParentLayoutSize = 0; + parentAlignmentRequirement = 0; + } + + NewArrayHolder pInfoArray = new LayoutRawFieldInfo[cFields + 1]; + UINT32 numInstanceFields; + BYTE fieldsAlignmentRequirement; + InitializeLayoutFieldInfoArray(pFields, cFields, pByValueClassCache, packingSize, pInfoArray, &numInstanceFields, &fieldsAlignmentRequirement); + + BYTE alignmentRequirement = max(max(1, min(packingSize, parentAlignmentRequirement)), fieldsAlignmentRequirement); + + // The packingSize acts as a ceiling on all individual alignment + // requirements so it follows that the largest alignment requirement + // is also capped. + _ASSERTE(alignmentRequirement <= packingSize); + SetAlignmentRequirement(alignmentRequirement); + SetPackingSize(packingSize); + + UINT32 lastFieldEnd = 0; + lastFieldEnd = ReadOffsetsForExplicitLayout(pModule, cl, pInfoArray, numInstanceFields, cbAdjustedParentLayoutSize); + + SetFieldOffsets(pFields, cFields, pInfoArray, numInstanceFields); + + UINT32 managedSize; + if (classSizeInMetadata != 0) + { + managedSize = CalculateSizeWithMetadataSize(cbAdjustedParentLayoutSize, lastFieldEnd, classSizeInMetadata); + } + else + { + managedSize = AlignSize(lastFieldEnd, alignmentRequirement); + } + + return SetInstanceBytesSize(managedSize); +} + +namespace +{ + #ifdef UNIX_AMD64_ABI void SystemVAmd64CheckForPassNativeStructInRegister(MethodTable* pMT, EEClassNativeLayoutInfo* pNativeLayoutInfo) { STANDARD_VM_CONTRACT; @@ -419,9 +694,8 @@ namespace pFieldDesc->GetSig(&pCOMSignature, &cbCOMSignature); // fill the appropriate entry in pInfoArray - pFieldInfoArrayOut->m_MD = fd; + pFieldInfoArrayOut->m_token = fd; pFieldInfoArrayOut->m_placement.m_offset = (UINT32)-1; - pFieldInfoArrayOut->m_sequence = 0; #ifdef _DEBUG LPCUTF8 szFieldName; @@ -449,137 +723,7 @@ namespace } // NULL out the last entry - pFieldInfoArrayOut->m_MD = mdFieldDefNil; - } - - void DetermineBlittabilityAndManagedSequential( - IMDInternalImport* pInternalImport, - HENUMInternal* phEnumField, - Module* pModule, - mdTypeDef cl, - ParseNativeTypeFlags nativeTypeFlags, - const SigTypeContext* pTypeContext, - BOOL* fDisqualifyFromManagedSequential, - BOOL* fHasAutoLayoutField, - BOOL* fHasInt128Field, - LayoutRawFieldInfo* pFieldInfoArrayOut, - BOOL* pIsBlittableOut, - ULONG* cInstanceFields - #ifdef _DEBUG - , - const ULONG cTotalFields, - LPCUTF8 szNamespace, - LPCUTF8 szName - #endif - ) - { - STANDARD_VM_CONTRACT; - - HRESULT hr; - mdFieldDef fd; - ULONG maxRid = pInternalImport->GetCountWithTokenKind(mdtFieldDef); - *pIsBlittableOut = TRUE; // Assume is blittable until proven otherwise. - - ULONG i; - for (i = 0; pInternalImport->EnumNext(phEnumField, &fd); i++) - { - DWORD dwFieldAttrs; - ULONG rid = RidFromToken(fd); - - if ((rid == 0) || (rid > maxRid)) - { - COMPlusThrowHR(COR_E_TYPELOAD, BFA_BAD_FIELD_TOKEN); - } - - IfFailThrow(pInternalImport->GetFieldDefProps(fd, &dwFieldAttrs)); - - PCCOR_SIGNATURE pNativeType = NULL; - ULONG cbNativeType; - // We ignore marshaling data attached to statics and literals, - // since these do not contribute to instance data. - if (!IsFdStatic(dwFieldAttrs) && !IsFdLiteral(dwFieldAttrs)) - { - PCCOR_SIGNATURE pCOMSignature; - ULONG cbCOMSignature; - - if (IsFdHasFieldMarshal(dwFieldAttrs)) - { - hr = pInternalImport->GetFieldMarshal(fd, &pNativeType, &cbNativeType); - if (FAILED(hr)) - { - cbNativeType = 0; - } - } - else - { - cbNativeType = 0; - } - - IfFailThrow(pInternalImport->GetSigOfFieldDef(fd, &cbCOMSignature, &pCOMSignature)); - - IfFailThrow(::validateTokenSig(fd, pCOMSignature, cbCOMSignature, dwFieldAttrs, pInternalImport)); - - // fill the appropriate entry in pInfoArray - pFieldInfoArrayOut->m_MD = fd; - pFieldInfoArrayOut->m_sequence = 0; - - #ifdef _DEBUG - LPCUTF8 szFieldName; - if (FAILED(pInternalImport->GetNameOfFieldDef(fd, &szFieldName))) - { - szFieldName = "Invalid FieldDef record"; - } - #endif - MetaSig fsig(pCOMSignature, cbCOMSignature, pModule, pTypeContext, MetaSig::sigField); - CorElementType corElemType = fsig.NextArg(); - - TypeHandle typeHandleMaybe; - if (corElemType == ELEMENT_TYPE_VALUETYPE) // Only look up the next element in the signature if it is a value type to avoid causing recursive type loads in valid scenarios. - { - SigPointer::HandleRecursiveGenericsForFieldLayoutLoad recursiveControl; - recursiveControl.pModuleWithTokenToAvoidIfPossible = pModule; - recursiveControl.tkTypeDefToAvoidIfPossible = cl; - typeHandleMaybe = fsig.GetArgProps().GetTypeHandleThrowing(pModule, - pTypeContext, - ClassLoader::LoadTypes, - CLASS_LOAD_APPROXPARENTS, - TRUE, NULL, NULL, NULL, - &recursiveControl); - - if (typeHandleMaybe.IsNull()) - { - // Everett C++ compiler can generate a TypeRef with RS=0 - // without respective TypeDef for unmanaged valuetypes, - // referenced only by pointers to them. - // In such case, GetTypeHandleThrowing returns null handle, - // and we return E_T_VOID - typeHandleMaybe = TypeHandle(CoreLibBinder::GetElementType(ELEMENT_TYPE_VOID)); - } - corElemType = typeHandleMaybe.AsMethodTable()->GetInternalCorElementType(); - if (corElemType != ELEMENT_TYPE_VALUETYPE) - typeHandleMaybe = TypeHandle(); - } - else if (corElemType == ELEMENT_TYPE_TYPEDBYREF) - { - typeHandleMaybe = TypeHandle(g_TypedReferenceMT); - } - - pFieldInfoArrayOut->m_placement = GetFieldPlacementInfo(corElemType, typeHandleMaybe); - *fDisqualifyFromManagedSequential |= TypeHasGCPointers(corElemType, typeHandleMaybe); - *fHasAutoLayoutField |= TypeHasAutoLayoutField(corElemType, typeHandleMaybe); - *fHasInt128Field |= TypeHasInt128Field(corElemType, typeHandleMaybe); - - if (!IsFieldBlittable(pModule, fd, corElemType, typeHandleMaybe, nativeTypeFlags)) - *pIsBlittableOut = FALSE; - - (*cInstanceFields)++; - pFieldInfoArrayOut++; - } - } - - _ASSERTE(i == cTotalFields); - // NULL out the last entry - pFieldInfoArrayOut->m_MD = mdFieldDefNil; + pFieldInfoArrayOut->m_token = mdFieldDefNil; } #ifdef FEATURE_HFA @@ -611,198 +755,23 @@ namespace pNativeLayoutInfo->SetHFAType(hfaType); } #endif // FEATURE_HFA -} - -//======================================================================= -// Called from the clsloader to load up and summarize the field metadata -// for layout classes. -// -// Warning: This function can load other classes (esp. for nested structs.) -//======================================================================= -VOID EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing( - mdTypeDef cl, // cl of the NStruct being loaded - BYTE packingSize, // packing size (from @dll.struct) - BYTE nlType, // nltype (from @dll.struct) - BOOL fExplicitOffsets, // explicit offsets? - MethodTable *pParentMT, // the loaded superclass - ULONG cTotalFields, // total number of fields (instance and static) - HENUMInternal *phEnumField, // enumerator for field - Module *pModule, // Module that defines the scope, loader and heap (for allocate FieldMarshalers) - const SigTypeContext *pTypeContext, // Type parameters for NStruct being loaded - EEClassLayoutInfo *pEEClassLayoutInfoOut, // caller-allocated structure to fill in. - LayoutRawFieldInfo *pInfoArrayOut, // caller-allocated array to fill in. Needs room for cMember+1 elements - LoaderAllocator *pAllocator, - AllocMemTracker *pamTracker -) -{ - CONTRACTL - { - STANDARD_VM_CHECK; - PRECONDITION(CheckPointer(pModule)); - } - CONTRACTL_END; - - // Internal interface for the NStruct being loaded. - IMDInternalImport *pInternalImport = pModule->GetMDImport(); - -#ifdef _DEBUG - LPCUTF8 szName; - LPCUTF8 szNamespace; - if (FAILED(pInternalImport->GetNameOfTypeDef(cl, &szName, &szNamespace))) - { - szName = szNamespace = "Invalid TypeDef record"; - } - - if (g_pConfig->ShouldBreakOnStructMarshalSetup(szName)) - CONSISTENCY_CHECK_MSGF(false, ("BreakOnStructMarshalSetup: '%s' ", szName)); -#endif - - // Running tote - if anything in this type disqualifies it from being ManagedSequential, somebody will set this to TRUE by the time - // function exits. - BOOL fDisqualifyFromManagedSequential; - BOOL hasAutoLayoutField = FALSE; - BOOL hasInt128Field = FALSE; - - // Check if this type might be ManagedSequential. Only valuetypes marked Sequential can be - // ManagedSequential. Other issues checked below might also disqualify the type. - if ( (!fExplicitOffsets) && // Is it marked sequential? - (pParentMT && (pParentMT->IsObjectClass() || pParentMT->IsValueTypeClass() || pParentMT->IsManagedSequential())) // Is it a valuetype or derived from a qualifying valuetype? - ) - { - fDisqualifyFromManagedSequential = FALSE; - } - else - { - fDisqualifyFromManagedSequential = TRUE; - } - - if (pParentMT && !pParentMT->IsValueTypeClass()) - { - if (pParentMT->IsAutoLayoutOrHasAutoLayoutField()) - hasAutoLayoutField = TRUE; - if (pParentMT->IsInt128OrHasInt128Fields()) - hasInt128Field = TRUE; - } - - - BOOL fHasNonTrivialParent = pParentMT && - !pParentMT->IsObjectClass() && - !pParentMT->IsValueTypeClass(); - - - // Set some defaults based on the parent type of this type (if one exists). - _ASSERTE(!(fHasNonTrivialParent && !(pParentMT->HasLayout()))); - - pEEClassLayoutInfoOut->SetIsZeroSized(FALSE); - pEEClassLayoutInfoOut->SetHasExplicitSize(FALSE); - pEEClassLayoutInfoOut->m_cbPackingSize = packingSize; - - BOOL fParentHasLayout = pParentMT && pParentMT->HasLayout(); - UINT32 cbAdjustedParentLayoutSize = 0; - EEClassLayoutInfo *pParentLayoutInfo = NULL; - if (fParentHasLayout) - { - pParentLayoutInfo = pParentMT->GetLayoutInfo(); - // Treat base class as an initial member. - // If the parent was originally a zero-sized explicit type but - // got bumped up to a size of 1 for compatibility reasons, then - // we need to remove the padding, but ONLY for inheritance situations. - if (pParentLayoutInfo->IsZeroSized()) { - cbAdjustedParentLayoutSize = 0; - } - else - { - cbAdjustedParentLayoutSize = pParentMT->GetNumInstanceFieldBytes(); - } - } - - ULONG cInstanceFields = 0; - - ParseNativeTypeFlags nativeTypeFlags = ParseNativeTypeFlags::None; - if (nlType == nltAnsi) - nativeTypeFlags = ParseNativeTypeFlags::IsAnsi; - - BOOL isBlittable; - - DetermineBlittabilityAndManagedSequential( - pInternalImport, - phEnumField, - pModule, - cl, - nativeTypeFlags, - pTypeContext, - &fDisqualifyFromManagedSequential, - &hasAutoLayoutField, - &hasInt128Field, - pInfoArrayOut, - &isBlittable, - &cInstanceFields - DEBUGARG(cTotalFields) - DEBUGARG(szNamespace) - DEBUGARG(szName) - ); - // Type is blittable only if parent is also blittable - isBlittable = isBlittable && (fHasNonTrivialParent ? pParentMT->IsBlittable() : TRUE); - pEEClassLayoutInfoOut->SetIsBlittable(isBlittable); - - pEEClassLayoutInfoOut->SetHasAutoLayoutField(hasAutoLayoutField); - - pEEClassLayoutInfoOut->SetIsInt128OrHasInt128Fields(hasInt128Field); - - S_UINT32 cbSortArraySize = S_UINT32(cTotalFields) * S_UINT32(sizeof(LayoutRawFieldInfo*)); - if (cbSortArraySize.IsOverflow()) + EEClassNativeLayoutInfo const* FindParentNativeLayoutInfo(MethodTable* pParentMT) { - ThrowHR(COR_E_TYPELOAD); - } - CQuickArray pSortArray; - pSortArray.ReSizeThrows(cbSortArraySize.Value()); - SetOffsetsAndSortFields(pInternalImport, cl, pInfoArrayOut, cInstanceFields, fExplicitOffsets, cbAdjustedParentLayoutSize, pModule, pSortArray.Ptr()); + STANDARD_VM_CONTRACT; - ULONG classSizeInMetadata = 0; - if (FAILED(pInternalImport->GetClassTotalSize(cl, &classSizeInMetadata))) - { - classSizeInMetadata = 0; - } - else - { - // If we can get the class size from metadata, that means that the user - // explicitly provided a value to the StructLayoutAttribute.Size field - // or explicitly provided the size in IL. - pEEClassLayoutInfoOut->SetHasExplicitSize(TRUE); - } + if (!pParentMT || !pParentMT->HasLayout()) + return nullptr; - BYTE parentAlignmentRequirement = 0; - if (fParentHasLayout) - { - parentAlignmentRequirement = pParentLayoutInfo->m_ManagedLargestAlignmentRequirementOfAllMembers; - } + bool fHasNonTrivialParent = pParentMT && + !pParentMT->IsObjectClass() && + !pParentMT->IsValueTypeClass(); - BYTE parentManagedAlignmentRequirement = 0; - if (pParentMT && (pParentMT->IsManagedSequential() || (pParentMT->GetClass()->HasExplicitFieldOffsetLayout() && pParentMT->IsBlittable()))) - { - parentManagedAlignmentRequirement = pParentLayoutInfo->m_ManagedLargestAlignmentRequirementOfAllMembers; - } + // Set some defaults based on the parent type of this type (if one exists). + _ASSERTE(!(fHasNonTrivialParent && !(pParentMT->HasLayout()))); - CalculateSizeAndFieldOffsets( - cbAdjustedParentLayoutSize, - cInstanceFields, - fExplicitOffsets, - pSortArray.Ptr(), - classSizeInMetadata, - packingSize, - parentManagedAlignmentRequirement, - /*limitToMaxInteropSize*/ FALSE, - &pEEClassLayoutInfoOut->m_ManagedLargestAlignmentRequirementOfAllMembers, - &pEEClassLayoutInfoOut->m_cbManagedSize); - - if (pEEClassLayoutInfoOut->m_cbManagedSize == 0) - { - pEEClassLayoutInfoOut->SetIsZeroSized(TRUE); - pEEClassLayoutInfoOut->m_cbManagedSize = 1; // Bump the managed size of the structure up to 1. + return pParentMT->GetNativeLayoutInfo(); } - - pEEClassLayoutInfoOut->SetIsManagedSequential(!fDisqualifyFromManagedSequential); } void EEClassNativeLayoutInfo::InitializeNativeLayoutFieldMetadataThrowing(MethodTable* pMT) @@ -875,19 +844,10 @@ EEClassNativeLayoutInfo* EEClassNativeLayoutInfo::CollectNativeLayoutFieldMetada MethodTable* pParentMT = pMT->GetParentMethodTable(); - BOOL fHasNonTrivialParent = pParentMT && - !pParentMT->IsObjectClass() && - !pParentMT->IsValueTypeClass(); - - // Set some defaults based on the parent type of this type (if one exists). - _ASSERTE(!(fHasNonTrivialParent && !(pParentMT->HasLayout()))); - - BOOL fParentHasLayout = pParentMT && pParentMT->HasLayout(); UINT32 cbAdjustedParentLayoutNativeSize = 0; - EEClassNativeLayoutInfo const* pParentLayoutInfo = NULL; - if (fParentHasLayout) + EEClassNativeLayoutInfo const* pParentLayoutInfo = FindParentNativeLayoutInfo(pParentMT); + if (pParentLayoutInfo != nullptr) { - pParentLayoutInfo = pParentMT->GetNativeLayoutInfo(); // Treat base class as an initial member. cbAdjustedParentLayoutNativeSize = pParentLayoutInfo->GetSize(); // If the parent was originally a zero-sized explicit type but @@ -899,12 +859,9 @@ EEClassNativeLayoutInfo* EEClassNativeLayoutInfo::CollectNativeLayoutFieldMetada } } - CorNativeLinkType charSet = pMT->GetCharSet(); - ParseNativeTypeFlags nativeTypeFlags = ParseNativeTypeFlags::None; - if (charSet == nltAnsi) - nativeTypeFlags = ParseNativeTypeFlags::IsAnsi; + ParseNativeTypeFlags nativeTypeFlags = NlTypeToNativeTypeFlags(charSet); ApproxFieldDescIterator fieldDescs(pMT, ApproxFieldDescIterator::INSTANCE_FIELDS); @@ -934,33 +891,53 @@ EEClassNativeLayoutInfo* EEClassNativeLayoutInfo::CollectNativeLayoutFieldMetada pNativeLayoutInfo->m_numFields = numTotalInstanceFields; + BYTE parentAlignmentRequirement = 0; + if (pParentLayoutInfo != nullptr) + { + parentAlignmentRequirement = pParentLayoutInfo->GetLargestAlignmentRequirement(); + } + + BYTE fieldAlignmentRequirement = 0; // Now compute the native size of each field - for (LayoutRawFieldInfo* pfwalk = pInfoArray; pfwalk->m_MD != mdFieldDefNil; pfwalk++) + for (LayoutRawFieldInfo* pfwalk = pInfoArray; pfwalk->m_token != mdFieldDefNil; pfwalk++) { pfwalk->m_placement.m_size = pfwalk->m_nfd.NativeSize(); pfwalk->m_placement.m_alignment = pfwalk->m_nfd.AlignmentRequirement(); + if (pfwalk->m_placement.m_alignment > fieldAlignmentRequirement) + { + fieldAlignmentRequirement = (BYTE)pfwalk->m_placement.m_alignment; + } } - S_UINT32 cbSortArraySize = S_UINT32(cInstanceFields) * S_UINT32(sizeof(LayoutRawFieldInfo*)); - if (cbSortArraySize.IsOverflow()) - { - ThrowHR(COR_E_TYPELOAD); - } + pNativeLayoutInfo->m_alignmentRequirement = max(max(1, parentAlignmentRequirement), fieldAlignmentRequirement); BOOL fExplicitOffsets = pMT->GetClass()->HasExplicitFieldOffsetLayout(); - CQuickArray pSortArray; - pSortArray.ReSizeThrows(cbSortArraySize.Value()); - SetOffsetsAndSortFields(pInternalImport, pMT->GetCl(), pInfoArray, cInstanceFields, fExplicitOffsets, cbAdjustedParentLayoutNativeSize, pModule, pSortArray.Ptr()); + ULONG lastFieldEnd = 0; + if (fExplicitOffsets) + { + lastFieldEnd = ReadOffsetsForExplicitLayout(pModule, pMT->GetCl(), pInfoArray, cInstanceFields, cbAdjustedParentLayoutNativeSize); + } + else + { + BYTE packingSize = pMT->GetLayoutInfo()->GetPackingSize(); + if (packingSize == 0) + { + packingSize = DEFAULT_PACKING_SIZE; + } + lastFieldEnd = CalculateOffsetsForSequentialLayout(pInfoArray, cInstanceFields, cbAdjustedParentLayoutNativeSize, packingSize); + } EEClassLayoutInfo* pEEClassLayoutInfo = pMT->GetLayoutInfo(); - ULONG classSizeInMetadata = 0; if (pEEClassLayoutInfo->HasExplicitSize()) { + ULONG classSizeInMetadata = 0; HRESULT hr = pInternalImport->GetClassTotalSize(pMT->GetCl(), &classSizeInMetadata); CONSISTENCY_CHECK(hr == S_OK); + + pNativeLayoutInfo->m_size = CalculateSizeWithMetadataSize(cbAdjustedParentLayoutNativeSize, lastFieldEnd, classSizeInMetadata); } else if (pMT->GetClass()->IsInlineArray()) { @@ -982,29 +959,20 @@ EEClassNativeLayoutInfo* EEClassNativeLayoutInfo::CollectNativeLayoutFieldMetada INT32 repeat = GET_UNALIGNED_VAL32((byte*)pVal + 2); if (repeat > 0) { - classSizeInMetadata = repeat * pInfoArray[0].m_nfd.NativeSize(); + pNativeLayoutInfo->m_size = repeat * pInfoArray[0].m_nfd.NativeSize(); } } } } - - BYTE parentAlignmentRequirement = 0; - if (fParentHasLayout) + else { - parentAlignmentRequirement = pParentLayoutInfo->GetLargestAlignmentRequirement(); + pNativeLayoutInfo->m_size = AlignSize(lastFieldEnd, pNativeLayoutInfo->GetLargestAlignmentRequirement()); } - CalculateSizeAndFieldOffsets( - cbAdjustedParentLayoutNativeSize, - cInstanceFields, - fExplicitOffsets, - pSortArray.Ptr(), - classSizeInMetadata, - pMT->GetLayoutInfo()->GetPackingSize(), - parentAlignmentRequirement, - /*limitToMaxInteropSize*/ TRUE, - &pNativeLayoutInfo->m_alignmentRequirement, - &pNativeLayoutInfo->m_size); + // We'll cap the total native size at a (somewhat) arbitrary limit to ensure + // that we don't expose some overflow bug later on. + if (pNativeLayoutInfo->m_size >= MAX_SIZE_FOR_INTEROP) + COMPlusThrowOM(); if (pNativeLayoutInfo->m_size == 0) { @@ -1020,8 +988,8 @@ EEClassNativeLayoutInfo* EEClassNativeLayoutInfo::CollectNativeLayoutFieldMetada // from the managed size and alignment. if (pMT->HasSameTypeDefAs(CoreLibBinder::GetClass(CLASS__VECTORT))) { - pNativeLayoutInfo->m_size = pEEClassLayoutInfo->GetManagedSize(); - pNativeLayoutInfo->m_alignmentRequirement = pEEClassLayoutInfo->m_ManagedLargestAlignmentRequirementOfAllMembers; + pNativeLayoutInfo->m_size = pMT->GetNumInstanceFieldBytes(); + pNativeLayoutInfo->m_alignmentRequirement = pEEClassLayoutInfo->GetAlignmentRequirement(); } else if (pMT->HasSameTypeDefAs(CoreLibBinder::GetClass(CLASS__INT128)) || @@ -1031,18 +999,15 @@ EEClassNativeLayoutInfo* EEClassNativeLayoutInfo::CollectNativeLayoutFieldMetada pMT->HasSameTypeDefAs(CoreLibBinder::GetClass(CLASS__VECTOR256T)) || pMT->HasSameTypeDefAs(CoreLibBinder::GetClass(CLASS__VECTOR512T))) { - pNativeLayoutInfo->m_alignmentRequirement = pEEClassLayoutInfo->m_ManagedLargestAlignmentRequirementOfAllMembers; + pNativeLayoutInfo->m_alignmentRequirement = pEEClassLayoutInfo->GetAlignmentRequirement(); } } PTR_NativeFieldDescriptor pNativeFieldDescriptors = pNativeLayoutInfo->GetNativeFieldDescriptors(); // Bring in the parent's fieldmarshalers - if (fHasNonTrivialParent) + if (pParentLayoutInfo != nullptr) { - CONSISTENCY_CHECK(fParentHasLayout); - _ASSERTE(pParentLayoutInfo != NULL); // See if (fParentHasLayout) branch above - UINT numChildCTMFields = cInstanceFields; NativeFieldDescriptor const* pParentCTMFieldSrcArray = pParentLayoutInfo->GetNativeFieldDescriptors(); @@ -1054,19 +1019,14 @@ EEClassNativeLayoutInfo* EEClassNativeLayoutInfo::CollectNativeLayoutFieldMetada } } + bool isMarshalable = pParentLayoutInfo != nullptr ? pParentLayoutInfo->IsMarshalable() : true; for (UINT i = 0; i < cInstanceFields; i++) { pInfoArray[i].m_nfd.SetExternalOffset(pInfoArray[i].m_placement.m_offset); pNativeFieldDescriptors[i] = pInfoArray[i].m_nfd; - } - - bool isMarshalable = true; - for (UINT i = 0; i < numTotalInstanceFields; i++) - { if (pNativeFieldDescriptors[i].IsUnmarshalable()) { isMarshalable = false; - break; } } @@ -1083,8 +1043,8 @@ EEClassNativeLayoutInfo* EEClassNativeLayoutInfo::CollectNativeLayoutFieldMetada _ASSERTE(pNativeFieldDescriptors[i].GetExternalOffset() == pNativeFieldDescriptors[i].GetFieldDesc()->GetOffset()); _ASSERTE(pNativeFieldDescriptors[i].NativeSize() == pNativeFieldDescriptors[i].GetFieldDesc()->GetSize()); } - _ASSERTE(pNativeLayoutInfo->GetSize() == pEEClassLayoutInfo->GetManagedSize()); - _ASSERTE(pNativeLayoutInfo->GetLargestAlignmentRequirement() == pEEClassLayoutInfo->m_ManagedLargestAlignmentRequirementOfAllMembers); + _ASSERTE(pNativeLayoutInfo->GetSize() == pMT->GetNumInstanceFieldBytes()); + _ASSERTE(pNativeLayoutInfo->GetLargestAlignmentRequirement() == pEEClassLayoutInfo->GetAlignmentRequirement()); } LOG((LF_INTEROP, LL_INFO100000, "\n\n")); @@ -1092,10 +1052,10 @@ EEClassNativeLayoutInfo* EEClassNativeLayoutInfo::CollectNativeLayoutFieldMetada LOG((LF_INTEROP, LL_INFO100000, "Packsize = %lu\n", (ULONG)pEEClassLayoutInfo->GetPackingSize())); LOG((LF_INTEROP, LL_INFO100000, "Max align req = %lu\n", (ULONG)(pNativeLayoutInfo->GetLargestAlignmentRequirement()))); LOG((LF_INTEROP, LL_INFO100000, "----------------------------\n")); - for (LayoutRawFieldInfo* pfwalk = pInfoArray; pfwalk->m_MD != mdFieldDefNil; pfwalk++) + for (LayoutRawFieldInfo* pfwalk = pInfoArray; pfwalk->m_token != mdFieldDefNil; pfwalk++) { LPCUTF8 fieldname; - if (FAILED(pInternalImport->GetNameOfFieldDef(pfwalk->m_MD, &fieldname))) + if (FAILED(pInternalImport->GetNameOfFieldDef(pfwalk->m_token, &fieldname))) { fieldname = "??"; } diff --git a/src/coreclr/vm/codepitchingmanager.cpp b/src/coreclr/vm/codepitchingmanager.cpp index f3ca5cae92282b..7cedeb0d2210cb 100644 --- a/src/coreclr/vm/codepitchingmanager.cpp +++ b/src/coreclr/vm/codepitchingmanager.cpp @@ -37,6 +37,7 @@ #if defined(FEATURE_JIT_PITCHING) #include "threadsuspend.h" +#include "minipal/time.h" static PtrHashMap* s_pPitchingCandidateMethods = nullptr; static PtrHashMap* s_pPitchingCandidateSizes = nullptr; @@ -427,7 +428,7 @@ EXTERN_C void CheckStacksAndPitch() if ((CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitPitchEnabled) != 0) && (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitPitchMemThreshold) != 0) && (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitPitchTimeInterval) == 0 || - ((::GetTickCount64() - s_JitPitchLastTick) > CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitPitchTimeInterval)))) + ((minipal_lowres_ticks() - s_JitPitchLastTick) > CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitPitchTimeInterval)))) { SimpleReadLockHolder srlh(s_totalNCSizeLock); @@ -467,7 +468,7 @@ EXTERN_C void CheckStacksAndPitch() s_pPitchingCandidateSizes->Compact(); } - s_JitPitchLastTick = ::GetTickCount64(); + s_JitPitchLastTick = minipal_lowres_ticks(); ThreadSuspend::RestartEE(FALSE, TRUE); } diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index fab56cdf642685..4e99da6129b95d 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -69,8 +69,6 @@ FCFuncEnd() FCFuncStart(gEnvironmentFuncs) FCFuncElement("get_CurrentManagedThreadId", JIT_GetCurrentManagedThreadId) - FCFuncElement("get_TickCount", SystemNative::GetTickCount) - FCFuncElement("get_TickCount64", SystemNative::GetTickCount64) FCFuncElement("set_ExitCode", SystemNative::SetExitCode) FCFuncElement("get_ExitCode", SystemNative::GetExitCode) FCFuncEnd() diff --git a/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h b/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h index da68b1551cee3f..49708badca33d0 100644 --- a/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h +++ b/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h @@ -19,6 +19,7 @@ #include "hostinformation.h" #include #include +#include #undef EP_INFINITE_WAIT #define EP_INFINITE_WAIT INFINITE @@ -990,11 +991,7 @@ ep_rt_perf_counter_query (void) { STATIC_CONTRACT_NOTHROW; - LARGE_INTEGER value; - if (QueryPerformanceCounter (&value)) - return static_cast(value.QuadPart); - else - return 0; + return minipal_hires_ticks(); } static @@ -1004,11 +1001,7 @@ ep_rt_perf_frequency_query (void) { STATIC_CONTRACT_NOTHROW; - LARGE_INTEGER value; - if (QueryPerformanceFrequency (&value)) - return static_cast(value.QuadPart); - else - return 0; + return minipal_hires_tick_frequency(); } static diff --git a/src/coreclr/vm/eventpipeinternal.cpp b/src/coreclr/vm/eventpipeinternal.cpp index 1fabe8f08ef967..e981e629055530 100644 --- a/src/coreclr/vm/eventpipeinternal.cpp +++ b/src/coreclr/vm/eventpipeinternal.cpp @@ -10,6 +10,7 @@ #endif // TARGET_UNIX #include +#include #ifdef FEATURE_PERFTRACING @@ -79,7 +80,7 @@ extern "C" BOOL QCALLTYPE EventPipeInternal_GetSessionInfo(UINT64 sessionID, Eve { pSessionInfo->StartTimeAsUTCFileTime = EventPipeAdapter::GetSessionStartTime(pSession); pSessionInfo->StartTimeStamp.QuadPart = EventPipeAdapter::GetSessionStartTimestamp(pSession); - QueryPerformanceFrequency(&pSessionInfo->TimeStampFrequency); + pSessionInfo->TimeStampFrequency.QuadPart = minipal_hires_tick_frequency(); retVal = true; } } diff --git a/src/coreclr/vm/eventtrace.cpp b/src/coreclr/vm/eventtrace.cpp index 651d8b0e4e9d20..238ba6a69514c1 100644 --- a/src/coreclr/vm/eventtrace.cpp +++ b/src/coreclr/vm/eventtrace.cpp @@ -1012,7 +1012,7 @@ void ETW::TypeSystemLog::SendObjectAllocatedEvent(Object * pObject) } SIZE_T nTotalSizeForTypeSample = size; - DWORD dwTickNow = GetTickCount(); + DWORD dwTickNow = (DWORD)minipal_lowres_ticks(); DWORD dwObjectCountForTypeSample = 0; // Get stats for type diff --git a/src/coreclr/vm/fieldmarshaler.cpp b/src/coreclr/vm/fieldmarshaler.cpp index 192d27508e68c1..81b52188444982 100644 --- a/src/coreclr/vm/fieldmarshaler.cpp +++ b/src/coreclr/vm/fieldmarshaler.cpp @@ -402,7 +402,7 @@ UINT32 NativeFieldDescriptor::AlignmentRequirement() const MethodTable* pMT = GetNestedNativeMethodTable(); if (pMT->IsBlittable()) { - return pMT->GetLayoutInfo()->m_ManagedLargestAlignmentRequirementOfAllMembers; + return pMT->GetLayoutInfo()->GetAlignmentRequirement(); } return pMT->GetNativeLayoutInfo()->GetLargestAlignmentRequirement(); } diff --git a/src/coreclr/vm/fieldmarshaler.h b/src/coreclr/vm/fieldmarshaler.h index fa778f3ba2f337..568322cab21106 100644 --- a/src/coreclr/vm/fieldmarshaler.h +++ b/src/coreclr/vm/fieldmarshaler.h @@ -188,26 +188,6 @@ VOID ParseNativeType(Module* pModule, #endif ); -//======================================================================= -// The classloader stores an intermediate representation of the layout -// metadata in an array of these structures. The dual-pass nature -// is a bit extra overhead but building this structure requiring loading -// other classes (for nested structures) and I'd rather keep this -// next to the other places where we load other classes (e.g. the superclass -// and implemented interfaces.) -// -// Each redirected field gets one entry in LayoutRawFieldInfo. -// The array is terminated by one dummy record whose m_MD == mdMemberDefNil. -//======================================================================= -struct LayoutRawFieldInfo -{ - mdFieldDef m_MD; // mdMemberDefNil for end of array - ULONG m_sequence; // sequence # from metadata - RawFieldPlacementInfo m_placement; - NativeFieldDescriptor m_nfd; -}; - - class EEClassNativeLayoutInfo { private: diff --git a/src/coreclr/vm/finalizerthread.cpp b/src/coreclr/vm/finalizerthread.cpp index 21bd8e58416ba8..0403df50ec3001 100644 --- a/src/coreclr/vm/finalizerthread.cpp +++ b/src/coreclr/vm/finalizerthread.cpp @@ -17,10 +17,11 @@ BOOL FinalizerThread::fQuitFinalizer = FALSE; #if defined(__linux__) && defined(FEATURE_EVENT_TRACE) +#include "minipal/time.h" #define LINUX_HEAP_DUMP_TIME_OUT 10000 extern bool s_forcedGCInProgress; -ULONGLONG FinalizerThread::LastHeapDumpTime = 0; +int64_t FinalizerThread::LastHeapDumpTime = 0; Volatile g_TriggerHeapDump = FALSE; #endif // __linux__ @@ -271,7 +272,7 @@ VOID FinalizerThread::FinalizerThreadWorker(void *args) } #if defined(__linux__) && defined(FEATURE_EVENT_TRACE) - if (g_TriggerHeapDump && (CLRGetTickCount64() > (LastHeapDumpTime + LINUX_HEAP_DUMP_TIME_OUT))) + if (g_TriggerHeapDump && (minipal_lowres_ticks() > (LastHeapDumpTime + LINUX_HEAP_DUMP_TIME_OUT))) { s_forcedGCInProgress = true; GetFinalizerThread()->DisablePreemptiveGC(); @@ -279,7 +280,7 @@ VOID FinalizerThread::FinalizerThreadWorker(void *args) GetFinalizerThread()->EnablePreemptiveGC(); s_forcedGCInProgress = false; - LastHeapDumpTime = CLRGetTickCount64(); + LastHeapDumpTime = minipal_lowres_ticks(); g_TriggerHeapDump = FALSE; } #endif @@ -386,6 +387,7 @@ DWORD WINAPI FinalizerThread::FinalizerThreadStart(void *args) // handshake with EE initialization, as now we can attach Thread objects to native threads. hEventFinalizerDone->Set(); + WaitForFinalizerEvent (hEventFinalizer); #endif s_FinalizerThreadOK = GetFinalizerThread()->HasStarted(); diff --git a/src/coreclr/vm/finalizerthread.h b/src/coreclr/vm/finalizerthread.h index eda53d2e2d7a69..46d104853f380c 100644 --- a/src/coreclr/vm/finalizerthread.h +++ b/src/coreclr/vm/finalizerthread.h @@ -10,7 +10,7 @@ class FinalizerThread static BOOL fQuitFinalizer; #if defined(__linux__) && defined(FEATURE_EVENT_TRACE) - static ULONGLONG LastHeapDumpTime; + static int64_t LastHeapDumpTime; #endif static CLREvent *hEventFinalizer; diff --git a/src/coreclr/vm/hash.cpp b/src/coreclr/vm/hash.cpp index 80bf159f9c31b6..e06370d5bc466a 100644 --- a/src/coreclr/vm/hash.cpp +++ b/src/coreclr/vm/hash.cpp @@ -19,6 +19,7 @@ Module Name: #include "syncclean.hpp" #include "threadsuspend.h" +#include "minipal/time.h" //--------------------------------------------------------------------- // Array of primes, used by hash table to choose the number of buckets @@ -1184,7 +1185,7 @@ void HashMap::HashMapTest() LookupPerfTest(table, MinThreshold); - INT64 t0 = GetTickCount(); + INT64 t0 = minipal_lowres_ticks(); INT64 t1; for(int rep = 0; rep < 10000000; rep++) { for(unsigned int i=MinThreshold; i < MaxThreshold; i++) { @@ -1199,7 +1200,7 @@ void HashMap::HashMapTest() table->InsertValue(i, i); if (rep % 500 == 0) { - t1 = GetTickCount(); + t1 = minipal_lowres_ticks(); minipal_log_print_info("Repetition %d, took %d ms\n", rep, (int) (t1-t0)); t0 = t1; LookupPerfTest(table, MinThreshold); @@ -1212,7 +1213,7 @@ void HashMap::HashMapTest() // For testing purposes only. void HashMap::LookupPerfTest(HashMap * table, const unsigned int MinThreshold) { - INT64 t0 = GetTickCount(); + INT64 t0 = minipal_lowres_ticks(); for(int rep = 0; rep < 1000; rep++) { for(unsigned int i=2; iLookupValue(i, i); @@ -1222,7 +1223,7 @@ void HashMap::LookupPerfTest(HashMap * table, const unsigned int MinThreshold) } } } - INT64 t1 = GetTickCount(); + INT64 t1 = minipal_lowres_ticks(); for(unsigned int i = MinThreshold * 80; i < MinThreshold * 80 + 1000; i++) table->LookupValue(i, i); //cout << "Lookup perf test (1000 * " << MinThreshold << ": " << (t1-t0) << " ms." << endl; diff --git a/src/coreclr/vm/interpexec.cpp b/src/coreclr/vm/interpexec.cpp index 0bfbe460275879..15d91a4cf5398c 100644 --- a/src/coreclr/vm/interpexec.cpp +++ b/src/coreclr/vm/interpexec.cpp @@ -91,6 +91,8 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr int8_t *stack; InterpMethod *pMethod = *(InterpMethod**)pFrame->startIp; + assert(pMethod->CheckIntegrity()); + pThreadContext->pStackPointer = pFrame->pStack + pMethod->allocaSize; ip = pFrame->startIp + sizeof(InterpMethod*) / sizeof(int32_t); stack = pFrame->pStack; @@ -1172,6 +1174,7 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr // Set execution state for the new frame pMethod = *(InterpMethod**)pFrame->startIp; + assert(pMethod->CheckIntegrity()); stack = pFrame->pStack; ip = pFrame->startIp + sizeof(InterpMethod*) / sizeof(int32_t); pThreadContext->pStackPointer = stack + pMethod->allocaSize; @@ -1423,6 +1426,21 @@ do { \ STELEM(double, double); break; } + case INTOP_LDTOKEN: + { + int dreg = ip[1]; + void *nativeHandle = pMethod->pDataItems[ip[2]]; + size_t helperDirectOrIndirect = (size_t)pMethod->pDataItems[ip[3]]; + HELPER_FTN_PP helper = nullptr; + if (helperDirectOrIndirect & INTERP_INDIRECT_HELPER_TAG) + helper = *(HELPER_FTN_PP *)(helperDirectOrIndirect & ~INTERP_INDIRECT_HELPER_TAG); + else + helper = (HELPER_FTN_PP)helperDirectOrIndirect; + void *managedHandle = helper(nativeHandle); + LOCAL_VAR(dreg, void*) = managedHandle; + ip += 4; + break; + } case INTOP_FAILFAST: assert(0); break; @@ -1456,6 +1474,7 @@ do { \ stack = pFrame->pStack; pMethod = *(InterpMethod**)pFrame->startIp; + assert(pMethod->CheckIntegrity()); pThreadContext->pStackPointer = pFrame->pStack + pMethod->allocaSize; goto MAIN_LOOP; } @@ -1472,6 +1491,7 @@ do { \ ip = pFrame->ip; stack = pFrame->pStack; pMethod = *(InterpMethod**)pFrame->startIp; + assert(pMethod->CheckIntegrity()); pFrame->ip = NULL; pThreadContext->pStackPointer = pFrame->pStack + pMethod->allocaSize; diff --git a/src/coreclr/vm/jithost.cpp b/src/coreclr/vm/jithost.cpp index 03f97bf7d477a5..44b10f66c103e5 100644 --- a/src/coreclr/vm/jithost.cpp +++ b/src/coreclr/vm/jithost.cpp @@ -6,6 +6,7 @@ #include "utilcode.h" #include "corjit.h" #include "jithost.h" +#include "minipal/time.h" void* JitHost::allocateMemory(size_t size) { @@ -176,7 +177,7 @@ void JitHost::reclaim() { if (m_pCurrentCachedList != NULL || m_pPreviousCachedList != NULL) { - DWORD ticks = ::GetTickCount(); + DWORD ticks = (DWORD)minipal_lowres_ticks(); if (m_lastFlush == 0) // Just update m_lastFlush first time around { diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index d050899899b3e2..87721965aeee8e 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -1964,12 +1964,12 @@ unsigned CEEInfo::getClassAlignmentRequirementStatic(TypeHandle clsHnd) // if it's the unmanaged view of the managed type, we always use the unmanaged alignment requirement result = pMT->GetNativeLayoutInfo()->GetLargestAlignmentRequirement(); } - else if (pInfo->IsManagedSequential() || pInfo->IsBlittable()) + else if (pInfo->GetLayoutType() == EEClassLayoutInfo::LayoutType::Sequential || pInfo->IsBlittable()) { _ASSERTE(!pMT->ContainsGCPointers()); // if it's managed sequential, we use the managed alignment requirement - result = pInfo->m_ManagedLargestAlignmentRequirementOfAllMembers; + result = pInfo->GetAlignmentRequirement(); } } diff --git a/src/coreclr/vm/method.hpp b/src/coreclr/vm/method.hpp index 5bf221d2498cdd..4875cd4ee17d1e 100644 --- a/src/coreclr/vm/method.hpp +++ b/src/coreclr/vm/method.hpp @@ -30,7 +30,6 @@ class FCallMethodDesc; class FieldDesc; class NDirect; class MethodDescChunk; -struct LayoutRawFieldInfo; class InstantiatedMethodDesc; class DictionaryLayout; class Dictionary; diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 422b4a95a19fa7..e04484a74274e6 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -8605,7 +8605,7 @@ int MethodTable::GetFieldAlignmentRequirement() { if (HasLayout()) { - return GetLayoutInfo()->m_ManagedLargestAlignmentRequirementOfAllMembers; + return GetLayoutInfo()->GetAlignmentRequirement(); } else if (GetClass()->HasCustomFieldAlignment()) { @@ -8629,7 +8629,7 @@ UINT32 MethodTable::GetNativeSize() CONTRACTL_END; if (IsBlittable()) { - return GetClass()->GetLayoutInfo()->GetManagedSize(); + return GetNumInstanceFieldBytes(); } return GetNativeLayoutInfo()->GetSize(); } diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index 78009bcf95dd23..5dd3f85bdd5920 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -40,7 +40,6 @@ class EEClass; class EnCFieldDesc; class FieldDesc; class JIT_TrialAlloc; -struct LayoutRawFieldInfo; class MetaSig; class MethodDesc; class MethodDescChunk; diff --git a/src/coreclr/vm/methodtablebuilder.cpp b/src/coreclr/vm/methodtablebuilder.cpp index 3d7e5478d08dad..44797143737284 100644 --- a/src/coreclr/vm/methodtablebuilder.cpp +++ b/src/coreclr/vm/methodtablebuilder.cpp @@ -736,7 +736,8 @@ void MethodTableBuilder::SetBMTData( bmtGCSeriesInfo *bmtGCSeries, bmtMethodImplInfo *bmtMethodImpl, const bmtGenericsInfo *bmtGenerics, - bmtEnumFieldInfo *bmtEnumFields) + bmtEnumFieldInfo *bmtEnumFields, + bmtLayoutInfo *bmtFieldLayout) { LIMITED_METHOD_CONTRACT; this->bmtAllocator = bmtAllocator; @@ -754,6 +755,7 @@ void MethodTableBuilder::SetBMTData( this->bmtMethodImpl = bmtMethodImpl; this->bmtGenerics = bmtGenerics; this->bmtEnumFields = bmtEnumFields; + this->bmtLayout = bmtFieldLayout; } //******************************************************************************* @@ -1165,7 +1167,6 @@ MethodTableBuilder::CopyParentVtable() // support. // If so: // - Update the NumInstanceFieldBytes on the bmtFieldPlacement. -// - Update the m_cbNativeSize and m_cbManagedSize if HasLayout() is true. // Return a BOOL result to indicate whether the size has been updated. // BOOL MethodTableBuilder::CheckIfSIMDAndUpdateSize() @@ -1203,12 +1204,6 @@ BOOL MethodTableBuilder::CheckIfSIMDAndUpdateSize() if (numInstanceFieldBytes != 16) { bmtFP->NumInstanceFieldBytes = numInstanceFieldBytes; - - if (HasLayout()) - { - GetLayoutInfo()->m_cbManagedSize = numInstanceFieldBytes; - } - return true; } #endif // TARGET_X86 || TARGET_AMD64 @@ -1282,7 +1277,7 @@ MethodTableBuilder::BuildMethodTableThrowing( Module * pModule, mdToken cl, BuildingInterfaceInfo_t * pBuildingInterfaceList, - const LayoutRawFieldInfo * pLayoutRawFieldInfos, + const bmtLayoutInfo * initialLayoutInfo, MethodTable * pParentMethodTable, const bmtGenericsInfo * bmtGenericsInfo, SigPointer parentInst, @@ -1315,7 +1310,8 @@ MethodTableBuilder::BuildMethodTableThrowing( new (GetStackingAllocator()) bmtGCSeriesInfo(), new (GetStackingAllocator()) bmtMethodImplInfo(), bmtGenericsInfo, - new (GetStackingAllocator()) bmtEnumFieldInfo(pModule->GetMDImport())); + new (GetStackingAllocator()) bmtEnumFieldInfo(pModule->GetMDImport()), + new (GetStackingAllocator()) bmtLayoutInfo(*initialLayoutInfo)); //Initialize structs @@ -1738,7 +1734,7 @@ MethodTableBuilder::BuildMethodTableThrowing( MethodTable ** pByValueClassCache = NULL; // Go thru all fields and initialize their FieldDescs. - InitializeFieldDescs(GetApproxFieldDescListRaw(), pLayoutRawFieldInfos, bmtInternal, bmtGenerics, + InitializeFieldDescs(GetApproxFieldDescListRaw(), bmtInternal, bmtGenerics, bmtMetaData, bmtEnumFields, bmtError, &pByValueClassCache, bmtMFDescs, bmtFP, &totalDeclaredFieldSize); @@ -1791,55 +1787,7 @@ MethodTableBuilder::BuildMethodTableThrowing( GetNumStaticFields(), GetNumHandleRegularStatics() + GetNumHandleThreadStatics(), pszDebugName)); - if (IsBlittable() || IsManagedSequential()) - { - bmtFP->NumGCPointerSeries = 0; - bmtFP->NumInstanceGCPointerFields = 0; - - _ASSERTE(HasLayout()); - - if (bmtFP->NumInlineArrayElements != 0) - { - INT64 extendedSize = (INT64)GetLayoutInfo()->m_cbManagedSize * (INT64)bmtFP->NumInlineArrayElements; - if (extendedSize > FIELD_OFFSET_LAST_REAL_OFFSET) - { - BuildMethodTableThrowException(IDS_CLASSLOAD_FIELDTOOLARGE); - } - - GetLayoutInfo()->m_cbManagedSize = (UINT32)extendedSize; - } - - bmtFP->NumInstanceFieldBytes = GetLayoutInfo()->m_cbManagedSize; - - // For simple Blittable types we still need to check if they have any overlapping - // fields and call the method SetHasOverlaidFields() when they are detected. - // - if (HasExplicitFieldOffsetLayout()) - { - _ASSERTE(!bmtGenerics->fContainsGenericVariables); // A simple Blittable type can't ever be an open generic type. - HandleExplicitLayout(pByValueClassCache); - } - } - else - { - _ASSERTE(!IsBlittable()); - // HandleExplicitLayout fails for the GenericTypeDefinition when - // it will succeed for some particular instantiations. - // Thus we only do explicit layout for real instantiations, e.g. C, not - // the open types such as the GenericTypeDefinition C or any - // of the "fake" types involving generic type variables which are - // used for reflection and verification, e.g. C>. - // - if (!bmtGenerics->fContainsGenericVariables && HasExplicitFieldOffsetLayout()) - { - HandleExplicitLayout(pByValueClassCache); - } - else - { - // Place instance fields - PlaceInstanceFields(pByValueClassCache); - } - } + PlaceInstanceFields(pByValueClassCache); if (IsValueClass()) { @@ -3583,6 +3531,14 @@ MethodTableBuilder::EnumerateClassFields() BuildMethodTableThrowException(hr, *bmtError); } + // Variant delegates should not have any instance fields of the variant. + // type parameter. For now, we just completely disallow all fields even + // if they are non-variant or static, as it is not a useful scenario. + if ((hEnumField.EnumGetCount() != 0) && IsDelegate() && (bmtGenerics->pVarianceInfo != NULL)) + { + BuildMethodTableThrowException(IDS_CLASSLOAD_VARIANCE_IN_DELEGATE); + } + bmtMetaData->cFields = hEnumField.EnumGetCount(); // Retrieve the fields and store them in a temp array. @@ -3862,19 +3818,6 @@ VOID MethodTableBuilder::AllocateFieldDescs() } } -#ifdef FEATURE_DOUBLE_ALIGNMENT_HINT -//******************************************************************************* -// -// Heuristic to determine if we should have instances of this class 8 byte aligned -// -BOOL MethodTableBuilder::ShouldAlign8(DWORD dwR8Fields, DWORD dwTotalFields) -{ - LIMITED_METHOD_CONTRACT; - - return dwR8Fields*2>dwTotalFields && dwR8Fields>=2; -} -#endif - //******************************************************************************* BOOL MethodTableBuilder::IsSelfReferencingStaticValueTypeField(mdToken dwByValueClassToken, bmtInternalInfo* bmtInternal, @@ -3940,7 +3883,6 @@ static BOOL IsSelfRef(MethodTable * pMT) // Go thru all fields and initialize their FieldDescs. // VOID MethodTableBuilder::InitializeFieldDescs(FieldDesc *pFieldDescList, - const LayoutRawFieldInfo* pLayoutRawFieldInfos, bmtInternalInfo* bmtInternal, const bmtGenericsInfo* bmtGenerics, bmtMetaDataInfo* bmtMetaData, @@ -3979,13 +3921,6 @@ VOID MethodTableBuilder::InitializeFieldDescs(FieldDesc *pFieldDescList, DWORD dwCurrentStaticField = 0; DWORD dwCurrentThreadStaticField = 0; - - DWORD dwR8Fields = 0; // Number of R8's the class has - -#ifdef FEATURE_64BIT_ALIGNMENT - // Track whether any field in this type requires 8-byte alignment - BOOL fFieldRequiresAlign8 = HasParent() ? GetParentMethodTable()->RequiresAlign8() : FALSE; -#endif #if defined(FEATURE_METADATA_UPDATER) bool isEnCField = pFieldDescList != NULL && pFieldDescList->IsEnCNew(); #else @@ -4126,23 +4061,11 @@ VOID MethodTableBuilder::InitializeFieldDescs(FieldDesc *pFieldDescList, } case ELEMENT_TYPE_R8: - { - dwR8Fields++; - - // Deliberate fall through... - FALLTHROUGH; - } - case ELEMENT_TYPE_I8: case ELEMENT_TYPE_U8: IN_TARGET_64BIT(case ELEMENT_TYPE_I:) IN_TARGET_64BIT(case ELEMENT_TYPE_U:) { -#ifdef FEATURE_64BIT_ALIGNMENT - // Record that this field requires alignment for Int64/UInt64. - if(!fIsStatic) - fFieldRequiresAlign8 = true; -#endif dwLog2FieldSize = 3; break; } @@ -4371,12 +4294,6 @@ VOID MethodTableBuilder::InitializeFieldDescs(FieldDesc *pFieldDescList, // Inherit instance attributes EEClass * pFieldClass = pByValueClass->GetClass(); -#ifdef FEATURE_64BIT_ALIGNMENT - // If a value type requires 8-byte alignment this requirement must be inherited by any - // class/struct that embeds it as a field. - if (pFieldClass->IsAlign8Candidate()) - fFieldRequiresAlign8 = true; -#endif if (pFieldClass->HasNonPublicFields()) SetHasNonPublicFields(); if (pFieldClass->HasFieldsWhichMustBeInited()) @@ -4454,22 +4371,6 @@ VOID MethodTableBuilder::InitializeFieldDescs(FieldDesc *pFieldDescList, bmtMFDescs->ppFieldDescList[i] = pFD; - const LayoutRawFieldInfo *pLayoutFieldInfo = NULL; - - if (HasLayout()) - { - const LayoutRawFieldInfo *pwalk = pLayoutRawFieldInfos; - while (pwalk->m_MD != mdFieldDefNil) - { - if (pwalk->m_MD == bmtMetaData->pFields[i]) - { - pLayoutFieldInfo = pwalk; - break; - } - pwalk++; - } - } - LPCSTR pszFieldName = NULL; #ifdef _DEBUG if (FAILED(pInternalImport->GetNameOfFieldDef(bmtMetaData->pFields[i], &pszFieldName))) @@ -4492,31 +4393,12 @@ VOID MethodTableBuilder::InitializeFieldDescs(FieldDesc *pFieldDescList, // if (fIsByValue) { - if (!fIsStatic && - (IsBlittable() || HasExplicitFieldOffsetLayout())) - { - (DWORD_PTR &)pFD->m_pMTOfEnclosingClass = - (*pByValueClassCache)[dwCurrentDeclaredField]->GetNumInstanceFieldBytes(); - - if (pLayoutFieldInfo) - IfFailThrow(pFD->SetOffset(pLayoutFieldInfo->m_placement.m_offset)); - else - pFD->SetOffset(FIELD_OFFSET_VALUE_CLASS); - } - else if (!fIsStatic && IsManagedSequential()) - { - (DWORD_PTR &)pFD->m_pMTOfEnclosingClass = - (*pByValueClassCache)[dwCurrentDeclaredField]->GetNumInstanceFieldBytes(); - - IfFailThrow(pFD->SetOffset(pLayoutFieldInfo->m_placement.m_offset)); - } - else - { - // static value class fields hold a handle, which is ptr sized - // (instance field layout ignores this value) - (DWORD_PTR&)(pFD->m_pMTOfEnclosingClass) = LOG2_PTRSIZE; - pFD->SetOffset(FIELD_OFFSET_VALUE_CLASS); - } + pFD->SetOffset(FIELD_OFFSET_VALUE_CLASS); + DWORD_PTR& fieldSizeStorage = (DWORD_PTR&)(pFD->m_pMTOfEnclosingClass); + // static value class fields hold a handle, which is ptr sized + fieldSizeStorage = fIsStatic + ? LOG2_PTRSIZE + : (*pByValueClassCache)[dwCurrentDeclaredField]->GetNumInstanceFieldBytes(); } else { @@ -4525,14 +4407,7 @@ VOID MethodTableBuilder::InitializeFieldDescs(FieldDesc *pFieldDescList, // -1 (FIELD_OFFSET_UNPLACED) means that this is a non-GC field that has not yet been placed // -2 (FIELD_OFFSET_UNPLACED_GC_PTR) means that this is a GC pointer field that has not yet been placed - // If there is any kind of explicit layout information for this field, use it. If not, then - // mark it as either GC or non-GC and as unplaced; it will get placed later on in an optimized way. - - if ((IsBlittable() || HasExplicitFieldOffsetLayout()) && !fIsStatic) - IfFailThrow(pFD->SetOffset(pLayoutFieldInfo->m_placement.m_offset)); - else if (IsManagedSequential() && !fIsStatic) - IfFailThrow(pFD->SetOffset(pLayoutFieldInfo->m_placement.m_offset)); - else if (bCurrentFieldIsObjectRef) + if (bCurrentFieldIsObjectRef) pFD->SetOffset(FIELD_OFFSET_UNPLACED_GC_PTR); else pFD->SetOffset(FIELD_OFFSET_UNPLACED); @@ -4674,31 +4549,6 @@ VOID MethodTableBuilder::InitializeFieldDescs(FieldDesc *pFieldDescList, GetHalfBakedClass()->SetHasFixedAddressVTStatics(); } -#ifdef FEATURE_64BIT_ALIGNMENT - // For types with layout we drop any 64-bit alignment requirement if the packing size was less than 8 - // bytes (this mimics what the native compiler does and ensures we match up calling conventions during - // interop). - // We don't do this for types that are marked as sequential but end up with auto-layout due to containing pointers, - // as auto-layout ignores any Pack directives. - if (HasLayout() && (HasExplicitFieldOffsetLayout() || IsManagedSequential()) && GetLayoutInfo()->GetPackingSize() < 8) - { - fFieldRequiresAlign8 = false; - } - - if (fFieldRequiresAlign8) - { - SetAlign8Candidate(); - } -#endif // FEATURE_64BIT_ALIGNMENT - -#ifdef FEATURE_DOUBLE_ALIGNMENT_HINT - if (ShouldAlign8(dwR8Fields, dwNumInstanceFields)) - { - SetAlign8Candidate(); - } -#endif // FEATURE_DOUBLE_ALIGNMENT_HINT - - //======================================================================== // END: // Go thru all fields and initialize their FieldDescs. @@ -8287,7 +8137,148 @@ VOID MethodTableBuilder::PlaceThreadStaticFields() // // Place instance fields // -VOID MethodTableBuilder::PlaceInstanceFields(MethodTable ** pByValueClassCache) +VOID MethodTableBuilder::PlaceInstanceFields(MethodTable** pByValueClassCache) +{ + MethodTable* pParentMT = GetParentMethodTable(); + bool hasNonTrivialParent = pParentMT && !pParentMT->IsObjectClass() && !pParentMT->IsValueTypeClass(); + + if (bmtLayout->layoutType == EEClassLayoutInfo::LayoutType::Auto) + { + // Auto layout has been requested. + // We never switch away from auto layout, so just go use it right away. + +#if defined(FEATURE_64BIT_ALIGNMENT) || defined(FEATURE_DOUBLE_ALIGNMENT_HINT) + // Check for 8-byte alignment requirements for this type. + // We don't need to check any of the other nested field flags + // for auto layout, so only check this flag when targeting + // a platform that can have the align8 requirement for a type. + EEClassLayoutInfo::NestedFieldFlags nestedFieldFlags = + EEClassLayoutInfo::GetNestedFieldFlags( + GetModule(), + GetHalfBakedClass()->GetFieldDescList(), + bmtEnumFields->dwNumDeclaredFields, + bmtLayout->nlFlags, + pByValueClassCache); + + bool isAlign8 = ((nestedFieldFlags & EEClassLayoutInfo::NestedFieldFlags::Align8) == EEClassLayoutInfo::NestedFieldFlags::Align8) +#if defined(FEATURE_64BIT_ALIGNMENT) + || (pParentMT && pParentMT->RequiresAlign8()) +#endif // FEATURE_64BIT_ALIGNMENT + ; + + if (isAlign8) + { + GetHalfBakedClass()->SetAlign8Candidate(); + } +#endif // FEATURE_64BIT_ALIGNMENT || FEATURE_DOUBLE_ALIGNMENT_HINT + + HandleAutoLayout(pByValueClassCache); + return; + } + + // We are not using auto layout, so we need to check all of the nested field flags. + // All other layouts need to consider these flags. + EEClassLayoutInfo::NestedFieldFlags nestedFieldFlags = + EEClassLayoutInfo::GetNestedFieldFlags( + GetModule(), + GetHalfBakedClass()->GetFieldDescList(), + bmtEnumFields->dwNumDeclaredFields, + bmtLayout->nlFlags, + pByValueClassCache); + + bool hasGCFields = (pParentMT && pParentMT->ContainsGCPointers()) + || ((nestedFieldFlags & EEClassLayoutInfo::NestedFieldFlags::GCPointer) == EEClassLayoutInfo::NestedFieldFlags::GCPointer); + + bool isBlittable = ((nestedFieldFlags & EEClassLayoutInfo::NestedFieldFlags::NonBlittable) != EEClassLayoutInfo::NestedFieldFlags::NonBlittable); + if (hasNonTrivialParent) + { + isBlittable &= pParentMT->IsBlittable() == TRUE; + } + + bool isAutoLayoutOrHasAutoLayoutField = ((nestedFieldFlags & EEClassLayoutInfo::NestedFieldFlags::AutoLayout) == EEClassLayoutInfo::NestedFieldFlags::AutoLayout); + if (hasNonTrivialParent) + { + isAutoLayoutOrHasAutoLayoutField &= pParentMT->IsAutoLayoutOrHasAutoLayoutField() == TRUE; + } + + bool hasInt128Field = (pParentMT && pParentMT->IsInt128OrHasInt128Fields()) + || ((nestedFieldFlags & EEClassLayoutInfo::NestedFieldFlags::Int128) == EEClassLayoutInfo::NestedFieldFlags::Int128); + + bool isAlign8 = ((nestedFieldFlags & EEClassLayoutInfo::NestedFieldFlags::Align8) == EEClassLayoutInfo::NestedFieldFlags::Align8) +#if defined(FEATURE_64BIT_ALIGNMENT) + || (pParentMT && pParentMT->RequiresAlign8()) +#endif // FEATURE_64BIT_ALIGNMENT + ; + + _ASSERTE(HasLayout()); + + EEClassLayoutInfo* pLayoutInfo = GetLayoutInfo(); + pLayoutInfo->SetIsBlittable(isBlittable ? TRUE : FALSE); + pLayoutInfo->SetHasAutoLayoutField(isAutoLayoutOrHasAutoLayoutField ? TRUE : FALSE); + pLayoutInfo->SetIsInt128OrHasInt128Fields(hasInt128Field ? TRUE : FALSE); + pLayoutInfo->SetHasExplicitSize(bmtLayout->classSize); + + if (bmtLayout->layoutType == EEClassLayoutInfo::LayoutType::Sequential) + { + if (hasNonTrivialParent && !pParentMT->IsManagedSequential()) + { + // If the parent type is not Object, ValueType or Sequential, then we need to use Auto layout. + bmtLayout->layoutType = EEClassLayoutInfo::LayoutType::Auto; + } + + if (hasGCFields) + { + // If this type has GC fields, we will use Auto layout instead of Sequential layout. + bmtLayout->layoutType = EEClassLayoutInfo::LayoutType::Auto; + } + } + + if (bmtLayout->layoutType == EEClassLayoutInfo::LayoutType::Auto) + { + if (isAlign8) + { + GetHalfBakedClass()->SetAlign8Candidate(); + } + HandleAutoLayout(pByValueClassCache); + return; + } + + // For types with layout we drop any 64-bit alignment requirement if the packing size was less than 8 + // bytes (this mimics what the native compiler does and ensures we match up calling conventions during + // interop). + // We don't do this for types that are marked as sequential but end up with auto-layout due to containing pointers, + // as auto-layout ignores any Pack directives. + if (bmtLayout->packingSize < 8) + { + isAlign8 = false; + } + + if (isAlign8) + { + GetHalfBakedClass()->SetAlign8Candidate(); + } + + if (!hasGCFields) + { + bmtFP->NumGCPointerSeries = 0; + bmtFP->NumInstanceGCPointerFields = 0; + } + + switch (bmtLayout->layoutType) + { + case EEClassLayoutInfo::LayoutType::Sequential: + HandleSequentialLayout(pByValueClassCache); + break; + case EEClassLayoutInfo::LayoutType::Explicit: + HandleExplicitLayout(pByValueClassCache); + break; + default: + UNREACHABLE(); + break; + } +} + +VOID MethodTableBuilder::HandleAutoLayout(MethodTable ** pByValueClassCache) { STANDARD_VM_CONTRACT; @@ -8392,7 +8383,7 @@ VOID MethodTableBuilder::PlaceInstanceFields(MethodTable ** pByValueClassCach break; // TODO: since we will refuse to place GC references we should filter them out here. // otherwise the "back-filling" process stops completely. - // (PlaceInstanceFields) + // (HandleAutoLayout) // the following code would fix the issue (a replacement for the code above this comment): // if (bmtFP->NumInstanceFieldsOfSize[j] != 0 && // (j != LOG2SLOT || bmtFP->NumInstanceFieldsOfSize[j] > bmtFP->NumInstanceGCPointerFields)) @@ -8665,6 +8656,85 @@ VOID MethodTableBuilder::PlaceInstanceFields(MethodTable ** pByValueClassCach //=============================================================== } +VOID MethodTableBuilder::HandleSequentialLayout(MethodTable** pByValueClassCache) +{ + STANDARD_VM_CONTRACT; + + _ASSERTE(HasLayout()); + + EEClassLayoutInfo* pLayoutInfo = GetLayoutInfo(); + + CONSISTENCY_CHECK(pLayoutInfo != nullptr); + + bmtFP->NumInstanceFieldBytes = pLayoutInfo->InitializeSequentialFieldLayout( + GetHalfBakedClass()->GetFieldDescList(), + pByValueClassCache, + bmtEnumFields->dwNumDeclaredFields, + bmtLayout->packingSize, + bmtLayout->classSize, + GetParentMethodTable() + ); + + // Handle InlineArray element layout + if (bmtFP->NumInlineArrayElements != 0) + { + INT64 extendedSize = (INT64)bmtFP->NumInstanceFieldBytes * (INT64)bmtFP->NumInlineArrayElements; + if (extendedSize > FIELD_OFFSET_LAST_REAL_OFFSET) + { + BuildMethodTableThrowException(IDS_CLASSLOAD_FIELDTOOLARGE); + } + bmtFP->NumInstanceFieldBytes = (DWORD)extendedSize; + } +} + +VOID MethodTableBuilder::HandleExplicitLayout(MethodTable** pByValueClassCache) +{ + STANDARD_VM_CONTRACT; + + _ASSERTE(HasLayout()); + + EEClassLayoutInfo* pLayoutInfo = GetLayoutInfo(); + + CONSISTENCY_CHECK(pLayoutInfo != nullptr); + + bmtFP->NumInstanceFieldBytes = pLayoutInfo->InitializeExplicitFieldLayout( + GetHalfBakedClass()->GetFieldDescList(), + pByValueClassCache, + bmtEnumFields->dwNumDeclaredFields, + bmtLayout->packingSize, + bmtLayout->classSize, + GetParentMethodTable(), + GetModule(), + GetCl() + ); + + // Handle InlineArray element layout + if (bmtFP->NumInlineArrayElements != 0) + { + INT64 extendedSize = (INT64)bmtFP->NumInstanceFieldBytes * (INT64)bmtFP->NumInlineArrayElements; + if (extendedSize > FIELD_OFFSET_LAST_REAL_OFFSET) + { + BuildMethodTableThrowException(IDS_CLASSLOAD_FIELDTOOLARGE); + } + bmtFP->NumInstanceFieldBytes = (DWORD)extendedSize; + } + + // ValidateExplicitLayout fails for the GenericTypeDefinition when + // it will succeed for some particular instantiations. + // Thus we only do explicit layout for real instantiations, e.g. C, not + // the open types such as the GenericTypeDefinition C or any + // of the "fake" types involving generic type variables which are + // used for reflection and verification, e.g. C>. + // + if (!bmtGenerics->fContainsGenericVariables) + { + // For simple Blittable types we still need to check if they have any overlapping + // fields and call the method SetHasOverlaidFields() when they are detected, + // so we do this for Explicit layout whether or not there's any GC fields. + ValidateExplicitLayout(pByValueClassCache); + } +} + //******************************************************************************* // this accesses the field size which is temporarily stored in m_pMTOfEnclosingClass // during class loading. Don't use any other time @@ -8751,7 +8821,7 @@ void MethodTableBuilder::StoreEightByteClassification(SystemVStructRegisterPassi // for object ref fields so we don't need to try to align it // VOID -MethodTableBuilder::HandleExplicitLayout( +MethodTableBuilder::ValidateExplicitLayout( MethodTable ** pByValueClassCache) { STANDARD_VM_CONTRACT; @@ -9029,7 +9099,7 @@ MethodTableBuilder::HandleExplicitLayout( else { // align up to the alignment requirements of the members of this value type. - numInstanceFieldBytes.AlignUp(GetLayoutInfo()->m_ManagedLargestAlignmentRequirementOfAllMembers); + numInstanceFieldBytes.AlignUp(GetLayoutInfo()->GetAlignmentRequirement()); if (numInstanceFieldBytes.IsOverflow()) { // addition overflow or cast truncation @@ -9073,7 +9143,7 @@ MethodTableBuilder::HandleExplicitLayout( BuildMethodTableThrowException(hr, *bmtError); } } -} // MethodTableBuilder::HandleExplicitLayout +} // MethodTableBuilder::ValidateExplicitLayout //******************************************************************************* // make sure that no object fields are overlapped incorrectly, returns the trust level @@ -10222,16 +10292,16 @@ void MethodTableBuilder::CheckForSystemTypes() // The System V ABI for i386 defaults to 8-byte alignment for __m64, except for parameter passing, // where it has an alignment of 4. - pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 8; // sizeof(__m64) + pLayout->SetAlignmentRequirement(8); // sizeof(__m64) } else if (strcmp(name, g_Vector128Name) == 0) { #ifdef TARGET_ARM // The Procedure Call Standard for ARM defaults to 8-byte alignment for __m128 - pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 8; + pLayout->SetAlignmentRequirement(8); #else - pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 16; // sizeof(__m128) + pLayout->SetAlignmentRequirement(16); // sizeof(__m128) #endif // TARGET_ARM } else if (strcmp(name, g_Vector256Name) == 0) @@ -10240,22 +10310,22 @@ void MethodTableBuilder::CheckForSystemTypes() // No such type exists for the Procedure Call Standard for ARM. We will default // to the same alignment as __m128, which is supported by the ABI. - pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 8; + pLayout->SetAlignmentRequirement(8); #elif defined(TARGET_ARM64) // The Procedure Call Standard for ARM 64-bit (with SVE support) defaults to // 16-byte alignment for __m256. - pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 16; + pLayout->SetAlignmentRequirement(16); #elif defined(TARGET_LOONGARCH64) // TODO-LoongArch64: Update alignment to proper value when implement LoongArch64 intrinsic. - pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 16; + pLayout->SetAlignmentRequirement(16); #elif defined(TARGET_RISCV64) // TODO-RISCV64: Update alignment to proper value when we implement RISC-V intrinsic. // RISC-V Vector Extenstion Intrinsic Document // https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/vector_type_infos.adoc - pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 16; + pLayout->SetAlignmentRequirement(16); #else - pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 32; // sizeof(__m256) + pLayout->SetAlignmentRequirement(32); // sizeof(__m256) #endif // TARGET_ARM elif TARGET_ARM64 } else if (strcmp(name, g_Vector512Name) == 0) @@ -10264,23 +10334,23 @@ void MethodTableBuilder::CheckForSystemTypes() // No such type exists for the Procedure Call Standard for ARM. We will default // to the same alignment as __m128, which is supported by the ABI. - pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 8; + pLayout->SetAlignmentRequirement(8); #elif defined(TARGET_ARM64) // The Procedure Call Standard for ARM 64-bit (with SVE support) defaults to // 16-byte alignment for __m256. - pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 16; + pLayout->SetAlignmentRequirement(16); #elif defined(TARGET_LOONGARCH64) // TODO-LoongArch64: Update alignment to proper value when implement LoongArch64 intrinsic. - pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 16; + pLayout->SetAlignmentRequirement(16); #elif defined(TARGET_RISCV64) // TODO-RISCV64: Update alignment to proper value when we implement RISC-V intrinsic. // RISC-V Vector Extenstion Intrinsic Document // https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/vector_type_infos.adoc - pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 16; + pLayout->SetAlignmentRequirement(16); #else - pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 64; // sizeof(__m512) + pLayout->SetAlignmentRequirement(64); // sizeof(__m512) #endif // TARGET_ARM elif TARGET_ARM64 } else @@ -10361,7 +10431,7 @@ void MethodTableBuilder::CheckForSystemTypes() case ELEMENT_TYPE_R8: { EEClassLayoutInfo * pLayout = pClass->GetLayoutInfo(); - pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 4; + pLayout->SetAlignmentRequirement(4); break; } @@ -10402,7 +10472,7 @@ void MethodTableBuilder::CheckForSystemTypes() // No such type exists for the Procedure Call Standard for ARM. We will default // to the same alignment as __m128, which is supported by the ABI. - pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 8; + pLayout->SetAlignmentRequirement(8); #elif defined(TARGET_64BIT) || defined(TARGET_X86) // These types correspond to fundamental data types in the underlying ABIs: @@ -10413,9 +10483,9 @@ void MethodTableBuilder::CheckForSystemTypes() // On Windows, no standard for Int128 has been established yet, // although applying 16 byte alignment is consistent with treatment of 128 bit SSE types // even on X86 - pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 16; // sizeof(__int128) + pLayout->SetAlignmentRequirement(16); // sizeof(__int128) #elif defined(TARGET_WASM) - pLayout->m_ManagedLargestAlignmentRequirementOfAllMembers = 16; // sizeof(v128) + pLayout->SetAlignmentRequirement(16); // sizeof(v128) #else #error Unknown architecture #endif // TARGET_64BIT @@ -12341,7 +12411,7 @@ MethodTableBuilder::GatherGenericsInfo( // *pPackingSize declared packing size // *pfExplicitoffsets offsets explicit in metadata or computed? //======================================================================= -BOOL HasLayoutMetadata(Assembly* pAssembly, IMDInternalImport* pInternalImport, mdTypeDef cl, MethodTable* pParentMT, BYTE* pPackingSize, BYTE* pNLTType, BOOL* pfExplicitOffsets) +BOOL HasLayoutMetadata(Assembly* pAssembly, IMDInternalImport* pInternalImport, mdTypeDef cl, MethodTable* pParentMT, BYTE* pPackingSize, ULONG* pClassSize, CorNativeLinkType* pNLTType, BOOL* pfExplicitOffsets) { CONTRACTL { @@ -12350,6 +12420,7 @@ BOOL HasLayoutMetadata(Assembly* pAssembly, IMDInternalImport* pInternalImport, MODE_ANY; PRECONDITION(CheckPointer(pInternalImport)); PRECONDITION(CheckPointer(pPackingSize)); + PRECONDITION(CheckPointer(pClassSize)); PRECONDITION(CheckPointer(pNLTType)); PRECONDITION(CheckPointer(pfExplicitOffsets)); } @@ -12417,6 +12488,11 @@ BOOL HasLayoutMetadata(Assembly* pAssembly, IMDInternalImport* pInternalImport, pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT); } + if (FAILED(pInternalImport->GetClassTotalSize(cl, pClassSize))) + { + *pClassSize = 0; + } + *pPackingSize = (BYTE)dwPackSize; return TRUE; @@ -12453,7 +12529,6 @@ ClassLoader::CreateTypeHandleForTypeDefThrowing( DWORD cInterfaces; BuildingInterfaceInfo_t * pInterfaceBuildInfo = NULL; IMDInternalImport * pInternalImport = NULL; - LayoutRawFieldInfo * pLayoutRawFieldInfos = NULL; MethodTableBuilder::bmtGenericsInfo genericsInfo; Assembly * pAssembly = pModule->GetAssembly(); @@ -12516,8 +12591,8 @@ ClassLoader::CreateTypeHandleForTypeDefThrowing( GetEnclosingClassThrowing(pInternalImport, pModule, cl, &tdEnclosing); - BYTE nstructPackingSize = 0, nstructNLT = 0; BOOL fExplicitOffsets = FALSE; + MethodTableBuilder::bmtLayoutInfo layoutInfo; // NOTE: HasLayoutMetadata does not load classes BOOL fHasLayout = !genericsInfo.fContainsGenericVariables && @@ -12526,10 +12601,22 @@ ClassLoader::CreateTypeHandleForTypeDefThrowing( pInternalImport, cl, pParentMethodTable, - &nstructPackingSize, - &nstructNLT, + &layoutInfo.packingSize, + &layoutInfo.classSize, + &layoutInfo.nlFlags, &fExplicitOffsets); + if (fHasLayout) + { + layoutInfo.layoutType = fExplicitOffsets + ? EEClassLayoutInfo::LayoutType::Explicit + : EEClassLayoutInfo::LayoutType::Sequential; + } + else + { + layoutInfo.layoutType = EEClassLayoutInfo::LayoutType::Auto; + } + BOOL fIsEnum = ((g_pEnumClass != NULL) && (pParentMethodTable == g_pEnumClass)); // enums may not have layout because they derive from g_pEnumClass and that has no layout @@ -12680,64 +12767,22 @@ ClassLoader::CreateTypeHandleForTypeDefThrowing( _ASSERTE(i == cInterfaces); } - if (fHasLayout || - /* Variant delegates should not have any instance fields of the variant. - type parameter. For now, we just completely disallow all fields even - if they are non-variant or static, as it is not a useful scenario. - @TODO: A more logical place for this check would be in - MethodTableBuilder::EnumerateClassMembers() */ - (fIsDelegate && genericsInfo.pVarianceInfo)) + if (fHasLayout) { - // check for fields and variance ULONG cFields; HENUMInternalHolder hEnumField(pInternalImport); hEnumField.EnumInit(mdtFieldDef, cl); cFields = pInternalImport->EnumGetCount(&hEnumField); - - if ((cFields != 0) && fIsDelegate && (genericsInfo.pVarianceInfo != NULL)) + // Though we fail on this condition, we should never run into it. + CONSISTENCY_CHECK(layoutInfo.packingSize != 0); + // MD Val check: PackingSize + if((layoutInfo.packingSize == 0) || + (layoutInfo.packingSize > 128) || + (layoutInfo.packingSize & (layoutInfo.packingSize-1))) { - pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_VARIANCE_IN_DELEGATE); - } - - if (fHasLayout) - { - // Though we fail on this condition, we should never run into it. - CONSISTENCY_CHECK(nstructPackingSize != 0); - // MD Val check: PackingSize - if((nstructPackingSize == 0) || - (nstructPackingSize > 128) || - (nstructPackingSize & (nstructPackingSize-1))) - { - THROW_BAD_FORMAT_MAYBE(!"ClassLayout:Invalid PackingSize", BFA_BAD_PACKING_SIZE, pModule); - pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT); - } - - pLayoutRawFieldInfos = (LayoutRawFieldInfo *)pStackingAllocator->Alloc( - (S_UINT32(1) + S_UINT32(cFields)) * S_UINT32(sizeof(LayoutRawFieldInfo))); - - { - // Warning: this can load classes - CONTRACT_VIOLATION(LoadsTypeViolation); - - // Set a flag that allows us to break dead-locks that are result of the LoadsTypeViolation - ThreadStateNCStackHolder tsNC(TRUE, Thread::TSNC_LoadsTypeViolation); - - EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing( - cl, - nstructPackingSize, - nstructNLT, - fExplicitOffsets, - pParentMethodTable, - cFields, - &hEnumField, - pModule, - &genericsInfo.typeContext, - &(((LayoutEEClass *)pClass)->m_LayoutInfo), - pLayoutRawFieldInfos, - pAllocator, - pamTracker); - } + THROW_BAD_FORMAT_MAYBE(!"ClassLayout:Invalid PackingSize", BFA_BAD_PACKING_SIZE, pModule); + pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT); } } @@ -12756,7 +12801,7 @@ ClassLoader::CreateTypeHandleForTypeDefThrowing( pModule, cl, pInterfaceBuildInfo, - pLayoutRawFieldInfos, + &layoutInfo, pParentMethodTable, &genericsInfo, parentInst, diff --git a/src/coreclr/vm/methodtablebuilder.h b/src/coreclr/vm/methodtablebuilder.h index 17e8a1fbe703d3..ebd987467d9c61 100644 --- a/src/coreclr/vm/methodtablebuilder.h +++ b/src/coreclr/vm/methodtablebuilder.h @@ -62,6 +62,23 @@ class MethodTableBuilder #endif //_DEBUG }; // struct bmtGenericsInfo + + struct bmtLayoutInfo + { + bmtLayoutInfo() + : nlFlags(nltNone), + packingSize(0), + layoutType(EEClassLayoutInfo::LayoutType::Auto) + { + LIMITED_METHOD_CONTRACT; + } + + CorNativeLinkType nlFlags; + BYTE packingSize; + ULONG classSize; + EEClassLayoutInfo::LayoutType layoutType; + }; + MethodTableBuilder( MethodTable * pHalfBakedMT, EEClass * pHalfBakedClass, @@ -101,7 +118,7 @@ class MethodTableBuilder Module * pModule, mdToken cl, BuildingInterfaceInfo_t * pBuildingInterfaceList, - const LayoutRawFieldInfo * pLayoutRawFieldInfos, + const bmtLayoutInfo * initialLayoutInfo, MethodTable * pParentMethodTable, const bmtGenericsInfo * bmtGenericsInfo, SigPointer parentInst, @@ -2269,6 +2286,7 @@ class MethodTableBuilder bmtMethodImplInfo *bmtMethodImpl; const bmtGenericsInfo *bmtGenerics; bmtEnumFieldInfo *bmtEnumFields; + bmtLayoutInfo* bmtLayout; void SetBMTData( LoaderAllocator *bmtAllocator = NULL, @@ -2285,7 +2303,8 @@ class MethodTableBuilder bmtGCSeriesInfo *bmtGCSeries = NULL, bmtMethodImplInfo *bmtMethodImpl = NULL, const bmtGenericsInfo *bmtGenerics = NULL, - bmtEnumFieldInfo *bmtEnumFields = NULL); + bmtEnumFieldInfo *bmtEnumFields = NULL, + bmtLayoutInfo *bmtLayout = NULL); // -------------------------------------------------------------------------------------------- // Returns the parent bmtRTType pointer. Can be null if no parent exists. @@ -2641,7 +2660,6 @@ class MethodTableBuilder VOID InitializeFieldDescs( FieldDesc *, - const LayoutRawFieldInfo*, bmtInternalInfo*, const bmtGenericsInfo*, bmtMetaDataInfo*, @@ -2900,9 +2918,7 @@ class MethodTableBuilder VOID PlaceThreadStaticFields(); - VOID - PlaceInstanceFields( - MethodTable **); + VOID PlaceInstanceFields(MethodTable** pByValueClassCache); BOOL CheckForVtsEventMethod( @@ -2951,7 +2967,17 @@ class MethodTableBuilder VOID SetFinalizationSemantics(); + VOID + HandleAutoLayout( + MethodTable **); + + VOID HandleSequentialLayout( + MethodTable **); + VOID HandleExplicitLayout( + MethodTable **); + + VOID ValidateExplicitLayout( MethodTable **pByValueClassCache); static ExplicitFieldTrust::TrustLevel CheckValueClassLayout( @@ -3011,11 +3037,6 @@ class MethodTableBuilder bmtMethodHandle hDeclMethod, bmtMethodHandle hImplMethod); - // Heuristic to detemine if we would like instances of this class 8 byte aligned - BOOL ShouldAlign8( - DWORD dwR8Fields, - DWORD dwTotalFields); - MethodTable * AllocateNewMT(Module *pLoaderModule, DWORD dwVtableSlots, DWORD dwVirtuals, diff --git a/src/coreclr/vm/multicorejit.cpp b/src/coreclr/vm/multicorejit.cpp index 98baf1206f1de4..10560356cb538f 100644 --- a/src/coreclr/vm/multicorejit.cpp +++ b/src/coreclr/vm/multicorejit.cpp @@ -20,6 +20,7 @@ #include "array.h" #include "fstream.h" #include "hash.h" +#include "minipal/time.h" #include "appdomain.hpp" #include "qcall.h" @@ -99,7 +100,7 @@ void _MulticoreJitTrace(const char * format, ...) if (s_startTick == 0) { - s_startTick = GetTickCount(); + s_startTick = (unsigned)minipal_lowres_ticks(); } va_list args; @@ -108,7 +109,7 @@ void _MulticoreJitTrace(const char * format, ...) #ifdef LOGGING LogSpew2 (LF2_MULTICOREJIT, LL_INFO100, "Mcj "); LogSpew2Valist(LF2_MULTICOREJIT, LL_INFO100, format, args); - LogSpew2 (LF2_MULTICOREJIT, LL_INFO100, ", (time=%d ms)\n", GetTickCount() - s_startTick); + LogSpew2 (LF2_MULTICOREJIT, LL_INFO100, ", (time=%d ms)\n", (unsigned)minipal_lowres_ticks() - s_startTick); #else // Following LogSpewValist(DWORD facility, DWORD level, const char *fmt, va_list args) @@ -118,7 +119,7 @@ void _MulticoreJitTrace(const char * format, ...) len = sprintf_s(buffer, ARRAY_SIZE(buffer), "Mcj TID %04x: ", GetCurrentThreadId()); len += _vsnprintf_s(buffer + len, ARRAY_SIZE(buffer) - len, format, args); - len += sprintf_s(buffer + len, ARRAY_SIZE(buffer) - len, ", (time=%d ms)\r\n", GetTickCount() - s_startTick); + len += sprintf_s(buffer + len, ARRAY_SIZE(buffer) - len, ", (time=%d ms)\r\n", (unsigned)minipal_lowres_ticks() - s_startTick); OutputDebugStringA(buffer); #endif diff --git a/src/coreclr/vm/multicorejitplayer.cpp b/src/coreclr/vm/multicorejitplayer.cpp index fcc4a46a33fcf1..a3b54d28d802b3 100644 --- a/src/coreclr/vm/multicorejitplayer.cpp +++ b/src/coreclr/vm/multicorejitplayer.cpp @@ -21,6 +21,7 @@ #include "fstream.h" #include "hash.h" #include "clrex.h" +#include "minipal/time.h" #include "appdomain.hpp" @@ -382,7 +383,7 @@ MulticoreJitProfilePlayer::MulticoreJitProfilePlayer(AssemblyBinder * pBinder, L m_pFileBuffer = NULL; m_nFileSize = 0; - m_nStartTime = GetTickCount(); + m_nStartTime = (unsigned int)minipal_lowres_ticks(); } @@ -733,7 +734,7 @@ bool MulticoreJitProfilePlayer::ShouldAbort(bool fast) const return false; } - if (GetTickCount() - m_nStartTime > MULTICOREJITLIFE) + if ((unsigned int)minipal_lowres_ticks() - m_nStartTime > MULTICOREJITLIFE) { MulticoreJitTrace(("MulticoreJitProfilePlayer::ShouldAbort time over")); @@ -1117,7 +1118,7 @@ HRESULT MulticoreJitProfilePlayer::PlayProfile() HRESULT hr = S_OK; - DWORD start = GetTickCount(); + DWORD start = (DWORD)minipal_lowres_ticks(); Thread * pThread = GetThread(); @@ -1311,7 +1312,7 @@ HRESULT MulticoreJitProfilePlayer::PlayProfile() } } - start = GetTickCount() - start; + start = (DWORD)minipal_lowres_ticks() - start; { FireEtwThreadTerminated((ULONGLONG) pThread, (ULONGLONG) GetAppDomain(), GetClrInstanceId()); diff --git a/src/coreclr/vm/peimagelayout.cpp b/src/coreclr/vm/peimagelayout.cpp index 533d3537f090ea..de28670f4df80f 100644 --- a/src/coreclr/vm/peimagelayout.cpp +++ b/src/coreclr/vm/peimagelayout.cpp @@ -106,7 +106,9 @@ PEImageLayout* PEImageLayout::LoadConverted(PEImage* pOwner, bool disableMapping _ASSERTE(!pOwner->IsFile() || !pFlat->HasReadyToRunHeader() || disableMapping); #endif - if ((pFlat->HasReadyToRunHeader() && AllowR2RForImage(pOwner)) + // If the image is R2R with native code (that is, not a component assembly of composite R2R) or has writeable sections, + // we need to actually load/map it into virtual addresses + if ((pFlat->HasReadyToRunHeader() && !pFlat->IsComponentAssembly() && AllowR2RForImage(pOwner)) || pFlat->HasWriteableSections()) { return new ConvertedImageLayout(pFlat, disableMapping); diff --git a/src/coreclr/vm/profdetach.cpp b/src/coreclr/vm/profdetach.cpp index 28b8442454cf0c..c487074500fcc9 100644 --- a/src/coreclr/vm/profdetach.cpp +++ b/src/coreclr/vm/profdetach.cpp @@ -17,6 +17,7 @@ #include "profilinghelper.h" #include "profilinghelper.inl" #include "eetoprofinterfaceimpl.inl" +#include "minipal/time.h" // Class static member variables CQuickArrayList ProfilingAPIDetach::s_profilerDetachInfos; @@ -224,7 +225,7 @@ HRESULT ProfilingAPIDetach::RequestProfilerDetach(ProfilerInfo *pProfilerInfo, D { ProfilerDetachInfo detachInfo; detachInfo.m_pProfilerInfo = pProfilerInfo; - detachInfo.m_ui64DetachStartTime = CLRGetTickCount64(); + detachInfo.m_ui64DetachStartTime = minipal_lowres_ticks(); detachInfo.m_dwExpectedCompletionMilliseconds = dwExpectedCompletionMilliseconds; s_profilerDetachInfos.Push(detachInfo); } @@ -422,7 +423,7 @@ void ProfilingAPIDetach::SleepWhileProfilerEvacuates(ProfilerDetachInfo *pDetach // (but not too soon) // * Occasionally thereafter (steady state) - ULONGLONG ui64ElapsedMilliseconds = CLRGetTickCount64() - ui64DetachStartTime; + ULONGLONG ui64ElapsedMilliseconds = minipal_lowres_ticks() - ui64DetachStartTime; ULONGLONG ui64SleepMilliseconds; if (ui64ExpectedCompletionMilliseconds > ui64ElapsedMilliseconds) { diff --git a/src/coreclr/vm/readytoruninfo.cpp b/src/coreclr/vm/readytoruninfo.cpp index 8ae5bd42a43d0c..53b7db308aa794 100644 --- a/src/coreclr/vm/readytoruninfo.cpp +++ b/src/coreclr/vm/readytoruninfo.cpp @@ -515,12 +515,37 @@ static bool AcquireImage(Module * pModule, PEImageLayout * pLayout, READYTORUN_H static NativeImage *AcquireCompositeImage(Module * pModule, PEImageLayout * pLayout, READYTORUN_HEADER *pHeader) { READYTORUN_SECTION * pSections = (READYTORUN_SECTION*)(pHeader + 1); - LPCUTF8 ownerCompositeExecutableName = NULL; + DWORD virtualAddress = UINT32_MAX; for (DWORD i = 0; i < pHeader->CoreHeader.NumberOfSections; i++) { if (pSections[i].Type == ReadyToRunSectionType::OwnerCompositeExecutable) { - ownerCompositeExecutableName = (LPCUTF8)pLayout->GetBase() + pSections[i].Section.VirtualAddress; + virtualAddress = pSections[i].Section.VirtualAddress; + break; + } + } + + if (virtualAddress == UINT32_MAX) + return NULL; + + LPCUTF8 ownerCompositeExecutableName = NULL; + if (pLayout->IsMapped()) + { + ownerCompositeExecutableName = (LPCUTF8)pLayout->GetBase() + virtualAddress; + } + else + { + // Flat layout - find the data corresponding to the owner composite executable name + int numSections = pLayout->GetNumberOfSections(); + IMAGE_SECTION_HEADER* sectionHeaders = pLayout->FindFirstSection(); + for (int i = 0; i < numSections; i++) + { + IMAGE_SECTION_HEADER& header = sectionHeaders[i]; + if (header.VirtualAddress > virtualAddress || header.VirtualAddress + header.SizeOfRawData < virtualAddress) + continue; + + DWORD offset = virtualAddress - header.VirtualAddress; + ownerCompositeExecutableName = (LPCUTF8)pLayout->GetBase() + header.PointerToRawData + offset; break; } } @@ -585,7 +610,8 @@ PTR_ReadyToRunInfo ReadyToRunInfo::Initialize(Module * pModule, AllocMemTracker } // The file must have been loaded using LoadLibrary - if (!pLayout->IsRelocated()) + bool isComponentAssembly = pLayout->IsComponentAssembly(); + if (!isComponentAssembly && !pLayout->IsRelocated()) { DoLog("Ready to Run disabled - module not loaded for execution"); return NULL; @@ -601,7 +627,7 @@ PTR_ReadyToRunInfo ReadyToRunInfo::Initialize(Module * pModule, AllocMemTracker } NativeImage *nativeImage = NULL; - if (pHeader->CoreHeader.Flags & READYTORUN_FLAG_COMPONENT) + if (isComponentAssembly) { nativeImage = AcquireCompositeImage(pModule, pLayout, pHeader); if (nativeImage == NULL) diff --git a/src/coreclr/vm/syncblk.cpp b/src/coreclr/vm/syncblk.cpp index 0d4e05a3bd4382..5d79a850071a97 100644 --- a/src/coreclr/vm/syncblk.cpp +++ b/src/coreclr/vm/syncblk.cpp @@ -28,6 +28,7 @@ #include "corhost.h" #include "comdelegate.h" #include "finalizerthread.h" +#include "minipal/time.h" #ifdef FEATURE_COMINTEROP #include "runtimecallablewrapper.h" @@ -591,13 +592,6 @@ void SyncBlockCache::CleanupSyncBlocks() } EE_END_FINALLY; } -// create the sync block cache -/* static */ -void SyncBlockCache::Attach() -{ - LIMITED_METHOD_CONTRACT; -} - // create the sync block cache /* static */ void SyncBlockCache::Start() @@ -2477,15 +2471,15 @@ inline void LogContention() #define LogContention() #endif -double ComputeElapsedTimeInNanosecond(LARGE_INTEGER startTicks, LARGE_INTEGER endTicks) +double ComputeElapsedTimeInNanosecond(int64_t startTicks, int64_t endTicks) { - static LARGE_INTEGER freq; - if (freq.QuadPart == 0) - QueryPerformanceFrequency(&freq); + static int64_t freq; + if (freq == 0) + freq = minipal_hires_tick_frequency(); const double NsPerSecond = 1000 * 1000 * 1000; - LONGLONG elapsedTicks = endTicks.QuadPart - startTicks.QuadPart; - return (elapsedTicks * NsPerSecond) / freq.QuadPart; + LONGLONG elapsedTicks = endTicks - startTicks; + return (elapsedTicks * NsPerSecond) / freq; } BOOL AwareLock::EnterEpilogHelper(Thread* pCurThread, INT32 timeOut) @@ -2510,12 +2504,12 @@ BOOL AwareLock::EnterEpilogHelper(Thread* pCurThread, INT32 timeOut) OBJECTREF obj = GetOwningObject(); - LARGE_INTEGER startTicks = { {0} }; + int64_t startTicks = 0; bool isContentionKeywordEnabled = ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context, TRACE_LEVEL_INFORMATION, CLR_CONTENTION_KEYWORD); if (isContentionKeywordEnabled) { - QueryPerformanceCounter(&startTicks); + startTicks = minipal_hires_ticks(); if (InterlockedCompareExchangeT(&m_emittedLockCreatedEvent, 1, 0) == 0) { @@ -2550,7 +2544,7 @@ BOOL AwareLock::EnterEpilogHelper(Thread* pCurThread, INT32 timeOut) // Measure the time we wait so that, in the case where we wake up // and fail to acquire the mutex, we can adjust remaining timeout // accordingly. - ULONGLONG start = CLRGetTickCount64(); + int64_t start = minipal_lowres_ticks(); // It is likely the case that An APC threw an exception, for instance Thread.Interrupt(). The wait subsystem // guarantees that if a signal to the event being waited upon is observed by the woken thread, that thread's @@ -2638,8 +2632,8 @@ BOOL AwareLock::EnterEpilogHelper(Thread* pCurThread, INT32 timeOut) // case is taken care of by 32-bit modulo arithmetic automatically. if (timeOut != (INT32)INFINITE) { - ULONGLONG end = CLRGetTickCount64(); - ULONGLONG duration; + int64_t end = minipal_lowres_ticks(); + int64_t duration; if (end == start) { duration = 1; @@ -2648,7 +2642,7 @@ BOOL AwareLock::EnterEpilogHelper(Thread* pCurThread, INT32 timeOut) { duration = end - start; } - duration = min(duration, (ULONGLONG)timeOut); + duration = min(duration, (int64_t)timeOut); timeOut -= (INT32)duration; } } @@ -2660,8 +2654,7 @@ BOOL AwareLock::EnterEpilogHelper(Thread* pCurThread, INT32 timeOut) if (isContentionKeywordEnabled) { - LARGE_INTEGER endTicks; - QueryPerformanceCounter(&endTicks); + int64_t endTicks = minipal_hires_ticks(); double elapsedTimeInNanosecond = ComputeElapsedTimeInNanosecond(startTicks, endTicks); diff --git a/src/coreclr/vm/syncblk.inl b/src/coreclr/vm/syncblk.inl index be935d084840b5..a9ea995d721297 100644 --- a/src/coreclr/vm/syncblk.inl +++ b/src/coreclr/vm/syncblk.inl @@ -438,7 +438,7 @@ FORCEINLINE void AwareLock::RecordWaiterStarvationStartTime() { WRAPPER_NO_CONTRACT; - DWORD currentTimeMs = GetTickCount(); + DWORD currentTimeMs = (DWORD)minipal_lowres_ticks(); if (currentTimeMs == 0) { // Don't record zero, that value is reserved for identifying that a time is not recorded @@ -455,7 +455,7 @@ FORCEINLINE bool AwareLock::ShouldStopPreemptingWaiters() const DWORD waiterStarvationStartTimeMs = m_waiterStarvationStartTimeMs; return waiterStarvationStartTimeMs != 0 && - GetTickCount() - waiterStarvationStartTimeMs >= WaiterStarvationDurationMsBeforeStoppingPreemptingWaiters; + (DWORD)minipal_lowres_ticks() - waiterStarvationStartTimeMs >= WaiterStarvationDurationMsBeforeStoppingPreemptingWaiters; } FORCEINLINE void AwareLock::SpinWait(const YieldProcessorNormalizationInfo &normalizationInfo, DWORD spinIteration) diff --git a/src/coreclr/vm/threads.cpp b/src/coreclr/vm/threads.cpp index 1685042586057f..b3ad5b35b47960 100644 --- a/src/coreclr/vm/threads.cpp +++ b/src/coreclr/vm/threads.cpp @@ -31,6 +31,7 @@ #include "appdomain.inl" #include "vmholder.h" #include "exceptmacros.h" +#include "minipal/time.h" #ifdef FEATURE_COMINTEROP #include "runtimecallablewrapper.h" @@ -3329,7 +3330,7 @@ DWORD Thread::DoAppropriateWaitWorker(int countHandles, HANDLE *handles, BOOL wa retry: if (millis != INFINITE) { - dwStart = CLRGetTickCount64(); + dwStart = minipal_lowres_ticks(); } if (tryNonblockingWaitFirst) @@ -3355,7 +3356,7 @@ DWORD Thread::DoAppropriateWaitWorker(int countHandles, HANDLE *handles, BOOL wa // in the thread state bits. Otherwise we just go back to sleep again. if (millis != INFINITE) { - dwEnd = CLRGetTickCount64(); + dwEnd = minipal_lowres_ticks(); if (dwEnd - dwStart >= millis) { ret = WAIT_TIMEOUT; @@ -3438,7 +3439,7 @@ DWORD Thread::DoAppropriateWaitWorker(int countHandles, HANDLE *handles, BOOL wa // Compute the new timeout value by assume that the timeout // is not large enough for more than one wrap - dwEnd = CLRGetTickCount64(); + dwEnd = minipal_lowres_ticks(); if (millis != INFINITE) { if (dwEnd - dwStart >= millis) @@ -3566,7 +3567,7 @@ DWORD Thread::DoSignalAndWaitWorker(HANDLE* pHandles, DWORD millis,BOOL alertabl if (INFINITE != millis) { - dwStart = CLRGetTickCount64(); + dwStart = minipal_lowres_ticks(); } ret = SignalObjectAndWait(pHandles[0], pHandles[1], millis, alertable); @@ -3585,7 +3586,7 @@ DWORD Thread::DoSignalAndWaitWorker(HANDLE* pHandles, DWORD millis,BOOL alertabl } if (INFINITE != millis) { - dwEnd = CLRGetTickCount64(); + dwEnd = minipal_lowres_ticks(); if (dwStart + millis <= dwEnd) { ret = WAIT_TIMEOUT; @@ -3595,7 +3596,7 @@ DWORD Thread::DoSignalAndWaitWorker(HANDLE* pHandles, DWORD millis,BOOL alertabl { millis -= (DWORD)(dwEnd - dwStart); } - dwStart = CLRGetTickCount64(); + dwStart = minipal_lowres_ticks(); } //Retry case we don't want to signal again so only do the wait... ret = WaitForSingleObjectEx(pHandles[1],millis,TRUE); @@ -3957,7 +3958,7 @@ void Thread::UserSleep(INT32 time) DWORD dwTime = (DWORD)time; retry: - ULONGLONG start = CLRGetTickCount64(); + ULONGLONG start = minipal_lowres_ticks(); res = ClrSleepEx (dwTime, TRUE); @@ -3977,7 +3978,7 @@ void Thread::UserSleep(INT32 time) } else { - ULONGLONG actDuration = CLRGetTickCount64() - start; + ULONGLONG actDuration = minipal_lowres_ticks() - start; if (dwTime > actDuration) { diff --git a/src/coreclr/vm/threadsuspend.cpp b/src/coreclr/vm/threadsuspend.cpp index 4e7a0020927076..e3c8f4f7546813 100644 --- a/src/coreclr/vm/threadsuspend.cpp +++ b/src/coreclr/vm/threadsuspend.cpp @@ -209,7 +209,7 @@ Thread::SuspendThreadResult Thread::SuspendThread(BOOL fOneTryOnly, DWORD *pdwSu #if defined(_DEBUG) int nCnt = 0; bool bDiagSuspend = g_pConfig->GetDiagnosticSuspend(); - ULONGLONG i64TimestampStart = CLRGetTickCount64(); + ULONGLONG i64TimestampStart = minipal_lowres_ticks(); ULONGLONG i64TimestampCur = i64TimestampStart; ULONGLONG i64TimestampPrev = i64TimestampStart; @@ -321,7 +321,7 @@ Thread::SuspendThreadResult Thread::SuspendThread(BOOL fOneTryOnly, DWORD *pdwSu if ((!fOneTryOnly) && bDiagSuspend) { while ( m_dwForbidSuspendThread != 0 && - CLRGetTickCount64()-i64TimestampStart < nCnt*(i64TimestampTicksMax>>3) ) + minipal_lowres_ticks()-i64TimestampStart < nCnt*(i64TimestampTicksMax>>3) ) { if (g_SystemInfo.dwNumberOfProcessors > 1) { @@ -379,9 +379,9 @@ Thread::SuspendThreadResult Thread::SuspendThread(BOOL fOneTryOnly, DWORD *pdwSu #if defined(_DEBUG) i64TimestampPrev = i64TimestampCur; - i64TimestampCur = CLRGetTickCount64(); - // CLRGetTickCount64() is global per machine (not per CPU, like getTimeStamp()). - // Next ASSERT states that CLRGetTickCount64() is increasing, or has wrapped. + i64TimestampCur = minipal_lowres_ticks(); + // minipal_lowres_ticks() is global per machine (not per CPU, like getTimeStamp()). + // Next ASSERT states that minipal_lowres_ticks() is increasing, or has wrapped. // If it wrapped, the last iteration should have executed faster then 0.5 seconds. _ASSERTE(i64TimestampCur >= i64TimestampPrev || i64TimestampCur <= 500); @@ -1202,8 +1202,8 @@ Thread::UserAbort(EEPolicy::ThreadAbortTypes abortType, DWORD timeout) // Swap in timeout if (timeout != INFINITE) { - ULONG64 curTime = CLRGetTickCount64(); - ULONG64 newEndTime = curTime + timeout; + ULONGLONG curTime = minipal_lowres_ticks(); + ULONGLONG newEndTime = curTime + timeout; SetAbortEndTime(newEndTime, abortType == EEPolicy::TA_Rude); } @@ -1263,7 +1263,7 @@ Thread::UserAbort(EEPolicy::ThreadAbortTypes abortType, DWORD timeout) ULONGLONG abortEndTime = GetAbortEndTime(); if (abortEndTime != MAXULONGLONG) { - ULONGLONG now_time = CLRGetTickCount64(); + ULONGLONG now_time = minipal_lowres_ticks(); if (now_time >= abortEndTime) { @@ -1657,7 +1657,7 @@ Thread::UserAbort(EEPolicy::ThreadAbortTypes abortType, DWORD timeout) return S_OK; } - ULONGLONG curTime = CLRGetTickCount64(); + ULONGLONG curTime = minipal_lowres_ticks(); if (curTime >= GetAbortEndTime()) { break; @@ -6056,20 +6056,13 @@ DWORD StatisticsBase::secondsToDisplay = 0; DWORD StatisticsBase::GetTime() { LIMITED_METHOD_CONTRACT; - LARGE_INTEGER large; if (divisor == 0) { - if (QueryPerformanceFrequency(&large) && (large.QuadPart != 0)) - divisor = (DWORD)(large.QuadPart / (1000 * 1000)); // microseconds - else - divisor = 1; + divisor = (DWORD)minipal_hires_tick_frequency() / (1000 * 1000); // microseconds } - if (QueryPerformanceCounter(&large)) - return (DWORD) (large.QuadPart / divisor); - else - return 0; + return (DWORD) (minipal_hires_ticks() / divisor); } DWORD StatisticsBase::GetElapsed(DWORD start, DWORD stop) @@ -6100,7 +6093,7 @@ void StatisticsBase::RollOverIfNeeded() const DWORD RolloverInterval = 3900; // every so often, print a summary of our statistics - DWORD ticksNow = GetTickCount(); + DWORD ticksNow = (DWORD)minipal_lowres_ticks(); if (secondsToDisplay == 0) { @@ -6115,7 +6108,7 @@ void StatisticsBase::RollOverIfNeeded() { DisplayAndUpdate(); - startTick = GetTickCount(); + startTick = (DWORD)minipal_lowres_ticks(); // Our counters are 32 bits and can count to 4 GB in microseconds or 4K in seconds. // Reset when we get close to overflowing diff --git a/src/coreclr/vm/tieredcompilation.cpp b/src/coreclr/vm/tieredcompilation.cpp index 2d1a8bddfdd919..1dd18ca48a0bab 100644 --- a/src/coreclr/vm/tieredcompilation.cpp +++ b/src/coreclr/vm/tieredcompilation.cpp @@ -12,6 +12,7 @@ #include "log.h" #include "threadsuspend.h" #include "tieredcompilation.h" +#include "minipal/time.h" // TieredCompilationManager determines which methods should be recompiled and // how they should be recompiled to best optimize the running code. It then @@ -500,12 +501,10 @@ void TieredCompilationManager::BackgroundWorkerStart() int processorCount = GetCurrentProcessCpuCount(); _ASSERTE(processorCount > 0); - LARGE_INTEGER li; - QueryPerformanceFrequency(&li); - UINT64 ticksPerS = li.QuadPart; - UINT64 maxWorkDurationTicks = ticksPerS * 50 / 1000; // 50 ms - UINT64 minWorkDurationTicks = min(ticksPerS * processorCount / 1000, maxWorkDurationTicks); // ms (capped) - UINT64 workDurationTicks = minWorkDurationTicks; + int64_t ticksPerS = minipal_hires_tick_frequency(); + int64_t maxWorkDurationTicks = ticksPerS * 50 / 1000; // 50 ms + int64_t minWorkDurationTicks = min(ticksPerS * processorCount / 1000, maxWorkDurationTicks); // ms (capped) + int64_t workDurationTicks = minWorkDurationTicks; while (true) { @@ -713,9 +712,9 @@ void TieredCompilationManager::AsyncCompleteCallCounting() // optimizations enabled and then installed as the active implementation // of the method entrypoint. bool TieredCompilationManager::DoBackgroundWork( - UINT64 *workDurationTicksRef, - UINT64 minWorkDurationTicks, - UINT64 maxWorkDurationTicks) + int64_t *workDurationTicksRef, + int64_t minWorkDurationTicks, + int64_t maxWorkDurationTicks) { WRAPPER_NO_CONTRACT; _ASSERTE(GetThread() == s_backgroundWorkerThread); @@ -723,7 +722,7 @@ bool TieredCompilationManager::DoBackgroundWork( _ASSERTE(workDurationTicksRef != nullptr); _ASSERTE(minWorkDurationTicks <= maxWorkDurationTicks); - UINT64 workDurationTicks = *workDurationTicksRef; + int64_t workDurationTicks = *workDurationTicksRef; _ASSERTE(workDurationTicks >= minWorkDurationTicks); _ASSERTE(workDurationTicks <= maxWorkDurationTicks); @@ -740,10 +739,8 @@ bool TieredCompilationManager::DoBackgroundWork( bool sendStopEvent = true; bool allMethodsJitted = false; UINT32 jittedMethodCount = 0; - LARGE_INTEGER li; - QueryPerformanceCounter(&li); - UINT64 startTicks = li.QuadPart; - UINT64 previousTicks = startTicks; + int64_t startTicks = minipal_hires_ticks(); + int64_t previousTicks = startTicks; do { @@ -822,8 +819,7 @@ bool TieredCompilationManager::DoBackgroundWork( // Yield the thread periodically to give preference to possibly more important work - QueryPerformanceCounter(&li); - UINT64 currentTicks = li.QuadPart; + int64_t currentTicks = minipal_hires_ticks(); if (currentTicks - startTicks < workDurationTicks) { previousTicks = currentTicks; @@ -849,11 +845,10 @@ bool TieredCompilationManager::DoBackgroundWork( ETW::CompilationLog::TieredCompilation::Runtime::SendBackgroundJitStop(countOfMethodsToOptimize, jittedMethodCount); } - UINT64 beforeSleepTicks = currentTicks; + int64_t beforeSleepTicks = currentTicks; ClrSleepEx(0, false); - QueryPerformanceCounter(&li); - currentTicks = li.QuadPart; + currentTicks = minipal_hires_ticks(); // Depending on how oversubscribed thread usage is on the system, the sleep may have caused this thread to not be // scheduled for a long time. Yielding the thread too frequently may significantly slow down the background work, which @@ -864,8 +859,8 @@ bool TieredCompilationManager::DoBackgroundWork( // work duration is capped to a maximum and since a long sleep delay is likely to repeat, to avoid going back to // too-frequent yielding too quickly, the background work duration is decayed back to the minimum if the sleep duration // becomes consistently short. - UINT64 newWorkDurationTicks = (currentTicks - beforeSleepTicks) / 4; - UINT64 decayedWorkDurationTicks = (workDurationTicks + workDurationTicks / 2) / 2; + int64_t newWorkDurationTicks = (currentTicks - beforeSleepTicks) / 4; + int64_t decayedWorkDurationTicks = (workDurationTicks + workDurationTicks / 2) / 2; workDurationTicks = newWorkDurationTicks < decayedWorkDurationTicks ? decayedWorkDurationTicks : newWorkDurationTicks; if (workDurationTicks < minWorkDurationTicks) { diff --git a/src/coreclr/vm/tieredcompilation.h b/src/coreclr/vm/tieredcompilation.h index 7177c6cc32a41e..b39ef788a72e12 100644 --- a/src/coreclr/vm/tieredcompilation.h +++ b/src/coreclr/vm/tieredcompilation.h @@ -71,7 +71,7 @@ class TieredCompilationManager private: static DWORD StaticBackgroundWorkCallback(void* args); - bool DoBackgroundWork(UINT64 *workDurationTicksRef, UINT64 minWorkDurationTicks, UINT64 maxWorkDurationTicks); + bool DoBackgroundWork(int64_t *workDurationTicksRef, int64_t minWorkDurationTicks, int64_t maxWorkDurationTicks); private: void OptimizeMethod(NativeCodeVersion nativeCodeVersion); diff --git a/src/coreclr/vm/util.hpp b/src/coreclr/vm/util.hpp index f2ecac4eac4aa3..62bbca2f21012f 100644 --- a/src/coreclr/vm/util.hpp +++ b/src/coreclr/vm/util.hpp @@ -17,6 +17,7 @@ #include "xclrdata.h" #include "posterror.h" #include +#include "minipal/time.h" #ifndef DACCESS_COMPILE #if defined(TARGET_WINDOWS) && defined(TARGET_ARM64) @@ -797,8 +798,8 @@ class NormalizedTimer static const int64_t NormalizedTicksPerSecond = 10000000 /* 100ns ticks per second (1e7) */; static Volatile s_frequency; - LARGE_INTEGER startTimestamp; - LARGE_INTEGER stopTimestamp; + int64_t startTimestamp; + int64_t stopTimestamp; #if _DEBUG bool isRunning = false; @@ -811,15 +812,14 @@ class NormalizedTimer if (s_frequency.Load() == -1) { double frequency; - LARGE_INTEGER qpfValue; - QueryPerformanceFrequency(&qpfValue); - frequency = static_cast(qpfValue.QuadPart); + int64_t qpfValue = minipal_hires_tick_frequency(); + frequency = static_cast(qpfValue); frequency /= NormalizedTicksPerSecond; s_frequency.Store(frequency); } - startTimestamp.QuadPart = 0; - startTimestamp.QuadPart = 0; + startTimestamp = 0; + stopTimestamp = 0; } // ====================================================================================== @@ -829,7 +829,7 @@ class NormalizedTimer { LIMITED_METHOD_CONTRACT; _ASSERTE(!isRunning); - QueryPerformanceCounter(&startTimestamp); + startTimestamp = minipal_hires_ticks(); #if _DEBUG isRunning = true; @@ -843,7 +843,7 @@ class NormalizedTimer { LIMITED_METHOD_CONTRACT; _ASSERTE(isRunning); - QueryPerformanceCounter(&stopTimestamp); + stopTimestamp = minipal_hires_ticks(); #if _DEBUG isRunning = false; @@ -859,9 +859,9 @@ class NormalizedTimer { LIMITED_METHOD_CONTRACT; _ASSERTE(!isRunning); - _ASSERTE(startTimestamp.QuadPart > 0); - _ASSERTE(stopTimestamp.QuadPart > 0); - return static_cast((stopTimestamp.QuadPart - startTimestamp.QuadPart) / s_frequency); + _ASSERTE(startTimestamp > 0); + _ASSERTE(stopTimestamp > 0); + return static_cast((stopTimestamp - startTimestamp) / s_frequency); } }; diff --git a/src/coreclr/vm/yieldprocessornormalized.cpp b/src/coreclr/vm/yieldprocessornormalized.cpp index 258e30d634c7ce..7901bd024c3145 100644 --- a/src/coreclr/vm/yieldprocessornormalized.cpp +++ b/src/coreclr/vm/yieldprocessornormalized.cpp @@ -3,7 +3,7 @@ #include "common.h" #include "yieldprocessornormalized.h" - +#include "minipal/time.h" #include "finalizerthread.h" diff --git a/src/coreclr/vm/yieldprocessornormalizedshared.cpp b/src/coreclr/vm/yieldprocessornormalizedshared.cpp index dc939ee9f8d45e..55acce2666bff5 100644 --- a/src/coreclr/vm/yieldprocessornormalizedshared.cpp +++ b/src/coreclr/vm/yieldprocessornormalizedshared.cpp @@ -9,40 +9,20 @@ enum class NormalizationState : uint8_t }; static const int NsPerYieldMeasurementCount = 8; -static const unsigned int MeasurementPeriodMs = 4000; +static const int64_t MeasurementPeriodMs = 4000; static const unsigned int NsPerS = 1000 * 1000 * 1000; static NormalizationState s_normalizationState = NormalizationState::Uninitialized; -static unsigned int s_previousNormalizationTimeMs; +static int64_t s_previousNormalizationTimeMs; -static uint64_t s_performanceCounterTicksPerS; +static int64_t s_performanceCounterTicksPerS; static double s_nsPerYieldMeasurements[NsPerYieldMeasurementCount]; static int s_nextMeasurementIndex; static double s_establishedNsPerYield = YieldProcessorNormalization::TargetNsPerNormalizedYield; void RhEnableFinalization(); -inline unsigned int GetTickCountPortable() -{ -#ifdef FEATURE_NATIVEAOT - return (unsigned int)PalGetTickCount64(); -#else - return GetTickCount(); -#endif -} - -static uint64_t GetPerformanceCounter() -{ -#ifdef FEATURE_NATIVEAOT - return PalQueryPerformanceCounter(); -#else - LARGE_INTEGER li; - QueryPerformanceCounter(&li); - return li.QuadPart; -#endif -} - static unsigned int DetermineMeasureDurationUs() { CONTRACTL @@ -60,8 +40,8 @@ static unsigned int DetermineMeasureDurationUs() // On some systems, querying the high performance counter has relatively significant overhead. Increase the measure duration // if the overhead seems high relative to the measure duration. unsigned int measureDurationUs = 1; - uint64_t startTicks = GetPerformanceCounter(); - uint64_t elapsedTicks = GetPerformanceCounter() - startTicks; + int64_t startTicks = minipal_hires_ticks(); + int64_t elapsedTicks = minipal_hires_ticks() - startTicks; if (elapsedTicks >= s_performanceCounterTicksPerS * measureDurationUs * (1000 / 4) / NsPerS) // elapsed >= 1/4 of the measure duration { measureDurationUs *= 4; @@ -84,17 +64,17 @@ static double MeasureNsPerYield(unsigned int measureDurationUs) _ASSERTE(s_normalizationState != NormalizationState::Failed); int yieldCount = (int)(measureDurationUs * 1000 / s_establishedNsPerYield) + 1; - uint64_t ticksPerS = s_performanceCounterTicksPerS; - uint64_t measureDurationTicks = ticksPerS * measureDurationUs / (1000 * 1000); + int64_t ticksPerS = s_performanceCounterTicksPerS; + int64_t measureDurationTicks = ticksPerS * measureDurationUs / (1000 * 1000); - uint64_t startTicks = GetPerformanceCounter(); + int64_t startTicks = minipal_hires_ticks(); for (int i = 0; i < yieldCount; ++i) { System_YieldProcessor(); } - uint64_t elapsedTicks = GetPerformanceCounter() - startTicks; + int64_t elapsedTicks = minipal_hires_ticks() - startTicks; while (elapsedTicks < measureDurationTicks) { int nextYieldCount = @@ -107,7 +87,7 @@ static double MeasureNsPerYield(unsigned int measureDurationUs) System_YieldProcessor(); } - elapsedTicks = GetPerformanceCounter() - startTicks; + elapsedTicks = minipal_hires_ticks() - startTicks; yieldCount += nextYieldCount; } @@ -138,7 +118,7 @@ void YieldProcessorNormalization::PerformMeasurement() double latestNsPerYield; if (s_normalizationState == NormalizationState::Initialized) { - if (GetTickCountPortable() - s_previousNormalizationTimeMs < MeasurementPeriodMs) + if (minipal_lowres_ticks() - s_previousNormalizationTimeMs < MeasurementPeriodMs) { return; } @@ -155,10 +135,10 @@ void YieldProcessorNormalization::PerformMeasurement() else if (s_normalizationState == NormalizationState::Uninitialized) { #ifdef FEATURE_NATIVEAOT - if ((s_performanceCounterTicksPerS = PalQueryPerformanceFrequency()) < 1000 * 1000) + if ((s_performanceCounterTicksPerS = minipal_hires_tick_frequency()) < 1000 * 1000) #else - LARGE_INTEGER li; - if (!QueryPerformanceFrequency(&li) || li.QuadPart < 1000 * 1000) + int64_t freq = minipal_hires_tick_frequency(); + if (freq < 1000 * 1000) #endif { // High precision clock not available or clock resolution is too low, resort to defaults @@ -167,7 +147,7 @@ void YieldProcessorNormalization::PerformMeasurement() } #ifndef FEATURE_NATIVEAOT - s_performanceCounterTicksPerS = li.QuadPart; + s_performanceCounterTicksPerS = freq; #endif unsigned int measureDurationUs = DetermineMeasureDurationUs(); @@ -223,7 +203,7 @@ void YieldProcessorNormalization::PerformMeasurement() GCHeapUtilities::GetGCHeap()->SetYieldProcessorScalingFactor((float)yieldsPerNormalizedYield); - s_previousNormalizationTimeMs = GetTickCountPortable(); + s_previousNormalizationTimeMs = (unsigned int)minipal_lowres_ticks(); s_normalizationState = NormalizationState::Initialized; s_isMeasurementScheduled = false; } @@ -242,7 +222,7 @@ void YieldProcessorNormalization::ScheduleMeasurementIfNecessary() NormalizationState normalizationState = VolatileLoadWithoutBarrier(&s_normalizationState); if (normalizationState == NormalizationState::Initialized) { - if (GetTickCountPortable() - s_previousNormalizationTimeMs < MeasurementPeriodMs) + if (minipal_lowres_ticks() - s_previousNormalizationTimeMs < MeasurementPeriodMs) { return; } diff --git a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetLowResolutionTimestamp.cs b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetLowResolutionTimestamp.cs new file mode 100644 index 00000000000000..4b369cf863a65c --- /dev/null +++ b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetLowResolutionTimestamp.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + internal static partial class Sys + { + [LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetLowResolutionTimestamp")] + [SuppressGCTransition] + internal static partial long GetLowResolutionTimestamp(); + } +} diff --git a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetTimestamp.cs b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetTimestamp.cs index 00c967896588b8..6a01db94332420 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetTimestamp.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetTimestamp.cs @@ -9,6 +9,6 @@ internal static partial class Sys { [LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetTimestamp")] [SuppressGCTransition] - internal static partial ulong GetTimestamp(); + internal static partial long GetTimestamp(); } } diff --git a/src/libraries/Common/tests/TestUtilities/System/TestEnvironment.cs b/src/libraries/Common/tests/TestUtilities/System/TestEnvironment.cs index 64209653f14c64..9ec75e2ce5d1b6 100644 --- a/src/libraries/Common/tests/TestUtilities/System/TestEnvironment.cs +++ b/src/libraries/Common/tests/TestUtilities/System/TestEnvironment.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.Generic; + namespace System { public static class TestEnvironment @@ -17,5 +19,24 @@ public static bool IsStressModeEnabled return value != null && (value == "1" || value.Equals("true", StringComparison.OrdinalIgnoreCase)); } } + + /// + /// Removes LANG and any environment variable starting with DOTNET_SYSTEM_GLOBALIZATION from the given environment dictionary. + /// + public static void ClearGlobalizationEnvironmentVars(IDictionary environment) + { + var keysToRemove = new List(); + foreach (var key in environment.Keys) + { + if (key == "LANG" || key.StartsWith("DOTNET_SYSTEM_GLOBALIZATION", StringComparison.OrdinalIgnoreCase)) + { + keysToRemove.Add(key); + } + } + foreach (var key in keysToRemove) + { + environment.Remove(key); + } + } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigBindingGenTestDriver.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigBindingGenTestDriver.cs index 2c6bf5c33bcaf2..b15815d72527fc 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigBindingGenTestDriver.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigBindingGenTestDriver.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; @@ -17,7 +18,7 @@ namespace Microsoft.Extensions.SourceGeneration.Configuration.Binder.Tests { - [ActiveIssue("https://github.com/dotnet/runtime/issues/52062", TestPlatforms.Browser)] + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public partial class ConfigurationBindingGeneratorTests : ConfigurationBinderTestsBase { internal sealed class ConfigBindingGenTestDriver diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs index 219c57b9e59131..e887e1b9cdec1f 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs @@ -72,7 +72,7 @@ public async Task Configure_T_NamedParameters_OutOfOrder(string row) using System.Collections.Generic; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; - + public class Program { public static void Main() @@ -84,7 +84,7 @@ public static void Main() {{row}} } - + public class MyClass { public string MyString { get; set; } @@ -109,7 +109,7 @@ public async Task Bind_T_NamedParameters_OutOfOrder(string row) using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; - + public class Program { public static void Main() @@ -121,7 +121,7 @@ public static void Main() {{row}} } - + public class MyClass { public string MyString { get; set; } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Incremental.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Incremental.cs index aff9a0c20364ca..bb6c5baae32272 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Incremental.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Incremental.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.Extensions.Configuration.Binder.SourceGeneration; @@ -11,7 +12,7 @@ namespace Microsoft.Extensions.SourceGeneration.Configuration.Binder.Tests { public partial class ConfigurationBindingGeneratorTests : ConfigurationBinderTestsBase { - [ActiveIssue("https://github.com/dotnet/runtime/issues/52062", TestPlatforms.Browser)] + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public sealed class IncrementalTests { [Fact] diff --git a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Main.cs b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Main.cs index 5a3479b42c3568..f55323caeedc14 100644 --- a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Main.cs +++ b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Main.cs @@ -24,7 +24,7 @@ namespace Microsoft.Gen.OptionsValidation.Unit.Test; public class EmitterTests { - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task TestEmitterWithCustomValidator() { string source = """ @@ -64,7 +64,7 @@ public partial struct MyOptionsValidator : IValidateOptions Assert.Equal(generatedSource.Replace("\r\n", "\n"), generatedSources[0].SourceText.ToString().Replace("\r\n", "\n")); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task PotentiallyMissingAttributes() { var (diagnostics, _) = await RunGenerator(@" @@ -94,7 +94,7 @@ public partial class FirstValidator : IValidateOptions Assert.Equal(DiagDescriptors.PotentiallyMissingEnumerableValidation.Id, diagnostics[1].Id); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task IgnoredStaticMembers() { var (d, _) = await RunGenerator(@" @@ -129,7 +129,7 @@ public partial class FirstModelValidator : IValidateOptions Assert.Empty(d); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task ValidationAttributeOnStaticMember() { var (d, _) = await RunGenerator(@" @@ -168,7 +168,7 @@ public partial class FirstModelValidator : IValidateOptions Assert.All(d, x => Assert.Equal(DiagnosticSeverity.Warning, x.DefaultSeverity)); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task CircularTypeReferences() { var (diagnostics, _) = await RunGenerator(@" @@ -189,7 +189,7 @@ public partial class FirstValidator : IValidateOptions Assert.Equal(DiagDescriptors.CircularTypeReferences.Id, diagnostics[0].Id); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task InvalidValidatorInterface() { var (diagnostics, _) = await RunGenerator(@" @@ -220,7 +220,7 @@ public partial class SecondValidator Assert.Equal(DiagDescriptors.DoesntImplementIValidateOptions.Id, diagnostics[0].Id); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task NotValidator() { var (diagnostics, _) = await RunGenerator(@" @@ -250,7 +250,7 @@ public partial class SecondValidator Assert.Equal(DiagDescriptors.DoesntImplementIValidateOptions.Id, diagnostics[0].Id); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task ValidatorAlreadyImplementValidateFunction() { var (diagnostics, _) = await RunGenerator(@" @@ -288,7 +288,7 @@ public ValidateOptionsResult Validate(string name, SecondModel options) Assert.Equal(DiagDescriptors.AlreadyImplementsValidateMethod.Id, diagnostics[0].Id); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task NullValidator() { var (diagnostics, _) = await RunGenerator(@" @@ -319,7 +319,7 @@ public partial class SecondValidator : IValidateOptions Assert.Equal(DiagDescriptors.NullValidatorType.Id, diagnostics[0].Id); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task NoSimpleValidatorConstructor() { var (diagnostics, _) = await RunGenerator(@" @@ -356,7 +356,7 @@ public SecondValidator(int _) Assert.Equal(DiagDescriptors.ValidatorsNeedSimpleConstructor.Id, diagnostics[0].Id); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task NoStaticValidator() { var (diagnostics, _) = await RunGenerator(@" @@ -376,7 +376,7 @@ public static partial class FirstValidator : IValidateOptions Assert.Equal(DiagDescriptors.CantBeStaticClass.Id, diagnostics[0].Id); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task BogusModelType() { var (diagnostics, _) = await RunGenerator(@" @@ -390,7 +390,7 @@ public partial class FirstValidator : IValidateOptions Assert.Empty(diagnostics); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task CantValidateOpenGenericMembers() { var (diagnostics, _) = await RunGenerator(@" @@ -421,7 +421,7 @@ public partial class FirstValidator : IValidateOptions> Assert.Equal(DiagDescriptors.CantUseWithGenericTypes.Id, diagnostics[2].Id); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task ClosedGenerics() { var (diagnostics, _) = await RunGenerator(@" @@ -457,7 +457,7 @@ public partial class FirstValidator : IValidateOptions> Assert.Equal(DiagDescriptors.NoEligibleMember.Id, diagnostics[3].Id); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task NoEligibleMembers() { var (diagnostics, _) = await RunGenerator(@" @@ -489,7 +489,7 @@ public partial class SecondValidator : IValidateOptions Assert.Equal(DiagDescriptors.NoEligibleMembersFromValidator.Id, diagnostics[1].Id); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task AlreadyImplemented() { var (diagnostics, _) = await RunGenerator(@" @@ -512,7 +512,7 @@ public void Validate(string name, FirstModel fm) Assert.Equal(DiagDescriptors.AlreadyImplementsValidateMethod.Id, diagnostics[0].Id); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task ShouldNotProduceInfoWhenTheClassHasABaseClass() { var (diagnostics, _) = await RunGenerator(@" @@ -537,7 +537,7 @@ public partial class Validator : IValidateOptions Assert.Empty(diagnostics); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task ShouldNotProduceInfoWhenTransitiveClassHasABaseClass() { var (diagnostics, _) = await RunGenerator(@" @@ -568,7 +568,7 @@ public partial class Validator : IValidateOptions Assert.Empty(diagnostics); } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] [InlineData("bool")] [InlineData("int")] [InlineData("double")] @@ -603,7 +603,7 @@ public partial class Validator : IValidateOptions Assert.Equal(DiagDescriptors.NoEligibleMember.Id, diagnostics[0].Id); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task ShouldProduceWarningWhenTheClassHasNoEligibleMembers() { var (diagnostics, _) = await RunGenerator(@" @@ -623,7 +623,7 @@ public partial class Validator : IValidateOptions Assert.Equal(DiagDescriptors.NoEligibleMembersFromValidator.Id, diagnostics[0].Id); } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] [InlineData("private")] [InlineData("protected")] public async Task ShouldProduceWarningWhenTheClassMembersAreInaccessible(string accessModifier) @@ -648,7 +648,7 @@ public partial class Validator : IValidateOptions Assert.Equal("SYSLIB1206", diagnostics[0].Id); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task ShouldNotProduceErrorWhenMultipleValidationAnnotationsExist() { var (diagnostics, _) = await RunGenerator(@" @@ -668,7 +668,7 @@ public partial class Validator : IValidateOptions Assert.Empty(diagnostics); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task ShouldNotProduceErrorWhenDataTypeAttributesAreUsed() { var (diagnostics, _) = await RunGenerator(@" @@ -702,7 +702,7 @@ public partial class Validator : IValidateOptions Assert.Empty(diagnostics); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task ShouldNotProduceErrorWhenConstVariableIsUsedAsAttributeArgument() { var (diagnostics, _) = await RunGenerator(@" @@ -723,7 +723,7 @@ public partial class Validator : IValidateOptions } // Testing on all existing & eligible annotations extending ValidationAttribute that aren't used above - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task ShouldNotProduceAnyMessagesWhenExistingValidationsArePlaced() { var (diagnostics, _) = await RunGenerator(@" @@ -763,7 +763,7 @@ public partial class Validator : IValidateOptions Assert.Empty(diagnostics); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task ShouldNotProduceErrorWhenPropertiesAreUsedAsAttributeArgument() { var (diagnostics, _) = await RunGenerator(@" @@ -783,7 +783,7 @@ public partial class Validator : IValidateOptions Assert.Empty(diagnostics); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task ShouldSkipWhenOptionsValidatorAttributeDoesNotExist() { var (diagnostics, _) = await RunGenerator(@" @@ -803,7 +803,7 @@ public partial class Validator : IValidateOptions Assert.Empty(diagnostics); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task ShouldSkipAtrributeWhenAttributeSymbolCannotBeFound() { var (diagnostics, _) = await RunGenerator(@" @@ -825,7 +825,7 @@ public partial class Validator : IValidateOptions Assert.Empty(diagnostics); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task ShouldSkipAtrributeWhenAttributeSymbolIsNotBasedOnValidationAttribute() { var (diagnostics, _) = await RunGenerator(@" @@ -847,7 +847,7 @@ public partial class Validator : IValidateOptions Assert.Empty(diagnostics); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task ShouldAcceptAtrributeWhenAttributeIsInDifferentNamespace() { var (diagnostics, _) = await RunGenerator(@" @@ -873,7 +873,7 @@ public partial class Validator : IValidateOptions Assert.Empty(diagnostics); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task ShouldHandleAtrributePropertiesOtherThanString() { var (diagnostics, _) = await RunGenerator(@" @@ -907,7 +907,7 @@ public TestAttribute() { Assert.Empty(diagnostics); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task ShouldStoreFloatValuesCorrectly() { var backupCulture = CultureInfo.CurrentCulture; @@ -938,7 +938,7 @@ public partial class Validator : IValidateOptions } } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task MultiModelValidatorGeneratesOnlyOnePartialTypeBlock() { var (diagnostics, sources) = await RunGenerator(@" @@ -987,7 +987,7 @@ public partial class MultiValidator : IValidateOptions, IValidateOpt Assert.Equal(3, validateMethodDeclarations.Length); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task CircularTypeReferencesInEnumeration() { var (diagnostics, _) = await RunGenerator(@" @@ -1008,7 +1008,7 @@ public partial class FirstValidator : IValidateOptions Assert.Equal(DiagDescriptors.CircularTypeReferences.Id, diagnostics[0].Id); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task NotValidatorInEnumeration() { var (diagnostics, _) = await RunGenerator(@" @@ -1038,7 +1038,7 @@ public partial class SecondValidator Assert.Equal(DiagDescriptors.DoesntImplementIValidateOptions.Id, diagnostics[0].Id); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task NullValidatorInEnumeration() { var (diagnostics, _) = await RunGenerator(@" @@ -1069,7 +1069,7 @@ public partial class SecondValidator : IValidateOptions Assert.Equal(DiagDescriptors.NullValidatorType.Id, diagnostics[0].Id); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task NoSimpleValidatorConstructorInEnumeration() { var (diagnostics, _) = await RunGenerator(@" @@ -1252,7 +1252,7 @@ internal sealed partial class SecondOptionsValidator : IValidateOptions Assert.DoesNotContain("Timeout", generatedSource); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task CantValidateOpenGenericMembersInEnumeration() { var (diagnostics, _) = await RunGenerator(@" @@ -1467,7 +1467,7 @@ public partial class FirstValidator : IValidateOptions> Assert.Equal(DiagDescriptors.CantUseWithGenericTypes.Id, diagnostics[2].Id); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task ClosedGenericsInEnumeration() { var (diagnostics, _) = await RunGenerator(@" @@ -1498,7 +1498,7 @@ public partial class FirstValidator : IValidateOptions> Assert.Equal(DiagDescriptors.NoEligibleMember.Id, diagnostics[2].Id); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task NotEnumerable() { var (diagnostics, _) = await RunGenerator(@" @@ -1519,7 +1519,7 @@ public partial class FirstValidator : IValidateOptions Assert.Equal(DiagDescriptors.NotEnumerableType.Id, diagnostics[0].Id); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task LanguageVersionTest() { string source = """ @@ -1576,7 +1576,7 @@ public partial class FirstModelValidator : IValidateOptions Assert.Equal(0, diags.Length); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNetCore))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles), nameof(PlatformDetection.IsNetCore))] public async Task DataAnnotationAttributesWithParams() { var (diagnostics, generatedSources) = await RunGenerator(@""" @@ -1709,7 +1709,7 @@ private static CSharpCompilation CreateCompilationForOptionsSource(string assemb return result; } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] [InlineData(LanguageVersion.CSharp10)] [InlineData(LanguageVersion.CSharp11)] public async Task GeneratedAttributesTest(LanguageVersion languageVersion) @@ -1821,7 +1821,7 @@ public sealed partial class OptionsUsingGeneratedAttributesValidator : IValidate // Console.WriteLine(emittedSource); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task UsingInterfaceAsPropertyTypeForLengthAttributesTests() { var (diagnostics, generatedSources) = await RunGenerator(@""" @@ -1865,7 +1865,7 @@ public partial class MyOptionsValidator : IValidateOptions Assert.Equal(generatedSource.Replace("\r\n", "\n"), generatedSources[0].SourceText.ToString().Replace("\r\n", "\n")); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task OptionsExtendingSystemClassTest() { string source = """ diff --git a/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/EmitterTests.cs b/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/EmitterTests.cs index 1f54faf77d7fef..da4aba73863aa8 100644 --- a/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/EmitterTests.cs +++ b/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/EmitterTests.cs @@ -17,7 +17,7 @@ namespace Microsoft.Gen.OptionsValidation.Test; public class EmitterTests { - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task TestEmitter() { var sources = new List(); diff --git a/src/libraries/Microsoft.VisualBasic.Core/tests/ErrObjectTests.cs b/src/libraries/Microsoft.VisualBasic.Core/tests/ErrObjectTests.cs index 4db6681ba537a5..5844f2ccf64d12 100644 --- a/src/libraries/Microsoft.VisualBasic.Core/tests/ErrObjectTests.cs +++ b/src/libraries/Microsoft.VisualBasic.Core/tests/ErrObjectTests.cs @@ -10,6 +10,7 @@ namespace Microsoft.VisualBasic.Tests public class ErrObjectTests { [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/114951", typeof(PlatformDetection), nameof(PlatformDetection.IsSingleFile))] [ActiveIssue("https://github.com/mono/mono/issues/14854", TestRuntimes.Mono)] public void Clear() { diff --git a/src/libraries/Microsoft.VisualBasic.Core/tests/Microsoft.VisualBasic.Core.Tests.csproj b/src/libraries/Microsoft.VisualBasic.Core/tests/Microsoft.VisualBasic.Core.Tests.csproj index 688a009eb8691f..6b4dbf83662206 100644 --- a/src/libraries/Microsoft.VisualBasic.Core/tests/Microsoft.VisualBasic.Core.Tests.csproj +++ b/src/libraries/Microsoft.VisualBasic.Core/tests/Microsoft.VisualBasic.Core.Tests.csproj @@ -62,4 +62,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.CodeDom/tests/System/CodeDom/Compiler/CompilerResultsTests.cs b/src/libraries/System.CodeDom/tests/System/CodeDom/Compiler/CompilerResultsTests.cs index aa791baa631aa8..f36b765421ba4e 100644 --- a/src/libraries/System.CodeDom/tests/System/CodeDom/Compiler/CompilerResultsTests.cs +++ b/src/libraries/System.CodeDom/tests/System/CodeDom/Compiler/CompilerResultsTests.cs @@ -28,7 +28,7 @@ public void Ctor_TempFileCollection(TempFileCollection tempFiles) Assert.Same(tempFiles, results.TempFiles); } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public void CompiledAssembly_GetWithPathToAssemblySet_ReturnsExpectedAssembly() { var results = new CompilerResults(null) { PathToAssembly = AssemblyPathHelper.GetAssemblyLocation(typeof(CompilerResultsTests).Assembly) }; diff --git a/src/libraries/System.ComponentModel.Composition/tests/System/ComponentModel/Composition/Hosting/AssemblyCatalogTests.cs b/src/libraries/System.ComponentModel.Composition/tests/System/ComponentModel/Composition/Hosting/AssemblyCatalogTests.cs index ae0c29c15bc0dc..fd3d3c13f00557 100644 --- a/src/libraries/System.ComponentModel.Composition/tests/System/ComponentModel/Composition/Hosting/AssemblyCatalogTests.cs +++ b/src/libraries/System.ComponentModel.Composition/tests/System/ComponentModel/Composition/Hosting/AssemblyCatalogTests.cs @@ -349,7 +349,7 @@ public void Constructor2_NonExistentFileNameAsCodeBaseArgument_ShouldThrowFileNo }); } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public void Constructor2_NullReflectionContextArgument_ShouldThrowArgumentNull() { AssemblyCatalogConstructorTests.Constructor_NullReflectionContextArgument_ShouldThrowArgumentNull((rc) => @@ -447,7 +447,7 @@ public void Constructor3_NonExistentFileNameAsCodeBaseArgument_ShouldThrowFileNo }); } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public void Constructor3_NullDefinitionOriginArgument_ShouldThrowArgumentNull() { AssemblyCatalogConstructorTests.Constructor_NullDefinitionOriginArgument_ShouldThrowArgumentNull((dO) => @@ -544,7 +544,7 @@ public void Constructor4_NonExistentFileNameAsCodeBaseArgument_ShouldThrowFileNo }); } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public void Constructor4_NullReflectionContextArgument_ShouldThrowArgumentNull() { AssemblyCatalogConstructorTests.Constructor_NullReflectionContextArgument_ShouldThrowArgumentNull((rc) => @@ -553,7 +553,7 @@ public void Constructor4_NullReflectionContextArgument_ShouldThrowArgumentNull() }); } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public void Constructor4_NullDefinitionOriginArgument_ShouldThrowArgumentNull() { AssemblyCatalogConstructorTests.Constructor_NullDefinitionOriginArgument_ShouldThrowArgumentNull((dO) => @@ -638,7 +638,7 @@ public void Constructor8_ValueAsAssemblyArgument_ShouldSetAssemblyProperty() }); } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public void Constructor8_NullReflectionContextArgument_ShouldThrowArgumentNull() { AssemblyCatalogConstructorTests.Constructor_NullReflectionContextArgument_ShouldThrowArgumentNull((rc) => @@ -648,7 +648,7 @@ public void Constructor8_NullReflectionContextArgument_ShouldThrowArgumentNull() } #pragma warning disable SYSLIB0012 - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public void Constructor8_NullDefinitionOriginArgument_ShouldThrowArgumentNull() { AssemblyCatalogConstructorTests.Constructor_NullDefinitionOriginArgument_ShouldThrowArgumentNull((dO) => diff --git a/src/libraries/System.ComponentModel.Composition/tests/System/ComponentModel/Composition/Hosting/DirectoryCatalogDebuggerProxyTests.cs b/src/libraries/System.ComponentModel.Composition/tests/System/ComponentModel/Composition/Hosting/DirectoryCatalogDebuggerProxyTests.cs index 72ae912ef1fd8e..16759cef1f4697 100644 --- a/src/libraries/System.ComponentModel.Composition/tests/System/ComponentModel/Composition/Hosting/DirectoryCatalogDebuggerProxyTests.cs +++ b/src/libraries/System.ComponentModel.Composition/tests/System/ComponentModel/Composition/Hosting/DirectoryCatalogDebuggerProxyTests.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; using System.ComponentModel.Composition.Hosting; using System.IO; using System.Linq; @@ -125,8 +126,7 @@ public void LoadedFiles_EmptyDirectory_ShouldBeFine() Assert.Equal(0, proxy.LoadedFiles.Count); } - [Fact] - [SkipOnPlatform(TestPlatforms.Browser, "Not supported on Browser.")] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public void LoadedFiles_ContainsMultipleDllsAndSomeNonDll_ShouldOnlyContainDlls() { string directoryPath = TemporaryFileCopier.GetNewTemporaryDirectory(); diff --git a/src/libraries/System.ComponentModel.Composition/tests/System/ComponentModel/Composition/Hosting/DirectoryCatalogTests.cs b/src/libraries/System.ComponentModel.Composition/tests/System/ComponentModel/Composition/Hosting/DirectoryCatalogTests.cs index c91e51eacd80e6..cddd3ae263f2e3 100644 --- a/src/libraries/System.ComponentModel.Composition/tests/System/ComponentModel/Composition/Hosting/DirectoryCatalogTests.cs +++ b/src/libraries/System.ComponentModel.Composition/tests/System/ComponentModel/Composition/Hosting/DirectoryCatalogTests.cs @@ -320,8 +320,7 @@ public void LoadedFiles_EmptyDirectory_ShouldBeFine() Assert.Equal(0, cat.LoadedFiles.Count); } - [Fact] - [SkipOnPlatform(TestPlatforms.Browser, "Not supported on Browser.")] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public void LoadedFiles_ContainsMultipleDllsAndSomeNonDll_ShouldOnlyContainDlls() { // Add one text file diff --git a/src/libraries/System.Configuration.ConfigurationManager/tests/Mono/ConfigurationManagerTest.cs b/src/libraries/System.Configuration.ConfigurationManager/tests/Mono/ConfigurationManagerTest.cs index ca65cb92533a72..d391f308c7faa6 100644 --- a/src/libraries/System.Configuration.ConfigurationManager/tests/Mono/ConfigurationManagerTest.cs +++ b/src/libraries/System.Configuration.ConfigurationManager/tests/Mono/ConfigurationManagerTest.cs @@ -44,6 +44,7 @@ public class ConfigurationManagerTest { [Fact] // OpenExeConfiguration (ConfigurationUserLevel) [ActiveIssue("https://github.com/dotnet/runtime/issues/21528", TargetFrameworkMonikers.NetFramework)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/114951", typeof(PlatformDetection), nameof(PlatformDetection.IsSingleFile))] public void OpenExeConfiguration1_UserLevel_None() { SysConfig config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); @@ -253,6 +254,7 @@ public void mapped_MachineConfig() // Doesn't pass on Mono // [Category("NotWorking")] [ActiveIssue("https://github.com/dotnet/runtime/issues/21528", TargetFrameworkMonikers.NetFramework)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/114951", typeof(PlatformDetection), nameof(PlatformDetection.IsSingleFile))] public void mapped_ExeConfiguration_null() { SysConfig config = ConfigurationManager.OpenMappedExeConfiguration(null, ConfigurationUserLevel.None); diff --git a/src/libraries/System.Diagnostics.StackTrace/tests/StackTraceSymbolsTests.cs b/src/libraries/System.Diagnostics.StackTrace/tests/StackTraceSymbolsTests.cs index b0470c1c8a5bd8..edd78bf6e61831 100644 --- a/src/libraries/System.Diagnostics.StackTrace/tests/StackTraceSymbolsTests.cs +++ b/src/libraries/System.Diagnostics.StackTrace/tests/StackTraceSymbolsTests.cs @@ -11,6 +11,7 @@ public class StackTraceSymbolsTests { [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] [ActiveIssue("https://github.com/dotnet/runtime/issues/51399", TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/114951", TestPlatforms.Android)] public void StackTraceSymbolsDoNotLockFile() { var asmPath = AssemblyPathHelper.GetAssemblyLocation(typeof(StackTraceSymbolsTests).Assembly); diff --git a/src/libraries/System.Diagnostics.TraceSource/tests/System.Diagnostics.TraceSource.Config.Tests/TraceSourceWithConfigurationTests.cs b/src/libraries/System.Diagnostics.TraceSource/tests/System.Diagnostics.TraceSource.Config.Tests/TraceSourceWithConfigurationTests.cs index 7d39211b10872b..1b523f9e88d019 100644 --- a/src/libraries/System.Diagnostics.TraceSource/tests/System.Diagnostics.TraceSource.Config.Tests/TraceSourceWithConfigurationTests.cs +++ b/src/libraries/System.Diagnostics.TraceSource/tests/System.Diagnostics.TraceSource.Config.Tests/TraceSourceWithConfigurationTests.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; using System.Configuration; using System.IO; using System.Reflection; @@ -35,7 +36,7 @@ private static void CreateAndLoadConfigFile(string filename) [Fact] [SkipOnPlatform(TestPlatforms.Browser, "Not supported on Browser")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/74244", TestPlatforms.tvOS)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/74244", TestPlatforms.tvOS | TestPlatforms.iOS | TestPlatforms.Android)] public void RuntimeFilterChange() { CreateAndLoadConfigFile("testhost_ConfigWithRuntime.config"); @@ -96,7 +97,7 @@ public void RuntimeFilterChange() [Fact] [SkipOnPlatform(TestPlatforms.Browser, "Not supported on Browser")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/74244", TestPlatforms.tvOS)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/74244", TestPlatforms.tvOS | TestPlatforms.iOS | TestPlatforms.Android)] public void Refresh_RemoveSwitch() { // Use a SourceSwitch that logs Error. @@ -137,7 +138,7 @@ void Log() [Fact] [SkipOnPlatform(TestPlatforms.Browser, "Not supported on Browser")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/74244", TestPlatforms.tvOS)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/74244", TestPlatforms.tvOS | TestPlatforms.iOS | TestPlatforms.Android)] public void Refresh_ChangeSwitch() { // Use a SourceSwitch that logs Error. @@ -163,7 +164,7 @@ public void Refresh_ChangeSwitch() [Fact] [SkipOnPlatform(TestPlatforms.Browser, "Not supported on Browser")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/74244", TestPlatforms.tvOS)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/74244", TestPlatforms.tvOS | TestPlatforms.iOS | TestPlatforms.Android)] public void Refresh_RemoveSource() { // Use a SourceSwitch that logs Error. @@ -197,7 +198,7 @@ public void Refresh_RemoveSource() [Fact] [SkipOnPlatform(TestPlatforms.Browser, "Not supported on Browser")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/74244", TestPlatforms.tvOS)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/74244", TestPlatforms.tvOS | TestPlatforms.iOS | TestPlatforms.Android)] public void ConfigWithEvents_RuntimeListener() { CreateAndLoadConfigFile("testhost_ConfigWithRuntime.config"); @@ -264,7 +265,7 @@ private void SubscribeToSwitch_Initializing(object? sender, InitializingSwitchEv [Fact] [SkipOnPlatform(TestPlatforms.Browser, "Not supported on Browser")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/74244", TestPlatforms.tvOS)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/74244", TestPlatforms.tvOS | TestPlatforms.iOS | TestPlatforms.Android)] public void AllTypes() { CreateAndLoadConfigFile("testhost_AllTypes.config"); @@ -309,7 +310,7 @@ public void AllTypes() [Fact] [SkipOnPlatform(TestPlatforms.Browser, "Not supported on Browser")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/74244", TestPlatforms.tvOS)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/74244", TestPlatforms.tvOS | TestPlatforms.iOS | TestPlatforms.Android)] public void Switch_MissingValue_Throws() { Exception e = Assert.Throws(() => @@ -320,7 +321,7 @@ public void Switch_MissingValue_Throws() [Fact] [SkipOnPlatform(TestPlatforms.Browser, "Not supported on Browser")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/74244", TestPlatforms.tvOS)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/74244", TestPlatforms.tvOS | TestPlatforms.iOS | TestPlatforms.Android)] public void UnsupportedAttribute_Throws() { CreateAndLoadConfigFile("testhost_UnsupportedAttribute_Throws.config"); diff --git a/src/libraries/System.IO.Pipelines/tests/PipeWriterTests.cs b/src/libraries/System.IO.Pipelines/tests/PipeWriterTests.cs index 85070e1534a8ee..c3128f15c98dfd 100644 --- a/src/libraries/System.IO.Pipelines/tests/PipeWriterTests.cs +++ b/src/libraries/System.IO.Pipelines/tests/PipeWriterTests.cs @@ -294,6 +294,7 @@ public async Task WritesUsingGetMemoryWorks() } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/114951",platforms: TestPlatforms.Android, runtimes: TestRuntimes.CoreCLR)] public async Task CompleteWithLargeWriteThrows() { var completeDelay = TimeSpan.FromMilliseconds(10); diff --git a/src/libraries/System.Memory/tests/Span/StringSearchValues.cs b/src/libraries/System.Memory/tests/Span/StringSearchValues.cs index 5a3bc8d9a87f06..2bb171a9826dbc 100644 --- a/src/libraries/System.Memory/tests/Span/StringSearchValues.cs +++ b/src/libraries/System.Memory/tests/Span/StringSearchValues.cs @@ -597,7 +597,7 @@ private static void RunUsingInvariantCulture(Action action) Assert.True(CanTestInvariantCulture); var psi = new ProcessStartInfo(); - psi.Environment.Clear(); + TestEnvironment.ClearGlobalizationEnvironmentVars(psi.Environment); psi.Environment.Add("DOTNET_SYSTEM_GLOBALIZATION_INVARIANT", "true"); RemoteExecutor.Invoke(action, new RemoteInvokeOptions { StartInfo = psi, TimeOut = 10 * 60 * 1000 }).Dispose(); @@ -608,7 +608,7 @@ private static void RunUsingNLS(Action action) Assert.True(CanTestNls); var psi = new ProcessStartInfo(); - psi.Environment.Clear(); + TestEnvironment.ClearGlobalizationEnvironmentVars(psi.Environment); psi.Environment.Add("DOTNET_SYSTEM_GLOBALIZATION_USENLS", "true"); RemoteExecutor.Invoke(action, new RemoteInvokeOptions { StartInfo = psi, TimeOut = 10 * 60 * 1000 }).Dispose(); diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 9f4af443787195..cea0562929595a 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -1880,6 +1880,9 @@ Common\Interop\Windows\Kernel32\Interop.GetCurrentThreadId.cs + + Interop\Windows\Kernel32\Interop.GetTickCount64.cs + Common\Interop\Windows\Kernel32\Interop.GetFileAttributesEx.cs @@ -2401,6 +2404,9 @@ Common\Interop\Unix\System.Native\Interop.GetSystemTimeAsTicks.cs + + Common\Interop\Unix\System.Native\Interop.GetLowResolutionTimestamp.cs + Common\Interop\Unix\System.Native\Interop.GetTimestamp.cs diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Stopwatch.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Stopwatch.Unix.cs index 487923148aa0df..77f7fa43d326ba 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Stopwatch.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Stopwatch.Unix.cs @@ -13,7 +13,7 @@ private static long QueryPerformanceFrequency() private static long QueryPerformanceCounter() { - return (long)Interop.Sys.GetTimestamp(); + return Interop.Sys.GetTimestamp(); } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Environment.UnixOrBrowser.cs b/src/libraries/System.Private.CoreLib/src/System/Environment.UnixOrBrowser.cs index 6dbbfe272b25b6..75128d7e22886c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Environment.UnixOrBrowser.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Environment.UnixOrBrowser.cs @@ -93,5 +93,9 @@ public static ProcessCpuUsage CpuUsage return new ProcessCpuUsage { UserTime = new TimeSpan((long)userTime100Nanoseconds), PrivilegedTime = new TimeSpan((long)kernelTime100Nanoseconds) }; } } + + /// Gets the number of milliseconds elapsed since the system started. + /// A 64-bit signed integer containing the amount of time in milliseconds that has passed since the last time the computer was started. + public static long TickCount64 => Interop.Sys.GetLowResolutionTimestamp(); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Environment.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Environment.Windows.cs index 314a73b4fbdceb..a84d9218acb1d6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Environment.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Environment.Windows.cs @@ -374,5 +374,9 @@ public static ProcessCpuUsage CpuUsage new ProcessCpuUsage { UserTime = new TimeSpan(procUserTime), PrivilegedTime = new TimeSpan(procKernelTime) } : new ProcessCpuUsage { UserTime = TimeSpan.Zero, PrivilegedTime = TimeSpan.Zero }; } + + /// Gets the number of milliseconds elapsed since the system started. + /// A 64-bit signed integer containing the amount of time in milliseconds that has passed since the last time the computer was started. + public static long TickCount64 => (long)Interop.Kernel32.GetTickCount64(); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Environment.cs b/src/libraries/System.Private.CoreLib/src/System/Environment.cs index 1f9e9a77d74300..81cd182e7da155 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Environment.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Environment.cs @@ -249,6 +249,10 @@ public static int SystemPageSize } } + /// Gets the number of milliseconds elapsed since the system started. + /// A 32-bit signed integer containing the amount of time in milliseconds that has passed since the last time the computer was started. + public static int TickCount => (int)TickCount64; + private static bool ValidateAndConvertRegistryTarget(EnvironmentVariableTarget target) { Debug.Assert(target != EnvironmentVariableTarget.Process); diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve2.PlatformNotSupported.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve2.PlatformNotSupported.cs index 5fe0e2293205a1..3b3ae004a4784e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve2.PlatformNotSupported.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve2.PlatformNotSupported.cs @@ -77,5 +77,55 @@ internal Arm64() { } /// BCAX Ztied1.D, Ztied1.D, Zop2.D, Zop3.D /// public static unsafe Vector BitwiseClearXor(Vector xor, Vector value, Vector mask) { throw new PlatformNotSupportedException(); } + + // Shift left and insert + + /// + /// svuint8_t svsli[_n_u8](svuint8_t op1, svuint8_t op2, uint64_t imm3) + /// SLI Ztied1.B, Zop2.B, #imm3 + /// + public static Vector ShiftLeftAndInsert(Vector left, Vector right, [ConstantExpected] byte shift) { throw new PlatformNotSupportedException(); } + + /// + /// svint16_t svsli[_n_s16](svint16_t op1, svint16_t op2, uint64_t imm3) + /// SLI Ztied1.H, Zop2.H, #imm3 + /// + public static Vector ShiftLeftAndInsert(Vector left, Vector right, [ConstantExpected] byte shift) { throw new PlatformNotSupportedException(); } + + /// + /// svint32_t svsli[_n_s32](svint32_t op1, svint32_t op2, uint64_t imm3) + /// SLI Ztied1.S, Zop2.S, #imm3 + /// + public static Vector ShiftLeftAndInsert(Vector left, Vector right, [ConstantExpected] byte shift) { throw new PlatformNotSupportedException(); } + + /// + /// svint64_t svsli[_n_s64](svint64_t op1, svint64_t op2, uint64_t imm3) + /// SLI Ztied1.D, Zop2.D, #imm3 + /// + public static Vector ShiftLeftAndInsert(Vector left, Vector right, [ConstantExpected] byte shift) { throw new PlatformNotSupportedException(); } + + /// + /// svint8_t svsli[_n_s8](svint8_t op1, svint8_t op2, uint64_t imm3) + /// SLI Ztied1.B, Zop2.B, #imm3 + /// + public static Vector ShiftLeftAndInsert(Vector left, Vector right, [ConstantExpected] byte shift) { throw new PlatformNotSupportedException(); } + + /// + /// svuint16_t svsli[_n_u16](svuint16_t op1, svuint16_t op2, uint64_t imm3) + /// SLI Ztied1.H, Zop2.H, #imm3 + /// + public static Vector ShiftLeftAndInsert(Vector left, Vector right, [ConstantExpected] byte shift) { throw new PlatformNotSupportedException(); } + + /// + /// svuint32_t svsli[_n_u32](svuint32_t op1, svuint32_t op2, uint64_t imm3) + /// SLI Ztied1.S, Zop2.S, #imm3 + /// + public static Vector ShiftLeftAndInsert(Vector left, Vector right, [ConstantExpected] byte shift) { throw new PlatformNotSupportedException(); } + + /// + /// svuint64_t svsli[_n_u64](svuint64_t op1, svuint64_t op2, uint64_t imm3) + /// SLI Ztied1.D, Zop2.D, #imm3 + /// + public static Vector ShiftLeftAndInsert(Vector left, Vector right, [ConstantExpected] byte shift) { throw new PlatformNotSupportedException(); } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve2.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve2.cs index 3a6340fb693c8a..8d70bea17d6c44 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve2.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Sve2.cs @@ -77,5 +77,55 @@ internal Arm64() { } /// BCAX Ztied1.D, Ztied1.D, Zop2.D, Zop3.D /// public static unsafe Vector BitwiseClearXor(Vector xor, Vector value, Vector mask) => BitwiseClearXor(xor, value, mask); + + // Shift left and insert + + /// + /// svuint8_t svsli[_n_u8](svuint8_t op1, svuint8_t op2, uint64_t imm3) + /// SLI Ztied1.B, Zop2.B, #imm3 + /// + public static Vector ShiftLeftAndInsert(Vector left, Vector right, [ConstantExpected] byte shift) => ShiftLeftAndInsert(left, right, shift); + + /// + /// svint16_t svsli[_n_s16](svint16_t op1, svint16_t op2, uint64_t imm3) + /// SLI Ztied1.H, Zop2.H, #imm3 + /// + public static Vector ShiftLeftAndInsert(Vector left, Vector right, [ConstantExpected] byte shift) => ShiftLeftAndInsert(left, right, shift); + + /// + /// svint32_t svsli[_n_s32](svint32_t op1, svint32_t op2, uint64_t imm3) + /// SLI Ztied1.S, Zop2.S, #imm3 + /// + public static Vector ShiftLeftAndInsert(Vector left, Vector right, [ConstantExpected] byte shift) => ShiftLeftAndInsert(left, right, shift); + + /// + /// svint64_t svsli[_n_s64](svint64_t op1, svint64_t op2, uint64_t imm3) + /// SLI Ztied1.D, Zop2.D, #imm3 + /// + public static Vector ShiftLeftAndInsert(Vector left, Vector right, [ConstantExpected] byte shift) => ShiftLeftAndInsert(left, right, shift); + + /// + /// svint8_t svsli[_n_s8](svint8_t op1, svint8_t op2, uint64_t imm3) + /// SLI Ztied1.B, Zop2.B, #imm3 + /// + public static Vector ShiftLeftAndInsert(Vector left, Vector right, [ConstantExpected] byte shift) => ShiftLeftAndInsert(left, right, shift); + + /// + /// svuint16_t svsli[_n_u16](svuint16_t op1, svuint16_t op2, uint64_t imm3) + /// SLI Ztied1.H, Zop2.H, #imm3 + /// + public static Vector ShiftLeftAndInsert(Vector left, Vector right, [ConstantExpected] byte shift) => ShiftLeftAndInsert(left, right, shift); + + /// + /// svuint32_t svsli[_n_u32](svuint32_t op1, svuint32_t op2, uint64_t imm3) + /// SLI Ztied1.S, Zop2.S, #imm3 + /// + public static Vector ShiftLeftAndInsert(Vector left, Vector right, [ConstantExpected] byte shift) => ShiftLeftAndInsert(left, right, shift); + + /// + /// svuint64_t svsli[_n_u64](svuint64_t op1, svuint64_t op2, uint64_t imm3) + /// SLI Ztied1.D, Zop2.D, #imm3 + /// + public static Vector ShiftLeftAndInsert(Vector left, Vector right, [ConstantExpected] byte shift) => ShiftLeftAndInsert(left, right, shift); } } diff --git a/src/libraries/System.Private.Xml/tests/XmlSerializer/XmlSerializerTests.cs b/src/libraries/System.Private.Xml/tests/XmlSerializer/XmlSerializerTests.cs index 4166f6942f7729..0d94c9fb861b25 100644 --- a/src/libraries/System.Private.Xml/tests/XmlSerializer/XmlSerializerTests.cs +++ b/src/libraries/System.Private.Xml/tests/XmlSerializer/XmlSerializerTests.cs @@ -2303,7 +2303,7 @@ public static void Xml_TypeWithSpecialCharacterInStringMember() Assert.Equal(x.Name, y.Name); } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] #if XMLSERIALIZERGENERATORTESTS // Lack of AssemblyDependencyResolver results in assemblies that are not loaded by path to get // loaded in the default ALC, which causes problems for this test. diff --git a/src/libraries/System.Reflection.Emit/tests/ModuleBuilder/ModuleBuilderDefineEnum.cs b/src/libraries/System.Reflection.Emit/tests/ModuleBuilder/ModuleBuilderDefineEnum.cs index 8bce42af9fac05..4e1f762cae074d 100644 --- a/src/libraries/System.Reflection.Emit/tests/ModuleBuilder/ModuleBuilderDefineEnum.cs +++ b/src/libraries/System.Reflection.Emit/tests/ModuleBuilder/ModuleBuilderDefineEnum.cs @@ -76,7 +76,7 @@ public void DefineEnum(string name, TypeAttributes visibility, Type underlyingTy Assert.Equal(FieldAttributes.Public | FieldAttributes.SpecialName | FieldAttributes.RTSpecialName, createdUnderlyingField.Attributes); } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] [MemberData(nameof(DefineEnum_TestData))] public void DefineEnumPersistedAssembly(string name, TypeAttributes visibility, Type underlyingType) { @@ -103,7 +103,7 @@ public void DefineEnumPersistedAssembly(string name, TypeAttributes visibility, ab.Save(stream); Assembly assemblyFromStream = mlc.LoadFromStream(stream); Type createdEnum = assemblyFromStream.GetType(name); - if (createdEnum != null) // null when name = "a\0b\0c" + if (createdEnum != null) // null when name = "a\0b\0c" { Assert.True(createdEnum.IsEnum); Assert.Equal(Helpers.GetFullName(name), createdEnum.Name); diff --git a/src/libraries/System.Reflection.Emit/tests/ModuleBuilder/ModuleBuilderDefineType.cs b/src/libraries/System.Reflection.Emit/tests/ModuleBuilder/ModuleBuilderDefineType.cs index cc68471251d56c..48cc610dd8eb86 100644 --- a/src/libraries/System.Reflection.Emit/tests/ModuleBuilder/ModuleBuilderDefineType.cs +++ b/src/libraries/System.Reflection.Emit/tests/ModuleBuilder/ModuleBuilderDefineType.cs @@ -95,7 +95,7 @@ void Verify(TypeBuilder type, Module module) } } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] [MemberData(nameof(TestData))] public void DefineTypePersistedAssembly(string name, TypeAttributes attributes, Type parent, PackingSize packingSize, int typesize, Type[] implementedInterfaces) { diff --git a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveAssemblyBuilderTests.cs b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveAssemblyBuilderTests.cs index 256039267a529c..4b909cca5300f8 100644 --- a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveAssemblyBuilderTests.cs +++ b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveAssemblyBuilderTests.cs @@ -14,7 +14,7 @@ namespace System.Reflection.Emit.Tests { - [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public class AssemblySaveAssemblyBuilderTests { private readonly AssemblyName _assemblyName = new AssemblyName("MyAssembly"); @@ -305,7 +305,7 @@ public void AssemblyWithDifferentTypes() [Theory] [ActiveIssue("https://github.com/dotnet/runtime/issues/113789", TestRuntimes.Mono)] - [InlineData(true)] + [InlineData(true)] [InlineData(false)] public unsafe void AssemblyWithInstanceBasedFunctionPointer(bool useExplicitThis) { @@ -350,7 +350,7 @@ static unsafe byte[] GenerateMethodInPersistedAssembly(bool useExplicitThis) // In this test, we use typeof(object) for the "this" pointer to ensure the IL could be re-used for other // reference types, but normally this would be the appropriate type such as typeof(MyClassWithGuidProperty). - parameterTypes: [typeof(object), typeof(IntPtr)]); + parameterTypes: [typeof(object), typeof(IntPtr)]); ILGenerator il = methodBuilder.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); // this @@ -489,7 +489,7 @@ void CheckAssembly(Assembly a) Assert.Equal(42, field.GetRawConstantValue()); field = type4.GetField("FieldOffset"); Assert.NotNull(field); - + field = type4.GetField("FieldModopt"); var cmods = field.GetRequiredCustomModifiers(); Assert.Equal(1, cmods.Length); diff --git a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveConstructorBuilderTests.cs b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveConstructorBuilderTests.cs index 34fe5c2aec3278..1b061f5fabbc3b 100644 --- a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveConstructorBuilderTests.cs +++ b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveConstructorBuilderTests.cs @@ -7,7 +7,7 @@ namespace System.Reflection.Emit.Tests { - [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public class AssemblySaveConstructorBuilderTests { [Fact] diff --git a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveCustomAttributeTests.cs b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveCustomAttributeTests.cs index 1fd2d53188361a..89d496684e8099 100644 --- a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveCustomAttributeTests.cs +++ b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveCustomAttributeTests.cs @@ -11,7 +11,7 @@ namespace System.Reflection.Emit.Tests { - [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public class AssemblySaveCustomAttributeTests { private List _attributes = new List @@ -208,7 +208,7 @@ public void CreateStructWithPseudoCustomAttributesTest() Type testType = moduleFromDisk.GetTypes()[0]; IList attributesFromDisk = testType.GetCustomAttributesData(); - Assert.Equal(typeAttributes.Count - 3, attributesFromDisk.Count); // 3 pseudo attributes + Assert.Equal(typeAttributes.Count - 3, attributesFromDisk.Count); // 3 pseudo attributes Assert.True((testType.Attributes & TypeAttributes.Serializable) != 0); // SerializableAttribute Assert.True((testType.Attributes & TypeAttributes.SpecialName) != 0); // SpecialNameAttribute Assert.True((testType.Attributes & TypeAttributes.ExplicitLayout) != 0); // StructLayoutAttribute diff --git a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveEnumBuilderTests.cs b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveEnumBuilderTests.cs index b10126675568e3..809a3e5a1bb011 100644 --- a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveEnumBuilderTests.cs +++ b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveEnumBuilderTests.cs @@ -8,7 +8,7 @@ namespace System.Reflection.Emit.Tests { - [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public class AssemblySaveEnumBuilderTests { private static AssemblyName PopulateAssemblyName() diff --git a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveEventBuilderTests.cs b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveEventBuilderTests.cs index f4692afe194986..8f8e5cfbd75420 100644 --- a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveEventBuilderTests.cs +++ b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveEventBuilderTests.cs @@ -9,7 +9,7 @@ namespace System.Reflection.Emit.Tests { - [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public class AssemblySaveEventBuilderTests { [Fact] diff --git a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveILGeneratorTests.cs b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveILGeneratorTests.cs index 2b155556c5f2ab..39d0f74aae4534 100644 --- a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveILGeneratorTests.cs +++ b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveILGeneratorTests.cs @@ -10,7 +10,7 @@ namespace System.Reflection.Emit.Tests { - [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public class AssemblySaveILGeneratorTests { [Fact] @@ -219,7 +219,7 @@ public void ILMaxStack_Test() il1.Emit(OpCodes.Ldarg_2); // push 1 MaxStack 7 il1.Emit(OpCodes.Ldc_I4_5); // push 1 MaxStack 8 il1.Emit(OpCodes.Ldarg_1); // push 1 MaxStack 9 - il1.Emit(OpCodes.Add); // pop 2 push 1 stack size 8 + il1.Emit(OpCodes.Add); // pop 2 push 1 stack size 8 il1.Emit(OpCodes.Sub); // pop 2 push 1 stack size 7 il1.Emit(OpCodes.Mul); // pop 2 push 1 stack size 6 il1.Emit(OpCodes.Add); // pop 2 push 1 stack size 5 @@ -630,7 +630,7 @@ public void ReferenceFieldAndMethodsInIL() MethodBuilder methodMultiply = tb.DefineMethod("Multiply", MethodAttributes.Public, typeof(int), [typeof(int)]); /* class MyType - { + { private int _field; int Multiply(int value) => _field * value; void Main(int a) @@ -643,7 +643,7 @@ void Main(int a) ILGenerator il = methodMultiply.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, field); - il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Mul); il.Emit(OpCodes.Ret); @@ -888,7 +888,7 @@ public void ReferenceStaticFieldAndMethodsInIL() FieldBuilder field = anotherType.DefineField("StaticField", typeof(int), FieldAttributes.Public | FieldAttributes.Static); MethodBuilder staticMethod = anotherType.DefineMethod("StaticMethod", MethodAttributes.Public | MethodAttributes.Static, typeof(void), Type.EmptyTypes); /*class MyType - { + { int Main(int a) { AnotherType.StaticField = a; @@ -2327,7 +2327,7 @@ static void GetCode() // Unreachable. ilg.Emit(OpCodes.Ldarg_0); - // Depth + // Depth ilg.MarkLabel(lab); ilg.Emit(OpCodes.Add); ilg.Emit(OpCodes.Ret); diff --git a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveModuleBuilderTests.cs b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveModuleBuilderTests.cs index 0c8a7a2aae81cf..0731f8754f964b 100644 --- a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveModuleBuilderTests.cs +++ b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveModuleBuilderTests.cs @@ -7,7 +7,7 @@ namespace System.Reflection.Emit.Tests { - [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public class AssemblySaveModuleBuilderTests { [Fact] diff --git a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySavePropertyBuilderTests.cs b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySavePropertyBuilderTests.cs index 6bff85e29e928e..60dfad0dcd0775 100644 --- a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySavePropertyBuilderTests.cs +++ b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySavePropertyBuilderTests.cs @@ -10,7 +10,7 @@ namespace System.Reflection.Emit.Tests { - [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public class AssemblySavePropertyBuilderTests { [Fact] diff --git a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveTypeBuilderAPIsTests.cs b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveTypeBuilderAPIsTests.cs index 9cf05f68a6f71e..74ab67d8d60622 100644 --- a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveTypeBuilderAPIsTests.cs +++ b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveTypeBuilderAPIsTests.cs @@ -9,7 +9,7 @@ namespace System.Reflection.Emit.Tests { - [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public class AssemblySaveTypeBuilderAPIsTests { [Fact] diff --git a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveTypeBuilderTests.cs b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveTypeBuilderTests.cs index b052a2861961b6..1894d8d5f35b86 100644 --- a/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveTypeBuilderTests.cs +++ b/src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveTypeBuilderTests.cs @@ -11,7 +11,7 @@ namespace System.Reflection.Emit.Tests { - [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public class AssemblySaveTypeBuilderTests { private static readonly AssemblyName s_assemblyName = new AssemblyName("MyDynamicAssembly") diff --git a/src/libraries/System.Reflection.Emit/tests/TypeBuilder/TypeBuilderDefineField.cs b/src/libraries/System.Reflection.Emit/tests/TypeBuilder/TypeBuilderDefineField.cs index 4b7613157c3c2a..19481655258161 100644 --- a/src/libraries/System.Reflection.Emit/tests/TypeBuilder/TypeBuilderDefineField.cs +++ b/src/libraries/System.Reflection.Emit/tests/TypeBuilder/TypeBuilderDefineField.cs @@ -60,7 +60,7 @@ public void DefineField(string name, Type fieldType, FieldAttributes attributes, } } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] [MemberData(nameof(TestData))] public void DefineFieldPersistedAssembly(string name, Type fieldType, FieldAttributes attributes, FieldAttributes expectedAttributes) { @@ -108,7 +108,7 @@ public void DefineField_NameCollision() Assert.Throws(() => createdType.GetField("FieldName", Helpers.AllFlags)); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public void DefineField_NameCollisionPersistedAssembly() { PersistedAssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); @@ -144,7 +144,7 @@ public void DefineField_65536Fields() Assert.Throws(() => type.CreateType()); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public void DefineField_65536FieldsPersistedAssembly() { PersistedAssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); @@ -179,7 +179,7 @@ public void DefineFieldMethod_LongName() Assert.Equal(Helpers.s_512Chars, method.Name); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public void DefineFieldMethod_LongNamePersistedAssembly() { PersistedAssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); diff --git a/src/libraries/System.Reflection.Emit/tests/TypeBuilder/TypeBuilderDefineMethod.cs b/src/libraries/System.Reflection.Emit/tests/TypeBuilder/TypeBuilderDefineMethod.cs index 1694945863f92b..9989ef29c60598 100644 --- a/src/libraries/System.Reflection.Emit/tests/TypeBuilder/TypeBuilderDefineMethod.cs +++ b/src/libraries/System.Reflection.Emit/tests/TypeBuilder/TypeBuilderDefineMethod.cs @@ -95,7 +95,7 @@ public void DefineMethod(string name, MethodAttributes attributes, CallingConven VerifyMethod(type4, method4, name, attributes, callingConvention, returnType, parameterTypes); } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] [MemberData(nameof(TestData))] public void DefineMethodPersistedAssembly(string name, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] parameterTypes) { @@ -136,10 +136,10 @@ public void DefineMethod_65536Methods() // System.TypeLoadException : Type 'TestType' from assembly 'TestAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' // contains more methods than the current implementation allows. - Assert.Throws(() => type.CreateType()); + Assert.Throws(() => type.CreateType()); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] [ActiveIssue("https://github.com/dotnet/runtime/issues/2389", TestRuntimes.Mono)] public void DefineMethod_65536MethodsPersistedAssembly() { diff --git a/src/libraries/System.Reflection.Emit/tests/TypeBuilder/TypeBuilderDefineProperty.cs b/src/libraries/System.Reflection.Emit/tests/TypeBuilder/TypeBuilderDefineProperty.cs index 99d0d572eb418f..011e2308a1f372 100644 --- a/src/libraries/System.Reflection.Emit/tests/TypeBuilder/TypeBuilderDefineProperty.cs +++ b/src/libraries/System.Reflection.Emit/tests/TypeBuilder/TypeBuilderDefineProperty.cs @@ -50,7 +50,7 @@ public void DefineProperty(string name, PropertyAttributes attributes, Type retu Assert.Equal(returnType ?? typeof(void), createdProperty.PropertyType); } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] [MemberData(nameof(TestData))] public void DefinePropertyPersistedAssembly(string name, PropertyAttributes attributes, Type returnType, Type[] parameterTypes, string expectedName, PropertyAttributes _) { @@ -91,10 +91,10 @@ public void DefineProperty_NameCollision() Assert.Equal(2, properties.Length); Assert.Equal("PropertyName", properties[0].Name); Assert.Equal("PropertyName", properties[1].Name); - Assert.Throws(() => createdType.GetProperty("PropertyName", Helpers.AllFlags)); + Assert.Throws(() => createdType.GetProperty("PropertyName", Helpers.AllFlags)); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public void DefineProperty_NameCollisionPersistedAssembly() { PersistedAssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); diff --git a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs index e3a88048723b6e..95c6db474d586e 100644 --- a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs +++ b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs @@ -6047,6 +6047,14 @@ internal Arm64() { } public static System.Numerics.Vector BitwiseClearXor(System.Numerics.Vector xor, System.Numerics.Vector value, System.Numerics.Vector mask) { throw null; } public static System.Numerics.Vector BitwiseClearXor(System.Numerics.Vector xor, System.Numerics.Vector value, System.Numerics.Vector mask) { throw null; } public static System.Numerics.Vector BitwiseClearXor(System.Numerics.Vector xor, System.Numerics.Vector value, System.Numerics.Vector mask) { throw null; } + public static System.Numerics.Vector ShiftLeftAndInsert(System.Numerics.Vector left, System.Numerics.Vector right, [ConstantExpected] byte shift) { throw null; } + public static System.Numerics.Vector ShiftLeftAndInsert(System.Numerics.Vector left, System.Numerics.Vector right, [ConstantExpected] byte shift) { throw null; } + public static System.Numerics.Vector ShiftLeftAndInsert(System.Numerics.Vector left, System.Numerics.Vector right, [ConstantExpected] byte shift) { throw null; } + public static System.Numerics.Vector ShiftLeftAndInsert(System.Numerics.Vector left, System.Numerics.Vector right, [ConstantExpected] byte shift) { throw null; } + public static System.Numerics.Vector ShiftLeftAndInsert(System.Numerics.Vector left, System.Numerics.Vector right, [ConstantExpected] byte shift) { throw null; } + public static System.Numerics.Vector ShiftLeftAndInsert(System.Numerics.Vector left, System.Numerics.Vector right, [ConstantExpected] byte shift) { throw null; } + public static System.Numerics.Vector ShiftLeftAndInsert(System.Numerics.Vector left, System.Numerics.Vector right, [ConstantExpected] byte shift) { throw null; } + public static System.Numerics.Vector ShiftLeftAndInsert(System.Numerics.Vector left, System.Numerics.Vector right, [ConstantExpected] byte shift) { throw null; } } public enum SveMaskPattern : byte diff --git a/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs b/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs index 00e924fcb47b0a..3292f12de6d7b8 100644 --- a/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs +++ b/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; using System.IO; using System.Reflection; using System.Reflection.Emit; @@ -106,8 +107,7 @@ public static void LoadFromAssemblyName_AssemblyNotFound() Assert.Throws(() => loadContext.LoadFromAssemblyName(asmName)); } - [Fact] - [SkipOnPlatform(TestPlatforms.Browser, "Corelib does not exist on disc for Browser builds")] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public static void LoadFromAssemblyName_ValidTrustedPlatformAssembly() { var asmName = typeof(System.Linq.Enumerable).Assembly.GetName(); diff --git a/src/libraries/System.Runtime.Loader/tests/ContextualReflection.cs b/src/libraries/System.Runtime.Loader/tests/ContextualReflection.cs index 1d61dbd4afd493..8e035c8038b4bc 100644 --- a/src/libraries/System.Runtime.Loader/tests/ContextualReflection.cs +++ b/src/libraries/System.Runtime.Loader/tests/ContextualReflection.cs @@ -144,6 +144,7 @@ public void FixtureSetupAssertions() } [ActiveIssue("https://github.com/mono/mono/issues/15142", TestRuntimes.Mono)] + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public class ContextualReflectionTest : IClassFixture { IContextualReflectionTestFixture _fixture; diff --git a/src/libraries/System.Runtime.Loader/tests/DefaultContext/DefaultLoadContextTest.cs b/src/libraries/System.Runtime.Loader/tests/DefaultContext/DefaultLoadContextTest.cs index 227f4d9111a1ff..ab0814f4e1e7be 100644 --- a/src/libraries/System.Runtime.Loader/tests/DefaultContext/DefaultLoadContextTest.cs +++ b/src/libraries/System.Runtime.Loader/tests/DefaultContext/DefaultLoadContextTest.cs @@ -85,7 +85,7 @@ private Assembly ResolveNullAssembly(AssemblyLoadContext sender, AssemblyName as // Does not apply to Mono AOT scenarios as it is expected the name of the .aotdata file matches // the true name of the assembly and not the physical file name. - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMonoAOT))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMonoAOT), nameof(PlatformDetection.HasAssemblyFiles))] public void LoadInDefaultContext() { // This will attempt to load an assembly, by path, in the Default Load context via the Resolving event diff --git a/src/libraries/System.Runtime.Loader/tests/RefEmitLoadContext/RefEmitLoadContextTest.cs b/src/libraries/System.Runtime.Loader/tests/RefEmitLoadContext/RefEmitLoadContextTest.cs index 1863ad3767d1f1..3694e501adb48d 100644 --- a/src/libraries/System.Runtime.Loader/tests/RefEmitLoadContext/RefEmitLoadContextTest.cs +++ b/src/libraries/System.Runtime.Loader/tests/RefEmitLoadContext/RefEmitLoadContextTest.cs @@ -64,7 +64,7 @@ private static void DeleteDirectory() catch { } } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] [ActiveIssue("https://github.com/dotnet/runtime/issues/31804", TestRuntimes.Mono)] public static void LoadRefEmitAssembly() { diff --git a/src/libraries/System.Runtime.Serialization.Xml/tests/DataContractSerializer.cs b/src/libraries/System.Runtime.Serialization.Xml/tests/DataContractSerializer.cs index 91afc052ae742c..7f5599020944f7 100644 --- a/src/libraries/System.Runtime.Serialization.Xml/tests/DataContractSerializer.cs +++ b/src/libraries/System.Runtime.Serialization.Xml/tests/DataContractSerializer.cs @@ -1116,7 +1116,7 @@ public static void DCS_TypeNamesWithSpecialCharacters() Assert.Equal(x.PropertyNameWithSpecialCharacters\u6F22\u00F1, y.PropertyNameWithSpecialCharacters\u6F22\u00F1); } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] #if XMLSERIALIZERGENERATORTESTS // Lack of AssemblyDependencyResolver results in assemblies that are not loaded by path to get // loaded in the default ALC, which causes problems for this test. @@ -1135,7 +1135,7 @@ public static void DCS_TypeInCollectibleALC() Assert.True(!weakRef.IsAlive); } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] #if XMLSERIALIZERGENERATORTESTS // Lack of AssemblyDependencyResolver results in assemblies that are not loaded by path to get // loaded in the default ALC, which causes problems for this test. diff --git a/src/libraries/System.Runtime/tests/System.Globalization.Calendars.Tests/CalendarTestWithConfigSwitch/CalendarTests.cs b/src/libraries/System.Runtime/tests/System.Globalization.Calendars.Tests/CalendarTestWithConfigSwitch/CalendarTests.cs index 4d1205811b8608..804a3a55b270ae 100644 --- a/src/libraries/System.Runtime/tests/System.Globalization.Calendars.Tests/CalendarTestWithConfigSwitch/CalendarTests.cs +++ b/src/libraries/System.Runtime/tests/System.Globalization.Calendars.Tests/CalendarTestWithConfigSwitch/CalendarTests.cs @@ -10,6 +10,7 @@ namespace System.Globalization.Tests public static class CalendarTests { [Fact] + [SkipOnPlatform(TestPlatforms.Android, "Doesn't throw on mobile")] public static void TestJapaneseCalendarDateParsing() { CultureInfo ciJapanese = new CultureInfo("ja-JP") { DateTimeFormat = { Calendar = new JapaneseCalendar() } }; diff --git a/src/libraries/System.Runtime/tests/System.Globalization.Tests/CultureInfo/CultureInfoCurrentCulture.cs b/src/libraries/System.Runtime/tests/System.Globalization.Tests/CultureInfo/CultureInfoCurrentCulture.cs index f7fa352690c3f4..c13c8446ffa89c 100644 --- a/src/libraries/System.Runtime/tests/System.Globalization.Tests/CultureInfo/CultureInfoCurrentCulture.cs +++ b/src/libraries/System.Runtime/tests/System.Globalization.Tests/CultureInfo/CultureInfoCurrentCulture.cs @@ -130,9 +130,7 @@ public void CurrentUICulture_Set_Null_ThrowsArgumentNullException() public void CurrentCulture_BasedOnLangEnvVar(string langEnvVar, string expectedCultureName) { var psi = new ProcessStartInfo(); - psi.Environment.Clear(); - - CopyEssentialTestEnvironment(psi.Environment); + TestEnvironment.ClearGlobalizationEnvironmentVars(psi.Environment); psi.Environment["LANG"] = langEnvVar; @@ -154,9 +152,7 @@ public void CurrentCulture_BasedOnLangEnvVar(string langEnvVar, string expectedC public void CurrentCulture_DefaultWithNoLang(string langEnvVar) { var psi = new ProcessStartInfo(); - psi.Environment.Clear(); - - CopyEssentialTestEnvironment(psi.Environment); + TestEnvironment.ClearGlobalizationEnvironmentVars(psi.Environment); if (langEnvVar != null) { @@ -187,20 +183,5 @@ public void CurrentCulture_DefaultWithNoLang(string langEnvVar) } }, new RemoteInvokeOptions { StartInfo = psi }).Dispose(); } - - private static void CopyEssentialTestEnvironment(IDictionary environment) - { - string[] essentialVariables = { "HOME", "LD_LIBRARY_PATH", "ICU_DATA" }; - string[] prefixedVariables = { "DOTNET_", "COMPlus_", "SuperPMIShim" }; - - foreach (DictionaryEntry de in Environment.GetEnvironmentVariables()) - { - if (Array.FindIndex(essentialVariables, x => x.Equals(de.Key)) >= 0 || - Array.FindIndex(prefixedVariables, x => ((string)de.Key).StartsWith(x, StringComparison.OrdinalIgnoreCase)) >= 0) - { - environment[(string)de.Key] = (string)de.Value; - } - } - } } } diff --git a/src/libraries/System.Runtime/tests/System.Globalization.Tests/CultureInfo/GetCultureInfo.cs b/src/libraries/System.Runtime/tests/System.Globalization.Tests/CultureInfo/GetCultureInfo.cs index ee72d3cdfc8bbb..8cc558389aa9b0 100644 --- a/src/libraries/System.Runtime/tests/System.Globalization.Tests/CultureInfo/GetCultureInfo.cs +++ b/src/libraries/System.Runtime/tests/System.Globalization.Tests/CultureInfo/GetCultureInfo.cs @@ -147,7 +147,7 @@ public void TestFakeCultureNames(string name) public void PredefinedCulturesOnlyEnvVarTest(string predefinedCulturesOnlyEnvVar, string cultureName) { var psi = new ProcessStartInfo(); - psi.Environment.Clear(); + TestEnvironment.ClearGlobalizationEnvironmentVars(psi.Environment); psi.Environment.Add("DOTNET_SYSTEM_GLOBALIZATION_PREDEFINED_CULTURES_ONLY", predefinedCulturesOnlyEnvVar); @@ -176,7 +176,7 @@ public void PredefinedCulturesOnlyEnvVarTest(string predefinedCulturesOnlyEnvVar public void TestAllowInvariantCultureOnly(bool enableInvariant, bool predefinedCulturesOnly, bool declarePredefinedCulturesOnly) { var psi = new ProcessStartInfo(); - psi.Environment.Clear(); + TestEnvironment.ClearGlobalizationEnvironmentVars(psi.Environment); if (enableInvariant) { diff --git a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/DisabledFileLockingTests/DisabledFileLockingSwitchTests.cs b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/DisabledFileLockingTests/DisabledFileLockingSwitchTests.cs index 736991961ac96e..8b83bae43f2f65 100644 --- a/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/DisabledFileLockingTests/DisabledFileLockingSwitchTests.cs +++ b/src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/DisabledFileLockingTests/DisabledFileLockingSwitchTests.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; using Xunit; namespace System.IO.Tests @@ -8,6 +9,7 @@ namespace System.IO.Tests public class DisabledFileLockingSwitchTests { [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/114951", typeof(PlatformDetection), nameof(PlatformDetection.IsSingleFile))] public static void ConfigSwitchIsHonored() { Assert.Equal(OperatingSystem.IsWindows(), PlatformDetection.IsFileLockingEnabled); diff --git a/src/libraries/System.Runtime/tests/System.Reflection.Tests/AssemblyTests.cs b/src/libraries/System.Runtime/tests/System.Reflection.Tests/AssemblyTests.cs index 57a5e1277fcfe9..eff32bc09ffe5f 100644 --- a/src/libraries/System.Runtime/tests/System.Reflection.Tests/AssemblyTests.cs +++ b/src/libraries/System.Runtime/tests/System.Reflection.Tests/AssemblyTests.cs @@ -39,7 +39,7 @@ public class AssemblyTests : FileCleanupTestBase public AssemblyTests() { - if (PlatformDetection.IsAssemblyLoadingSupported) + if (PlatformDetection.IsAssemblyLoadingSupported && PlatformDetection.HasAssemblyFiles) { // Assembly.Location does not return the file path for single-file deployment targets. DestTestAssemblyPath = Path.Combine(base.TestDirectory, s_sourceTestAssemblyName); @@ -229,7 +229,7 @@ public void GetFile() } } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported), nameof(PlatformDetection.HasAssemblyFiles))] public void GetFile_InMemory() { var inMemBlob = File.ReadAllBytes(SourceTestAssemblyPath); @@ -241,7 +241,7 @@ public void GetFile_InMemory() Assert.Throws(() => asm.GetFiles(getResourceModules: false)); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported), nameof(PlatformDetection.HasAssemblyFiles))] public void CodeBaseInMemory() { var inMemBlob = File.ReadAllBytes(SourceTestAssemblyPath); @@ -392,7 +392,7 @@ public void Load_Invalid() Assert.Throws(() => Assembly.Load(new AssemblyName("no such assembly"))); // No such assembly } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported), nameof(PlatformDetection.HasAssemblyFiles))] public void LoadFile() { Assembly currentAssembly = typeof(AssemblyTests).Assembly; @@ -416,20 +416,20 @@ public void LoadFile() Assert.Equal(loadedAssembly1, loadedAssembly2); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported), nameof(PlatformDetection.HasAssemblyFiles))] public void LoadFile_NullPath_ThrowsArgumentNullException() { AssertExtensions.Throws("path", () => Assembly.LoadFile(null)); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported), nameof(PlatformDetection.HasAssemblyFiles))] public void LoadFile_NoSuchPath_ThrowsFileNotFoundException() { string rootedPath = Path.GetFullPath(Guid.NewGuid().ToString("N")); AssertExtensions.ThrowsContains(() => Assembly.LoadFile(rootedPath), rootedPath); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported), nameof(PlatformDetection.HasAssemblyFiles))] public void LoadFile_PartiallyQualifiedPath_ThrowsArgumentException() { string path = "System.Runtime.Tests.dll"; @@ -439,7 +439,7 @@ public void LoadFile_PartiallyQualifiedPath_ThrowsArgumentException() // This test should apply equally to Unix, but this reliably hits a particular one of the // myriad ways that assembly load can fail - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported), nameof(PlatformDetection.HasAssemblyFiles))] [PlatformSpecific(TestPlatforms.Windows)] public void LoadFile_ValidPEBadIL_ThrowsBadImageFormatExceptionWithPath() { @@ -450,7 +450,7 @@ public void LoadFile_ValidPEBadIL_ThrowsBadImageFormatExceptionWithPath() AssertExtensions.ThrowsContains(() => Assembly.LoadFile(path), path); } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported), nameof(PlatformDetection.HasAssemblyFiles))] [InlineData(0)] [InlineData(5)] [InlineData(50)] @@ -471,20 +471,20 @@ public void LoadFile_ValidPEBadIL_ThrowsBadImageFormatExceptionWithPath_ByInitia } #pragma warning disable SYSLIB0056 // AssemblyHashAlgorithm overload is not supported and throws NotSupportedException. - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported), nameof(PlatformDetection.HasAssemblyFiles))] public void LoadFromUsingHashValue() { Assert.Throws(() => Assembly.LoadFrom("abc", null, System.Configuration.Assemblies.AssemblyHashAlgorithm.SHA1)); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported), nameof(PlatformDetection.HasAssemblyFiles))] public void LoadFrom_WithHashValue_ThrowsNotSupportedException() { Assert.Throws(() => Assembly.LoadFrom(DestTestAssemblyPath, new byte[0], Configuration.Assemblies.AssemblyHashAlgorithm.None)); } #pragma warning restore SYSLIB0056 // AssemblyHashAlgorithm overload is not supported and throws NotSupportedException. - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported), nameof(PlatformDetection.HasAssemblyFiles))] public void LoadFrom_SamePath_ReturnsEqualAssemblies() { Assembly assembly1 = Assembly.LoadFrom(DestTestAssemblyPath); @@ -492,7 +492,7 @@ public void LoadFrom_SamePath_ReturnsEqualAssemblies() Assert.Equal(assembly1, assembly2); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported), nameof(PlatformDetection.HasAssemblyFiles))] public void LoadFrom_SameIdentityAsAssemblyWithDifferentPath_ReturnsEqualAssemblies() { Assembly assembly1 = Assembly.LoadFrom(AssemblyPathHelper.GetAssemblyLocation(typeof(AssemblyTests).Assembly)); @@ -503,28 +503,28 @@ public void LoadFrom_SameIdentityAsAssemblyWithDifferentPath_ReturnsEqualAssembl Assert.Equal(assembly1, assembly2); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported), nameof(PlatformDetection.HasAssemblyFiles))] public void LoadFrom_NullAssemblyFile_ThrowsArgumentNullException() { AssertExtensions.Throws("assemblyFile", () => Assembly.LoadFrom(null)); AssertExtensions.Throws("assemblyFile", () => Assembly.UnsafeLoadFrom(null)); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported), nameof(PlatformDetection.HasAssemblyFiles))] public void LoadFrom_EmptyAssemblyFile_ThrowsArgumentException() { AssertExtensions.Throws("path", null, (() => Assembly.LoadFrom(""))); AssertExtensions.Throws("path", null, (() => Assembly.UnsafeLoadFrom(""))); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported), nameof(PlatformDetection.HasAssemblyFiles))] public void LoadFrom_NoSuchFile_ThrowsFileNotFoundException() { Assert.Throws(() => Assembly.LoadFrom("NoSuchPath")); Assert.Throws(() => Assembly.UnsafeLoadFrom("NoSuchPath")); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported), nameof(PlatformDetection.HasAssemblyFiles))] public void UnsafeLoadFrom_SamePath_ReturnsEqualAssemblies() { Assembly assembly1 = Assembly.UnsafeLoadFrom(DestTestAssemblyPath); @@ -532,7 +532,7 @@ public void UnsafeLoadFrom_SamePath_ReturnsEqualAssemblies() Assert.Equal(assembly1, assembly2); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported), nameof(PlatformDetection.HasAssemblyFiles))] public void LoadModule() { Assembly assembly = typeof(AssemblyTests).Assembly; @@ -567,7 +567,7 @@ public void Location_ExecutingAssembly_IsNotNull() } #pragma warning disable SYSLIB0012 - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] // single file + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.HasAssemblyFiles))] // single file public void CodeBase() { if (PlatformDetection.IsNativeAot) @@ -819,7 +819,7 @@ public void AssemblyLoadFromStringNeg() Assert.Throws(() => Assembly.Load("no such assembly")); // No such assembly } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported), nameof(PlatformDetection.HasAssemblyFiles))] public void AssemblyLoadFromBytes() { Assembly assembly = typeof(AssemblyTests).Assembly; @@ -843,8 +843,9 @@ public void AssemblyLoadFromBytesNeg() Assert.Throws(() => Assembly.Load(new byte[0])); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported), nameof(PlatformDetection.HasAssemblyFiles))] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst, "Symbols are in a different location on iOS/tvOS/MacCatalyst")] + [ActiveIssue("https://github.com/dotnet/runtime/issues/114951", TestPlatforms.Android)] public void AssemblyLoadFromBytesWithSymbols() { Assembly assembly = typeof(AssemblyTests).Assembly; @@ -864,7 +865,7 @@ public void AssemblyReflectionOnlyLoadFromString() Assert.Throws(() => Assembly.ReflectionOnlyLoad(an.FullName)); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported), nameof(PlatformDetection.HasAssemblyFiles))] public void AssemblyReflectionOnlyLoadFromBytes() { Assembly assembly = typeof(AssemblyTests).Assembly; diff --git a/src/libraries/System.Runtime/tests/System.Reflection.Tests/CoreCLR/AssemblyTests.cs b/src/libraries/System.Runtime/tests/System.Reflection.Tests/CoreCLR/AssemblyTests.cs index 5e043eb306f63c..0146537db43527 100644 --- a/src/libraries/System.Runtime/tests/System.Reflection.Tests/CoreCLR/AssemblyTests.cs +++ b/src/libraries/System.Runtime/tests/System.Reflection.Tests/CoreCLR/AssemblyTests.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; using System.IO; using System.Runtime.Loader; using Xunit; @@ -9,8 +10,7 @@ namespace System.Reflection.Tests { public class AssemblyTests { - [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/39650", TestPlatforms.Browser)] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public void CurrentLocation_HasLocaton() { string location = GetExecutingAssembly().Location; diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/AppDomainTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/AppDomainTests.cs index e3c0a312eab3bb..54c473bf00b8d3 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/AppDomainTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/AppDomainTests.cs @@ -366,7 +366,7 @@ public void Load() Assert.NotNull(AppDomain.CurrentDomain.Load(typeof(AppDomainTests).Assembly.FullName)); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported), nameof(PlatformDetection.HasAssemblyFiles))] [SkipOnPlatform(TestPlatforms.Browser, "Not supported on Browser.")] public void LoadBytes() { @@ -792,7 +792,7 @@ private void CopyTestAssemblies() string rootPath; string assemblyResolvePath = "AssemblyResolveTestApp"; string appOutsideTPAPath = "TestAppOutsideOfTPA"; - + if (PlatformDetection.IsiOS || PlatformDetection.IstvOS) { rootPath = Path.GetTempPath(); @@ -839,7 +839,7 @@ public static void GetPermissionSet() #pragma warning restore SYSLIB0003 // Obsolete: CAS } - public static bool FileCreateCaseSensitiveAndAssemblyLoadingSupported => PlatformDetection.FileCreateCaseSensitive && PlatformDetection.IsAssemblyLoadingSupported; + public static bool FileCreateCaseSensitiveAndAssemblyLoadingSupported => PlatformDetection.FileCreateCaseSensitive && PlatformDetection.IsAssemblyLoadingSupported && PlatformDetection.HasAssemblyFiles; [ConditionalTheory(nameof(FileCreateCaseSensitiveAndAssemblyLoadingSupported))] [MemberData(nameof(TestingCreateInstanceFromObjectHandleData))] diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/EnvironmentTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/EnvironmentTests.cs index 6d8e5372051759..a73dcc6a91a583 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/EnvironmentTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/EnvironmentTests.cs @@ -94,7 +94,7 @@ public void ProcessPath_Idempotent() } [Fact] - [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "Throws PNSE")] + [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.Android, "Throws PNSE")] public void ProcessPath_MatchesExpectedValue() { string expectedProcessPath = PlatformDetection.IsBrowser ? null : Process.GetCurrentProcess().MainModule.FileName; diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/ExceptionTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/ExceptionTests.cs index 4ad6379e4069d1..885b5a1ce0433d 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/ExceptionTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/ExceptionTests.cs @@ -109,6 +109,7 @@ public static void Exception_TargetSite_Rethrow() [Fact] [ActiveIssue("https://github.com/mono/mono/issues/15140", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/114951", TestPlatforms.Android)] public static void ThrowStatementDoesNotResetExceptionStackLineSameMethod() { (string, string, int) rethrownExceptionStackFrame = (null, null, 0); @@ -139,6 +140,7 @@ private static (string, string, int) ThrowAndRethrowSameMethod(out (string, stri [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotArm64Process))] // [ActiveIssue(https://github.com/dotnet/runtime/issues/1871)] can't use ActiveIssue for archs [ActiveIssue("https://github.com/mono/mono/issues/15141", TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/114951", TestPlatforms.Android)] public static void ThrowStatementDoesNotResetExceptionStackLineOtherMethod() { (string, string, int) rethrownExceptionStackFrame = (null, null, 0); diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorIncrementalTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorIncrementalTests.cs index 5bcb01a94bde9a..115181e2079028 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorIncrementalTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorIncrementalTests.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; using System.Collections; using System.Collections.Generic; using System.Linq; @@ -11,10 +12,9 @@ namespace System.Text.Json.SourceGeneration.UnitTests { - [ActiveIssue("https://github.com/dotnet/runtime/issues/58226", TestPlatforms.Browser)] [SkipOnCoreClr("https://github.com/dotnet/runtime/issues/71962", ~RuntimeConfiguration.Release)] [SkipOnMono("https://github.com/dotnet/runtime/issues/92467")] - [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotX86Process))] // https://github.com/dotnet/runtime/issues/71962 + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotX86Process), nameof(PlatformDetection.HasAssemblyFiles))] // https://github.com/dotnet/runtime/issues/71962 public static class JsonSourceGeneratorIncrementalTests { [Theory] @@ -44,12 +44,12 @@ public static void CompilingEquivalentSourcesResultsInEqualModels() { string source1 = """ using System.Text.Json.Serialization; - + namespace Test { [JsonSerializable(typeof(MyPoco))] public partial class JsonContext : JsonSerializerContext { } - + public class MyPoco { public int MyProperty { get; set; } = 42; @@ -60,7 +60,7 @@ public class MyPoco string source2 = """ using System; using System.Text.Json.Serialization; - + namespace Test { // Same as above but with different implementation @@ -100,12 +100,12 @@ public static void CompilingDifferentSourcesResultsInUnequalModels() { string source1 = """ using System.Text.Json.Serialization; - + namespace Test { [JsonSerializable(typeof(MyPoco))] public partial class JsonContext : JsonSerializerContext { } - + public class MyPoco { public int MyProperty { get; set; } = 42; @@ -115,12 +115,12 @@ public class MyPoco string source2 = """ using System.Text.Json.Serialization; - + namespace Test { [JsonSerializable(typeof(MyPoco))] public partial class JsonContext : JsonSerializerContext { } - + public class MyPoco { public int MyProperty { get; } = 42; // same, but missing a getter @@ -248,12 +248,12 @@ public static void IncrementalGenerator_EquivalentSources_DoesNotRegenerate() string source1 = """ using System; using System.Text.Json.Serialization; - + namespace Test { [JsonSerializable(typeof(MyPoco))] public partial class JsonContext : JsonSerializerContext { } - + public class MyPoco { public string MyProperty { get; set; } = 42; @@ -264,7 +264,7 @@ public class MyPoco string source2 = """ using System; using System.Text.Json.Serialization; - + namespace Test { // Same as above but with different implementation @@ -317,12 +317,12 @@ public static void IncrementalGenerator_DifferentSources_Regenerates() string source1 = """ using System; using System.Text.Json.Serialization; - + namespace Test { [JsonSerializable(typeof(MyPoco))] public partial class JsonContext : JsonSerializerContext { } - + public class MyPoco { public string MyProperty { get; set; } = 42; @@ -333,12 +333,12 @@ public class MyPoco string source2 = """ using System; using System.Text.Json.Serialization; - + namespace Test { [JsonSerializable(typeof(MyPoco))] public partial class JsonContext : JsonSerializerContext { } - + public class MyPoco { public string MyProperty { get; } = 42; // same, but missing a getter diff --git a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexGeneratorHelper.netcoreapp.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexGeneratorHelper.netcoreapp.cs index 90e638570f629f..677bf16d32ff0a 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexGeneratorHelper.netcoreapp.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexGeneratorHelper.netcoreapp.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; @@ -21,6 +22,7 @@ namespace System.Text.RegularExpressions.Tests { + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public static class RegexGeneratorHelper { private static readonly CSharpParseOptions s_previewParseOptions = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Preview).WithDocumentationMode(DocumentationMode.Diagnose); diff --git a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/UpgradeToGeneratedRegexAnalyzerTests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/UpgradeToGeneratedRegexAnalyzerTests.cs index 2a8b634e78d973..afc509f070c136 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/UpgradeToGeneratedRegexAnalyzerTests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/UpgradeToGeneratedRegexAnalyzerTests.cs @@ -15,6 +15,7 @@ namespace System.Text.RegularExpressions.Tests { [ActiveIssue("https://github.com/dotnet/runtime/issues/69823", TestRuntimes.Mono)] + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public class UpgradeToGeneratedRegexAnalyzerTests { private const string UseRegexSourceGeneratorDiagnosticId = @"SYSLIB1045"; diff --git a/src/libraries/System.Threading/tests/MutexTests.cs b/src/libraries/System.Threading/tests/MutexTests.cs index b83cfd571fa203..de4cc8bb7eaf2e 100644 --- a/src/libraries/System.Threading/tests/MutexTests.cs +++ b/src/libraries/System.Threading/tests/MutexTests.cs @@ -236,6 +236,7 @@ public void Ctor_InvalidNames_Unix() [Theory] [MemberData(nameof(GetValidNames))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/114951",platforms: TestPlatforms.Android, runtimes: TestRuntimes.CoreCLR)] public void Ctor_ValidName(string name) { bool createdNew; @@ -317,6 +318,7 @@ public void Ctor_TryCreateGlobalMutexTest_Uwp(bool currentUserOnly, bool current [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] [MemberData(nameof(GetValidNames))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/114951",platforms: TestPlatforms.Android, runtimes: TestRuntimes.CoreCLR)] public void OpenExisting(string name) { Mutex resultHandle; @@ -350,6 +352,7 @@ public void OpenExisting_InvalidNames() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/114951",platforms: TestPlatforms.Android, runtimes: TestRuntimes.CoreCLR)] public void OpenExisting_UnavailableName() { string name = Guid.NewGuid().ToString("N"); @@ -386,6 +389,7 @@ public void NamedWaitHandleOptionsTest() [Theory] [MemberData(nameof(NamePrefixes_MemberData))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/114951",platforms: TestPlatforms.Android, runtimes: TestRuntimes.CoreCLR)] public void NameOptionsApiCompatibilityTest(string namePrefix) { string name = Guid.NewGuid().ToString("N"); @@ -447,6 +451,7 @@ public static IEnumerable NamePrefixAndOptionsCompatibilityTest_Member [Theory] [MemberData(nameof(NamePrefixAndOptionsCompatibilityTest_MemberData))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/114951",platforms: TestPlatforms.Android, runtimes: TestRuntimes.CoreCLR)] public void NamePrefixAndOptionsCompatibilityTest(bool currentUserOnly, bool currentSessionOnly, string namePrefix) { string name = namePrefix + Guid.NewGuid().ToString("N"); @@ -478,6 +483,7 @@ public static IEnumerable NameNamespaceTests_MemberData() [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoNorServerCore))] // Windows Nano Server and Server Core apparently use the same namespace for the Local\ and Global\ prefixes [MemberData(nameof(NameNamespaceTests_MemberData))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/114951",platforms: TestPlatforms.Android, runtimes: TestRuntimes.CoreCLR)] public void NameNamespaceTest( bool create_currentUserOnly, bool create_currentSessionOnly, @@ -592,6 +598,7 @@ public static IEnumerable AbandonExisting_MemberData() [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] [MemberData(nameof(AbandonExisting_MemberData))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/114951",platforms: TestPlatforms.Android, runtimes: TestRuntimes.CoreCLR)] public void AbandonExisting( string name, WaitHandleWaitType waitType, @@ -845,6 +852,7 @@ private static void IncrementValueInFileNTimes(Mutex mutex, string fileName, int [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] [ActiveIssue("https://github.com/dotnet/runtime/issues/96191", TestPlatforms.Browser)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/114951",platforms: TestPlatforms.Android, runtimes: TestRuntimes.CoreCLR)] public void NamedMutex_ThreadExitDisposeRaceTest() { var mutexName = Guid.NewGuid().ToString("N"); @@ -906,6 +914,7 @@ public void NamedMutex_ThreadExitDisposeRaceTest() } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/114951",platforms: TestPlatforms.Android, runtimes: TestRuntimes.CoreCLR)] public void NamedMutex_DisposeWhenLockedRaceTest() { var mutexName = Guid.NewGuid().ToString("N"); diff --git a/src/libraries/oob-src.proj b/src/libraries/oob-src.proj index b1d9ddb7d5827b..9cef0fb3922a8d 100644 --- a/src/libraries/oob-src.proj +++ b/src/libraries/oob-src.proj @@ -8,7 +8,7 @@ true true + '$(DotNetBuildFromVMR)' == 'true'">true - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - + + + + + + - - - - + + - - - - - + - - - - + + - - - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mono/System.Private.CoreLib/src/System/Environment.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Environment.Mono.cs index 91d6ccef63e2ea..97f62e4a1fd033 100644 --- a/src/mono/System.Private.CoreLib/src/System/Environment.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Environment.Mono.cs @@ -24,18 +24,6 @@ public static extern int ExitCode [MethodImplAttribute(MethodImplOptions.InternalCall)] private static extern int GetProcessorCount(); - public static extern int TickCount - { - [MethodImplAttribute(MethodImplOptions.InternalCall)] - get; - } - - public static extern long TickCount64 - { - [MethodImplAttribute(MethodImplOptions.InternalCall)] - get; - } - [MethodImplAttribute(MethodImplOptions.InternalCall)] [DoesNotReturn] public static extern void Exit(int exitCode); diff --git a/src/mono/cmake/config.h.in b/src/mono/cmake/config.h.in index 8ac0c0f7c3c290..b5224211265cdb 100644 --- a/src/mono/cmake/config.h.in +++ b/src/mono/cmake/config.h.in @@ -263,21 +263,9 @@ /* CLOCK_MONOTONIC */ #cmakedefine HAVE_CLOCK_MONOTONIC 1 -/* CLOCK_MONOTONIC_COARSE */ -#cmakedefine HAVE_CLOCK_MONOTONIC_COARSE 1 - /* clockid_t */ #cmakedefine HAVE_CLOCKID_T 1 -/* mach_absolute_time */ -#cmakedefine HAVE_MACH_ABSOLUTE_TIME 1 - -/* gethrtime */ -#cmakedefine HAVE_GETHRTIME 1 - -/* read_real_time */ -#cmakedefine HAVE_READ_REAL_TIME 1 - /* Define to 1 if you have the `clock_nanosleep' function. */ #cmakedefine HAVE_CLOCK_NANOSLEEP 1 diff --git a/src/mono/cmake/configure.cmake b/src/mono/cmake/configure.cmake index b5cf1c625e4bb3..6b9e021f1437bc 100644 --- a/src/mono/cmake/configure.cmake +++ b/src/mono/cmake/configure.cmake @@ -113,7 +113,6 @@ check_function_exists(clock_gettime HAVE_CLOCK_GETTIME) check_symbol_exists(madvise "sys/mman.h" HAVE_MADVISE) check_symbol_exists(pthread_mutexattr_setprotocol "pthread.h" HAVE_DECL_PTHREAD_MUTEXATTR_SETPROTOCOL) check_symbol_exists(CLOCK_MONOTONIC "time.h" HAVE_CLOCK_MONOTONIC) -check_symbol_exists(CLOCK_MONOTONIC_COARSE "time.h" HAVE_CLOCK_MONOTONIC_COARSE) check_symbol_exists(sys_signame "signal.h" HAVE_SYSSIGNAME) check_symbol_exists(pthread_jit_write_protect_np "pthread.h" HAVE_PTHREAD_JIT_WRITE_PROTECT_NP) @@ -277,9 +276,6 @@ elseif(HOST_WASI) set(HAVE_MKSTEMP 0) set(HAVE_BACKTRACE_SYMBOLS 0) set(HAVE_GETPID 0) - set(HAVE_MACH_ABSOLUTE_TIME 0) - set(HAVE_GETHRTIME 0) - set(HAVE_READ_REAL_TIME 0) set(HAVE_SCHED_GETAFFINITY 0) set(HAVE_SCHED_SETAFFINITY 0) set(HAVE_GETHOSTBYNAME 0) diff --git a/src/mono/mono.proj b/src/mono/mono.proj index dab11c80cc5b92..2517ffe86d89d1 100644 --- a/src/mono/mono.proj +++ b/src/mono/mono.proj @@ -127,7 +127,7 @@ - + <_MonoCMakeArgs Include="-DENABLE_WERROR=1"/> diff --git a/src/mono/mono/eventpipe/ep-rt-mono.c b/src/mono/mono/eventpipe/ep-rt-mono.c index 196b183a2d7971..a6ea9092673d29 100644 --- a/src/mono/mono/eventpipe/ep-rt-mono.c +++ b/src/mono/mono/eventpipe/ep-rt-mono.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -329,27 +330,19 @@ ep_rt_mono_thread_exited (void) } } -#ifdef HOST_WIN32 int64_t ep_rt_mono_perf_counter_query (void) { - LARGE_INTEGER value; - if (QueryPerformanceCounter (&value)) - return (int64_t)value.QuadPart; - else - return 0; + return minipal_hires_ticks(); } int64_t ep_rt_mono_perf_frequency_query (void) { - LARGE_INTEGER value; - if (QueryPerformanceFrequency (&value)) - return (int64_t)value.QuadPart; - else - return 0; + return minipal_hires_tick_frequency(); } +#ifdef HOST_WIN32 void ep_rt_mono_system_time_get (EventPipeSystemTime *system_time) { @@ -385,19 +378,12 @@ ep_rt_mono_system_timestamp_get (void) #include #endif // HAVE_SYS_TIME_H -#if HAVE_MACH_ABSOLUTE_TIME -#include -static mono_lazy_init_t _ep_rt_mono_time_base_info_init = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED; -static mach_timebase_info_data_t _ep_rt_mono_time_base_info = {0}; -#endif - #ifdef HAVE_LOCALTIME_R #define HAVE_GMTIME_R 1 #endif static const int64_t SECS_BETWEEN_1601_AND_1970_EPOCHS = 11644473600LL; static const int64_t SECS_TO_100NS = 10000000; -static const int64_t SECS_TO_NS = 1000000000; static const int64_t MSECS_TO_MIS = 1000; /* clock_gettime () is found by configure on Apple builds, but its only present from ios 10, macos 10.12, tvos 10 and watchos 3 */ @@ -409,67 +395,12 @@ static const int64_t MSECS_TO_MIS = 1000; static const int64_t MISECS_TO_NS = 1000; #endif -static -void -time_base_info_lazy_init (void); - static int64_t system_time_to_int64 ( time_t sec, long nsec); -#if HAVE_MACH_ABSOLUTE_TIME -static -void -time_base_info_lazy_init (void) -{ - kern_return_t result = mach_timebase_info (&_ep_rt_mono_time_base_info); - if (result != KERN_SUCCESS) - memset (&_ep_rt_mono_time_base_info, 0, sizeof (_ep_rt_mono_time_base_info)); -} -#endif - -int64_t -ep_rt_mono_perf_counter_query (void) -{ -#if HAVE_MACH_ABSOLUTE_TIME - return (int64_t)mach_absolute_time (); -#elif HAVE_CLOCK_MONOTONIC - struct timespec ts; - int result = clock_gettime (CLOCK_MONOTONIC, &ts); - if (result == 0) - return ((int64_t)(ts.tv_sec) * (int64_t)(SECS_TO_NS)) + (int64_t)(ts.tv_nsec); -#else - #error "ep_rt_mono_perf_counter_get requires either mach_absolute_time () or clock_gettime (CLOCK_MONOTONIC) to be supported." -#endif - return 0; -} - -int64_t -ep_rt_mono_perf_frequency_query (void) -{ -#if HAVE_MACH_ABSOLUTE_TIME - // (numer / denom) gives you the nanoseconds per tick, so the below code - // computes the number of ticks per second. We explicitly do the multiplication - // first in order to help minimize the error that is produced by integer division. - mono_lazy_initialize (&_ep_rt_mono_time_base_info_init, time_base_info_lazy_init); - if (_ep_rt_mono_time_base_info.denom == 0 || _ep_rt_mono_time_base_info.numer == 0) - return 0; - return ((int64_t)(SECS_TO_NS) * (int64_t)(_ep_rt_mono_time_base_info.denom)) / (int64_t)(_ep_rt_mono_time_base_info.numer); -#elif HAVE_CLOCK_MONOTONIC - // clock_gettime () returns a result in terms of nanoseconds rather than a count. This - // means that we need to either always scale the result by the actual resolution (to - // get a count) or we need to say the resolution is in terms of nanoseconds. We prefer - // the latter since it allows the highest throughput and should minimize error propagated - // to the user. - return (int64_t)(SECS_TO_NS); -#else - #error "ep_rt_mono_perf_frequency_query requires either mach_absolute_time () or clock_gettime (CLOCK_MONOTONIC) to be supported." -#endif - return 0; -} - void ep_rt_mono_system_time_get (EventPipeSystemTime *system_time) { diff --git a/src/mono/mono/metadata/icall-decl.h b/src/mono/mono/metadata/icall-decl.h index ebce337af7b1a3..9c5e9f8c56490b 100644 --- a/src/mono/mono/metadata/icall-decl.h +++ b/src/mono/mono/metadata/icall-decl.h @@ -118,8 +118,6 @@ ICALL_EXPORT double ves_icall_System_Math_FusedMultiplyAdd (double, double, doub ICALL_EXPORT float ves_icall_System_MathF_Log2 (float); ICALL_EXPORT float ves_icall_System_MathF_FusedMultiplyAdd (float, float, float); ICALL_EXPORT gint32 ves_icall_System_Environment_get_ProcessorCount (void); -ICALL_EXPORT gint32 ves_icall_System_Environment_get_TickCount (void); -ICALL_EXPORT gint64 ves_icall_System_Environment_get_TickCount64 (void); ICALL_EXPORT gint64 ves_icall_System_GC_GetTotalMemory (MonoBoolean forceCollection); ICALL_EXPORT int ves_icall_System_GC_GetCollectionCount (int); ICALL_EXPORT int ves_icall_System_GC_GetMaxGeneration (void); diff --git a/src/mono/mono/metadata/icall-def.h b/src/mono/mono/metadata/icall-def.h index 2661ebd4bc0989..acb70083ad990c 100644 --- a/src/mono/mono/metadata/icall-def.h +++ b/src/mono/mono/metadata/icall-def.h @@ -203,8 +203,6 @@ HANDLES(ENV_1a, "FailFast", ves_icall_System_Environment_FailFast, void, 3, (Mon HANDLES(ENV_2, "GetCommandLineArgs", ves_icall_System_Environment_GetCommandLineArgs, MonoArray, 0, ()) NOHANDLES(ICALL(ENV_4, "GetProcessorCount", ves_icall_System_Environment_get_ProcessorCount)) NOHANDLES(ICALL(ENV_9, "get_ExitCode", mono_environment_exitcode_get)) -NOHANDLES(ICALL(ENV_15, "get_TickCount", ves_icall_System_Environment_get_TickCount)) -NOHANDLES(ICALL(ENV_15a, "get_TickCount64", ves_icall_System_Environment_get_TickCount64)) NOHANDLES(ICALL(ENV_20, "set_ExitCode", mono_environment_exitcode_set)) ICALL_TYPE(GC, "System.GC", GC_4a) diff --git a/src/mono/mono/metadata/icall.c b/src/mono/mono/metadata/icall.c index 7b095b3ab8e534..69b2cf2813dbd3 100644 --- a/src/mono/mono/metadata/icall.c +++ b/src/mono/mono/metadata/icall.c @@ -6244,19 +6244,6 @@ ves_icall_System_Environment_FailFast (MonoStringHandle message, MonoExceptionHa abort (); } -gint32 -ves_icall_System_Environment_get_TickCount (void) -{ - /* this will overflow after ~24 days */ - return (gint32) (mono_msec_boottime () & 0xffffffff); -} - -gint64 -ves_icall_System_Environment_get_TickCount64 (void) -{ - return mono_msec_boottime (); -} - gpointer ves_icall_RuntimeMethodHandle_GetFunctionPointer (MonoMethod *method, MonoError *error) { diff --git a/src/mono/mono/utils/mono-time.c b/src/mono/mono/utils/mono-time.c index 2a89bd9d3d0772..bf047cd01a497f 100644 --- a/src/mono/mono/utils/mono-time.c +++ b/src/mono/mono/utils/mono-time.c @@ -15,19 +15,10 @@ #include #endif -#ifdef HOST_DARWIN -#include -#include -#endif - #include #include -#if HAVE_MACH_ABSOLUTE_TIME -#include -#endif - #define MTICKS_PER_SEC (10 * 1000 * 1000) typedef enum _TimeConversionConstants @@ -51,18 +42,6 @@ mono_msec_ticks (void) #ifdef HOST_WIN32 #include -#ifndef _MSC_VER -/* we get "error: implicit declaration of function 'GetTickCount64'" */ -WINBASEAPI ULONGLONG WINAPI GetTickCount64(void); -#endif - -gint64 -mono_msec_boottime (void) -{ - /* GetTickCount () is reportedly monotonic */ - return GetTickCount64 (); -} - /* Returns the number of 100ns ticks from unspecified time: this should be monotonic */ gint64 mono_100ns_ticks (void) @@ -113,69 +92,6 @@ MONO_RESTORE_WARNING #include -/* Returns the number of milliseconds from boot time: this should be monotonic */ -/* Adapted from CoreCLR: https://github.com/dotnet/runtime/blob/402aa8584ed18792d6bc6ed1869f7c31b38f8139/src/coreclr/pal/src/misc/time.cpp */ -gint64 -mono_msec_boottime (void) -{ - /* 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))) - clockid_t clockType = - /* emscripten exposes CLOCK_MONOTONIC_COARSE but doesn't implement it */ -#if defined(HAVE_CLOCK_MONOTONIC_COARSE) && !defined(TARGET_WASM) - CLOCK_MONOTONIC_COARSE; /* good enough resolution, fastest speed */ -#else - CLOCK_MONOTONIC; -#endif - struct timespec ts; - if (clock_gettime (clockType, &ts) != 0) { - g_error ("clock_gettime(CLOCK_MONOTONIC*) failed; errno is %d", errno, strerror (errno)); - return 0; - } - return (ts.tv_sec * tccSecondsToMillieSeconds) + (ts.tv_nsec / tccMillieSecondsToNanoSeconds); - -#elif HAVE_MACH_ABSOLUTE_TIME - static gboolean timebase_inited; - static mach_timebase_info_data_t s_TimebaseInfo; - - if (!timebase_inited) { - kern_return_t machRet; - mach_timebase_info_data_t tmp; - machRet = mach_timebase_info (&tmp); - g_assert (machRet == KERN_SUCCESS); - /* Assume memcpy works correctly if ran concurrently */ - memcpy (&s_TimebaseInfo, &tmp, sizeof (mach_timebase_info_data_t)); - mono_memory_barrier (); - timebase_inited = TRUE; - } else { - // This barrier prevents reading s_TimebaseInfo before reading timebase_inited. - mono_memory_barrier (); - } - return (mach_absolute_time () * s_TimebaseInfo.numer / s_TimebaseInfo.denom) / tccMillieSecondsToNanoSeconds; - -#elif HAVE_GETHRTIME - return (gint64)(gethrtime () / tccMillieSecondsToNanoSeconds); - -#elif HAVE_READ_REAL_TIME - timebasestruct_t tb; - read_real_time (&tb, TIMEBASE_SZ); - if (time_base_to_time (&tb, TIMEBASE_SZ) != 0) { - g_error ("time_base_to_time() failed; errno is %d (%s)", errno, strerror (errno)); - return 0; - } - return (tb.tb_high * tccSecondsToMillieSeconds) + (tb.tb_low / tccMillieSecondsToNanoSeconds); - -#else - struct timeval tv; - if (gettimeofday (&tv, NULL) == -1) { - g_error ("gettimeofday() failed; errno is %d (%s)", errno, strerror (errno)); - return 0; - } - return (tv.tv_sec * tccSecondsToMillieSeconds) + (tv.tv_usec / tccMillieSecondsToMicroSeconds); - -#endif /* HAVE_CLOCK_MONOTONIC */ -} - /* Returns the number of 100ns ticks from unspecified time: this should be monotonic */ gint64 mono_100ns_ticks (void) diff --git a/src/mono/mono/utils/mono-time.h b/src/mono/mono/utils/mono-time.h index 685f2bc76e31ef..b62352ab26a8cf 100644 --- a/src/mono/mono/utils/mono-time.h +++ b/src/mono/mono/utils/mono-time.h @@ -11,11 +11,6 @@ #include #endif -/* Returns the number of milliseconds from boot time: this should be monotonic - * - * Prefer to use mono_msec_ticks for elapsed time calculation. */ -gint64 mono_msec_boottime (void); - /* Returns the number of milliseconds ticks from unspecified time: this should be monotonic */ MONO_COMPONENT_API gint64 mono_msec_ticks (void); diff --git a/src/mono/msbuild/android/build/AndroidBuild.targets b/src/mono/msbuild/android/build/AndroidBuild.targets index 5e45180b07960a..56dd94a5983986 100644 --- a/src/mono/msbuild/android/build/AndroidBuild.targets +++ b/src/mono/msbuild/android/build/AndroidBuild.targets @@ -22,7 +22,7 @@ <_MobileIntermediateOutputPath>$([MSBuild]::NormalizeDirectory($(IntermediateOutputPath), 'mobile')) $(PlatformTarget) $(AssemblyName) - False + false diff --git a/src/mono/msbuild/apple/build/AppleBuild.props b/src/mono/msbuild/apple/build/AppleBuild.props index a3fc8dc30b3be1..ba3ff16ac72337 100644 --- a/src/mono/msbuild/apple/build/AppleBuild.props +++ b/src/mono/msbuild/apple/build/AppleBuild.props @@ -17,7 +17,7 @@ true true - false + false <_IsLibraryMode Condition="('$(UseNativeAOTRuntime)' != 'true' and '$(NativeLib)' != '') or ('$(UseNativeAOTRuntime)' == 'true' and '$(NativeLib)' == 'Shared')">true diff --git a/src/mono/sample/Android/AndroidSampleApp.csproj b/src/mono/sample/Android/AndroidSampleApp.csproj index 74ce1168a1ab57..b0f10b8c163825 100644 --- a/src/mono/sample/Android/AndroidSampleApp.csproj +++ b/src/mono/sample/Android/AndroidSampleApp.csproj @@ -9,7 +9,6 @@ Link false $(ForceAOT) - True HelloAndroid $(AssemblyName).dll true diff --git a/src/native/libs/System.Native/entrypoints.c b/src/native/libs/System.Native/entrypoints.c index a133f59b179e2d..fb6d78ceef3c55 100644 --- a/src/native/libs/System.Native/entrypoints.c +++ b/src/native/libs/System.Native/entrypoints.c @@ -255,6 +255,7 @@ static const Entry s_sysNative[] = DllImportEntry(SystemNative_UTimensat) DllImportEntry(SystemNative_FUTimens) DllImportEntry(SystemNative_GetTimestamp) + DllImportEntry(SystemNative_GetLowResolutionTimestamp) DllImportEntry(SystemNative_GetBootTimeTicks) DllImportEntry(SystemNative_GetCpuUtilization) DllImportEntry(SystemNative_GetPwUidR) diff --git a/src/native/libs/System.Native/pal_time.c b/src/native/libs/System.Native/pal_time.c index 488c49776fd9f3..0f37ddbe006418 100644 --- a/src/native/libs/System.Native/pal_time.c +++ b/src/native/libs/System.Native/pal_time.c @@ -12,9 +12,7 @@ #include #include #include -#if HAVE_CLOCK_GETTIME_NSEC_NP -#include -#endif +#include enum { @@ -81,19 +79,14 @@ int32_t SystemNative_FUTimens(intptr_t fd, TimeSpec* times) return result; } -uint64_t SystemNative_GetTimestamp(void) +int64_t SystemNative_GetTimestamp(void) { -#if HAVE_CLOCK_GETTIME_NSEC_NP - return clock_gettime_nsec_np(CLOCK_UPTIME_RAW); -#else - struct timespec ts; - - int result = clock_gettime(CLOCK_MONOTONIC, &ts); - assert(result == 0); // only possible errors are if MONOTONIC isn't supported or &ts is an invalid address - (void)result; // suppress unused parameter warning in release builds + return minipal_hires_ticks(); +} - return ((uint64_t)(ts.tv_sec) * SecondsToNanoSeconds) + (uint64_t)(ts.tv_nsec); -#endif +int64_t SystemNative_GetLowResolutionTimestamp(void) +{ + return minipal_lowres_ticks(); } int64_t SystemNative_GetBootTimeTicks(void) @@ -141,7 +134,7 @@ double SystemNative_GetCpuUtilization(ProcessCpuInformation* previousCpuInfo) ((uint64_t)(resUsage.ru_utime.tv_usec) * MicroSecondsToNanoSeconds); } - uint64_t currentTime = SystemNative_GetTimestamp(); + uint64_t currentTime = (uint64_t)minipal_hires_ticks(); uint64_t lastRecordedCurrentTime = previousCpuInfo->lastRecordedCurrentTime; uint64_t lastRecordedKernelTime = previousCpuInfo->lastRecordedKernelTime; diff --git a/src/native/libs/System.Native/pal_time.h b/src/native/libs/System.Native/pal_time.h index 26db2c20c102ef..dad3cf3c8e847e 100644 --- a/src/native/libs/System.Native/pal_time.h +++ b/src/native/libs/System.Native/pal_time.h @@ -37,7 +37,12 @@ PALEXPORT int32_t SystemNative_FUTimens(intptr_t fd, TimeSpec* times); /** * Gets a high-resolution timestamp that can be used for time-interval measurements. */ -PALEXPORT uint64_t SystemNative_GetTimestamp(void); +PALEXPORT int64_t SystemNative_GetTimestamp(void); + +/** + * Gets a low-resolution timestamp in milliseconds. + */ + PALEXPORT int64_t SystemNative_GetLowResolutionTimestamp(void); /** * Gets system boot time ticks. (Linux only) diff --git a/src/native/minipal/configure.cmake b/src/native/minipal/configure.cmake index e9560786df50a1..473c4f8124c521 100644 --- a/src/native/minipal/configure.cmake +++ b/src/native/minipal/configure.cmake @@ -11,6 +11,8 @@ check_function_exists(fsync HAVE_FSYNC) check_symbol_exists(arc4random_buf "stdlib.h" HAVE_ARC4RANDOM_BUF) check_symbol_exists(O_CLOEXEC fcntl.h HAVE_O_CLOEXEC) +check_symbol_exists(CLOCK_MONOTONIC time.h HAVE_CLOCK_MONOTONIC) +check_symbol_exists(CLOCK_MONOTONIC_COARSE time.h HAVE_CLOCK_MONOTONIC_COARSE) check_symbol_exists(clock_gettime_nsec_np time.h HAVE_CLOCK_GETTIME_NSEC_NP) if(CMAKE_C_BYTE_ORDER STREQUAL "BIG_ENDIAN") diff --git a/src/native/minipal/minipalconfig.h.in b/src/native/minipal/minipalconfig.h.in index e5207103dddf0f..1ecd683be425c2 100644 --- a/src/native/minipal/minipalconfig.h.in +++ b/src/native/minipal/minipalconfig.h.in @@ -6,6 +6,8 @@ #cmakedefine01 HAVE_HWPROBE_H #cmakedefine01 HAVE_O_CLOEXEC #cmakedefine01 HAVE_SYSCTLBYNAME +#cmakedefine01 HAVE_CLOCK_MONOTONIC +#cmakedefine01 HAVE_CLOCK_MONOTONIC_COARSE #cmakedefine01 HAVE_CLOCK_GETTIME_NSEC_NP #cmakedefine01 BIGENDIAN #cmakedefine01 HAVE_BCRYPT_H diff --git a/src/native/minipal/time.c b/src/native/minipal/time.c index 20c117be5ff48c..844e10287f4144 100644 --- a/src/native/minipal/time.c +++ b/src/native/minipal/time.c @@ -12,22 +12,32 @@ int64_t minipal_hires_ticks() { LARGE_INTEGER ts; - QueryPerformanceCounter(&ts); + BOOL ret; + ret = QueryPerformanceCounter(&ts); + assert(ret); // The function is documented to never fail on Windows XP+. return ts.QuadPart; } int64_t minipal_hires_tick_frequency() { LARGE_INTEGER ts; - QueryPerformanceFrequency(&ts); + BOOL ret; + ret = QueryPerformanceFrequency(&ts); + assert(ret); // The function is documented to never fail on Windows XP+. return ts.QuadPart; } +int64_t minipal_lowres_ticks() +{ + return GetTickCount64(); +} + #else // HOST_WINDOWS #include "minipalconfig.h" -#include // nanosleep +#include +#include #include inline static void YieldProcessor(void); @@ -56,6 +66,8 @@ inline static void YieldProcessor(void) } #define tccSecondsToNanoSeconds 1000000000 // 10^9 +#define tccSecondsToMilliSeconds 1000 // 10^3 +#define tccMilliSecondsToNanoSeconds 1000000 // 10^6 int64_t minipal_hires_tick_frequency(void) { return tccSecondsToNanoSeconds; @@ -65,7 +77,7 @@ int64_t minipal_hires_ticks(void) { #if HAVE_CLOCK_GETTIME_NSEC_NP return (int64_t)clock_gettime_nsec_np(CLOCK_UPTIME_RAW); -#else +#elif HAVE_CLOCK_MONOTONIC struct timespec ts; int result = clock_gettime(CLOCK_MONOTONIC, &ts); if (result != 0) @@ -74,6 +86,42 @@ int64_t minipal_hires_ticks(void) } return ((int64_t)(ts.tv_sec) * (int64_t)(tccSecondsToNanoSeconds)) + (int64_t)(ts.tv_nsec); +#else + #error "minipal_hires_ticks requires clock_gettime_nsec_np or clock_gettime to be supported." +#endif +} + +int64_t minipal_lowres_ticks(void) +{ +#if HAVE_CLOCK_GETTIME_NSEC_NP + return (int64_t)clock_gettime_nsec_np(CLOCK_UPTIME_RAW) / (int64_t)(tccMilliSecondsToNanoSeconds); +#elif HAVE_CLOCK_MONOTONIC + struct timespec ts; + + // emscripten exposes CLOCK_MONOTONIC_COARSE but doesn't implement it +#if HAVE_CLOCK_MONOTONIC_COARSE && !defined(__EMSCRIPTEN__) + // CLOCK_MONOTONIC_COARSE has enough precision for GetTickCount but + // doesn't have the same overhead as CLOCK_MONOTONIC. This allows + // overall higher throughput. See dotnet/coreclr#2257 for more details. + + const clockid_t clockType = CLOCK_MONOTONIC_COARSE; +#else + const clockid_t clockType = CLOCK_MONOTONIC; +#endif + + int result = clock_gettime(clockType, &ts); + if (result != 0) + { +#if HAVE_CLOCK_MONOTONIC_COARSE && !defined(__EMSCRIPTEN__) + assert(!"clock_gettime(CLOCK_MONOTONIC_COARSE) failed"); +#else + assert(!"clock_gettime(CLOCK_MONOTONIC) failed"); +#endif + } + + return ((int64_t)(ts.tv_sec) * (int64_t)(tccSecondsToMilliSeconds)) + ((int64_t)(ts.tv_nsec) / (int64_t)(tccMilliSecondsToNanoSeconds)); +#else + #error "minipal_lowres_ticks requires clock_gettime_nsec_np or clock_gettime to be supported." #endif } diff --git a/src/native/minipal/time.h b/src/native/minipal/time.h index 27359aa407c754..f0ada2f7f507ce 100644 --- a/src/native/minipal/time.h +++ b/src/native/minipal/time.h @@ -17,6 +17,9 @@ extern "C" // Returns the frequency of high resolution timer ticks in Hz int64_t minipal_hires_tick_frequency(void); + // Returns a low-precision monotonically increasing timer in milliseconds + int64_t minipal_lowres_ticks(void); + // Delays execution of current thread by `usecs` microseconds. // The delay is best-effort and may take longer than desired. // Some delays, depending on OS and duration, could be implemented via busy waiting. diff --git a/src/tasks/AndroidAppBuilder/ApkBuilder.cs b/src/tasks/AndroidAppBuilder/ApkBuilder.cs index 9944e69d31e469..21fd800c89681a 100644 --- a/src/tasks/AndroidAppBuilder/ApkBuilder.cs +++ b/src/tasks/AndroidAppBuilder/ApkBuilder.cs @@ -195,11 +195,8 @@ public ApkBuilder(TaskLoggingHelper logger) Directory.CreateDirectory(Path.Combine(OutputDir, "assets")); var extensionsToIgnore = new List { ".so", ".a", ".dex", ".jar" }; - if (StripDebugSymbols) - { - extensionsToIgnore.Add(".pdb"); - extensionsToIgnore.Add(".dbg"); - } + extensionsToIgnore.Add(".pdb"); + extensionsToIgnore.Add(".dbg"); // Copy sourceDir to OutputDir/assets-tozip (ignore native files) // these files then will be zipped and copied to apk/assets/assets.zip @@ -391,6 +388,8 @@ public ApkBuilder(TaskLoggingHelper logger) project.GenerateCMake(OutputDir, MinApiLevel, StripDebugSymbols); project.BuildCMake(OutputDir, StripDebugSymbols); + // TODO: https://github.com/dotnet/runtime/issues/115717 + string abi = project.Abi; // 2. Compile Java files diff --git a/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs b/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs index 440e9ee20e3bb1..e6cd15bcb1d491 100644 --- a/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs +++ b/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_Arm.cs @@ -4748,6 +4748,15 @@ ("SveVecTernOpTest.template", new Dictionary { ["TestName"] = "Sve2_BitwiseClearXor_ushort", ["Isa"] = "Sve2", ["LoadIsa"] = "Sve2", ["Method"] = "BitwiseClearXor", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt16", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt16()", ["ConvertFunc"] = "", ["ValidateIterResult"] = "result[i] != Helpers.BitwiseClearXor(firstOp[i], secondOp[i], thirdOp[i])", ["GetIterResult"] = "Helpers.BitwiseClearXor(firstOp[i], secondOp[i], thirdOp[i])"}), ("SveVecTernOpTest.template", new Dictionary { ["TestName"] = "Sve2_BitwiseClearXor_uint", ["Isa"] = "Sve2", ["LoadIsa"] = "Sve2", ["Method"] = "BitwiseClearXor", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ConvertFunc"] = "", ["ValidateIterResult"] = "result[i] != Helpers.BitwiseClearXor(firstOp[i], secondOp[i], thirdOp[i])", ["GetIterResult"] = "Helpers.BitwiseClearXor(firstOp[i], secondOp[i], thirdOp[i])"}), ("SveVecTernOpTest.template", new Dictionary { ["TestName"] = "Sve2_BitwiseClearXor_ulong", ["Isa"] = "Sve2", ["LoadIsa"] = "Sve2", ["Method"] = "BitwiseClearXor", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["Op3VectorType"] = "Vector", ["Op3BaseType"] = "UInt64", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["ConvertFunc"] = "", ["ValidateIterResult"] = "result[i] != Helpers.BitwiseClearXor(firstOp[i], secondOp[i], thirdOp[i])", ["GetIterResult"] = "Helpers.BitwiseClearXor(firstOp[i], secondOp[i], thirdOp[i])"}), + + ("SveVecImmBinOpTest.template", new Dictionary { ["TestName"] = "Sve2_ShiftLeftAndInsert_sbyte", ["Isa"] = "Sve2", ["LoadIsa"] = "Sve2", ["Method"] = "ShiftLeftAndInsert", ["RetVectorType"] = "Vector", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "SByte", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueMask"] = "Helpers.getMaskSByte()", ["Imm"] = "5", ["InvalidImm"] = "8", ["ValidateIterResult"] = "result[i] != Helpers.ShiftLeftAndInsert(firstOp[i], secondOp[i], Imm)", ["GetIterResult"] = "Helpers.ShiftLeftAndInsert(firstOp[i], secondOp[i], Imm)"}), + ("SveVecImmBinOpTest.template", new Dictionary { ["TestName"] = "Sve2_ShiftLeftAndInsert_short", ["Isa"] = "Sve2", ["LoadIsa"] = "Sve2", ["Method"] = "ShiftLeftAndInsert", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int16", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueMask"] = "Helpers.getMaskInt16()", ["Imm"] = "12", ["InvalidImm"] = "16", ["ValidateIterResult"] = "result[i] != Helpers.ShiftLeftAndInsert(firstOp[i], secondOp[i], Imm)", ["GetIterResult"] = "Helpers.ShiftLeftAndInsert(firstOp[i], secondOp[i], Imm)"}), + ("SveVecImmBinOpTest.template", new Dictionary { ["TestName"] = "Sve2_ShiftLeftAndInsert_int", ["Isa"] = "Sve2", ["LoadIsa"] = "Sve2", ["Method"] = "ShiftLeftAndInsert", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int32", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueMask"] = "Helpers.getMaskInt32()", ["Imm"] = "23", ["InvalidImm"] = "32", ["ValidateIterResult"] = "result[i] != Helpers.ShiftLeftAndInsert(firstOp[i], secondOp[i], Imm)", ["GetIterResult"] = "Helpers.ShiftLeftAndInsert(firstOp[i], secondOp[i], Imm)"}), + ("SveVecImmBinOpTest.template", new Dictionary { ["TestName"] = "Sve2_ShiftLeftAndInsert_long", ["Isa"] = "Sve2", ["LoadIsa"] = "Sve2", ["Method"] = "ShiftLeftAndInsert", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Int64", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["NextValueMask"] = "Helpers.getMaskInt64()", ["Imm"] = "63", ["InvalidImm"] = "64", ["ValidateIterResult"] = "result[i] != Helpers.ShiftLeftAndInsert(firstOp[i], secondOp[i], Imm)", ["GetIterResult"] = "Helpers.ShiftLeftAndInsert(firstOp[i], secondOp[i], Imm)"}), + ("SveVecImmBinOpTest.template", new Dictionary { ["TestName"] = "Sve2_ShiftLeftAndInsert_byte", ["Isa"] = "Sve2", ["LoadIsa"] = "Sve2", ["Method"] = "ShiftLeftAndInsert", ["RetVectorType"] = "Vector", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "Byte", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueMask"] = "Helpers.getMaskByte()", ["Imm"] = "3", ["InvalidImm"] = "8", ["ValidateIterResult"] = "result[i] != Helpers.ShiftLeftAndInsert(firstOp[i], secondOp[i], Imm)", ["GetIterResult"] = "Helpers.ShiftLeftAndInsert(firstOp[i], secondOp[i], Imm)"}), + ("SveVecImmBinOpTest.template", new Dictionary { ["TestName"] = "Sve2_ShiftLeftAndInsert_ushort", ["Isa"] = "Sve2", ["LoadIsa"] = "Sve2", ["Method"] = "ShiftLeftAndInsert", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt16", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueMask"] = "Helpers.getMaskUInt16()", ["Imm"] = "9", ["InvalidImm"] = "16", ["ValidateIterResult"] = "result[i] != Helpers.ShiftLeftAndInsert(firstOp[i], secondOp[i], Imm)", ["GetIterResult"] = "Helpers.ShiftLeftAndInsert(firstOp[i], secondOp[i], Imm)"}), + ("SveVecImmBinOpTest.template", new Dictionary { ["TestName"] = "Sve2_ShiftLeftAndInsert_uint", ["Isa"] = "Sve2", ["LoadIsa"] = "Sve2", ["Method"] = "ShiftLeftAndInsert", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt32", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueMask"] = "Helpers.getMaskUInt32()", ["Imm"] = "17", ["InvalidImm"] = "32", ["ValidateIterResult"] = "result[i] != Helpers.ShiftLeftAndInsert(firstOp[i], secondOp[i], Imm)", ["GetIterResult"] = "Helpers.ShiftLeftAndInsert(firstOp[i], secondOp[i], Imm)"}), + ("SveVecImmBinOpTest.template", new Dictionary { ["TestName"] = "Sve2_ShiftLeftAndInsert_ulong", ["Isa"] = "Sve2", ["LoadIsa"] = "Sve2", ["Method"] = "ShiftLeftAndInsert", ["RetVectorType"] = "Vector", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector", ["Op2BaseType"] = "UInt64", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueMask"] = "Helpers.getMaskUInt64()", ["Imm"] = "45", ["InvalidImm"] = "64", ["ValidateIterResult"] = "result[i] != Helpers.ShiftLeftAndInsert(firstOp[i], secondOp[i], Imm)", ["GetIterResult"] = "Helpers.ShiftLeftAndInsert(firstOp[i], secondOp[i], Imm)"}), }; string projectName = args[0]; diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_115495/Runtime_115495.cs b/src/tests/JIT/Regression/JitBlue/Runtime_115495/Runtime_115495.cs new file mode 100644 index 00000000000000..ff50dcf6beb11b --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_115495/Runtime_115495.cs @@ -0,0 +1,89 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Numerics; +using System.Runtime.CompilerServices; +using Xunit; + +// LLM-Fuzz Mutation 5 + +public class Runtime_115495 +{ + private const int Pass = 100; + private const int Fail = -1; + + public class Assert + { + public static void Equal(float a, float b) + { + if (a != b) + throw new Exception("Assert.Equal failed"); + } + + public static void NotEqual(float a, float b) + { + if (a == b) + throw new Exception("Assert.NotEqual failed"); + } + } + + public struct SimpleVector3 + { + // Introduce lambda expressions to process array values. + static Func multiply = x => x * 2; + + static void Vector3GetHashCodeTest(ref int checksum) + { + Vector3 one = new Vector3(2.0f, 3.0f, 3.3f); + Vector3 two = new Vector3(2.0f, 3.0f, 3.3f); + Vector3 three = new Vector3(3.0f, 2.0f, 3.3f); + Assert.Equal(one.GetHashCode(), two.GetHashCode()); + Assert.NotEqual(one.GetHashCode(), three.GetHashCode()); + Vector3 zero = new Vector3(0.0f, 0.0f, 0.0f); + Vector3 oneAxis = new Vector3(1.0f, 0.0f, 0.0f); + Assert.NotEqual(zero.GetHashCode(), oneAxis.GetHashCode()); + + // Create an array and then use a for-loop with invariant bounds. + float[] items = new float[] { one.X, one.Y, one.Z, three.X, three.Y }; + for (int i = 0, cnt = items.Length; i < cnt; i++) + { + checksum += (int)(items[i] * 1.0f); + } + // Use a for-each loop conditionally. + if (checksum % 4 == 0) + { + foreach (float f in items) + { + checksum += multiply((int)f); + } + } + Console.WriteLine("Intermediate Checksum (Mutation 5): " + checksum); + } + + [Fact] + public static int Problem() + { + int checksum = 19; + int returnVal = Pass; + try + { + Vector3GetHashCodeTest(ref checksum); + } + catch (Exception ex) + { + Console.WriteLine("FAILED: " + ex.Message); + returnVal = Fail; + } + // Additional clonable loop using same array in a different context. + int[] reusedArray = { 2, 4, 6, 8, 10 }; + for (int i = 0, length = reusedArray.Length; i < length; i++) + { + checksum += (i % 2 == 0) ? reusedArray[i] : -reusedArray[i]; + } + Console.WriteLine("Final Checksum (Mutation 5): " + checksum); + return returnVal; + } + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_115495/Runtime_115495.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_115495/Runtime_115495.csproj new file mode 100644 index 00000000000000..de6d5e08882e86 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_115495/Runtime_115495.csproj @@ -0,0 +1,8 @@ + + + True + + + + + diff --git a/src/tests/JIT/interpreter/Interpreter.cs b/src/tests/JIT/interpreter/Interpreter.cs index 866102e9f2e480..a78df5ef49b14e 100644 --- a/src/tests/JIT/interpreter/Interpreter.cs +++ b/src/tests/JIT/interpreter/Interpreter.cs @@ -419,6 +419,13 @@ public static void RunInterpreterTests() if (!TestSizeof()) Environment.FailFast(null); + if (!TestLdtoken()) + Environment.FailFast(null); + /* + if (!TestMdArray()) + Environment.FailFast(null); + */ + System.GC.Collect(); } @@ -959,4 +966,31 @@ public static unsafe bool TestSizeof() return false; return true; } + + public static int LdtokenField = 7; + + public static bool TestLdtoken() + { + Type t = typeof(int); + int i = 42; + if (!ReferenceEquals(t, i.GetType())) + return false; + // These generate field and method ldtoken opcodes, but the test fails because we are missing castclass and possibly also generics + /* + System.Linq.Expressions.Expression> f = () => LdtokenField; + System.Linq.Expressions.Expression a = () => TestLdtoken(); + */ + return true; + } + + public static bool TestMdArray() + { + // FIXME: This generates roughly: + // newobj int[,].ctor + // ldtoken int[,] + // call System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray + // The newobj currently fails because int[,].ctor isn't a real method, the interp needs to use getCallInfo to determine how to invoke it + int[,] a = {{1, 2}, {3, 4}}; + return a[0, 1] == 2; + } } diff --git a/src/tests/build.proj b/src/tests/build.proj index 2a6dc297f2d7da..f0ccb7759a9120 100644 --- a/src/tests/build.proj +++ b/src/tests/build.proj @@ -211,9 +211,8 @@ $(IntermediateOutputPath)\AndroidApps\$(Category) $(BuildDir)\apk $(XUnitTestBinBase)$(CategoryWithSlash)\$(Category).apk - False 127.0.0.1:9000,nosuspend,listen - True + true $(ArtifactsBinDir)microsoft.netcore.app.runtime.android-$(TargetArchitecture)\$(Configuration)\runtimes\android-$(TargetArchitecture)\ arm64-v8a armeabi-v7a diff --git a/src/tests/nativeaot/SmokeTests/UnitTests/Generics.cs b/src/tests/nativeaot/SmokeTests/UnitTests/Generics.cs index 38d622dc0e7e00..5521646cd1fb7f 100644 --- a/src/tests/nativeaot/SmokeTests/UnitTests/Generics.cs +++ b/src/tests/nativeaot/SmokeTests/UnitTests/Generics.cs @@ -60,6 +60,7 @@ internal static int Run() Test104913Regression.Run(); Test105397Regression.Run(); Test105880Regression.Run(); + Test115442Regression.Run(); TestInvokeMemberCornerCaseInGenerics.Run(); TestRefAny.Run(); TestNullableCasting.Run(); @@ -3685,6 +3686,19 @@ public static void Run() } } + class Test115442Regression + { + public readonly struct TypeBuilder + { + public TypeBuilder<(T1, T2), T3> Add() => default; + } + + public static void Run() + { + typeof(TypeBuilder).GetMethod("Add").MakeGenericMethod(typeof(int)).Invoke(default(TypeBuilder), []); + } + } + class TestInvokeMemberCornerCaseInGenerics { class Generic diff --git a/src/tests/tracing/eventpipe/common/Microsoft.Diagnostics.NETCore.Client/Microsoft.Diagnostics.NETCore.Client.csproj b/src/tests/tracing/eventpipe/common/Microsoft.Diagnostics.NETCore.Client/Microsoft.Diagnostics.NETCore.Client.csproj index 064e21555e3d2a..fc7c42a9f4bdce 100644 --- a/src/tests/tracing/eventpipe/common/Microsoft.Diagnostics.NETCore.Client/Microsoft.Diagnostics.NETCore.Client.csproj +++ b/src/tests/tracing/eventpipe/common/Microsoft.Diagnostics.NETCore.Client/Microsoft.Diagnostics.NETCore.Client.csproj @@ -12,7 +12,7 @@ true true false - true + true false