From bfff07b53706619ca593b91eb4edfd59821b703f Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" Date: Mon, 17 Aug 2026 14:26:32 +0200 Subject: [PATCH] =?UTF-8?q?[runtime]=20Source=20update=20691fd96=20?= =?UTF-8?q?=E2=86=92=20a36e3c1=20Diff:=20https://github.com/maestro-auth-t?= =?UTF-8?q?est/runtime/compare/691fd960eb500743b4be71373b11b2263bdbc318..a?= =?UTF-8?q?36e3c1c9a993f0b4c6db87f033105f0bb364f3b?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From: https://github.com/maestro-auth-test/runtime/commit/691fd960eb500743b4be71373b11b2263bdbc318 To: https://github.com/maestro-auth-test/runtime/commit/a36e3c1c9a993f0b4c6db87f033105f0bb364f3b [[ commit created by automation ]] --- src/runtime/.config/dotnet-tools.json | 2 +- .../design/coreclr/botr/readytorun-format.md | 19 +- .../coreclr/jit/runtime-async-inlining.md | 352 ++ .../docs/project/list-of-diagnostics.md | 2 +- src/runtime/eng/Version.Details.props | 88 +- src/runtime/eng/Version.Details.xml | 172 +- src/runtime/eng/Versions.props | 2 +- src/runtime/eng/common/Get-GitHubAppToken.ps1 | 154 + src/runtime/eng/common/SetupNugetSources.ps1 | 38 +- src/runtime/eng/common/SetupNugetSources.sh | 4 +- src/runtime/eng/common/build.ps1 | 7 +- src/runtime/eng/common/build.sh | 14 +- .../core-templates/job/helix-job-monitor.yml | 6 + .../common/core-templates/job/onelocbuild.yml | 28 +- .../job/publish-build-assets.yml | 2 - .../post-build/common-variables.yml | 2 - .../common/core-templates/stages/renovate.yml | 2 + .../steps/enable-internal-sources.yml | 12 +- .../steps/get-github-app-token.yml | 79 + .../core-templates/steps/publish-logs.yml | 3 - src/runtime/eng/common/msbuild.ps1 | 10 +- src/runtime/eng/common/msbuild.sh | 16 +- .../steps/get-github-app-token.yml | 7 + .../templates/steps/get-github-app-token.yml | 7 + src/runtime/eng/common/tools.ps1 | 11 +- src/runtime/eng/common/tools.sh | 24 +- src/runtime/eng/native/build-commons.sh | 12 + .../eng/native/configurecompiler.cmake | 5 + .../eng/native/sccache-xarch-wrapper.sh | 37 + .../coreclr/templates/sccache-stats.yml | 2 +- .../coreclr/templates/setup-sccache.yml | 38 +- .../installer/helix-queues-setup.yml | 31 +- src/runtime/eng/pipelines/installer/helix.yml | 2 + src/runtime/eng/pipelines/runtime.yml | 203 +- src/runtime/global.json | 8 +- .../CompilerServices/AsyncHelpers.CoreCLR.cs | 165 + .../src/coreclr/binder/applicationcontext.cpp | 9 +- .../coreclr/binder/defaultassemblybinder.cpp | 3 +- .../coreclr/binder/inc/applicationcontext.hpp | 3 +- src/runtime/src/coreclr/build-runtime.sh | 4 - .../coreclr/debug/createdump/crashinfo.cpp | 8 +- .../src/coreclr/debug/createdump/crashinfo.h | 8 +- .../coreclr/debug/createdump/crashinfomac.cpp | 6 +- .../debug/createdump/crashinfounix.cpp | 10 +- .../src/coreclr/debug/createdump/createdump.h | 13 +- .../debug/createdump/createdumpmain.cpp | 6 +- .../debug/createdump/createdumpunix.cpp | 2 +- .../debug/createdump/dumpwritermacho.cpp | 4 +- .../src/coreclr/debug/dbgutil/elfreader.cpp | 1 - .../src/coreclr/debug/dbgutil/machoreader.cpp | 1 - .../src/coreclr/debug/di/breakpoint.cpp | 6 +- src/runtime/src/coreclr/debug/di/cordb.cpp | 2 +- src/runtime/src/coreclr/debug/di/divalue.cpp | 4 +- src/runtime/src/coreclr/debug/di/module.cpp | 23 +- src/runtime/src/coreclr/debug/di/process.cpp | 165 +- .../src/coreclr/debug/di/rsappdomain.cpp | 2 +- .../src/coreclr/debug/di/rsfunction.cpp | 2 +- src/runtime/src/coreclr/debug/di/rsmain.cpp | 5 +- src/runtime/src/coreclr/debug/di/rspriv.h | 4 +- src/runtime/src/coreclr/debug/di/rsthread.cpp | 22 +- .../src/coreclr/debug/ee/amd64/walker.cpp | 14 +- .../src/coreclr/debug/ee/arm/walker.cpp | 6 +- .../src/coreclr/debug/ee/arm64/walker.cpp | 20 +- .../src/coreclr/debug/ee/controller.cpp | 116 +- src/runtime/src/coreclr/debug/ee/debugger.cpp | 135 +- src/runtime/src/coreclr/debug/ee/debugger.h | 2 +- src/runtime/src/coreclr/debug/ee/debugger.inl | 2 +- .../src/coreclr/debug/ee/debuggermodule.cpp | 8 +- .../src/coreclr/debug/ee/executioncontrol.cpp | 12 +- .../src/coreclr/debug/ee/frameinfo.cpp | 9 +- src/runtime/src/coreclr/debug/ee/funceval.cpp | 10 +- .../src/coreclr/debug/ee/functioninfo.cpp | 30 +- .../src/coreclr/debug/ee/i386/walker.cpp | 5 +- .../coreclr/debug/ee/loongarch64/walker.cpp | 6 +- src/runtime/src/coreclr/debug/ee/rcthread.cpp | 12 +- src/runtime/src/coreclr/debug/inc/common.h | 4 +- .../coreclr/debug/shared/arm/primitives.cpp | 4 +- .../coreclr/debug/shared/arm64/primitives.cpp | 4 +- .../coreclr/debug/shared/i386/primitives.cpp | 4 +- .../debug/shared/loongarch64/primitives.cpp | 12 +- .../debug/shared/riscv64/primitives.cpp | 14 +- .../src/coreclr/dlls/mscorpe/pewriter.cpp | 5 +- src/runtime/src/coreclr/gc/allocation.cpp | 32 +- src/runtime/src/coreclr/gc/background.cpp | 8 +- src/runtime/src/coreclr/gc/card_table.cpp | 6 +- src/runtime/src/coreclr/gc/collect.cpp | 14 +- src/runtime/src/coreclr/gc/diagnostics.cpp | 10 +- .../src/coreclr/gc/dynamic_heap_count.cpp | 38 +- src/runtime/src/coreclr/gc/dynamic_tuning.cpp | 6 +- src/runtime/src/coreclr/gc/env/common.h | 1 + src/runtime/src/coreclr/gc/env/gcenv.os.h | 20 +- src/runtime/src/coreclr/gc/gc.cpp | 17 +- src/runtime/src/coreclr/gc/gc.h | 5 +- src/runtime/src/coreclr/gc/gccommon.cpp | 4 +- src/runtime/src/coreclr/gc/gcee.cpp | 4 +- src/runtime/src/coreclr/gc/gcinternal.h | 28 +- src/runtime/src/coreclr/gc/gcpriv.h | 48 +- src/runtime/src/coreclr/gc/handletable.cpp | 9 +- src/runtime/src/coreclr/gc/init.cpp | 18 +- src/runtime/src/coreclr/gc/interface.cpp | 12 +- src/runtime/src/coreclr/gc/mark_phase.cpp | 15 +- src/runtime/src/coreclr/gc/no_gc.cpp | 6 +- src/runtime/src/coreclr/gc/objecthandle.cpp | 4 +- src/runtime/src/coreclr/gc/plan_phase.cpp | 29 +- .../src/coreclr/gc/unix/gcenv.unix.cpp | 26 - src/runtime/src/coreclr/gc/wasm/gcenv.cpp | 19 - .../src/coreclr/gc/windows/gcenv.windows.cpp | 50 - src/runtime/src/coreclr/ildasm/ildasmpch.h | 1 + src/runtime/src/coreclr/inc/corinfo.h | 8 + .../src/coreclr/inc/jiteeversionguid.h | 10 +- src/runtime/src/coreclr/inc/log.h | 8 +- src/runtime/src/coreclr/inc/sstring.h | 5 +- src/runtime/src/coreclr/inc/stresslog.h | 6 +- src/runtime/src/coreclr/jit/assertionprop.cpp | 27 +- src/runtime/src/coreclr/jit/async.cpp | 893 +++++- src/runtime/src/coreclr/jit/async.h | 80 +- src/runtime/src/coreclr/jit/block.cpp | 1 + src/runtime/src/coreclr/jit/block.h | 2 + src/runtime/src/coreclr/jit/codegenarm64.cpp | 8 +- src/runtime/src/coreclr/jit/codegencommon.cpp | 10 +- src/runtime/src/coreclr/jit/codegenlinear.cpp | 2 +- src/runtime/src/coreclr/jit/codegenxarch.cpp | 4 +- src/runtime/src/coreclr/jit/compiler.cpp | 8 +- src/runtime/src/coreclr/jit/compiler.h | 45 +- src/runtime/src/coreclr/jit/copyprop.cpp | 6 + src/runtime/src/coreclr/jit/disasm.cpp | 4 +- src/runtime/src/coreclr/jit/ee_il_dll.cpp | 2 +- src/runtime/src/coreclr/jit/emit.cpp | 53 +- src/runtime/src/coreclr/jit/emitarm.cpp | 17 +- src/runtime/src/coreclr/jit/emitarm64.cpp | 45 +- src/runtime/src/coreclr/jit/emitarm64sve.cpp | 8 +- .../src/coreclr/jit/emitloongarch64.cpp | 18 +- src/runtime/src/coreclr/jit/emitriscv64.cpp | 2 +- src/runtime/src/coreclr/jit/emitwasm.cpp | 19 +- src/runtime/src/coreclr/jit/emitxarch.cpp | 41 +- src/runtime/src/coreclr/jit/error.cpp | 2 +- src/runtime/src/coreclr/jit/fgdiagnostic.cpp | 2 +- src/runtime/src/coreclr/jit/fginline.cpp | 255 +- src/runtime/src/coreclr/jit/fgprofile.cpp | 8 +- src/runtime/src/coreclr/jit/gcencode.cpp | 2 +- src/runtime/src/coreclr/jit/gentree.cpp | 56 +- src/runtime/src/coreclr/jit/gentree.h | 12 + src/runtime/src/coreclr/jit/hashbv.cpp | 18 +- src/runtime/src/coreclr/jit/host.h | 12 +- src/runtime/src/coreclr/jit/importer.cpp | 25 +- src/runtime/src/coreclr/jit/importercalls.cpp | 216 +- src/runtime/src/coreclr/jit/inline.cpp | 20 +- src/runtime/src/coreclr/jit/inline.def | 3 + src/runtime/src/coreclr/jit/inline.h | 6 + src/runtime/src/coreclr/jit/inlinepolicy.cpp | 4 +- src/runtime/src/coreclr/jit/jitconfigvalues.h | 6 + src/runtime/src/coreclr/jit/jitmetadata.cpp | 2 +- src/runtime/src/coreclr/jit/lclvars.cpp | 6 +- src/runtime/src/coreclr/jit/lower.cpp | 10 +- src/runtime/src/coreclr/jit/lsra.cpp | 2 +- src/runtime/src/coreclr/jit/morph.cpp | 2 +- src/runtime/src/coreclr/jit/objectalloc.cpp | 4 +- src/runtime/src/coreclr/jit/optcse.cpp | 23 +- src/runtime/src/coreclr/jit/optimizebools.cpp | 31 +- src/runtime/src/coreclr/jit/optimizer.cpp | 6 +- src/runtime/src/coreclr/jit/promotion.cpp | 2 +- .../src/coreclr/jit/redundantbranchopts.cpp | 33 +- src/runtime/src/coreclr/jit/scev.cpp | 2 +- src/runtime/src/coreclr/jit/ssabuilder.cpp | 15 +- .../src/coreclr/jit/ssarenamestate.cpp | 2 +- src/runtime/src/coreclr/jit/unwind.cpp | 2 +- src/runtime/src/coreclr/jit/unwindarmarch.cpp | 54 +- .../src/coreclr/jit/unwindloongarch64.cpp | 46 +- src/runtime/src/coreclr/jit/unwindriscv64.cpp | 46 +- src/runtime/src/coreclr/jit/utils.cpp | 2 +- src/runtime/src/coreclr/jit/valuenum.cpp | 76 +- src/runtime/src/coreclr/jit/wellknownargs.h | 15 + .../src/coreclr/md/ceefilegen/blobfetcher.cpp | 2 +- src/runtime/src/coreclr/md/compiler/disp.cpp | 16 +- .../src/coreclr/nativeaot/Runtime/startup.cpp | 2 +- .../nativeaot/Runtime/unix/PalCreateDump.cpp | 1 - .../src/Resources/Strings.resx | 45 - ...System.Private.Reflection.Execution.csproj | 3 - .../pal/src/exception/remote-unwind.cpp | 2 - .../coreclr/pal/src/exception/seh-unwind.cpp | 1 - .../src/coreclr/pal/src/misc/sysinfo.cpp | 1 - .../CompilerTypeSystemContext.Wasm.cs | 29 +- .../tools/Common/InstructionSetHelpers.cs | 6 - .../tools/Common/JitInterface/CorInfoImpl.cs | 18 +- .../tools/Common/JitInterface/CorInfoTypes.cs | 4 + .../tools/Common/JitInterface/WasmLowering.cs | 26 +- .../Dataflow/GenericArgumentDataFlow.cs | 44 +- .../Compiler/Dataflow/ReflectionMarker.cs | 22 +- .../DataflowAnalyzedTypeDefinitionNode.cs | 16 +- .../IL/ILImporter.Scanner.cs | 7 + .../MissingVirtualSignature/Dependency.cs | 6 + .../MissingVirtualSignature/Input.cs | 30 + .../TestCases/R2RTestSuites.cs | 37 +- .../TestCasesRunner/R2RTestRunner.cs | 4 + .../WasmArgumentLayoutTests.cs | 37 + .../InheritedVirtualMethodsNode.cs | 93 +- .../ReadyToRun/TypeHandle.cs | 2 +- .../Compiler/ReadyToRunCodegenCompilation.cs | 4 + .../src/coreclr/tools/metainfo/mdinfo.cpp | 1 + .../tools/superpmi/superpmi-shared/agnostic.h | 4 + .../superpmi-shared/methodcontext.cpp | 8 + .../superpmi/superpmi-shared/standardpch.h | 1 + .../src/coreclr/utilcode/loaderheap.cpp | 8 +- .../coreclr/utilcode/loaderheap_shared.cpp | 4 +- .../src/coreclr/vm/amd64/cgenamd64.cpp | 4 +- .../src/coreclr/vm/amd64/excepamd64.cpp | 4 +- src/runtime/src/coreclr/vm/appdomain.cpp | 14 +- src/runtime/src/coreclr/vm/arm/stubs.cpp | 2 +- .../src/coreclr/vm/arm64/singlestepper.cpp | 11 +- src/runtime/src/coreclr/vm/arm64/stubs.cpp | 10 +- src/runtime/src/coreclr/vm/ceeload.cpp | 4 +- src/runtime/src/coreclr/vm/ceemain.cpp | 2 +- src/runtime/src/coreclr/vm/class.cpp | 4 +- .../src/coreclr/vm/classlayoutinfo.cpp | 8 +- src/runtime/src/coreclr/vm/clrex.cpp | 2 +- src/runtime/src/coreclr/vm/clrex.h | 2 +- src/runtime/src/coreclr/vm/clsload.cpp | 2 +- src/runtime/src/coreclr/vm/codeman.cpp | 4 +- src/runtime/src/coreclr/vm/comdelegate.cpp | 2 +- src/runtime/src/coreclr/vm/common.h | 3 +- src/runtime/src/coreclr/vm/comutilnative.cpp | 7 +- src/runtime/src/coreclr/vm/corelib.h | 4 + src/runtime/src/coreclr/vm/crst.cpp | 10 +- src/runtime/src/coreclr/vm/dllimport.cpp | 6 +- src/runtime/src/coreclr/vm/dynamicmethod.cpp | 48 +- .../src/coreclr/vm/eedbginterfaceimpl.cpp | 16 +- .../src/coreclr/vm/eetoprofinterfaceimpl.cpp | 110 +- src/runtime/src/coreclr/vm/eetwain.cpp | 6 +- src/runtime/src/coreclr/vm/encee.cpp | 6 +- src/runtime/src/coreclr/vm/excep.cpp | 18 +- .../src/coreclr/vm/exceptionhandling.cpp | 24 +- .../src/coreclr/vm/gcenv.ee.common.cpp | 8 +- .../src/coreclr/vm/gcheaputilities.cpp | 3 +- src/runtime/src/coreclr/vm/gchelpers.cpp | 2 +- src/runtime/src/coreclr/vm/generics.cpp | 2 +- src/runtime/src/coreclr/vm/i386/cgenx86.cpp | 18 +- src/runtime/src/coreclr/vm/ilstubcache.cpp | 2 +- src/runtime/src/coreclr/vm/jithelpers.cpp | 28 +- src/runtime/src/coreclr/vm/jitinterface.cpp | 34 +- .../coreclr/vm/loongarch64/singlestepper.cpp | 11 +- .../src/coreclr/vm/loongarch64/stubs.cpp | 15 +- src/runtime/src/coreclr/vm/methodtable.cpp | 2 +- .../src/coreclr/vm/methodtablebuilder.cpp | 4 +- src/runtime/src/coreclr/vm/mlinfo.cpp | 8 +- src/runtime/src/coreclr/vm/multicorejitimpl.h | 3 +- .../src/coreclr/vm/multicorejitplayer.cpp | 13 +- src/runtime/src/coreclr/vm/object.cpp | 3 +- src/runtime/src/coreclr/vm/peimagelayout.cpp | 2 +- src/runtime/src/coreclr/vm/perfmap.cpp | 7 +- .../src/coreclr/vm/proftoeeinterfaceimpl.cpp | 116 +- src/runtime/src/coreclr/vm/rcwrefcache.cpp | 2 +- .../src/coreclr/vm/riscv64/singlestepper.cpp | 11 +- src/runtime/src/coreclr/vm/riscv64/stubs.cpp | 15 +- src/runtime/src/coreclr/vm/stackwalk.cpp | 15 +- src/runtime/src/coreclr/vm/stubgen.cpp | 7 +- src/runtime/src/coreclr/vm/stubhelpers.cpp | 4 +- src/runtime/src/coreclr/vm/stubmgr.cpp | 67 +- src/runtime/src/coreclr/vm/syncblk.cpp | 9 +- src/runtime/src/coreclr/vm/threads.cpp | 11 +- src/runtime/src/coreclr/vm/threadsuspend.cpp | 18 +- .../src/coreclr/vm/tieredcompilation.cpp | 2 +- src/runtime/src/coreclr/vm/util.cpp | 42 +- src/runtime/src/coreclr/vm/wasm/helpers.cpp | 18 +- .../aspnetcore/Http3/QPack/QPackDecoder.cs | 12 + .../src/System/Net/Http/aspnetcore/SR.resx | 3 + .../Net/aspnetcore/Http3/QPackDecoderTest.cs | 14 + .../gen/DiagDescriptors.cs | 6 + .../gen/Emitter.cs | 423 ++- .../gen/Model/ValidatedMember.cs | 6 +- .../gen/Model/ValidatedModel.cs | 3 + .../gen/Model/ValidationAttributeInfo.cs | 2 +- .../gen/Parser.cs | 246 +- .../gen/Resources/Strings.resx | 6 + .../gen/Resources/xlf/Strings.cs.xlf | 10 + .../gen/Resources/xlf/Strings.de.xlf | 10 + .../gen/Resources/xlf/Strings.es.xlf | 10 + .../gen/Resources/xlf/Strings.fr.xlf | 10 + .../gen/Resources/xlf/Strings.it.xlf | 10 + .../gen/Resources/xlf/Strings.ja.xlf | 10 + .../gen/Resources/xlf/Strings.ko.xlf | 10 + .../gen/Resources/xlf/Strings.pl.xlf | 10 + .../gen/Resources/xlf/Strings.pt-BR.xlf | 10 + .../gen/Resources/xlf/Strings.ru.xlf | 10 + .../gen/Resources/xlf/Strings.tr.xlf | 10 + .../gen/Resources/xlf/Strings.zh-Hans.xlf | 10 + .../gen/Resources/xlf/Strings.zh-Hant.xlf | 10 + .../gen/SymbolHolder.cs | 7 +- .../gen/SymbolLoader.cs | 24 +- .../tests/SourceGeneration.Unit.Tests/Main.cs | 547 ++++ ...Options.SourceGeneration.Unit.Tests.csproj | 1 + .../OptionsRuntimeTests.cs | 781 ++++- .../Resources/Strings.resx | 6 + .../Baselines/NetCoreApp/Validators.g.cs | 247 +- .../Baselines/NetFX/Validators.g.cs | 156 +- .../Generated/KeywordNamesTests.cs | 33 + .../Resources/Strings.resx | 6 + .../TestClasses/KeywordNames.cs | 2 +- .../TestClasses/SelfValidation.cs | 28 + ...ted.SerializableAssembly.XmlSerializers.cs | 2856 +++++++++-------- .../SafeHandles/SafeProcessHandle.Unix.cs | 4 +- .../src/Resources/Strings.resx | 6 + .../src/Resources/Strings.resx | 5 +- .../StressTests/HttpStress/HttpStress.csproj | 2 +- .../Managed/HttpListenerRequest.Managed.cs | 18 +- .../Net/Windows/WebSockets/WebSocketBase.cs | 18 +- .../tests/HttpListenerRequestTests.cs | 2 - .../tests/HttpListenerWebSocketTests.cs | 64 + .../tests/InvalidClientRequestTests.cs | 9 + .../src/System/Net/Mail/MailAddress.cs | 11 + .../MailAddressDisplayNameTest.cs | 16 + .../MailAddressTests/MailAddressParserTest.cs | 11 + .../MailAddressParsingTest.cs | 1 - .../ref/System.Net.NameResolution.cs | 38 + .../src/Resources/Strings.resx | 3 + .../src/System/Net/Dns.Resolve.cs | 57 + .../src/System/Net/DnsResolver.cs | 4 + .../src/System/Net/DnsResolverPal.Managed.cs | 13 + .../System/Net/DnsResolverPal.Unsupported.cs | 2 + .../DnsResolverLoopbackTest.cs | 42 +- .../tests/FunctionalTests/DnsResolverTest.cs | 103 +- .../NetworkAddressChange.OSX.cs | 14 +- .../src/System/Net/Quic/QuicStream.cs | 9 +- .../SslAuthenticationOptionsTests.Desktop.cs | 85 + .../SslAuthenticationOptionsTests.cs | 71 +- .../System.Net.Security.Unit.Tests.csproj | 5 + .../src/Resources/Strings.resx | 2 +- .../Runtime/InteropServices/ComWrappers.cs | 323 +- .../src/System/Xml/Linq/XContainer.cs | 161 +- .../tests/misc/RegressionTests.cs | 210 ++ .../ReflectionXmlSerializationReader.cs | 86 +- .../ReflectionXmlSerializationWriter.cs | 239 +- .../Serialization/XmlSerializationReader.cs | 24 +- .../XmlSerializationReaderILGen.cs | 36 +- .../tests/XmlSerializer/XmlSerializerTests.cs | 82 + .../ConvertToLibraryImportFixerTests.cs | 4 +- .../src/System/Number.BigInteger.cs | 5 + .../tests/BigInteger/parse.cs | 5 + .../tests/SerializationTypes.RuntimeOnly.cs | 46 + .../System/Numerics/BFloat16Tests.cs | 56 +- .../RateLimiting/SlidingWindowRateLimiter.cs | 77 +- .../tests/SlidingWindowRateLimiterTests.cs | 296 +- src/runtime/src/mono/mono/eglib/glib.h | 16 +- src/runtime/src/mono/mono/eglib/gmem.c | 6 +- src/runtime/src/mono/mono/metadata/class.c | 4 +- .../src/mono/mono/metadata/debug-helpers.c | 2 +- src/runtime/src/mono/mono/metadata/icall.c | 2 +- .../src/mono/mono/metadata/jit-icall-reg.h | 1 + src/runtime/src/mono/mono/metadata/threads.c | 6 +- src/runtime/src/mono/mono/mini/driver.c | 2 +- .../src/mono/mono/mini/interp/interp-pgo.c | 2 +- .../src/mono/mono/mini/interp/jiterpreter.c | 8 +- .../src/mono/mono/mini/interp/transform-opt.c | 2 +- .../src/mono/mono/mini/interp/transform.c | 20 +- src/runtime/src/mono/mono/mini/jit-icalls.c | 9 + src/runtime/src/mono/mono/mini/jit-icalls.h | 2 + src/runtime/src/mono/mono/mini/method-to-ir.c | 42 +- src/runtime/src/mono/mono/mini/mini-arm64.c | 2 +- src/runtime/src/mono/mono/mini/mini-runtime.c | 1 + src/runtime/src/mono/mono/mini/tramp-amd64.c | 2 +- .../src/mono/mono/utils/mono-os-mutex.c | 4 +- .../mono/utils/mono-threads-state-machine.c | 2 +- .../src/mono/mono/utils/mono-threads.c | 4 +- ...rosoft.NET.Sdk.WebAssembly.Browser.targets | 1 - .../src/native/corehost/bundle/reader.h | 4 +- .../src/native/corehost/fxr/sdk_resolver.cpp | 4 +- .../src/native/corehost/hostmisc/trace.c | 2 +- .../src/native/corehost/hostmisc/trace.h | 27 +- .../corehost/hostpolicy/deps_format.cpp | 2 +- .../native/corehost/hostpolicy/hostpolicy.cpp | 2 +- .../hostpolicy/hostpolicy_context.cpp | 4 + .../corehost/hostpolicy/hostpolicy_init.cpp | 6 +- .../src/native/libs/Common/pal_compiler.h | 4 +- .../native/libs/System.Native/pal_string.h | 2 +- .../osslcompat_30.h | 3 +- .../CoreCLRContracts.cs | 4 +- .../ClrDataAppDomain.cs | 27 +- .../ClrDataExceptionState.cs | 36 +- .../ClrDataFrame.cs | 54 +- .../ClrDataMethodDefinition.cs | 47 +- .../ClrDataMethodInstance.cs | 57 +- .../ClrDataModule.cs | 186 +- .../ClrDataStackWalk.cs | 20 +- .../ClrDataTask.cs | 84 +- .../ClrDataTypeDefinition.cs | 185 +- .../ClrDataTypeInstance.cs | 184 +- .../ClrDataValue.cs | 112 +- .../Dbi/DacDbiImpl.cs | 144 +- .../MetaDataImportImpl.cs | 349 +- .../SOSDacImpl.ICLRDataEnumMemoryRegions.cs | 7 +- .../SOSDacImpl.IXCLRDataProcess.cs | 353 +- .../SOSDacImpl.cs | 247 +- .../mscordaccore_universal/Entrypoints.cs | 43 +- .../DacDbi/DacDbiAppDomainDumpTests.cs | 2 +- .../DacDbi/DacDbiApproxTypeHandleDumpTests.cs | 2 +- .../DumpTests/DacDbi/DacDbiCCWDumpTests.cs | 2 +- .../DacDbi/DacDbiComWrappersDumpTests.cs | 2 +- .../DacDbi/DacDbiDebuggerDumpTests.cs | 2 +- .../DacDbi/DacDbiExactTypeHandleDumpTests.cs | 2 +- .../DumpTests/DacDbi/DacDbiGCDumpTests.cs | 2 +- .../DacDbi/DacDbiHeapWalkDumpTests.cs | 2 +- .../DumpTests/DacDbi/DacDbiLoaderDumpTests.cs | 2 +- .../DacDbi/DacDbiMultiModuleDumpTests.cs | 2 +- .../DumpTests/DacDbi/DacDbiObjectDumpTests.cs | 2 +- .../DumpTests/DacDbi/DacDbiRCWDumpTests.cs | 2 +- .../DacDbi/DacDbiRefWalkDumpTests.cs | 2 +- .../DacDbi/DacDbiStackWalkDumpTests.cs | 2 +- .../DumpTests/DacDbi/DacDbiThreadDumpTests.cs | 2 +- .../DumpTests/ISOSDacInterface13Tests.cs | 2 +- .../tests/DumpTests/ISOSDacInterfaceTests.cs | 2 +- .../DumpTests/IXCLRDataAppDomainDumpTests.cs | 2 +- .../DumpTests/IXCLRDataFrameDumpTests.cs | 2 +- .../IXCLRDataMethodDefinitionDumpTests.cs | 4 +- .../DumpTests/IXCLRDataValueDumpTests.cs | 4 +- .../DumpTests/MetaDataImportDumpTests.cs | 2 +- .../tests/DumpTests/StackWalkDumpTests.cs | 12 +- .../tests/DumpTests/StressLogDumpTests.cs | 6 +- .../UnitTests/ClrDataExceptionStateTests.cs | 57 +- .../tests/UnitTests/ClrDataRequestTests.cs | 8 +- .../cdac/tests/UnitTests/ClrDataTaskTests.cs | 2 +- .../cdac/tests/UnitTests/DacDbiImplTests.cs | 34 +- .../UnitTests/FunctionTableAccessTests.cs | 12 +- .../tests/UnitTests/GetRegisterNameTests.cs | 2 +- .../tests/UnitTests/IXCLRDataProcessTests.cs | 8 +- .../cdac/tests/UnitTests/LoaderTests.cs | 6 +- .../UnitTests/MetaDataImportImplTests.cs | 26 +- .../cdac/tests/UnitTests/MethodTableTests.cs | 4 +- .../cdac/tests/UnitTests/ObjectTests.cs | 2 +- .../tests/UnitTests/SOSDacInterface5Tests.cs | 2 +- .../tests/UnitTests/SOSDacInterface8Tests.cs | 9 +- .../cdac/tests/UnitTests/StackWalkTests.cs | 2 +- .../cdac/tests/UnitTests/TypeHandleTests.cs | 13 +- ...tics.DataContractReader.Usage.Tests.csproj | 1 - .../tests/UsageTests/UsageGraphFixture.cs | 8 +- .../CdacUsageGraph/Analysis/UsageWalker.cs | 28 + .../src/CdacUsageGraph/AnalysisOptions.cs | 9 - .../src/CdacUsageGraph/AnalysisPipeline.cs | 41 +- .../src/CdacUsageGraph/CdacSymbols.cs | 4 + .../src/CdacUsageGraph/CdacUsageGraph.csproj | 14 +- .../src/CdacUsageGraph/Commands.cs | 20 +- .../Compilation/CdacCompilationLoader.cs | 6 +- .../Discovery/ContractRegistrationParser.cs | 22 +- .../Docs/DocDescriptorMeanings.cs | 2 +- .../Docs/DocDescriptorOverrides.cs | 2 +- .../src/CdacUsageGraph/Docs/DocGenerator.cs | 2 +- .../Semantic/CdacSymbolMatcher.cs | 6 + .../src/CdacUsageGraph/UsageGraphAnalyzer.cs | 24 +- .../DataTypeIndexTests.cs | 215 +- .../UsageWalkerIntegrationTests.cs | 15 +- src/runtime/src/native/minipal/cpufeatures.c | 6 +- src/runtime/src/native/minipal/log.h | 2 +- src/runtime/src/native/minipal/types.h | 19 +- .../AssetsComputingHelper.cs | 26 +- .../coreclr/InterpToNativeGenerator.cs | 9 +- .../WasmAppBuilder/coreclr/SignatureMapper.cs | 76 +- .../WasmAppBuilder/mono/PInvokeCollector.cs | 20 +- .../Interop/COM/ComWrappers/API/Program.cs | 39 +- .../JitBlue/Runtime_130700/Runtime_130700.cs | 207 ++ .../Runtime_130700/Runtime_130700.csproj | 14 + .../JitBlue/Runtime_132268/Runtime_132268.cs | 47 + .../WasmR2RStructAlignment.cs | 164 + .../WasmR2RStructAlignment.csproj | 11 + .../JIT/Regression/Regression_ro_2.csproj | 1 + .../Regression/GitHub_130545.cs | 2 + .../Regression/GitHub_130545.csproj | 3 + .../generics/regressions/131537/test131537.cs | 49 + .../regressions/131537/test131537.csproj | 18 + .../asyncversion-inline.cs | 173 + .../asyncversion-inline.csproj | 5 + .../inlined-asyncversion-frames.cs | 123 + .../inlined-asyncversion-frames.csproj | 5 + .../inlined-frame-configureawait.cs | 120 + .../inlined-frame-configureawait.csproj | 5 + .../inlined-frame-contexts.cs | 203 ++ .../inlined-frame-contexts.csproj | 5 + .../inlined-frame-exceptions.cs | 74 + .../inlined-frame-exceptions.csproj | 5 + .../inlined-frame-ldvirtftn-await.cs | 74 + .../inlined-frame-ldvirtftn-await.csproj | 5 + .../inlined-frame-transition-suspends.cs | 184 ++ .../inlined-frame-transition-suspends.csproj | 5 + .../osr-inlined-contexts.cs | 129 + .../osr-inlined-contexts.csproj | 18 + .../src/tests/async/regression/126750.cs | 94 + .../src/tests/async/regression/126750.csproj | 5 + .../DynamicOptimization.csproj | 2 + .../illink/src/ILLink.CodeFix/Resources.resx | 3 + .../UnsafeModifierCodeFixHelpers.cs | 20 +- .../DynamicallyAccessedMembersAnalyzer.cs | 23 +- .../GenericArgumentDataFlow.cs | 6 +- .../Linker.Dataflow/ReflectionMarker.cs | 14 +- .../src/linker/Linker.Steps/MarkStep.cs | 96 +- ...mentationSignatureGenerator.PartVisitor.cs | 2 +- .../AddUnsafeToExternCodeFixTests.cs | 2 +- .../RemoveUndocumentedUnsafeCodeFixTests.cs | 2 + .../RequiresUnsafeCodeFixTests.cs | 4 +- ...MissingSafetyDocumentationAnalyzerTests.cs | 5 +- .../DataFlow/GenericParameterDataFlow.cs | 1 - .../GenericParameterDataFlowMarking.cs | 39 + .../RequiresCapability/RequiresOnClass.cs | 82 + src/source-manifest.json | 6 +- 500 files changed, 14728 insertions(+), 4767 deletions(-) create mode 100644 src/runtime/docs/design/coreclr/jit/runtime-async-inlining.md create mode 100644 src/runtime/eng/common/Get-GitHubAppToken.ps1 create mode 100644 src/runtime/eng/common/core-templates/steps/get-github-app-token.yml create mode 100644 src/runtime/eng/common/templates-official/steps/get-github-app-token.yml create mode 100644 src/runtime/eng/common/templates/steps/get-github-app-token.yml create mode 100755 src/runtime/eng/native/sccache-xarch-wrapper.sh create mode 100644 src/runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCases/MissingVirtualSignature/Dependency.cs create mode 100644 src/runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCases/MissingVirtualSignature/Input.cs create mode 100644 src/runtime/src/libraries/System.Net.Security/tests/UnitTests/SslAuthenticationOptionsTests.Desktop.cs delete mode 100644 src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/AnalysisOptions.cs create mode 100644 src/runtime/src/tests/JIT/Regression/JitBlue/Runtime_130700/Runtime_130700.cs create mode 100644 src/runtime/src/tests/JIT/Regression/JitBlue/Runtime_130700/Runtime_130700.csproj create mode 100644 src/runtime/src/tests/JIT/Regression/JitBlue/Runtime_132268/Runtime_132268.cs create mode 100644 src/runtime/src/tests/JIT/Regression/JitBlue/WasmR2RStructAlignment/WasmR2RStructAlignment.cs create mode 100644 src/runtime/src/tests/JIT/Regression/JitBlue/WasmR2RStructAlignment/WasmR2RStructAlignment.csproj create mode 100644 src/runtime/src/tests/Loader/classloader/generics/regressions/131537/test131537.cs create mode 100644 src/runtime/src/tests/Loader/classloader/generics/regressions/131537/test131537.csproj create mode 100644 src/runtime/src/tests/async/asyncversion-inline/asyncversion-inline.cs create mode 100644 src/runtime/src/tests/async/asyncversion-inline/asyncversion-inline.csproj create mode 100644 src/runtime/src/tests/async/inlined-asyncversion-frames/inlined-asyncversion-frames.cs create mode 100644 src/runtime/src/tests/async/inlined-asyncversion-frames/inlined-asyncversion-frames.csproj create mode 100644 src/runtime/src/tests/async/inlined-frame-configureawait/inlined-frame-configureawait.cs create mode 100644 src/runtime/src/tests/async/inlined-frame-configureawait/inlined-frame-configureawait.csproj create mode 100644 src/runtime/src/tests/async/inlined-frame-contexts/inlined-frame-contexts.cs create mode 100644 src/runtime/src/tests/async/inlined-frame-contexts/inlined-frame-contexts.csproj create mode 100644 src/runtime/src/tests/async/inlined-frame-exceptions/inlined-frame-exceptions.cs create mode 100644 src/runtime/src/tests/async/inlined-frame-exceptions/inlined-frame-exceptions.csproj create mode 100644 src/runtime/src/tests/async/inlined-frame-ldvirtftn-await/inlined-frame-ldvirtftn-await.cs create mode 100644 src/runtime/src/tests/async/inlined-frame-ldvirtftn-await/inlined-frame-ldvirtftn-await.csproj create mode 100644 src/runtime/src/tests/async/inlined-frame-transition-suspends/inlined-frame-transition-suspends.cs create mode 100644 src/runtime/src/tests/async/inlined-frame-transition-suspends/inlined-frame-transition-suspends.csproj create mode 100644 src/runtime/src/tests/async/osr-inlined-contexts/osr-inlined-contexts.cs create mode 100644 src/runtime/src/tests/async/osr-inlined-contexts/osr-inlined-contexts.csproj create mode 100644 src/runtime/src/tests/async/regression/126750.cs create mode 100644 src/runtime/src/tests/async/regression/126750.csproj diff --git a/src/runtime/.config/dotnet-tools.json b/src/runtime/.config/dotnet-tools.json index 111aec2c8a2a..74ab0de00949 100644 --- a/src/runtime/.config/dotnet-tools.json +++ b/src/runtime/.config/dotnet-tools.json @@ -27,7 +27,7 @@ ] }, "microsoft.dotnet.helix.jobmonitor": { - "version": "11.0.0-beta.26407.8", + "version": "11.0.0-beta.26411.119", "commands": [ "dotnet-helix-job-monitor" ] diff --git a/src/runtime/docs/design/coreclr/botr/readytorun-format.md b/src/runtime/docs/design/coreclr/botr/readytorun-format.md index a6b6c8f11817..6e4184afa653 100644 --- a/src/runtime/docs/design/coreclr/botr/readytorun-format.md +++ b/src/runtime/docs/design/coreclr/botr/readytorun-format.md @@ -1078,6 +1078,9 @@ The string format is: | `V` | returns `v128` (a `Vector128`, or a 16-byte `Vector`) | | `S` | struct return via hidden buffer, `N` is the struct size in bytes | +Struct returns always use `S` regardless of alignment. The aligned form is valid only +for parameters because their placement in the transition block depends on it. + **This pointer** (if the method has a `this` parameter): | Encoding | Meaning | @@ -1103,7 +1106,8 @@ it knows a hidden retbuf pointer argument is present in the Wasm parameter list. | `f` | `f32` parameter | | `d` | `f64` parameter | | `V` | `v128` parameter (a `Vector128`, or a 16-byte `Vector`, passed by value) | -| `S` | struct parameter passed by reference, `` is the struct size in bytes | +| `S` | struct parameter passed by reference, `` is the struct size in bytes and its alignment is at most 8 | +| `A` | struct parameter passed by reference, `` is the struct size in bytes and its alignment exceeds 8 | | `e` | empty struct parameter — elided from Wasm args but present in the string | | `` | multi-slot parameter passed by value, see below | @@ -1124,8 +1128,8 @@ matching the treatment of a struct wrapping a `v128`. The digit is required. A repeated slot character without one — `ll`, `VV` — is not an aggregate: it is two independent scalar parameters, which is how every implementation reads it. So `ll2VV4` is `i64`, `Int128`, `Vector128`, `Vector512`. The grammar stays -unambiguous because no other token places a digit after a slot character; `S` consumes -its own digits. +unambiguous because no other token places a digit after a slot character; struct tokens +consume their own size. These types are still *returned* through a hidden buffer, encoded as `S` like any other aggregate. Limitation: a single digit carries both the slot count and the elevation factor, @@ -1136,6 +1140,10 @@ elevation 1. No such type exists in the Wasm ABI today. WasmAppBuilder does not emit or consume multi-slot tokens: they do not appear in `InternalCall` or `PInvoke` signatures. +A struct argument is placed at its own alignment clamped to `[8, 16]` in the transition +block. Therefore `A` covers every struct whose declared alignment exceeds 8: alignments +of 16 or higher all require the same 16-byte transition-block placement. + **Suffix**: | Encoding | Meaning | @@ -1162,14 +1170,15 @@ prefix to distinguish thunk categories: | `void F(int x)` (instance) | `vTip` | | `static MyStruct F()` where `MyStruct` is 16 bytes | `S16p` | | `static void F(MyStruct s)` where `MyStruct` is 8 bytes | `vS8p` | +| `static void F(long tag, MyStruct s, int t)` where `MyStruct` is 32 bytes and at least 16-byte aligned | `vlA32ip` | | `static int F(float x, double y)` | `ifdp` | | `static long F(long tag, Int128 v, int t)` | `lll2ip` | | `static int F(long tag, Vector512 v, int t)` | `ilV4ip` | | `[UnmanagedCallersOnly] static int F(int x)` | `ii` | **Slot sizing for structs**: When computing interpreter stack layout, struct parameters -(`S`) consume `max(N / 8, 1)` interpreter stack slots, while all other parameter types -consume exactly 1 slot. +(`S` and `A`) consume `max((N + 7) / 8, 1)` interpreter stack slots, while all +other parameter types consume exactly 1 slot. # References diff --git a/src/runtime/docs/design/coreclr/jit/runtime-async-inlining.md b/src/runtime/docs/design/coreclr/jit/runtime-async-inlining.md new file mode 100644 index 000000000000..30b8b57aa65d --- /dev/null +++ b/src/runtime/docs/design/coreclr/jit/runtime-async-inlining.md @@ -0,0 +1,352 @@ +# General runtime async inlining + +This document outlines some challenges and thoughts behind general inlining of runtime async calls. + +## Background + +Runtime async comes with several user-visible behaviors that must be preserved when inlining. +These can be categorized in behaviors attached to the call site and behaviors attached to the callee. + +### Await/call site behaviors + +Custom awaiters and synchronous Task/ValueTask-returning functions can be inlined today, so below we consider only runtime async backed implementations. + +- Every suspending await saves/restores the `ExecutionContext`. +Concretely this is what saves and restores the values of `AsyncLocal` if suspension/resumption happens around an await. +The behavior of this cannot be configured per-await, but it can be configured globally via `ExecutionContext.SuppressFlow()`. +For our purposes we can consider this to always require saving/restoration. +- For suspending `Task` and `ValueTask` awaits the resumption behavior is configurable: + + By default, the current `SynchronizationContext` or `TaskScheduler` is captured and the continuation is posted to it. + + If `ConfigureAwait(false)` is applied the continuation is run on the thread pool. + + The "location to continue", either a `SynchronizationContext`, `TaskScheduler` or the thread pool, is collectively called the _continuation context_ in this document. + +For awaits that finish synchronously (i.e. do not suspend) no additional work happens at the call site. + +To accomplish the above the JIT works together with async infrastructure: +- Suspension generates code to obtain and save the `ExecutionContext` into the `Continuation` object. +On resumption, async infrastructure restores the `ExecutionContext` before calling back into JIT'ed code. +- Suspension generates code to capture continuation context information into the `Continuation` object. +On resumption, async infrastructure ensures that the continuation runs in the captured continuation context. + +The above are accomplished with several helpers returned via the `getAsyncInfo` JIT-EE helper: +- `AsyncHelpers.CaptureExecutionContext` +- `AsyncHelpers.CaptureContinuationContext` +- `AsyncHelpers.FinishSuspensionNoContinuationContext` (optimized case) +- `AsyncHelpers.FinishSuspensionWithContinuationContext` (optimized case) + +### Function/callee behaviors +Every runtime async function body is wrapped with save and restore of the async contexts on the current Thread object. +This restore happens only when the function finishes synchronously. +Concretely a runtime async function ends up looking like: +```csharp +ExecutionContext execContext; +SynchronizationContext syncContext; +AsyncHelpers.CaptureContexts(out execContext, out syncContext); +try +{ + // actual user code +} +finally +{ + AsyncHelpers.RestoreContexts(resumed, execContext, syncContext); +} +``` + +Note the `resumed` argument, used to check if the runtime async function finished synchronously or not. +If the runtime async function finished after resuming then contexts are not restored. + +Additionally, every suspension _also_ restores the contexts. +This is done by inserting a similar call +```csharp +AsyncHelpers.RestoreContextsOnSuspension(resumed, execContext, syncContext) +``` +in suspensions. +This is folded into the `AsyncHelpers.FinishSuspensionNoContinuationContext` and `AsyncHelpers.FinishSuspensionWithContinuationContext` helpers. +The JIT uses those helpers whenever possible. + +## Inlining runtime async calls +When inlining a runtime async call we remove both a call site and the callee. +This removes the user-visible behaviors discussed above. +To inline correctly we need to ensure the JIT preserves these behaviors. + +### Suspending inside an inlinee + +Consider a scenario like: + +```csharp +async Task A() +{ + ... + await B(); + ... +} + +async Task B() +{ + ... + await C(); + ... +} + +async Task C() +{ + ... + await Task.Yield(); + ... +} +``` +Now assume that we have available bools `resumed_A`, `resumed_B`, `resumed_C` that represent whether `A`, `B` and `C` are currently running after being resumed (true), or whether they are running because they were started and have never suspended before (false). +Note that `resumed_C` and `resumed_B` can switch between true/false multiple times during the execution if `B` and `C` are in loops, while `resumed_A` will switch to `true` and then stay `true`. + +Assume we inlined `B()` and `C()` into `A`, and that we are logically suspending on `Task.Yield()` in `C`. +What does this suspension capture? That depends on `resumed_B` and `resumed_C`. +- Let's first consider `!resumed_C`. +This means that we just started running `C`, and on suspension we would restore `ExecutionContext` and `SynchronizationContext` from the beginning of `C` into the `Thread` object. +If we hadn't inlined then `B`'s frame would be physically present on the stack due to `!resumed_C`, so after returning it would create and link its own continuation. +This continuation would capture the `ExecutionContext` restored by `C` and also capture continuation context information based on the `SynchronizationContext` restored by `C`. +- If `resumed_C` then `B`'s frame would not be physically present on the stack. +Rather, the existing `B` continuation would be linked to the newly created `C` continuation by async infrastructure. +It would maintain its values from the time we suspended in `C` with `!resumed_C`. + +The take away is that the suspension for the inlined `Task.Yield()` needs to roughly accomplish the following, in addition to storing its normal state: +```csharp +continuation = AllocOrReuseContinuation(); +CaptureContinuationContext(continuation, ref continuation.ContinuationContext, ref continuation.Flags); // In the general case, but not for Task.Yield() +CaptureExecutionContext(continuation, ref continuation.ExecutionContext); +if (!resumed_C) +{ + RestoreContextsOnSuspension(false, execContext_C, syncContext_C); + // Logical return to B and linking in B's continuation + CaptureContinuationContext(continuation, ref continuation.ContinuationContextForB, ref continuation.FlagsForB) + CaptureExecutionContext(continuation, ref continuation.ExecutionContextForB); + if (!resumed_B) + { + RestoreContextsOnSuspension(false, execContext_B, syncContext_B); + // Logical return to A and linking in A's continuation + CaptureContinuationContext(continuation, ref continuation.ContinuationContextForA, ref continuation.FlagsForA) + CaptureExecutionContext(continuation, ref continuation.ExecutionContextForA); + + RestoreContextsOnSuspension(resumed_A, execContext_A, syncContext_A); + } + else + { + // keep continuation.ContinuationContextForA, FlagsForA, ExecutionContextForA + } +} +else +{ + // keep continuation.ContinuationContextForB, FlagsForB, ExecutionContextForB +} +``` +Note also that we have the implications `resumed_C` implies `resumed_B` implies `resumed_A` simplifying the `else` cases here. +The else cases also rely on `continuation.ContinuationContextForB/A` staying assigned in the continuations, which is the case only because the JIT allocates a single continuation and reuses it throughout the execution of `A`. + +This may look like a large amount of code for every suspension inside `C`, but sharing of tails is possible since all the inlined suspensions end with the same code that does not change per suspension site. + +### Resuming inside an inlinee + +Let's imagine we resume at the inlined `Task.Yield()` in `C`. +Initially such a resumption progresses as normal: async infrastructure restores the `ExecutionContext` that was saved. +If this was a task await (which it isn't, but often will be), the async infrastructure ensures it is running in the right continuation context. +Then it resumes in the code. + +When `C` logically returns to `B` we need to handle what the async infrastructure would have handled for us. +Call this the _post-inline IR_. +- We need to restore the `ExecutionContext` that we captured for the suspension at `C()`. +Logically, we need to do something like +```csharp +if (resumed_C) + AsyncHelpers.RestoreExecutionContext(Thread.CurrentThreadAssumedInitialized, continuation.ExecutionContextForB); +``` +- We need to ensure we're running on the proper continuation context. +The JIT cannot accomplish this on its own; there is no way to directly set up the environment without posting a callback. +Hence, in the case where we are not running in the right context we need help from async infrastructure to proceed with a suspension+switch+resumption: +```csharp +if (resumed_C && !AsyncHelpers.IsOnRightContext(continuation.ContinuationContextForB, continuation.FlagsForB)) + await AsyncHelpers.SwitchContext(continuation.ContinuationContextForB, continuation.FlagsForB); +``` + +We expect `IsOnRightContext` to be true almost always, since it is very rare that the current synchronization context is modified, especially during the execution of async methods. +If this was a common case then it is unlikely that inlining would ever be profitable. + +The implementation expands only the `resumed_C` check as JIT IR and leaves the rest as a single +`AsyncHelpers.RestoreInlinedFrameContexts` call, which does the `ExecutionContext` restore, the +`IsOnRightContext` check and the suspension itself internally. +The synchronous case is the one worth optimizing for, and anything past the `resumed_C` check has +already paid for at least one suspension and resumption. + +### Handling synchronous saves and restores of contexts + +Recall that every runtime async function's body was wrapped with a save/restore of the contexts. +Given `resumed_A`, `resumed_B` and `resumed_C` it is not hard to insert these for every inlinee. +For example, when inlining `C` we insert code similar to: + +```csharp +ExecutionContext execContext; +SynchronizationContext syncContext; +AsyncHelpers.CaptureContexts(out execContext, out syncContext); +try +{ + // actual user code +} +finally +{ + AsyncHelpers.RestoreContexts(resumed_C, execContext, syncContext); +} +``` + +### Special cases + +The only case supported today is when we know the inlinee never suspends, by virtue of having no awaits at all. +This simplifies the cases above since `resumed_B` and `resumed_C` are always false, and all suspension points generated belong to `A`. + +### Computing `resumed_A`, `resumed_B`, `resumed_C` ... + +Today we compute the `resumed` value only for the top-level async function, since it is computed based on the async continuation parameter. +With inlinees this strategy no longer works. +Instead insert IR to compute these values at several points: +1. When starting a function `F` (whether it be the top function or start of an inlined function), assign `resumed_F = false` +2. When resuming `F` at one of its resumption points assign `resumed_F = true` +3. When logically returning from `F` to its caller, inherit the resumption status: `resumed_caller |= resumed_F`. + +Note that these are introduced at different points. (1) and (3) will likely be inserted during `PHASE_SAVE_ASYNC_CONTEXTS` while (2) will be inserted in `PHASE_ASYNC`. + +(2) is a store to `resumed_F` inserted very late. +Until the async transformation we will model this as a `LCL_ADDR` well-known argument added to all async calls. + +It is important that the JIT can reason about `resumed` booleans to be able to eliminate the cruft for inlinees that are proven to never suspend. +We would like constant propagation to realize `resumed_C` is always false if `C` has no suspension point, for example. + +### Representation of post-inline IR + +The post-inline IR we need to insert when `C` returns to `B` looks like: + +```csharp +if (resumed_C) +{ + AsyncHelpers.RestoreExecutionContext(Thread.CurrentThreadAssumedInitialized, continuation.ExecutionContextForB); + + if (!AsyncHelpers.IsOnRightContext(continuation.ContinuationContextForB, continuation.FlagsForB)) + { + await AsyncHelpers.SwitchContext(continuation.ContinuationContextForB, continuation.FlagsForB); + } + + resumed_B = true; +} +``` + +It is not clear how to represent `continuation.ExecutionContextForB`, `continuation.ContinuationContextForB` and `continuation.FlagsForB`. +This IR is likely something to insert as part of inlining, yet at that point we have not laid out the continuation yet. +To solve this we will introduce a `GT_CONTINUATION_MEMBER_OFFSET` node that represents the member offset and that is replaced by a constant as part of the async transformation. + +If the inlinee throws an exception the post-inline IR will not run. +Given that the exception may be thrown after resumption we furthermore need to propagate the indicator variable in that scenario so that the inliner's own context restore will not run. +We can reuse the try-fault inserted in the inlinee for its context save/restore to do that. + +### Exceptions + +Inlined functions can finish by throwing exceptions too. +Under normal circumstances the async infrastructures catches the exception and looks for the next continuation that may handle the exception. +Once located, the same resumption mechanism applies: the `ExecutionContext` is restored and the proper continuation context is ensured. + +Correct handling requires catching the possible exception and then rethrowing it in the post-inline IR. +The expansion for calls in try clauses would look roughly like: +```csharp +try +{ + // user code for C +} +catch (throwable ex) when (resumed_C) +{ + throwable_C = ex; +} + +if (resumed_C) +{ + AsyncHelpers.RestoreExecutionContext(Thread.CurrentThreadAssumedInitialized, continuation.ExecutionContextForB); + + if (!AsyncHelpers.IsOnRightContext(continuation.ContinuationContextForB, continuation.FlagsForB)) + { + await AsyncHelpers.SwitchContext(continuation.ContinuationContextForB, continuation.FlagsForB); + } + + resumed_B = true; + + if (throwable_C != null) + ThrowExact(throwable_C); +} +``` + +Initially we will skip inlining async calls that may suspend in try clauses. + +## Some examples + +In the following assume the presence of two synchronization contexts `_syncContext1` and `_syncContext2` that set up the global environment in some distinguishable way. + +```csharp +public static async Task Foo() +{ + SynchronizationContext.SetSynchronizationContext(_syncContext1); + await Bar(); +} + +private static async Task Bar() +{ + SynchronizationContext.SetSynchronizationContext(_syncContext2); + await Baz(); +} + +private static async Task Baz() +{ + await new AlwaysThreadPoolAwaitable(); +} + +private struct AlwaysThreadPoolAwaitable : INotifyCompletion +{ + public bool IsCompleted => false; + public void OnCompleted(Action continuation) + { + ThreadPool.QueueUserWorkItem(_ => { Thread.Sleep(100); continuation(); }); + } + public void GetResult() { } + + public AlwaysThreadPoolAwaitable GetAwaiter() => this; +} +``` + +- `Foo()` runs in the ambient synchronization context but switches its own synchronization context before awaiting `Bar()`. Its continuation captures `_syncContext1` as the continuation context. +- `Bar()` also switches its own synchronization context before awaiting `Baz()`. Its continuation captures `_syncContext2` as the continuation context. +- `Baz()` always suspends, switching onto a thread pool thread. No continuation context is captured for custom awaitables. +- On resumption, async infrastructure runs `Baz` directly in the context of `AlwaysThreadPoolAwaitable` +- Next, async infrastructure switches to `_syncContext2` to run `Bar`'s continuation +- Next, async infrastructure switches to `_syncContext1` to run `Foo`'s continuation + +Inlining in this case would need to suspend+switch+resume in both the `IsOnRightContext` checks. + +```csharp +private static AsyncLocal s_local = new(); +public static async Task Foo() +{ + s_local.Value = 1; + await Bar(); + Console.WriteLine(s_local.Value); +} + +private static async Task Bar() +{ + s_local.Value = 2; + await Baz(); + Console.WriteLine(s_local.Value); +} + +private static async Task Baz() +{ + s_local.Value = 3; + await new AlwaysThreadPoolAwaitable(); + Console.WriteLine(s_local.Value); +} +``` + +Similar to above, except this time we do not need a full bail out; rather, the post-inline handling will restore the `ExecutionContext` to make sure the value of `s_local` is properly restored. +Proper output is 3,2,1 and relies on `ExecutionContext`s having been restored by the post-inline handling. diff --git a/src/runtime/docs/project/list-of-diagnostics.md b/src/runtime/docs/project/list-of-diagnostics.md index 3e6aa5f9bcdc..13e7e9c8aef8 100644 --- a/src/runtime/docs/project/list-of-diagnostics.md +++ b/src/runtime/docs/project/list-of-diagnostics.md @@ -266,7 +266,7 @@ The diagnostic id values reserved for .NET Libraries analyzer warnings are `SYSL | __`SYSLIB1216`__ | C# language version not supported by the options validation source generator. | | __`SYSLIB1217`__ | The validation attribute is only applicable to properties of type string, array, or ICollection; it cannot be used with other types. | | __`SYSLIB1218`__ | _`SYSLIB1201`-`SYSLIB1219` reserved for Microsoft.Extensions.Options.SourceGeneration._ | -| __`SYSLIB1219`__ | _`SYSLIB1201`-`SYSLIB1219` reserved for Microsoft.Extensions.Options.SourceGeneration._ | +| __`SYSLIB1219`__ | Options validation generator: A type already includes an implementation of the 'ValidateAsync' method. | | __`SYSLIB1220`__ | JsonSourceGenerator encountered a [JsonConverterAttribute] with an invalid type argument. | | __`SYSLIB1221`__ | JsonSourceGenerator does not support this C# language version. | | __`SYSLIB1222`__ | Constructor annotated with JsonConstructorAttribute is inaccessible. | diff --git a/src/runtime/eng/Version.Details.props b/src/runtime/eng/Version.Details.props index 59e435354bae..3b6601014a2c 100644 --- a/src/runtime/eng/Version.Details.props +++ b/src/runtime/eng/Version.Details.props @@ -5,50 +5,49 @@ This file should be imported by eng/Versions.props --> - - 11.0.0-beta.26407.8 - 11.0.0-beta.26381.1 - 5.10.0-1.26379.102 - 5.10.0-1.26379.102 - 5.10.0-1.26379.102 - 5.10.0-1.26379.102 - 11.0.100-rc.1.26379.102 - 11.0.100-rc.1.26379.102 - 11.0.0-beta.26379.102 - 11.0.0-beta.26379.102 - 11.0.0-beta.26379.102 - 11.0.0-beta.26379.102 - 11.0.0-beta.26379.102 - 11.0.0-beta.26379.102 - 11.0.0-beta.26379.102 - 11.0.0-beta.26379.102 - 0.11.5-preview.26379.102 - 11.0.0-beta.26379.102 - 11.0.0-beta.26379.102 - 11.0.0-beta.26379.102 - 11.0.0-beta.26379.102 - 11.0.0-beta.26379.102 - 11.0.0-beta.26379.102 - 11.0.0-beta.26379.102 + 5.11.0-1.26411.119 + 5.11.0-1.26411.119 + 5.11.0-1.26411.119 + 5.11.0-1.26411.119 + 11.0.100-rc.1.26411.119 + 11.0.100-rc.1.26411.119 + 11.0.0-beta.26411.119 + 11.0.0-beta.26411.119 + 11.0.0-beta.26411.119 + 11.0.0-beta.26411.119 + 11.0.0-beta.26411.119 + 11.0.0-beta.26411.119 + 11.0.0-beta.26411.119 + 11.0.0-beta.26411.119 + 0.11.5-preview.26411.119 + 11.0.0-beta.26411.119 + 11.0.0-beta.26411.119 + 11.0.0-beta.26411.119 + 11.0.0-beta.26411.119 + 11.0.0-beta.26411.119 + 11.0.0-beta.26411.119 + 11.0.0-beta.26411.119 + 11.0.0-beta.26411.119 + 11.0.0-beta.26411.119 3.2.2-beta.26257.113 - 2.9.3-beta.26379.102 - 11.0.0-beta.26379.102 - 5.10.0-1.26379.102 - 11.0.0-rc.1.26379.102 - 11.0.0-rc.1.26379.102 - 11.0.100-rc.1.26379.102 - 11.0.0-rc.1.26379.102 - 11.0.0-rc.1.26379.102 - 7.10.0-rc.38002 - 7.10.0-rc.38002 - 7.10.0-rc.38002 - 7.10.0-rc.38002 - 11.0.0-rc.1.26379.102 - 3.0.0-rc.1.26379.102 - 11.0.0-rc.1.26379.102 - 11.0.0-rc.1.26379.102 - 11.0.0-rc.1.26379.102 + 2.9.3-beta.26411.119 + 11.0.0-beta.26411.119 + 5.11.0-1.26411.119 + 11.0.0-rc.1.26411.119 + 11.0.0-rc.1.26411.119 + 11.0.100-rc.1.26411.119 + 11.0.0-rc.1.26411.119 + 11.0.0-rc.1.26411.119 + 7.11.0-rc.65534 + 7.11.0-rc.65534 + 7.11.0-rc.65534 + 7.11.0-rc.65534 + 11.0.0-rc.1.26411.119 + 3.0.0-rc.1.26411.119 + 11.0.0-rc.1.26411.119 + 11.0.0-rc.1.26411.119 + 11.0.0-rc.1.26411.119 11.0.0-alpha.0.26180.1 @@ -123,9 +122,6 @@ This file should be imported by eng/Versions.props - - $(MicrosoftDotNetHelixJobMonitorPackageVersion) - $(MicrosoftDotNetHelixSdkPackageVersion) $(MicrosoftCodeAnalysisPackageVersion) $(MicrosoftCodeAnalysisAnalyzersPackageVersion) @@ -145,6 +141,8 @@ This file should be imported by eng/Versions.props $(MicrosoftDotNetCodeAnalysisPackageVersion) $(MicrosoftDotNetGenAPIPackageVersion) $(MicrosoftDotNetGenFacadesPackageVersion) + $(MicrosoftDotNetHelixJobMonitorPackageVersion) + $(MicrosoftDotNetHelixSdkPackageVersion) $(MicrosoftDotNetPackageTestingPackageVersion) $(MicrosoftDotNetRemoteExecutorPackageVersion) $(MicrosoftDotNetSharedFrameworkSdkPackageVersion) diff --git a/src/runtime/eng/Version.Details.xml b/src/runtime/eng/Version.Details.xml index b5046f3ebc92..e52776c3b4da 100644 --- a/src/runtime/eng/Version.Details.xml +++ b/src/runtime/eng/Version.Details.xml @@ -1,5 +1,5 @@ - + https://github.com/dotnet/icu @@ -37,95 +37,95 @@ https://github.com/dotnet/llvm-project 8ae183bac6b9a8fc311b885cc6e261f77bbb7a57 - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a - - https://github.com/dotnet/arcade - 93eebf1a31a5eaafd44326f1a81ca107913e098c + + https://github.com/dotnet/dotnet + 7cdb217445905f3342bbb0266a4497b9a014389a - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a https://github.com/dotnet/dotnet 0eae08ed2f094f44e0151e4815e7cdd1a334fcdf - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a https://github.com/dotnet/runtime-assets @@ -263,33 +263,33 @@ https://github.com/dotnet/llvm-project 8ae183bac6b9a8fc311b885cc6e261f77bbb7a57 - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a https://github.com/dotnet/xharness @@ -303,9 +303,9 @@ https://github.com/dotnet/xharness acc639bea6c5720abf118b8808e18f9cabe90568 - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a https://dev.azure.com/dnceng/internal/_git/dotnet-optimization @@ -327,29 +327,29 @@ https://github.com/dotnet/runtime-assets 7d4d3d2b53b18ad0ca1826581c9710b565b44fe5 - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a https://dev.azure.com/dnceng/internal/_git/dotnet-optimization @@ -361,21 +361,21 @@ - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a https://github.com/dotnet/node @@ -421,13 +421,13 @@ https://github.com/dotnet/hotreload-utils 28af8e7016d4b1ad30ed932f15bd56c033402457 - + https://github.com/dotnet/dotnet - 813f634ceb016018f5acc9bd3c2b16e17dff4686 + 7cdb217445905f3342bbb0266a4497b9a014389a - - https://github.com/dotnet/arcade - 212960245c74330fbfb71776563638061e35446c + + https://github.com/dotnet/dotnet + 7cdb217445905f3342bbb0266a4497b9a014389a - + \ No newline at end of file diff --git a/src/runtime/eng/Versions.props b/src/runtime/eng/Versions.props index 1bb235aaa972..21e88638fc35 100644 --- a/src/runtime/eng/Versions.props +++ b/src/runtime/eng/Versions.props @@ -128,7 +128,7 @@ 2.0.0 17.10.0-beta1.24272.1 3.1.28 - 0.2.736901 + 0.2.740901 2.1.0 2.0.3 1.0.4-preview6.19326.1 diff --git a/src/runtime/eng/common/Get-GitHubAppToken.ps1 b/src/runtime/eng/common/Get-GitHubAppToken.ps1 new file mode 100644 index 000000000000..6b5899d7a299 --- /dev/null +++ b/src/runtime/eng/common/Get-GitHubAppToken.ps1 @@ -0,0 +1,154 @@ +# Mints a short-lived GitHub App installation access token by signing a JWT +# with a private key stored in Azure Key Vault (RSA, RS256). The signed JWT is +# exchanged with the GitHub API for a token scoped to a single installation. +# +# Requirements: +# - A GitHub App whose private key has been uploaded into Key Vault as an RSA +# key (the PEM converted to a Key Vault *key*, NOT stored as a secret). +# - The caller (the federated Azure service connection used to run this script) +# must have the `Key Vault Crypto User` role (or at minimum the `Sign` +# action) on that key. +# - The App must be installed on the target organization/account +# (`InstallationOwner`) with the permissions/repositories it needs. +# +# Installation tokens (ghs_*) are exempt from the enterprise classic-PAT +# lifetime policy, which is why this replaces the long-lived PAT. + +[CmdletBinding()] +param( + # Name of the Key Vault that holds the GitHub App's RSA signing key. + [Parameter(Mandatory = $true)] + [string] $KeyVaultName, + + # Name of the RSA key inside the Key Vault (the App's private key). + [Parameter(Mandatory = $true)] + [string] $KeyName, + + # The GitHub App's Client ID (the value to put in the `iss` JWT claim). + [Parameter(Mandatory = $true)] + [string] $AppClientId, + + # Login of the organization or user account whose installation we should + # mint the token for (e.g. `dotnet`, `microsoft`). + [Parameter(Mandatory = $true)] + [string] $InstallationOwner, + + # Optional Azure DevOps pipeline variable name to set with the installation + # token (marked as a secret). When not specified, the token is written to + # stdout instead. + [Parameter(Mandatory = $false)] + [string] $OutputVariableName +) + +$ErrorActionPreference = 'Stop' +$PSNativeCommandUseErrorActionPreference = $true + +. $PSScriptRoot\pipeline-logging-functions.ps1 + +function ConvertTo-Base64Url([byte[]] $bytes) { + return [Convert]::ToBase64String($bytes).TrimEnd('=').Replace('+', '-').Replace('/', '_') +} + +# Build JWT header and payload. Use [ordered] hashtables so JSON +# serialization is deterministic. +$jwtHeader = [ordered]@{ + alg = 'RS256' + typ = 'JWT' +} +$now = [System.DateTimeOffset]::UtcNow +$jwtPayload = [ordered]@{ + iat = $now.AddMinutes(-1).ToUnixTimeSeconds() + exp = $now.AddMinutes(5).ToUnixTimeSeconds() + iss = $AppClientId +} + +$headerEncoded = ConvertTo-Base64Url ([System.Text.Encoding]::UTF8.GetBytes(($jwtHeader | ConvertTo-Json -Compress))) +$payloadEncoded = ConvertTo-Base64Url ([System.Text.Encoding]::UTF8.GetBytes(($jwtPayload | ConvertTo-Json -Compress))) +$signingInput = "$headerEncoded.$payloadEncoded" + +# Key Vault `sign` expects the *digest* (base64), not the raw bytes. +$sha256 = [System.Security.Cryptography.SHA256]::Create() +$digestBytes = $sha256.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($signingInput)) +$digestBase64 = [Convert]::ToBase64String($digestBytes) + +Write-Host "Signing JWT with key '$KeyName' in vault '$KeyVaultName'..." +$previousNativeCommandErrorPreference = $PSNativeCommandUseErrorActionPreference +try { + # Azure CLI can emit non-fatal Python warnings to stderr even when signing succeeds. + # Use the exit code to determine success for this invocation. + $PSNativeCommandUseErrorActionPreference = $false + $signatureBase64 = az keyvault key sign ` + --vault-name $KeyVaultName ` + --name $KeyName ` + --algorithm RS256 ` + --digest $digestBase64 ` + --query signature ` + --output tsv ` + --only-show-errors + $signExitCode = $LASTEXITCODE +} +catch { + Write-PipelineTelemetryError -Category 'Build' -Message "Failed to sign the JWT via Key Vault (key '$KeyName', vault '$KeyVaultName'): $_. Verify the service connection identity has the 'Key Vault Crypto User' role (Sign action) on the key." + exit 1 +} +finally { + $PSNativeCommandUseErrorActionPreference = $previousNativeCommandErrorPreference +} +if ($signExitCode -ne 0 -or [string]::IsNullOrWhiteSpace($signatureBase64)) { + Write-PipelineTelemetryError -Category 'Build' -Message "'az keyvault key sign' exited with code $signExitCode for key '$KeyName' in vault '$KeyVaultName'. Verify the service connection identity has the 'Key Vault Crypto User' role (Sign action) on the key." + exit 1 +} +$signatureUrl = $signatureBase64.Trim().TrimEnd('=').Replace('+', '-').Replace('/', '_') +$jwt = "$signingInput.$signatureUrl" + +$headers = @{ + Authorization = "Bearer $jwt" + 'X-GitHub-Api-Version' = '2022-11-28' + Accept = 'application/vnd.github+json' + 'User-Agent' = 'dotnet-arcade-onelocbuild' +} + +Write-Host "Looking up installation for '$InstallationOwner'..." +try { + $installations = @() + $page = 1 + do { + $pageInstallations = @(Invoke-RestMethod ` + -Uri "https://api.github.com/app/installations?per_page=100&page=$page" ` + -Headers $headers ` + -Method Get) + $installations += $pageInstallations + $page++ + } while ($pageInstallations.Count -eq 100) +} +catch { + Write-PipelineTelemetryError -Category 'Build' -Message "Failed to list GitHub App installations: $_. The signed JWT may be invalid or the App's Client ID ('$AppClientId') may be incorrect." + exit 1 +} +$installation = $installations | Where-Object { $_.account.login -ieq $InstallationOwner } | Select-Object -First 1 +if (-not $installation) { + $found = ($installations | ForEach-Object { $_.account.login }) -join ', ' + Write-PipelineTelemetryError -Category 'Build' -Message "No installation found for '$InstallationOwner'. App is installed on: $found" + exit 1 +} + +try { + $tokenResponse = Invoke-RestMethod ` + -Uri "https://api.github.com/app/installations/$($installation.id)/access_tokens" ` + -Headers $headers ` + -Method Post ` + -ContentType 'application/json' +} +catch { + Write-PipelineTelemetryError -Category 'Build' -Message "Failed to mint an installation access token for '$InstallationOwner' (installation $($installation.id)): $_" + exit 1 +} + +Write-Host "Got installation token for '$InstallationOwner' (expires $($tokenResponse.expires_at))." +if ($OutputVariableName) { + Write-Host "Setting pipeline variable '$OutputVariableName'." + Write-Host "##vso[task.setvariable variable=$OutputVariableName;issecret=true]$($tokenResponse.token)" +} +else { + Write-Host $tokenResponse.token -ForegroundColor Green +} diff --git a/src/runtime/eng/common/SetupNugetSources.ps1 b/src/runtime/eng/common/SetupNugetSources.ps1 index b3bddff355e7..b7a3769364dd 100644 --- a/src/runtime/eng/common/SetupNugetSources.ps1 +++ b/src/runtime/eng/common/SetupNugetSources.ps1 @@ -11,7 +11,7 @@ # condition: eq(variables['Agent.OS'], 'Windows_NT') # inputs: # filePath: $(System.DefaultWorkingDirectory)/eng/common/SetupNugetSources.ps1 -# arguments: -ConfigFile $(System.DefaultWorkingDirectory)/NuGet.config -Password $Env:Token +# arguments: -ConfigFile $(System.DefaultWorkingDirectory)/NuGet.config # env: # Token: $(InternalFeedToken) # @@ -29,12 +29,14 @@ [CmdletBinding()] param ( [Parameter(Mandatory = $true)][string]$ConfigFile, - $Password + # Keep the legacy name as an alias while callers migrate secrets to the Token environment variable. + [Alias("Password")]$Credential ) $ErrorActionPreference = "Stop" Set-StrictMode -Version 2.0 [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 +$feedCredential = if ($env:Token) { $env:Token } else { $Credential } # This script only consumes helper functions from tools.ps1 to configure NuGet feeds. # Skip importing configure-toolset.ps1 so that repo-specific toolset setup (e.g. acquiring @@ -44,14 +46,14 @@ $disableConfigureToolsetImport = $true . $PSScriptRoot\tools.ps1 # Adds or enables the package source with the given name -function AddOrEnablePackageSource($sources, $disabledPackageSources, $SourceName, $SourceEndPoint, $creds, $Username, $pwd) { - if ($disabledPackageSources -eq $null -or -not (EnableInternalPackageSource -DisabledPackageSources $disabledPackageSources -Creds $creds -PackageSourceName $SourceName)) { - AddPackageSource -Sources $sources -SourceName $SourceName -SourceEndPoint $SourceEndPoint -Creds $creds -Username $userName -pwd $Password +function AddOrEnablePackageSource($sources, $disabledPackageSources, $SourceName, $SourceEndPoint, $creds, $Username, $credential) { + if ($disabledPackageSources -eq $null -or -not (EnableInternalPackageSource -DisabledPackageSources $disabledPackageSources -Creds $creds -PackageSourceName $SourceName -Credential $credential)) { + AddPackageSource -Sources $sources -SourceName $SourceName -SourceEndPoint $SourceEndPoint -Creds $creds -Username $Username -credential $credential } } # Add source entry to PackageSources -function AddPackageSource($sources, $SourceName, $SourceEndPoint, $creds, $Username, $pwd) { +function AddPackageSource($sources, $SourceName, $SourceEndPoint, $creds, $Username, $credential) { $packageSource = $sources.SelectSingleNode("add[@key='$SourceName']") if ($packageSource -eq $null) @@ -67,13 +69,13 @@ function AddPackageSource($sources, $SourceName, $SourceEndPoint, $creds, $Usern Write-Host "Package source $SourceName already present and enabled." } - AddCredential -Creds $creds -Source $SourceName -Username $Username -pwd $pwd + AddCredential -Creds $creds -Source $SourceName -Username $Username -credential $credential } # Add a credential node for the specified source -function AddCredential($creds, $source, $username, $pwd) { +function AddCredential($creds, $source, $username, $credential) { # If no cred supplied, don't do anything. - if (!$pwd) { + if (!$credential) { return; } @@ -108,19 +110,19 @@ function AddCredential($creds, $source, $username, $pwd) { $sourceElement.AppendChild($passwordElement) | Out-Null } - $passwordElement.SetAttribute("value", $pwd) + $passwordElement.SetAttribute("value", $credential) } # Enable all darc-int package sources. -function EnableMaestroInternalPackageSources($DisabledPackageSources, $Creds) { +function EnableMaestroInternalPackageSources($DisabledPackageSources, $Creds, $Credential) { $maestroInternalSources = $DisabledPackageSources.SelectNodes("add[contains(@key,'darc-int')]") ForEach ($DisabledPackageSource in $maestroInternalSources) { - EnableInternalPackageSource -DisabledPackageSources $DisabledPackageSources -Creds $Creds -PackageSourceName $DisabledPackageSource.key + EnableInternalPackageSource -DisabledPackageSources $DisabledPackageSources -Creds $Creds -PackageSourceName $DisabledPackageSource.key -Credential $Credential } } # Enables an internal package source by name, if found. Returns true if the package source was found and enabled, false otherwise. -function EnableInternalPackageSource($DisabledPackageSources, $Creds, $PackageSourceName) { +function EnableInternalPackageSource($DisabledPackageSources, $Creds, $PackageSourceName, $Credential) { $DisabledPackageSource = $DisabledPackageSources.SelectSingleNode("add[@key='$PackageSourceName']") if ($DisabledPackageSource) { Write-Host "Enabling internal source '$($DisabledPackageSource.key)'." @@ -128,7 +130,7 @@ function EnableInternalPackageSource($DisabledPackageSources, $Creds, $PackageSo # Due to https://github.com/NuGet/Home/issues/10291, we must actually remove the disabled entries $DisabledPackageSources.RemoveChild($DisabledPackageSource) - AddCredential -Creds $creds -Source $DisabledPackageSource.Key -Username $userName -pwd $Password + AddCredential -Creds $creds -Source $DisabledPackageSource.Key -Username $userName -credential $credential return $true } return $false @@ -153,7 +155,7 @@ if ($sources -eq $null) { $creds = $null $feedSuffix = "v3/index.json" -if ($Password) { +if ($feedCredential) { $feedSuffix = "v2" # Looks for a node. Create it if none is found. $creds = $doc.DocumentElement.SelectSingleNode("packageSourceCredentials") @@ -169,7 +171,7 @@ $userName = "dn-bot" $disabledSources = $doc.DocumentElement.SelectSingleNode("disabledPackageSources") if ($disabledSources -ne $null) { Write-Host "Checking for any darc-int disabled package sources in the disabledPackageSources node" - EnableMaestroInternalPackageSources -DisabledPackageSources $disabledSources -Creds $creds + EnableMaestroInternalPackageSources -DisabledPackageSources $disabledSources -Creds $creds -Credential $feedCredential } $dotnetVersions = @('5','6','7','8','9','10') @@ -177,8 +179,8 @@ foreach ($dotnetVersion in $dotnetVersions) { $feedPrefix = "dotnet" + $dotnetVersion; $dotnetSource = $sources.SelectSingleNode("add[@key='$feedPrefix']") if ($dotnetSource -ne $null) { - AddOrEnablePackageSource -Sources $sources -DisabledPackageSources $disabledSources -SourceName "$feedPrefix-internal" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/$feedPrefix-internal/nuget/$feedSuffix" -Creds $creds -Username $userName -pwd $Password - AddOrEnablePackageSource -Sources $sources -DisabledPackageSources $disabledSources -SourceName "$feedPrefix-internal-transport" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/$feedPrefix-internal-transport/nuget/$feedSuffix" -Creds $creds -Username $userName -pwd $Password + AddOrEnablePackageSource -Sources $sources -DisabledPackageSources $disabledSources -SourceName "$feedPrefix-internal" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/$feedPrefix-internal/nuget/$feedSuffix" -Creds $creds -Username $userName -credential $feedCredential + AddOrEnablePackageSource -Sources $sources -DisabledPackageSources $disabledSources -SourceName "$feedPrefix-internal-transport" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/$feedPrefix-internal-transport/nuget/$feedSuffix" -Creds $creds -Username $userName -credential $feedCredential } } diff --git a/src/runtime/eng/common/SetupNugetSources.sh b/src/runtime/eng/common/SetupNugetSources.sh index 67e7e0942ca1..c3ae8ac054fe 100755 --- a/src/runtime/eng/common/SetupNugetSources.sh +++ b/src/runtime/eng/common/SetupNugetSources.sh @@ -24,7 +24,9 @@ # This logic is also abstracted into enable-internal-sources.yml. ConfigFile=$1 -CredToken=$2 +# Prefer the environment variable so credentials do not appear in process arguments. +# Retain the positional argument as a compatibility fallback for existing callers. +CredToken=${Token:-$2} NL='\n' TB=' ' diff --git a/src/runtime/eng/common/build.ps1 b/src/runtime/eng/common/build.ps1 index dd84699f500c..fee2f839919a 100644 --- a/src/runtime/eng/common/build.ps1 +++ b/src/runtime/eng/common/build.ps1 @@ -8,6 +8,7 @@ Param( [bool] $warnAsError = $true, [string] $warnNotAsError = '', [bool] $nodeReuse = $true, + [bool][Alias('mt')]$msbuildMultiThreaded = $false, [switch] $buildCheck = $false, [switch][Alias('r')]$restore, [switch] $deployDeps, @@ -79,6 +80,7 @@ function Print-Usage() { Write-Host " -excludePrereleaseVS Set to exclude build engines in prerelease versions of Visual Studio" Write-Host " -nativeToolsOnMachine Sets the native tools on machine environment variable (indicating that the script should use native tools on machine)" Write-Host " -nodeReuse Sets nodereuse msbuild parameter ('true' or 'false')" + Write-Host " -msbuildMultiThreaded Sets MSBuild's multi-threaded mode, i.e. the -mt switch ('1' or '0') (short: -mt)" Write-Host " -buildCheck Sets /check msbuild parameter" Write-Host " -fromVMR Set when building from within the VMR" Write-Host " -disablePipelineSetResult Set to disable masking the actual exit code in the pipeline when the build fails" @@ -175,9 +177,8 @@ try { if (-not $excludeCIBinarylog) { $binaryLog = $true } - # Disable node reuse on CI unless explicitly opted in via MSBUILD_NODEREUSE_ENABLED. - # Internal testing only; this env var will be replaced with a switch (https://github.com/dotnet/arcade/issues/17013) and must not be depended on. - if ($env:MSBUILD_NODEREUSE_ENABLED -ne "1") { + # Node reuse isn't used on CI unless it was explicitly requested via -nodeReuse. + if (-not $PSBoundParameters.ContainsKey('nodeReuse')) { $nodeReuse = $false } } diff --git a/src/runtime/eng/common/build.sh b/src/runtime/eng/common/build.sh index e37edd6cff34..109d83ff73f7 100755 --- a/src/runtime/eng/common/build.sh +++ b/src/runtime/eng/common/build.sh @@ -43,6 +43,7 @@ usage() echo " --pipelinesLog Promote msbuild errors/warnings to Azure Pipelines timeline issues; defaults to on in CI (short: -pl)" echo " --prepareMachine Prepare machine for CI run, clean up processes after build" echo " --nodeReuse Sets nodereuse msbuild parameter ('true' or 'false')" + echo " --msbuildMultiThreaded Sets MSBuild's multi-threaded mode, i.e. the -mt switch ('true' or 'false') (short: --mt)" echo " --warnAsError Sets warnaserror msbuild parameter ('true' or 'false')" echo " --warnNotAsError Sets a semi-colon delimited list of warning codes that should not be treated as errors" echo " --buildCheck Sets /check msbuild parameter" @@ -84,7 +85,9 @@ clean=false warn_as_error=true warn_not_as_error='' -node_reuse=true +# Empty means "not specified"; tools.sh defaults these to on for local builds and off on CI. +node_reuse='' +msbuild_multi_threaded='' build_check=false binary_log=false binary_log_name='' @@ -199,6 +202,10 @@ while [[ $# -gt 0 ]]; do node_reuse=$2 shift ;; + -msbuildmultithreaded|-mt) + msbuild_multi_threaded=$2 + shift + ;; -buildcheck) build_check=true ;; @@ -224,11 +231,6 @@ fi if [[ "$ci" == true ]]; then pipelines_log=true - # Disable node reuse on CI unless explicitly opted in via MSBUILD_NODEREUSE_ENABLED. - # Internal testing only; this env var will be replaced with a switch (https://github.com/dotnet/arcade/issues/17013) and must not be depended on. - if [[ "${MSBUILD_NODEREUSE_ENABLED:-}" != "1" ]]; then - node_reuse=false - fi if [[ "$exclude_ci_binary_log" == false ]]; then binary_log=true fi diff --git a/src/runtime/eng/common/core-templates/job/helix-job-monitor.yml b/src/runtime/eng/common/core-templates/job/helix-job-monitor.yml index 0e92fb1f477f..a65b50d0a787 100644 --- a/src/runtime/eng/common/core-templates/job/helix-job-monitor.yml +++ b/src/runtime/eng/common/core-templates/job/helix-job-monitor.yml @@ -26,6 +26,11 @@ parameters: type: string default: '' +# Whether failures in the monitor job should allow the pipeline to continue. +- name: continueOnError + type: boolean + default: false + # NuGet package id of the Helix job monitor tool. - name: toolPackageId type: string @@ -103,6 +108,7 @@ jobs: - job: HelixJobMonitor displayName: Monitor Helix Jobs timeoutInMinutes: ${{ parameters.timeoutInMinutes }} + continueOnError: ${{ parameters.continueOnError }} ${{ if ne(length(parameters.dependsOn), 0) }}: dependsOn: ${{ parameters.dependsOn }} ${{ if ne(parameters.condition, '') }}: diff --git a/src/runtime/eng/common/core-templates/job/onelocbuild.yml b/src/runtime/eng/common/core-templates/job/onelocbuild.yml index 2816d2905a06..4f5653d73ac7 100644 --- a/src/runtime/eng/common/core-templates/job/onelocbuild.yml +++ b/src/runtime/eng/common/core-templates/job/onelocbuild.yml @@ -14,6 +14,15 @@ parameters: # exist, and any pipeline that sets this to '' fall back to PAT-based auth via the CeapexPat parameter. CeapexServiceConnection: 'dnceng-onelocbuild-ceapex' + # GitHub App authentication for the OneLoc check-in PR (dnceng/internal only). + # The infrastructure identifiers are centralized here and the App path is enabled by default. + # DevDiv requires its own project-scoped service connection before this path can be enabled there. + UseGitHubAppAuthentication: true + GitHubAppServiceConnection: 'dnceng-oneloc-githubapp' + GitHubAppClientId: 'Iv23lijBU8x3gc9lDOc9' + GitHubAppKeyVaultName: 'EngKeyVault' + GitHubAppKeyName: 'oneloc-localization-app-key' + SourcesDirectory: $(System.DefaultWorkingDirectory) CreatePr: true AutoCompletePr: false @@ -89,6 +98,20 @@ jobs: outputVariableName: 'CeapexEntraToken' condition: ${{ parameters.condition }} + # Mint a short-lived GitHub App installation token for the loc check-in PR (dnceng/internal only). + # All other projects fall back to PAT-based auth, since the app service connection is scoped to dnceng/internal. + - ${{ if and(eq(parameters.RepoType, 'gitHub'), eq(parameters.UseGitHubAppAuthentication, true), eq(variables['System.TeamProject'], 'internal')) }}: + - template: /eng/common/core-templates/steps/get-github-app-token.yml + parameters: + is1ESPipeline: ${{ parameters.is1ESPipeline }} + azureSubscription: ${{ parameters.GitHubAppServiceConnection }} + keyVaultName: ${{ parameters.GitHubAppKeyVaultName }} + keyName: ${{ parameters.GitHubAppKeyName }} + appClientId: ${{ parameters.GitHubAppClientId }} + installationOwner: ${{ parameters.GitHubOrg }} + outputVariableName: 'GitHubAppInstallationToken' + condition: ${{ parameters.condition }} + - task: OneLocBuild@2 displayName: OneLocBuild env: @@ -110,7 +133,10 @@ jobs: patVariable: ${{ parameters.CeapexPat }} ${{ if eq(parameters.RepoType, 'gitHub') }}: repoType: ${{ parameters.RepoType }} - gitHubPatVariable: "${{ parameters.GithubPat }}" + ${{ if and(eq(parameters.UseGitHubAppAuthentication, true), eq(variables['System.TeamProject'], 'internal')) }}: + gitHubPatVariable: "$(GitHubAppInstallationToken)" + ${{ if or(eq(parameters.UseGitHubAppAuthentication, false), ne(variables['System.TeamProject'], 'internal')) }}: + gitHubPatVariable: "${{ parameters.GithubPat }}" ${{ if ne(parameters.MirrorRepo, '') }}: isMirrorRepoSelected: true gitHubOrganization: ${{ parameters.GitHubOrg }} diff --git a/src/runtime/eng/common/core-templates/job/publish-build-assets.yml b/src/runtime/eng/common/core-templates/job/publish-build-assets.yml index 4229288d3d38..330225ae0938 100644 --- a/src/runtime/eng/common/core-templates/job/publish-build-assets.yml +++ b/src/runtime/eng/common/core-templates/job/publish-build-assets.yml @@ -58,8 +58,6 @@ jobs: parameters: is1ESPipeline: ${{ parameters.is1ESPipeline }} - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: - - group: Publish-Build-Assets - - group: AzureDevOps-Artifact-Feeds-Pats - name: runCodesignValidationInjection value: false # unconditional - needed for logs publishing (redactor tool version) diff --git a/src/runtime/eng/common/core-templates/post-build/common-variables.yml b/src/runtime/eng/common/core-templates/post-build/common-variables.yml index db298ae16bae..a3a8480e254a 100644 --- a/src/runtime/eng/common/core-templates/post-build/common-variables.yml +++ b/src/runtime/eng/common/core-templates/post-build/common-variables.yml @@ -1,6 +1,4 @@ variables: - - group: Publish-Build-Assets - # Whether the build is internal or not - name: IsInternalBuild value: ${{ and(ne(variables['System.TeamProject'], 'public'), contains(variables['Build.SourceBranch'], 'internal')) }} diff --git a/src/runtime/eng/common/core-templates/stages/renovate.yml b/src/runtime/eng/common/core-templates/stages/renovate.yml index edab28182585..cfa9683794ad 100644 --- a/src/runtime/eng/common/core-templates/stages/renovate.yml +++ b/src/runtime/eng/common/core-templates/stages/renovate.yml @@ -81,6 +81,8 @@ resources: extends: template: v1/1ES.Official.PipelineTemplate.yml@1ESPipelineTemplates parameters: + settings: + networkIsolationPolicy: Permissive pool: ${{ parameters.pool }} sdl: sourceAnalysisPool: ${{ parameters.sdlPool }} diff --git a/src/runtime/eng/common/core-templates/steps/enable-internal-sources.yml b/src/runtime/eng/common/core-templates/steps/enable-internal-sources.yml index 51af9a017091..843cdff7821e 100644 --- a/src/runtime/eng/common/core-templates/steps/enable-internal-sources.yml +++ b/src/runtime/eng/common/core-templates/steps/enable-internal-sources.yml @@ -19,7 +19,7 @@ steps: displayName: Setup Internal Feeds inputs: filePath: $(System.DefaultWorkingDirectory)/eng/common/SetupNugetSources.ps1 - arguments: -ConfigFile $(System.DefaultWorkingDirectory)/NuGet.config -Password $Env:Token + arguments: -ConfigFile $(System.DefaultWorkingDirectory)/NuGet.config env: Token: ${{ parameters.legacyCredential }} - task: Bash@3 @@ -28,7 +28,7 @@ steps: inputs: targetType: inline script: | - "$(System.DefaultWorkingDirectory)/eng/common/SetupNugetSources.sh" "$(System.DefaultWorkingDirectory)/NuGet.config" "$Token" + "$(System.DefaultWorkingDirectory)/eng/common/SetupNugetSources.sh" "$(System.DefaultWorkingDirectory)/NuGet.config" env: Token: ${{ parameters.legacyCredential }} # If running on dnceng (internal project), just use the default behavior for NuGetAuthenticate. @@ -58,13 +58,17 @@ steps: displayName: Setup Internal Feeds inputs: filePath: $(System.DefaultWorkingDirectory)/eng/common/SetupNugetSources.ps1 - arguments: -ConfigFile $(System.DefaultWorkingDirectory)/NuGet.config -Password $(dnceng-artifacts-feeds-read-access-token) + arguments: -ConfigFile $(System.DefaultWorkingDirectory)/NuGet.config + env: + Token: $(dnceng-artifacts-feeds-read-access-token) - task: Bash@3 condition: and(succeeded(), ne(variables['Agent.Os'], 'Windows_NT')) displayName: Setup Internal Feeds inputs: filePath: $(System.DefaultWorkingDirectory)/eng/common/SetupNugetSources.sh - arguments: $(System.DefaultWorkingDirectory)/NuGet.config $(dnceng-artifacts-feeds-read-access-token) + arguments: $(System.DefaultWorkingDirectory)/NuGet.config + env: + Token: $(dnceng-artifacts-feeds-read-access-token) # This is required in certain scenarios to install the ADO credential provider. # It installed by default in some msbuild invocations (e.g. VS msbuild), but needs to be installed for others # (e.g. dotnet msbuild). diff --git a/src/runtime/eng/common/core-templates/steps/get-github-app-token.yml b/src/runtime/eng/common/core-templates/steps/get-github-app-token.yml new file mode 100644 index 000000000000..6d42a48d3c36 --- /dev/null +++ b/src/runtime/eng/common/core-templates/steps/get-github-app-token.yml @@ -0,0 +1,79 @@ +# Mints a short-lived GitHub App installation access token by signing a JWT +# with a private key stored in Azure Key Vault (RSA, RS256). The JWT is +# exchanged with the GitHub API for a token scoped to a single installation. +# +# Requirements (per GitHub App you want to authenticate as): +# - A GitHub App with its private key uploaded into Key Vault as an RSA key +# (PEM converted to a key, NOT stored as a secret). +# - The Azure service connection passed via `azureSubscription` must be +# granted the `Key Vault Crypto User` role (or at minimum `Sign` action) +# on that key. +# - The App must be installed on the target organization/account +# (`installationOwner`) with the permissions/repositories you need. +# +# Output: a secret pipeline variable named ${{ parameters.outputVariableName }} +# containing the installation access token. Token lifetime is ~1 hour and is +# automatically scrubbed from logs. Installation tokens are exempt from the +# enterprise classic-PAT lifetime policy. + +parameters: +# Azure DevOps service connection (federated) that can call +# `az keyvault key sign` on the App's signing key. +- name: azureSubscription + type: string + +# Name of the Key Vault that holds the GitHub App's RSA signing key. +- name: keyVaultName + type: string + +# Name of the RSA key inside the Key Vault (the App's private key). +- name: keyName + type: string + +# The GitHub App's Client ID (the value to put in the `iss` JWT claim). +# Prefer this over the numeric App ID; GitHub accepts either, but Client ID +# is the documented form going forward. +- name: appClientId + type: string + +# Login of the organization or user account whose installation we should +# mint the token for (e.g. `dotnet`, `microsoft`). +- name: installationOwner + type: string + +# Name of the pipeline variable that will receive the installation token. +- name: outputVariableName + type: string + +- name: is1ESPipeline + type: boolean + +- name: stepName + type: string + default: getGitHubAppInstallationToken + +- name: condition + type: string + default: '' + +- name: displayName + type: string + default: Get GitHub App installation token + +steps: +- task: AzureCLI@2 + displayName: ${{ parameters.displayName }} + name: ${{ parameters.stepName }} + ${{ if ne(parameters.condition, '') }}: + condition: ${{ parameters.condition }} + inputs: + azureSubscription: ${{ parameters.azureSubscription }} + scriptType: pscore + scriptLocation: inlineScript + inlineScript: | + & "$(System.DefaultWorkingDirectory)/eng/common/Get-GitHubAppToken.ps1" ` + -KeyVaultName '${{ parameters.keyVaultName }}' ` + -KeyName '${{ parameters.keyName }}' ` + -AppClientId '${{ parameters.appClientId }}' ` + -InstallationOwner '${{ parameters.installationOwner }}' ` + -OutputVariableName '${{ parameters.outputVariableName }}' diff --git a/src/runtime/eng/common/core-templates/steps/publish-logs.yml b/src/runtime/eng/common/core-templates/steps/publish-logs.yml index c496f3d0dc7a..2c1e0ab11620 100644 --- a/src/runtime/eng/common/core-templates/steps/publish-logs.yml +++ b/src/runtime/eng/common/core-templates/steps/publish-logs.yml @@ -30,8 +30,6 @@ steps: -TokensFilePath '$(System.DefaultWorkingDirectory)/eng/BinlogSecretsRedactionFile.txt' -runtimeSourceFeed https://ci.dot.net/internal -runtimeSourceFeedKey '$(dotnetbuilds-internal-container-read-token-base64)' - '$(publishing-dnceng-devdiv-code-r-build-re)' - '$(akams-client-id)' '$(System.AccessToken)' ${{parameters.CustomSensitiveDataList}} continueOnError: true @@ -56,4 +54,3 @@ steps: condition: always() retryCountOnTaskFailure: 10 # for any files being locked isProduction: false # logs are non-production artifacts - diff --git a/src/runtime/eng/common/msbuild.ps1 b/src/runtime/eng/common/msbuild.ps1 index 495d533a9098..b6dfb570ea50 100644 --- a/src/runtime/eng/common/msbuild.ps1 +++ b/src/runtime/eng/common/msbuild.ps1 @@ -3,6 +3,7 @@ Param( [string] $verbosity = 'minimal', [bool] $warnAsError = $true, [bool] $nodeReuse = $true, + [bool][Alias('mt')]$msbuildMultiThreaded = $false, [switch] $ci, [switch] $prepareMachine, [switch] $excludePrereleaseVS, @@ -13,12 +14,9 @@ Param( . $PSScriptRoot\tools.ps1 try { - if ($ci) { - # Disable node reuse on CI unless explicitly opted in via MSBUILD_NODEREUSE_ENABLED. - # Internal testing only; this env var will be replaced with a switch (https://github.com/dotnet/arcade/issues/17013) and must not be depended on. - if ($env:MSBUILD_NODEREUSE_ENABLED -ne "1") { - $nodeReuse = $false - } + # Node reuse isn't used on CI unless it was explicitly requested via -nodeReuse. + if ($ci -and -not $PSBoundParameters.ContainsKey('nodeReuse')) { + $nodeReuse = $false } MSBuild @extraArgs diff --git a/src/runtime/eng/common/msbuild.sh b/src/runtime/eng/common/msbuild.sh index 333be3232fcf..a40c101237b1 100755 --- a/src/runtime/eng/common/msbuild.sh +++ b/src/runtime/eng/common/msbuild.sh @@ -14,7 +14,9 @@ scriptroot="$( cd -P "$( dirname "$source" )" && pwd )" verbosity='minimal' warn_as_error=true -node_reuse=true +# Empty means "not specified"; tools.sh defaults these to on for local builds and off on CI. +node_reuse='' +msbuild_multi_threaded='' prepare_machine=false extra_args='' @@ -33,6 +35,10 @@ while (($# > 0)); do node_reuse=$2 shift 2 ;; + --msbuildmultithreaded|--mt) + msbuild_multi_threaded=$2 + shift 2 + ;; --ci) ci=true shift 1 @@ -50,13 +56,5 @@ done . "$scriptroot/tools.sh" -if [[ "$ci" == true ]]; then - # Disable node reuse on CI unless explicitly opted in via MSBUILD_NODEREUSE_ENABLED. - # Internal testing only; this env var will be replaced with a switch (https://github.com/dotnet/arcade/issues/17013) and must not be depended on. - if [[ "${MSBUILD_NODEREUSE_ENABLED:-}" != "1" ]]; then - node_reuse=false - fi -fi - MSBuild $extra_args ExitWithExitCode 0 diff --git a/src/runtime/eng/common/templates-official/steps/get-github-app-token.yml b/src/runtime/eng/common/templates-official/steps/get-github-app-token.yml new file mode 100644 index 000000000000..c89f3641a4db --- /dev/null +++ b/src/runtime/eng/common/templates-official/steps/get-github-app-token.yml @@ -0,0 +1,7 @@ +steps: +- template: /eng/common/core-templates/steps/get-github-app-token.yml + parameters: + is1ESPipeline: true + + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} diff --git a/src/runtime/eng/common/templates/steps/get-github-app-token.yml b/src/runtime/eng/common/templates/steps/get-github-app-token.yml new file mode 100644 index 000000000000..79e182c64167 --- /dev/null +++ b/src/runtime/eng/common/templates/steps/get-github-app-token.yml @@ -0,0 +1,7 @@ +steps: +- template: /eng/common/core-templates/steps/get-github-app-token.yml + parameters: + is1ESPipeline: false + + ${{ each parameter in parameters }}: + ${{ parameter.key }}: ${{ parameter.value }} diff --git a/src/runtime/eng/common/tools.ps1 b/src/runtime/eng/common/tools.ps1 index da07386ff1fe..e84033dad90c 100644 --- a/src/runtime/eng/common/tools.ps1 +++ b/src/runtime/eng/common/tools.ps1 @@ -31,11 +31,16 @@ # Set to true to reuse msbuild nodes. Recommended to not reuse on CI. [bool]$nodeReuse = if (Test-Path variable:nodeReuse) { $nodeReuse } else { !$ci } +# Set to true to build with MSBuild's multi-threaded mode (-mt). Opt-in for now, so off unless it was +# explicitly requested. It's intended to become the default for local builds once it has proven out. +[bool]$msbuildMultiThreaded = if (Test-Path variable:msbuildMultiThreaded) { $msbuildMultiThreaded } else { $false } + # Configures warning treatment in msbuild. [bool]$warnAsError = if (Test-Path variable:warnAsError) { $warnAsError } else { $true } # Specifies semi-colon delimited list of warning codes that should not be treated as errors. -[string]$warnNotAsError = if (Test-Path variable:warnNotAsError) { $warnNotAsError } else { '' } +# Defaults to NuGet Audit warning codes NU1901-NU1904. +[string]$warnNotAsError = if ((Test-Path variable:warnNotAsError) -and $warnNotAsError) { $warnNotAsError } else { 'NU1901;NU1902;NU1903;NU1904' } # Specifies which msbuild engine to use for build: 'vs', 'dotnet' or unspecified (determined based on presence of tools.vs in global.json). [string]$msbuildEngine = if (Test-Path variable:msbuildEngine) { $msbuildEngine } else { $null } @@ -808,8 +813,8 @@ function MSBuild() { $cmdArgs = "$($buildTool.Command) /m /nologo /clp:Summary /v:$verbosity /nr:$nodeReuse /p:ContinuousIntegrationBuild=$ci" - # Add -mt flag for MSBuild multithreaded mode if enabled via environment variable - if ($env:MSBUILD_MT_ENABLED -eq "1") { + # Build with MSBuild's multi-threaded mode. + if ($msbuildMultiThreaded) { $cmdArgs += ' -mt' } diff --git a/src/runtime/eng/common/tools.sh b/src/runtime/eng/common/tools.sh index 20f791c11dee..4d14b100b063 100755 --- a/src/runtime/eng/common/tools.sh +++ b/src/runtime/eng/common/tools.sh @@ -1,5 +1,15 @@ #!/usr/bin/env bash +# Normalizes the value of a boolean build argument. Accepts 1/0 in addition to true/false so that +# the same value works with the PowerShell scripts, whose [bool] parameters only bind 1/0. +function NormalizeBoolArg { + case "${1:-}" in + 1) echo true ;; + 0) echo false ;; + *) echo "${1:-}" ;; + esac +} + # Initialize variables if they aren't already defined. # CI mode - set to true on CI server for PR validation build or official build. @@ -43,17 +53,25 @@ restore=${restore:-true} verbosity=${verbosity:-'minimal'} # Set to true to reuse msbuild nodes. Recommended to not reuse on CI. +node_reuse=$(NormalizeBoolArg "${node_reuse:-}") if [[ "$ci" == true ]]; then node_reuse=${node_reuse:-false} else node_reuse=${node_reuse:-true} fi +# Set to true to build with MSBuild's multi-threaded mode (-mt). Opt-in for now, so off unless it was +# explicitly requested. It's intended to become the default for local builds once it has proven out. +msbuild_multi_threaded=$(NormalizeBoolArg "${msbuild_multi_threaded:-}") +msbuild_multi_threaded=${msbuild_multi_threaded:-false} + # Configures warning treatment in msbuild. +warn_as_error=$(NormalizeBoolArg "${warn_as_error:-}") warn_as_error=${warn_as_error:-true} # Specifies semi-colon delimited list of warning codes that should not be treated as errors. -warn_not_as_error=${warn_not_as_error:-''} +# Defaults to NuGet Audit warning codes NU1901-NU1904. +warn_not_as_error="${warn_not_as_error:-NU1901;NU1902;NU1903;NU1904}" # True to attempt using .NET Core already that meets requirements specified in global.json # installed on the machine instead of downloading one. @@ -587,9 +605,9 @@ function MSBuild { } } - # Add -mt flag for MSBuild multithreaded mode if enabled via environment variable + # Build with MSBuild's multi-threaded mode. local mt_switch="" - if [[ "${MSBUILD_MT_ENABLED:-}" == "1" ]]; then + if [[ "$msbuild_multi_threaded" == true ]]; then mt_switch="-mt" fi diff --git a/src/runtime/eng/native/build-commons.sh b/src/runtime/eng/native/build-commons.sh index 5e94540ee12b..fdf156b16fec 100755 --- a/src/runtime/eng/native/build-commons.sh +++ b/src/runtime/eng/native/build-commons.sh @@ -60,6 +60,18 @@ build_native() cmakeArgs="$6" message="$7" + # When sccache is enabled, use it as the compiler launcher. + # On macOS, CMake wraps PCH includes with -Xarch_ which sccache + # cannot parse. Use a thin wrapper that strips -Xarch_ flags + # (safe in single-architecture builds) before forwarding to sccache. + if [[ "${USE_SCCACHE:-}" == "true" ]]; then + local __sccacheLauncher="sccache" + if [[ "$targetOS" == osx || "$targetOS" == maccatalyst ]]; then + __sccacheLauncher="$__RepoRootDir/eng/native/sccache-xarch-wrapper.sh" + fi + cmakeArgs="-DCMAKE_C_COMPILER_LAUNCHER=$__sccacheLauncher -DCMAKE_CXX_COMPILER_LAUNCHER=$__sccacheLauncher $cmakeArgs" + fi + # All set to commence the build echo "Commencing build of \"$target\" target in \"$message\" for $__TargetOS.$__TargetArch.$__BuildType in $intermediatesDir" diff --git a/src/runtime/eng/native/configurecompiler.cmake b/src/runtime/eng/native/configurecompiler.cmake index ce8e2e51d016..bc5fcb1733ac 100644 --- a/src/runtime/eng/native/configurecompiler.cmake +++ b/src/runtime/eng/native/configurecompiler.cmake @@ -8,6 +8,11 @@ set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) +# Enable C99 inttypes.h format macros (PRI*, SCN*) for C++ translation units. +# Some C++ standard library implementations gate these macros behind +# __STDC_FORMAT_MACROS in C++ mode (e.g. glibc prior to C++11 conformance). +add_compile_definitions($<$:__STDC_FORMAT_MACROS>) + # We need to set this to Release as there's no way to intercept configuration-specific linker flags # for try_compile-style tests (like check_c_source_compiles) and some of the default Debug flags # (ie. /INCREMENTAL) conflict with our own flags. diff --git a/src/runtime/eng/native/sccache-xarch-wrapper.sh b/src/runtime/eng/native/sccache-xarch-wrapper.sh new file mode 100755 index 000000000000..fd92766ad3bf --- /dev/null +++ b/src/runtime/eng/native/sccache-xarch-wrapper.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +# Wrapper around sccache for macOS builds. +# sccache cannot parse -Xarch_ flags that CMake generates for PCH +# includes. Rewrite them to explicit Clang frontend options that preserve +# use of the generated PCH while remaining parseable by sccache. + +for arg in "$@"; do + if [[ "$arg" == "-emit-pch" ]]; then + exec "$@" + fi +done + +args=() +skip_xarch=false + +for arg in "$@"; do + if $skip_xarch; then + skip_xarch=false + if [[ "$arg" == -include?* ]]; then + local_path="${arg#-include}" + args+=( + "-Xclang" "-include-pch" "-Xclang" "${local_path}.pch" + "-Xclang" "-include" "-Xclang" "$local_path" + ) + else + args+=("$arg") + fi + continue + fi + if [[ "$arg" == -Xarch_* ]]; then + skip_xarch=true + continue + fi + args+=("$arg") +done + +exec sccache "${args[@]}" diff --git a/src/runtime/eng/pipelines/coreclr/templates/sccache-stats.yml b/src/runtime/eng/pipelines/coreclr/templates/sccache-stats.yml index d881dad08e17..3f7f000ced1a 100644 --- a/src/runtime/eng/pipelines/coreclr/templates/sccache-stats.yml +++ b/src/runtime/eng/pipelines/coreclr/templates/sccache-stats.yml @@ -12,7 +12,7 @@ parameters: osSubgroup: '' steps: - - ${{ if and(or(eq(parameters.osGroup, 'linux'), eq(parameters.osGroup, 'freebsd'), eq(parameters.osGroup, 'openbsd')), or(eq(parameters.archType, 'x64'), eq(parameters.archType, 'arm64'))) }}: + - ${{ if and(or(eq(parameters.osGroup, 'linux'), eq(parameters.osGroup, 'freebsd'), eq(parameters.osGroup, 'openbsd'), eq(parameters.osGroup, 'osx')), or(eq(parameters.archType, 'x64'), eq(parameters.archType, 'arm64'))) }}: - script: sccache --show-stats || true displayName: Sccache stats condition: always() diff --git a/src/runtime/eng/pipelines/coreclr/templates/setup-sccache.yml b/src/runtime/eng/pipelines/coreclr/templates/setup-sccache.yml index d15e1953bdb9..d133175afb59 100644 --- a/src/runtime/eng/pipelines/coreclr/templates/setup-sccache.yml +++ b/src/runtime/eng/pipelines/coreclr/templates/setup-sccache.yml @@ -11,11 +11,12 @@ parameters: shouldContinueOnError: false osSubgroup: '' - # sccache NuGet package version + # sccache version. Keep the version in sync across platforms so all jobs + # cache against the same compiler-launcher behavior. sccacheVersion: '0.15.0' steps: - - ${{ if and(or(eq(parameters.osGroup, 'linux'), eq(parameters.osGroup, 'freebsd'), eq(parameters.osGroup, 'openbsd')), or(eq(parameters.archType, 'x64'), eq(parameters.archType, 'arm64'))) }}: + - ${{ if and(or(eq(parameters.osGroup, 'linux'), eq(parameters.osGroup, 'freebsd'), eq(parameters.osGroup, 'openbsd'), eq(parameters.osGroup, 'osx')), or(eq(parameters.archType, 'x64'), eq(parameters.archType, 'arm64'))) }}: # Set up the Azure Pipeline Cache for sccache's local cache directory. # Use a rolling key so each build can update the cache; restoreKeys # falls back to the most recent saved entry. @@ -26,6 +27,10 @@ steps: # flags are controlled by RuntimeConfiguration (-rc), which is # constant per leg regardless of buildConfig. Omitting it lets PR # builds warm-start from rolling-build caches saved in the main scope. + # + # osGroup/osSubgroup/archType keep each platform's cache isolated so + # Mac jobs don't poison the Linux entries (different compiler, different + # cache contents). - task: Cache@2 displayName: Sccache cache continueOnError: true @@ -35,11 +40,34 @@ steps: restoreKeys: | sccache | ${{ parameters.osGroup }}${{ parameters.osSubgroup }} | ${{ parameters.archType }} | ${{ parameters.nameSuffix }} - # Download the sccache NuGet package and configure the environment. + # Download sccache and configure the environment. + # + # The unsuffixed package contains the linux-musl-x64 binary. On macOS, + # select the package matching the agent host architecture. - script: | + set -euo pipefail sccacheVersion="${{ parameters.sccacheVersion }}" - sccacheDir="$(Build.SourcesDirectory)/.packages/sccache/${sccacheVersion}/tools" - "$(Build.SourcesDirectory)/eng/common/dotnet.sh" package download "sccache@${sccacheVersion}" -o "$(Build.SourcesDirectory)/.packages" -v quiet + osGroup="${{ parameters.osGroup }}" + sccachePackage="sccache" + + if [[ "$osGroup" == "osx" ]]; then + case "$(uname -m)" in + arm64) + sccachePackage="sccache.osx-arm64" + ;; + x86_64) + sccachePackage="sccache.osx-x64" + ;; + *) + echo "Unsupported macOS host architecture: $(uname -m)" >&2 + exit 1 + ;; + esac + fi + + "$(Build.SourcesDirectory)/eng/common/dotnet.sh" package download "${sccachePackage}@${sccacheVersion}" -o "$(Build.SourcesDirectory)/.packages" -v quiet + sccacheDir="$(Build.SourcesDirectory)/.packages/${sccachePackage}/${sccacheVersion}/tools" + chmod +x "$sccacheDir/sccache" echo "##vso[task.prependpath]$sccacheDir" echo "##vso[task.setvariable variable=SCCACHE_DIR]$(Pipeline.Workspace)/.sccache" diff --git a/src/runtime/eng/pipelines/installer/helix-queues-setup.yml b/src/runtime/eng/pipelines/installer/helix-queues-setup.yml index 99707d4e6949..99232a1897a5 100644 --- a/src/runtime/eng/pipelines/installer/helix-queues-setup.yml +++ b/src/runtime/eng/pipelines/installer/helix-queues-setup.yml @@ -1,26 +1,23 @@ parameters: - jobTemplate: '' - variables: [] + archType: '' + condition: always() + creator: '' + includeAllPlatforms: false + isExtraPlatformsBuild: false osGroup: '' osSubgroup: '' - archType: '' - container: '' - pool: '' platform: '' - shouldContinueOnError: false - jobParameters: {} + useHelixMonitor: false -jobs: -- template: ${{ parameters.jobTemplate }} +steps: +- template: /eng/pipelines/installer/helix.yml parameters: - variables: ${{ parameters.variables }} + archType: ${{ parameters.archType }} + condition: ${{ parameters.condition }} + creator: ${{ parameters.creator }} osGroup: ${{ parameters.osGroup }} osSubgroup: ${{ parameters.osSubgroup }} - archType: ${{ parameters.archType }} - container: ${{ parameters.container }} - pool: ${{ parameters.pool }} - platform: ${{ parameters.platform }} - shouldContinueOnError: ${{ parameters.shouldContinueOnError }} + useHelixMonitor: ${{ parameters.useHelixMonitor }} helixQueues: # Linux arm @@ -36,7 +33,7 @@ jobs: - (Alpine.324.Amd64.Open)AzureLinux.3.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.24-helix-amd64@sha256:240788457ec91460a35f6aa8d70bc1aaa7d1347d211fc5f5c0b35f648a33d7bd # Linux musl arm64 - - ${{ if and(eq(parameters.platform, 'linux_musl_arm64'), or(eq(parameters.jobParameters.isExtraPlatformsBuild, true), eq(parameters.jobParameters.includeAllPlatforms, true))) }}: + - ${{ if and(eq(parameters.platform, 'linux_musl_arm64'), or(eq(parameters.isExtraPlatformsBuild, true), eq(parameters.includeAllPlatforms, true))) }}: - (Alpine.324.Arm64.Open)AzureLinux.3.Arm64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.24-helix-arm64v8@sha256:c0651a184147638e54b2f6a3c8f040274b1bf2deb0bf3e5c4513824598497ae0 # Linux x64 @@ -62,5 +59,3 @@ jobs: # windows arm64 - ${{ if eq(parameters.platform, 'windows_arm64') }}: - Windows.11.Arm64.Open - - ${{ insert }}: ${{ parameters.jobParameters }} diff --git a/src/runtime/eng/pipelines/installer/helix.yml b/src/runtime/eng/pipelines/installer/helix.yml index 5824c4366c0f..0c1341d429ab 100644 --- a/src/runtime/eng/pipelines/installer/helix.yml +++ b/src/runtime/eng/pipelines/installer/helix.yml @@ -4,6 +4,7 @@ parameters: osSubgroup: '' creator: '' helixQueues: '' + condition: always() useHelixMonitor: false steps: @@ -38,3 +39,4 @@ steps: Creator: ${{ parameters.creator }} HelixTargetQueues: ${{ join('+', parameters.helixQueues) }} UseHelixMonitor: ${{ parameters.useHelixMonitor }} + condition: and(succeeded(), ${{ parameters.condition }}) diff --git a/src/runtime/eng/pipelines/runtime.yml b/src/runtime/eng/pipelines/runtime.yml index 669cfe5b545c..af2fc6e3392c 100644 --- a/src/runtime/eng/pipelines/runtime.yml +++ b/src/runtime/eng/pipelines/runtime.yml @@ -75,7 +75,7 @@ extends: allowNoHelixJobs: true # - # Build CoreCLR verticals where we don't run host tests + # Build CoreCLR verticals # - template: /eng/pipelines/common/platform-matrix.yml parameters: @@ -289,8 +289,8 @@ extends: useHelixMonitor: ${{ variables.enableHelixJobMonitor }} # - # Build CoreCLR and Libraries with Libraries tests - # For running libraries tests and installer tests + # Build CoreCLR verticals + # Run libraries tests and installer tests # - template: /eng/pipelines/common/platform-matrix.yml parameters: @@ -305,23 +305,18 @@ extends: variables: - name: librariesContainsChange value: $[ stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_libraries.containsChange'] ] + - name: coreclrContainsChange + value: $[ stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_coreclr.containsChange'] ] + - name: installerContainsChange + value: $[ stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_installer.containsChange'] ] jobParameters: - nameSuffix: CoreCLR_Libraries - buildArgs: -s clr+libs+libs.tests -rc Release -c $(_BuildConfig) /p:ArchiveTests=true - timeoutInMinutes: 120 + nameSuffix: CoreCLR_AllSubsets + buildArgs: -s clr+libs+libs.tests+host+packs -rc Release -c $(_BuildConfig) /p:ArchiveTests=true + timeoutInMinutes: 180 preBuildSteps: - template: /eng/pipelines/coreclr/templates/setup-sccache.yml postBuildSteps: - template: /eng/pipelines/coreclr/templates/sccache-stats.yml - - template: /eng/pipelines/common/upload-artifact-step.yml - parameters: - rootFolder: $(Build.SourcesDirectory)/artifacts/bin - includeRootFolder: false - archiveType: $(archiveType) - archiveExtension: $(archiveExtension) - tarCompression: $(tarCompression) - artifactName: CoreCLR_Libraries_BuildArtifacts_$(osGroup)$(osSubgroup)_$(archType)_$(_BuildConfig) - displayName: Build Assets - template: /eng/pipelines/libraries/helix.yml parameters: creator: dotnet-bot @@ -332,6 +327,18 @@ extends: or( eq(variables['librariesContainsChange'], true), eq(variables['isRollingBuild'], true)) + - template: /eng/pipelines/installer/helix-queues-setup.yml + parameters: + creator: dotnet-bot + useHelixMonitor: ${{ variables.enableHelixJobMonitor }} + condition: >- + or( + eq(variables['installerContainsChange'], true), + and( + eq(variables['osGroup'], 'osx'), + eq(variables['archType'], 'arm64'), + eq(variables['coreclrContainsChange'], true)), + eq(variables['isRollingBuild'], true)) condition: >- or( eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_non_mono_and_wasm.containsChange'], true), @@ -348,20 +355,13 @@ extends: variables: - name: librariesContainsChange value: $[ stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_libraries.containsChange'] ] + - name: installerContainsChange + value: $[ stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_installer.containsChange'] ] jobParameters: - nameSuffix: CoreCLR_Libraries - buildArgs: -s clr+libs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true - timeoutInMinutes: 120 + nameSuffix: CoreCLR_AllSubsets + buildArgs: -s clr+libs+libs.tests+host+packs -c $(_BuildConfig) /p:ArchiveTests=true + timeoutInMinutes: 180 postBuildSteps: - - template: /eng/pipelines/common/upload-artifact-step.yml - parameters: - rootFolder: $(Build.SourcesDirectory)/artifacts/bin - includeRootFolder: false - archiveType: $(archiveType) - archiveExtension: $(archiveExtension) - tarCompression: $(tarCompression) - artifactName: CoreCLR_Libraries_BuildArtifacts_$(osGroup)$(osSubgroup)_$(archType)_$(_BuildConfig) - displayName: Build Assets - template: /eng/pipelines/libraries/helix.yml parameters: helixBuildConfig: Release @@ -373,6 +373,14 @@ extends: or( eq(variables['librariesContainsChange'], true), eq(variables['isRollingBuild'], true)) + - template: /eng/pipelines/installer/helix-queues-setup.yml + parameters: + creator: dotnet-bot + useHelixMonitor: ${{ variables.enableHelixJobMonitor }} + condition: >- + or( + eq(variables['installerContainsChange'], true), + eq(variables['isRollingBuild'], true)) condition: >- or( eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_non_mono_and_wasm.containsChange'], true), @@ -380,7 +388,7 @@ extends: eq(variables['isRollingBuild'], true)) # - # Build CoreCLR and Libraries + # Build CoreCLR verticals # For running installer tests # - template: /eng/pipelines/common/platform-matrix.yml @@ -389,20 +397,25 @@ extends: buildConfig: release platforms: - osx_x64 + variables: + - name: installerContainsChange + value: $[ stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_installer.containsChange'] ] jobParameters: - nameSuffix: CoreCLR_Libraries - buildArgs: -s clr+libs -c $(_BuildConfig) - timeoutInMinutes: 120 + nameSuffix: CoreCLR_AllSubsets + buildArgs: -s clr+libs+host+packs -c $(_BuildConfig) + timeoutInMinutes: 180 + preBuildSteps: + - template: /eng/pipelines/coreclr/templates/setup-sccache.yml postBuildSteps: - - template: /eng/pipelines/common/upload-artifact-step.yml + - template: /eng/pipelines/coreclr/templates/sccache-stats.yml + - template: /eng/pipelines/installer/helix-queues-setup.yml parameters: - rootFolder: $(Build.SourcesDirectory)/artifacts/bin - includeRootFolder: false - archiveType: $(archiveType) - archiveExtension: $(archiveExtension) - tarCompression: $(tarCompression) - artifactName: CoreCLR_Libraries_BuildArtifacts_$(osGroup)$(osSubgroup)_$(archType)_$(_BuildConfig) - displayName: Build Assets + creator: dotnet-bot + useHelixMonitor: ${{ variables.enableHelixJobMonitor }} + condition: >- + or( + eq(variables['installerContainsChange'], true), + eq(variables['isRollingBuild'], true)) condition: >- or( eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_non_mono_and_wasm.containsChange'], true), @@ -557,7 +570,10 @@ extends: nameSuffix: Libraries_CheckedCoreCLR buildArgs: -s clr+libs -c $(_BuildConfig) -rc Checked timeoutInMinutes: 120 + preBuildSteps: + - template: /eng/pipelines/coreclr/templates/setup-sccache.yml postBuildSteps: + - template: /eng/pipelines/coreclr/templates/sccache-stats.yml - template: /eng/pipelines/coreclr/templates/build-native-test-assets-step.yml - template: /eng/pipelines/common/upload-artifact-step.yml parameters: @@ -856,7 +872,10 @@ extends: timeoutInMinutes: 180 nameSuffix: NativeAOT buildArgs: -s clr.aot+libs+tools.illink -c $(_BuildConfig) -rc $(_BuildConfig) -lc Release /p:RunAnalyzers=false + preBuildSteps: + - template: /eng/pipelines/coreclr/templates/setup-sccache.yml postBuildSteps: + - template: /eng/pipelines/coreclr/templates/sccache-stats.yml - template: /eng/pipelines/coreclr/nativeaot-post-build-steps.yml parameters: creator: dotnet-bot @@ -895,8 +914,11 @@ extends: nameSuffix: NativeAOT_Libraries buildArgs: -s clr.aot+libs+libs.tests -c $(_BuildConfig) /p:TestNativeAot=true /p:RunSmokeTestsOnly=true /p:ArchiveTests=true /p:RunAnalyzers=false timeoutInMinutes: 240 # Doesn't actually take long, but we've seen the ARM64 Helix queue often get backlogged for 2+ hours + preBuildSteps: + - template: /eng/pipelines/coreclr/templates/setup-sccache.yml # extra steps, run tests postBuildSteps: + - template: /eng/pipelines/coreclr/templates/sccache-stats.yml - template: /eng/pipelines/libraries/helix.yml parameters: creator: dotnet-bot @@ -1551,109 +1573,6 @@ extends: eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_tools_illink.containsChange'], true), eq(variables['isRollingBuild'], true)) - # - # Installer Build and Test - # Only when installer-relevant paths change (or on rolling builds). - # osx_arm64 also runs on coreclr changes to catch single-file issues. - # - - template: /eng/pipelines/common/platform-matrix.yml - parameters: - jobTemplate: /eng/pipelines/common/global-build-job.yml - buildConfig: ${{ variables.debugOnPrReleaseOnRolling }} - platforms: - - windows_x86 - - osx_x64 - helixQueuesTemplate: /eng/pipelines/installer/helix-queues-setup.yml - jobParameters: - nameSuffix: Installer_Build_And_Test - buildArgs: -s host+packs -c $(_BuildConfig) -lc Release -rc Release - dependsOnGlobalBuilds: - - nameSuffix: CoreCLR_Libraries - buildConfig: release - preBuildSteps: - - template: /eng/pipelines/common/download-artifact-step.yml - parameters: - artifactName: CoreCLR_Libraries_BuildArtifacts_$(osGroup)$(osSubgroup)_$(archType)_Release - artifactFileName: CoreCLR_Libraries_BuildArtifacts_$(osGroup)$(osSubgroup)_$(archType)_Release$(archiveExtension) - unpackFolder: $(Build.SourcesDirectory)/artifacts/bin - displayName: 'unified artifacts' - timeoutInMinutes: 150 - postBuildSteps: - - template: /eng/pipelines/installer/helix.yml - parameters: - creator: dotnet-bot - useHelixMonitor: ${{ variables.enableHelixJobMonitor }} - condition: - or( - eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true), - eq(variables['isRollingBuild'], true)) - - - template: /eng/pipelines/common/platform-matrix.yml - parameters: - jobTemplate: /eng/pipelines/common/global-build-job.yml - buildConfig: release - platforms: - - windows_x64 - - linux_x64 - - linux_musl_x64 - helixQueuesTemplate: /eng/pipelines/installer/helix-queues-setup.yml - jobParameters: - nameSuffix: Installer_Build_And_Test - buildArgs: -s host+packs -c $(_BuildConfig) -lc ${{ variables.debugOnPrReleaseOnRolling }} -rc Release - dependsOnGlobalBuilds: - - nameSuffix: CoreCLR_Libraries - buildConfig: ${{ variables.debugOnPrReleaseOnRolling }} - preBuildSteps: - - template: /eng/pipelines/common/download-artifact-step.yml - parameters: - artifactName: CoreCLR_Libraries_BuildArtifacts_$(osGroup)$(osSubgroup)_$(archType)_$(debugOnPrReleaseOnRolling) - artifactFileName: CoreCLR_Libraries_BuildArtifacts_$(osGroup)$(osSubgroup)_$(archType)_$(debugOnPrReleaseOnRolling)$(archiveExtension) - unpackFolder: $(Build.SourcesDirectory)/artifacts/bin - displayName: 'unified artifacts' - timeoutInMinutes: 150 - postBuildSteps: - - template: /eng/pipelines/installer/helix.yml - parameters: - creator: dotnet-bot - useHelixMonitor: ${{ variables.enableHelixJobMonitor }} - condition: - or( - eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true), - eq(variables['isRollingBuild'], true)) - - # osx_arm64 installer tests also run on coreclr changes to catch single-file issues - - template: /eng/pipelines/common/platform-matrix.yml - parameters: - jobTemplate: /eng/pipelines/common/global-build-job.yml - buildConfig: release - platforms: - - osx_arm64 - helixQueuesTemplate: /eng/pipelines/installer/helix-queues-setup.yml - jobParameters: - nameSuffix: Installer_Build_And_Test - buildArgs: -s host+packs -c $(_BuildConfig) -lc ${{ variables.debugOnPrReleaseOnRolling }} -rc Release - dependsOnGlobalBuilds: - - nameSuffix: CoreCLR_Libraries - buildConfig: ${{ variables.debugOnPrReleaseOnRolling }} - preBuildSteps: - - template: /eng/pipelines/common/download-artifact-step.yml - parameters: - artifactName: CoreCLR_Libraries_BuildArtifacts_$(osGroup)$(osSubgroup)_$(archType)_$(debugOnPrReleaseOnRolling) - artifactFileName: CoreCLR_Libraries_BuildArtifacts_$(osGroup)$(osSubgroup)_$(archType)_$(debugOnPrReleaseOnRolling)$(archiveExtension) - unpackFolder: $(Build.SourcesDirectory)/artifacts/bin - displayName: 'unified artifacts' - timeoutInMinutes: 150 - postBuildSteps: - - template: /eng/pipelines/installer/helix.yml - parameters: - creator: dotnet-bot - useHelixMonitor: ${{ variables.enableHelixJobMonitor }} - condition: - or( - eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_coreclr.containsChange'], true), - eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true), - eq(variables['isRollingBuild'], true)) - # # Build the whole product using Mono and run runtime tests # diff --git a/src/runtime/global.json b/src/runtime/global.json index da838abda3a7..2e097b75ffe7 100644 --- a/src/runtime/global.json +++ b/src/runtime/global.json @@ -13,11 +13,11 @@ "dotnet": "11.0.100-preview.6.26359.118" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "11.0.0-beta.26379.102", - "Microsoft.DotNet.Helix.Sdk": "11.0.0-beta.26381.1", - "Microsoft.DotNet.SharedFramework.Sdk": "11.0.0-beta.26379.102", + "Microsoft.DotNet.Arcade.Sdk": "11.0.0-beta.26411.119", + "Microsoft.DotNet.Helix.Sdk": "11.0.0-beta.26411.119", + "Microsoft.DotNet.SharedFramework.Sdk": "11.0.0-beta.26411.119", "Microsoft.Build.NoTargets": "3.7.0", "Microsoft.Build.Traversal": "3.4.0", - "Microsoft.NET.Sdk.IL": "11.0.0-rc.1.26379.102" + "Microsoft.NET.Sdk.IL": "11.0.0-rc.1.26411.119" } } diff --git a/src/runtime/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs b/src/runtime/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs index 70447aee1db3..90f74e4b8674 100644 --- a/src/runtime/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs +++ b/src/runtime/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs @@ -1491,6 +1491,171 @@ private static void CaptureContinuationContextFlags(ref ContinuationFlags flags, flags |= ContinuationFlags.ContinueOnThreadPool; } + // Restore the contexts that an inlined async frame captured when it logically returned to + // its caller, after that frame was resumed inside its own body. + // + // Used by the JIT when inlining runtime async calls. The JIT emits the check of whether + // the frame was resumed at all and calls this when it was; everything the async + // infrastructure would otherwise have done at that frame boundary happens here. + // + // Unlike the synchronous restore at the end of a method, the ExecutionContext restore runs + // only after a resumption, so it must target the thread we were resumed on rather than the + // one whose contexts were captured on entry. + // + // The continuation context check determines whether resuming the caller's continuation here + // would be dispatched inline. It mirrors the "can inline" conditions in + // RuntimeAsyncTaskContinuation.QueueIfNecessary; the two must be kept in sync. + // + // 'flags' must contain only ContinuationFlags.AllContinuationFlags bits. + [BypassReadyToRun] + [MethodImpl(MethodImplOptions.Async)] + private static void RestoreInlinedFrameContexts(ExecutionContext? previousExecCtx, object? continuationContext, ContinuationFlags flags) + { + Debug.Assert((flags & ~ContinuationFlags.AllContinuationFlags) == 0); + + // We are inside a runtime async chain, so the thread has already been cached. Use it + // instead of Thread.CurrentThreadAssumedInitialized to keep this to one TLS lookup. + ref RuntimeAsyncAwaitState state = ref t_runtimeAsyncAwaitState; + Thread? currentThread = state.CurrentThread; + Debug.Assert(currentThread != null); + + RestoreExecutionContext(currentThread, previousExecCtx); + + if ((flags & ContinuationFlags.ContinueOnThreadPool) != 0) + { + SynchronizationContext? syncCtx = currentThread._synchronizationContext; + if (syncCtx is null || syncCtx.GetType() == typeof(SynchronizationContext)) + { + TaskScheduler? sched = TaskScheduler.InternalCurrent; + if (sched is null || sched == TaskScheduler.Default) + { + return; + } + } + } + else if ((flags & ContinuationFlags.ContinueOnCapturedSynchronizationContext) != 0) + { + Debug.Assert(continuationContext is SynchronizationContext); + if (continuationContext == currentThread._synchronizationContext) + { + return; + } + } + else if ((flags & ContinuationFlags.ContinueOnCapturedTaskScheduler) != 0) + { + Debug.Assert(continuationContext is TaskScheduler); + if (continuationContext == TaskScheduler.InternalCurrent) + { + return; + } + } + else + { + // No continuation context was captured, so there is nothing to switch to. + return; + } + + TailAwait(); + SwitchToContinuationContext(ref state, continuationContext, flags); + } + + // Suspend and resume in the specified continuation context. + // + // Suspending on an already completed task makes the dispatcher re-dispatch the continuation + // immediately. Because that dispatch happens with canInline: false, it always posts or + // schedules onto the requested context rather than running inline here, which is what we + // want -- we only get here when we are known to be on the wrong context. + [BypassReadyToRun] + [MethodImpl(MethodImplOptions.Async)] + private static unsafe void SwitchToContinuationContext(ref RuntimeAsyncAwaitState state, object? continuationContext, ContinuationFlags flags) + { + Continuation? sentinelContinuation = state.SentinelContinuation ??= new Continuation(); + + RuntimeAsyncTaskContinuation? taskCont = state.CachedTaskContinuation; + if (taskCont != null) + { + state.CachedTaskContinuation = null; + } + else + { + taskCont = new RuntimeAsyncTaskContinuation(); + } + + taskCont.Initialize(Task.CompletedTask); + taskCont.ContinuationContext = continuationContext; + taskCont.Flags |= flags; + + sentinelContinuation.Next = taskCont; + state.StackState->TaskContinuation = taskCont; + + state.CaptureContexts(); + AsyncSuspend(taskCont); + } + + // Capture the contexts an inlined async frame hands to its caller when it logically + // returns during a suspension, i.e. what the caller's continuation would have captured + // had the callee's frame been physically present. + // + // No-ops when the frame has already resumed: in that case the caller's continuation + // already exists and keeps the values it captured when the frame first suspended. + // + // The suspension walks the inlined frames outward, and a frame having resumed implies + // its caller has too, so these can be emitted as a straight line: once one frame has + // resumed, this and every subsequent capture for the frames outside it no-op. + // + // Which of the three variants the JIT emits follows how the caller awaited the frame. + // Each assigns the whole flags value rather than adding to it, since the per-depth + // storage is shared and may hold what an unrelated suspension point left there. + // + // Capture with the caller's continuation context, for a frame whose caller awaited it in + // a way that has to come back to the context it was on. + private static void CaptureInlinedFrameTransitionWithContinuationContext(bool resumed, + ref object? continuationContext, + ref ContinuationFlags flags, + ref ExecutionContext? execContext) + { + if (resumed) + { + return; + } + + flags = default; + CaptureContinuationContext(ref continuationContext, ref flags); + execContext = CaptureExecutionContext(); + } + + // Capture for a frame whose caller awaited it in a way that captures no continuation + // context at all, as a custom awaiter does, so only the ExecutionContext has to be + // restored when the frame logically returns. + private static void CaptureInlinedFrameTransitionNoContinuationContext(bool resumed, + ref ContinuationFlags flags, + ref ExecutionContext? execContext) + { + if (resumed) + { + return; + } + + flags = default; + execContext = CaptureExecutionContext(); + } + + // Capture for a frame whose caller awaited it with ConfigureAwait(false), which asks to + // continue off any captured context, so the frame gets back to the thread pool rather + // than to a context it recorded. + private static void CaptureInlinedFrameTransitionContinueOnThreadPool(bool resumed, + ref ContinuationFlags flags, + ref ExecutionContext? execContext) + { + if (resumed) + { + return; + } + + flags = ContinuationFlags.ContinueOnThreadPool; + execContext = CaptureExecutionContext(); + } + // Finish suspension in the common case of a custom await or for a ConfigureAwait(false) task await: // - Capture current ExecutionContext into the continuation // - Restore ExecutionContext and SynchronizationContext to the current Thread object diff --git a/src/runtime/src/coreclr/binder/applicationcontext.cpp b/src/runtime/src/coreclr/binder/applicationcontext.cpp index bb399c5ffb01..280ecef78732 100644 --- a/src/runtime/src/coreclr/binder/applicationcontext.cpp +++ b/src/runtime/src/coreclr/binder/applicationcontext.cpp @@ -80,16 +80,11 @@ namespace BINDER_SPACE HRESULT ApplicationContext::SetupBindingPaths(SString &sTrustedPlatformAssemblies, SString &sPlatformResourceRoots, - SString &sAppPaths, - BOOL fAcquireLock) + SString &sAppPaths) { HRESULT hr = S_OK; - CRITSEC_Holder contextLock(fAcquireLock ? GetCriticalSectionCookie() : NULL); - if (m_pTrustedPlatformAssemblyMap != nullptr) - { - GO_WITH_HRESULT(S_OK); - } + _ASSERTE(m_pTrustedPlatformAssemblyMap == nullptr); // // Parse TrustedPlatformAssemblies diff --git a/src/runtime/src/coreclr/binder/defaultassemblybinder.cpp b/src/runtime/src/coreclr/binder/defaultassemblybinder.cpp index cf986dc9b6ab..ae9833f9de0d 100644 --- a/src/runtime/src/coreclr/binder/defaultassemblybinder.cpp +++ b/src/runtime/src/coreclr/binder/defaultassemblybinder.cpp @@ -203,7 +203,7 @@ HRESULT DefaultAssemblyBinder::SetupBindingPaths(SString &sTrustedPlatformAssem EX_TRY { - hr = GetAppContext()->SetupBindingPaths(sTrustedPlatformAssemblies, sPlatformResourceRoots, sAppPaths, TRUE /* fAcquireLock */); + hr = GetAppContext()->SetupBindingPaths(sTrustedPlatformAssemblies, sPlatformResourceRoots, sAppPaths); } EX_CATCH_HRESULT(hr); return hr; @@ -231,4 +231,3 @@ HRESULT DefaultAssemblyBinder::BindToSystem(BINDER_SPACE::Assembly** ppSystemAss return hr; } - diff --git a/src/runtime/src/coreclr/binder/inc/applicationcontext.hpp b/src/runtime/src/coreclr/binder/inc/applicationcontext.hpp index 8aad61e49f4b..6642e68fd5f0 100644 --- a/src/runtime/src/coreclr/binder/inc/applicationcontext.hpp +++ b/src/runtime/src/coreclr/binder/inc/applicationcontext.hpp @@ -86,8 +86,7 @@ namespace BINDER_SPACE HRESULT SetupBindingPaths(/* in */ SString &sTrustedPlatformAssemblies, /* in */ SString &sPlatformResourceRoots, - /* in */ SString &sAppPaths, - /* in */ BOOL fAcquireLock); + /* in */ SString &sAppPaths); // Getters/Setter inline ExecutionContext *GetExecutionContext(); diff --git a/src/runtime/src/coreclr/build-runtime.sh b/src/runtime/src/coreclr/build-runtime.sh index 6147564b20c1..6809330b216d 100755 --- a/src/runtime/src/coreclr/build-runtime.sh +++ b/src/runtime/src/coreclr/build-runtime.sh @@ -173,10 +173,6 @@ if [[ "$__TargetArch" != "$__HostArch" ]]; then __CMakeArgs="-DCLR_CMAKE_TARGET_ARCH=$__TargetArch $__CMakeArgs" fi -if [[ "$USE_SCCACHE" == "true" ]]; then - __CMakeArgs="-DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache $__CMakeArgs" -fi - eval "$__RepoRootDir/eng/native/version/copy_version_files.sh" build_native "$__HostOS" "$__HostArch" "$__ProjectRoot" "$__IntermediatesDir" "$__CMakeTarget" "$__CMakeArgs" "CoreCLR component" diff --git a/src/runtime/src/coreclr/debug/createdump/crashinfo.cpp b/src/runtime/src/coreclr/debug/createdump/crashinfo.cpp index c99ce68afa72..4a40c6d38630 100644 --- a/src/runtime/src/coreclr/debug/createdump/crashinfo.cpp +++ b/src/runtime/src/coreclr/debug/createdump/crashinfo.cpp @@ -464,7 +464,7 @@ CrashInfo::EnumerateManagedModules() if (enumModules != 0) { m_pClrDataProcess->EndEnumModules(enumModules); } - TRACE("EnumerateManagedModules: Module enumeration FINISHED (%d) ModuleMappings %06llx\n", m_dataTargetPagesAdded, m_cbModuleMappings / PAGE_SIZE); + TRACE("EnumerateManagedModules: Module enumeration FINISHED (%d) ModuleMappings %06" PRIx64 "\n", m_dataTargetPagesAdded, m_cbModuleMappings / PAGE_SIZE); } return true; } @@ -791,7 +791,7 @@ CrashInfo::PageMappedToPhysicalMemory(uint64_t start) if (seekResult != pagemapOffset) { int seekErrno = errno; - TRACE("Seeking in pagemap file FAILED, addr: %" PRIA PRIx ", pagemap offset: %" PRIA PRIx ", ERRNO %d: %s\n", start, pagemapOffset, seekErrno, strerror(seekErrno)); + TRACE("Seeking in pagemap file FAILED, addr: %" PRIA PRIx64 ", pagemap offset: %" PRIA PRIx64 ", ERRNO %d: %s\n", start, pagemapOffset, seekErrno, strerror(seekErrno)); return true; } uint64_t value; @@ -799,13 +799,13 @@ CrashInfo::PageMappedToPhysicalMemory(uint64_t start) if (readResult == (size_t) -1) { int readErrno = errno; - TRACE("Reading of pagemap file FAILED, addr: %" PRIA PRIx ", pagemap offset: %" PRIA PRIx ", size: %zu, ERRNO %d: %s\n", start, pagemapOffset, sizeof(value), readErrno, strerror(readErrno)); + TRACE("Reading of pagemap file FAILED, addr: %" PRIA PRIx64 ", pagemap offset: %" PRIA PRIx64 ", size: %zu, ERRNO %d: %s\n", start, pagemapOffset, sizeof(value), readErrno, strerror(readErrno)); return true; } bool is_page_present = (value & ((uint64_t)1 << 63)) != 0; bool is_page_swapped = (value & ((uint64_t)1 << 62)) != 0; - TRACE_VERBOSE("Pagemap value for %" PRIA PRIx ", pagemap offset %" PRIA PRIx " is %" PRIA PRIx " -> %s\n", start, pagemapOffset, value, is_page_present ? "in memory" : (is_page_swapped ? "in swap" : "NOT in memory")); + TRACE_VERBOSE("Pagemap value for %" PRIA PRIx64 ", pagemap offset %" PRIA PRIx64 " is %" PRIA PRIx64 " -> %s\n", start, pagemapOffset, value, is_page_present ? "in memory" : (is_page_swapped ? "in swap" : "NOT in memory")); return is_page_present || is_page_swapped; #endif } diff --git a/src/runtime/src/coreclr/debug/createdump/crashinfo.h b/src/runtime/src/coreclr/debug/createdump/crashinfo.h index d324c1444570..7a51cceb81d4 100644 --- a/src/runtime/src/coreclr/debug/createdump/crashinfo.h +++ b/src/runtime/src/coreclr/debug/createdump/crashinfo.h @@ -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. +#include + #ifdef __APPLE__ #include "../dbgutil/machoreader.h" #else @@ -32,7 +34,7 @@ typedef __typeof__(((elf_aux_entry*) 0)->a_un.a_val) elf_aux_val_t; extern const std::string GetFileName(const std::string& fileName); extern const std::string GetDirectory(const std::string& fileName); -extern std::string FormatString(const char* format, ...); +extern std::string FormatString(const char* format, ...) MINIPAL_ATTR_FORMAT_PRINTF(1, 2); extern std::string ConvertString(const WCHAR* str); extern std::string FormatGuid(const GUID* guid); @@ -166,6 +168,6 @@ class CrashInfo : public ICLRDataEnumMemoryRegionsCallback, public ICLRDataLoggi uint32_t GetMemoryRegionFlags(uint64_t start); bool PageCanBeRead(uint64_t start); bool PageMappedToPhysicalMemory(uint64_t start); - void Trace(const char* format, ...); - void TraceVerbose(const char* format, ...); + void Trace(const char* format, ...) MINIPAL_ATTR_FORMAT_PRINTF(2, 3); + void TraceVerbose(const char* format, ...) MINIPAL_ATTR_FORMAT_PRINTF(2, 3); }; diff --git a/src/runtime/src/coreclr/debug/createdump/crashinfomac.cpp b/src/runtime/src/coreclr/debug/createdump/crashinfomac.cpp index 2181b365e525..6de4ef0c4196 100644 --- a/src/runtime/src/coreclr/debug/createdump/crashinfomac.cpp +++ b/src/runtime/src/coreclr/debug/createdump/crashinfomac.cpp @@ -123,7 +123,7 @@ CrashInfo::EnumerateMemoryRegions() address, address + size, size / PAGE_SIZE, - info.pages_resident, + (unsigned long long)info.pages_resident, info.offset, info.is_submap ? "sub" : " ", depth, @@ -402,8 +402,8 @@ CrashInfo::ReadProcessMemory(uint64_t address, void* buffer, size_t size, size_t if (result != KERN_SUCCESS || bytesRead != PAGE_SIZE) { g_readProcessMemoryResult = result; - TRACE_VERBOSE("ReadProcessMemory(%p %d): vm_read_overwrite failed bytesLeft %d bytesRead %d from %p: %s (%x)\n", - (void*)address, size, bytesLeft, bytesRead, (void*)addressAligned, mach_error_string(result), result); + TRACE_VERBOSE("ReadProcessMemory(%p %zd): vm_read_overwrite failed bytesLeft %zd bytesRead %lu from %p: %s (%x)\n", + (void*)address, size, bytesLeft, (unsigned long)bytesRead, (void*)addressAligned, mach_error_string(result), result); break; } ssize_t bytesToCopy = PAGE_SIZE - offset; diff --git a/src/runtime/src/coreclr/debug/createdump/crashinfounix.cpp b/src/runtime/src/coreclr/debug/createdump/crashinfounix.cpp index b392ef9fdab0..854301453f48 100644 --- a/src/runtime/src/coreclr/debug/createdump/crashinfounix.cpp +++ b/src/runtime/src/coreclr/debug/createdump/crashinfounix.cpp @@ -301,7 +301,7 @@ CrashInfo::EnumerateMemoryRegions() if (g_diagnostics) { - TRACE("Module mappings (%06llx):\n", m_cbModuleMappings / PAGE_SIZE); + TRACE("Module mappings (%06" PRIx64 "):\n", m_cbModuleMappings / PAGE_SIZE); for (const ModuleRegion& region : m_moduleMappings) { region.Trace(); @@ -446,7 +446,7 @@ CrashInfo::VisitProgramHeader(uint64_t loadbias, uint64_t baseAddress, Phdr* phd { uint64_t ehFrameHdrStart = loadbias + phdr->p_vaddr; uint64_t ehFrameHdrSize = phdr->p_memsz; - TRACE("VisitProgramHeader: ehFrameHdrStart %016llx ehFrameHdrSize %08llx\n", ehFrameHdrStart, ehFrameHdrSize); + TRACE("VisitProgramHeader: ehFrameHdrStart %" PRIA PRIx64 " ehFrameHdrSize %08" PRIx64 "\n", ehFrameHdrStart, ehFrameHdrSize); InsertMemoryRegion(ehFrameHdrStart, ehFrameHdrSize); if (m_appModel != AppModelType::NativeAOT) @@ -455,7 +455,7 @@ CrashInfo::VisitProgramHeader(uint64_t loadbias, uint64_t baseAddress, Phdr* phd ULONG64 ehFrameSize; if (PAL_GetUnwindInfoSize(baseAddress, ehFrameHdrStart, ReadMemoryAdapter, &ehFrameStart, &ehFrameSize)) { - TRACE("VisitProgramHeader: ehFrameStart %016llx ehFrameSize %08llx\n", ehFrameStart, ehFrameSize); + TRACE("VisitProgramHeader: ehFrameStart %" PRIA PRIx64 " ehFrameSize %08" PRIx64 "\n", ehFrameStart, ehFrameSize); if (ehFrameStart != 0 && ehFrameSize != 0) { InsertMemoryRegion(ehFrameStart, ehFrameSize); @@ -492,7 +492,7 @@ CrashInfo::GetMemoryRegionFlags(uint64_t start) if (region != nullptr) { return region->Flags(); } - TRACE_VERBOSE("GetMemoryRegionFlags: %016llx FAILED\n", start); + TRACE_VERBOSE("GetMemoryRegionFlags: %" PRIA PRIx64 " FAILED\n", start); return PF_R | PF_W | PF_X; } @@ -540,7 +540,7 @@ CrashInfo::ReadProcessMemory(uint64_t address, void* buffer, size_t size, size_t { // Preserve errno for the ELF dump writer call g_readProcessMemoryErrno = errno; - TRACE_VERBOSE("ReadProcessMemory FAILED addr: %" PRIA PRIx " size: %zu error: %s (%d)\n", address, size, strerror(g_readProcessMemoryErrno), g_readProcessMemoryErrno); + TRACE_VERBOSE("ReadProcessMemory FAILED addr: %" PRIA PRIx64 " size: %zu error: %s (%d)\n", address, size, strerror(g_readProcessMemoryErrno), g_readProcessMemoryErrno); return false; } return true; diff --git a/src/runtime/src/coreclr/debug/createdump/createdump.h b/src/runtime/src/coreclr/debug/createdump/createdump.h index 4bfe1582ec4e..d647ec49502d 100644 --- a/src/runtime/src/coreclr/debug/createdump/createdump.h +++ b/src/runtime/src/coreclr/debug/createdump/createdump.h @@ -9,9 +9,11 @@ extern bool g_diagnostics; extern bool g_diagnosticsVerbose; +#include + #ifdef HOST_UNIX -extern void trace_printf(const char* format, ...); -extern void trace_verbose_printf(const char* format, ...); +extern void trace_printf(const char* format, ...) MINIPAL_ATTR_FORMAT_PRINTF(1, 2); +extern void trace_verbose_printf(const char* format, ...) MINIPAL_ATTR_FORMAT_PRINTF(1, 2); #define TRACE(args...) trace_printf(args) #define TRACE_VERBOSE(args...) trace_verbose_printf(args) #else @@ -91,12 +93,11 @@ typedef int T_CONTEXT; #include #include #endif -#define __STDC_FORMAT_MACROS -#include #else #include #include #endif +#include #include #include #include @@ -166,5 +167,5 @@ extern DWORD GetTempPathWrapper(IN DWORD nBufferLength, OUT LPSTR lpBuffer); #else #define GetTempPathWrapper GetTempPathA #endif -extern void printf_status(const char* format, ...); -extern void printf_error(const char* format, ...); +extern void printf_status(const char* format, ...) MINIPAL_ATTR_FORMAT_PRINTF(1, 2); +extern void printf_error(const char* format, ...) MINIPAL_ATTR_FORMAT_PRINTF(1, 2); diff --git a/src/runtime/src/coreclr/debug/createdump/createdumpmain.cpp b/src/runtime/src/coreclr/debug/createdump/createdumpmain.cpp index 5bb0f1b948da..68e5f6929f8a 100644 --- a/src/runtime/src/coreclr/debug/createdump/createdumpmain.cpp +++ b/src/runtime/src/coreclr/debug/createdump/createdumpmain.cpp @@ -199,7 +199,7 @@ int createdump_main(const int argc, const char* argv[]) g_ticksPerMS = minipal_hires_tick_frequency() / 1000UL; g_startTime = minipal_hires_ticks(); - TRACE("TickFrequency: %d ticks per ms\n", g_ticksPerMS); + TRACE("TickFrequency: %" PRIu64 " ticks per ms\n", g_ticksPerMS); AStringHolder tmpPath = new char[MAX_LONGPATH]; if (options.DumpPathTemplate == nullptr) @@ -220,11 +220,11 @@ int createdump_main(const int argc, const char* argv[]) if (CreateDump(options)) { - printf_status("Dump successfully written in %llums\n", (minipal_hires_ticks() - g_startTime) / g_ticksPerMS); + printf_status("Dump successfully written in %" PRIu64 "ms\n", (minipal_hires_ticks() - g_startTime) / g_ticksPerMS); } else { - printf_error("Failure took %llums\n", (minipal_hires_ticks() - g_startTime) / g_ticksPerMS); + printf_error("Failure took %" PRIu64 "ms\n", (minipal_hires_ticks() - g_startTime) / g_ticksPerMS); exitCode = -1; } diff --git a/src/runtime/src/coreclr/debug/createdump/createdumpunix.cpp b/src/runtime/src/coreclr/debug/createdump/createdumpunix.cpp index 6fdc334b5ed2..44a8c6a154ce 100644 --- a/src/runtime/src/coreclr/debug/createdump/createdumpunix.cpp +++ b/src/runtime/src/coreclr/debug/createdump/createdumpunix.cpp @@ -23,7 +23,7 @@ CreateDump(const CreateDumpOptions& options) #if defined(__arm__) || defined(__aarch64__) || defined(__loongarch64) || defined(__riscv) g_pageSize = minipal_getpagesize(); #endif - TRACE("PAGE_SIZE %d\n", PAGE_SIZE); + TRACE("PAGE_SIZE %lu\n", (unsigned long)PAGE_SIZE); if (options.CrashReport && (options.AppModel == AppModelType::SingleFile || options.AppModel == AppModelType::NativeAOT)) { diff --git a/src/runtime/src/coreclr/debug/createdump/dumpwritermacho.cpp b/src/runtime/src/coreclr/debug/createdump/dumpwritermacho.cpp index c459c9423cce..3b024edd7828 100644 --- a/src/runtime/src/coreclr/debug/createdump/dumpwritermacho.cpp +++ b/src/runtime/src/coreclr/debug/createdump/dumpwritermacho.cpp @@ -71,7 +71,7 @@ DumpWriter::WriteDump() if (alignment > 0) { if (alignment > sizeof(m_tempBuffer)) { - printf_error("Internal error: segment alignment %llu > sizeof(m_tempBuffer)\n", alignment); + printf_error("Internal error: segment alignment %" PRIu64 " > sizeof(m_tempBuffer)\n", alignment); return false; } memset(m_tempBuffer, 0, alignment); @@ -252,7 +252,7 @@ DumpWriter::WriteHeader(uint64_t* pFileOffset) bool DumpWriter::WriteSegments() { - TRACE("Writing %" PRIu64 " memory regions to core file\n", m_segmentLoadCommands.size()); + TRACE("Writing %zu memory regions to core file\n", m_segmentLoadCommands.size()); // Read from target process and write memory regions to core uint64_t total = 0; diff --git a/src/runtime/src/coreclr/debug/dbgutil/elfreader.cpp b/src/runtime/src/coreclr/debug/dbgutil/elfreader.cpp index 51f0118111bd..7e6116c68731 100644 --- a/src/runtime/src/coreclr/debug/dbgutil/elfreader.cpp +++ b/src/runtime/src/coreclr/debug/dbgutil/elfreader.cpp @@ -5,7 +5,6 @@ #include #include #include -#define __STDC_FORMAT_MACROS #include #include "elfreader.h" diff --git a/src/runtime/src/coreclr/debug/dbgutil/machoreader.cpp b/src/runtime/src/coreclr/debug/dbgutil/machoreader.cpp index 5527e9fac87a..8211efa453cc 100644 --- a/src/runtime/src/coreclr/debug/dbgutil/machoreader.cpp +++ b/src/runtime/src/coreclr/debug/dbgutil/machoreader.cpp @@ -5,7 +5,6 @@ #include #include #include -#define __STDC_FORMAT_MACROS #include #include #include "machoreader.h" diff --git a/src/runtime/src/coreclr/debug/di/breakpoint.cpp b/src/runtime/src/coreclr/debug/di/breakpoint.cpp index 943c0617db58..8032444160b0 100644 --- a/src/runtime/src/coreclr/debug/di/breakpoint.cpp +++ b/src/runtime/src/coreclr/debug/di/breakpoint.cpp @@ -607,9 +607,9 @@ HRESULT CordbStepper::StepRange(BOOL fStepIn, m_id = LsPtrToCookie(pEvent->StepData.stepperToken); - LOG((LF_CORDB,LL_INFO10000, "CS::SR: m_id:0x%x | 0x%x \n", - m_id, - LsPtrToCookie(pEvent->StepData.stepperToken))); + LOG((LF_CORDB,LL_INFO10000, "CS::SR: m_id:0x%zx | 0x%zx \n", + (size_t)m_id, + (size_t)LsPtrToCookie(pEvent->StepData.stepperToken))); #ifdef _DEBUG CordbAppDomain *pAppDomain = GetAppDomain(); diff --git a/src/runtime/src/coreclr/debug/di/cordb.cpp b/src/runtime/src/coreclr/debug/di/cordb.cpp index 64cd8d053cda..18a11297b281 100644 --- a/src/runtime/src/coreclr/debug/di/cordb.cpp +++ b/src/runtime/src/coreclr/debug/di/cordb.cpp @@ -260,7 +260,7 @@ BOOL WINAPI DbgDllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) WszGetModuleFileName(hInstance, rcFile); LOG((LF_CORDB, LL_INFO10000, "DI::DbgDllMain: load right side support from file '%s'\n", - rcFile.GetUnicode())); + rcFile.GetUTF8())); } #endif diff --git a/src/runtime/src/coreclr/debug/di/divalue.cpp b/src/runtime/src/coreclr/debug/di/divalue.cpp index a809af7cc342..4a0abfa6bacd 100644 --- a/src/runtime/src/coreclr/debug/di/divalue.cpp +++ b/src/runtime/src/coreclr/debug/di/divalue.cpp @@ -741,7 +741,7 @@ CordbReferenceValue::CordbReferenceValue(CordbAppDomain * pAppdomai { memset(&m_info, 0, sizeof(m_info)); - LOG((LF_CORDB,LL_EVERYTHING,"CRV::CRV: this:0x%x\n",this)); + LOG((LF_CORDB,LL_EVERYTHING,"CRV::CRV: this:0x%p\n",this)); m_size = sizeof(void *); // now instantiate the value home @@ -810,7 +810,7 @@ CordbReferenceValue::~CordbReferenceValue() { DTOR_ENTRY(this); - LOG((LF_CORDB,LL_EVERYTHING,"CRV::~CRV: this:0x%x\n",this)); + LOG((LF_CORDB,LL_EVERYTHING,"CRV::~CRV: this:0x%p\n",this)); _ASSERTE(IsNeutered()); } // CordbReferenceValue::~CordbReferenceValue diff --git a/src/runtime/src/coreclr/debug/di/module.cpp b/src/runtime/src/coreclr/debug/di/module.cpp index 8ccee6bda8d2..9846d82fcb97 100644 --- a/src/runtime/src/coreclr/debug/di/module.cpp +++ b/src/runtime/src/coreclr/debug/di/module.cpp @@ -1733,7 +1733,7 @@ HRESULT CordbModule::UpdateFunction(mdMethodDef funcMetaDataToken, // go looking for it later and easier to put it in now than have code to insert it later. if (!pOldVersion) { - LOG((LF_ENC, LL_INFO10000, "CM::UF: adding %8.8x with version %d\n", funcMetaDataToken, enCVersion)); + LOG((LF_ENC, LL_INFO10000, "CM::UF: adding %8.8x with version %zu\n", funcMetaDataToken, enCVersion)); HRESULT hr = S_OK; EX_TRY { @@ -1749,7 +1749,7 @@ HRESULT CordbModule::UpdateFunction(mdMethodDef funcMetaDataToken, // This method should not be called for versions that already exist _ASSERTE( enCVersion > pOldVersion->GetEnCVersionNumber()); - LOG((LF_ENC, LL_INFO10000, "CM::UF: updating %8.8x with version %d\n", funcMetaDataToken, enCVersion)); + LOG((LF_ENC, LL_INFO10000, "CM::UF: updating %8.8x with version %zu\n", funcMetaDataToken, enCVersion)); // Create a new function object. CordbFunction * pNewVersion = new (nothrow) CordbFunction(this, funcMetaDataToken, enCVersion); @@ -2183,18 +2183,19 @@ HRESULT CordbModule::ApplyChangesInternal(ULONG cbMetaData, { // Done receiving update events hr = retEvent->ApplyChangesResult.hr; - LOG((LF_CORDB, LL_INFO1000, "[%x] RCET::DRCE: EnC apply changes result %8.8x.\n", hr)); + LOG((LF_CORDB, LL_INFO1000, "[%x] RCET::DRCE: EnC apply changes result %8.8x.\n", GetCurrentThreadId(), hr)); break; } _ASSERTE(retEvent->type == DB_IPCE_ENC_UPDATE_FUNCTION || retEvent->type == DB_IPCE_ENC_ADD_FUNCTION || retEvent->type == DB_IPCE_ENC_ADD_FIELD); - LOG((LF_CORDB, LL_INFO1000, "[%x] RCET::DRCE: EnC %s %8.8x to version %d.\n", + LOG((LF_CORDB, LL_INFO1000, "[%x] RCET::DRCE: EnC %s %8.8x to version %llu.\n", GetCurrentThreadId(), retEvent->type == DB_IPCE_ENC_UPDATE_FUNCTION ? "Update function" : retEvent->type == DB_IPCE_ENC_ADD_FUNCTION ? "Add function" : "Add field", - retEvent->EnCUpdate.memberMetadataToken, retEvent->EnCUpdate.newVersionNumber)); + static_cast(retEvent->EnCUpdate.memberMetadataToken), + static_cast(retEvent->EnCUpdate.newVersionNumber))); CordbAppDomain *pAppDomain = GetAppDomain(); _ASSERTE(NULL != pAppDomain); @@ -2921,7 +2922,7 @@ HRESULT CordbCode::GetVersionNumber( ULONG32 *nVersion) FAIL_IF_NEUTERED(this); VALIDATE_POINTER_TO_OBJECT(nVersion, ULONG32 *); - LOG((LF_CORDB,LL_INFO10000,"R:CC:GVN:Returning 0x%x " + LOG((LF_CORDB,LL_INFO10000,"R:CC:GVN:Returning 0x%zx " "as version\n",m_nVersion)); *nVersion = (ULONG32)m_nVersion; @@ -3123,7 +3124,7 @@ HRESULT CordbILCode::GetLocalVarSig(SigParser *pLocalSigParser, } IfFailRet(hr); - LOG((LF_CORDB, LL_INFO100000, "CIC::GLVS creating sig parser sig=0x%x size=0x%x\n", localSignature, size)); + LOG((LF_CORDB, LL_INFO100000, "CIC::GLVS creating sig parser sig=%p size=0x%x\n", localSignature, size)); SigParser sigParser = SigParser(localSignature, size); uint32_t data; @@ -4718,10 +4719,10 @@ CordbNativeCode * CordbModule::LookupOrCreateNativeCode(mdMethodDef methodToken, // We didn't have an instance, so we'll build one and add it to the hash table LOG((LF_CORDB, LL_INFO10000, - "R:CT::RSCreating code w/ ver:0x%x, md:0x%x, nativeStart=0x%08x, nativeSize=0x%08x\n", - codeInfo.encVersion, - VmPtrToCookie(codeInfo.vmNativeCodeMethodDescToken), - codeInfo.m_rgCodeRegions[kHot].pAddress, + "R:CT::RSCreating code w/ ver:0x%zx, md:0x%zx, nativeStart=0x%08zx, nativeSize=0x%08x\n", + static_cast(codeInfo.encVersion), + (size_t)VmPtrToCookie(codeInfo.vmNativeCodeMethodDescToken), + (size_t)codeInfo.m_rgCodeRegions[kHot].pAddress, codeInfo.m_rgCodeRegions[kHot].cbSize)); // Lookup the function object that this code should be bound to diff --git a/src/runtime/src/coreclr/debug/di/process.cpp b/src/runtime/src/coreclr/debug/di/process.cpp index 45c52a54969b..b7464de024d8 100644 --- a/src/runtime/src/coreclr/debug/di/process.cpp +++ b/src/runtime/src/coreclr/debug/di/process.cpp @@ -977,7 +977,7 @@ CordbProcess::CordbProcess(ULONG64 clrInstanceId, CordbProcess::~CordbProcess() { - LOG((LF_CORDB, LL_INFO1000, "CP::~CP: deleting process 0x%08x\n", this)); + LOG((LF_CORDB, LL_INFO1000, "CP::~CP: deleting process %p\n", this)); DTOR_ENTRY(this); @@ -1771,7 +1771,7 @@ void CordbProcess::Terminating(BOOL fDetach) { INTERNAL_API_ENTRY(this); - LOG((LF_CORDB, LL_INFO1000,"CP::T: Terminating process 0x%x detach=%d\n", m_id, fDetach)); + LOG((LF_CORDB, LL_INFO1000,"CP::T: Terminating process 0x%zx detach=%d\n", m_id, fDetach)); m_terminated = true; m_cordb->ProcessStateChanged(); @@ -3325,7 +3325,7 @@ HRESULT CordbProcess::Stop(DWORD dwTimeout) HRESULT CordbProcess::StopInternal(DWORD dwTimeout, VMPTR_AppDomain pAppDomainToken) { - LOG((LF_CORDB, LL_INFO1000, "CP::S: stopping process 0x%x(%d) with timeout %d\n", m_id, m_id, dwTimeout)); + LOG((LF_CORDB, LL_INFO1000, "CP::S: stopping process 0x%zx(%zu) with timeout %d\n", m_id, m_id, dwTimeout)); INTERNAL_API_ENTRY(this); @@ -3463,7 +3463,8 @@ HRESULT CordbProcess::StopInternal(DWORD dwTimeout, VMPTR_AppDomain pAppDomainTo event = (DebuggerIPCEvent*) _alloca(CorDBIPC_BUFFER_SIZE); InitIPCEvent(event, DB_IPCE_ASYNC_BREAK, false, pAppDomainToken); - STRESS_LOG1(LF_CORDB, LL_INFO1000, "CP::S: sending async stop to appd 0x%x.\n", VmPtrToCookie(pAppDomainToken)); + STRESS_LOG1(LF_CORDB, LL_INFO1000, "CP::S: sending async stop to appd 0x%zx.\n", + static_cast(VmPtrToCookie(pAppDomainToken))); hr = m_cordb->SendIPCEvent(this, event, CorDBIPC_BUFFER_SIZE); hr = WORST_HR(hr, event->hr); @@ -3474,7 +3475,8 @@ HRESULT CordbProcess::StopInternal(DWORD dwTimeout, VMPTR_AppDomain pAppDomainTo return hr; } - LOG((LF_CORDB, LL_INFO1000, "CP::S: sent async stop to appd 0x%x.\n", VmPtrToCookie(pAppDomainToken))); + LOG((LF_CORDB, LL_INFO1000, "CP::S: sent async stop to appd 0x%zx.\n", + static_cast(VmPtrToCookie(pAppDomainToken)))); // Wait for the sync complete message to come in. Note: when the sync complete message arrives to the RCEventThread, // it will mark the process as synchronized and _not_ dispatch any events. Instead, it will set m_stopWaitEvent @@ -3699,7 +3701,7 @@ HRESULT CordbProcess::ContinueInternal(BOOL fIsOutOfBand) CORDBFailIfOnWin32EventThread(this); - STRESS_LOG1(LF_CORDB, LL_INFO1000, "CP::CI: continuing IB, this=0x%X\n", this); + STRESS_LOG1(LF_CORDB, LL_INFO1000, "CP::CI: continuing IB, this=%p\n", this); // Stop + Continue are executed under the Stop-Go lock. This makes them atomic. // We'll toggle the process-lock (b/c we communicate w/ the W32et, so that's not sufficient). @@ -4053,7 +4055,8 @@ HRESULT CordbProcess::ContinueInternal(BOOL fIsOutOfBand) } else if (fWasSynchronized) { - LOG((LF_CORDB, LL_INFO1000, "CP::CI: Sending continue to AppD:0x%x.\n", VmPtrToCookie(pAppDomainToken))); + LOG((LF_CORDB, LL_INFO1000, "CP::CI: Sending continue to AppD:0x%zx.\n", + static_cast(VmPtrToCookie(pAppDomainToken)))); #ifdef FEATURE_INTEROP_DEBUGGING STRESS_LOG2(LF_CORDB, LL_INFO1000, "Continue flags:special=%d, dowin32=%d\n", m_specialDeferment, fDoWin32Continue); #endif @@ -4075,7 +4078,8 @@ HRESULT CordbProcess::ContinueInternal(BOOL fIsOutOfBand) } _ASSERTE(SUCCEEDED(pEvent->hr)); - LOG((LF_CORDB, LL_INFO1000, "CP::CI: Continue sent to AppD:0x%x.\n", VmPtrToCookie(pAppDomainToken))); + LOG((LF_CORDB, LL_INFO1000, "CP::CI: Continue sent to AppD:0x%zx.\n", + static_cast(VmPtrToCookie(pAppDomainToken)))); } #ifdef FEATURE_INTEROP_DEBUGGING @@ -4790,10 +4794,10 @@ void CordbProcess::RawDispatchEvent( case DB_IPCE_LOAD_MODULE: { LOG((LF_CORDB, LL_INFO100, - "RCET::HRCE: load module (includes assembly loading) on thread %#x Asm:0x%08x AD:0x%08x \n", + "RCET::HRCE: load module (includes assembly loading) on thread %#x Asm:0x%08zx AD:0x%08zx \n", dwVolatileThreadId, - VmPtrToCookie(pEvent->LoadModuleData.vmAssembly), - VmPtrToCookie(pEvent->vmAppDomain))); + static_cast(VmPtrToCookie(pEvent->LoadModuleData.vmAssembly)), + static_cast(VmPtrToCookie(pEvent->vmAppDomain)))); _ASSERTE (pAppDomain != NULL); @@ -4821,10 +4825,10 @@ void CordbProcess::RawDispatchEvent( case DB_IPCE_UNLOAD_MODULE: { - STRESS_LOG3(LF_CORDB, LL_INFO100, "RCET::HRCE: unload module on thread %#x Mod:0x%x AD:0x%08x\n", + STRESS_LOG3(LF_CORDB, LL_INFO100, "RCET::HRCE: unload module on thread %#x Mod:0x%zx AD:0x%08zx\n", dwVolatileThreadId, - VmPtrToCookie(pEvent->UnloadModuleData.vmAssembly), - VmPtrToCookie(pEvent->vmAppDomain)); + static_cast(VmPtrToCookie(pEvent->UnloadModuleData.vmAssembly)), + static_cast(VmPtrToCookie(pEvent->vmAppDomain))); _ASSERTE (pAppDomain != NULL); @@ -4858,12 +4862,12 @@ void CordbProcess::RawDispatchEvent( CordbClass *pClass = NULL; LOG((LF_CORDB, LL_INFO10000, - "RCET::HRCE: load class on thread %#x Tok:0x%08x Mod:0x%08x Asm:0x%08x AD:0x%08x\n", + "RCET::HRCE: load class on thread %#x Tok:0x%08x Mod:0x%08zx Asm:0x%08zx AD:0x%08zx\n", dwVolatileThreadId, - pEvent->LoadClass.classMetadataToken, - VmPtrToCookie(pEvent->LoadClass.vmAssembly), - LsPtrToCookie(pEvent->LoadClass.classDebuggerAssemblyToken), - VmPtrToCookie(pEvent->vmAppDomain))); + static_cast(pEvent->LoadClass.classMetadataToken), + static_cast(VmPtrToCookie(pEvent->LoadClass.vmAssembly)), + static_cast(LsPtrToCookie(pEvent->LoadClass.classDebuggerAssemblyToken)), + static_cast(VmPtrToCookie(pEvent->vmAppDomain)))); _ASSERTE (pAppDomain != NULL); @@ -4916,11 +4920,11 @@ void CordbProcess::RawDispatchEvent( case DB_IPCE_UNLOAD_CLASS: { LOG((LF_CORDB, LL_INFO10000, - "RCET::HRCE: unload class on thread %#x Tok:0x%08x Mod:0x%08x AD:0x%08x\n", + "RCET::HRCE: unload class on thread %#x Tok:0x%08x Mod:0x%08zx AD:0x%08zx\n", dwVolatileThreadId, - pEvent->UnloadClass.classMetadataToken, - VmPtrToCookie(pEvent->UnloadClass.vmAssembly), - VmPtrToCookie(pEvent->vmAppDomain))); + static_cast(pEvent->UnloadClass.classMetadataToken), + static_cast(VmPtrToCookie(pEvent->UnloadClass.vmAssembly)), + static_cast(VmPtrToCookie(pEvent->vmAppDomain)))); // get the appdomain object _ASSERTE (pAppDomain != NULL); @@ -5019,9 +5023,9 @@ void CordbProcess::RawDispatchEvent( case DB_IPCE_CREATE_APP_DOMAIN: { STRESS_LOG2(LF_CORDB, LL_INFO100, - "RCET::HRCE: create appdomain on thread %#x AD:0x%08x \n", + "RCET::HRCE: create appdomain on thread %#x AD:0x%08zx \n", dwVolatileThreadId, - VmPtrToCookie(pEvent->vmAppDomain)); + static_cast(VmPtrToCookie(pEvent->vmAppDomain))); // Enumerate may have prepopulated the appdomain, so check if it already exists. @@ -5041,10 +5045,10 @@ void CordbProcess::RawDispatchEvent( case DB_IPCE_UNLOAD_ASSEMBLY: { - LOG((LF_CORDB, LL_INFO100, "RCET::DRCE: unload assembly on thread %#x Asm:0x%x AD:0x%x\n", + LOG((LF_CORDB, LL_INFO100, "RCET::DRCE: unload assembly on thread %#x Asm:0x%zx AD:0x%zx\n", dwVolatileThreadId, - VmPtrToCookie(pEvent->AssemblyData.vmAssembly), - VmPtrToCookie(pEvent->vmAppDomain))); + static_cast(VmPtrToCookie(pEvent->AssemblyData.vmAssembly)), + static_cast(VmPtrToCookie(pEvent->vmAppDomain)))); _ASSERTE (pAppDomain != NULL); @@ -5156,9 +5160,9 @@ void CordbProcess::RawDispatchEvent( case DB_IPCE_NAME_CHANGE: { - LOG((LF_CORDB, LL_INFO1000, "RCET::HRCE: Name Change %d 0x%p\n", + LOG((LF_CORDB, LL_INFO1000, "RCET::HRCE: Name Change %d 0x%zx\n", dwVolatileThreadId, - VmPtrToCookie(pEvent->NameChange.vmAppDomain))); + static_cast(VmPtrToCookie(pEvent->NameChange.vmAppDomain)))); pThread = NULL; pAppDomain.Clear(); @@ -5360,9 +5364,9 @@ void CordbProcess::RawDispatchEvent( STRESS_LOG4(LF_CORDB, LL_INFO100, "RCET::DRCE: Exception2 0x%p 0x%X 0x%X 0x%X\n", CORDB_ADDRESS_TO_PTR(pEvent->ExceptionCallback2.framePointer), - pEvent->ExceptionCallback2.nOffset, - pEvent->ExceptionCallback2.eventType, - pEvent->ExceptionCallback2.dwFlags + static_cast(pEvent->ExceptionCallback2.nOffset), + static_cast(pEvent->ExceptionCallback2.eventType), + static_cast(pEvent->ExceptionCallback2.dwFlags) ); if (pThread == NULL) @@ -5410,8 +5414,8 @@ void CordbProcess::RawDispatchEvent( { STRESS_LOG2(LF_CORDB, LL_INFO100, "RCET::DRCE: Exception Unwind 0x%X 0x%X\n", - pEvent->ExceptionCallback2.eventType, - pEvent->ExceptionCallback2.dwFlags + static_cast(pEvent->ExceptionCallback2.eventType), + static_cast(pEvent->ExceptionCallback2.dwFlags) ); if (pThread == NULL) @@ -5471,7 +5475,7 @@ void CordbProcess::RawDispatchEvent( _ASSERTE(!"Unknown event"); LOG((LF_CORDB, LL_INFO1000, "[%x] RCET::HRCE: Unknown event: 0x%08x\n", - GetCurrentThreadId(), pEvent->type)); + GetCurrentThreadId(), static_cast(pEvent->type))); } @@ -5676,7 +5680,7 @@ HRESULT CordbProcess::SetAllThreadsDebugState(CorDebugThreadState state, } CordbThread * pCordbExceptThread = static_cast (pExceptThread); - LOG((LF_CORDB, LL_INFO1000, "CP::SATDS: except thread=0x%08x 0x%x\n", + LOG((LF_CORDB, LL_INFO1000, "CP::SATDS: except thread=%p 0x%zx\n", pExceptThread, (pCordbExceptThread != NULL) ? pCordbExceptThread->m_id : 0)); @@ -5778,7 +5782,8 @@ HRESULT CordbProcess::IsTransitionStub(CORDB_ADDRESS address, BOOL *pfTransition _ASSERTE(eventData.type == DB_IPCE_IS_TRANSITION_STUB_RESULT); *pfTransitionStub = eventData.IsTransitionStubResult.isStub; - LOG((LF_CORDB, LL_INFO1000, "CP::ITS: addr=0x%p result=%d\n", address, *pfTransitionStub)); + LOG((LF_CORDB, LL_INFO1000, "CP::ITS: addr=%p result=%d\n", CORDB_ADDRESS_TO_PTR(address), + *pfTransitionStub)); // @todo - beware that IsTransitionStub has a very important sideeffect - it synchronizes the runtime! // This for example covers an OS bug where SetThreadContext may silently fail if we're not synchronized. // (See IMDArocess::SetThreadContext for details on that bug). @@ -6144,7 +6149,7 @@ HRESULT CordbProcess::ReadMemory(CORDB_ADDRESS address, // read. if ((*read > 0) && (*read <= size)) { - LOG((LF_CORDB, LL_INFO100000, "CP::RM: read %d bytes from 0x%08x, first byte is 0x%x\n", + LOG((LF_CORDB, LL_INFO100000, "CP::RM: read %zu bytes from 0x%08x, first byte is 0x%x\n", *read, (DWORD)address, buffer[0])); if (m_initialized) @@ -6234,7 +6239,7 @@ HRESULT CordbProcess::AdjustBuffer( CORDB_ADDRESS address, if (!m_runtimeOffsetsInitialized) return S_OK; - LOG((LF_CORDB,LL_INFO10000, "CordbProcess::AdjustBuffer at addr 0x%p\n", address)); + LOG((LF_CORDB,LL_INFO10000, "CordbProcess::AdjustBuffer at addr %p\n", CORDB_ADDRESS_TO_PTR(address))); if (mode == AB_WRITE) { @@ -6757,7 +6762,7 @@ HRESULT CordbProcess::WriteMemory(CORDB_ADDRESS address, DWORD size, } - LOG((LF_CORDB, LL_INFO100000, "CP::WM: wrote %d bytes at 0x%08x, first byte is 0x%x\n", + LOG((LF_CORDB, LL_INFO100000, "CP::WM: wrote %zu bytes at 0x%08x, first byte is 0x%x\n", *written, (DWORD)address, buffer[0])); if (bUpdateOriginalPatchTable == TRUE ) @@ -7141,57 +7146,57 @@ HRESULT CordbProcess::GetRuntimeOffsets() #ifdef FEATURE_INTEROP_DEBUGGING LOG((LF_CORDB, LL_INFO10000, " m_genericHijackFuncAddr= 0x%p\n", m_runtimeOffsets.m_genericHijackFuncAddr)); - LOG((LF_CORDB, LL_INFO10000, " m_signalHijackStartedBPAddr= 0x%p\n", - m_runtimeOffsets.m_signalHijackStartedBPAddr)); - LOG((LF_CORDB, LL_INFO10000, " m_excepNotForRuntimeBPAddr= 0x%p\n", - m_runtimeOffsets.m_excepNotForRuntimeBPAddr)); - LOG((LF_CORDB, LL_INFO10000, " m_notifyRSOfSyncCompleteBPAddr= 0x%p\n", - m_runtimeOffsets.m_notifyRSOfSyncCompleteBPAddr)); + LOG((LF_CORDB, LL_INFO10000, " m_signalHijackStartedBPAddr= %p\n", + (void*)(m_runtimeOffsets.m_signalHijackStartedBPAddr))); + LOG((LF_CORDB, LL_INFO10000, " m_excepNotForRuntimeBPAddr= %p\n", + (void*)(m_runtimeOffsets.m_excepNotForRuntimeBPAddr))); + LOG((LF_CORDB, LL_INFO10000, " m_notifyRSOfSyncCompleteBPAddr= %p\n", + (void*)(m_runtimeOffsets.m_notifyRSOfSyncCompleteBPAddr))); LOG((LF_CORDB, LL_INFO10000, " m_debuggerWordTLSIndex= 0x%08x\n", m_runtimeOffsets.m_debuggerWordTLSIndex)); #endif // FEATURE_INTEROP_DEBUGGING - LOG((LF_CORDB, LL_INFO10000, " m_setThreadContextNeededAddr= 0x%p\n", - m_runtimeOffsets.m_setThreadContextNeededAddr)); - LOG((LF_CORDB, LL_INFO10000, " m_TLSIndex= 0x%08x\n", + LOG((LF_CORDB, LL_INFO10000, " m_setThreadContextNeededAddr= %p\n", + (void*)(m_runtimeOffsets.m_setThreadContextNeededAddr))); + LOG((LF_CORDB, LL_INFO10000, " m_TLSIndex= 0x%08zx\n", m_runtimeOffsets.m_TLSIndex)); - LOG((LF_CORDB, LL_INFO10000, " m_EEThreadStateOffset= 0x%08x\n", + LOG((LF_CORDB, LL_INFO10000, " m_EEThreadStateOffset= 0x%08zx\n", m_runtimeOffsets.m_EEThreadStateOffset)); - LOG((LF_CORDB, LL_INFO10000, " m_EEThreadStateNCOffset= 0x%08x\n", + LOG((LF_CORDB, LL_INFO10000, " m_EEThreadStateNCOffset= 0x%08zx\n", m_runtimeOffsets.m_EEThreadStateNCOffset)); - LOG((LF_CORDB, LL_INFO10000, " m_EEThreadPGCDisabledOffset= 0x%08x\n", + LOG((LF_CORDB, LL_INFO10000, " m_EEThreadPGCDisabledOffset= 0x%08zx\n", m_runtimeOffsets.m_EEThreadPGCDisabledOffset)); LOG((LF_CORDB, LL_INFO10000, " m_EEThreadPGCDisabledValue= 0x%08x\n", m_runtimeOffsets.m_EEThreadPGCDisabledValue)); - LOG((LF_CORDB, LL_INFO10000, " m_EEThreadFrameOffset= 0x%08x\n", + LOG((LF_CORDB, LL_INFO10000, " m_EEThreadFrameOffset= 0x%08zx\n", m_runtimeOffsets.m_EEThreadFrameOffset)); - LOG((LF_CORDB, LL_INFO10000, " m_EEThreadMaxNeededSize= 0x%08x\n", + LOG((LF_CORDB, LL_INFO10000, " m_EEThreadMaxNeededSize= 0x%08zx\n", m_runtimeOffsets.m_EEThreadMaxNeededSize)); LOG((LF_CORDB, LL_INFO10000, " m_EEThreadSteppingStateMask= 0x%08x\n", m_runtimeOffsets.m_EEThreadSteppingStateMask)); LOG((LF_CORDB, LL_INFO10000, " m_EEMaxFrameValue= 0x%08x\n", m_runtimeOffsets.m_EEMaxFrameValue)); - LOG((LF_CORDB, LL_INFO10000, " m_EEThreadDebuggerFilterContextOffset= 0x%08x\n", + LOG((LF_CORDB, LL_INFO10000, " m_EEThreadDebuggerFilterContextOffset= 0x%08zx\n", m_runtimeOffsets.m_EEThreadDebuggerFilterContextOffset)); - LOG((LF_CORDB, LL_INFO10000, " m_EEFrameNextOffset= 0x%08x\n", + LOG((LF_CORDB, LL_INFO10000, " m_EEFrameNextOffset= 0x%08zx\n", m_runtimeOffsets.m_EEFrameNextOffset)); LOG((LF_CORDB, LL_INFO10000, " m_EEIsManagedExceptionStateMask= 0x%08x\n", m_runtimeOffsets.m_EEIsManagedExceptionStateMask)); - LOG((LF_CORDB, LL_INFO10000, " m_pPatches= 0x%08x\n", + LOG((LF_CORDB, LL_INFO10000, " m_pPatches= %p\n", m_runtimeOffsets.m_pPatches)); - LOG((LF_CORDB, LL_INFO10000, " m_offRgData= 0x%08x\n", + LOG((LF_CORDB, LL_INFO10000, " m_offRgData= 0x%08zx\n", m_runtimeOffsets.m_offRgData)); - LOG((LF_CORDB, LL_INFO10000, " m_offCData= 0x%08x\n", + LOG((LF_CORDB, LL_INFO10000, " m_offCData= 0x%08zx\n", m_runtimeOffsets.m_offCData)); - LOG((LF_CORDB, LL_INFO10000, " m_cbPatch= 0x%08x\n", + LOG((LF_CORDB, LL_INFO10000, " m_cbPatch= 0x%08zx\n", m_runtimeOffsets.m_cbPatch)); - LOG((LF_CORDB, LL_INFO10000, " m_offAddr= 0x%08x\n", + LOG((LF_CORDB, LL_INFO10000, " m_offAddr= 0x%08zx\n", m_runtimeOffsets.m_offAddr)); - LOG((LF_CORDB, LL_INFO10000, " m_offOpcode= 0x%08x\n", + LOG((LF_CORDB, LL_INFO10000, " m_offOpcode= 0x%08zx\n", m_runtimeOffsets.m_offOpcode)); - LOG((LF_CORDB, LL_INFO10000, " m_cbOpcode= 0x%08x\n", + LOG((LF_CORDB, LL_INFO10000, " m_cbOpcode= 0x%08zx\n", m_runtimeOffsets.m_cbOpcode)); - LOG((LF_CORDB, LL_INFO10000, " m_offTraceType= 0x%08x\n", + LOG((LF_CORDB, LL_INFO10000, " m_offTraceType= 0x%08zx\n", m_runtimeOffsets.m_offTraceType)); LOG((LF_CORDB, LL_INFO10000, " m_traceTypeUnmanaged= 0x%08x\n", m_runtimeOffsets.m_traceTypeUnmanaged)); @@ -8403,7 +8408,7 @@ bool CordbProcess::IsBreakOpcodeAtAddress(const void * address) HRESULT CordbProcess::SetUnmanagedBreakpoint(CORDB_ADDRESS address, ULONG32 bufsize, BYTE buffer[], ULONG32 * bufLen) { - LOG((LF_CORDB, LL_INFO100, "CP::SetUnBP: pProcess=%x, address=%p.\n", this, CORDB_ADDRESS_TO_PTR(address))); + LOG((LF_CORDB, LL_INFO100, "CP::SetUnBP: pProcess=%p, address=%p.\n", this, CORDB_ADDRESS_TO_PTR(address))); #ifndef FEATURE_INTEROP_DEBUGGING return E_NOTIMPL; #else @@ -8430,7 +8435,7 @@ CordbProcess::SetUnmanagedBreakpoint(CORDB_ADDRESS address, ULONG32 bufsize, BYT HRESULT CordbProcess::SetUnmanagedBreakpointInternal(CORDB_ADDRESS address, ULONG32 bufsize, BYTE buffer[], ULONG32 * bufLen) { - LOG((LF_CORDB, LL_INFO100, "CP::SetUnBPI: pProcess=%x, address=%p.\n", this, CORDB_ADDRESS_TO_PTR(address))); + LOG((LF_CORDB, LL_INFO100, "CP::SetUnBPI: pProcess=%p, address=%p.\n", this, CORDB_ADDRESS_TO_PTR(address))); #ifndef FEATURE_INTEROP_DEBUGGING return E_NOTIMPL; #else @@ -8522,7 +8527,7 @@ CordbProcess::SetUnmanagedBreakpointInternal(CORDB_ADDRESS address, ULONG32 bufs HRESULT CordbProcess::ClearUnmanagedBreakpoint(CORDB_ADDRESS address) { - LOG((LF_CORDB, LL_INFO100, "CP::ClearUnBP: pProcess=%x, address=%p.\n", this, CORDB_ADDRESS_TO_PTR(address))); + LOG((LF_CORDB, LL_INFO100, "CP::ClearUnBP: pProcess=%p, address=%p.\n", this, CORDB_ADDRESS_TO_PTR(address))); #ifndef FEATURE_INTEROP_DEBUGGING return E_NOTIMPL; #else @@ -8844,7 +8849,7 @@ void CordbProcess::FinishInitializeIPCChannelWorker() BOOL fBlockExists; GetEventBlock(&fBlockExists); // throws on error - LOG((LF_CORDB, LL_EVERYTHING, "Size of CdbP is %d\n", sizeof(CordbProcess))); + LOG((LF_CORDB, LL_EVERYTHING, "Size of CdbP is %zu\n", sizeof(CordbProcess))); m_pEventChannel->Init(m_handle); @@ -9278,8 +9283,9 @@ HRESULT CordbRCEventThread::SendIPCEvent(CordbProcess* process, if (eventSize > CorDBIPC_BUFFER_SIZE) return E_INVALIDARG; - STRESS_LOG4(LF_CORDB, LL_INFO1000, "CRCET::SIPCE: sending %s to AD 0x%x, proc 0x%x(%d)\n", - IPCENames::GetName(event->type), VmPtrToCookie(event->vmAppDomain), process->m_id, process->m_id); + STRESS_LOG4(LF_CORDB, LL_INFO1000, "CRCET::SIPCE: sending %s to AD 0x%zx, proc 0x%zx(%zu)\n", + IPCENames::GetName(event->type), static_cast(VmPtrToCookie(event->vmAppDomain)), + static_cast(process->m_id), static_cast(process->m_id)); // For 2-way events, this check is unnecessary (since we already check for LS exit) // But for async events, we need this. @@ -9626,8 +9632,11 @@ void CordbProcess::HandleRCEvent( IfFailThrow(pManagedEvent->hr); - STRESS_LOG4(LF_CORDB, LL_INFO1000, "RCET::TP: Got %s for AD 0x%x, proc 0x%x(%d)\n", - IPCENames::GetName(pManagedEvent->type), VmPtrToCookie(pManagedEvent->vmAppDomain), this->m_id, this->m_id); + STRESS_LOG4(LF_CORDB, LL_INFO1000, "RCET::TP: Got %s for AD 0x%zx, proc 0x%zx(%zu)\n", + IPCENames::GetName(pManagedEvent->type), + static_cast(VmPtrToCookie(pManagedEvent->vmAppDomain)), + static_cast(this->m_id), + static_cast(this->m_id)); RSExtSmartPtr pCallback2; pCallback->QueryInterface(IID_ICorDebugManagedCallback2, reinterpret_cast (&pCallback2)); @@ -9762,7 +9771,7 @@ void CordbRCEventThread::ThreadProc() // per-process mutex when checking the process's synchronized flag here. if (!pProcess->GetSynchronized() && pProcess->IsSafeToSendEvents()) { - STRESS_LOG2(LF_CORDB, LL_INFO1000, "RCET::TP: listening to process 0x%x(%d)\n", + STRESS_LOG2(LF_CORDB, LL_INFO1000, "RCET::TP: listening to process 0x%zx(%zu)\n", pProcess->m_id, pProcess->m_id); waitSet[waitCount] = pProcess->m_leftSideEventAvailable; @@ -10038,11 +10047,11 @@ HRESULT CordbRCEventThread::WaitForIPCEventFromProcess(CordbProcess * pProcess, { IfFailThrow(pEvent->hr); - STRESS_LOG4(LF_CORDB, LL_INFO1000, "CRCET::SIPCE: Got %s for AD 0x%x, proc 0x%x(%d)\n", + STRESS_LOG4(LF_CORDB, LL_INFO1000, "CRCET::SIPCE: Got %s for AD 0x%zx, proc 0x%zx(%zu)\n", IPCENames::GetName(pEvent->type), - VmPtrToCookie(pEvent->vmAppDomain), - pProcess->m_id, - pProcess->m_id); + static_cast(VmPtrToCookie(pEvent->vmAppDomain)), + static_cast(pProcess->m_id), + static_cast(pProcess->m_id)); } EX_CATCH_HRESULT(hr) diff --git a/src/runtime/src/coreclr/debug/di/rsappdomain.cpp b/src/runtime/src/coreclr/debug/di/rsappdomain.cpp index 889fc0bfc764..2b07c1649afd 100644 --- a/src/runtime/src/coreclr/debug/di/rsappdomain.cpp +++ b/src/runtime/src/coreclr/debug/di/rsappdomain.cpp @@ -54,7 +54,7 @@ CordbAppDomain::CordbAppDomain(CordbProcess * pProcess, VMPTR_AppDomain vmAppDo // of whether our ADID is valid or not, and requery if necessary. IfFailThrow(m_pProcess->GetDAC()->GetAppDomainId(m_vmAppDomain, &m_AppDomainId)); - LOG((LF_CORDB,LL_INFO10000, "CAD::CAD: this:0x%x (void*)this:0x%x<%d>\n", this, (void *)this, m_AppDomainId)); + LOG((LF_CORDB,LL_INFO10000, "CAD::CAD: this:%p (void*)this:%p<%d>\n", this, (void *)this, m_AppDomainId)); #ifdef _DEBUG m_assemblies.DebugSetRSLock(pProcess->GetProcessLock()); diff --git a/src/runtime/src/coreclr/debug/di/rsfunction.cpp b/src/runtime/src/coreclr/debug/di/rsfunction.cpp index f5d3a3f57f1b..92c73b9aba68 100644 --- a/src/runtime/src/coreclr/debug/di/rsfunction.cpp +++ b/src/runtime/src/coreclr/debug/di/rsfunction.cpp @@ -812,7 +812,7 @@ HRESULT CordbFunction::GetILCodeAndSigToken() } } - LOG((LF_CORDB,LL_INFO10000,"R:CF::GICAST: looking for IL code, version 0x%x\n", currentEnCVersion)); + LOG((LF_CORDB,LL_INFO10000,"R:CF::GICAST: looking for IL code, version 0x%zx\n", currentEnCVersion)); LOG((LF_CORDB,LL_INFO10000,"R:CF::GICAST: not found, creating...\n")); if(codeInfo.pAddress == 0) diff --git a/src/runtime/src/coreclr/debug/di/rsmain.cpp b/src/runtime/src/coreclr/debug/di/rsmain.cpp index c7d5c5a9e24e..e2f251637370 100644 --- a/src/runtime/src/coreclr/debug/di/rsmain.cpp +++ b/src/runtime/src/coreclr/debug/di/rsmain.cpp @@ -1305,7 +1305,7 @@ void Cordb::AddProcess(CordbProcess* process) { // At this point, we should have already checked that we // can have another debuggee. - STRESS_LOG1(LF_CORDB, LL_INFO10, "Cordb::AddProcess %08x...\n", process); + STRESS_LOG1(LF_CORDB, LL_INFO10, "Cordb::AddProcess %p...\n", process); if ((m_managedCallback == NULL) || (m_managedCallback2 == NULL) || (m_managedCallback3 == NULL) || (m_managedCallback4 == NULL)) { @@ -1330,7 +1330,7 @@ void Cordb::AddProcess(CordbProcess* process) // void Cordb::RemoveProcess(CordbProcess* process) { - STRESS_LOG1(LF_CORDB, LL_INFO10, "Cordb::RemoveProcess %08x...\n", process); + STRESS_LOG1(LF_CORDB, LL_INFO10, "Cordb::RemoveProcess %p...\n", process); LockProcessList(); GetProcessList()->RemoveBase((ULONG_PTR)process->m_id); @@ -2547,4 +2547,3 @@ HRESULT CopyOutString(LPCWSTR pInputString, ULONG32 cchName, ULONG32 * pcchName, return S_OK; } } - diff --git a/src/runtime/src/coreclr/debug/di/rspriv.h b/src/runtime/src/coreclr/debug/di/rspriv.h index fdafbac62706..fae880461662 100644 --- a/src/runtime/src/coreclr/debug/di/rspriv.h +++ b/src/runtime/src/coreclr/debug/di/rspriv.h @@ -11124,7 +11124,7 @@ class InternalDacCallbackHolder // - we're only being called through a public API. //----------------------------------------------------------------------------- #define PUBLIC_API_ENTRY(_pThis) \ - STRESS_LOG2(LF_CORDB, LL_INFO1000, "[Public API '%s', this=0x%p]\n", __FUNCTION__, _pThis); \ + STRESS_LOG2(LF_CORDB, LL_INFO1000, "[Public API '%s', this=%p]\n", __FUNCTION__, static_cast(_pThis)); \ PUBLIC_CONTRACT; \ PublicAPIHolder __pah; @@ -11133,7 +11133,7 @@ class InternalDacCallbackHolder // public version is heavier (eg, checking the HRESULT) so we benefit from having a fast // internal version and calling that directly. #define PUBLIC_REENTRANT_API_ENTRY(_pThis) \ - STRESS_LOG2(LF_CORDB, LL_INFO1000, "[Public API (re) '%s', this=0x%p]\n", __FUNCTION__, _pThis); \ + STRESS_LOG2(LF_CORDB, LL_INFO1000, "[Public API (re) '%s', this=%p]\n", __FUNCTION__, static_cast(_pThis)); \ PUBLIC_CONTRACT; \ PublicReentrantAPIHolder __pah; diff --git a/src/runtime/src/coreclr/debug/di/rsthread.cpp b/src/runtime/src/coreclr/debug/di/rsthread.cpp index 08c760735f91..345b59adaa86 100644 --- a/src/runtime/src/coreclr/debug/di/rsthread.cpp +++ b/src/runtime/src/coreclr/debug/di/rsthread.cpp @@ -95,8 +95,8 @@ CordbThread::CordbThread(CordbProcess * pProcess, VMPTR_Thread vmThread) : // If we ever support fibers, then we need to use something more unique than that. IfFailThrow(pProcess->GetDAC()->GetUniqueThreadID(vmThread, &m_dwUniqueID)); // may throw - LOG((LF_CORDB, LL_INFO1000, "CT::CT new thread 0x%p vmptr=0x%p id=0x%x\n", - this, m_vmThreadToken, m_dwUniqueID)); + LOG((LF_CORDB, LL_INFO1000, "CT::CT new thread 0x%p vmptr=0x%zx id=0x%x\n", + this, (size_t)VmPtrToCookie(m_vmThreadToken), m_dwUniqueID)); // Unique ID should never be 0. _ASSERTE(m_dwUniqueID != 0); @@ -679,7 +679,7 @@ HRESULT CordbThread::SetDebugState(CorDebugThreadState state) FAIL_IF_NEUTERED(this); ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess()); - LOG((LF_CORDB, LL_INFO1000, "CT::SDS: thread=0x%08x 0x%x, state=%d\n", this, m_id, state)); + LOG((LF_CORDB, LL_INFO1000, "CT::SDS: thread=%p 0x%zx, state=%d\n", this, (size_t)m_id, state)); // @dbgtodo- , sync - decide on how to suspend a thread. V2 leverages synchronization // (see below). For V3, do we just hard suspend the thread? @@ -1642,17 +1642,17 @@ HRESULT CordbThread::SetIP(bool fCanSetIPOnly, event.SetIP.fIsIL = fIsIL; - LOG((LF_CORDB, LL_INFO10000, "[%x] CT::SIP: Info:thread:0x%x" - "mod:0x%x MethodDef:0x%x offset:0x%x il?:0x%x\n", + LOG((LF_CORDB, LL_INFO10000, "[%x] CT::SIP: Info:thread:0x%zx" + "mod:0x%zx MethodDef:0x%x offset:0x%zx il?:0x%x\n", GetCurrentThreadId(), - VmPtrToCookie(m_vmThreadToken), - VmPtrToCookie(vmAssembly), + (size_t)VmPtrToCookie(m_vmThreadToken), + (size_t)VmPtrToCookie(vmAssembly), pNativeCode->GetMetadataToken(), offset, fIsIL)); - LOG((LF_CORDB, LL_INFO10000, "[%x] CT::SIP: sizeof(DebuggerIPCEvent):0x%x **********\n", - sizeof(DebuggerIPCEvent))); + LOG((LF_CORDB, LL_INFO10000, "[%x] CT::SIP: sizeof(DebuggerIPCEvent):0x%zx **********\n", + GetCurrentThreadId(), sizeof(DebuggerIPCEvent))); HRESULT hr = GetProcess()->m_cordb->SendIPCEvent(GetProcess(), &event, sizeof(DebuggerIPCEvent)); @@ -9784,7 +9784,7 @@ BOOL CordbEval::DoAppDomainsMatch( CordbAppDomain * pAppDomain, if ((pValueAppDomain != NULL) && (pValueAppDomain != pAppDomain)) { - LOG((LF_CORDB,LL_INFO1000, "CordbEval::DADM - AD mismatch. appDomain=0x%08x, param #%d=0x%08x, must fail.\n", + LOG((LF_CORDB,LL_INFO1000, "CordbEval::DADM - AD mismatch. appDomain=%p, param #%d=%p, must fail.\n", pAppDomain, i, pValueAppDomain)); return FALSE; } @@ -9797,7 +9797,7 @@ BOOL CordbEval::DoAppDomainsMatch( CordbAppDomain * pAppDomain, if( pTypeAppDomain != NULL && pTypeAppDomain != pAppDomain ) { - LOG((LF_CORDB,LL_INFO1000, "CordbEval::DADM - AD mismatch. appDomain=0x%08x, type param #%d=0x%08x, must fail.\n", + LOG((LF_CORDB,LL_INFO1000, "CordbEval::DADM - AD mismatch. appDomain=%p, type param #%d=%p, must fail.\n", pAppDomain, i, pTypeAppDomain)); return FALSE; } diff --git a/src/runtime/src/coreclr/debug/ee/amd64/walker.cpp b/src/runtime/src/coreclr/debug/ee/amd64/walker.cpp index 5ed3b9c8e319..f9ff163d5bed 100644 --- a/src/runtime/src/coreclr/debug/ee/amd64/walker.cpp +++ b/src/runtime/src/coreclr/debug/ee/amd64/walker.cpp @@ -1036,7 +1036,7 @@ void NativeWalker::DecodeInstructionForPatchSkip(const BYTE *address, Instructio if (done) break; - LOG((LF_CORDB, LL_INFO10000, "prefix:%0.2x ", *address)); + LOG((LF_CORDB, LL_INFO10000, "prefix:%02x ", *address)); address++; } while (true); @@ -1227,7 +1227,7 @@ void NativeWalker::DecodeInstructionForPatchSkip(const BYTE *address, Instructio size_t opCode = size_t(*address); size_t opCodeExt = (opCode << 2) | pp; - LOG((LF_CORDB, LL_INFO10000, "opCode:%02x pp:%d W:%d L:%d LL:%d ", opCode, pp, W ? 1 : 0, L ? 1 : 0, evex_LL)); + LOG((LF_CORDB, LL_INFO10000, "opCode:%02zx pp:%d W:%d L:%d LL:%d ", opCode, pp, W ? 1 : 0, L ? 1 : 0, evex_LL)); switch (opCodeMap) { @@ -1311,18 +1311,18 @@ void NativeWalker::DecodeInstructionForPatchSkip(const BYTE *address, Instructio case 0xC2: // RET case 0xC3: // RET N pInstrAttrib->m_fIsAbsBranch = true; - LOG((LF_CORDB, LL_INFO10000, "ABS:%0.2x\n", opcode0)); + LOG((LF_CORDB, LL_INFO10000, "ABS:%02x\n", opcode0)); break; case 0xE8: // CALL relative pInstrAttrib->m_fIsCall = true; - LOG((LF_CORDB, LL_INFO10000, "CALL REL:%0.2x\n", opcode0)); + LOG((LF_CORDB, LL_INFO10000, "CALL REL:%02x\n", opcode0)); break; case 0xC8: // ENTER pInstrAttrib->m_fIsCall = true; pInstrAttrib->m_fIsAbsBranch = true; - LOG((LF_CORDB, LL_INFO10000, "CALL ABS:%0.2x\n", opcode0)); + LOG((LF_CORDB, LL_INFO10000, "CALL ABS:%02x\n", opcode0)); break; case 0xFF: // CALL/JMP modr/m @@ -1342,11 +1342,11 @@ void NativeWalker::DecodeInstructionForPatchSkip(const BYTE *address, Instructio pInstrAttrib->m_fIsAbsBranch = true; break; } - LOG((LF_CORDB, LL_INFO10000, "CALL/JMP modr/m:%0.2x\n", opcode0)); + LOG((LF_CORDB, LL_INFO10000, "CALL/JMP modr/m:%02x\n", opcode0)); break; default: - LOG((LF_CORDB, LL_INFO10000, "NORMAL:%0.2x\n", opcode0)); + LOG((LF_CORDB, LL_INFO10000, "NORMAL:%02x\n", opcode0)); break; } } diff --git a/src/runtime/src/coreclr/debug/ee/arm/walker.cpp b/src/runtime/src/coreclr/debug/ee/arm/walker.cpp index d71a8ae09f6e..8e6b0a837293 100644 --- a/src/runtime/src/coreclr/debug/ee/arm/walker.cpp +++ b/src/runtime/src/coreclr/debug/ee/arm/walker.cpp @@ -39,7 +39,7 @@ void NativeWalker::Decode() // execute. Just return WALK_UNKNOWN so the caller will invoke single-step to update the register // context correctly for the next instruction. - LOG((LF_CORDB, LL_INFO100000, "ArmWalker::Decode: IT block at %x\n", m_ip)); + LOG((LF_CORDB, LL_INFO100000, "ArmWalker::Decode: IT block at %p\n", (void*)m_ip)); return; } @@ -59,7 +59,7 @@ void NativeWalker::Decode() // Fetch second word of 32-bit instruction. WORD opcode2 = CORDbgGetInstruction((BYTE*)((DWORD)m_ip) + 2); - LOG((LF_CORDB, LL_INFO100000, "ArmWalker::Decode 32bit instruction at %x, opcode: %x%x\n", m_ip, (DWORD)opcode1, (DWORD)opcode2)); + LOG((LF_CORDB, LL_INFO100000, "ArmWalker::Decode 32bit instruction at %p, opcode: %x%x\n", (void*)m_ip, (DWORD)opcode1, (DWORD)opcode2)); // WALK_RETURN if (((opcode1 & 0xffd0) == 0xe890) && @@ -247,7 +247,7 @@ void NativeWalker::Decode() } else { - LOG((LF_CORDB, LL_INFO100000, "ArmWalker::Decode 16bit instruction at %x, opcode: %x\n", m_ip, (DWORD)opcode1)); + LOG((LF_CORDB, LL_INFO100000, "ArmWalker::Decode 16bit instruction at %p, opcode: %x\n", (void*)m_ip, (DWORD)opcode1)); // WALK_RETURN if ((opcode1 & 0xfe00) == 0xbc00) { diff --git a/src/runtime/src/coreclr/debug/ee/arm64/walker.cpp b/src/runtime/src/coreclr/debug/ee/arm64/walker.cpp index ebec232a9afb..4697e885600b 100644 --- a/src/runtime/src/coreclr/debug/ee/arm64/walker.cpp +++ b/src/runtime/src/coreclr/debug/ee/arm64/walker.cpp @@ -130,12 +130,12 @@ BYTE* NativeWalker::SetupOrSimulateInstructionForPatchSkip(T_CONTEXT * context, { offset = offset << 12; finalAddr = (PCODE)(address + offset) & ~0xFFF; - LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Simulate opcode: %x to ADRP X%d %p finalAddr = %p\n", opcode, RegNum, offset, finalAddr)); + LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Simulate opcode: %x to ADRP X%d %p finalAddr = %p\n", opcode, RegNum, (void*)(size_t)offset, (void*)(size_t)finalAddr)); } else { finalAddr = (PCODE)(address + offset); - LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Simulate opcode: %x to ADR X%d %p finalAddr = %p\n", opcode, RegNum, offset, finalAddr)); + LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Simulate opcode: %x to ADR X%d %p finalAddr = %p\n", opcode, RegNum, (void*)(size_t)offset, (void*)(size_t)finalAddr)); } CORDbgSetInstruction((CORDB_ADDRESS_TYPE *)patchBypass, 0xd503201f); //Add Nop in buffer @@ -147,7 +147,7 @@ BYTE* NativeWalker::SetupOrSimulateInstructionForPatchSkip(T_CONTEXT * context, { offset = Expand19bitoffset(opcode); RegNum = (opcode & 0x1F); - LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Simulate opcode: %x to LDR[SW] | PRFM X%d %p\n", opcode, RegNum, offset)); + LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Simulate opcode: %x to LDR[SW] | PRFM X%d %p\n", opcode, RegNum, (void*)(size_t)offset)); } else if (NativeWalker::DecodePCRelativeBranchInst(context,opcode, offset, walk)) { @@ -189,7 +189,7 @@ BYTE* NativeWalker::SetupOrSimulateInstructionForPatchSkip(T_CONTEXT * context, if (walk == WALK_CALL) //initialize Lr { SetLR(context, (PCODE)address + MAX_INSTRUCTION_LENGTH); - LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Simulate opcode: %x is a Call instr, setting LR to %p \n", opcode,GetLR(context))); + LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Simulate opcode: %x is a Call instr, setting LR to %p \n", opcode, (void*)(size_t)GetLR(context))); } } else if(RegNum >= 0) @@ -242,7 +242,7 @@ BYTE* NativeWalker::SetupOrSimulateInstructionForPatchSkip(T_CONTEXT * context, LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Simulate Unknown opcode: %x [LDR(litera,SIMD &FP)] \n", opcode)); _ASSERTE(!("Arm64Walker::Simulated Unknown opcode")); } - LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Simulate loadedMemory [Hi: %ull, lo: %ull]\n", SimdRegContents.High, SimdRegContents.Low)); + LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Simulate loadedMemory [Hi: %llx, lo: %llx]\n", (unsigned long long)SimdRegContents.High, (unsigned long long)SimdRegContents.Low)); } } @@ -286,12 +286,12 @@ BOOL NativeWalker::DecodePCRelativeBranchInst(PT_CONTEXT context, const PRD_TYP if ((opcode & 0x80000000) != 0) //BL { walk = WALK_CALL; - LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Decoded opcode: %x to BL %p \n", opcode, offset)); + LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Decoded opcode: %x to BL %p \n", opcode, (void*)(size_t)offset)); } else { walk = WALK_BRANCH; //B - LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Decoded opcode: %x to B %p \n", opcode, offset)); + LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Decoded opcode: %x to B %p \n", opcode, (void*)(size_t)offset)); } return TRUE; } @@ -330,7 +330,7 @@ BOOL NativeWalker::DecodePCRelativeBranchInst(PT_CONTEXT context, const PRD_TYP { walk = WALK_BRANCH; offset = Expand19bitoffset(opcode); - LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Decoded opcode: %x to B.cond %p \n", opcode, offset)); + LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Decoded opcode: %x to B.cond %p \n", opcode, (void*)(size_t)offset)); } else // NOP { @@ -371,7 +371,7 @@ BOOL NativeWalker::DecodePCRelativeBranchInst(PT_CONTEXT context, const PRD_TYP { walk = WALK_BRANCH; offset = Expand19bitoffset(opcode); - LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Decoded opcode: %x to CB[N]Z X%d %p \n", opcode, RegNum, offset)); + LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Decoded opcode: %x to CB[N]Z X%d %p \n", opcode, RegNum, (void*)(size_t)offset)); } else // NOP { @@ -412,7 +412,7 @@ BOOL NativeWalker::DecodePCRelativeBranchInst(PT_CONTEXT context, const PRD_TYP { offset = offset | 0xFFFFFFFFFFFF0000; } - LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Decoded opcode: %x to TB[N]Z X%d %p \n", opcode, RegNum, offset)); + LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Decoded opcode: %x to TB[N]Z X%d %p \n", opcode, RegNum, (void*)(size_t)offset)); } else // NOP { diff --git a/src/runtime/src/coreclr/debug/ee/controller.cpp b/src/runtime/src/coreclr/debug/ee/controller.cpp index 9b5f3e156201..48a3e52fed16 100644 --- a/src/runtime/src/coreclr/debug/ee/controller.cpp +++ b/src/runtime/src/coreclr/debug/ee/controller.cpp @@ -200,7 +200,7 @@ SharedPatchBypassBuffer* DebuggerControllerPatch::GetOrCreateSharedPatchBypassBu BYTE* patchBypassRW = pSharedPatchBypassBufferRW->PatchBypass; BYTE* patchBypassRX = m_pSharedPatchBypassBuffer->PatchBypass; - LOG((LF_CORDB, LL_INFO10000, "DCP::CSPBB: Patch skip for opcode 0x%.4x at address %p buffer allocated at 0x%.8x\n", this->opcode, this->address, m_pSharedPatchBypassBuffer)); + LOG((LF_CORDB, LL_INFO10000, "DCP::CSPBB: Patch skip for opcode 0x%zx at address %p buffer allocated at %p\n", (size_t)this->opcode, this->address, m_pSharedPatchBypassBuffer)); // CopyInstructionBlock copies all the code bytes except the breakpoint byte(s). _ASSERTE( this->IsBound() ); @@ -1445,7 +1445,7 @@ bool DebuggerController::BindPatch(DebuggerControllerPatch *patch, } LOG((LF_CORDB,LL_INFO10000, "DC::BP: For startAddr %p, got DJI %p, from %p size: 0x%zu\n", - startAddr, info, info->m_addrOfCode, info->m_sizeOfCode)); + startAddr, info, (void*)info->m_addrOfCode, info->m_sizeOfCode)); } LOG((LF_CORDB, LL_INFO10000, "DC::BP: Trying to bind patch in %s::%s version %zu\n", @@ -1541,8 +1541,8 @@ bool DebuggerController::ApplyPatch(DebuggerControllerPatch *patch) patch->opcode = CORDbgGetInstruction(patch->address); CORDbgInsertBreakpoint((CORDB_ADDRESS_TYPE *)patch->address); - LOG((LF_CORDB, LL_EVERYTHING, "DC::ApplyPatch Breakpoint was inserted at %p for opcode %x\n", - patch->address, patch->opcode)); + LOG((LF_CORDB, LL_EVERYTHING, "DC::ApplyPatch Breakpoint was inserted at %p for opcode %zx\n", + patch->address, (size_t)patch->opcode)); #if !defined(HOST_OSX) || !defined(HOST_ARM64) if (!VirtualProtect(baseAddress, @@ -2522,7 +2522,7 @@ bool DebuggerController::PatchTrace(TraceDestination *trace, case TRACE_UNMANAGED: LOG((LF_CORDB, LL_INFO10000, "DC::PT: Setting unmanaged trace patch at 0x%p(%p)\n", - trace->GetAddress(), fp.GetSPValue())); + (void*)trace->GetAddress(), fp.GetSPValue())); if (fStopInUnmanaged && !_AddrIsJITHelper(trace->GetAddress())) { @@ -2541,7 +2541,7 @@ bool DebuggerController::PatchTrace(TraceDestination *trace, case TRACE_MANAGED: LOG((LF_CORDB, LL_INFO10000, - "Setting managed trace patch at 0x%p(%p)\n", trace->GetAddress(), fp.GetSPValue())); + "Setting managed trace patch at 0x%p(%p)\n", (void*)trace->GetAddress(), fp.GetSPValue())); MethodDesc *fd; fd = g_pEEInterface->GetNativeCodeMethodDesc(trace->GetAddress()); @@ -2585,7 +2585,7 @@ bool DebuggerController::PatchTrace(TraceDestination *trace, case TRACE_FRAME_PUSH: LOG((LF_CORDB, LL_INFO10000, - "Setting frame patch at %p(%p)\n", trace->GetAddress(), fp.GetSPValue())); + "Setting frame patch at %p(%p)\n", (void*)trace->GetAddress(), fp.GetSPValue())); AddAndActivateNativePatchForAddress((CORDB_ADDRESS_TYPE *)trace->GetAddress(), fp, @@ -2596,7 +2596,7 @@ bool DebuggerController::PatchTrace(TraceDestination *trace, case TRACE_MGR_PUSH: LOG((LF_CORDB, LL_INFO10000, "Setting frame patch (TRACE_MGR_PUSH) at %p(%p)\n", - trace->GetAddress(), fp.GetSPValue())); + (void*)trace->GetAddress(), fp.GetSPValue())); dcp = AddAndActivateNativePatchForAddress((CORDB_ADDRESS_TYPE *)trace->GetAddress(), LEAF_MOST_FRAME, // But Mgr_push can't have fp affinity! TRUE, @@ -2646,7 +2646,7 @@ bool DebuggerController::MatchPatch(Thread *thread, CONTEXT *context, DebuggerControllerPatch *patch) { - LOG((LF_CORDB, LL_INFO100000, "DC::MP: EIP:0x%p\n", GetIP(context))); + LOG((LF_CORDB, LL_INFO100000, "DC::MP: EIP:0x%p\n", (void*)GetIP(context))); // Caller should have already matched our addresses. if (patch->address != dac_cast(GetIP(context))) @@ -2754,7 +2754,7 @@ DebuggerPatchSkip *DebuggerController::ActivatePatchSkip(Thread *thread, _ASSERTE(pExecControl != NULL); pExecControl->BypassPatch(patch, thread); - LOG((LF_CORDB,LL_INFO10000, "DC::APS: Interpreter patch at PC=0x%p - bypass via ExecutionControl with opcode 0x%x\n", PC, patch->opcode)); + LOG((LF_CORDB,LL_INFO10000, "DC::APS: Interpreter patch at PC=0x%p - bypass via ExecutionControl with opcode 0x%zx\n", PC, (size_t)patch->opcode)); return NULL; } #endif // FEATURE_INTERPRETER @@ -3794,7 +3794,7 @@ bool DebuggerController::DispatchUnwind(Thread *thread, // LOG((LF_CORDB, LL_INFO10000, "Unwind trigger at offset 0x%p; handlerFP: 0x%p unwindReason: 0x%x.\n", - newOffset, handlerFP.GetSPValue(), unwindReason)); + (void*)newOffset, handlerFP.GetSPValue(), unwindReason)); p->TriggerUnwind(thread, fd, pDJI, @@ -3806,7 +3806,7 @@ bool DebuggerController::DispatchUnwind(Thread *thread, { LOG((LF_CORDB, LL_INFO10000, "Unwind trigger at offset 0x%p; handlerFP: 0x%p unwindReason: 0x%x.\n", - newOffset, handlerFP.GetSPValue(), unwindReason)); + (void*)newOffset, handlerFP.GetSPValue(), unwindReason)); } } @@ -3837,7 +3837,7 @@ void DebuggerController::EnableTraceCall(FramePointer maxFrame) ASSERT(m_thread != NULL); - LOG((LF_CORDB,LL_INFO1000, "DC::ETC maxFrame=0x%x, thread=0x%x\n", + LOG((LF_CORDB,LL_INFO1000, "DC::ETC maxFrame=%p, thread=0x%x\n", maxFrame.GetSPValue(), Debugger::GetThreadIdHelper(m_thread))); // JMC stepper should never enabled this. (They should enable ME instead). @@ -3976,7 +3976,7 @@ bool DebuggerController::DispatchTraceCall(Thread *thread, bool used = false; LOG((LF_CORDB, LL_INFO10000, - "DC::DTC: TraceCall at 0x%x\n", ip)); + "DC::DTC: TraceCall at 0x%p\n", ip)); ControllerLockHolder lockController; { @@ -4864,7 +4864,7 @@ DebuggerPatchSkip::DebuggerPatchSkip(Thread *thread, if (context ==(T_CONTEXT*) &c) thread->SetThreadContext(&c); - LOG((LF_CORDB, LL_INFO10000, "DPS::DPS Bypass at %p for opcode 0x%zx \n", patchBypassRX, patch->opcode)); + LOG((LF_CORDB, LL_INFO10000, "DPS::DPS Bypass at %p for opcode 0x%zx \n", patchBypassRX, (size_t)patch->opcode)); } // @@ -4944,8 +4944,8 @@ TP_RESULT DebuggerPatchSkip::TriggerPatch(DebuggerControllerPatch *patch, #if defined(_DEBUG) && !defined(FEATURE_EMULATE_SINGLESTEP) CONTEXT *context = GetManagedLiveCtx(thread); - LOG((LF_CORDB, LL_INFO1000, "DPS::TP: We've patched 0x%x (byPass:0x%x) " - "for a skip after an EnC update!\n", GetIP(context), + LOG((LF_CORDB, LL_INFO1000, "DPS::TP: We've patched %p (byPass:%p) " + "for a skip after an EnC update!\n", (void*)GetIP(context), GetBypassAddress())); _ASSERTE(g_patches != NULL); @@ -5027,11 +5027,11 @@ TP_RESULT DebuggerPatchSkip::TriggerExceptionHook(Thread *thread, CONTEXT * cont SIZE_T *sp = (SIZE_T *) GetSP(context); LOG((LF_CORDB, LL_INFO10000, - "Bypass call return address redirected from %p\n", *sp)); + "Bypass call return address redirected from 0x%zx\n", *sp)); *sp -= patchBypass - (BYTE*)m_address; - LOG((LF_CORDB, LL_INFO10000, "to %p\n", *sp)); + LOG((LF_CORDB, LL_INFO10000, "to 0x%zx\n", *sp)); } #else PORTABILITY_ASSERT("DebuggerPatchSkip::TriggerExceptionHook -- return address fixup NYI"); @@ -5042,7 +5042,7 @@ TP_RESULT DebuggerPatchSkip::TriggerExceptionHook(Thread *thread, CONTEXT * cont { // Fixup IP - LOG((LF_CORDB, LL_INFO10000, "Bypass instruction redirected from %p\n", GetIP(context))); + LOG((LF_CORDB, LL_INFO10000, "Bypass instruction redirected from %p\n", (void*)GetIP(context))); if (IsSingleStep(exception->ExceptionCode)) { @@ -5091,7 +5091,7 @@ TP_RESULT DebuggerPatchSkip::TriggerExceptionHook(Thread *thread, CONTEXT * cont SetIP(context, (PCODE)((BYTE *)GetIP(context) - (patchBypass - (BYTE *)m_address))); } - LOG((LF_CORDB, LL_ALWAYS, "DPS::TEH: IP now at %p\n", GetIP(context))); + LOG((LF_CORDB, LL_ALWAYS, "DPS::TEH: IP now at %p\n", (void*)GetIP(context))); } #endif @@ -5543,7 +5543,7 @@ DebuggerStepper::~DebuggerStepper() bool DebuggerStepper::ShouldContinueStep( ControllerStackInfo *info, SIZE_T nativeOffset) { - LOG((LF_CORDB,LL_INFO10000, "DeSt::ShContSt: nativeOffset:0x%p \n", nativeOffset)); + LOG((LF_CORDB,LL_INFO10000, "DeSt::ShContSt: nativeOffset:0x%p \n", (void*)nativeOffset)); if (m_rgfMappingStop != STOP_ALL && (m_reason != STEP_EXIT) ) { @@ -5554,7 +5554,7 @@ bool DebuggerStepper::ShouldContinueStep( ControllerStackInfo *info, LOG((LF_CORDB,LL_INFO10000,"DeSt::ShContSt: For code 0x%p, got " "DJI 0x%p, from 0x%p to 0x%p\n", (const BYTE*)GetControlPC(&(info->m_activeFrame.registers)), - ji, ji->m_addrOfCode, ji->m_addrOfCode+ji->m_sizeOfCode)); + ji, (void*)ji->m_addrOfCode, (void*)(ji->m_addrOfCode+ji->m_sizeOfCode))); } else { @@ -5609,9 +5609,9 @@ bool DebuggerStepper::IsRangeAppropriate(ControllerStackInfo *info) realFrame = &(info->m_activeFrame); } - LOG((LF_CORDB,LL_INFO10000, "DS::IRA: info->m_activeFrame.fp:0x%p m_fp:0x%p\n", info->m_activeFrame.fp, m_fp)); + LOG((LF_CORDB,LL_INFO10000, "DS::IRA: info->m_activeFrame.fp:%p m_fp:%p\n", info->m_activeFrame.fp.GetSPValue(), m_fp.GetSPValue())); LOG((LF_CORDB,LL_INFO10000, "DS::IRA: m_fdException:0x%p realFrame->md:0x%p realFrame->fp:0x%p m_fpException:0x%p\n", - m_fdException, realFrame->md, realFrame->fp, m_fpException)); + m_fdException, realFrame->md, realFrame->fp.GetSPValue(), m_fpException.GetSPValue())); if ( (info->m_activeFrame.fp == m_fp) || ( (m_fdException != NULL) && (realFrame->md == m_fdException) && IsEqualOrCloserToRoot(realFrame->fp, m_fpException) ) ) @@ -5765,7 +5765,7 @@ bool DebuggerStepper::DetectHandleInterceptors(ControllerStackInfo *info) if (!fAttemptStepOut) { - LOG((LF_CORDB,LL_INFO10000,"DS::DHI 0x%x set to STEP_INTERCEPT\n", this)); + LOG((LF_CORDB,LL_INFO10000,"DS::DHI 0x%p set to STEP_INTERCEPT\n", this)); m_reason = STEP_INTERCEPT; //remember why we've stopped } @@ -5781,7 +5781,7 @@ bool DebuggerStepper::DetectHandleInterceptors(ControllerStackInfo *info) } else { - LOG((LF_CORDB,LL_INFO10000,"DS::DHI 0x%x set to STEP_INTERCEPT\n", this)); + LOG((LF_CORDB,LL_INFO10000,"DS::DHI 0x%p set to STEP_INTERCEPT\n", this)); m_reason = STEP_INTERCEPT; //remember why we've stopped } @@ -5805,7 +5805,7 @@ bool DebuggerStepper::DetectHandleInterceptors(ControllerStackInfo *info) } else { - LOG((LF_CORDB, LL_INFO10000,"DS::DHI 0x%x set to STEP_INTERCEPT\n", this)); + LOG((LF_CORDB, LL_INFO10000,"DS::DHI 0x%p set to STEP_INTERCEPT\n", this)); m_reason = STEP_INTERCEPT; //remember why we've stopped } @@ -6113,7 +6113,7 @@ bool DebuggerStepper::TrapStepInHelper( else { LOG((LF_CORDB, LL_INFO1000, "Didn't step: md:%p td.type:%s td.address:%p, hot code address:%p\n", - md, GetTType(td.GetTraceType()), td.GetAddress(), code.getAddrOfHotCode())); + md, GetTType(td.GetTraceType()), (void*)td.GetAddress(), (void*)code.getAddrOfHotCode())); } } else @@ -6208,7 +6208,7 @@ static bool IsTailCall(const BYTE * ip, ControllerStackInfo* info, TailCallFunct bool DebuggerStepper::TrapInterpreterCodeStep(ControllerStackInfo *info, bool in, DebuggerJitInfo *ji) { PCODE currentPC = GetControlPC(&info->m_activeFrame.registers); - LOG((LF_CORDB,LL_INFO10000,"DS::TICS: In interpreter code at %p (in=%d)\n", currentPC, in)); + LOG((LF_CORDB,LL_INFO10000,"DS::TICS: In interpreter code at %p (in=%d)\n", (void*)currentPC, in)); InterpreterStepHelper helper(this, info, ji); @@ -6331,9 +6331,9 @@ bool DebuggerStepper::TrapStep(ControllerStackInfo *info, bool in) } #ifdef TARGET_X86 - LOG((LF_CORDB,LL_INFO1000, "GetJitInfo for pc = 0x%x (addr of " - "that value:0x%x)\n", (const BYTE*)(GetControlPC(&info->m_activeFrame.registers)), - GetRegdisplayPCTAddr(&info->m_activeFrame.registers))); + LOG((LF_CORDB,LL_INFO1000, "GetJitInfo for pc = %p (addr of " + "that value:%p)\n", (void*)(GetControlPC(&info->m_activeFrame.registers)), + (void*)GetRegdisplayPCTAddr(&info->m_activeFrame.registers))); #endif // Note: we used to pass in the IP from the active frame to GetJitInfo, but there seems to be no value in that, and @@ -6345,7 +6345,7 @@ bool DebuggerStepper::TrapStep(ControllerStackInfo *info, bool in) LOG((LF_CORDB,LL_INFO10000,"DS::TS: For code 0x%p, got DJI 0x%p, " "from 0x%p to 0x%p\n", (const BYTE*)(GetControlPC(&info->m_activeFrame.registers)), - ji, ji->m_addrOfCode, ji->m_addrOfCode+ji->m_sizeOfCode)); + ji, (void*)ji->m_addrOfCode, (void*)(ji->m_addrOfCode+ji->m_sizeOfCode))); } else { @@ -6580,7 +6580,7 @@ bool DebuggerStepper::TrapStep(ControllerStackInfo *info, bool in) SIZE_T offset = CodeRegionInfo::GetCodeRegionInfo(ji, info->m_activeFrame.md).AddressToOffset(ip); - LOG((LF_CORDB, LL_INFO1000, "Walking to ip 0x%p (natOff:0x%x)\n",ip,offset)); + LOG((LF_CORDB, LL_INFO1000, "Walking to ip 0x%p (natOff:0x%zx)\n",ip,offset)); if (!IsInRange(offset, range, rangeCount) && !ShouldContinueStep( info, offset )) @@ -6656,7 +6656,7 @@ bool DebuggerStepper::TrapStep(ControllerStackInfo *info, bool in) info->GetReturnFrame().fp, NULL); - LOG((LF_CORDB,LL_INFO10000,"DS0x%x m_reason=STEP_CALL 2\n", + LOG((LF_CORDB,LL_INFO10000,"DS0x%p m_reason=STEP_CALL 2\n", this)); m_reason = STEP_CALL; @@ -6852,7 +6852,7 @@ void DebuggerStepper::TrapStepOut(ControllerStackInfo *info, bool fForceTraditio LOG((LF_CORDB, LL_INFO10000, "DS::TSO:normally managed code AddPatch" - " in %s::%s, offset 0x%x, m_reason=%d\n", + " in %s::%s, offset 0x%zx, m_reason=%d\n", info->GetReturnFrame().md->m_pszDebugClassName, info->GetReturnFrame().md->m_pszDebugMethodName, reloffset, m_reason)); @@ -7120,8 +7120,8 @@ void DebuggerStepper::TrapStepOut(ControllerStackInfo *info, bool fForceTraditio // We're stepping out into unmanaged code LOG((LF_CORDB, LL_INFO10000, - "DS::TSO: Setting unmanaged trace patch at 0x%x(%x)\n", - GetControlPC(&(info->m_activeFrame.registers)), + "DS::TSO: Setting unmanaged trace patch at %p(%p)\n", + (void*)GetControlPC(&(info->m_activeFrame.registers)), info->GetReturnFrame().fp.GetSPValue())); AddAndActivateNativePatchForAddress((CORDB_ADDRESS_TYPE *)GetControlPC(&(info->m_activeFrame.registers)), @@ -7158,7 +7158,7 @@ void DebuggerStepper::TrapStepOut(ControllerStackInfo *info, bool fForceTraditio // EnableUnwind( m_fp ); void DebuggerStepper::StepOut(FramePointer fp, StackTraceTicket ticket) { - LOG((LF_CORDB, LL_INFO10000, "Attempting to step out, fp:0x%x this:0x%x" + LOG((LF_CORDB, LL_INFO10000, "Attempting to step out, fp:%p this:%p" "\n", fp.GetSPValue(), this )); Thread *thread = GetThread(); @@ -7259,7 +7259,7 @@ bool DebuggerStepper::SetRangesFromIL(DebuggerJitInfo *dji, COR_DEBUG_STEP_RANGE if (dji != NULL) { LOG((LF_CORDB,LL_INFO10000,"DeSt::St: For code md=%p, got DJI %p, from %p to %p\n", - fd, dji, dji->m_addrOfCode, dji->m_addrOfCode + dji->m_sizeOfCode)); + fd, dji, (void*)dji->m_addrOfCode, (void*)(dji->m_addrOfCode + dji->m_sizeOfCode))); // // Map ranges to native offsets for jitted code @@ -7612,8 +7612,8 @@ TP_RESULT DebuggerStepper::TriggerPatch(DebuggerControllerPatch *patch, StackTraceTicket ticket(patch); info.GetStackInfo(ticket, thread, LEAF_MOST_FRAME, context); - LOG((LF_CORDB, LL_INFO10000, "DS::TP: this:0x%p in %s::%s (fp:0x%p, " - "off:0x%p md:0x%p), \n\texception source:%s::%s (fp:0x%p)\n", + LOG((LF_CORDB, LL_INFO10000, "DS::TP: this:0x%p in %s::%s (fp:%p, " + "off:0x%zx md:0x%08x), \n\texception source:%s::%s (fp:%p)\n", this, info.m_activeFrame.md!=NULL?info.m_activeFrame.md->m_pszDebugClassName:"Unknown", info.m_activeFrame.md!=NULL?info.m_activeFrame.md->m_pszDebugMethodName:"Unknown", @@ -7639,7 +7639,7 @@ TP_RESULT DebuggerStepper::TriggerPatch(DebuggerControllerPatch *patch, { LOG((LF_CORDB, LL_INFO10000, - "Frame (stub) patch hit at offset 0x%x\n", offset)); + "Frame (stub) patch hit at offset 0x%zx\n", offset)); // This is a stub patch. If it was a TRACE_FRAME_PUSH that // got us here, then the stub's frame is pushed now, so we @@ -7741,12 +7741,12 @@ TP_RESULT DebuggerStepper::TriggerPatch(DebuggerControllerPatch *patch, SIZE_T offsetRet = dac_cast(traceManagerRetAddr - pcodeNative); LOG((LF_CORDB, LL_INFO10000, "DS::TP: Before normally managed code AddPatch" - " in %s::%s \n\tmd=0x%p, offset 0x%x, pcode=0x%p, dji=0x%p\n", + " in %s::%s \n\tmd=0x%p, offset 0x%zx, pcode=0x%p, dji=0x%p\n", mdNative->m_pszDebugClassName, mdNative->m_pszDebugMethodName, mdNative, offsetRet, - pcodeNative, + (void*)pcodeNative, dji)); // Place the patch. @@ -7793,7 +7793,7 @@ TP_RESULT DebuggerStepper::TriggerPatch(DebuggerControllerPatch *patch, } LOG((LF_CORDB, LL_INFO10000, - "Unmanaged step patch hit at 0x%x\n", offset)); + "Unmanaged step patch hit at 0x%zx\n", offset)); StackTraceTicket ticket(patch); PrepareForSendEvent(ticket); @@ -7816,7 +7816,7 @@ TP_RESULT DebuggerStepper::TriggerPatch(DebuggerControllerPatch *patch, // on the trace type == TRACE_UNJITTED_METHOD to identify this case. { PCODE currentPC = GetControlPC(&(info.m_activeFrame.registers)); - LOG((LF_CORDB, LL_INFO10000, "DS::TP: Checking stub at PC %p, IsStub=%d\n", currentPC, g_pEEInterface->IsStub((const BYTE*)currentPC))); + LOG((LF_CORDB, LL_INFO10000, "DS::TP: Checking stub at PC %p, IsStub=%d\n", (void*)currentPC, g_pEEInterface->IsStub((const BYTE*)currentPC))); if (g_pEEInterface->IsStub((const BYTE*)currentPC)) { LOG((LF_CORDB, LL_INFO10000, "DS::TP: IsStub=true, calling TraceStub\n")); @@ -7836,7 +7836,7 @@ TP_RESULT DebuggerStepper::TriggerPatch(DebuggerControllerPatch *patch, trace.GetTraceType() == TRACE_MGR_PUSH && trace.GetAddress() == currentPC) { - LOG((LF_CORDB, LL_INFO10000, "DS::TP: Got TRACE_MGR_PUSH at current IP: 0x%p, calling TraceManager\n", currentPC)); + LOG((LF_CORDB, LL_INFO10000, "DS::TP: Got TRACE_MGR_PUSH at current IP: 0x%p, calling TraceManager\n", (void*)currentPC)); CONTRACT_VIOLATION(GCViolation); PTR_BYTE traceManagerRetAddr = NULL; traceOk = g_pEEInterface->TraceManager( @@ -7870,7 +7870,7 @@ TP_RESULT DebuggerStepper::TriggerPatch(DebuggerControllerPatch *patch, ShouldContinueStep( &info, offset)) { LOG((LF_CORDB, LL_INFO10000, - "Intermediate step patch hit at 0x%x\n", offset)); + "Intermediate step patch hit at 0x%zx\n", offset)); if (!TrapStep(&info, m_stepIn)) TrapStepNext(&info); @@ -7880,7 +7880,7 @@ TP_RESULT DebuggerStepper::TriggerPatch(DebuggerControllerPatch *patch, } else { - LOG((LF_CORDB, LL_INFO10000, "Step patch hit at 0x%x\n", offset)); + LOG((LF_CORDB, LL_INFO10000, "Step patch hit at 0x%zx\n", offset)); // For a JMC stepper, we have an additional constraint: // skip non-user code. So if we're still in non-user code, then @@ -8138,7 +8138,7 @@ bool DebuggerStepper::TriggerSingleStep(Thread *thread, const BYTE *ip) void DebuggerStepper::TriggerTraceCall(Thread *thread, const BYTE *ip) { - LOG((LF_CORDB,LL_INFO10000,"DS::TTC this:0x%x, @ ip:0x%x\n",this,ip)); + LOG((LF_CORDB,LL_INFO10000,"DS::TTC this:0x%p, @ ip:0x%p\n",this,ip)); TraceDestination trace; if (IsFrozen()) @@ -8198,7 +8198,7 @@ void DebuggerStepper::TriggerUnwind(Thread *thread, LOG((LF_CORDB,LL_INFO10000,"DS::TU this:0x%p, in %s::%s, offset 0x%p " "frame:0x%p unwindReason:0x%x\n", this, fd->m_pszDebugClassName, - fd->m_pszDebugMethodName, offset, fp.GetSPValue(), unwindReason)); + fd->m_pszDebugMethodName, (void*)offset, fp.GetSPValue(), unwindReason)); _ASSERTE(unwindReason == STEP_EXCEPTION_FILTER || unwindReason == STEP_EXCEPTION_HANDLER); @@ -8293,7 +8293,7 @@ void DebuggerStepper::PrepareForSendEvent(StackTraceTicket ticket) m_fReadyToSend = true; #endif - LOG((LF_CORDB, LL_INFO10000, "DS::SE m_fpStepInto:0x%x\n", m_fpStepInto.GetSPValue())); + LOG((LF_CORDB, LL_INFO10000, "DS::SE m_fpStepInto:%p\n", m_fpStepInto.GetSPValue())); if (m_fpStepInto != LEAF_MOST_FRAME) { @@ -8306,12 +8306,12 @@ void DebuggerStepper::PrepareForSendEvent(StackTraceTicket ticket) { m_reason = STEP_CALL; - LOG((LF_CORDB, LL_INFO10000, "DS::SE this:0x%x STEP_CALL!\n", this)); + LOG((LF_CORDB, LL_INFO10000, "DS::SE this:0x%p STEP_CALL!\n", this)); } #ifdef _DEBUG else { - LOG((LF_CORDB, LL_INFO10000, "DS::SE this:0x%x not a step call!\n", this)); + LOG((LF_CORDB, LL_INFO10000, "DS::SE this:0x%p not a step call!\n", this)); } #endif } @@ -8360,7 +8360,7 @@ bool DebuggerStepper::SendEvent(Thread *thread, bool fIpChanged) // This is technically an issue, but we consider it benign enough to leave in. _ASSERTE(!fIpChanged || !"Stepper interrupted by SetIp"); - LOG((LF_CORDB, LL_INFO10000, "DS::SE m_fpStepInto:0x%x\n", m_fpStepInto.GetSPValue())); + LOG((LF_CORDB, LL_INFO10000, "DS::SE m_fpStepInto:%p\n", m_fpStepInto.GetSPValue())); _ASSERTE(m_fReadyToSend); _ASSERTE(GetThreadNULLOk() == thread); @@ -8502,7 +8502,7 @@ bool DebuggerJMCStepper::TrapStepInHelper( SIZE_T offset = CodeRegionInfo::GetCodeRegionInfo(dji, pDesc).AddressToOffset(ipNext); - LOG((LF_CORDB, LL_INFO100000, "DJMCStepper::TSIH, at '%s::%s', calling=%p, next=%p, offset=%d\n", + LOG((LF_CORDB, LL_INFO100000, "DJMCStepper::TSIH, at '%s::%s', calling=%p, next=%p, offset=%zu\n", pDesc->m_pszDebugClassName, pDesc->m_pszDebugMethodName, ipCallTarget, ipNext, diff --git a/src/runtime/src/coreclr/debug/ee/debugger.cpp b/src/runtime/src/coreclr/debug/ee/debugger.cpp index 9cddb5e4254a..b8b8a050302a 100644 --- a/src/runtime/src/coreclr/debug/ee/debugger.cpp +++ b/src/runtime/src/coreclr/debug/ee/debugger.cpp @@ -2357,7 +2357,7 @@ void Debugger::JITComplete(NativeCodeVersion nativeCodeVersion, TADDR newAddress MethodDesc* fd = nativeCodeVersion.GetMethodDesc(); LOG((LF_CORDB, LL_INFO100000, "D::JITComplete: md:%p (%s::%s), address:%p.\n", - fd, fd->m_pszDebugClassName, fd->m_pszDebugMethodName, newAddress)); + fd, fd->m_pszDebugClassName, fd->m_pszDebugMethodName, (void*)newAddress)); #ifdef TARGET_ARM newAddress = newAddress|THUMB_CODE; @@ -2392,12 +2392,12 @@ void Debugger::JITComplete(NativeCodeVersion nativeCodeVersion, TADDR newAddress // return the same code pointer and this callback is invoked // multiple times. LOG((LF_CORDB, LL_INFO1000000, "D::JITComplete: md:%p (%s::%s), address:%p. Already created\n", - fd, fd->m_pszDebugClassName, fd->m_pszDebugMethodName, newAddress)); + fd, fd->m_pszDebugClassName, fd->m_pszDebugMethodName, (void*)newAddress)); goto Exit; } LOG((LF_CORDB, LL_INFO1000000, "D::JITComplete: md:%p (%s::%s), address:%p. Created dji:%p\n", - fd, fd->m_pszDebugClassName, fd->m_pszDebugMethodName, newAddress, dji)); + fd, fd->m_pszDebugClassName, fd->m_pszDebugMethodName, (void*)newAddress, dji)); // Bind any IL patches to the newly jitted native code. HRESULT hr; @@ -2598,7 +2598,7 @@ DebuggerJitInfo *Debugger::GetJitInfoWorker(MethodDesc *fd, const BYTE *pbAddr, if(trace.GetTraceType() == TRACE_MANAGED && (PCODE)pbAddr != trace.GetAddress()) { startAddr = trace.GetAddress(); - LOG((LF_CORDB,LL_INFO1000,"D::GJIW: Address thru thunk: 0x%p\n", startAddr)); + LOG((LF_CORDB,LL_INFO1000,"D::GJIW: Address thru thunk: 0x%p\n", (void*)startAddr)); } #ifdef LOGGING else @@ -3459,7 +3459,7 @@ HRESULT Debugger::SetIP( bool fCanSetIPOnly, Thread *thread,Module *module, { offsetNatTo = offsetILTo; LOG((LF_CORDB, LL_INFO1000, "D::SIP:Dest of 0x%p (via native " - "offset) is fine!\n", offsetNatTo)); + "offset) is fine!\n", (void*)offsetNatTo)); } CorDebugMappingResult mapping; @@ -3492,13 +3492,13 @@ HRESULT Debugger::SetIP( bool fCanSetIPOnly, Thread *thread,Module *module, // Once we finally have a native offset, it had better be in range. if (offsetNatTo >= dwSize) { - LOG((LF_CORDB, LL_INFO1000, "D::SIP:Code out of range! offsetNatTo = 0x%x, dwSize=0x%x\n", offsetNatTo, dwSize)); + LOG((LF_CORDB, LL_INFO1000, "D::SIP:Code out of range! offsetNatTo = 0x%zx, dwSize=0x%x\n", offsetNatTo, dwSize)); hrAdvise = E_INVALIDARG; goto LExit; } pbDest = CodeRegionInfo::GetCodeRegionInfo(dji).OffsetToAddress(offsetNatTo); - LOG((LF_CORDB, LL_INFO1000, "D::SIP:Dest is 0x%p\n", pbDest)); + LOG((LF_CORDB, LL_INFO1000, "D::SIP:Dest is 0x%p\n", (void*)pbDest)); // Don't allow SetIP if the source or target is cold (SetIPFromSrcToDst does not // correctly handle this case). @@ -3520,7 +3520,7 @@ HRESULT Debugger::SetIP( bool fCanSetIPOnly, Thread *thread,Module *module, &pVCs); LOG((LF_CORDB|LF_ENC, LL_INFO10000, - "D::SIP: rgVal1 0x%X, rgVal2 0x%X\n", + "D::SIP: rgVal1 0x%p, rgVal2 0x%p\n", rgVal1, rgVal2)); @@ -3613,7 +3613,7 @@ HRESULT Debugger::SetIP( bool fCanSetIPOnly, Thread *thread,Module *module, ::SetIP(pCtx, pbDest); - LOG((LF_CORDB, LL_INFO1000, "D::SIP:Set IP to be 0x%p\n", GetIP(pCtx))); + LOG((LF_CORDB, LL_INFO1000, "D::SIP:Set IP to be 0x%p\n", (void*)GetIP(pCtx))); } @@ -3706,7 +3706,7 @@ HRESULT Debugger::ShuffleVariablesGet(DebuggerJitInfo *dji, LOG((LF_CORDB|LF_ENC, LL_INFO10000, - "D::SVG cVariables %d, hiddens %d, rgVal1 0x%X, rgVal2 0x%X\n", + "D::SVG cVariables %d, hiddens %d, rgVal1 0x%p, rgVal2 0x%p\n", cVariables, unsigned(-ICorDebugInfo::UNKNOWN_ILNUM), rgVal1, @@ -3770,7 +3770,7 @@ HRESULT Debugger::ShuffleVariablesSet(DebuggerJitInfo *dji, LOG((LF_CORDB|LF_ENC, LL_INFO10000, - "D::SVS: rgVal1 0x%X, rgVal2 0x%X\n", + "D::SVS: rgVal1 0x%p, rgVal2 0x%p\n", (*prgVal1), (*prgVal2))); @@ -3785,7 +3785,7 @@ HRESULT Debugger::ShuffleVariablesSet(DebuggerJitInfo *dji, LOG((LF_CORDB|LF_ENC, LL_INFO100000, - "D::SVS deleting rgVal1 0x%X, rgVal2 0x%X\n", + "D::SVS deleting rgVal1 0x%p, rgVal2 0x%p\n", (*prgVal1), (*prgVal2))); @@ -4007,7 +4007,7 @@ GetSetFrameHelper::Init(MethodDesc *pMD) m_rgSize[i] = GetSetFrameHelper::GetSizeOfElement(m_rgElemType[i]); } - LOG((LF_CORDB, LL_INFO10000, "GSFH::I: var 0x%x is of type %x, size:0x%x\n", + LOG((LF_CORDB, LL_INFO10000, "GSFH::I: var 0x%x is of type %x, size:0x%zx\n", i, m_rgElemType[i], m_rgSize[i])); } } @@ -4303,7 +4303,7 @@ HRESULT Debugger::GetVariablesFromOffset(MethodDesc *pMD, pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName, varNativeInfoCount, - offsetFrom)); + (void*)offsetFrom)); GetSetFrameHelper frameHelper; HRESULT hr = frameHelper.Init(pMD); @@ -4412,7 +4412,7 @@ HRESULT Debugger::GetVariablesFromOffset(MethodDesc *pMD, cValueClasses++; #ifdef _DEBUG LOG((LF_CORDB|LF_ENC,LL_INFO10000, - "D::GVFO [%2u] varnum %d, VC len %d, addr %p, sample: %8.8x%8.8x\n", + "D::GVFO [%2u] varnum %u, VC len %zu, addr %p, sample: %8.8x%8.8x\n", i, varNativeInfo[i].varNumber, cbClass, @@ -4470,7 +4470,7 @@ HRESULT Debugger::SetVariablesAtOffset(MethodDesc *pMD, pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName, varNativeInfoCount, - offsetTo)); + (void*)offsetTo)); if (varNativeInfoCount == 0) { @@ -4523,7 +4523,7 @@ HRESULT Debugger::SetVariablesAtOffset(MethodDesc *pMD, BIT64_ARG(cbClass)); LOG((LF_CORDB|LF_ENC,LL_INFO10000, - "D::SVAO [%2d] varnum %d, nonVC type %x, addr %8.8x: %8.8x;%8.8x\n", + "D::SVAO [%2d] varnum %u, nonVC type %d, addr %p: %8.8zx;%8.8zx\n", i, varNativeInfo[i].varNumber, varNativeInfo[i].loc.vlType, @@ -4546,7 +4546,7 @@ HRESULT Debugger::SetVariablesAtOffset(MethodDesc *pMD, { // it's new in scope, so just clear it memset(NativeVarStackAddr(varNativeInfo[i].loc, pCtx), 0, cbClass); - LOG((LF_CORDB|LF_ENC,LL_INFO10000, "D::SVAO [%2d] varnum %d, new VC len %d, addr %8.8x\n", + LOG((LF_CORDB|LF_ENC,LL_INFO10000, "D::SVAO [%2d] varnum %u, new VC len %zu, addr %p\n", i, varNativeInfo[i].varNumber, cbClass, @@ -4557,7 +4557,7 @@ HRESULT Debugger::SetVariablesAtOffset(MethodDesc *pMD, memmove(NativeVarStackAddr(varNativeInfo[i].loc, pCtx), rgpVCs[iVC], cbClass); #ifdef _DEBUG LOG((LF_CORDB|LF_ENC,LL_INFO10000, - "D::SVAO [%2d] varnum %d, VC len %d, addr: %8.8x sample: %8.8x%8.8x\n", + "D::SVAO [%2d] varnum %u, VC len %zu, addr: %p sample: %8.8x%8.8x\n", i, varNativeInfo[i].varNumber, cbClass, @@ -5055,7 +5055,7 @@ DebuggerModule* Debugger::AddDebuggerModule(Assembly * pAssembly) } CONTRACTL_END; - LOG((LF_CORDB, LL_INFO1000, "D::ADM asm=0x%x\n", pAssembly)); + LOG((LF_CORDB, LL_INFO1000, "D::ADM asm=0x%p\n", pAssembly)); DebuggerDataLockHolder chInfo(this); Module * pRuntimeModule = pAssembly->GetModule(); @@ -5072,7 +5072,7 @@ DebuggerModule* Debugger::AddDebuggerModule(Assembly * pAssembly) // @dbgtodo inspection/exceptions - this may leak module in OOM case. LS is not OOM resilient; and we // expect to get rid of DebuggerModule anyways. - LOG((LF_CORDB, LL_INFO1000, "D::ADM asm=0x%x -> dm=0x%x\n", pAssembly, pModule)); + LOG((LF_CORDB, LL_INFO1000, "D::ADM asm=0x%p -> dm=0x%p\n", pAssembly, pModule)); return pModule; } @@ -5208,7 +5208,7 @@ void Debugger::ReleaseAllRuntimeThreads(AppDomain *pAppDomain) pAppDomain = NULL; STRESS_LOG1(LF_CORDB, LL_INFO10000, "D::RART: Releasing all Runtime threads " - "for AppD 0x%x.\n", pAppDomain); + "for AppD 0x%p.\n", pAppDomain); // Mark that we're on our way now... m_trappingRuntimeThreads = FALSE; @@ -5787,7 +5787,7 @@ void Debugger::SendBreakpoint(Thread *thread, CONTEXT *context, } #endif - LOG((LF_CORDB, LL_INFO10000, "D::SB: breakpoint BP:0x%x\n", breakpoint)); + LOG((LF_CORDB, LL_INFO10000, "D::SB: breakpoint BP:0x%p\n", breakpoint)); _ASSERTE((g_pEEInterface->GetThread() && !g_pEEInterface->GetThread()->m_fPreemptiveGCDisabled)); @@ -5986,8 +5986,10 @@ void Debugger::LockAndSendEnCRemapEvent(DebuggerJitInfo * dji, SIZE_T currentIP, ipce->EnCRemap.resumeILOffset = PTR_TO_CORDB_ADDRESS(resumeIP); ipce->EnCRemap.funcMetadataToken = pMD->GetMemberDef(); - LOG((LF_CORDB, LL_INFO10000, "D::LASEnCRE: methodDef 0x%x, from version %zx to %zx\n", - ipce->EnCRemap.funcMetadataToken, ipce->EnCRemap.currentVersionNumber, ipce->EnCRemap.resumeVersionNumber)); + LOG((LF_CORDB, LL_INFO10000, "D::LASEnCRE: methodDef 0x%x, from version %llx to %llx\n", + static_cast(ipce->EnCRemap.funcMetadataToken), + static_cast(ipce->EnCRemap.currentVersionNumber), + static_cast(ipce->EnCRemap.resumeVersionNumber))); Module *pRuntimeModule = pMD->GetModule(); @@ -6041,7 +6043,7 @@ void Debugger::LockAndSendEnCRemapCompleteEvent(MethodDesc *pMD) LOG((LF_CORDB, LL_INFO10000, "D::LASEnCRE: %s::%s dmod:%p, methodDef:0x%08x \n", pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName, pDModule, - ipce->EnCRemap.funcMetadataToken)); + static_cast(ipce->EnCRemapComplete.funcMetadataToken))); // IPC event is now initialized, so we can send it over. SendSimpleIPCEventAndBlock(); @@ -8154,7 +8156,7 @@ void Debugger::ExceptionFilter(MethodDesc *fd, TADDR pMethodAddr, SIZE_T offset, } CONTRACTL_END; - LOG((LF_CORDB,LL_INFO10000, "D::EF: pStack:0x%x MD: %s::%s, offset:0x%x\n", + LOG((LF_CORDB,LL_INFO10000, "D::EF: pStack:0x%p MD: %s::%s, offset:0x%zx\n", pStack, fd->m_pszDebugClassName, fd->m_pszDebugMethodName, offset)); // @@ -8841,8 +8843,8 @@ void Debugger::ThreadStarted(Thread* pRuntimeThread) } pRuntimeThread->SetThreadStateNC(Thread::TSNC_DebuggerThreadStartSent); - LOG((LF_CORDB, LL_INFO100, "D::TS: thread attach : ID=%#x AD:%#x\n", - GetThreadIdHelper(pRuntimeThread), AppDomain::GetCurrentDomain())); + LOG((LF_CORDB, LL_INFO100, "D::TS: thread attach : ID=%#x AD:%p\n", + GetThreadIdHelper(pRuntimeThread), static_cast(AppDomain::GetCurrentDomain()))); // We just need to send a VMPTR_Thread. The RS will get everything else it needs from DAC. // @@ -8942,7 +8944,7 @@ void Debugger::DetachThread(Thread *pRuntimeThread) _ASSERTE (pRuntimeThread != NULL); - LOG((LF_CORDB, LL_INFO100, "D::DT: thread detach : ID=%#x AD:%#x.\n", + LOG((LF_CORDB, LL_INFO100, "D::DT: thread detach : ID=%#x AD:%p.\n", GetThreadIdHelper(pRuntimeThread), AppDomain::GetCurrentDomain())); @@ -9101,7 +9103,7 @@ void Debugger::AppDomainCreated(AppDomain * pRuntimeAppDomain) return; } - STRESS_LOG1(LF_CORDB, LL_INFO10000, "D::SCADE: AppDomain creation:%#08x\n", + STRESS_LOG1(LF_CORDB, LL_INFO10000, "D::SCADE: AppDomain creation:%p\n", pRuntimeAppDomain); @@ -9324,7 +9326,7 @@ void Debugger::SendUpdateModuleSymsEventAndBlock(Module* pRuntimeModule) } CGrowableStream * pStream = pRuntimeModule->GetInMemorySymbolStream(); - LOG((LF_CORDB, LL_INFO10000, "D::UMS: update module syms RuntimeModule:0x%08x CGrowableStream:0x%08x\n", pRuntimeModule, pStream)); + LOG((LF_CORDB, LL_INFO10000, "D::UMS: update module syms RuntimeModule:0x%p CGrowableStream:0x%p\n", pRuntimeModule, pStream)); if (pStream == NULL) { // No in-memory Pdb available. @@ -9365,7 +9367,7 @@ void Debugger::UnloadModule(Module* pRuntimeModule) if (CORDBUnrecoverableError(this)) return; - LOG((LF_CORDB, LL_INFO100, "D::UM: unload module Mod:%#08x runtimeMod:%#08x modName:%s\n", + LOG((LF_CORDB, LL_INFO100, "D::UM: unload module Mod:%p runtimeMod:%p modName:%s\n", LookupOrCreateModule(pRuntimeModule), pRuntimeModule, pRuntimeModule->GetDebugName())); Thread *thread = g_pEEInterface->GetThread(); @@ -9376,14 +9378,14 @@ void Debugger::UnloadModule(Module* pRuntimeModule) DebuggerModule* module = LookupOrCreateModule(pRuntimeModule); if (module == NULL) { - LOG((LF_CORDB, LL_INFO100, "D::UM: module already unloaded runtimeMod:%#08x modName:%s\n", + LOG((LF_CORDB, LL_INFO100, "D::UM: module already unloaded runtimeMod:%p modName:%s\n", pRuntimeModule, pRuntimeModule->GetDebugName())); goto LExit; } _ASSERTE(module != NULL); STRESS_LOG6(LF_CORDB, LL_INFO10000, - "D::UM: Unloading RTMod:%#08x (DomFile: %#08x, IsISStream:%#08x); DMod:%#08x(RTMod:%#08x DomFile: %#08x)\n", + "D::UM: Unloading RTMod:%p (DomFile: %p, IsISStream:%#08x); DMod:%p(RTMod:%p DomFile: %p)\n", pRuntimeModule, pRuntimeModule->GetAssembly(), false, module, module->GetRuntimeModule(), module->GetAssembly()); @@ -9457,7 +9459,7 @@ void Debugger::DestructModule(Module *pModule) } CONTRACTL_END; - LOG((LF_CORDB, LL_INFO100, "D::DM: destruct module runtimeMod:%#08x modName:%s\n", + LOG((LF_CORDB, LL_INFO100, "D::DM: destruct module runtimeMod:%p modName:%s\n", pModule, pModule->GetDebugName())); // @@@ @@ -9538,7 +9540,7 @@ void Debugger::SendClassLoadUnloadEvent (mdTypeDef classMetadataToken, CONTRACTL_END; - LOG((LF_CORDB,LL_INFO10000, "D::SCLUE: Tok:0x%x isLoad:0x%x Mod:%#08x\n", + LOG((LF_CORDB,LL_INFO10000, "D::SCLUE: Tok:0x%08x isLoad:0x%x Mod:%p\n", classMetadataToken, fIsLoadEvent, pClassDebuggerModule)); DebuggerIPCEvent * pEvent = m_pRCThread->GetIPCEventSendBuffer(); @@ -9655,7 +9657,7 @@ BOOL Debugger::LoadClass(TypeHandle th, if (CORDBUnrecoverableError(this)) return FALSE; - LOG((LF_CORDB, LL_INFO10000, "D::LC: load class Tok:%#08x Mod:%#08x classMod:%#08x modName:%s\n", + LOG((LF_CORDB, LL_INFO10000, "D::LC: load class Tok:%#08x Mod:%p classMod:%p modName:%s\n", classMetadataToken, LookupOrCreateModule(classModule), classModule, classModule->GetDebugName())); @@ -9709,7 +9711,7 @@ void Debugger::UnloadClass(mdTypeDef classMetadataToken, return; } - LOG((LF_CORDB, LL_INFO10000, "D::UC: unload class Tok:0x%08x Mod:%#08x \runtimeMod:%#08x modName:%s\n", + LOG((LF_CORDB, LL_INFO10000, "D::UC: unload class Tok:0x%08x Mod:%p runtimeMod:%p modName:%s\n", classMetadataToken, LookupOrCreateModule(classModule), classModule, classModule->GetDebugName())); Assembly *pAssembly = classModule->GetClassLoader()->GetAssembly(); @@ -9796,7 +9798,8 @@ void Debugger::FuncEvalComplete(Thread* pThread, DebuggerEval *pDE) GetSizeForCorElementType(ipce->FuncEvalComplete.resultType.elementType))); LOG((LF_CORDB, LL_INFO1000, "D::FEC: returned el %04x resultAddr %p\n", - ipce->FuncEvalComplete.resultType.elementType, (CORDB_ADDRESS_TO_PTR(ipce->FuncEvalComplete.resultAddr)))); + static_cast(ipce->FuncEvalComplete.resultType.elementType), + (CORDB_ADDRESS_TO_PTR(ipce->FuncEvalComplete.resultAddr)))); m_pRCThread->SendIPCEvent(); @@ -10283,11 +10286,11 @@ bool Debugger::HandleIPCEvent(DebuggerIPCEvent * pEvent) } LOG((LF_CORDB,LL_INFO10000,"\tBP Add: BPTOK:" - "0x%x, tok=0x%08x, offset=0x%x, isIL=%d dm=0x%x m=0x%x\n", + "0x%p, tok=0x%08x, offset=0x%x, isIL=%d dm=0x%p m=0x%p\n", pDebuggerBP, - pEvent->BreakpointData.funcMetadataToken, - pEvent->BreakpointData.offset, - pEvent->BreakpointData.isIL, + static_cast(pEvent->BreakpointData.funcMetadataToken), + static_cast(pEvent->BreakpointData.offset), + static_cast(pEvent->BreakpointData.isIL), pDebuggerModule, pModule)); @@ -10318,9 +10321,9 @@ bool Debugger::HandleIPCEvent(DebuggerIPCEvent * pEvent) CORDB_ADDRESS_TO_PTR(pEvent->StepData.frameToken), (pEvent->StepData.stepIn ? "true" : "false"), (pEvent->StepData.rangeIL ? "true" : "false"), - pEvent->StepData.rangeCount, - pEvent->StepData.rgfMappingStop, - pEvent->StepData.rgfInterceptStop, + static_cast(pEvent->StepData.rangeCount), + static_cast(pEvent->StepData.rgfMappingStop), + static_cast(pEvent->StepData.rgfInterceptStop), pEvent->vmAppDomain.GetRawPtr())); // @todo memory allocation - bad if we're synced @@ -10481,7 +10484,7 @@ bool Debugger::HandleIPCEvent(DebuggerIPCEvent * pEvent) Thread * pThread = pEvent->SetAllDebugState.vmThreadToken.GetRawPtr(); CorDebugThreadState debugState = pEvent->SetAllDebugState.debugState; - LOG((LF_CORDB,LL_INFO10000,"HandleIPCE: SetAllDebugState: except thread 0x%08x (ID:0x%x) to state 0x%x\n", + LOG((LF_CORDB,LL_INFO10000,"HandleIPCE: SetAllDebugState: except thread 0x%p (ID:0x%x) to state 0x%x\n", pThread, (pThread != NULL) ? GetThreadIdHelper(pThread) : 0, debugState)); @@ -11027,7 +11030,7 @@ bool Debugger::HandleIPCEvent(DebuggerIPCEvent * pEvent) SUPPRESS_ALLOCATION_ASSERTS_IN_THIS_SCOPE; Module * pModule = pEvent->MetadataUpdateRequest.vmModule.GetRawPtr(); - LOG((LF_CORDB, LL_INFO100000, "D::HIPCE Got module 0x%x\n", pModule)); + LOG((LF_CORDB, LL_INFO100000, "D::HIPCE Got module 0x%p\n", pModule)); DWORD countBytes = 0; @@ -11050,7 +11053,7 @@ bool Debugger::HandleIPCEvent(DebuggerIPCEvent * pEvent) pResult->MetadataUpdateRequest.pMetadataStart = PTR_TO_CORDB_ADDRESS(pData); pResult->MetadataUpdateRequest.nMetadataSize = countBytes; pResult->hr = hr; - LOG((LF_CORDB, LL_INFO1000000, "D::HIPCE metadataStart=0x%x, nMetadataSize=0x%x\n", pData, countBytes)); + LOG((LF_CORDB, LL_INFO1000000, "D::HIPCE metadataStart=0x%p, nMetadataSize=0x%x\n", pData, countBytes)); m_pRCThread->SendIPCReply(); LOG((LF_CORDB, LL_INFO1000000, "D::HIPCE reply sent\n")); @@ -11075,7 +11078,7 @@ bool Debugger::HandleIPCEvent(DebuggerIPCEvent * pEvent) // We should never get an event that we don't know about. CONSISTENCY_CHECK_MSGF(false, ("Unknown Debug-Event on LS:id=0x%08x.", pEvent->type)); LOG((LF_CORDB, LL_INFO10000, "Unknown event type: 0x%08x\n", - pEvent->type)); + static_cast(pEvent->type))); } STRESS_LOG0(LF_CORDB, LL_INFO10000, "D::HIPCE: finished handling event\n"); @@ -11574,7 +11577,7 @@ void Debugger::TypeHandleToExpandedTypeInfo(AreValueTypesBoxed boxed, } break; } - LOG((LF_CORDB, LL_INFO10000, "D::THTETI: converted left-side type handle to expanded right-side type info, res->ClassTypeData.typeHandle = 0x%08x.\n", res->ClassTypeData.typeHandle.GetRawPtr())); + LOG((LF_CORDB, LL_INFO10000, "D::THTETI: converted left-side type handle to expanded right-side type info, res->ClassTypeData.typeHandle = 0x%p.\n", res->ClassTypeData.typeHandle.GetRawPtr())); } @@ -11587,7 +11590,9 @@ HRESULT Debugger::BasicTypeInfoToTypeHandle(DebuggerIPCE_BasicTypeData *data, Ty } CONTRACTL_END; - LOG((LF_CORDB, LL_INFO10000, "D::BTITTH: expanding basic right-side type to left-side type, ELEMENT_TYPE: %d.\n", data->elementType)); + LOG((LF_CORDB, LL_INFO10000, + "D::BTITTH: expanding basic right-side type to left-side type, ELEMENT_TYPE: %d.\n", + static_cast(data->elementType))); *pRes = TypeHandle(); TypeHandle th; switch (data->elementType) @@ -11679,7 +11684,9 @@ TypeHandle Debugger::TypeDataWalk::ReadTypeHandle() if (!data) COMPlusThrow(kArgumentException, W("Argument_InvalidGenericArg")); - LOG((LF_CORDB, LL_INFO10000, "D::ETITTH: expanding right-side type to left-side type, ELEMENT_TYPE: %d.\n", data->data.elementType)); + LOG((LF_CORDB, LL_INFO10000, + "D::ETITTH: expanding right-side type to left-side type, ELEMENT_TYPE: %d.\n", + static_cast(data->data.elementType))); TypeHandle th; CorElementType et = data->data.elementType; @@ -11754,7 +11761,7 @@ void Debugger::GetAndSendTransitionStubInfo(CORDB_ADDRESS_TYPE *stubAddress) } CONTRACTL_END; - LOG((LF_CORDB, LL_INFO10000, "D::GASTSI: IsTransitionStub. Addr=0x%08x\n", stubAddress)); + LOG((LF_CORDB, LL_INFO10000, "D::GASTSI: IsTransitionStub. Addr=0x%p\n", stubAddress)); bool result = false; @@ -11827,7 +11834,7 @@ HRESULT Debugger::AllocateRemoteBuffer( ULONG bufSize, void **ppBuffer ) // Actually allocate the buffer BYTE* pBuffer = new (interopsafe, nothrow) BYTE[bufSize]; - LOG((LF_CORDB, LL_EVERYTHING, "D::ARB: new'd 0x%x\n", *ppBuffer)); + LOG((LF_CORDB, LL_EVERYTHING, "D::ARB: new'd 0x%p\n", *ppBuffer)); // Check for out of memory error if (pBuffer == NULL) @@ -12826,7 +12833,7 @@ HRESULT Debugger::AddFunction(MethodDesc* pMD, SIZE_T encVersion) DebuggerDataLockHolder debuggerDataLockHolder(this); LOG((LF_CORDB, LL_INFO10000, "D::AF: adding " - "%s::%s to version %d\n", pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName, encVersion)); + "%s::%s to version %zu\n", pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName, encVersion)); _ASSERTE(pMD != NULL); Module *pModule = g_pEEInterface->MethodDescGetModule(pMD); @@ -12954,7 +12961,7 @@ HRESULT Debugger::MapILInfoToCurrentNative(MethodDesc *pMD, _ASSERTE(HasLazyData()); // only used for EnC, should have already inited. LOG((LF_CORDB, LL_INFO1000000, "D::MILITCN: %s::%s ilOff:0x%zx, natFnx:%p\n", - pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName, ilOffset, nativeFnxStart)); + pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName, ilOffset, (void*)nativeFnxStart)); *nativeOffset = 0; DebuggerJitInfo *djiTo = GetJitInfo( pMD, (const BYTE *)nativeFnxStart); @@ -13872,7 +13879,7 @@ Debugger::InsertToMethodInfoList( DebuggerMethodInfo *dmi ) dmi, FALSE); - LOG((LF_CORDB,LL_INFO10000,"D:IAHOL: DMI version 0x%04x for token 0x%08x\n", + LOG((LF_CORDB,LL_INFO10000,"D:IAHOL: DMI version 0x%04zx for token 0x%08x\n", dmi->GetCurrentEnCVersion(),dmi->m_token)); } else @@ -14262,7 +14269,7 @@ HRESULT Debugger::FuncEvalSetup(DebuggerIPCE_FuncEvalInfo *pEvalInfo, // will show a wrong IP, so it shouldn't be done. *debuggerEvalKey = pDE; - LOG((LF_CORDB, LL_INFO100000, "D:FES for pDE:%08x evalType:%d on thread %#x, id=0x%x\n", + LOG((LF_CORDB, LL_INFO100000, "D:FES for pDE:%p evalType:%d on thread %p, id=0x%x\n", pDE, pDE->m_evalType, pThread, GetThreadIdHelper(pThread))); return S_OK; @@ -14306,7 +14313,7 @@ Debugger::FuncEvalAbort( pDE->m_aborting = DebuggerEval::FE_ABORT_NORMAL; LOG((LF_CORDB, LL_INFO1000, - "D::FEA: performing UserAbort on thread %#x, id=0x%x\n", + "D::FEA: performing UserAbort on thread %p, id=0x%x\n", pDE->m_thread, GetThreadIdHelper(pDE->m_thread))); if (!IsAtProcessExit() && !pDE->m_completed) @@ -14373,7 +14380,7 @@ Debugger::FuncEvalRudeAbort( pDE->m_aborting = (DebuggerEval::FUNC_EVAL_ABORT_TYPE)(pDE->m_aborting | DebuggerEval::FE_ABORT_RUDE); LOG((LF_CORDB, LL_INFO1000, - "D::FEA: performing RudeAbort on thread %#x, id=0x%x\n", + "D::FEA: performing RudeAbort on thread %p, id=0x%x\n", pDE->m_thread, Debugger::GetThreadIdHelper(pDE->m_thread))); if (!IsAtProcessExit() && !pDE->m_completed) @@ -14416,7 +14423,7 @@ HRESULT Debugger::FuncEvalCleanup(DebuggerEval *debuggerEvalKey) _ASSERTE(pDE->m_completed); - LOG((LF_CORDB, LL_INFO1000, "D::FEC: pDE:%08x 0x%08x, id=0x%x\n", + LOG((LF_CORDB, LL_INFO1000, "D::FEC: pDE:%p 0x%p, id=0x%x\n", pDE, pDE->m_thread, GetThreadIdHelper(pDE->m_thread))); DeleteInteropSafeExecutable(pDE->m_bpInfoSegment); @@ -14783,7 +14790,7 @@ HRESULT Debugger::NameChangeEvent(AppDomain *pAppDomain, Thread *pThread) } } - LOG((LF_CORDB, LL_INFO1000, "D::NCE: Sending NameChangeEvent 0x%x 0x%x\n", + LOG((LF_CORDB, LL_INFO1000, "D::NCE: Sending NameChangeEvent 0x%p 0x%p\n", pAppDomain, pThread)); Thread *curThread = g_pEEInterface->GetThread(); diff --git a/src/runtime/src/coreclr/debug/ee/debugger.h b/src/runtime/src/coreclr/debug/ee/debugger.h index 120bf42009c7..d5341b4f68fe 100644 --- a/src/runtime/src/coreclr/debug/ee/debugger.h +++ b/src/runtime/src/coreclr/debug/ee/debugger.h @@ -1507,7 +1507,7 @@ class DebuggerJitInfo " m_lastIL: 0x%x\n" " m_sequenceMapCount: %u\n", this, (m_jitComplete ? "true" : "false"), encState, - m_methodInfo, m_addrOfCode, m_sizeOfCode, m_lastIL, m_sequenceMapCount)); + m_methodInfo, (void*)m_addrOfCode, m_sizeOfCode, m_lastIL, m_sequenceMapCount)); #endif //LOGGING } diff --git a/src/runtime/src/coreclr/debug/ee/debugger.inl b/src/runtime/src/coreclr/debug/ee/debugger.inl index f966fe314b30..02505d5070f2 100644 --- a/src/runtime/src/coreclr/debug/ee/debugger.inl +++ b/src/runtime/src/coreclr/debug/ee/debugger.inl @@ -57,7 +57,7 @@ inline DebuggerModule::DebuggerModule(Module * pRuntimeModule, m_pRuntimeModule(pRuntimeModule), m_pRuntimeAssembly(pAssembly) { - LOG((LF_CORDB,LL_INFO10000, "DM::DM this:0x%x Module:0x%x Asm:0x%x\n", + LOG((LF_CORDB,LL_INFO10000, "DM::DM this:%p Module:%p Asm:%p\n", this, pRuntimeModule, pAssembly)); // Dynamic modules must receive ClassLoad callbacks in order to receive metadata updates as the module diff --git a/src/runtime/src/coreclr/debug/ee/debuggermodule.cpp b/src/runtime/src/coreclr/debug/ee/debuggermodule.cpp index 11b4cc59c70b..f8f495aa85ad 100644 --- a/src/runtime/src/coreclr/debug/ee/debuggermodule.cpp +++ b/src/runtime/src/coreclr/debug/ee/debuggermodule.cpp @@ -99,7 +99,7 @@ void DebuggerModuleTable::AddModule(DebuggerModule *pModule) _ASSERTE(pModule != NULL); - LOG((LF_CORDB, LL_EVERYTHING, "DMT::AM: DebuggerMod:0x%x Module:0x%x\n", + LOG((LF_CORDB, LL_EVERYTHING, "DMT::AM: DebuggerMod:%p Module:%p\n", pModule, pModule->GetRuntimeModule())); DebuggerModuleEntry * pEntry = (DebuggerModuleEntry *) Add(HASH(pModule->GetRuntimeModule())); @@ -124,7 +124,7 @@ void DebuggerModuleTable::RemoveModule(Module* pModule) } CONTRACTL_END; - LOG((LF_CORDB, LL_INFO1000, "DMT::RM Attempting to remove Module:0x%x\n", pModule)); + LOG((LF_CORDB, LL_INFO1000, "DMT::RM Attempting to remove Module:%p\n", pModule)); _ASSERTE(ThreadHoldsLock()); _ASSERTE(pModule != NULL); @@ -140,7 +140,7 @@ void DebuggerModuleTable::RemoveModule(Module* pModule) if (pRuntimeModule == pModule) { - LOG((LF_CORDB, LL_INFO1000, "DMT::RM Removing DebuggerMod:0x%x - Module:0x%x DF:0x%x\n", + LOG((LF_CORDB, LL_INFO1000, "DMT::RM Removing DebuggerMod:%p - Module:%p Asm:%p\n", pDM, pModule, pDM->GetAssembly())); TRACE_FREE(pDM); DeleteInteropSafe(pDM); @@ -150,7 +150,7 @@ void DebuggerModuleTable::RemoveModule(Module* pModule) } } - LOG((LF_CORDB, LL_INFO1000, "DMT::RM No debugger module found for Module:0x%x\n", pModule)); + LOG((LF_CORDB, LL_INFO1000, "DMT::RM No debugger module found for Module:%p\n", pModule)); } diff --git a/src/runtime/src/coreclr/debug/ee/executioncontrol.cpp b/src/runtime/src/coreclr/debug/ee/executioncontrol.cpp index 4855b45ac8df..2f156d3ee1a9 100644 --- a/src/runtime/src/coreclr/debug/ee/executioncontrol.cpp +++ b/src/runtime/src/coreclr/debug/ee/executioncontrol.cpp @@ -52,8 +52,8 @@ bool InterpreterExecutionControl::ApplyPatch(DebuggerControllerPatch* patch) patch->opcode = currentOpcode; // Save original opcode patch->m_interpActivated = true; // Mark as activated (needed since opcode 0 is valid for interpreter) *(uint32_t*)patch->address = INTOP_BREAKPOINT; - LOG((LF_CORDB, LL_INFO10000, "InterpreterEC::ApplyPatch Breakpoint inserted at %p, saved opcode 0x%x\n", - patch->address, patch->opcode)); + LOG((LF_CORDB, LL_INFO10000, "InterpreterEC::ApplyPatch Breakpoint inserted at %p, saved opcode 0x%zx\n", + patch->address, (size_t)patch->opcode)); return true; } @@ -64,8 +64,8 @@ bool InterpreterExecutionControl::UnapplyPatch(DebuggerControllerPatch* patch) _ASSERTE(patch->address != NULL); _ASSERTE(patch->IsActivated()); - LOG((LF_CORDB, LL_INFO1000, "InterpreterEC::UnapplyPatch %p at bytecode addr %p, replacing with original opcode 0x%x\n", - patch, patch->address, patch->opcode)); + LOG((LF_CORDB, LL_INFO1000, "InterpreterEC::UnapplyPatch %p at bytecode addr %p, replacing with original opcode 0x%zx\n", + patch, patch->address, (size_t)patch->opcode)); // Restore the original opcode *(uint32_t*)patch->address = (uint32_t)patch->opcode; // Opcodes are stored in uint32_t slots @@ -88,8 +88,8 @@ void InterpreterExecutionControl::BypassPatch(DebuggerControllerPatch* patch, Th pThreadContext->SetBypass((const int32_t*)patch->address, (int32_t)patch->opcode); - LOG((LF_CORDB, LL_INFO10000, "InterpreterEC::BypassPatch at %p, opcode 0x%x\n", - patch->address, patch->opcode)); + LOG((LF_CORDB, LL_INFO10000, "InterpreterEC::BypassPatch at %p, opcode 0x%zx\n", + patch->address, (size_t)patch->opcode)); } #endif // FEATURE_INTERPRETER diff --git a/src/runtime/src/coreclr/debug/ee/frameinfo.cpp b/src/runtime/src/coreclr/debug/ee/frameinfo.cpp index f3adbb139ee6..81fa0fcb2dde 100644 --- a/src/runtime/src/coreclr/debug/ee/frameinfo.cpp +++ b/src/runtime/src/coreclr/debug/ee/frameinfo.cpp @@ -436,8 +436,9 @@ bool HasExitRuntime(Frame *pFrame, DebuggerFrameData *pData, FramePointer *pPote EX_END_CATCH LOG((LF_CORDB, LL_INFO100000, - "DWSP: TYPE_EXIT: returnIP=0x%08x, returnSP=0x%08x, frame=0x%08x, threadFrame=0x%08x, regSP=0x%08x\n", - returnIP, returnSP, pFrame, pData->GetThread()->GetFrame(), GetRegdisplaySP(&pData->regDisplay))); + "DWSP: TYPE_EXIT: returnIP=0x%08x, returnSP=0x%08x, frame=%p, threadFrame=%p, regSP=0x%08x\n", + returnIP, returnSP, static_cast(pFrame), static_cast(pData->GetThread()->GetFrame()), + GetRegdisplaySP(&pData->regDisplay))); if (pPotentialFP != NULL) { @@ -1745,8 +1746,8 @@ StackWalkAction DebuggerWalkStackProc(CrawlFrame *pCF, void *data) #if defined(TARGET_AMD64) LOG((LF_CORDB, LL_INFO100000, "DWSP: Saving REGDISPLAY with sp = 0x%p, pc = 0x%p.\n", - GetRegdisplaySP(&(d->info.registers)), - GetControlPC(&(d->info.registers)))); + (void*)GetRegdisplaySP(&(d->info.registers)), + (void*)GetControlPC(&(d->info.registers)))); #endif // TARGET_AMD64 d->needParentInfo = true; diff --git a/src/runtime/src/coreclr/debug/ee/funceval.cpp b/src/runtime/src/coreclr/debug/ee/funceval.cpp index 7e81734c7f63..d1fe3751457b 100644 --- a/src/runtime/src/coreclr/debug/ee/funceval.cpp +++ b/src/runtime/src/coreclr/debug/ee/funceval.cpp @@ -2328,7 +2328,7 @@ void CopyArgsToBuffer(DebuggerEval *pDE, "\t: argSigType=0x%x, byrefArgSigType=0x%0x, inType=0x%0x\n", pFEArgInfo[currArgIndex].argSigType, pFEArgInfo[currArgIndex].byrefArgSigType, - pFEAD->argElementType)); + static_cast(pFEAD->argElementType))); INT64 *pDest = &(pBufferArray[currArgIndex]); @@ -2748,7 +2748,7 @@ void PackArgumentArray(DebuggerEval *pDE, : DL_All) ); - LOG((LF_CORDB, LL_EVERYTHING, "this = 0x%08x\n", ArgSlotToPtr(pArguments[currArgSlot]))); + LOG((LF_CORDB, LL_EVERYTHING, "this = %p\n", ArgSlotToPtr(pArguments[currArgSlot]))); // We need to check 'this' for a null ref ourselves... NOTE: only do this if we put an object reference on // the stack. If we put a byref for a value type, then we don't need to do this! @@ -2843,7 +2843,7 @@ void PackArgumentArray(DebuggerEval *pDE, "\t: argSigType=0x%x, byrefArgSigType=0x%0x, inType=0x%0x\n", pFEArgInfo[currArgIndex].argSigType, pFEArgInfo[currArgIndex].byrefArgSigType, - pFEAD->argElementType)); + static_cast(pFEAD->argElementType))); GetFuncEvalArgValue(pDE, @@ -3363,7 +3363,7 @@ static void DoNormalFuncEval( DebuggerEval *pDE, allocArgCnt++; LOG((LF_CORDB, LL_EVERYTHING, - "Func eval for %s::%s: allocArgCnt=%d\n", + "Func eval for %s::%s: allocArgCnt=%zu\n", pDE->m_md->m_pszDebugClassName, pDE->m_md->m_pszDebugMethodName, allocArgCnt)); @@ -3818,7 +3818,7 @@ void * STDCALL FuncEvalHijackWorker(DebuggerEval *pDE) { GCX_FORBID(); - LOG((LF_CORDB, LL_INFO100000, "D:FEHW for pDE:%08x evalType:%d\n", pDE, pDE->m_evalType)); + LOG((LF_CORDB, LL_INFO100000, "D:FEHW for pDE:%p evalType:%d\n", pDE, pDE->m_evalType)); pThread = GetThread(); diff --git a/src/runtime/src/coreclr/debug/ee/functioninfo.cpp b/src/runtime/src/coreclr/debug/ee/functioninfo.cpp index aed4b0e532bd..0e652d890dac 100644 --- a/src/runtime/src/coreclr/debug/ee/functioninfo.cpp +++ b/src/runtime/src/coreclr/debug/ee/functioninfo.cpp @@ -43,7 +43,7 @@ static void _dumpVarNativeInfo(ICorDebugInfo::NativeVarInfo* vni) { WRAPPER_NO_CONTRACT; - LOG((LF_CORDB, LL_INFO1000000, "Var %02d: 0x%04x-0x%04x vlt=", + LOG((LF_CORDB, LL_INFO1000000, "Var %02d: 0x%04x-0x%04x vlt=%d, ", vni->varNumber, vni->startOffset, vni->endOffset, vni->loc.vlType)); @@ -517,7 +517,7 @@ SIZE_T DebuggerJitInfo::MapSpecialToNative(CorDebugMappingResult mapping, } CONTRACTL_END; - LOG((LF_CORDB, LL_INFO10000, "DJI::MSTN map:0x%x which:0x%x\n", mapping, which)); + LOG((LF_CORDB, LL_INFO10000, "DJI::MSTN map:0x%x which:0x%zx\n", mapping, which)); bool fFound; SIZE_T cFound = 0; @@ -645,7 +645,7 @@ void DebuggerJitInfo::MapILRangeToMapEntryRange(SIZE_T startOffset, CONTRACTL_END; LOG((LF_CORDB, LL_INFO1000000, - "DJI::MIRTMER: IL 0x%04x-0x%04x\n", + "DJI::MIRTMER: IL 0x%04zx-0x%04zx\n", startOffset, endOffset)); if (GetSequenceMapCount() == 0) @@ -683,7 +683,7 @@ void DebuggerJitInfo::MapILRangeToMapEntryRange(SIZE_T startOffset, LOG((LF_CORDB, LL_INFO1000000, - "DJI::MIRTMER: IL 0x%04x-0x%04x --> 0x%04x 0x%08x-0x%08x\n" + "DJI::MIRTMER: IL 0x%04zx-0x%04zx --> 0x%04x 0x%08x-0x%08x\n" " --> 0x%04x 0x%08x-0x%08x\n", startOffset, endOffset, (*start)->ilOffset, @@ -1226,12 +1226,12 @@ void DebuggerJitInfo::Init(TADDR newAddress) "Code from %p to %p " "varCount=%u seqCount=%u\n", this, this->m_encVersion, - this->m_codeRegionInfo.getAddrOfHotCode(), - this->m_codeRegionInfo.getAddrOfHotCode() + this->m_codeRegionInfo.getSizeOfHotCode(), - this->m_codeRegionInfo.getAddrOfColdCode(), - this->m_codeRegionInfo.getAddrOfColdCode() + this->m_codeRegionInfo.getSizeOfColdCode(), - this->m_addrOfCode, - this->m_addrOfCode+(ULONG)this->m_sizeOfCode, + (void*)this->m_codeRegionInfo.getAddrOfHotCode(), + (void*)(this->m_codeRegionInfo.getAddrOfHotCode() + this->m_codeRegionInfo.getSizeOfHotCode()), + (void*)this->m_codeRegionInfo.getAddrOfColdCode(), + (void*)(this->m_codeRegionInfo.getAddrOfColdCode() + this->m_codeRegionInfo.getSizeOfColdCode()), + (void*)this->m_addrOfCode, + (void*)(this->m_addrOfCode+(ULONG)this->m_sizeOfCode), this->GetVarNativeInfoCount(), this->GetSequenceMapCount())); @@ -1264,7 +1264,7 @@ ICorDebugInfo::SourceTypes DebuggerJitInfo::GetSrcTypeFromILOffset(SIZE_T ilOffs BOOL exact = FALSE; DebuggerILToNativeMap *pMap = MapILOffsetToMapEntry(ilOffset, &exact); - LOG((LF_CORDB, LL_INFO100000, "DJI::GSTFILO: for il 0x%x, got entry 0x%p," + LOG((LF_CORDB, LL_INFO100000, "DJI::GSTFILO: for il 0x%zx, got entry 0x%p," "(il 0x%x) nat 0x%x to 0x%x, SourceTypes 0x%x, exact:%x\n", ilOffset, pMap, pMap->ilOffset, pMap->nativeStartOffset, pMap->nativeEndOffset, pMap->source, exact)); @@ -1672,7 +1672,7 @@ DebuggerJitInfo *DebuggerMethodInfo::CreateInitAndAddJitInfo(NativeCodeVersion n m_latestJitInfo = dji; - LOG((LF_CORDB,LL_INFO10000,"DMI:CAAJI: DJI version 0x%04x for %s\n", + LOG((LF_CORDB,LL_INFO10000,"DMI:CAAJI: DJI version 0x%04zx for %s\n", GetCurrentEnCVersion(), dji->m_nativeCodeVersion.GetMethodDesc()->m_pszDebugMethodName)); } @@ -1715,7 +1715,7 @@ void DebuggerMethodInfo::DeleteJitInfo(DebuggerJitInfo *dji) Debugger::DebuggerDataLockHolder debuggerDataLockHolder(g_pDebugger); - LOG((LF_CORDB,LL_INFO10000,"DMI:DJI: dji:0x%08x\n", dji)); + LOG((LF_CORDB,LL_INFO10000,"DMI:DJI: dji:0x%p\n", dji)); DebuggerJitInfo *djiPrev = dji->m_prevJitInfo; @@ -2051,7 +2051,7 @@ void DebuggerMethodInfo::CreateDJIsForMethodDesc(MethodDesc * pMethodDesc) // Some versions may not be compiled yet - skip those for now // if they compile later the JitCompiled callback will add a DJI to our cache at that time PCODE codeAddr = GetInterpreterCodeFromEntryPointIfPresent(itr->GetNativeCode()); - LOG((LF_CORDB, LL_INFO10000, "DMI::CDJIFMD (%d) Native code for DJI - %p\n", ++count, codeAddr)); + LOG((LF_CORDB, LL_INFO10000, "DMI::CDJIFMD (%d) Native code for DJI - %p\n", ++count, (void*)codeAddr)); if (codeAddr) { // The DJI may already be populated in the cache, if so CreateInitAndAdd is @@ -2216,7 +2216,7 @@ void DebuggerMethodInfoTable::ClearMethodsOfModule(Module *pModule) _ASSERTE(g_pDebugger->HasDebuggerDataLock()); - LOG((LF_CORDB, LL_INFO1000000, "CMOM:mod:0x%x (%s)\n", pModule + LOG((LF_CORDB, LL_INFO1000000, "CMOM:mod:0x%p (%s)\n", pModule ,pModule->GetDebugName())); HASHFIND info; diff --git a/src/runtime/src/coreclr/debug/ee/i386/walker.cpp b/src/runtime/src/coreclr/debug/ee/i386/walker.cpp index 800f8b64357a..3e8b51d195ff 100644 --- a/src/runtime/src/coreclr/debug/ee/i386/walker.cpp +++ b/src/runtime/src/coreclr/debug/ee/i386/walker.cpp @@ -29,7 +29,7 @@ void NativeWalker::Decode() m_skipIP = NULL; m_nextIP = NULL; - LOG((LF_CORDB, LL_INFO100000, "NW:Decode: m_ip 0x%x\n", m_ip)); + LOG((LF_CORDB, LL_INFO100000, "NW:Decode: m_ip %p\n", const_cast(static_cast(m_ip)))); // // Skip instruction prefixes // @@ -68,7 +68,8 @@ void NativeWalker::Decode() // Read the opcode m_opcode = *ip++; - LOG((LF_CORDB, LL_INFO100000, "NW:Decode: ip 0x%x, m_opcode:%0.2x\n", ip, m_opcode)); + LOG((LF_CORDB, LL_INFO100000, "NW:Decode: ip %p, m_opcode:%0.2x\n", + const_cast(static_cast(ip)), m_opcode)); if (m_opcode == 0xcc) { diff --git a/src/runtime/src/coreclr/debug/ee/loongarch64/walker.cpp b/src/runtime/src/coreclr/debug/ee/loongarch64/walker.cpp index 01cf8de4747e..fa63f940cb9f 100644 --- a/src/runtime/src/coreclr/debug/ee/loongarch64/walker.cpp +++ b/src/runtime/src/coreclr/debug/ee/loongarch64/walker.cpp @@ -96,7 +96,8 @@ BOOL NativeWalker::DecodePCRelativeBranchInst(PT_CONTEXT context, const PRD_TYP } walk = WALK_BRANCH; //B - LOG((LF_CORDB, LL_INFO100000, "LoongArch64Walker::Decoded opcode: %x to B %x \n", opcode, offset)); + LOG((LF_CORDB, LL_INFO100000, "LoongArch64Walker::Decoded opcode: %x to B %zx \n", + opcode, static_cast(offset))); return TRUE; } @@ -116,7 +117,8 @@ BOOL NativeWalker::DecodePCRelativeBranchInst(PT_CONTEXT context, const PRD_TYP } walk = WALK_CALL; - LOG((LF_CORDB, LL_INFO100000, "LoongArch64Walker::Decoded opcode: %x to BL %x \n", opcode, offset)); + LOG((LF_CORDB, LL_INFO100000, "LoongArch64Walker::Decoded opcode: %x to BL %zx \n", + opcode, static_cast(offset))); return TRUE; } diff --git a/src/runtime/src/coreclr/debug/ee/rcthread.cpp b/src/runtime/src/coreclr/debug/ee/rcthread.cpp index 9f6740228e04..e60996b61960 100644 --- a/src/runtime/src/coreclr/debug/ee/rcthread.cpp +++ b/src/runtime/src/coreclr/debug/ee/rcthread.cpp @@ -1513,7 +1513,7 @@ HRESULT DebuggerRCThread::SendIPCEvent() STRESS_LOG2(LF_CORDB, LL_INFO1000, "D::SendIPCEvent %s to outofproc appD 0x%p,\n", IPCENames::GetName(pManagedEvent->type), - VmPtrToCookie(pManagedEvent->vmAppDomain)); + (void*)VmPtrToCookie(pManagedEvent->vmAppDomain)); // increase the debug counter DbgLog((DebuggerIPCEventType)(pManagedEvent->type & DB_IPCE_TYPE_MASK)); @@ -1642,7 +1642,7 @@ void DebuggerRCThread::DoFavor(FAVORCALLBACK fp, void * pData) // pickup that event, call the fp, and set the Read event SetEvent(GetFavorAvailableEvent()); - LOG((LF_CORDB, LL_INFO10000, "DRCT::DF - Waiting on FavorReadEvent for favor 0x%08x\n", fp)); + LOG((LF_CORDB, LL_INFO10000, "DRCT::DF - Waiting on FavorReadEvent for favor %p\n", (void*)fp)); // Wait for either the FavorEventRead to be set (which means that the favor // was executed by the helper thread) or the helper thread's handle (which means @@ -1680,12 +1680,12 @@ void DebuggerRCThread::DoFavor(FAVORCALLBACK fp, void * pData) if (wn == 0) // m_FavorEventRead { // Favor was executed, nothing to do here. - LOG((LF_CORDB, LL_INFO10000, "DRCT::DF - favor 0x%08x finished, ret = %d\n", fp, ret)); + LOG((LF_CORDB, LL_INFO10000, "DRCT::DF - favor %p finished, ret = %d\n", (void*)fp, ret)); } else { LOG((LF_CORDB, LL_INFO10000, "DRCT::DF - lost helper thread during wait, " - "doing favor 0x%08x on current thread\n", fp)); + "doing favor %p on current thread\n", (void*)fp)); // Since we have no timeout, we shouldn't be able to get an error on the wait, // but just in case ... @@ -1707,14 +1707,14 @@ void DebuggerRCThread::DoFavor(FAVORCALLBACK fp, void * pData) else { LOG((LF_CORDB, LL_INFO10000, "DRCT::DF - helper thread not ready, " - "doing favor 0x%08x on current thread\n", fp)); + "doing favor %p on current thread\n", (void*)fp)); // If helper isn't ready yet, go ahead and execute the favor // on the callee's space (*fp)(pData); } // Drop a log message so that we know if we survived a stack overflow or not - LOG((LF_CORDB, LL_INFO10000, "DRCT::DF - Favor 0x%08x completed successfully\n", fp)); + LOG((LF_CORDB, LL_INFO10000, "DRCT::DF - Favor %p completed successfully\n", (void*)fp)); } diff --git a/src/runtime/src/coreclr/debug/inc/common.h b/src/runtime/src/coreclr/debug/inc/common.h index 5e4000839846..77a4582e4fde 100644 --- a/src/runtime/src/coreclr/debug/inc/common.h +++ b/src/runtime/src/coreclr/debug/inc/common.h @@ -49,8 +49,8 @@ void InitEventForDebuggerNotification(DEBUG_EVENT * pDebugEvent, #define CopyContextChunk(_t, _f, _end, _flag) \ { \ LOG((LF_CORDB, LL_INFO1000000, \ - "CP::CTC: copying " #_flag ":" FMT_ADDR "<---" FMT_ADDR "(%d)\n", \ - DBG_ADDR(_t), DBG_ADDR(_f), ((UINT_PTR)(_end) - (UINT_PTR)_t))); \ + "CP::CTC: copying " #_flag ":" FMT_ADDR "<---" FMT_ADDR "(%zu)\n", \ + DBG_ADDR(_t), DBG_ADDR(_f), (size_t)((UINT_PTR)(_end) - (UINT_PTR)_t))); \ memcpy((_t), (_f), ((UINT_PTR)(_end) - (UINT_PTR)(_t))); \ } diff --git a/src/runtime/src/coreclr/debug/shared/arm/primitives.cpp b/src/runtime/src/coreclr/debug/shared/arm/primitives.cpp index 4cdf1e82af64..9a682fe26f3f 100644 --- a/src/runtime/src/coreclr/debug/shared/arm/primitives.cpp +++ b/src/runtime/src/coreclr/debug/shared/arm/primitives.cpp @@ -21,8 +21,8 @@ void CORDbgCopyThreadContext(DT_CONTEXT* pDst, const DT_CONTEXT* pSrc) DWORD dstFlags = pDst->ContextFlags; DWORD srcFlags = pSrc->ContextFlags; LOG((LF_CORDB, LL_INFO1000000, - "CP::CTC: pDst=0x%08x dstFlags=0x%x, pSrc=0x%08x srcFlags=0x%x\n", - pDst, dstFlags, pSrc, srcFlags)); + "CP::CTC: pDst=%p dstFlags=0x%x, pSrc=%p srcFlags=0x%x\n", + (void*)pDst, dstFlags, (void*)pSrc, srcFlags)); if ((dstFlags & srcFlags & DT_CONTEXT_CONTROL) == DT_CONTEXT_CONTROL) CopyContextChunk(&(pDst->Sp), &(pSrc->Sp), &(pDst->Fpscr), diff --git a/src/runtime/src/coreclr/debug/shared/arm64/primitives.cpp b/src/runtime/src/coreclr/debug/shared/arm64/primitives.cpp index a381891b02d8..189443083e23 100644 --- a/src/runtime/src/coreclr/debug/shared/arm64/primitives.cpp +++ b/src/runtime/src/coreclr/debug/shared/arm64/primitives.cpp @@ -21,8 +21,8 @@ void CORDbgCopyThreadContext(DT_CONTEXT* pDst, const DT_CONTEXT* pSrc) DWORD dstFlags = pDst->ContextFlags; DWORD srcFlags = pSrc->ContextFlags; LOG((LF_CORDB, LL_INFO1000000, - "CP::CTC: pDst=0x%08x dstFlags=0x%x, pSrc=0x%08x srcFlags=0x%x\n", - pDst, dstFlags, pSrc, srcFlags)); + "CP::CTC: pDst=%p dstFlags=0x%x, pSrc=%p srcFlags=0x%x\n", + static_cast(pDst), dstFlags, const_cast(static_cast(pSrc)), srcFlags)); if ((dstFlags & srcFlags & DT_CONTEXT_CONTROL) == DT_CONTEXT_CONTROL) { diff --git a/src/runtime/src/coreclr/debug/shared/i386/primitives.cpp b/src/runtime/src/coreclr/debug/shared/i386/primitives.cpp index 96a5a8f9aea9..e0bb2044d02d 100644 --- a/src/runtime/src/coreclr/debug/shared/i386/primitives.cpp +++ b/src/runtime/src/coreclr/debug/shared/i386/primitives.cpp @@ -21,8 +21,8 @@ void CORDbgCopyThreadContext(DT_CONTEXT* pDst, const DT_CONTEXT* pSrc) DWORD dstFlags = pDst->ContextFlags; DWORD srcFlags = pSrc->ContextFlags; LOG((LF_CORDB, LL_INFO1000000, - "CP::CTC: pDst=0x%08x dstFlags=0x%x, pSrc=0x%08x srcFlags=0x%x\n", - pDst, dstFlags, pSrc, srcFlags)); + "CP::CTC: pDst=%p dstFlags=0x%x, pSrc=%p srcFlags=0x%x\n", + (void*)pDst, dstFlags, (void*)pSrc, srcFlags)); if ((dstFlags & srcFlags & DT_CONTEXT_CONTROL) == DT_CONTEXT_CONTROL) CopyContextChunk(&(pDst->Ebp), &(pSrc->Ebp), pDst->ExtendedRegisters, diff --git a/src/runtime/src/coreclr/debug/shared/loongarch64/primitives.cpp b/src/runtime/src/coreclr/debug/shared/loongarch64/primitives.cpp index 11801fea05c1..aec98e9d4530 100644 --- a/src/runtime/src/coreclr/debug/shared/loongarch64/primitives.cpp +++ b/src/runtime/src/coreclr/debug/shared/loongarch64/primitives.cpp @@ -22,29 +22,29 @@ void CORDbgCopyThreadContext(DT_CONTEXT* pDst, const DT_CONTEXT* pSrc) DWORD dstFlags = pDst->ContextFlags; DWORD srcFlags = pSrc->ContextFlags; LOG((LF_CORDB, LL_INFO1000000, - "CP::CTC: pDst=0x%08x dstFlags=0x%x, pSrc=0x%08x srcFlags=0x%x\n", - pDst, dstFlags, pSrc, srcFlags)); + "CP::CTC: pDst=%p dstFlags=0x%x, pSrc=%p srcFlags=0x%x\n", + (void*)pDst, dstFlags, (void*)pSrc, srcFlags)); if ((dstFlags & srcFlags & DT_CONTEXT_CONTROL) == DT_CONTEXT_CONTROL) { LOG((LF_CORDB, LL_INFO1000000, "CP::CTC: RA: pDst=0x%lx, pSrc=0x%lx, Flags=0x%x\n", - pDst->Ra, pSrc->Ra, DT_CONTEXT_CONTROL)); + pDst->Ra, pSrc->Ra, static_cast(DT_CONTEXT_CONTROL))); pDst->Ra = pSrc->Ra; LOG((LF_CORDB, LL_INFO1000000, "CP::CTC: SP: pDst=0x%lx, pSrc=0x%lx, Flags=0x%x\n", - pDst->Sp, pSrc->Sp, DT_CONTEXT_CONTROL)); + pDst->Sp, pSrc->Sp, static_cast(DT_CONTEXT_CONTROL))); pDst->Sp = pSrc->Sp; LOG((LF_CORDB, LL_INFO1000000, "CP::CTC: FP: pDst=0x%lx, pSrc=0x%lx, Flags=0x%x\n", - pDst->Fp, pSrc->Fp, DT_CONTEXT_CONTROL)); + pDst->Fp, pSrc->Fp, static_cast(DT_CONTEXT_CONTROL))); pDst->Fp = pSrc->Fp; LOG((LF_CORDB, LL_INFO1000000, "CP::CTC: PC: pDst=0x%lx, pSrc=0x%lx, Flags=0x%x\n", - pDst->Pc, pSrc->Pc, DT_CONTEXT_CONTROL)); + pDst->Pc, pSrc->Pc, static_cast(DT_CONTEXT_CONTROL))); pDst->Pc = pSrc->Pc; } diff --git a/src/runtime/src/coreclr/debug/shared/riscv64/primitives.cpp b/src/runtime/src/coreclr/debug/shared/riscv64/primitives.cpp index cf306684ada4..cd54b8543178 100644 --- a/src/runtime/src/coreclr/debug/shared/riscv64/primitives.cpp +++ b/src/runtime/src/coreclr/debug/shared/riscv64/primitives.cpp @@ -20,29 +20,29 @@ void CORDbgCopyThreadContext(DT_CONTEXT* pDst, const DT_CONTEXT* pSrc) DWORD dstFlags = pDst->ContextFlags; DWORD srcFlags = pSrc->ContextFlags; LOG((LF_CORDB, LL_INFO1000000, - "CP::CTC: pDst=0x%08x dstFlags=0x%x, pSrc=0x%08x srcFlags=0x%x\n", - pDst, dstFlags, pSrc, srcFlags)); + "CP::CTC: pDst=%p dstFlags=0x%x, pSrc=%p srcFlags=0x%x\n", + (void*)pDst, dstFlags, (void*)pSrc, srcFlags)); if ((dstFlags & srcFlags & DT_CONTEXT_CONTROL) == DT_CONTEXT_CONTROL) { LOG((LF_CORDB, LL_INFO1000000, "CP::CTC: RA: pDst=0x%lx, pSrc=0x%lx, Flags=0x%x\n", - pDst->Ra, pSrc->Ra, DT_CONTEXT_CONTROL)); + pDst->Ra, pSrc->Ra, static_cast(DT_CONTEXT_CONTROL))); pDst->Ra = pSrc->Ra; LOG((LF_CORDB, LL_INFO1000000, "CP::CTC: SP: pDst=0x%lx, pSrc=0x%lx, Flags=0x%x\n", - pDst->Sp, pSrc->Sp, DT_CONTEXT_CONTROL)); + pDst->Sp, pSrc->Sp, static_cast(DT_CONTEXT_CONTROL))); pDst->Sp = pSrc->Sp; LOG((LF_CORDB, LL_INFO1000000, "CP::CTC: FP: pDst=0x%lx, pSrc=0x%lx, Flags=0x%x\n", - pDst->Fp, pSrc->Fp, DT_CONTEXT_CONTROL)); + pDst->Fp, pSrc->Fp, static_cast(DT_CONTEXT_CONTROL))); pDst->Fp = pSrc->Fp; LOG((LF_CORDB, LL_INFO1000000, "CP::CTC: PC: pDst=0x%lx, pSrc=0x%lx, Flags=0x%x\n", - pDst->Pc, pSrc->Pc, DT_CONTEXT_CONTROL)); + pDst->Pc, pSrc->Pc, static_cast(DT_CONTEXT_CONTROL))); pDst->Pc = pSrc->Pc; } @@ -54,7 +54,7 @@ void CORDbgCopyThreadContext(DT_CONTEXT* pDst, const DT_CONTEXT* pSrc) DT_CONTEXT_INTEGER); LOG((LF_CORDB, LL_INFO1000000, "CP::CTC: T0: pDst=0x%lx, pSrc=0x%lx, Flags=0x%x\n", - pDst->R0, pSrc->R0, DT_CONTEXT_INTEGER)); + pDst->R0, pSrc->R0, static_cast(DT_CONTEXT_INTEGER))); pDst->R0 = pSrc->R0; } diff --git a/src/runtime/src/coreclr/dlls/mscorpe/pewriter.cpp b/src/runtime/src/coreclr/dlls/mscorpe/pewriter.cpp index e6833ffd83a6..5f602656c640 100644 --- a/src/runtime/src/coreclr/dlls/mscorpe/pewriter.cpp +++ b/src/runtime/src/coreclr/dlls/mscorpe/pewriter.cpp @@ -296,6 +296,7 @@ HRESULT PEWriterSection::applyRelocs(IMAGE_NT_HEADERS * pNtHeaders, #ifdef LOGGING LOG((LF_ZAP, LL_INFO1000000, " Reloc %s%s at %-7s+%04x (RVA=%08x) at" FMT_ADDR, + RelocName[curType], &RelocSpaces[strlen(RelocName[curType])], m_name, curOffset, curRVA, DBG_ADDR(pos))); @@ -385,8 +386,8 @@ HRESULT PEWriterSection::applyRelocs(IMAGE_NT_HEADERS * pNtHeaders, #ifdef LOGGING LOG((LF_ZAP, LL_INFO1000000, - "to %-7s+%04x, old =" FMT_ADDR "new =" FMT_ADDR "%s\n", - cur->section->m_name, targetOffset, + "to %-7s+%04lx, old =" FMT_ADDR "new =" FMT_ADDR "%s\n", + cur->section->m_name, (unsigned long)targetOffset, DBG_ADDR(oldStarPos), DBG_ADDR(newStarPos), baseReloc ? "(BASE RELOC)" : "")); #endif diff --git a/src/runtime/src/coreclr/gc/allocation.cpp b/src/runtime/src/coreclr/gc/allocation.cpp index 06d5d231a9d0..c3526eb8dd39 100644 --- a/src/runtime/src/coreclr/gc/allocation.cpp +++ b/src/runtime/src/coreclr/gc/allocation.cpp @@ -277,7 +277,7 @@ void allocator::count_items (gc_heap* this_hp, size_t* fl_items_count, size_t* f num_fl_items++; // Get the heap its region belongs to see if we need to put it back. heap_segment* region = gc_heap::region_of (free_item); - dprintf (3, ("b#%2d FL %Ix region %Ix heap %d -> %d", + dprintf (3, ("b#%2d FL %p region %zx heap %d -> %d", i, free_item, (size_t)region, this_hp->heap_number, region->heap->heap_number)); if (region->heap != this_hp) { @@ -289,7 +289,7 @@ void allocator::count_items (gc_heap* this_hp, size_t* fl_items_count, size_t* f } end_us = GetHighPrecisionTimeStamp(); - dprintf (3, ("total - %Id items out of %Id items are from a different heap in %I64d us", + dprintf (3, ("total - %zd items out of %zd items are from a different heap in %" PRIu64 " us", num_fl_items_for_oh, num_fl_items, (end_us - start_us))); *fl_items_count = num_fl_items; @@ -373,7 +373,7 @@ void allocator::rethread_items (size_t* num_total_fl_items, size_t* num_total_fl num_fl_items++; // Get the heap its region belongs to see if we need to put it back. heap_segment* region = gc_heap::region_of (free_item); - dprintf (3, ("b#%2d FL %Ix region %Ix heap %d -> %d", + dprintf (3, ("b#%2d FL %p region %zx heap %d -> %d", i, free_item, (size_t)region, current_heap->heap_number, region->heap->heap_number)); // need to keep track of heap and only check if it's not from our heap!! if (region->heap != current_heap) @@ -409,7 +409,7 @@ void allocator::rethread_items (size_t* num_total_fl_items, size_t* num_total_fl } end_us = GetHighPrecisionTimeStamp(); - dprintf (8888, ("h%d total %Id items rethreaded out of %Id items in %I64d us (%I64dms)", + dprintf (8888, ("h%d total %zd items rethreaded out of %zd items in %" PRIu64 " us (%" PRIu64 "ms)", current_heap->heap_number, num_fl_items_rethreaded, num_fl_items, (end_us - start_us), ((end_us - start_us) / 1000))); (*num_total_fl_items) += num_fl_items; @@ -1004,7 +1004,7 @@ void add_to_hb_numa ( bool set_ideal_p) { int tid = (int)GCToOSInterface::GetCurrentThreadIdForLogging (); - uint64_t timestamp = RawGetHighPrecisionTimeStamp (); + int64_t timestamp = minipal_hires_ticks (); int saved_proc_no = proc_no; int numa_no = -1; @@ -1314,7 +1314,7 @@ bool gc_heap::new_allocation_allowed (int gen_number) if ((allocation_running_amount - dd_new_allocation (dd0)) > dd_min_size (dd0)) { - uint64_t ctime = GCToOSInterface::GetLowPrecisionTimeStamp(); + int64_t ctime = minipal_lowres_ticks(); if ((ctime - allocation_running_time) > 1000) { dprintf (2, (">1s since last gen0 gc")); @@ -3480,7 +3480,7 @@ uoh_allocation_action gc_heap::get_bgc_allocate_action (int gen_number) // doesn't make sense. if (bgc_begin_uoh_size[uoh_idx] >= (2 * end_uoh_size[uoh_idx])) { - dprintf (3, ("h%d alloc-ed too much before bgc started, last end %Id, this start %Id, wait", + dprintf (3, ("h%d alloc-ed too much before bgc started, last end %zd, this start %zd, wait", heap_number, end_uoh_size[uoh_idx], bgc_begin_uoh_size[uoh_idx])); return uoh_alloc_wait; } @@ -3536,7 +3536,7 @@ void gc_heap::bgc_record_uoh_end_seg_allocation (int gen_number, size_t size) #ifdef SIMPLE_DPRINTF dynamic_data* dd_uoh = dynamic_data_of (gen_number); size_t gen_size = generation_size (gen_number); - dprintf (3, ("h%d g%d size is now %Id (inc-ed %Id), size is %Id (gen size is %Id), budget %.3fmb, new alloc %.3fmb", + dprintf (3, ("h%d g%d size is now %zd (inc-ed %zd), size is %zd (gen size is %zd), budget %.3fmb, new alloc %.3fmb", heap_number, gen_number, bgc_uoh_current_size[uoh_idx], (bgc_uoh_current_size[uoh_idx] - bgc_begin_uoh_size[uoh_idx]), size, gen_size, mb (dd_desired_allocation (dd_uoh)), (dd_new_allocation (dd_uoh) / 1000.0 / 1000.0))); @@ -3912,7 +3912,7 @@ allocation_state gc_heap::try_allocate_more_space (alloc_context* acontext, size if (gc_heap::gc_started) { wait_for_gc_done(); - //dprintf (5555, ("h%d TAMS g%d %Id returning a_state_retry_allocate!", heap_number, gen_number, size)); + //dprintf (5555, ("h%d TAMS g%d %zd returning a_state_retry_allocate!", heap_number, gen_number, size)); return a_state_retry_allocate; } @@ -3921,7 +3921,7 @@ allocation_state gc_heap::try_allocate_more_space (alloc_context* acontext, size GCSpinLock* msl = loh_p ? &more_space_lock_uoh : &more_space_lock_soh; #ifdef SYNCHRONIZATION_STATS - int64_t msl_acquire_start = GCToOSInterface::QueryPerformanceCounter(); + int64_t msl_acquire_start = minipal_hires_ticks(); #endif //SYNCHRONIZATION_STATS msl_status = enter_spin_lock_msl (msl); @@ -3930,7 +3930,7 @@ allocation_state gc_heap::try_allocate_more_space (alloc_context* acontext, size add_saved_spinlock_info (loh_p, me_acquire, mt_try_alloc, msl_status); dprintf (SPINLOCK_LOG, ("[%d]Emsl for alloc", heap_number)); #ifdef SYNCHRONIZATION_STATS - int64_t msl_acquire = GCToOSInterface::QueryPerformanceCounter() - msl_acquire_start; + int64_t msl_acquire = minipal_hires_ticks() - msl_acquire_start; total_msl_acquire += msl_acquire; num_msl_acquired++; if (msl_acquire > 200) @@ -4483,27 +4483,27 @@ BOOL gc_heap::allocate_more_space(alloc_context* acontext, size_t size, else { alloc_heap = balance_heaps_uoh (acontext, size, alloc_generation_number); - dprintf (3, ("uoh alloc %Id on h%d", size, alloc_heap->heap_number)); + dprintf (3, ("uoh alloc %zd on h%d", size, alloc_heap->heap_number)); saved_alloc_heap = alloc_heap; } bool alloced_on_retry = (status == a_state_retry_allocate); status = alloc_heap->try_allocate_more_space (acontext, size, flags, alloc_generation_number); - dprintf (3, ("UOH h%d %Id returned from TAMS, s %d", alloc_heap->heap_number, size, status)); + dprintf (3, ("UOH h%d %zd returned from TAMS, s %d", alloc_heap->heap_number, size, status)); uint64_t end_us = GetHighPrecisionTimeStamp (); if (status == a_state_retry_allocate) { // This records that we had to retry due to decommissioned heaps or GC in progress - dprintf (5555, ("UOH h%d alloc %Id retry!", alloc_heap->heap_number, size)); + dprintf (5555, ("UOH h%d alloc %zd retry!", alloc_heap->heap_number, size)); } else { if (alloced_on_retry) { - dprintf (5555, ("UOH h%d allocated %Id on retry (%I64dus)", alloc_heap->heap_number, size, (end_us - start_us))); + dprintf (5555, ("UOH h%d allocated %zd on retry (%" PRIu64 "us)", alloc_heap->heap_number, size, (end_us - start_us))); } } } @@ -5592,7 +5592,7 @@ uint8_t* gc_heap::allocate_in_condemned_generations (generation* gen, ((pinned_plug (oldest_pin()) < heap_segment_allocated (seg)) && (pinned_plug (oldest_pin()) >= generation_allocation_pointer (gen)))) { - LOG((LF_GC, LL_INFO10, "remaining pinned plug %zx while leaving segment on allocation", + LOG((LF_GC, LL_INFO10, "remaining pinned plug %p while leaving segment on allocation", pinned_plug (oldest_pin()))); FATAL_GC_ERROR(); } diff --git a/src/runtime/src/coreclr/gc/background.cpp b/src/runtime/src/coreclr/gc/background.cpp index aac8b1fd388d..ae602fdf9115 100644 --- a/src/runtime/src/coreclr/gc/background.cpp +++ b/src/runtime/src/coreclr/gc/background.cpp @@ -2697,7 +2697,7 @@ void gc_heap::background_grow_c_mark_list() assert (new_c_mark_list); memcpy (new_c_mark_list, c_mark_list, c_mark_list_length*sizeof(uint8_t*)); c_mark_list_length = c_mark_list_length*2; - dprintf (5555, ("h%d replacing mark list at %Ix with %Ix", heap_number, (size_t)c_mark_list, (size_t)new_c_mark_list)); + dprintf (5555, ("h%d replacing mark list at %zx with %zx", heap_number, (size_t)c_mark_list, (size_t)new_c_mark_list)); delete[] c_mark_list; c_mark_list = new_c_mark_list; } @@ -2789,7 +2789,7 @@ void gc_heap::add_to_bgc_th_creation_history (size_t gc_index, size_t count_crea { if ((count_created != 0) || (count_created_th_existed != 0) || (count_creation_failed != 0)) { - dprintf (6666, ("ADDING to BGC th hist entry%d gc index %Id, created %d, %d th existed, %d failed", + dprintf (6666, ("ADDING to BGC th hist entry%d gc index %zd, created %zu, %zu th existed, %zu failed", bgc_th_creation_hist_index, gc_index, count_created, count_created_th_existed, count_creation_failed)); bgc_thread_creation_history* current_hist = &bgc_th_creation_hist[bgc_th_creation_hist_index]; @@ -3128,10 +3128,10 @@ void gc_heap::bgc_thread_function() // this is the case where we have more background GC threads than heaps // - wait until we're told to continue... - dprintf (6666, ("BGC%Id h%d going idle (%d heaps), idle count is now %d", + dprintf (6666, ("BGC%zd h%d going idle (%d heaps), idle count is now %d", VolatileLoadWithoutBarrier (&settings.gc_index), heap_number, n_heaps, VolatileLoadWithoutBarrier (&dynamic_heap_count_data.idle_bgc_thread_count))); bgc_idle_thread_event.Wait(INFINITE, FALSE); - dprintf (6666, ("BGC%Id h%d woke from idle (%d heaps), idle count is now %d", + dprintf (6666, ("BGC%zd h%d woke from idle (%d heaps), idle count is now %d", VolatileLoadWithoutBarrier (&settings.gc_index), heap_number, n_heaps, VolatileLoadWithoutBarrier (&dynamic_heap_count_data.idle_bgc_thread_count))); continue; } diff --git a/src/runtime/src/coreclr/gc/card_table.cpp b/src/runtime/src/coreclr/gc/card_table.cpp index a8cc465e36f6..de1ad08506b4 100644 --- a/src/runtime/src/coreclr/gc/card_table.cpp +++ b/src/runtime/src/coreclr/gc/card_table.cpp @@ -283,9 +283,9 @@ bool gc_heap::on_used_changed (uint8_t* new_used) assert ((UINT64_MAX - new_committed_size) > (uint64_t)g_gc_lowest_address); uint8_t* double_commit = g_gc_lowest_address + new_committed_size; new_bookkeeping_covered_committed = max(double_commit, new_used); - dprintf (REGIONS_LOG, ("committed_size = %zd", committed_size)); - dprintf (REGIONS_LOG, ("total_size = %zd", total_size)); - dprintf (REGIONS_LOG, ("new_committed_size = %zd", new_committed_size)); + dprintf (REGIONS_LOG, ("committed_size = %" PRIu64, committed_size)); + dprintf (REGIONS_LOG, ("total_size = %" PRIu64, total_size)); + dprintf (REGIONS_LOG, ("new_committed_size = %" PRIu64, new_committed_size)); dprintf (REGIONS_LOG, ("double_commit = %p", double_commit)); } dprintf (REGIONS_LOG, ("bookkeeping_covered_committed = %p", bookkeeping_covered_committed)); diff --git a/src/runtime/src/coreclr/gc/collect.cpp b/src/runtime/src/coreclr/gc/collect.cpp index ee2c1d10139a..8b2151b7a6e0 100644 --- a/src/runtime/src/coreclr/gc/collect.cpp +++ b/src/runtime/src/coreclr/gc/collect.cpp @@ -66,7 +66,7 @@ void gc_heap::update_end_gc_time_per_heap() if (heap_number == 0) { - dprintf (3, ("prev gen%d GC end time: prev start %I64d + prev gc elapsed %Id = %I64d", + dprintf (3, ("prev gen%d GC end time: prev start %" PRIu64 " + prev gc elapsed %zu = %" PRIu64, gen_number, dd_previous_time_clock (dd), dd_gc_elapsed_time (dd), (dd_previous_time_clock (dd) + dd_gc_elapsed_time (dd)))); } @@ -74,7 +74,7 @@ void gc_heap::update_end_gc_time_per_heap() if (heap_number == 0) { - dprintf (3, ("updated NGC%d %Id elapsed time to %I64d - %I64d = %I64d", gen_number, dd_gc_clock (dd), end_gc_time, dd_time_clock (dd), dd_gc_elapsed_time (dd))); + dprintf (3, ("updated NGC%d %zd elapsed time to %" PRIu64 " - %" PRIu64 " = %zu", gen_number, dd_gc_clock (dd), end_gc_time, dd_time_clock (dd), dd_gc_elapsed_time (dd))); } } } @@ -204,7 +204,7 @@ void gc_heap::gc1() if ((heap_number == 0) && (dynamic_adaptation_mode == dynamic_adaptation_to_application_sizes)) { time_since_last_gen2 = (size_t)(end_gc_time - (dd_previous_time_clock (dd) + dd_gc_elapsed_time (dd))); - dprintf (6666, ("BGC %Id end %I64d - (prev gen2 start %I64d + elapsed %Id = %I64d) = time inbewteen gen2 %Id", + dprintf (6666, ("BGC %zd end %" PRIu64 " - (prev gen2 start %" PRIu64 " + elapsed %zu = %" PRIu64 ") = time inbewteen gen2 %zu", dd_gc_clock (dd), end_gc_time, dd_previous_time_clock (dd), dd_gc_elapsed_time (dd), (dd_previous_time_clock (dd) + dd_gc_elapsed_time (dd)), time_since_last_gen2)); } #endif //DYNAMIC_HEAP_COUNT @@ -213,14 +213,14 @@ void gc_heap::gc1() #ifdef DYNAMIC_HEAP_COUNT if ((heap_number == 0) && (dynamic_adaptation_mode == dynamic_adaptation_to_application_sizes)) { - dprintf (6666, ("updating BGC %Id elapsed time to %I64d - %I64d = %I64d", dd_gc_clock (dd), end_gc_time, dd_time_clock (dd), dd_gc_elapsed_time (dd))); + dprintf (6666, ("updating BGC %zd elapsed time to %" PRIu64 " - %" PRIu64 " = %zu", dd_gc_clock (dd), end_gc_time, dd_time_clock (dd), dd_gc_elapsed_time (dd))); float bgc_percent = (float)dd_gc_elapsed_time (dd) * 100.0f / (float)time_since_last_gen2; dynamic_heap_count_data_t::gen2_sample& g2_sample = dynamic_heap_count_data.gen2_samples[dynamic_heap_count_data.gen2_sample_index]; g2_sample.gc_index = VolatileLoadWithoutBarrier (&(settings.gc_index)); g2_sample.gc_duration = dd_gc_elapsed_time (dd); g2_sample.gc_percent = bgc_percent; - dprintf (6666, ("gen2 sample %d elapsed %Id * 100 / time inbetween gen2 %Id = %.3f", + dprintf (6666, ("gen2 sample %d elapsed %zd * 100 / time inbetween gen2 %zd = %.3f", dynamic_heap_count_data.gen2_sample_index, dd_gc_elapsed_time (dd), time_since_last_gen2, bgc_percent)); dynamic_heap_count_data.gen2_sample_index = (dynamic_heap_count_data.gen2_sample_index + 1) % dynamic_heap_count_data_t::sample_size; (dynamic_heap_count_data.current_gen2_samples_count)++; @@ -576,7 +576,7 @@ void gc_heap::gc1() size_t desired_per_heap_before_trim = desired_per_heap; desired_per_heap = joined_youngest_desired (desired_per_heap); - dprintf (6666, ("final gen0 bcs: total desired: %Id (%.3fmb/heap), before smooth %zd -> after smooth %zd -> after joined %zd", + dprintf (6666, ("final gen0 bcs: total desired: %zd (%.3fmb/heap), before smooth %zd -> after smooth %zd -> after joined %zd", total_desired, ((double)(total_desired / n_heaps)/ 1000.0 / 1000.0), desired_per_heap_before_smoothing, desired_per_heap_after_smoothing, desired_per_heap)); #endif // HOST_64BIT @@ -1305,7 +1305,7 @@ void gc_heap::garbage_collect (int n) gc1(); } #ifndef MULTIPLE_HEAPS - allocation_running_time = GCToOSInterface::GetLowPrecisionTimeStamp(); + allocation_running_time = minipal_lowres_ticks(); allocation_running_amount = dd_new_allocation (dynamic_data_of (0)); fgn_last_alloc = dd_new_allocation (dynamic_data_of (0)); #endif //MULTIPLE_HEAPS diff --git a/src/runtime/src/coreclr/gc/diagnostics.cpp b/src/runtime/src/coreclr/gc/diagnostics.cpp index b456c799f231..370afcb96b40 100644 --- a/src/runtime/src/coreclr/gc/diagnostics.cpp +++ b/src/runtime/src/coreclr/gc/diagnostics.cpp @@ -542,7 +542,7 @@ void gc_heap::descr_generations (const char* msg) size_t idx = VolatileLoadWithoutBarrier (&settings.gc_index); - dprintf (REGIONS_LOG, ("[%s] GC#%5Id [%s] heap %Idmb (F: %Idmb %d%%) commit size: %Idmb, %0.3f min, %d,%d new in plan, %d in threading", + dprintf (REGIONS_LOG, ("[%s] GC#%5zd [%s] heap %zdmb (F: %zdmb %d%%) commit size: %zdmb, %0.3f min, %d,%d new in plan, %d in threading", msg, idx, (settings.promotion ? "PM" : "NPM"), alloc_size, frag_size, (int)((double)frag_size * 100.0 / (double)alloc_size), commit_size, @@ -559,7 +559,7 @@ void gc_heap::descr_generations (const char* msg) int bgcs = VolatileLoadWithoutBarrier (¤t_bgc_state); #ifdef SIMPLE_DPRINTF - dprintf (REGIONS_LOG, ("[%s] GC#%Id (bgcs: %d, %s) g0: %Idmb (f: %Idmb %d%%), g1: %Idmb (f: %Idmb %d%%), g2: %Idmb (f: %Idmb %d%%), g3: %Idmb (f: %Idmb %d%%)", + dprintf (REGIONS_LOG, ("[%s] GC#%zd (bgcs: %d, %s) g0: %zdmb (f: %zdmb %d%%), g1: %zdmb (f: %zdmb %d%%), g2: %zdmb (f: %zdmb %d%%), g3: %zdmb (f: %zdmb %d%%)", msg, idx, bgcs, str_bgc_state[bgcs], total_gen_size_mb[0], total_gen_fragmentation_mb[0], (total_gen_size_mb[0] ? (int)((double)total_gen_fragmentation_mb[0] * 100.0 / (double)total_gen_size_mb[0]) : 0), total_gen_size_mb[1], total_gen_fragmentation_mb[1], (total_gen_size_mb[1] ? (int)((double)total_gen_fragmentation_mb[1] * 100.0 / (double)total_gen_size_mb[1]) : 0), @@ -569,7 +569,7 @@ void gc_heap::descr_generations (const char* msg) // print every 20 GCs so it's easy to see if we are making progress. if ((idx % 20) == 0) { - dprintf (1, ("[%5s] GC#%5Id total heap size: %Idmb (F: %Idmb %d%%) commit size: %Idmb, %0.3f min, %d,%d new in plan, %d in threading\n", + dprintf (1, ("[%5s] GC#%5zd total heap size: %zdmb (F: %zdmb %d%%) commit size: %zdmb, %0.3f min, %d,%d new in plan, %d in threading\n", msg, idx, alloc_size, frag_size, (int)((double)frag_size * 100.0 / (double)alloc_size), commit_size, @@ -1643,8 +1643,8 @@ void gc_heap::record_interesting_info_per_heap() (interesting_mechanism_bits_per_heap[i])++; } - // h# | GC | gen | C | EX | NF | BF | ML | DM || PreS | PostS | Merge | Conv | Pre | Post | PrPo | PreP | PostP | - cprintf (("%2d | %6d | %1d | %1s | %2s | %2s | %2s | %2s | %2s || %5Id | %5Id | %5Id | %5Id | %5Id | %5Id | %5Id | %5Id | %5Id |", + // h# | GC | gen | C | EX | NF | BF | ML | DM || PreS | PostS | Merge | Conv | Pre | Post | PrPo | PreP | PostP | + cprintf (("%2d | %6zu | %1d | %1s | %2s | %2s | %2s | %2s | %2s || %5zu | %5zu | %5zu | %5zu | %5zu | %5zu | %5zu | %5zu | %5zu |", heap_number, (size_t)settings.gc_index, settings.condemned_generation, diff --git a/src/runtime/src/coreclr/gc/dynamic_heap_count.cpp b/src/runtime/src/coreclr/gc/dynamic_heap_count.cpp index 853a1c5ffe58..ef195307b67f 100644 --- a/src/runtime/src/coreclr/gc/dynamic_heap_count.cpp +++ b/src/runtime/src/coreclr/gc/dynamic_heap_count.cpp @@ -460,7 +460,7 @@ void gc_heap::calculate_new_heap_count () { assert (dynamic_adaptation_mode == dynamic_adaptation_to_application_sizes); - dprintf (6666, ("current num of samples %Id (g2: %Id) prev processed %Id (g2: %Id), last full GC happened at index %Id", + dprintf (6666, ("current num of samples %zd (g2: %zd) prev processed %zd (g2: %zd), last full GC happened at index %zd", dynamic_heap_count_data.current_samples_count, dynamic_heap_count_data.current_gen2_samples_count, dynamic_heap_count_data.processed_samples_count, dynamic_heap_count_data.processed_gen2_samples_count, gc_index_full_gc_end)); @@ -495,9 +495,9 @@ void gc_heap::calculate_new_heap_count () assert (throughput_cost_percents[i] >= 0.0); if (throughput_cost_percents[i] > 100.0) throughput_cost_percents[i] = 100.0; - dprintf (6666, ("sample %d in GC#%Id msl %I64d / %d + pause %I64d / elapsed %I64d = tcp: %.3f, surv %zd, gc speed %zd/ms", i, + dprintf (6666, ("sample %d in GC#%zu msl %" PRIu64 " / %d + pause %" PRIu64 " / elapsed %" PRIu64 " = tcp: %.3f, surv %zu, gc speed %" PRIu64 "/ms", i, sample.gc_index, sample.msl_wait_time, n_heaps, sample.gc_pause_time, sample.elapsed_between_gcs, throughput_cost_percents[i], - sample.gc_survived_size, (sample.gc_pause_time ? (sample.gc_survived_size * 1000 / sample.gc_pause_time) : 0))); + sample.gc_survived_size, (sample.gc_pause_time ? (sample.gc_survived_size * 1000 / sample.gc_pause_time) : (uint64_t)0))); } } @@ -515,7 +515,7 @@ void gc_heap::calculate_new_heap_count () min_pause = min (dynamic_heap_count_data.samples[i].gc_pause_time, min_pause); } - dprintf (6666, ("checking if samples are stable %Id %Id %Id, min tcp %.3f, min pause %I64d", + dprintf (6666, ("checking if samples are stable %zd %zd %zd, min tcp %.3f, min pause %" PRIu64, dynamic_heap_count_data.samples[0].gc_survived_size, dynamic_heap_count_data.samples[1].gc_survived_size, dynamic_heap_count_data.samples[2].gc_survived_size, min_tcp, min_pause)); @@ -526,7 +526,7 @@ void gc_heap::calculate_new_heap_count () { dynamic_heap_count_data_t::sample& sample = dynamic_heap_count_data.samples[i]; float diff = (float)(sample.gc_survived_size - min_survived) / (float)min_survived; - dprintf (6666, ("sample %d diff from min is %Id -> %.3f", i, (sample.gc_survived_size - min_survived), diff)); + dprintf (6666, ("sample %d diff from min is %zd -> %.3f", i, (sample.gc_survived_size - min_survived), diff)); if (diff >= 0.15) { survived_stable_p = false; @@ -665,7 +665,7 @@ void gc_heap::calculate_new_heap_count () // We always need to reset these since we already made decisions based on them. dynamic_heap_count_data.reset_accumulation(); - dprintf (6666, ("changing HC or budget %d -> %d at GC#%Id", n_heaps, new_n_heaps, current_gc_index)); + dprintf (6666, ("changing HC or budget %d -> %d at GC#%zd", n_heaps, new_n_heaps, current_gc_index)); dprintf (6666, ("total max gen %.3fmb, total bcd %.3fmb, diff %% %.3f-> +%d hc (%%%.3f)", mb (total_soh_stable_size), mb (total_bcd), diff_pct, change_int, (change_int * 100.0 / n_heaps))); @@ -723,7 +723,7 @@ void gc_heap::calculate_new_heap_count () else if ((median_gen2_tcp < (target_gen2_tcp / 2)) && (num_gen2s_since_last_change > 30)) { new_n_heaps -= step_down; - dprintf (6666, ("[CHP3-0] last gen2 sample count when changed: %Id, gen2 tcp: %.3f, dec by %d, %d -> %d", + dprintf (6666, ("[CHP3-0] last gen2 sample count when changed: %zd, gen2 tcp: %.3f, dec by %d, %d -> %d", dynamic_heap_count_data.gen2_last_changed_sample_count, median_gen2_tcp, step_down, n_heaps, new_n_heaps)); } @@ -739,7 +739,7 @@ void gc_heap::calculate_new_heap_count () if (process_eph_samples_p) { - dprintf (6666, ("processed eph samples, updating processed %Id -> %Id", dynamic_heap_count_data.processed_samples_count, dynamic_heap_count_data.current_samples_count)); + dprintf (6666, ("processed eph samples, updating processed %zd -> %zd", dynamic_heap_count_data.processed_samples_count, dynamic_heap_count_data.current_samples_count)); dynamic_heap_count_data.processed_samples_count = dynamic_heap_count_data.current_samples_count; } @@ -760,14 +760,14 @@ void gc_heap::calculate_new_heap_count () (float)gen2_samples[2].gc_percent); #endif //FEATURE_EVENT_TRACEs - dprintf (6666, ("processed gen2 samples, updating processed %Id -> %Id", dynamic_heap_count_data.processed_gen2_samples_count, dynamic_heap_count_data.current_gen2_samples_count)); + dprintf (6666, ("processed gen2 samples, updating processed %zd -> %zd", dynamic_heap_count_data.processed_gen2_samples_count, dynamic_heap_count_data.current_gen2_samples_count)); dynamic_heap_count_data.processed_gen2_samples_count = dynamic_heap_count_data.current_gen2_samples_count; } #endif //STRESS_DYNAMIC_HEAP_COUNT if (new_n_heaps != n_heaps) { - dprintf (6666, ("GC#%Id should change! %d->%d (%s)", + dprintf (6666, ("GC#%zd should change! %d->%d (%s)", VolatileLoadWithoutBarrier (&settings.gc_index), n_heaps, new_n_heaps, ((n_heaps < new_n_heaps) ? "INC" : "DEC"))); dynamic_heap_count_data.heap_count_to_change_to = new_n_heaps; dynamic_heap_count_data.should_change_heap_count = true; @@ -801,7 +801,7 @@ void gc_heap::check_heap_count () if (dynamic_heap_count_data.new_n_heaps != n_heaps) { - dprintf (6666, ("prep to change from %d to %d at GC#%Id", n_heaps, dynamic_heap_count_data.new_n_heaps, VolatileLoadWithoutBarrier (&settings.gc_index))); + dprintf (6666, ("prep to change from %d to %d at GC#%zd", n_heaps, dynamic_heap_count_data.new_n_heaps, VolatileLoadWithoutBarrier (&settings.gc_index))); if (!prepare_to_change_heap_count (dynamic_heap_count_data.new_n_heaps)) { // we don't have sufficient resources - reset the new heap count @@ -817,7 +817,7 @@ void gc_heap::check_heap_count () dynamic_heap_count_data.processed_gen2_samples_count = dynamic_heap_count_data.current_gen2_samples_count; dynamic_heap_count_data.should_change_heap_count = false; - dprintf (6666, ("heap count stays the same %d, no work to do, set processed sample count to %Id", + dprintf (6666, ("heap count stays the same %d, no work to do, set processed sample count to %zd", dynamic_heap_count_data.new_n_heaps, dynamic_heap_count_data.current_samples_count)); GCToEEInterface::RestartEE(TRUE); @@ -1300,7 +1300,7 @@ bool gc_heap::change_heap_count (int new_n_heaps) new_alloc_per_heap[gen_idx] = Align (total_new_alloc / max_n_heaps, get_alignment_constant (gen_idx <= max_generation)); desired_alloc_per_heap[gen_idx] = Align (total_desired_alloc / max_n_heaps, get_alignment_constant (gen_idx <= max_generation)); size_t allocated_in_budget = total_desired_alloc - total_new_alloc; - dprintf (6666, ("g%d: total budget %zd (%zd / heap), left in budget: %zd (%zd / heap), (allocated %Id, %.3f%%), min %zd", + dprintf (6666, ("g%d: total budget %zd (%zd / heap), left in budget: %zd (%zd / heap), (allocated %zd, %.3f%%), min %zd", gen_idx, total_desired_alloc, desired_alloc_per_heap[gen_idx], total_new_alloc, new_alloc_per_heap[gen_idx], allocated_in_budget, ((double)allocated_in_budget * 100.0 / (double)total_desired_alloc), @@ -1383,7 +1383,7 @@ bool gc_heap::change_heap_count (int new_n_heaps) change_heap_count_time = GetHighPrecisionTimeStamp() - start_time; total_change_heap_count_time += change_heap_count_time; total_change_heap_count++; - dprintf (6666, ("changing HC took %I64dus", change_heap_count_time)); + dprintf (6666, ("changing HC took %" PRIu64 "us", change_heap_count_time)); } return true; @@ -1437,9 +1437,9 @@ void gc_heap::process_datas_sample() (((float)sample.msl_wait_time / n_heaps + sample.gc_pause_time) * 100.0f / (float)sample.elapsed_between_gcs) : 0.0f); size_t total_soh_stable_size = get_total_soh_stable_size(); desired_per_heap_datas = dynamic_heap_count_data.compute_gen0_budget_per_heap (total_soh_stable_size, tcp, desired_per_heap); - dprintf (6666, ("gen0 new_alloc %Id (%.3fmb), from datas: %Id (%.3fmb)", + dprintf (6666, ("gen0 new_alloc %zd (%.3fmb), from datas: %zd (%.3fmb)", desired_per_heap, mb (desired_per_heap), desired_per_heap_datas, mb (desired_per_heap_datas))); - dprintf (6666, ("budget DATAS %Id, previous %Id", desired_per_heap_datas, desired_per_heap)); + dprintf (6666, ("budget DATAS %zd, previous %zd", desired_per_heap_datas, desired_per_heap)); sample.gen0_budget_per_heap = (int)desired_per_heap_datas; if (desired_per_heap_datas != desired_per_heap) @@ -1448,7 +1448,7 @@ void gc_heap::process_datas_sample() assign_new_budget (0, desired_per_heap_datas); } - dprintf (6666, ("sample#%d: %d heaps, this GC end %I64d - last sus end %I64d = %I64d, this GC pause %.3fms, msl wait %I64dus, tcp %.3f, surv %zd, gc speed %.3fmb/ms (%.3fkb/ms/heap)", + dprintf (6666, ("sample#%d: %d heaps, this GC end %" PRIu64 " - last sus end %" PRIu64 " = %" PRIu64 ", this GC pause %.3fms, msl wait %" PRIu64 "us, tcp %.3f, surv %zd, gc speed %.3fmb/ms (%.3fkb/ms/heap)", dynamic_heap_count_data.sample_index, n_heaps, before_distribute_free_regions_time, last_suspended_end_time, sample.elapsed_between_gcs, (sample.gc_pause_time / 1000.0), sample.msl_wait_time, tcp, sample.gc_survived_size, (sample.gc_pause_time ? (sample.gc_survived_size / 1000.0 / sample.gc_pause_time) : 0), @@ -1479,7 +1479,7 @@ void gc_heap::process_datas_sample() g2_sample.gc_percent = (float)gen2_elapsed_time * 100.0f / elapsed_between_gen2_gcs; (dynamic_heap_count_data.current_gen2_samples_count)++; - dprintf (6666, ("gen2 sample#%d: this GC end %I64d - last gen2 end %I64d = %I64d, GC elapsed %I64d, percent %.3f", + dprintf (6666, ("gen2 sample#%d: this GC end %" PRIu64 " - last gen2 end %" PRIu64 " = %zu, GC elapsed %zu, percent %.3f", dynamic_heap_count_data.gen2_sample_index, before_distribute_free_regions_time, prev_gen2_end_time, elapsed_between_gen2_gcs, gen2_elapsed_time, g2_sample.gc_percent)); dynamic_heap_count_data.gen2_sample_index = (dynamic_heap_count_data.gen2_sample_index + 1) % dynamic_heap_count_data_t::sample_size; } @@ -1503,7 +1503,7 @@ void gc_heap::process_datas_sample() void gc_heap::add_to_hc_history_worker (hc_history* hist, int* current_index, hc_record_stage stage, const char* msg) { - dprintf (6666, ("h%d ADDING %s HC hist to entry #%d, stage %d, gc index %Id, last %d, n %d, new %d", + dprintf (6666, ("h%d ADDING %s HC hist to entry #%d, stage %d, gc index %zd, last %d, n %d, new %d", heap_number, msg, *current_index, (int)stage, VolatileLoadWithoutBarrier (&settings.gc_index), dynamic_heap_count_data.last_n_heaps, n_heaps, dynamic_heap_count_data.new_n_heaps)); hc_history* current_hist = &hist[*current_index]; diff --git a/src/runtime/src/coreclr/gc/dynamic_tuning.cpp b/src/runtime/src/coreclr/gc/dynamic_tuning.cpp index d73395fb0f07..3007689f97a0 100644 --- a/src/runtime/src/coreclr/gc/dynamic_tuning.cpp +++ b/src/runtime/src/coreclr/gc/dynamic_tuning.cpp @@ -1376,7 +1376,7 @@ double gc_heap::bgc_tuning::calculate_ml_tuning (uint64_t current_available_phys (size_t)total_physical_mem, (size_t)available_memory_goal, (size_t)current_available_physical, gen2_physical_size, gen3_physical_size)); - dprintf (BGC_TUNING_LOG, ("BTL: Max output: %zd, ER %zd / %zd = %.3f, %s", + dprintf (BGC_TUNING_LOG, ("BTL: Max output: %zd, ER %zd / %" PRIu64 " = %.3f, %s", (size_t)max_output, error, available_memory_goal, error_ratio, (include_in_i_p ? "inc" : "exc"))); @@ -1745,7 +1745,7 @@ void gc_heap::init_static_data() bool gc_heap::init_dynamic_data() { - uint64_t now_raw_ts = RawGetHighPrecisionTimeStamp (); + int64_t now_raw_ts = minipal_hires_ticks (); #ifdef HEAP_BALANCE_INSTRUMENTATION start_raw_ts = now_raw_ts; #endif //HEAP_BALANCE_INSTRUMENTATION @@ -2450,7 +2450,7 @@ void gc_heap::get_and_reset_uoh_alloc_info() hp->uoh_a_bgc_planning[i - uoh_start_generation] = 0; } } - dprintf (2, ("LOH alloc: outside bgc: %zd; bm: %zd; bp: %zd", + dprintf (2, ("LOH alloc: outside bgc: %" PRIu64 "; bm: %" PRIu64 "; bp: %" PRIu64, total_uoh_a_no_bgc, total_uoh_a_bgc_marking, total_uoh_a_bgc_planning)); diff --git a/src/runtime/src/coreclr/gc/env/common.h b/src/runtime/src/coreclr/gc/env/common.h index d356baa598d1..b02e6f537872 100644 --- a/src/runtime/src/coreclr/gc/env/common.h +++ b/src/runtime/src/coreclr/gc/env/common.h @@ -13,6 +13,7 @@ #endif // _CRT_SECURE_NO_WARNINGS #include +#include #include #include #include diff --git a/src/runtime/src/coreclr/gc/env/gcenv.os.h b/src/runtime/src/coreclr/gc/env/gcenv.os.h index 60fa02f0b210..44116483613e 100644 --- a/src/runtime/src/coreclr/gc/env/gcenv.os.h +++ b/src/runtime/src/coreclr/gc/env/gcenv.os.h @@ -10,6 +10,7 @@ using std::nothrow; #include +#include #define NUMA_NODE_UNDEFINED UINT16_MAX @@ -487,25 +488,6 @@ class GCToOSInterface // Break into a debugger static void DebugBreak(); - // - // Time - // - - // Get a high precision performance counter - // Return: - // The counter value - static int64_t QueryPerformanceCounter(); - - // Get a frequency of the high precision performance counter - // Return: - // The counter frequency - static int64_t QueryPerformanceFrequency(); - - // Get a time stamp with a low precision - // Return: - // Time stamp in milliseconds - static uint64_t GetLowPrecisionTimeStamp(); - // Gets the total number of processors on the machine, not taking // into account current process affinity. // Return: diff --git a/src/runtime/src/coreclr/gc/gc.cpp b/src/runtime/src/coreclr/gc/gc.cpp index 68e766a725d2..73195c2f30ab 100644 --- a/src/runtime/src/coreclr/gc/gc.cpp +++ b/src/runtime/src/coreclr/gc/gc.cpp @@ -163,11 +163,6 @@ uint64_t qpf; double qpf_ms; double qpf_us; -uint64_t RawGetHighPrecisionTimeStamp() -{ - return (uint64_t)GCToOSInterface::QueryPerformanceCounter(); -} - #ifdef BGC_SERVO_TUNING bool gc_heap::bgc_tuning::enable_fl_tuning = false; uint32_t gc_heap::bgc_tuning::memory_load_goal = 0; @@ -298,7 +293,7 @@ static unsigned int gc_count_during_log; // In ms. This is how often we print out stats. static const unsigned int log_interval = 5000; // Time (in ms) when we start a new log interval. -static uint64_t log_start_tick; +static int64_t log_start_tick; static unsigned int gc_lock_contended; static int64_t log_start_hires; // Cycles accumulated in SuspendEE during log_interval. @@ -314,11 +309,11 @@ process_sync_log_stats() { #ifdef SYNCHRONIZATION_STATS - uint64_t log_elapsed = GCToOSInterface::GetLowPrecisionTimeStamp() - log_start_tick; + int64_t log_elapsed = minipal_lowres_ticks() - log_start_tick; if (log_elapsed > log_interval) { - uint64_t total = GCToOSInterface::QueryPerformanceCounter() - log_start_hires; + uint64_t total = minipal_hires_ticks() - log_start_hires; // Print out the cycles we spent on average in each suspend and restart. printf("\n_________________________________________________________________________________\n" "Past %d(s): #%3d GCs; Total gc_lock contended: %8u; GC: %12u\n" @@ -490,7 +485,7 @@ enter_msl_status gc_heap::enter_spin_lock_msl_helper (GCSpinLock* msl) #ifdef DYNAMIC_HEAP_COUNT uint64_t end = GetHighPrecisionTimeStamp(); Interlocked::ExchangeAdd64 (&msl->msl_wait_time, end - start); - dprintf (3, ("h%d wait for msl lock wait time %zd, total wait time: %zd", heap_number, (end - start), msl->msl_wait_time)); + dprintf (3, ("h%d wait for msl lock wait time %" PRIu64 ", total wait time: %" PRIu64, heap_number, (end - start), msl->msl_wait_time)); #endif //DYNAMIC_HEAP_COUNT } while (Interlocked::CompareExchange (&msl->lock, lock_taken, lock_free) != lock_free); @@ -1004,7 +999,7 @@ uint64_t gc_heap::total_alloc_bytes_uoh = 0; int gc_heap::gc_policy = 0; -uint64_t gc_heap::allocation_running_time; +int64_t gc_heap::allocation_running_time; size_t gc_heap::allocation_running_amount; @@ -4250,7 +4245,7 @@ gc_heap::verify_free_lists () { // The logic in change_heap_count depends on the coming BGC (or blocking gen 2) to rebuild the gen 2 free list. // In that case, before the rebuild happens, the gen2 free list is expected to contain free list items that do not belong to the right heap. - dprintf (1, ("curr free item %p should be on heap %d, but actually is on heap %d: %d", free_list, this->heap_number, region->heap->heap_number)); + dprintf (1, ("curr free item %p should be on heap %d, but actually is on heap %d", free_list, this->heap_number, region->heap->heap_number)); FATAL_GC_ERROR(); } #endif //USE_REGIONS && MULTIPLE_HEAPS diff --git a/src/runtime/src/coreclr/gc/gc.h b/src/runtime/src/coreclr/gc/gc.h index f36584114787..47e66e22b93e 100644 --- a/src/runtime/src/coreclr/gc/gc.h +++ b/src/runtime/src/coreclr/gc/gc.h @@ -15,6 +15,7 @@ Module Name: #include "gcinterface.h" #include "env/gcenv.os.h" +#include #include "gchandletableimpl.h" @@ -394,7 +395,7 @@ inline bool IsServerHeap() HRESULT initialize_log_file(); void flush_gc_log (bool); -void GCLog (const char *fmt, ... ); +void GCLog (const char *fmt, ... ) MINIPAL_ATTR_FORMAT_PRINTF(1, 2); #define dprintf(l,x) {if ((l == 1) || (l == GTC_LOG)) {GCLog x;}} #define SIMPLE_DPRINTF_ARG(x) , x @@ -482,7 +483,7 @@ void GCLog (const char *fmt, ... ); FILE* CreateLogFile(const GCConfigStringHolder& temp_logfile_name, bool is_config); #endif //TRACE_GC || GC_CONFIG_DRIVEN -void log_init_error_to_host (const char* format, ...); +void log_init_error_to_host (const char* format, ...) MINIPAL_ATTR_FORMAT_PRINTF(1, 2); uint64_t GetHighPrecisionTimeStamp(); diff --git a/src/runtime/src/coreclr/gc/gccommon.cpp b/src/runtime/src/coreclr/gc/gccommon.cpp index 304ee55636b7..e1827fb37b5e 100644 --- a/src/runtime/src/coreclr/gc/gccommon.cpp +++ b/src/runtime/src/coreclr/gc/gccommon.cpp @@ -288,8 +288,8 @@ uint64_t GetHighPrecisionTimeStamp() { if (g_QPFus == 0.0) { - g_QPFus = 1000.0 * 1000.0 / (double)GCToOSInterface::QueryPerformanceFrequency(); + g_QPFus = 1000.0 * 1000.0 / (double)minipal_hires_tick_frequency(); } - return (uint64_t)((double)GCToOSInterface::QueryPerformanceCounter() * g_QPFus); + return (uint64_t)((double)minipal_hires_ticks() * g_QPFus); } #endif // !DACCESS_COMPILE diff --git a/src/runtime/src/coreclr/gc/gcee.cpp b/src/runtime/src/coreclr/gc/gcee.cpp index 1f4095ecb3a3..ec3723fd5e62 100644 --- a/src/runtime/src/coreclr/gc/gcee.cpp +++ b/src/runtime/src/coreclr/gc/gcee.cpp @@ -57,7 +57,7 @@ void GCHeap::UpdatePreGCCounters() #endif //MULTIPLE_HEAPS // Publish perf stats - g_TotalTimeInGC = GCToOSInterface::QueryPerformanceCounter(); + g_TotalTimeInGC = minipal_hires_ticks(); gc_mechanisms *pSettings = &gc_heap::settings; @@ -189,7 +189,7 @@ void GCHeap::UpdatePostGCCounters() #endif // FEATURE_EVENT_TRACE // Compute Time in GC - uint64_t _currentPerfCounterTimer = GCToOSInterface::QueryPerformanceCounter(); + uint64_t _currentPerfCounterTimer = minipal_hires_ticks(); g_TotalTimeInGC = _currentPerfCounterTimer - g_TotalTimeInGC; uint64_t _timeInGCBase = (_currentPerfCounterTimer - g_TotalTimeSinceLastGCEnd); diff --git a/src/runtime/src/coreclr/gc/gcinternal.h b/src/runtime/src/coreclr/gc/gcinternal.h index 20100696d596..8a2ae31dffb9 100644 --- a/src/runtime/src/coreclr/gc/gcinternal.h +++ b/src/runtime/src/coreclr/gc/gcinternal.h @@ -291,7 +291,7 @@ class t_join // remember join id and last thread to arrive so restart can use these int thd; // we want to print statistics every 10 seconds - this is to remember the start of the 10 sec interval - uint64_t start_tick; + int64_t start_tick; // counters for joins, in 1000's of clock cycles uint64_t elapsed_total[gc_join_max], wake_total[gc_join_max], seq_loss_total[gc_join_max], par_loss_total[gc_join_max], in_join_total[gc_join_max]; #endif //JOIN_STATS @@ -325,7 +325,7 @@ class t_join flavor = f; #ifdef JOIN_STATS - start_tick = GCToOSInterface::GetLowPrecisionTimeStamp(); + start_tick = minipal_lowres_ticks(); #endif //JOIN_STATS return TRUE; @@ -405,7 +405,7 @@ class t_join if (dwJoinWait != WAIT_OBJECT_0) { - STRESS_LOG1 (LF_GC, LL_FATALERROR, "joined event wait failed with code: %zx", dwJoinWait); + STRESS_LOG1 (LF_GC, LL_FATALERROR, "joined event wait failed with code: %x", dwJoinWait); FATAL_GC_ERROR (); } } @@ -414,7 +414,7 @@ class t_join if (color == join_struct.lock_color.LoadWithoutBarrier()) { dprintf (9999, ("---h%d %d j%d %d - respin!!! (c:%d-%d)", - gch->heap_number, join_id, join_struct.n_threads, color, join_struct.lock_color.LoadWithoutBarrier())); + gch->heap_number, flavor, join_id, join_struct.n_threads, color, join_struct.lock_color.LoadWithoutBarrier())); goto respin; } @@ -485,7 +485,7 @@ class t_join uint32_t dwJoinWait = join_struct.joined_event[first_thread_arrived].Wait(INFINITE, FALSE); if (dwJoinWait != WAIT_OBJECT_0) { - STRESS_LOG1 (LF_GC, LL_FATALERROR, "joined event wait failed with code: %zx", dwJoinWait); + STRESS_LOG1 (LF_GC, LL_FATALERROR, "joined event wait failed with code: %x", dwJoinWait); FATAL_GC_ERROR (); } } @@ -512,7 +512,7 @@ class t_join #ifdef JOIN_STATS uint64_t get_ts() { - return GCToOSInterface::QueryPerformanceCounter(); + return minipal_hires_ticks(); } void start_ts (gc_heap* gch) @@ -559,7 +559,7 @@ class t_join par_loss_total[id] += par_loss; // every 10 seconds, print a summary of the time spent in each type of join - if (GCToOSInterface::GetLowPrecisionTimeStamp() - start_tick > 10*1000) + if (minipal_lowres_ticks() - start_tick > 10*1000) { printf("**** summary *****\n"); for (int i = 0; i < 16; i++) @@ -573,7 +573,7 @@ class t_join ts_scale*in_join_total[i]); elapsed_total[i] = wake_total[i] = seq_loss_total[i] = par_loss_total[i] = in_join_total[i] = 0; } - start_tick = GCToOSInterface::GetLowPrecisionTimeStamp(); + start_tick = minipal_lowres_ticks(); } #endif //JOIN_STATS @@ -1916,8 +1916,6 @@ extern const size_t low_latency_alloc; extern gc_reason gc_trigger_reason; extern double qpf_us; -uint64_t RawGetHighPrecisionTimeStamp(); - #ifdef WRITE_WATCH #ifdef BACKGROUND_GC extern const size_t ww_reset_quantum; @@ -2351,8 +2349,8 @@ void gc_heap::set_region_plan_gen_num (heap_segment* region, int plan_gen_num, b } planned_regions_per_gen[plan_gen_num]++; - dprintf (REGIONS_LOG, ("h%d g%d %zx(%zx) -> g%d (total %d region planned in g%d)", - heap_number, heap_segment_gen_num (region), (size_t)region, heap_segment_mem (region), plan_gen_num, planned_regions_per_gen[plan_gen_num], plan_gen_num)); + dprintf (REGIONS_LOG, ("h%d g%d %p(%p) -> g%d (total %d region planned in g%d)", + heap_number, heap_segment_gen_num (region), region, heap_segment_mem (region), plan_gen_num, planned_regions_per_gen[plan_gen_num], plan_gen_num)); heap_segment_plan_gen_num (region) = plan_gen_num; @@ -3036,7 +3034,7 @@ size_t gc_heap::generation_unusable_fragmentation (generation* inst, int hn) unusable_frag = fo_space + (condemned_allocated * generation_free_list_space (inst) / total_plan_allocated); } - dprintf (3, ("h%d g%d FLa: %Id, ESa: %Id, Ca: %Id | FO: %Id, FL %Id, fl effi %.3f, unusable fl is %Id", + dprintf (3, ("h%d g%d FLa: %zu, ESa: %zu, Ca: %zu | FO: %zu, FL %zu, fl effi %.3f, unusable fl is %zu", hn, inst->gen_num, generation_free_list_allocated (inst), generation_end_seg_allocated (inst), (size_t)condemned_allocated, fo_space, generation_free_list_space (inst), @@ -3313,7 +3311,7 @@ void gc_heap::record_mark_time (uint64_t& mark_time, { current_mark_time = GetHighPrecisionTimeStamp(); mark_time = limit_time_to_uint32 (current_mark_time - last_mark_time); - dprintf (3, ("%zd - %zd = %zd", + dprintf (3, ("%" PRIu64 " - %" PRIu64 " = %" PRIu64, current_mark_time, last_mark_time, (current_mark_time - last_mark_time))); last_mark_time = current_mark_time; } @@ -3794,7 +3792,7 @@ extern uint32_t bgc_alloc_spin; #define check_msl_status(msg, size) if (msl_status == msl_retry_different_heap) \ { \ - dprintf (5555, ("h%d RETRY %s(%Id)", heap_number, msg, size)); \ + dprintf (5555, ("h%d RETRY %s(%zu)", heap_number, msg, size)); \ return a_state_retry_allocate; \ } diff --git a/src/runtime/src/coreclr/gc/gcpriv.h b/src/runtime/src/coreclr/gc/gcpriv.h index a40cb468873a..e8ce0a41caa7 100644 --- a/src/runtime/src/coreclr/gc/gcpriv.h +++ b/src/runtime/src/coreclr/gc/gcpriv.h @@ -16,6 +16,7 @@ #define inline __forceinline #endif // __GNUC__ +#include #include "gc.h" #include "gcrecord.h" @@ -250,11 +251,11 @@ inline void FATAL_GC_ERROR() #ifdef SYNCHRONIZATION_STATS #define BEGIN_TIMING(x) \ int64_t x##_start; \ - x##_start = GCToOSInterface::QueryPerformanceCounter() + x##_start = minipal_hires_ticks() #define END_TIMING(x) \ int64_t x##_end; \ - x##_end = GCToOSInterface::QueryPerformanceCounter(); \ + x##_end = minipal_hires_ticks(); \ x += x##_end - x##_start #else //SYNCHRONIZATION_STATS @@ -263,7 +264,10 @@ inline void FATAL_GC_ERROR() #endif //SYNCHRONIZATION_STATS #ifdef GC_CONFIG_DRIVEN -void GCLogConfig (const char *fmt, ... ); + +#include + +void GCLogConfig (const char *fmt, ... ) MINIPAL_ATTR_FORMAT_PRINTF(1, 2); #define cprintf(x) {GCLogConfig x;} #endif //GC_CONFIG_DRIVEN @@ -1112,7 +1116,7 @@ struct static_data float fragmentation_burden_limit; float limit; float max_limit; - uint64_t time_clock; // time after which to collect generation, in performance counts (see QueryPerformanceCounter) + uint64_t time_clock; // time after which to collect generation, in performance counts (see minipal_hires_ticks) size_t gc_clock; // number of gcs after which to collect generation }; @@ -3048,7 +3052,7 @@ class gc_heap void print() { - dprintf (3, ("last plug: %Ix, last plug reloc: %Ix, before last: %Ix, b: %Ix", + dprintf (3, ("last plug: %p, last plug reloc: %zx, before last: %p, b: %zx", last_plug, last_plug_relocation, before_last_plug, current_compacted_brick)); } }; @@ -3940,7 +3944,7 @@ class gc_heap #ifdef MULTIPLE_HEAPS #else //MULTIPLE_HEAPS // Used in the allocator code paths to decide if we should trigger GCs - PER_HEAP_FIELD_ALLOC uint64_t allocation_running_time; + PER_HEAP_FIELD_ALLOC int64_t allocation_running_time; PER_HEAP_FIELD_ALLOC size_t allocation_running_amount; #endif //MULTIPLE_HEAPS @@ -4490,7 +4494,7 @@ class gc_heap if (adj->metric == adjust_budget) { (adj->count)++; - dprintf (6666, ("last adjustment was also budget at GC#%Id, inc count to %d", adj->gc_index, adj->count)); + dprintf (6666, ("last adjustment was also budget at GC#%zd, inc count to %d", adj->gc_index, adj->count)); return; } } @@ -4502,7 +4506,7 @@ class gc_heap adj->hc_change = change_int; adj->gc_index = current_gc_index; - dprintf (6666, ("recording adjustment %s at #%d GC#%Id - distance to target %.3f, changed %d HC", + dprintf (6666, ("recording adjustment %s at #%d GC#%zd - distance to target %.3f, changed %d HC", str_adjust_metrics[metric], current_adjustment_index, adj->gc_index, adj->distance, adj->hc_change)); current_adjustment_index = (current_adjustment_index + 1) % recorded_adjustment_size; @@ -4712,7 +4716,7 @@ class gc_heap bool check_p = (current_gc_index < (last_changed_gc_index + (2 * sample_size))); - dprintf (6666, ("last adjusted at GC#%Id, %Id GCs ago, %s", + dprintf (6666, ("last adjusted at GC#%zd, %zd GCs ago, %s", last_changed_gc_index, (current_gc_index - last_changed_gc_index), (check_p ? "check success" : "already checked success"))); if (!check_p) { @@ -4775,11 +4779,11 @@ class gc_heap *current_around_target_accumulation = around_target_accumulation; *num_gcs_since_last_change = current_gc_index - last_changed_gc_index; - dprintf (6666, ("we adjusted at GC#%Id, %Id GCs ago", last_changed_gc_index, *num_gcs_since_last_change)); + dprintf (6666, ("we adjusted at GC#%zd, %zd GCs ago", last_changed_gc_index, *num_gcs_since_last_change)); if (last_changed_gc_index && (*num_gcs_since_last_change < (2 * sample_size))) { *change_decision = decide_change_condition::too_few_samples; - dprintf (6666, ("we just adjusted %Id GCs ago, skipping", *num_gcs_since_last_change)); + dprintf (6666, ("we just adjusted %zd GCs ago, skipping", *num_gcs_since_last_change)); return false; } @@ -4899,9 +4903,9 @@ class gc_heap *reason = hc_change_freq_reason::expensive_hc_change; } - dprintf (6666, ("last HC change took %.3fms / avg gc pause %.3fms = %d , factor %d", + dprintf (6666, ("last HC change took %.3fms / avg gc pause %.3fms = %lu , factor %d", (change_heap_count_time / 1000.0), (avg_gc_pause_time / 1000.0), - (change_heap_count_time / avg_gc_pause_time), factor)); + (unsigned long)(change_heap_count_time / avg_gc_pause_time), factor)); } if (change_int < 0) @@ -4913,7 +4917,7 @@ class gc_heap adjustment* adj = get_last_adjustment(); int last_hc_change = adj->hc_change; - dprintf (6666, ("dec: last HC change %d heaps at GC#%Id, factor %d", last_hc_change, last_change_gc_index, factor)); + dprintf (6666, ("dec: last HC change %d heaps at GC#%zd, factor %d", last_hc_change, last_change_gc_index, factor)); if (last_hc_change < 0) { @@ -4931,7 +4935,7 @@ class gc_heap if (last_2nd_change_gc_index > 0) { int last_2nd_hc_change = adj->hc_change; - dprintf (6666, ("before last was %d heaps at GC#%Id (%Id GCs), factor is now %d", + dprintf (6666, ("before last was %d heaps at GC#%zd (%zd GCs), factor is now %d", last_2nd_hc_change, last_2nd_change_gc_index, (last_change_gc_index - last_2nd_change_gc_index), factor)); if (last_2nd_hc_change < 0) @@ -5047,7 +5051,7 @@ class gc_heap count = adj->count; } - dprintf (6666, ("we've changed budget instead of HC %d times from %Id GCs ago, thres %d times", + dprintf (6666, ("we've changed budget instead of HC %d times from %zd GCs ago, thres %d times", count, num_gcs_since_change, delayed_hc_change_freq_factor)); if (count < delayed_hc_change_freq_factor) @@ -5059,7 +5063,7 @@ class gc_heap else { bool change_p = (num_gcs_since_change > (size_t)(*hc_change_freq_factor * sample_size)); - dprintf (6666, ("It's been %Id GCs since we changed last time, thres %d GCs, %s", + dprintf (6666, ("It's been %zd GCs since we changed last time, thres %d GCs, %s", num_gcs_since_change, (*hc_change_freq_factor * sample_size), (change_p ? "change" : "don't change yet"))); if (!change_p) { @@ -5103,7 +5107,7 @@ class gc_heap gen0_growth_soh_ratio = max ((double)gen0_growth_soh_ratio_min, gen0_growth_soh_ratio); size_t total_new_allocation_old_gen = (size_t)(gen0_growth_soh_ratio * (double)total_soh_stable_size); - dprintf (6666, ("stable soh %Id (%.3fmb), factor %.3f=>%.3f -> total gen0 new_alloc %Id (%.3fmb)", + dprintf (6666, ("stable soh %zd (%.3fmb), factor %.3f=>%.3f -> total gen0 new_alloc %zd (%.3fmb)", total_soh_stable_size, ((double)total_soh_stable_size / 1000.0 / 1000.0), saved_gen0_growth_soh_ratio, gen0_growth_soh_ratio, total_new_allocation_old_gen, ((double)total_new_allocation_old_gen / 1000.0 / 1000.0))); @@ -5124,7 +5128,7 @@ class gc_heap budget_old_gen_per_heap = min (max_gen0_new_allocation, budget_old_gen_per_heap); budget_old_gen_per_heap = max (min_gen0_new_allocation, budget_old_gen_per_heap); - dprintf (6666, ("BCD: %Id/heap (%.3fmb) -> %.3fmb, BCS %Id/heap (%.3fmb)", + dprintf (6666, ("BCD: %zd/heap (%.3fmb) -> %.3fmb, BCS %zd/heap (%.3fmb)", saved_budget_old_gen_per_heap, ((double)saved_budget_old_gen_per_heap / 1000.0 / 1000.0), ((double)budget_old_gen_per_heap / 1000.0 / 1000.0), bcs_per_heap, ((double)bcs_per_heap / 1000.0 / 1000.0))); @@ -5149,7 +5153,7 @@ class gc_heap last_changed_gc_index++; } - dprintf (6666, ("last gc gen0 budget %Id, last adjustment %s was at GC#%Id, last BGC was #%Id, this GC #%Id, %s", + dprintf (6666, ("last gc gen0 budget %zd, last adjustment %s was at GC#%zd, last BGC was #%zd, this GC #%zd, %s", last_budget_per_heap, str_adjust_metrics[adj->metric], saved_last_changed_gc_index, last_bgc_index, current_gc_index, ((last_changed_gc_index < (current_gc_index - 1)) ? "didn't just change" : "did just change"))); @@ -5177,7 +5181,7 @@ class gc_heap new_budget_per_heap = max (new_budget_per_heap, bcs_per_heap); new_budget_per_heap = min (new_budget_per_heap, budget_old_gen_per_heap); - dprintf (6666, ("adjust last budget %Id to %Id->%Id (%.3fmb)", + dprintf (6666, ("adjust last budget %zd to %zd->%zd (%.3fmb)", last_budget_per_heap, saved_new_budget_per_heap, new_budget_per_heap, (new_budget_per_heap / 1000.0 / 1000.0))); return new_budget_per_heap; @@ -5185,7 +5189,7 @@ class gc_heap } } - dprintf (6666, ("taking min of the two: %Id, %Id", bcs_per_heap, budget_old_gen_per_heap)); + dprintf (6666, ("taking min of the two: %zd, %zd", bcs_per_heap, budget_old_gen_per_heap)); return min (bcs_per_heap, budget_old_gen_per_heap); } diff --git a/src/runtime/src/coreclr/gc/handletable.cpp b/src/runtime/src/coreclr/gc/handletable.cpp index 356b0e0bdc31..b13e881ba848 100644 --- a/src/runtime/src/coreclr/gc/handletable.cpp +++ b/src/runtime/src/coreclr/gc/handletable.cpp @@ -11,6 +11,7 @@ */ #include "common.h" +#include #include "gcenv.h" @@ -1125,14 +1126,14 @@ void DEBUG_LogScanningStatistics(HandleTable *pTable, uint32_t level) // dump the generation number and the number of blocks scanned LOG((LF_GC, level, "--------------------------------------------------------------\n")); LOG((LF_GC, level, " Condemned Generation = %d\n", i)); - LOG((LF_GC, level, " Blocks Scanned = %llu\n", totalBlocksScanned)); + LOG((LF_GC, level, " Blocks Scanned = %" PRId64 "\n", totalBlocksScanned)); // if we scanned any blocks in this generation then dump some interesting numbers if (totalBlocksScanned) { - LOG((LF_GC, level, " Blocks Examined = %llu\n", pTable->_DEBUG_TotalBlocksScannedNonTrivially[i])); - LOG((LF_GC, level, " Slots Scanned = %llu\n", pTable->_DEBUG_TotalHandleSlotsScanned [i])); - LOG((LF_GC, level, " Handles Scanned = %llu\n", pTable->_DEBUG_TotalHandlesActuallyScanned [i])); + LOG((LF_GC, level, " Blocks Examined = %" PRId64 "\n", pTable->_DEBUG_TotalBlocksScannedNonTrivially[i])); + LOG((LF_GC, level, " Slots Scanned = %" PRId64 "\n", pTable->_DEBUG_TotalHandleSlotsScanned [i])); + LOG((LF_GC, level, " Handles Scanned = %" PRId64 "\n", pTable->_DEBUG_TotalHandlesActuallyScanned [i])); double blocksScanned = (double) totalBlocksScanned; double blocksExamined = (double) pTable->_DEBUG_TotalBlocksScannedNonTrivially[i]; diff --git a/src/runtime/src/coreclr/gc/init.cpp b/src/runtime/src/coreclr/gc/init.cpp index 6a55b60ec150..eef1ccbafd3c 100644 --- a/src/runtime/src/coreclr/gc/init.cpp +++ b/src/runtime/src/coreclr/gc/init.cpp @@ -308,12 +308,12 @@ void gc_heap::gc_thread_function () wait_time = min (wait_time, (uint32_t)(sample.elapsed_between_gcs / 1000 / 3)); wait_time = max (wait_time, 1u); - dprintf (6666, ("gc#0 thread waiting for %d ms (betwen GCs %I64d)", wait_time, sample.elapsed_between_gcs)); + dprintf (6666, ("gc#0 thread waiting for %d ms (betwen GCs %" PRIu64 ")", wait_time, sample.elapsed_between_gcs)); } #endif //DYNAMIC_HEAP_COUNT uint32_t wait_result = gc_heap::ee_suspend_event.Wait(wait_on_time_out_p ? wait_time : INFINITE, FALSE); #ifdef DYNAMIC_HEAP_COUNT - dprintf (9999, ("waiting for ee done res %d (timeout %d, %I64d ms since last suspend end)(should_change_heap_count is %d) (gradual_decommit_in_progress_p %d)", + dprintf (9999, ("waiting for ee done res %d (timeout %d, %" PRIu64 " ms since last suspend end)(should_change_heap_count is %d) (gradual_decommit_in_progress_p %d)", wait_result, wait_time, ((GetHighPrecisionTimeStamp() - last_suspended_end_time) / 1000), dynamic_heap_count_data.should_change_heap_count, gradual_decommit_in_progress_p)); #endif //DYNAMIC_HEAP_COUNT @@ -414,10 +414,10 @@ void gc_heap::gc_thread_function () } else { - dprintf (9999, ("GC thread %d waiting_for_gc_start(%d)(gc%Id)", heap_number, n_heaps, VolatileLoadWithoutBarrier(&settings.gc_index))); + dprintf (9999, ("GC thread %d waiting_for_gc_start(%d)(gc%zd)", heap_number, n_heaps, VolatileLoadWithoutBarrier(&settings.gc_index))); gc_start_event.Wait(INFINITE, FALSE); #ifdef DYNAMIC_HEAP_COUNT - dprintf (9999, ("GC thread %d waiting_done_gc_start(%d-%d)(i: %d)(gc%Id)", + dprintf (9999, ("GC thread %d waiting_done_gc_start(%d-%d)(i: %d)(gc%zd)", heap_number, n_heaps, dynamic_heap_count_data.new_n_heaps, dynamic_heap_count_data.init_only_p, VolatileLoadWithoutBarrier (&settings.gc_index))); if ((gc_heap::dynamic_adaptation_mode == dynamic_adaptation_to_application_sizes) && @@ -449,10 +449,10 @@ void gc_heap::gc_thread_function () Interlocked::Increment (&dynamic_heap_count_data.idle_thread_count); add_to_hc_history (hc_record_became_inactive); - dprintf (9999, ("GC thread %d wait_on_idle(%d < %d)(gc%Id), total idle %d", heap_number, old_n_heaps, new_n_heaps, + dprintf (9999, ("GC thread %d wait_on_idle(%d < %d)(gc%zd), total idle %d", heap_number, old_n_heaps, new_n_heaps, VolatileLoadWithoutBarrier (&settings.gc_index), VolatileLoadWithoutBarrier (&dynamic_heap_count_data.idle_thread_count))); gc_idle_thread_event.Wait (INFINITE, FALSE); - dprintf (9999, ("GC thread %d waking_from_idle(%d)(gc%Id) after doing change", heap_number, n_heaps, VolatileLoadWithoutBarrier (&settings.gc_index))); + dprintf (9999, ("GC thread %d waking_from_idle(%d)(gc%zd) after doing change", heap_number, n_heaps, VolatileLoadWithoutBarrier (&settings.gc_index))); } } else @@ -465,10 +465,10 @@ void gc_heap::gc_thread_function () { Interlocked::Increment (&dynamic_heap_count_data.idle_thread_count); add_to_hc_history (hc_record_inactive_waiting); - dprintf (9999, ("GC thread %d wait_on_idle(< max %d)(gc%Id), total idle %d", heap_number, num_threads_to_wake, + dprintf (9999, ("GC thread %d wait_on_idle(< max %d)(gc%zd), total idle %d", heap_number, num_threads_to_wake, VolatileLoadWithoutBarrier (&settings.gc_index), VolatileLoadWithoutBarrier (&dynamic_heap_count_data.idle_thread_count))); gc_idle_thread_event.Wait (INFINITE, FALSE); - dprintf (9999, ("GC thread %d waking_from_idle(%d)(gc%Id)", heap_number, n_heaps, VolatileLoadWithoutBarrier (&settings.gc_index))); + dprintf (9999, ("GC thread %d waking_from_idle(%d)(gc%zd)", heap_number, n_heaps, VolatileLoadWithoutBarrier (&settings.gc_index))); } continue; @@ -1210,7 +1210,7 @@ size_t gc_heap::get_gen0_min_size() } #endif //DYNAMIC_HEAP_COUNT - dprintf (1, ("gen0size: %zd * %d = %zd, physical mem: %zd / 6 = %zd", + dprintf (1, ("gen0size: %zu * %d = %zu, physical mem: %" PRIu64 " / 6 = %" PRIu64, gen0size, n_heaps, (gen0size * n_heaps), gc_heap::total_physical_mem, gc_heap::total_physical_mem / 6)); diff --git a/src/runtime/src/coreclr/gc/interface.cpp b/src/runtime/src/coreclr/gc/interface.cpp index 2debd70cdcd5..871c84ee737a 100644 --- a/src/runtime/src/coreclr/gc/interface.cpp +++ b/src/runtime/src/coreclr/gc/interface.cpp @@ -81,8 +81,8 @@ init_sync_log_stats() gc_during_log = 0; gc_lock_contended = 0; - log_start_tick = GCToOSInterface::GetLowPrecisionTimeStamp(); - log_start_hires = GCToOSInterface::QueryPerformanceCounter(); + log_start_tick = minipal_lowres_ticks(); + log_start_hires = minipal_hires_ticks(); } gc_count_during_log++; #endif //SYNCHRONIZATION_STATS @@ -204,11 +204,11 @@ HRESULT GCHeap::Init(size_t hn) HRESULT GCHeap::Initialize() { #ifndef TRACE_GC - STRESS_LOG_VA (1, (ThreadStressLog::gcLoggingIsOffMsg())); + STRESS_LOG0 (LF_GC, LL_ALWAYS, "TraceGC is not turned on"); #endif HRESULT hr = S_OK; - qpf = (uint64_t)GCToOSInterface::QueryPerformanceFrequency(); + qpf = (uint64_t)minipal_hires_tick_frequency(); qpf_ms = 1000.0 / (double)qpf; qpf_us = 1000.0 * 1000.0 / (double)qpf; @@ -734,7 +734,7 @@ HRESULT GCHeap::Initialize() if (gc_heap::dynamic_heap_count_data.gen0_growth_soh_ratio_min > gc_heap::dynamic_heap_count_data.gen0_growth_soh_ratio_max) { - log_init_error_to_host ("DATAS min permil for gen0 growth %d is greater than max %d, it needs to be lower", + log_init_error_to_host ("DATAS min permil for gen0 growth %.3f is greater than max %.3f, it needs to be lower", gc_heap::dynamic_heap_count_data.gen0_growth_soh_ratio_min, gc_heap::dynamic_heap_count_data.gen0_growth_soh_ratio_max); return E_FAIL; } @@ -743,7 +743,7 @@ HRESULT GCHeap::Initialize() GCConfig::SetGCDGen0GrowthPercent ((int)(gc_heap::dynamic_heap_count_data.gen0_growth_soh_ratio_percent * 100.0f)); GCConfig::SetGCDGen0GrowthMinFactor ((int)(gc_heap::dynamic_heap_count_data.gen0_growth_soh_ratio_min * 1000.0f)); GCConfig::SetGCDGen0GrowthMaxFactor ((int)(gc_heap::dynamic_heap_count_data.gen0_growth_soh_ratio_max * 1000.0f)); - dprintf (6666, ("DATAS gen0 growth multiplier will be adjusted by %d%%, cap %.3f-%.3f, min budget %Id, max %Id", + dprintf (6666, ("DATAS gen0 growth multiplier will be adjusted by %d%%, cap %.3f-%.3f, min budget %zd, max %zd", (int)GCConfig::GetGCDGen0GrowthPercent(), gc_heap::dynamic_heap_count_data.gen0_growth_soh_ratio_min, gc_heap::dynamic_heap_count_data.gen0_growth_soh_ratio_max, gc_heap::dynamic_heap_count_data.min_gen0_new_allocation, gc_heap::dynamic_heap_count_data.max_gen0_new_allocation)); diff --git a/src/runtime/src/coreclr/gc/mark_phase.cpp b/src/runtime/src/coreclr/gc/mark_phase.cpp index 769126a32112..f8562f479724 100644 --- a/src/runtime/src/coreclr/gc/mark_phase.cpp +++ b/src/runtime/src/coreclr/gc/mark_phase.cpp @@ -1156,7 +1156,8 @@ void gc_heap::equalize_promoted_bytes(int condemned_gen_number) } } assert (start_region); - dprintf (3, ("making sure heap %d gen %d has at least one region by adding region %zx", start_region)); + dprintf (3, ("making sure heap %d gen %d has at least one region by adding region %p", + hp->heap_number, gen_idx, start_region)); heap_segment_next (start_region) = nullptr; assert (heap_segment_heap (start_region) == nullptr && hp != nullptr); @@ -1980,7 +1981,7 @@ gc_heap::mark_steal() #ifdef SNOOP_STATS dprintf (SNOOP_LOG, ("(GC%d)heap%d: start snooping %d", settings.gc_index, heap_number, (heap_number+1)%n_heaps)); - uint64_t begin_tick = GCToOSInterface::GetLowPrecisionTimeStamp(); + int64_t begin_tick = minipal_lowres_ticks(); #endif //SNOOP_STATS int idle_loop_count = 0; @@ -2080,18 +2081,18 @@ gc_heap::mark_steal() { #ifdef SNOOP_STATS - dprintf (SNOOP_LOG, ("heap%d: marking %zx from %d [%d] tl:%dms", + dprintf (SNOOP_LOG, ("heap%d: marking %zx from %d [%d] tl:%I64dms", heap_number, (size_t)o, (heap_number+1)%n_heaps, level, - (GCToOSInterface::GetLowPrecisionTimeStamp()-begin_tick))); - uint64_t start_tick = GCToOSInterface::GetLowPrecisionTimeStamp(); + (minipal_lowres_ticks()-begin_tick))); + int64_t start_tick = minipal_lowres_ticks(); #endif //SNOOP_STATS mark_object_simple1 (o, start, heap_number); #ifdef SNOOP_STATS - dprintf (SNOOP_LOG, ("heap%d: done marking %zx from %d [%d] %dms tl:%dms", + dprintf (SNOOP_LOG, ("heap%d: done marking %zx from %d [%d] %I64dms tl:%I64dms", heap_number, (size_t)o, (heap_number+1)%n_heaps, level, - (GCToOSInterface::GetLowPrecisionTimeStamp()-start_tick),(GCToOSInterface::GetLowPrecisionTimeStamp()-begin_tick))); + (minipal_lowres_ticks()-start_tick),(minipal_lowres_ticks()-begin_tick))); #endif //SNOOP_STATS mark_stack_busy() = 0; diff --git a/src/runtime/src/coreclr/gc/no_gc.cpp b/src/runtime/src/coreclr/gc/no_gc.cpp index dfcc281e6412..17c2f381d47f 100644 --- a/src/runtime/src/coreclr/gc/no_gc.cpp +++ b/src/runtime/src/coreclr/gc/no_gc.cpp @@ -843,7 +843,7 @@ void gc_heap::allocate_for_no_gc_after_gc() enable_no_gc_region_callback_status gc_heap::enable_no_gc_callback(NoGCRegionCallbackFinalizerWorkItem* callback, uint64_t callback_threshold) { - dprintf(1, ("[no_gc_callback] calling enable_no_gc_callback with callback_threshold = %llu\n", callback_threshold)); + dprintf(1, ("[no_gc_callback] calling enable_no_gc_callback with callback_threshold = %" PRIu64 "\n", callback_threshold)); enable_no_gc_region_callback_status status = enable_no_gc_region_callback_status::succeed; suspend_EE(); { @@ -898,12 +898,12 @@ enable_no_gc_region_callback_status gc_heap::enable_no_gc_callback(NoGCRegionCal #endif if (dd_new_allocation (hp->dynamic_data_of (soh_gen0)) <= (ptrdiff_t)soh_withheld_budget) { - dprintf(1, ("[no_gc_callback] failed because of running out of soh budget= %llu\n", soh_withheld_budget)); + dprintf(1, ("[no_gc_callback] failed because of running out of soh budget= %zu\n", soh_withheld_budget)); status = insufficient_budget; } if (dd_new_allocation (hp->dynamic_data_of (loh_generation)) <= (ptrdiff_t)loh_withheld_budget) { - dprintf(1, ("[no_gc_callback] failed because of running out of loh budget= %llu\n", loh_withheld_budget)); + dprintf(1, ("[no_gc_callback] failed because of running out of loh budget= %zu\n", loh_withheld_budget)); status = insufficient_budget; } } diff --git a/src/runtime/src/coreclr/gc/objecthandle.cpp b/src/runtime/src/coreclr/gc/objecthandle.cpp index 756dd52411f9..92fd6889c87d 100644 --- a/src/runtime/src/coreclr/gc/objecthandle.cpp +++ b/src/runtime/src/coreclr/gc/objecthandle.cpp @@ -278,8 +278,8 @@ void CALLBACK ClearDependentHandle(_UNCHECKED_OBJECTREF *pObjRef, uintptr_t *pEx if (!g_theGCHeap->IsPromoted(*pPrimaryRef)) { - LOG((LF_GC, LL_INFO1000, "\tunreachable ", LOG_OBJECT_CLASS(*pPrimaryRef))); - LOG((LF_GC, LL_INFO1000, "\tunreachable ", LOG_OBJECT_CLASS(*pSecondaryRef))); + LOG((LF_GC, LL_INFO1000, "\tunreachable " LOG_OBJECT_CLASS(*pPrimaryRef))); + LOG((LF_GC, LL_INFO1000, "\tunreachable " LOG_OBJECT_CLASS(*pSecondaryRef))); *pPrimaryRef = NULL; *pSecondaryRef = NULL; } diff --git a/src/runtime/src/coreclr/gc/plan_phase.cpp b/src/runtime/src/coreclr/gc/plan_phase.cpp index 1e18354bebb6..b680194045e2 100644 --- a/src/runtime/src/coreclr/gc/plan_phase.cpp +++ b/src/runtime/src/coreclr/gc/plan_phase.cpp @@ -703,12 +703,12 @@ bool gc_heap::try_get_new_free_region() bool gc_heap::init_table_for_region (int gen_number, heap_segment* region) { #ifdef BACKGROUND_GC - dprintf (GC_TABLE_LOG, ("new seg %Ix, mark_array is %Ix", + dprintf (GC_TABLE_LOG, ("new seg %p, mark_array is %p", heap_segment_mem (region), mark_array)); if (((region->flags & heap_segment_flags_ma_committed) == 0) && !commit_mark_array_new_seg (__this, region)) { - dprintf (GC_TABLE_LOG, ("failed to commit mark array for the new region %Ix-%Ix", + dprintf (GC_TABLE_LOG, ("failed to commit mark array for the new region %p-%p", get_region_start (region), heap_segment_reserved (region))); // We don't have memory to commit the mark array so we cannot use the new region. @@ -1624,8 +1624,9 @@ void gc_heap::merge_fl_from_other_heaps (int gen_idx, int to_n_heaps, int from_n uint64_t elapsed = GetHighPrecisionTimeStamp () - start_us; - dprintf (8888, ("rethreaded %Id items, merging took %I64dus (%I64dms)", - total_num_fl_items_rethreaded_stage2, elapsed, (elapsed / 1000))); + dprintf (8888, ("rethreaded %zu items, merging took %lluus (%llums)", + total_num_fl_items_rethreaded_stage2, static_cast(elapsed), + static_cast(elapsed / 1000))); #endif //_DEBUG for (int hn = 0; hn < to_n_heaps; hn++) @@ -1690,7 +1691,7 @@ void gc_heap::merge_fl_from_other_heaps (int gen_idx, int to_n_heaps, int from_n total_fl_items_for_oh_count += fl_items_for_oh_count; } - dprintf (8888, ("total %Id fl items, %Id are for other heaps", + dprintf (8888, ("total %zu fl items, %zu are for other heaps", total_fl_items_count, total_fl_items_for_oh_count)); if (total_fl_items_for_oh_count) @@ -2223,7 +2224,7 @@ uint8_t* gc_heap::loh_allocate_in_condemned (size_t size) generation_allocation_pointer (gen)))) { LOG((LF_GC, LL_INFO10, "remaining pinned plug %zx while leaving segment on allocation", - pinned_plug (loh_oldest_pin()))); + (size_t)pinned_plug (loh_oldest_pin()))); dprintf (1, ("queue empty: %d", loh_pinned_plug_que_empty_p())); FATAL_GC_ERROR(); } @@ -2613,7 +2614,7 @@ void gc_heap::decide_on_demotion_pin_surv (heap_segment* region, int* no_pinned_ if (pinned_surv == 0) { (*no_pinned_surv_region_count)++; - dprintf (REGIONS_LOG, ("h%d gen%d region %Ix will be empty", heap_number, heap_segment_gen_num (region), heap_segment_mem (region))); + dprintf (REGIONS_LOG, ("h%d gen%d region %p will be empty", heap_number, heap_segment_gen_num (region), heap_segment_mem (region))); } else { @@ -2654,7 +2655,7 @@ void gc_heap::process_last_np_surv_region (generation* consing_gen, assert ((consing_gen_alloc_ptr >= heap_segment_mem (alloc_region)) && (consing_gen_alloc_ptr <= heap_segment_reserved (alloc_region))); - dprintf (REGIONS_LOG, ("h%d PLN: (%s) plan gen%d->%d, consing alloc region: %p, ptr: %p (%Id) (consing gen: %d)", + dprintf (REGIONS_LOG, ("h%d PLN: (%s) plan gen%d->%d, consing alloc region: %p, ptr: %p (%td) (consing gen: %d)", heap_number, (settings.promotion ? "promotion" : "no promotion"), current_plan_gen_num, next_plan_gen_num, heap_segment_mem (alloc_region), generation_allocation_pointer (consing_gen), @@ -2779,7 +2780,7 @@ void gc_heap::process_remaining_regions (int current_plan_gen_num, generation* c assert (pinned_plug_que_empty_p ()); if (!pinned_plug_que_empty_p ()) { - dprintf (REGIONS_LOG, ("we still have a pin at %Ix but no more regions!?", pinned_plug (oldest_pin ()))); + dprintf (REGIONS_LOG, ("we still have a pin at %p but no more regions!?", pinned_plug (oldest_pin ()))); GCToOSInterface::DebugBreak (); } @@ -2822,7 +2823,7 @@ void gc_heap::process_remaining_regions (int current_plan_gen_num, generation* c dprintf (REGIONS_LOG, ("h%d planned regions in g2: %d, g1: %d, g0: %d, before processing remaining regions", heap_number, planned_regions_per_gen[2], planned_regions_per_gen[1], planned_regions_per_gen[0])); - dprintf (REGIONS_LOG, ("h%d g2: surv %Id(p: %Id, %.2f%%), g1: surv %Id(p: %Id, %.2f%%), g0: surv %Id(p: %Id, %.2f%%)", + dprintf (REGIONS_LOG, ("h%d g2: surv %zu(p: %zu, %.2f%%), g1: surv %zu(p: %zu, %.2f%%), g0: surv %zu(p: %zu, %.2f%%)", heap_number, dd_survived_size (dynamic_data_of (2)), dd_pinned_survived_size (dynamic_data_of (2)), (dd_survived_size (dynamic_data_of (2)) ? ((double)dd_pinned_survived_size (dynamic_data_of (2)) * 100.0 / (double)dd_survived_size (dynamic_data_of (2))) : 0), @@ -3065,7 +3066,7 @@ void gc_heap::process_remaining_regions (int current_plan_gen_num, generation* c if (plan_regions_needed > 0) { dprintf (REGIONS_LOG, ("h%d %d regions short for having at least one region per gen, special sweep on", - heap_number)); + heap_number, plan_regions_needed)); special_sweep_p = true; } } @@ -3622,7 +3623,7 @@ void gc_heap::plan_phase (int condemned_gen_number) { #ifdef USE_REGIONS regions_per_gen[condemned_gen_index1]++; - dprintf (REGIONS_LOG, ("h%d PS: gen%d %p-%p (%d, surv: %d), %d regions", + dprintf (REGIONS_LOG, ("h%d PS: gen%d %p-%p (%td, surv: %d), %d regions", heap_number, condemned_gen_index1, heap_segment_mem (seg2), heap_segment_allocated (seg2), (heap_segment_allocated (seg2) - heap_segment_mem (seg2)), @@ -5863,7 +5864,7 @@ bool gc_heap::should_sweep_in_plan (heap_segment* region) assert (heap_segment_gen_num (region) == heap_segment_plan_gen_num (region)); uint8_t surv_ratio = (uint8_t)(((double)heap_segment_survived (region) * 100.0) / (double)basic_region_size); - dprintf (2222, ("SSIP: region %p surv %hu / %zd = %d%%(%d)", + dprintf (2222, ("SSIP: region %p surv %zu / %zu = %d%%(%d)", heap_segment_mem (region), heap_segment_survived (region), basic_region_size, @@ -6042,7 +6043,7 @@ void gc_heap::sweep_region_in_plan (heap_segment* region, #ifdef _DEBUG size_t region_index = get_basic_region_index_for_address (heap_segment_mem (region)); - dprintf (REGIONS_LOG, ("region #%zd %p survived %zd, %s recorded %d", + dprintf (REGIONS_LOG, ("region #%zu %p survived %zu, %s recorded %zu", region_index, heap_segment_mem (region), survived, ((survived == heap_segment_survived (region)) ? "same as" : "diff from"), heap_segment_survived (region))); diff --git a/src/runtime/src/coreclr/gc/unix/gcenv.unix.cpp b/src/runtime/src/coreclr/gc/unix/gcenv.unix.cpp index 16633799ab5f..6625a4bd70bc 100644 --- a/src/runtime/src/coreclr/gc/unix/gcenv.unix.cpp +++ b/src/runtime/src/coreclr/gc/unix/gcenv.unix.cpp @@ -6,7 +6,6 @@ #include #include #include -#define __STDC_FORMAT_MACROS #include #include #include @@ -1278,31 +1277,6 @@ void GCToOSInterface::GetMemoryStatus(uint64_t restricted_limit, uint32_t* memor *available_page_file = GetAvailablePageFile(); } -// Get a high precision performance counter -// Return: -// The counter value -int64_t GCToOSInterface::QueryPerformanceCounter() -{ - return minipal_hires_ticks(); -} - -// Get a frequency of the high precision performance counter -// Return: -// The counter frequency -int64_t GCToOSInterface::QueryPerformanceFrequency() -{ - // The counter frequency of gettimeofday is in microseconds. - return minipal_hires_tick_frequency(); -} - -// Get a time stamp with a low precision -// Return: -// Time stamp in milliseconds -uint64_t GCToOSInterface::GetLowPrecisionTimeStamp() -{ - return (uint64_t)minipal_lowres_ticks(); -} - // Gets the total number of processors on the machine, not taking // into account current process affinity. // Return: diff --git a/src/runtime/src/coreclr/gc/wasm/gcenv.cpp b/src/runtime/src/coreclr/gc/wasm/gcenv.cpp index 2b64b6143540..e8fe0c3fcafc 100644 --- a/src/runtime/src/coreclr/gc/wasm/gcenv.cpp +++ b/src/runtime/src/coreclr/gc/wasm/gcenv.cpp @@ -389,25 +389,6 @@ void GCToOSInterface::GetMemoryStatus(uint64_t restricted_limit, uint32_t* memor *available_page_file = 0; // No page file on wasm } -// ============================================================================ -// Time -// ============================================================================ - -int64_t GCToOSInterface::QueryPerformanceCounter() -{ - return minipal_hires_ticks(); -} - -int64_t GCToOSInterface::QueryPerformanceFrequency() -{ - return minipal_hires_tick_frequency(); -} - -uint64_t GCToOSInterface::GetLowPrecisionTimeStamp() -{ - return (uint64_t)minipal_lowres_ticks(); -} - // ============================================================================ // Processor count / NUMA / CPU Groups // ============================================================================ diff --git a/src/runtime/src/coreclr/gc/windows/gcenv.windows.cpp b/src/runtime/src/coreclr/gc/windows/gcenv.windows.cpp index 34da2e182c99..9057bf041895 100644 --- a/src/runtime/src/coreclr/gc/windows/gcenv.windows.cpp +++ b/src/runtime/src/coreclr/gc/windows/gcenv.windows.cpp @@ -1066,56 +1066,6 @@ void GCToOSInterface::GetMemoryStatus(uint64_t restricted_limit, uint32_t* memor } } -// Get a high precision performance counter -// Return: -// The counter value -int64_t GCToOSInterface::QueryPerformanceCounter() -{ - LARGE_INTEGER ts; - if (!::QueryPerformanceCounter(&ts)) - { - assert(false && "Failed to query performance counter"); - } - - return ts.QuadPart; -} - -// Get a frequency of the high precision performance counter -// Return: -// The counter frequency -int64_t GCToOSInterface::QueryPerformanceFrequency() -{ - LARGE_INTEGER ts; - if (!::QueryPerformanceFrequency(&ts)) - { - assert(false && "Failed to query performance counter"); - } - - return ts.QuadPart; -} - -// Get a time stamp with a low precision -// Return: -// Time stamp in milliseconds -uint64_t GCToOSInterface::GetLowPrecisionTimeStamp() -{ - // GetTickCount64 uses fixed resolution of 10-16ms for backward compatibility. Use - // QueryUnbiasedInterruptTime instead which becomes more accurate if the underlying system - // resolution is improved. This helps responsiveness in the case an app is trying to opt - // into things like multimedia scenarios and additionally does not include "bias" from time - // the system is spent asleep or in hibernation. - - const ULONGLONG TicksPerMillisecond = 10000; - - ULONGLONG unbiasedTime; - if (!::QueryUnbiasedInterruptTime(&unbiasedTime)) - { - assert(false && "Failed to query unbiased interrupt time"); - } - - return (uint64_t)(unbiasedTime / TicksPerMillisecond); -} - // Gets the total number of processors on the machine, not taking // into account current process affinity. // Return: diff --git a/src/runtime/src/coreclr/ildasm/ildasmpch.h b/src/runtime/src/coreclr/ildasm/ildasmpch.h index af7295f12a21..6b634acea0e9 100644 --- a/src/runtime/src/coreclr/ildasm/ildasmpch.h +++ b/src/runtime/src/coreclr/ildasm/ildasmpch.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include "dn-stdio.h" diff --git a/src/runtime/src/coreclr/inc/corinfo.h b/src/runtime/src/coreclr/inc/corinfo.h index f85c006c9a1d..dee4aae95153 100644 --- a/src/runtime/src/coreclr/inc/corinfo.h +++ b/src/runtime/src/coreclr/inc/corinfo.h @@ -1836,6 +1836,14 @@ struct CORINFO_ASYNC_INFO CORINFO_METHOD_HANDLE restoreContextsMethHnd; // Method handle for AsyncHelpers.RestoreContextsOnSuspension, used before suspending in async methods CORINFO_METHOD_HANDLE restoreContextsOnSuspensionMethHnd; + // Method handle for AsyncHelpers.RestoreInlinedFrameContexts, used when an inlined + // async callee logically returns to its caller after having been resumed + CORINFO_METHOD_HANDLE restoreInlinedFrameContextsMethHnd; + // Method handles for AsyncHelpers.CaptureInlinedFrameTransition*, used on suspension to capture + // the contexts each inlined async frame hands to its caller + CORINFO_METHOD_HANDLE captureInlinedFrameTransitionWithContinuationContextMethHnd; + CORINFO_METHOD_HANDLE captureInlinedFrameTransitionNoContinuationContextMethHnd; + CORINFO_METHOD_HANDLE captureInlinedFrameTransitionContinueOnThreadPoolMethHnd; // Finish suspension without saving continuation context (i.e. custom awaiter or ConfigureAwait(false)) CORINFO_METHOD_HANDLE finishSuspensionNoContinuationContextMethHnd; // Finish suspension with saving continuation context (i.e. normal task await) diff --git a/src/runtime/src/coreclr/inc/jiteeversionguid.h b/src/runtime/src/coreclr/inc/jiteeversionguid.h index d922f09ff402..7256e79b2c6b 100644 --- a/src/runtime/src/coreclr/inc/jiteeversionguid.h +++ b/src/runtime/src/coreclr/inc/jiteeversionguid.h @@ -37,11 +37,11 @@ #include -constexpr GUID JITEEVersionIdentifier = { /* aa3cece7-a5f9-4b4e-9309-852c8bd4bdb1 */ - 0xaa3cece7, - 0xa5f9, - 0x4b4e, - {0x93, 0x09, 0x85, 0x2c, 0x8b, 0xd4, 0xbd, 0xb1} +constexpr GUID JITEEVersionIdentifier = { /* 0d18a7df-af1f-4481-a72f-aa6cf8aa0a65 */ + 0x0d18a7df, + 0xaf1f, + 0x4481, + {0xa7, 0x2f, 0xaa, 0x6c, 0xf8, 0xaa, 0x0a, 0x65} }; #endif // JIT_EE_VERSIONING_GUID_H diff --git a/src/runtime/src/coreclr/inc/log.h b/src/runtime/src/coreclr/inc/log.h index fee40d0ea47b..73b85dc63caa 100644 --- a/src/runtime/src/coreclr/inc/log.h +++ b/src/runtime/src/coreclr/inc/log.h @@ -12,6 +12,8 @@ #ifndef __LOG_H__ #define __LOG_H__ +#include + #define DEFINE_LOG_FACILITY(logname, value) logname = value, @@ -74,14 +76,14 @@ extern VOID InitLogging(); extern VOID ShutdownLogging(); extern VOID FlushLogging(); -extern VOID LogSpew(DWORD facility, DWORD level, const char *fmt, ... ); +extern VOID LogSpew(DWORD facility, DWORD level, const char *fmt, ... ) MINIPAL_ATTR_FORMAT_PRINTF(3, 4); extern VOID LogSpewValist(DWORD facility, DWORD level, const char *fmt, va_list args); -extern VOID LogSpew2(DWORD facility2, DWORD level, const char *fmt, ... ); +extern VOID LogSpew2(DWORD facility2, DWORD level, const char *fmt, ... ) MINIPAL_ATTR_FORMAT_PRINTF(3, 4); extern VOID LogSpew2Valist(DWORD facility2, DWORD level, const char *fmt, va_list args); extern VOID LogSpewAlwaysValist(const char *fmt, va_list args); -extern VOID LogSpewAlways (const char *fmt, ... ); +extern VOID LogSpewAlways (const char *fmt, ... ) MINIPAL_ATTR_FORMAT_PRINTF(1, 2); extern VOID EnterLogLock(); extern VOID LeaveLogLock(); diff --git a/src/runtime/src/coreclr/inc/sstring.h b/src/runtime/src/coreclr/inc/sstring.h index bf2c7ab80a4d..072ffbf805f4 100644 --- a/src/runtime/src/coreclr/inc/sstring.h +++ b/src/runtime/src/coreclr/inc/sstring.h @@ -45,6 +45,7 @@ #include "utilcode.h" #include "sbuffer.h" #include "debugmacros.h" +#include // ========================================================================================== // Documentational typedefs: use these to indicate specific representations of 8 bit strings: @@ -566,9 +567,9 @@ class EMPTY_BASES SString : private SBuffer // Utilities //--------------------------------------------------------------------- - void Printf(const CHAR *format, ...); + void Printf(const CHAR *format, ...) MINIPAL_ATTR_FORMAT_PRINTF(2, 3); void VPrintf(const CHAR *format, va_list args); - void AppendPrintf(const CHAR *format, ...); + void AppendPrintf(const CHAR *format, ...) MINIPAL_ATTR_FORMAT_PRINTF(2, 3); void AppendVPrintf(const CHAR *format, va_list args); public: diff --git a/src/runtime/src/coreclr/inc/stresslog.h b/src/runtime/src/coreclr/inc/stresslog.h index f93a2cde304a..b206da7e1535 100644 --- a/src/runtime/src/coreclr/inc/stresslog.h +++ b/src/runtime/src/coreclr/inc/stresslog.h @@ -291,7 +291,7 @@ class StressLog { static BOOL InlinedStressLogOn(unsigned facility, unsigned level); static BOOL InlinedETWLogOn(unsigned facility, unsigned level); - static void LogMsg(unsigned level, unsigned facility, int cArgs, const char* format, ... ); + static void LogMsg(unsigned level, unsigned facility, int cArgs, const char* format, ... ) MINIPAL_ATTR_FORMAT_PRINTF(4, 5); static void LogMsg(unsigned level, unsigned facility, const StressLogMsg& msg); @@ -313,7 +313,7 @@ class StressLog { #endif static void LogMsgOL(const char* format) - { LogMsg(LL_ALWAYS, LF_GC, 0, format); } + { LogMsg(LL_ALWAYS, LF_GC, 0, "%s", format); } template static void LogMsgOL(const char* format, Ts... args) @@ -754,7 +754,7 @@ class ThreadStressLog { return "StressLog TaskSwitch Marker\n"; } - void LogMsg(unsigned facility, int cArgs, const char* format, ...); + void LogMsg(unsigned facility, int cArgs, const char* format, ...) MINIPAL_ATTR_FORMAT_PRINTF(4, 5); FORCEINLINE void LogMsg (unsigned facility, int cArgs, const char* format, va_list Args); #ifdef STRESS_LOG_READONLY diff --git a/src/runtime/src/coreclr/jit/assertionprop.cpp b/src/runtime/src/coreclr/jit/assertionprop.cpp index 4a9229bba797..bcb65ac24788 100644 --- a/src/runtime/src/coreclr/jit/assertionprop.cpp +++ b/src/runtime/src/coreclr/jit/assertionprop.cpp @@ -746,9 +746,9 @@ static void optAssertionProp_HWIntrinsic(Compiler* comp, GenTreeHWIntrinsic* tre #ifdef DEBUG /* static */ void IntegralRange::Print(IntegralRange range) { - printf("[%lld", SymbolicToRealValue(range.m_lowerBound)); + printf("[%lld", (long long)SymbolicToRealValue(range.m_lowerBound)); printf(".."); - printf("%lld]", SymbolicToRealValue(range.m_upperBound)); + printf("%lld]", (long long)SymbolicToRealValue(range.m_upperBound)); } #endif // DEBUG @@ -1009,7 +1009,7 @@ void Compiler::optPrintAssertion(const AssertionDsc& curAssertion, AssertionInde ssize_t iconVal = curAssertion.GetOp2().GetIntConstant(); if (IsAot()) { - printf("MT(%p)", dspPtr(iconVal)); + printf("MT(%p)", (void*)dspPtr(iconVal)); } else { @@ -1022,11 +1022,11 @@ void Compiler::optPrintAssertion(const AssertionDsc& curAssertion, AssertionInde } else if (curAssertion.GetOp2().HasIconFlag()) { - printf("[%p]", dspPtr(curAssertion.GetOp2().GetIntConstant())); + printf("[%zx]", (size_t)dspPtr(curAssertion.GetOp2().GetIntConstant())); } else { - printf("%lld", (int64_t)curAssertion.GetOp2().GetIntConstant()); + printf("%lld", (long long)curAssertion.GetOp2().GetIntConstant()); } break; @@ -1105,11 +1105,11 @@ void Compiler::optDumpAssertionIndices(const char* header, ASSERT_TP assertions, Compiler* compiler = JitTls::GetCompiler(); if (compiler->verbose) { - printf(header); + printf("%s", header); compiler->optPrintAssertionIndices(assertions); if (footer != nullptr) { - printf(footer); + printf("%s", footer); } } #endif // DEBUG @@ -3748,6 +3748,12 @@ GenTree* Compiler::optCopyAssertionProp(const AssertionDsc& curAssertion, return nullptr; } + if (lclVarDsc->lvOnlyUsedOnSynchronousPath || copyVarDsc->lvOnlyUsedOnSynchronousPath) + { + // Do not touch these -- it will likely cause us to unnecessarily save state to the continuation. + return nullptr; + } + tree->SetLclNum(copyLclNum); // The copied var also needs multi-reg, if set @@ -4690,7 +4696,7 @@ GenTree* Compiler::optAssertionPropGlobal_RelOp(ASSERT_VALARG_TP assertions, } else if (op1->TypeIs(TYP_LONG)) { - printf("%lld\n", vnStore->ConstantValue(vnCns)); + printf("%lld\n", (long long)vnStore->ConstantValue(vnCns)); } else if (op1->TypeIs(TYP_DOUBLE)) { @@ -4709,12 +4715,13 @@ GenTree* Compiler::optAssertionPropGlobal_RelOp(ASSERT_VALARG_TP assertions, } else { - printf("%d (gcref)\n", static_cast(vnStore->ConstantValue(vnCns))); + printf("%zd (gcref)\n", + (ssize_t) static_cast(vnStore->ConstantValue(vnCns))); } } else if (op1->TypeIs(TYP_BYREF)) { - printf("%d (byref)\n", static_cast(vnStore->ConstantValue(vnCns))); + printf("%zd (byref)\n", (ssize_t) static_cast(vnStore->ConstantValue(vnCns))); } else { diff --git a/src/runtime/src/coreclr/jit/async.cpp b/src/runtime/src/coreclr/jit/async.cpp index 68684d62c28b..3496a584cd14 100644 --- a/src/runtime/src/coreclr/jit/async.cpp +++ b/src/runtime/src/coreclr/jit/async.cpp @@ -64,6 +64,63 @@ ContinuationMember ContinuationMember::CustomAwaiterOfLayout(ClassLayout* layout return member; } +//------------------------------------------------------------------------ +// ContinuationMember::InlineFrameExecutionContext: +// Create a continuation member that stores the ExecutionContext an inlined async +// frame captured when it logically returned to its caller. +// +// Parameters: +// inlineDepth - Depth of the inlined frame. +// +// Returns: +// A continuation member describing the ExecutionContext. +// +ContinuationMember ContinuationMember::InlineFrameExecutionContext(unsigned inlineDepth) +{ + ContinuationMember member; + member.Type = ContinuationMemberType::InlineFrameExecutionContext; + member.m_inlineDepth = inlineDepth; + return member; +} + +//------------------------------------------------------------------------ +// ContinuationMember::InlineFrameContinuationContext: +// Create a continuation member that stores the continuation context an inlined +// async frame captured when it logically returned to its caller. +// +// Parameters: +// inlineDepth - Depth of the inlined frame. +// +// Returns: +// A continuation member describing the continuation context. +// +ContinuationMember ContinuationMember::InlineFrameContinuationContext(unsigned inlineDepth) +{ + ContinuationMember member; + member.Type = ContinuationMemberType::InlineFrameContinuationContext; + member.m_inlineDepth = inlineDepth; + return member; +} + +//------------------------------------------------------------------------ +// ContinuationMember::InlineFrameFlags: +// Create a continuation member that stores the ContinuationFlags describing the +// continuation context of an inlined async frame. +// +// Parameters: +// inlineDepth - Depth of the inlined frame. +// +// Returns: +// A continuation member describing the flags. +// +ContinuationMember ContinuationMember::InlineFrameFlags(unsigned inlineDepth) +{ + ContinuationMember member; + member.Type = ContinuationMemberType::InlineFrameFlags; + member.m_inlineDepth = inlineDepth; + return member; +} + //------------------------------------------------------------------------ // ContinuationMember::GetCustomAwaiterLayout: // Get the layout of a custom awaiter continuation member. @@ -77,13 +134,56 @@ ClassLayout* ContinuationMember::GetCustomAwaiterLayout() const return m_customAwaiterLayout; } +//------------------------------------------------------------------------ +// ContinuationMember::GetInlineDepth: +// Get the inline depth of the frame an inlined frame member belongs to. +// +// Returns: +// The inline depth. +// +unsigned ContinuationMember::GetInlineDepth() const +{ + assert(IsInlineFrameMember()); + return m_inlineDepth; +} + +//------------------------------------------------------------------------ +// ContinuationMember::GetStorageType: +// Get the type of the storage this member occupies in the continuation. +// +// Parameters: +// layout - [out] Layout of the storage when the returned type is TYP_STRUCT, +// nullptr otherwise. +// +// Returns: +// Type of the storage. +// +var_types ContinuationMember::GetStorageType(ClassLayout** layout) const +{ + *layout = nullptr; + + switch (Type) + { + case ContinuationMemberType::CustomAwaiterOfLayout: + *layout = m_customAwaiterLayout; + return TYP_STRUCT; + case ContinuationMemberType::InlineFrameExecutionContext: + case ContinuationMemberType::InlineFrameContinuationContext: + return TYP_REF; + case ContinuationMemberType::InlineFrameFlags: + return TYP_INT; + default: + unreached(); + } +} + //------------------------------------------------------------------------ // ContinuationMember::AreCompatible: // Check whether two continuation members can share the same storage. // // Parameters: -// a - First continuation member. -// b - Second continuation member. +// a - The first member +// b - The second member // // Returns: // True if the members are compatible; otherwise false. @@ -99,6 +199,15 @@ bool ContinuationMember::AreCompatible(const ContinuationMember& a, const Contin { case ContinuationMemberType::CustomAwaiterOfLayout: return ClassLayout::AreCompatible(a.m_customAwaiterLayout, b.m_customAwaiterLayout); + case ContinuationMemberType::InlineFrameExecutionContext: + case ContinuationMemberType::InlineFrameContinuationContext: + case ContinuationMemberType::InlineFrameFlags: + // Keyed by inline depth rather than by individual inline frame. Two frames at + // the same depth can share storage because their live ranges cannot overlap: + // the value is written at a frame's first suspension and consumed by that same + // frame's post-inline IR, and one frame at a given depth must be left before + // another can be entered. + return a.m_inlineDepth == b.m_inlineDepth; default: unreached(); } @@ -116,12 +225,46 @@ void ContinuationMember::Print() const case ContinuationMemberType::CustomAwaiterOfLayout: printf("CustomAwaiter<%s>", m_customAwaiterLayout->GetClassName()); break; + case ContinuationMemberType::InlineFrameExecutionContext: + printf("ExecutionContext for inline depth %u", m_inlineDepth); + break; + case ContinuationMemberType::InlineFrameContinuationContext: + printf("Continuation context for inline depth %u", m_inlineDepth); + break; + case ContinuationMemberType::InlineFrameFlags: + printf("Continuation flags for inline depth %u", m_inlineDepth); + break; default: unreached(); } } #endif +//------------------------------------------------------------------------ +// CollectWellKnownArgs: +// Collect the nodes of all arguments of a call with a specific well-known kind, in +// argument order. +// +// Parameters: +// call - The call +// wka - The well-known argument kind +// nodes - [out] Stack to push the argument nodes onto +// +// Remarks: +// Async context pseudo-args can appear multiple times on a call: general async +// inlining adds one set per enclosing inlined frame. +// +static void CollectWellKnownArgs(GenTreeCall* call, WellKnownArg wka, ArrayStack& nodes) +{ + for (CallArg& arg : call->gtArgs.Args()) + { + if (arg.GetWellKnownArg() == wka) + { + nodes.Push(arg.GetNode()); + } + } +} + //------------------------------------------------------------------------ // Compiler::GetContinuationMemberIndex: // Find or add a continuation member and return its index. @@ -134,15 +277,18 @@ void ContinuationMember::Print() const // size_t Compiler::GetContinuationMemberIndex(const ContinuationMember& member) { - if (m_asyncContinuationMembers == nullptr) + Compiler* const root = impInlineRoot(); + + if (root->m_asyncContinuationMembers == nullptr) { - m_asyncContinuationMembers = new (this, CMK_Async) jitstd::vector(getAllocator(CMK_Async)); + root->m_asyncContinuationMembers = + new (root, CMK_Async) jitstd::vector(root->getAllocator(CMK_Async)); } else { - for (size_t i = 0; i < m_asyncContinuationMembers->size(); i++) + for (size_t i = 0; i < root->m_asyncContinuationMembers->size(); i++) { - const ContinuationMember& existingMember = m_asyncContinuationMembers->at(i); + const ContinuationMember& existingMember = root->m_asyncContinuationMembers->at(i); if (ContinuationMember::AreCompatible(member, existingMember)) { @@ -151,8 +297,43 @@ size_t Compiler::GetContinuationMemberIndex(const ContinuationMember& member) } } - m_asyncContinuationMembers->push_back(member); - return m_asyncContinuationMembers->size() - 1; + root->m_asyncContinuationMembers->push_back(member); + return root->m_asyncContinuationMembers->size() - 1; +} + +//------------------------------------------------------------------------ +// Compiler::TryGetContinuationMemberIndex: +// Look up the index of an already registered continuation member. +// +// Parameters: +// member - The member +// index - [out] Index of the member, if it is registered +// +// Returns: +// True if the member is registered. +// +// Remarks: +// Unlike GetContinuationMemberIndex this does not register the member. Use it after +// the continuation layout has been created, where growing the member table would put +// the new member beyond the end of the layout. +// +bool Compiler::TryGetContinuationMemberIndex(const ContinuationMember& member, size_t* index) +{ + Compiler* const root = impInlineRoot(); + + if (root->m_asyncContinuationMembers != nullptr) + { + for (size_t i = 0; i < root->m_asyncContinuationMembers->size(); i++) + { + if (ContinuationMember::AreCompatible(member, root->m_asyncContinuationMembers->at(i))) + { + *index = i; + return true; + } + } + } + + return false; } //------------------------------------------------------------------------ @@ -162,9 +343,10 @@ size_t Compiler::GetContinuationMemberIndex(const ContinuationMember& member) // Returns: // The number of registered continuation members. // -size_t Compiler::GetContinuationMemberCount() const +size_t Compiler::GetContinuationMemberCount() { - return m_asyncContinuationMembers == nullptr ? 0 : m_asyncContinuationMembers->size(); + Compiler* const root = impInlineRoot(); + return root->m_asyncContinuationMembers == nullptr ? 0 : root->m_asyncContinuationMembers->size(); } //------------------------------------------------------------------------ @@ -179,8 +361,64 @@ size_t Compiler::GetContinuationMemberCount() const // const ContinuationMember& Compiler::GetContinuationMember(size_t index) { - assert(index < m_asyncContinuationMembers->size()); - return m_asyncContinuationMembers->at(index); + Compiler* const root = impInlineRoot(); + assert(index < root->m_asyncContinuationMembers->size()); + return root->m_asyncContinuationMembers->at(index); +} + +//------------------------------------------------------------------------ +// Compiler::ehIsAsyncContextRestore: +// Check whether an EH clause is one of the context restore clauses created by +// SaveAsyncContexts. +// +// Parameters: +// ehID - ID of the EH clause +// +// Returns: +// True if so. +// +bool Compiler::ehIsAsyncContextRestore(unsigned short ehID) +{ + Compiler* const root = impInlineRoot(); + return (root->m_asyncContextRestoreEHIDs != nullptr) && root->m_asyncContextRestoreEHIDs->Lookup(ehID); +} + +//------------------------------------------------------------------------ +// Compiler::ehIsInsideNonAsyncContextRestoreRegion: +// Check whether a block is inside any protected region other than the context +// restore regions created by SaveAsyncContexts. +// +// Parameters: +// block - The block +// +// Returns: +// True if so. +// +// Remarks: +// Every async frame gets a context restore try-fault wrapped around its whole +// body, so a plain hasTryIndex() check cannot distinguish user EH from the EH +// the JIT itself introduced. +// +// Only the try nesting is considered. The C# compiler hoists awaits out of +// handlers, so the JIT never sees a suspension point inside one. +// +bool Compiler::ehIsInsideNonAsyncContextRestoreRegion(BasicBlock* block) +{ + if (!block->hasTryIndex()) + { + return false; + } + + for (unsigned index = block->getTryIndex(); index != EHblkDsc::NO_ENCLOSING_INDEX; + index = ehGetDsc(index)->ebdEnclosingTryIndex) + { + if (!ehIsAsyncContextRestore(ehGetDsc(index)->ebdID)) + { + return true; + } + } + + return false; } //------------------------------------------------------------------------ @@ -210,17 +448,29 @@ PhaseStatus Compiler::SaveAsyncContexts() lvaAsyncExecutionContextVar = lvaGrabTemp(false DEBUGARG("Async ExecutionContext")); lvaAsyncSynchronizationContextVar = lvaGrabTemp(false DEBUGARG("Async SynchronizationContext")); - lvaGetDesc(lvaResumedIndicator)->lvType = TYP_I_IMPL; - lvaGetDesc(lvaAsyncThreadObjectVar)->lvType = TYP_REF; - lvaGetDesc(lvaAsyncExecutionContextVar)->lvType = TYP_REF; - lvaGetDesc(lvaAsyncSynchronizationContextVar)->lvType = TYP_REF; + LclVarDsc* const resumedDsc = lvaGetDesc(lvaResumedIndicator); + LclVarDsc* const threadDsc = lvaGetDesc(lvaAsyncThreadObjectVar); + LclVarDsc* const execCtxDsc = lvaGetDesc(lvaAsyncExecutionContextVar); + LclVarDsc* const syncCtxDsc = lvaGetDesc(lvaAsyncSynchronizationContextVar); + + resumedDsc->lvType = TYP_I_IMPL; + threadDsc->lvType = TYP_REF; + execCtxDsc->lvType = TYP_REF; + syncCtxDsc->lvType = TYP_REF; + + // None of these are read once this frame has resumed, so a suspension does not need to + // capture them. That holds for inlined frames too, which get their own set of these. + resumedDsc->lvOnlyUsedOnSynchronousPath = true; + threadDsc->lvOnlyUsedOnSynchronousPath = true; + execCtxDsc->lvOnlyUsedOnSynchronousPath = true; + syncCtxDsc->lvOnlyUsedOnSynchronousPath = true; if (opts.IsOSR()) { - lvaGetDesc(lvaResumedIndicator)->lvIsOSRLocal = true; - lvaGetDesc(lvaAsyncThreadObjectVar)->lvIsOSRLocal = true; - lvaGetDesc(lvaAsyncExecutionContextVar)->lvIsOSRLocal = true; - lvaGetDesc(lvaAsyncSynchronizationContextVar)->lvIsOSRLocal = true; + resumedDsc->lvIsOSRLocal = true; + threadDsc->lvIsOSRLocal = true; + execCtxDsc->lvIsOSRLocal = true; + syncCtxDsc->lvIsOSRLocal = true; } // Create try-fault structure. This is actually a try-finally, but we @@ -249,6 +499,17 @@ PhaseStatus Compiler::SaveAsyncContexts() newEntry->ebdID = asyncContextRestoreEHID; newEntry->ebdHandlerType = EH_HANDLER_FAULT; + { + Compiler* const root = impInlineRoot(); + if (root->m_asyncContextRestoreEHIDs == nullptr) + { + root->m_asyncContextRestoreEHIDs = + new (root, CMK_Async) AsyncContextRestoreEHIDSet(root->getAllocator(CMK_Async)); + } + + root->m_asyncContextRestoreEHIDs->Set(asyncContextRestoreEHID, true); + } + newEntry->ebdTryBeg = tryBegBB; newEntry->ebdTryLast = tryLastBB; @@ -366,10 +627,7 @@ PhaseStatus Compiler::SaveAsyncContexts() for (BasicBlock* block : Blocks()) { - if (!compIsForInlining()) - { - AddContextArgsToAsyncCalls(block); - } + AddContextArgsToAsyncCalls(block); if (!block->KindIs(BBJ_RETURN) || (block == newReturnBB)) { @@ -461,23 +719,124 @@ void Compiler::AddContextArgsToAsyncCalls(BasicBlock* block) return WALK_CONTINUE; } - GenTreeCall* call = tree->AsCall(); - GenTree* resumed = m_compiler->gtNewLclVarNode(m_compiler->lvaResumedIndicator, TYP_INT); - GenTree* resumedAddr = m_compiler->gtNewLclAddrNode(m_compiler->lvaResumedIndicator, 0); - GenTree* execCtx = m_compiler->gtNewLclVarNode(m_compiler->lvaAsyncExecutionContextVar, TYP_REF); - GenTree* syncCtx = m_compiler->gtNewLclVarNode(m_compiler->lvaAsyncSynchronizationContextVar, TYP_REF); + GenTreeCall* call = tree->AsCall(); + + // Record that this body has a suspension point. Inlinees without one keep the + // cheap shape: no post-inline IR and no capture chain is emitted for them. + m_compiler->compAsyncBodyMaySuspend = true; + + if (call->gtArgs.FindWellKnownArg(WellKnownArg::AsyncResumedUse) != nullptr) + { + // Already has context args: this is an async call in an inlinee that + // inherited them from the inlining call (see + // impInheritAsyncContextsFromInliner). + assert(m_compiler->compIsForInlining()); + return WALK_CONTINUE; + } + + if (m_compiler->compIsForInlining() && !generalAsyncInliningEnabled()) + { + // Only general async inlining introduces inlinee async calls that need + // their own contexts. + return WALK_CONTINUE; + } + + GenTree* resumed = m_compiler->gtNewLclVarNode(m_compiler->lvaResumedIndicator, TYP_INT); + GenTree* resumedAddr = m_compiler->gtNewLclAddrNode(m_compiler->lvaResumedIndicator, 0); + GenTree* execCtx = m_compiler->gtNewLclVarNode(m_compiler->lvaAsyncExecutionContextVar, TYP_REF); + GenTree* syncCtx = m_compiler->gtNewLclVarNode(m_compiler->lvaAsyncSynchronizationContextVar, TYP_REF); JITDUMP( "Adding resumed use [%06u], resumed def [%06u] exec context [%06u], sync context [%06u] to async call [%06u]\n", dspTreeID(resumed), dspTreeID(resumedAddr), dspTreeID(execCtx), dspTreeID(syncCtx), dspTreeID(call)); - call->gtArgs.PushFront(m_compiler, - NewCallArg::Primitive(syncCtx).WellKnown(WellKnownArg::AsyncSynchronizationContext)); - call->gtArgs.PushFront(m_compiler, - NewCallArg::Primitive(execCtx).WellKnown(WellKnownArg::AsyncExecutionContext)); - call->gtArgs.PushFront(m_compiler, - NewCallArg::Primitive(resumedAddr).WellKnown(WellKnownArg::AsyncResumedDef)); - call->gtArgs.PushFront(m_compiler, NewCallArg::Primitive(resumed).WellKnown(WellKnownArg::AsyncResumedUse)); + + NewCallArg resumedDefArg = NewCallArg::Primitive(resumedAddr).WellKnown(WellKnownArg::AsyncResumedDef); + NewCallArg resumedUseArg = NewCallArg::Primitive(resumed).WellKnown(WellKnownArg::AsyncResumedUse); + NewCallArg execCtxArg = NewCallArg::Primitive(execCtx).WellKnown(WellKnownArg::AsyncExecutionContext); + NewCallArg syncCtxArg = NewCallArg::Primitive(syncCtx).WellKnown(WellKnownArg::AsyncSynchronizationContext); + + // The def is only ever present once, so keeping it outside leaves the rest as + // a clean run of (resumed, exec context, sync context) triples, one per frame. + CallArg* insertAfter = call->gtArgs.PushFront(m_compiler, resumedDefArg); + insertAfter = call->gtArgs.InsertAfter(m_compiler, insertAfter, resumedUseArg); + insertAfter = call->gtArgs.InsertAfter(m_compiler, insertAfter, execCtxArg); + insertAfter = call->gtArgs.InsertAfter(m_compiler, insertAfter, syncCtxArg); m_compiler->lvaGetDesc(m_compiler->lvaResumedIndicator)->lvHasLdAddrOp = true; + + if (!m_compiler->compIsForInlining()) + { + return WALK_CONTINUE; + } + + // Add the context values of the frames enclosing this inlined async frame. + // When the call suspends, every enclosing frame that has not yet resumed must + // capture the contexts it hands to its caller and restore its caller's + // contexts onto the thread, as if its physical frame had returned. The IR for + // that is created by the async transformation, long after the optimizer has + // run, so we model it by adding pseudo-args for the values it will use. + // + // The enclosing frames are exactly the ones the inlining call already + // describes, so its chain is simply copied over: the frame it sits in followed + // by that frame's own chain out to the root. These are the values as they + // appear in the caller's IR, which is what the suspension has to store. That + // composes for nested inlines: the inlining call lives in IR that was itself + // extended this way if its method was inlined, so by the time we get here the + // chain out to the root is complete. + GenTreeCall* const inlCall = m_compiler->impInlineInfo->iciCall; + unsigned numCopied = 0; + + for (CallArg& arg : inlCall->gtArgs.Args()) + { + switch (arg.GetWellKnownArg()) + { + case WellKnownArg::AsyncResumedUse: + case WellKnownArg::AsyncExecutionContext: + case WellKnownArg::AsyncSynchronizationContext: + break; + default: + continue; + } + + NewCallArg newArg = + NewCallArg::Primitive(m_compiler->gtCloneExpr(arg.GetNode())).WellKnown(arg.GetWellKnownArg()); + insertAfter = call->gtArgs.InsertAfter(m_compiler, insertAfter, newArg); + numCopied++; + } + + assert((numCopied % 3) == 0); + + if (numCopied == 0) + { + // The inlining call does no context handling, so no enclosing frame is a + // logical async frame. This frame has nothing to hand back and there are + // no frame transitions to run on suspension. + JITDUMP("Inlining call [%06u] has no context args; inlinee has no enclosing async frame\n", + dspTreeID(inlCall)); + return WALK_CONTINUE; + } + + // How each of those frames has to hand off to its caller. This frame hands off + // the way the inlining call awaited it, and the frames outside it the way the + // inlining call already records. + jitstd::vector* const handling = new (m_compiler, CMK_Async) + jitstd::vector(m_compiler->getAllocator(CMK_Async)); + handling->push_back(inlCall->GetAsyncInfo().ContinuationContextHandling); + + if (inlCall->GetAsyncInfo().InlineFrameContextHandling != nullptr) + { + for (ContinuationContextHandling outer : *inlCall->GetAsyncInfo().InlineFrameContextHandling) + { + handling->push_back(outer); + } + } + + call->GetAsyncInfo().InlineFrameContextHandling = handling; + assert(handling->size() == (numCopied / 3)); + + // This frame and the ones enclosing it. The first set doubles as the one + // the handling of the suspension itself consumes. + JITDUMP("Extended async call [%06u] to %u frames in chain\n", dspTreeID(call), (numCopied / 3) + 1); + return WALK_CONTINUE; } }; @@ -905,7 +1264,7 @@ PhaseStatus AsyncTransformation::Run() assert(continuationLayout->ContinuationMemberOffsets[memberIndex] != UINT_MAX); ssize_t offset = (OFFSETOF__CORINFO_Continuation__data - SIZEOF__CORINFO_Object) + continuationLayout->ContinuationMemberOffsets[memberIndex]; - node->BashToConst(offset, TYP_INT); + node->BashToConst(offset, node->TypeGet()); } m_compiler->fgInvalidateDfsTree(); @@ -1213,7 +1572,7 @@ void AsyncTransformation::CreateLiveSetForSuspension(BasicBlock* auto visitDef = [&](const LocalDef& def) { if (def.IsEntire) { - if (HasNonContextRestoreExceptionalFlow(block)) + if (m_compiler->ehIsInsideNonAsyncContextRestoreRegion(block)) { JITDUMP(" V%02u is fully defined but the block has exceptional flow\n", def.Def->GetLclNum()); } @@ -1228,24 +1587,6 @@ void AsyncTransformation::CreateLiveSetForSuspension(BasicBlock* call->VisitLocalDefs(m_compiler, visitDef); - // Exclude method-level context locals (only live on synchronous path) - if (m_compiler->lvaAsyncThreadObjectVar != BAD_VAR_NUM) - { - excludedLocals.AddOrUpdate(m_compiler->lvaAsyncThreadObjectVar, true); - } - if (m_compiler->lvaAsyncSynchronizationContextVar != BAD_VAR_NUM) - { - excludedLocals.AddOrUpdate(m_compiler->lvaAsyncSynchronizationContextVar, true); - } - if (m_compiler->lvaAsyncExecutionContextVar != BAD_VAR_NUM) - { - excludedLocals.AddOrUpdate(m_compiler->lvaAsyncExecutionContextVar, true); - } - if (m_compiler->lvaResumedIndicator != BAD_VAR_NUM) - { - excludedLocals.AddOrUpdate(m_compiler->lvaResumedIndicator, true); - } - #ifdef TARGET_WASM // The Wasm shadow stack pointer is a Wasm local set by the caller, not // continuation state, so exclude it from the save/restore set. @@ -1256,6 +1597,13 @@ void AsyncTransformation::CreateLiveSetForSuspension(BasicBlock* #endif // TARGET_WASM analyses.GetLiveLocals(layoutBuilder, [&](unsigned lclNum) { + // Some locals like async contexts are not read if we resumed, so they never need + // to be captured. + if (m_compiler->lvaGetDesc(lclNum)->lvOnlyUsedOnSynchronousPath) + { + return false; + } + return !excludedLocals.Contains(lclNum); }); LiftLIREdges(block, defs, layoutBuilder); @@ -1280,29 +1628,6 @@ void AsyncTransformation::CreateLiveSetForSuspension(BasicBlock* #endif } -//------------------------------------------------------------------------ -// AsyncTransformation::HasNonContextRestoreExceptionalFlow: -// Check if there is internal control flow out of the specified block and if -// that target is not the canonical "restore context" EH handler. -// -// Parameters: -// block - The block -// -// Returns: -// True if there is such control flow. -// -bool AsyncTransformation::HasNonContextRestoreExceptionalFlow(BasicBlock* block) -{ - if (!block->hasTryIndex()) - { - return false; - } - - EHblkDsc* ehDsc = m_compiler->ehGetDsc(block->getTryIndex()); - return (ehDsc->ebdID != m_compiler->asyncContextRestoreEHID) || - (ehDsc->ebdEnclosingTryIndex != EHblkDsc::NO_ENCLOSING_INDEX); -} - //------------------------------------------------------------------------ // AsyncTransformation::LiftLIREdges: // Create locals capturing outstanding LIR edges and add information @@ -1474,7 +1799,7 @@ void AsyncTransformation::BuildContinuation(BasicBlock* block, layoutBuilder->SetNeedsOSRAddress(); } - if (HasNonContextRestoreExceptionalFlow(block)) + if (m_compiler->ehIsInsideNonAsyncContextRestoreRegion(block)) { // If we are enclosed in any try region that isn't our special "context // restore" try region then we need to rethrow an exception. For our @@ -1725,10 +2050,68 @@ ContinuationLayout* ContinuationLayoutBuilder::Create(ArrayStack& cont continue; } - ClassLayout* memberLayout = m_compiler->GetContinuationMember(memberIndex).GetCustomAwaiterLayout(); - unsigned alignment = memberLayout->GetAlignmentRequirement(m_compiler); - unsigned heapAlignment = std::min(alignment, (unsigned)TARGET_POINTER_SIZE); - layout->ContinuationMemberOffsets[memberIndex] = allocLayout(heapAlignment, memberLayout->GetSize()); + const ContinuationMember& member = m_compiler->GetContinuationMember(memberIndex); + + ClassLayout* memberLayout; + var_types const storageType = member.GetStorageType(&memberLayout); + + unsigned alignment; + unsigned size; + if (memberLayout != nullptr) + { + alignment = memberLayout->GetAlignmentRequirement(m_compiler); + size = memberLayout->GetSize(); + } + else + { + alignment = genTypeAlignments[storageType]; + size = genTypeSize(storageType); + } + + layout->ContinuationMemberOffsets[memberIndex] = + allocLayout(std::min(alignment, (unsigned)TARGET_POINTER_SIZE), size); + } + + // The suspension tail hands all three members of an inlined frame to + // CaptureInlinedFrameTransition together, so if any of them still has a read then the + // other two need storage as well. When none of them does the members are dead: the + // post-inline transition IR that reads them was optimized away (for example because a + // no-return call in the inlinee made it unreachable), and the tail skips the capture + // instead of storing values nothing can observe. + for (size_t i = 0; i < continuationMemberCount; i++) + { + if (layout->ContinuationMemberOffsets[i] == UINT_MAX) + { + continue; + } + + const ContinuationMember& liveMember = m_compiler->GetContinuationMember(i); + if (!liveMember.IsInlineFrameMember()) + { + continue; + } + + unsigned const depth = liveMember.GetInlineDepth(); + for (size_t j = 0; j < continuationMemberCount; j++) + { + if (layout->ContinuationMemberOffsets[j] != UINT_MAX) + { + continue; + } + + const ContinuationMember& member = m_compiler->GetContinuationMember(j); + if (!member.IsInlineFrameMember() || (member.GetInlineDepth() != depth)) + { + continue; + } + + ClassLayout* memberLayout; + var_types const storageType = member.GetStorageType(&memberLayout); + assert(memberLayout == nullptr); + unsigned const alignment = genTypeAlignments[storageType]; + layout->ContinuationMemberOffsets[j] = + allocLayout(std::min(alignment, (unsigned)TARGET_POINTER_SIZE), genTypeSize(storageType)); + } } if (m_needsKeepAlive) @@ -1783,8 +2166,10 @@ ContinuationLayout* ContinuationLayoutBuilder::Create(ArrayStack& cont { if (layout->ContinuationMemberOffsets[i] != UINT_MAX) { - bitmapBuilder.SetType(layout->ContinuationMemberOffsets[i], TYP_STRUCT, - m_compiler->GetContinuationMember(i).GetCustomAwaiterLayout()); + const ContinuationMember& member = m_compiler->GetContinuationMember(i); + ClassLayout* memberLayout; + var_types const storageType = member.GetStorageType(&memberLayout); + bitmapBuilder.SetType(layout->ContinuationMemberOffsets[i], storageType, memberLayout); } } @@ -1806,7 +2191,7 @@ ContinuationLayout* ContinuationLayoutBuilder::Create(ArrayStack& cont while (end < endOfObjRefs && *end) end++; - printf(" [%3u..%3u) obj refs\n", (start - objRefs) * TARGET_POINTER_SIZE, + printf(" [%3zu..%3zu) obj refs\n", (start - objRefs) * TARGET_POINTER_SIZE, (end - objRefs) * TARGET_POINTER_SIZE); start = end; } @@ -1864,7 +2249,7 @@ CallDefinitionInfo AsyncTransformation::CanonicalizeCallDefinition(BasicBlock* // preserve its value because of an exception being thrown after // potential resumption. (This check is conservative, we could use liveness for it as well.) if (!call->gtNext->OperIsLocalStore() || (call->gtNext->Data() != call) || - HasNonContextRestoreExceptionalFlow(block)) + m_compiler->ehIsInsideNonAsyncContextRestoreRegion(block)) { LIR::Use use; bool gotUse = LIR::AsRange(block).TryGetUse(call, &use); @@ -2087,7 +2472,8 @@ bool AsyncTransformation::IsReusableSuspension(const AsyncState* state, if (asyncInfoThis.ContinuationContextHandling != asyncInfoOther.ContinuationContextHandling) { JITDUMP(" No; disagreement on continuation context handling (%u vs %u)\n", - asyncInfoThis.ContinuationContextHandling, asyncInfoOther.ContinuationContextHandling); + static_cast(asyncInfoThis.ContinuationContextHandling), + static_cast(asyncInfoOther.ContinuationContextHandling)); return false; } @@ -2130,35 +2516,46 @@ bool AsyncTransformation::IsReusableSuspension(const AsyncState* state, } } + // These can be duplicated: general async inlining adds one set of context args per + // enclosing inlined frame, describing the chain of frames whose handling a suspension + // has to run. All of them must agree for a suspension to be reusable. static const WellKnownArg validateArgs[] = {WellKnownArg::AsyncAwaiter, WellKnownArg::AsyncResumedUse, WellKnownArg::AsyncResumedDef, WellKnownArg::AsyncExecutionContext, WellKnownArg::AsyncSynchronizationContext}; + ArrayStack thisNodes(m_compiler->getAllocator(CMK_Async)); + ArrayStack otherNodes(m_compiler->getAllocator(CMK_Async)); for (WellKnownArg arg : validateArgs) { - CallArg* thisArg = call->gtArgs.FindWellKnownArg(arg); - CallArg* otherArg = predAsyncCall->gtArgs.FindWellKnownArg(arg); + thisNodes.Reset(); + otherNodes.Reset(); + CollectWellKnownArgs(call, arg, thisNodes); + CollectWellKnownArgs(predAsyncCall, arg, otherNodes); - if ((thisArg == nullptr) != (otherArg == nullptr)) + if (thisNodes.Height() != otherNodes.Height()) { - JITDUMP(" No; disagreement on presence of %s argument\n", getWellKnownArgName(arg)); + JITDUMP(" No; disagreement on number of %s arguments (%d vs %d)\n", getWellKnownArgName(arg), + thisNodes.Height(), otherNodes.Height()); return false; } - if (thisArg != nullptr) + for (int i = 0; i < thisNodes.Height(); i++) { + GenTree* thisNode = thisNodes.Bottom(i); + GenTree* otherNode = otherNodes.Bottom(i); + // The value may have been folded to a constant (e.g. when the // indicator is provably zero at this point), which is still fine to // compare and to remove from the call. - if (!thisArg->GetNode()->OperIsAnyLocal() && !thisArg->GetNode()->IsInvariant()) + if (!thisNode->OperIsAnyLocal() && !thisNode->IsInvariant()) { JITDUMP(" No; %s argument is too complex\n", getWellKnownArgName(arg)); return false; } - if (!GenTree::Compare(thisArg->GetNode(), otherArg->GetNode())) + if (!GenTree::Compare(thisNode, otherNode)) { JITDUMP(" No; disagreement on value of %s argument ([%06u] vs [%06u])\n", getWellKnownArgName(arg), - Compiler::dspTreeID(thisArg->GetNode()), Compiler::dspTreeID(otherArg->GetNode())); + Compiler::dspTreeID(thisNode), Compiler::dspTreeID(otherNode)); return false; } } @@ -2191,8 +2588,10 @@ void AsyncTransformation::HandleReusedSuspension(BasicBlock* callBlock, GenTreeC WellKnownArg::AsyncSynchronizationContext}; for (WellKnownArg wka : argsToRemove) { - CallArg* arg = call->gtArgs.FindWellKnownArg(wka); - if (arg != nullptr) + // These can be duplicated: general async inlining adds one set of context args + // per enclosing inlined frame. All of them must go. + for (CallArg* arg = call->gtArgs.FindWellKnownArg(wka); arg != nullptr; + arg = call->gtArgs.FindWellKnownArg(wka)) { assert(arg->GetNode()->OperIsAnyLocal() || arg->GetNode()->IsInvariant()); LIR::AsRange(callBlock).Remove(arg->GetNode()); @@ -2447,8 +2846,12 @@ void AsyncTransformation::StoreAsyncAwaiter(BasicBlock* callBlock, ClassLayout* awaiterLayout = awaiterArg->GetSignatureLayout(); assert(awaiterLayout != nullptr); - size_t memberIndex = - m_compiler->GetContinuationMemberIndex(ContinuationMember::CustomAwaiterOfLayout(awaiterLayout)); + // Layout is fixed at this point, so this is expected not to add new entries. + size_t memberIndex = 0; + bool isRegistered = + m_compiler->TryGetContinuationMemberIndex(ContinuationMember::CustomAwaiterOfLayout(awaiterLayout), + &memberIndex); + assert(isRegistered); assert(memberIndex < layout.ContinuationMemberOffsets.size()); assert(layout.ContinuationMemberOffsets[memberIndex] != UINT_MAX); @@ -2818,11 +3221,16 @@ void AsyncTransformation::FinishContextHandlingAndSuspension(BasicBlock* LIR::AsRange(suspendBB).InsertAtEnd(LIR::SeqTree(m_compiler, store)); } - RestoreContexts(callBlock, call, suspendBB); + GenTree* const frameResumed = RestoreContexts(callBlock, call, suspendBB); assert(suspendBB->KindIs(BBJ_RETURN)); - if (m_sharedReturnBB != nullptr) + BasicBlock* const frameTail = CreateInlinedFrameSuspensionTail(callBlock, call, layout, frameResumed); + if (frameTail != nullptr) + { + suspendBB->SetKindAndTargetEdge(BBJ_ALWAYS, m_compiler->fgAddRefPred(frameTail, suspendBB)); + } + else if (m_sharedReturnBB != nullptr) { suspendBB->SetKindAndTargetEdge(BBJ_ALWAYS, m_compiler->fgAddRefPred(m_sharedReturnBB, suspendBB)); } @@ -2907,7 +3315,12 @@ void AsyncTransformation::FinishContextHandlingAndSuspensionWithHelper(BasicBloc LIR::AsRange(callBlock).Remove(syncContext); call->gtArgs.RemoveUnsafe(syncContextArg); - if (sharedFinish != nullptr) + // A call inside an inlined async frame needs the enclosing frames' handling to run + // after this one, so it cannot use a finish block shared with suspensions in other + // frames. + BasicBlock* const frameTail = CreateInlinedFrameSuspensionTail(callBlock, call, layout, resumed); + + if ((sharedFinish != nullptr) && (frameTail == nullptr)) { // Store the vars to the shared locals that the shared finish block will take them from. if (m_sharedFinishContextHandlingResumedVar != BAD_VAR_NUM) @@ -2938,8 +3351,13 @@ void AsyncTransformation::FinishContextHandlingAndSuspensionWithHelper(BasicBloc // Otherwise insert a new call InsertFinishContextHandlingCall(suspendBB, layout, helper, resumed, execContext, syncContext); - // And return either via a new GT_RETURN_SUSPEND or via the shared return BB. - if (m_sharedReturnBB != nullptr) + // And continue with the enclosing frames, or return either via a new + // GT_RETURN_SUSPEND or via the shared return BB. + if (frameTail != nullptr) + { + suspendBB->SetKindAndTargetEdge(BBJ_ALWAYS, m_compiler->fgAddRefPred(frameTail, suspendBB)); + } + else if (m_sharedReturnBB != nullptr) { suspendBB->SetKindAndTargetEdge(BBJ_ALWAYS, m_compiler->fgAddRefPred(m_sharedReturnBB, suspendBB)); } @@ -2952,6 +3370,259 @@ void AsyncTransformation::FinishContextHandlingAndSuspensionWithHelper(BasicBloc } } +//------------------------------------------------------------------------ +// AsyncTransformation::CreateInlinedFrameSuspensionTail: +// Create the block that runs the context handling of the frames enclosing an inlined +// async frame on suspension. +// +// Parameters: +// callBlock - The block containing the async call +// call - The async call +// layout - Information about the continuation layout +// +// Returns: +// The block to continue suspension in, or nullptr if this call is not inside an +// inlined async frame. +// +// Remarks: +// Each frame that has not yet resumed must capture the contexts it would hand to its +// caller, and restore its caller's contexts onto the thread, as if its physical frame +// had returned. A frame having resumed implies its caller has too, so the frames can be +// walked outward as a straight line: once one frame has resumed, the helpers for it and +// every frame outside it no-op. +// +// TODO-Async: suspensions in the same frame could share a tail when they agree on all +// of the values below, which would save some cold code. +// +BasicBlock* AsyncTransformation::CreateInlinedFrameSuspensionTail(BasicBlock* callBlock, + GenTreeCall* call, + const ContinuationLayout& layout, + GenTree* frameResumed) +{ + // The frames enclosing the one this call sits in. The frame's own set was consumed by + // the handling of the suspension itself, so what is left on the call is one set per + // enclosing frame. + unsigned numEnclosing = 0; + for (CallArg& arg : call->gtArgs.Args()) + { + if (arg.GetWellKnownArg() == WellKnownArg::AsyncResumedUse) + { + numEnclosing++; + } + } + + if (numEnclosing == 0) + { + // Not inside an inlined async frame, so there are no logical frame transitions to + // run and no context args beyond the ones the suspension itself consumed. + return nullptr; + } + + unsigned const numFrames = numEnclosing + 1; + + assert(frameResumed != nullptr); + + jitstd::vector* const handling = call->GetAsyncInfo().InlineFrameContextHandling; + assert((handling != nullptr) && (handling->size() == numEnclosing)); + + JITDUMP(" Call [%06u] is inside an inlined async frame; %u frames in chain\n", Compiler::dspTreeID(call), + numFrames); + + // Take the values of the enclosing frames off the call. These args are the source of + // truth for what to store: the optimizer may have rewritten them since they were + // added, for example folding a "resumed" indicator to a constant, and the stores must + // reflect that rather than re-reading the locals the args originally named. + ArrayStack values(m_compiler->getAllocator(CMK_Async)); + + for (unsigned i = 0; i + 1 < numFrames; i++) + { + CallArg* frameArgs[3] = {call->gtArgs.FindWellKnownArg(WellKnownArg::AsyncResumedUse), + call->gtArgs.FindWellKnownArg(WellKnownArg::AsyncExecutionContext), + call->gtArgs.FindWellKnownArg(WellKnownArg::AsyncSynchronizationContext)}; + + for (unsigned j = 0; j < 3; j++) + { + CallArg* arg = frameArgs[j]; + assert(arg != nullptr); + + GenTree* node = arg->GetNode(); + if (!node->IsInvariant() && !node->OperIs(GT_LCL_VAR)) + { + // We are going to reference this from a different block, so spill it. + LIR::Use use(LIR::AsRange(callBlock), &arg->NodeRef(), call); + use.ReplaceWithLclVar(m_compiler); + node = use.Def(); + } + + LIR::AsRange(callBlock).Remove(node); + call->gtArgs.RemoveUnsafe(arg); + values.Push(node); + } + } + + if (m_sharedReturnBB == nullptr) + { + CreateSharedReturnBB(); + } + + BasicBlock* tailBB = m_compiler->fgNewBBbefore(BBJ_ALWAYS, m_sharedReturnBB, false); + tailBB->bbSetRunRarely(); + tailBB->clearTryIndex(); + tailBB->clearHndIndex(); + tailBB->SetKindAndTargetEdge(BBJ_ALWAYS, m_compiler->fgAddRefPred(m_sharedReturnBB, tailBB)); + + if (m_compiler->fgIsUsingProfileWeights()) + { + tailBB->SetFlags(BBF_PROF_WEIGHT); + } + + JITDUMP(" Created inlined frame suspension tail " FMT_BB " for %u frames\n", tailBB->bbNum, numFrames); + + // A frame's handling below runs only the first time the physical frame suspends + // underneath it. Once any frame at or inside it has resumed, its continuation already + // exists and holds what it captured then, so redoing the capture would overwrite it + // and redoing the restore would put the wrong contexts back on the thread. + // + // A frame's own indicator is not enough to see that: it is only set when the frame + // logically returns, which has not happened yet at a suspension. So accumulate the + // indicators of the frames walked so far and gate on that instead. + unsigned const anyResumedLcl = m_compiler->lvaGrabTemp(false DEBUGARG("Async any inlined frame resumed")); + LclVarDsc* const anyResumedDsc = m_compiler->lvaGetDesc(anyResumedLcl); + anyResumedDsc->lvType = TYP_INT; + anyResumedDsc->lvOnlyUsedOnSynchronousPath = true; + + GenTree* const initAnyResumed = + m_compiler->gtNewStoreLclVarNode(anyResumedLcl, m_compiler->gtCloneExpr(frameResumed)); + LIR::AsRange(tailBB).InsertAtEnd(LIR::SeqTree(m_compiler, initAnyResumed)); + + for (unsigned i = 0; i + 1 < numFrames; i++) + { + GenTree* const outerResumed = values.Bottom((int)(i * 3)); + GenTree* const outerExec = values.Bottom((int)(i * 3 + 1)); + GenTree* const outerSync = values.Bottom((int)(i * 3 + 2)); + unsigned const depth = numFrames - 1 - i; + + // Capture what this frame hands to its caller. The members are only ever read by + // the post-inline frame transition IR, so if that IR was optimized away -- for + // example because a no-return call in the inlinee made it unreachable -- the + // members have no storage and there is nothing to capture. The layout gives all + // three members of a frame storage if any of them is read, so testing one is + // enough. + size_t flagsIndex = 0; + bool membersAreLive = + m_compiler->TryGetContinuationMemberIndex(ContinuationMember::InlineFrameFlags(depth), &flagsIndex); + assert(membersAreLive && "suspension tail needs a frame whose members were never registered"); + membersAreLive = membersAreLive && (layout.ContinuationMemberOffsets[flagsIndex] != UINT_MAX); + + if (membersAreLive) + { + // The caller's await decides whether this frame has to come back to the + // context it was on when it suspended. + ContinuationContextHandling const frameHandling = (*handling)[i]; + CORINFO_METHOD_HANDLE captureMethHnd; + bool captureContinuationContext = false; + switch (frameHandling) + { + case ContinuationContextHandling::ContinueOnCapturedContext: + captureMethHnd = m_asyncInfo->captureInlinedFrameTransitionWithContinuationContextMethHnd; + captureContinuationContext = true; + break; + + case ContinuationContextHandling::ContinueOnThreadPool: + captureMethHnd = m_asyncInfo->captureInlinedFrameTransitionContinueOnThreadPoolMethHnd; + break; + + case ContinuationContextHandling::None: + captureMethHnd = m_asyncInfo->captureInlinedFrameTransitionNoContinuationContextMethHnd; + break; + + default: + unreached(); + } + + GenTreeCall* captureCall = m_compiler->gtNewUserCallNode(captureMethHnd, TYP_VOID); + + NewCallArg execCtxArg = NewCallArg::Primitive( + ContinuationMemberAddress(layout, ContinuationMember::InlineFrameExecutionContext(depth))); + NewCallArg flagsArg = + NewCallArg::Primitive(ContinuationMemberAddress(layout, ContinuationMember::InlineFrameFlags(depth))); + NewCallArg anyResumedArg = NewCallArg::Primitive(m_compiler->gtNewLclvNode(anyResumedLcl, TYP_INT)); + + captureCall->gtArgs.PushFront(m_compiler, execCtxArg); + captureCall->gtArgs.PushFront(m_compiler, flagsArg); + if (captureContinuationContext) + { + NewCallArg contContextArg = NewCallArg::Primitive( + ContinuationMemberAddress(layout, ContinuationMember::InlineFrameContinuationContext(depth))); + captureCall->gtArgs.PushFront(m_compiler, contContextArg); + } + captureCall->gtArgs.PushFront(m_compiler, anyResumedArg); + + m_compiler->compCurBB = tailBB; + m_compiler->fgMorphTree(captureCall); + LIR::AsRange(tailBB).InsertAtEnd(LIR::SeqTree(m_compiler, captureCall)); + } + else + { + JITDUMP(" No reads of inline frame depth %u members survived; skipping its capture\n", depth); + } + + // Fold in the frame we are about to hand off to: from here on out its handling, + // and that of every frame outside it, is likewise only needed the first time. + GenTree* const merged = + m_compiler->gtNewOperNode(GT_OR, TYP_INT, m_compiler->gtNewLclvNode(anyResumedLcl, TYP_INT), + m_compiler->gtCloneExpr(outerResumed)); + GenTree* const orStore = m_compiler->gtNewStoreLclVarNode(anyResumedLcl, merged); + LIR::AsRange(tailBB).InsertAtEnd(LIR::SeqTree(m_compiler, orStore)); + + // Then restore the caller's contexts, as its physical frame's return would have. + GenTreeCall* restoreCall = + m_compiler->gtNewUserCallNode(m_asyncInfo->restoreContextsOnSuspensionMethHnd, TYP_VOID); + NewCallArg outerSyncArg = NewCallArg::Primitive(m_compiler->gtCloneExpr(outerSync)); + NewCallArg outerExecArg = NewCallArg::Primitive(m_compiler->gtCloneExpr(outerExec)); + NewCallArg anyResumedArg = NewCallArg::Primitive(m_compiler->gtNewLclvNode(anyResumedLcl, TYP_INT)); + + restoreCall->gtArgs.PushFront(m_compiler, outerSyncArg); + restoreCall->gtArgs.PushFront(m_compiler, outerExecArg); + restoreCall->gtArgs.PushFront(m_compiler, anyResumedArg); + + m_compiler->compCurBB = tailBB; + m_compiler->fgMorphTree(restoreCall); + LIR::AsRange(tailBB).InsertAtEnd(LIR::SeqTree(m_compiler, restoreCall)); + } + + DISPRANGE(LIR::AsRange(tailBB)); + + return tailBB; +} + +//------------------------------------------------------------------------ +// AsyncTransformation::ContinuationMemberAddress: +// Create the address of a continuation member in the newly created continuation. +// +// Parameters: +// layout - Information about the continuation layout +// member - The member +// +// Returns: +// IR node computing the address. +// +GenTree* AsyncTransformation::ContinuationMemberAddress(const ContinuationLayout& layout, + const ContinuationMember& member) +{ + // Layout is fixed at this point, so this is expected not to add new entries. + size_t memberIndex = 0; + bool isRegistered = m_compiler->TryGetContinuationMemberIndex(member, &memberIndex); + assert(isRegistered); + assert(memberIndex < layout.ContinuationMemberOffsets.size()); + assert(layout.ContinuationMemberOffsets[memberIndex] != UINT_MAX); + + unsigned const offset = OFFSETOF__CORINFO_Continuation__data + layout.ContinuationMemberOffsets[memberIndex]; + GenTree* const continuation = m_compiler->gtNewLclvNode(GetNewContinuationVar(), TYP_REF); + return m_compiler->gtNewOperNode(GT_ADD, TYP_BYREF, continuation, + m_compiler->gtNewIconNode((ssize_t)offset, TYP_I_IMPL)); +} + //------------------------------------------------------------------------ // AsyncTransformation::RestoreContexts: // Create IR to restore contexts on suspension. @@ -2961,7 +3632,11 @@ void AsyncTransformation::FinishContextHandlingAndSuspensionWithHelper(BasicBloc // call - The async call // suspendBB - The basic block to add IR to. // -void AsyncTransformation::RestoreContexts(BasicBlock* block, GenTreeCall* call, BasicBlock* suspendBB) +// Returns: +// The node holding the frame's resumed indicator, or nullptr if the call has no +// contexts. The suspension tail needs it to gate this frame's own transition. +// +GenTree* AsyncTransformation::RestoreContexts(BasicBlock* block, GenTreeCall* call, BasicBlock* suspendBB) { CallArg* resumedArg = call->gtArgs.FindWellKnownArg(WellKnownArg::AsyncResumedUse); CallArg* execContextArg = call->gtArgs.FindWellKnownArg(WellKnownArg::AsyncExecutionContext); @@ -2972,7 +3647,7 @@ void AsyncTransformation::RestoreContexts(BasicBlock* block, GenTreeCall* call, { JITDUMP(" Call [%06u] does not have async contexts; skipping restore on suspension\n", Compiler::dspTreeID(call)); - return; + return nullptr; } JITDUMP(" Call [%06u] has async contexts; will restore on suspension\n", Compiler::dspTreeID(call)); @@ -3057,6 +3732,8 @@ void AsyncTransformation::RestoreContexts(BasicBlock* block, GenTreeCall* call, JITDUMP(" Created RestoreContexts call on suspension:\n"); DISPTREERANGE(LIR::AsRange(suspendBB), restoreCall); + + return resumed; } //------------------------------------------------------------------------ diff --git a/src/runtime/src/coreclr/jit/async.h b/src/runtime/src/coreclr/jit/async.h index cc4eea0ae034..0f58e072b699 100644 --- a/src/runtime/src/coreclr/jit/async.h +++ b/src/runtime/src/coreclr/jit/async.h @@ -3,7 +3,18 @@ enum class ContinuationMemberType { + // A custom awaiter, stored so that it can be awaited from the continuation. + // Deduplicated by layout: all awaits of compatible awaiter types share one slot. CustomAwaiterOfLayout, + // The ExecutionContext an inlined async frame captured when it logically returned + // to its caller. Deduplicated by inline depth. + InlineFrameExecutionContext, + // The continuation context an inlined async frame captured when it logically + // returned to its caller. Deduplicated by inline depth. + InlineFrameContinuationContext, + // The ContinuationFlags describing the above continuation context. Deduplicated by + // inline depth. + InlineFrameFlags, }; struct ContinuationMember @@ -11,12 +22,31 @@ struct ContinuationMember ContinuationMemberType Type; void Print() const; + private: ClassLayout* m_customAwaiterLayout; + unsigned m_inlineDepth; public: - ClassLayout* GetCustomAwaiterLayout() const; + ClassLayout* GetCustomAwaiterLayout() const; + unsigned GetInlineDepth() const; + + // Whether this member describes what an inlined async frame hands to its caller, and + // so is keyed by inline depth. + bool IsInlineFrameMember() const + { + return (Type == ContinuationMemberType::InlineFrameExecutionContext) || + (Type == ContinuationMemberType::InlineFrameContinuationContext) || + (Type == ContinuationMemberType::InlineFrameFlags); + } + + // The type of the storage this member requires in the continuation. + var_types GetStorageType(ClassLayout** layout) const; + static ContinuationMember CustomAwaiterOfLayout(ClassLayout* layout); + static ContinuationMember InlineFrameExecutionContext(unsigned inlineDepth); + static ContinuationMember InlineFrameContinuationContext(unsigned inlineDepth); + static ContinuationMember InlineFrameFlags(unsigned inlineDepth); static bool AreCompatible(const ContinuationMember& a, const ContinuationMember& b); }; @@ -414,8 +444,6 @@ class AsyncTransformation AsyncAnalysis& analyses, ContinuationLayoutBuilder* layoutBuilder); - bool HasNonContextRestoreExceptionalFlow(BasicBlock* block); - void LiftLIREdges(BasicBlock* block, const jitstd::vector& defs, ContinuationLayoutBuilder* layoutBuilder); @@ -476,7 +504,7 @@ class AsyncTransformation const ContinuationLayout& layout, const ContinuationLayoutBuilder& subLayout, SuspensionContextHelper helper); - void RestoreContexts(BasicBlock* block, GenTreeCall* call, BasicBlock* insertionBB); + GenTree* RestoreContexts(BasicBlock* block, GenTreeCall* call, BasicBlock* insertionBB); void StoreAsyncAwaiter(BasicBlock* callBlock, GenTreeCall* call, BasicBlock* suspendBB, @@ -517,30 +545,34 @@ class AsyncTransformation var_types storeType, GenTreeFlags indirFlags = GTF_IND_NONFAULTING); - void CreateDebugInfoForSuspensionPoint(const ContinuationLayout& layout, - const ContinuationLayoutBuilder& subLayout); - unsigned GetReturnedContinuationVar(); - unsigned GetNewContinuationVar(); - unsigned GetResultBaseVar(); - unsigned GetExceptionVar(); - void CreateSharedReturnBB(); - BasicBlock* CreateSharedFinishContextHandlingBB(SuspensionContextHelper helper, - const ContinuationLayout& layout, - GenTree* invariantResumed, - bool execContextMayVary, - bool syncContextMayVary); - void InsertFinishContextHandlingCall(BasicBlock* block, - const ContinuationLayout& layout, - SuspensionContextHelper helper, - GenTree* resumed, - GenTree* execContext, - GenTree* syncContext); - bool ReuseContinuations(); - + void CreateDebugInfoForSuspensionPoint(const ContinuationLayout& layout, + const ContinuationLayoutBuilder& subLayout); + unsigned GetReturnedContinuationVar(); + unsigned GetNewContinuationVar(); + unsigned GetResultBaseVar(); + unsigned GetExceptionVar(); + void CreateSharedReturnBB(); + BasicBlock* CreateSharedFinishContextHandlingBB(SuspensionContextHelper helper, + const ContinuationLayout& layout, + GenTree* invariantResumed, + bool execContextMayVary, + bool syncContextMayVary); + void InsertFinishContextHandlingCall(BasicBlock* block, + const ContinuationLayout& layout, + SuspensionContextHelper helper, + GenTree* resumed, + GenTree* execContext, + GenTree* syncContext); GenTreeLclVarCommon* FindAndRemoveCommonAsyncResumedDef(); const ContinuationLayout* CreateResumptionsAndSuspensions(ArrayStack& continuationMemberOffsets); void CreateResumptionSwitch(GenTreeLclVarCommon* commonAsyncResumedDef); + BasicBlock* CreateInlinedFrameSuspensionTail(BasicBlock* callBlock, + GenTreeCall* call, + const ContinuationLayout& layout, + GenTree* frameResumed); + GenTree* ContinuationMemberAddress(const ContinuationLayout& layout, const ContinuationMember& member); + public: AsyncTransformation(Compiler* comp) : m_compiler(comp) diff --git a/src/runtime/src/coreclr/jit/block.cpp b/src/runtime/src/coreclr/jit/block.cpp index 27711d0dc4e5..d7bfc21e46d0 100644 --- a/src/runtime/src/coreclr/jit/block.cpp +++ b/src/runtime/src/coreclr/jit/block.cpp @@ -550,6 +550,7 @@ void BasicBlock::dspFlags() const {BBF_ASYNC_RESUMPTION, "a-resume"}, {BBF_CATCH_RESUMPTION, "c-resume"}, {BBF_THROW_HELPER, "throw-hlpr"}, + {BBF_STALE_PREDICATE, "stale-pred"}, }; bool first = true; diff --git a/src/runtime/src/coreclr/jit/block.h b/src/runtime/src/coreclr/jit/block.h index 5d12efdc0888..c8fec368a6bf 100644 --- a/src/runtime/src/coreclr/jit/block.h +++ b/src/runtime/src/coreclr/jit/block.h @@ -447,6 +447,8 @@ enum BasicBlockFlags : uint64_t BBF_ASYNC_RESUMPTION = MAKE_BBFLAG(36), // Block is a resumption block in an async method BBF_CATCH_RESUMPTION = MAKE_BBFLAG(37), // Block is a resumption from a catch BBF_THROW_HELPER = MAKE_BBFLAG(38), // Block is a call to a throw helper + BBF_STALE_PREDICATE = MAKE_BBFLAG(39), // Block's branch condition VN only describes flow that + // actually passes through the block (set/used by RBO) // The following are sets of flags. diff --git a/src/runtime/src/coreclr/jit/codegenarm64.cpp b/src/runtime/src/coreclr/jit/codegenarm64.cpp index b1dfa28f5172..85bebf191cc2 100644 --- a/src/runtime/src/coreclr/jit/codegenarm64.cpp +++ b/src/runtime/src/coreclr/jit/codegenarm64.cpp @@ -2196,7 +2196,9 @@ void CodeGen::instGen_Set_Reg_To_Imm(emitAttr size, } else { - if (emitter::emitIns_valid_imm_for_mov(imm, size)) + emitAttr immSize = EA_SIZE(size); + + if (emitter::emitIns_valid_imm_for_mov(imm, immSize)) { GetEmitter()->emitIns_R_I(INS_mov, size, reg, imm, INS_OPTS_NONE, INS_SCALABLE_OPTS_NONE DEBUGARG(targetHandle) DEBUGARG(gtFlags)); @@ -2214,7 +2216,7 @@ void CodeGen::instGen_Set_Reg_To_Imm(emitAttr size, // Determine whether movn or movz will require the fewest instructions to populate the immediate int preferMovn = 0; - for (int i = (size == EA_8BYTE) ? 48 : 16; i >= 0; i -= 16) + for (int i = (immSize == EA_8BYTE) ? 48 : 16; i >= 0; i -= 16) { if (uint16_t(imm >> i) == 0xffff) ++preferMovn; // a single movk 0xffff could be skipped if movn was used @@ -2229,7 +2231,7 @@ void CodeGen::instGen_Set_Reg_To_Imm(emitAttr size, // This can allow skipping filling a halfword uint16_t skipVal = (preferMovn > 0) ? 0xffff : 0; - unsigned bits = (size == EA_8BYTE) ? 64 : 32; + unsigned bits = (immSize == EA_8BYTE) ? 64 : 32; // Iterate over imm examining 16 bits at a time for (unsigned i = 0; i < bits; i += 16) diff --git a/src/runtime/src/coreclr/jit/codegencommon.cpp b/src/runtime/src/coreclr/jit/codegencommon.cpp index 00b3d5f0935c..1ec58f10841f 100644 --- a/src/runtime/src/coreclr/jit/codegencommon.cpp +++ b/src/runtime/src/coreclr/jit/codegencommon.cpp @@ -2260,7 +2260,7 @@ void CodeGen::genGenerateMachineCode() } printf(" for "); - printf(Target::g_tgtCPUName); + printf("%s", Target::g_tgtCPUName); #if defined(TARGET_XARCH) // Check ISA directly here instead of using @@ -3031,7 +3031,7 @@ void CodeGen::genGCWriteBarrier(GenTreeStoreInd* store, GCInfo::WriteBarrierForm unclassifiedBarrierSite++; printf("unclassifiedBarrierSite = %d:\n", unclassifiedBarrierSite); m_compiler->gtDispTree(store); - printf(""); // Flush. + fflush(jitstdout()); printf("\n"); } #endif // DEBUG @@ -3247,7 +3247,7 @@ class RegGraph printf(" %s", getRegName(regNode->reg)); for (RegNodeEdge* incoming = regNode->incoming; incoming != nullptr; incoming = incoming->nextIncoming) { - printf("\n <- %s", getRegName(incoming->from->reg), varTypeName(incoming->type)); + printf("\n <- %s (%s)", getRegName(incoming->from->reg), varTypeName(incoming->type)); if (incoming->destOffset != 0) { @@ -6987,7 +6987,7 @@ void CodeGen::genReportRichDebugInfoInlineTreeToFile(FILE* file, InlineContext* *first = false; fprintf(file, "{\"Ordinal\":%u,", context->GetOrdinal()); - fprintf(file, "\"MethodID\":%lld,", (int64_t)context->GetCallee()); + fprintf(file, "\"MethodID\":%lld,", (long long)context->GetCallee()); fprintf(file, "\"ILOffset\":%u,", context->GetLocation().GetOffset()); fprintf(file, "\"LocationFlags\":%u,", (uint32_t)context->GetLocation().GetSourceTypes()); fprintf(file, "\"ExactILOffset\":%u,", context->GetActualCallOffset()); @@ -7028,7 +7028,7 @@ void CodeGen::genReportRichDebugInfoToFile() } // MethodID in ETW events are the method handles. - fprintf(file, "{\"MethodID\":%lld,", (INT64)m_compiler->info.compMethodHnd); + fprintf(file, "{\"MethodID\":%lld,", (long long)m_compiler->info.compMethodHnd); // Print inline tree. fprintf(file, "\"InlineTree\":"); diff --git a/src/runtime/src/coreclr/jit/codegenlinear.cpp b/src/runtime/src/coreclr/jit/codegenlinear.cpp index 1cb9b830a127..a21a859edc2c 100644 --- a/src/runtime/src/coreclr/jit/codegenlinear.cpp +++ b/src/runtime/src/coreclr/jit/codegenlinear.cpp @@ -198,7 +198,7 @@ void CodeGen::genCodeForBBlist() if (m_compiler->verbose) { printf("\n# "); - printf("compCycleEstimate = %6d, compSizeEstimate = %5d ", m_compiler->compCycleEstimate, + printf("compCycleEstimate = %6zu, compSizeEstimate = %5zu ", m_compiler->compCycleEstimate, m_compiler->compSizeEstimate); printf("%s\n", m_compiler->info.compFullName); } diff --git a/src/runtime/src/coreclr/jit/codegenxarch.cpp b/src/runtime/src/coreclr/jit/codegenxarch.cpp index 7ac31ae170ce..0c3c3ee5419a 100644 --- a/src/runtime/src/coreclr/jit/codegenxarch.cpp +++ b/src/runtime/src/coreclr/jit/codegenxarch.cpp @@ -8322,7 +8322,7 @@ void* CodeGen::genCreateAndStoreGCInfoJIT32(unsigned codeSize, { if (temp == ptab) { - printf("\nMethod info block - ptrtab [%u bytes]:", ptrMapSize); + printf("\nMethod info block - ptrtab [%zu bytes]:", ptrMapSize); printf("\n %04X: %*c", i & ~0xF, 3 * (i & 0xF), ' '); } else @@ -8349,7 +8349,7 @@ void* CodeGen::genCreateAndStoreGCInfoJIT32(unsigned codeSize, InfoHdr dumpHeader; printf("GC Info for method %s\n", m_compiler->info.compFullName); - printf("GC info size = %3u\n", m_compiler->compInfoBlkSize); + printf("GC info size = %3zu\n", m_compiler->compInfoBlkSize); size = gcInfo.gcInfoBlockHdrDump(base, &dumpHeader, &methodSize); // printf("size of header encoding is %3u\n", size); diff --git a/src/runtime/src/coreclr/jit/compiler.cpp b/src/runtime/src/coreclr/jit/compiler.cpp index 335f4aa86f0d..dbc56f2344e5 100644 --- a/src/runtime/src/coreclr/jit/compiler.cpp +++ b/src/runtime/src/coreclr/jit/compiler.cpp @@ -2698,7 +2698,7 @@ void Compiler::compInitOptions(JitFlags* jitFlags) { printf("****** START compiling %s (MethodHash=%08x)\n", info.compFullName, info.compMethodHash()); printf("Generating code for %s %s\n", Target::g_tgtPlatformName(), Target::g_tgtCPUName); - printf(""); // in our logic this causes a flush + fflush(jitstdout()); } if (JitConfig.JitBreak().contains(info.compMethodHnd, info.compClassHnd, &info.compMethodInfo->args)) @@ -6644,7 +6644,7 @@ void Compiler::compCompileFinish() printf(" %3d |", info.compTotalColdCodeSize); printf(" %s\n", eeGetMethodFullName(info.compMethodHnd)); - printf(""); // in our logic this causes a flush + fflush(jitstdout()); } JITDUMP("Final metrics:\n"); @@ -6657,7 +6657,7 @@ void Compiler::compCompileFinish() if (verbose) { printf("\n****** DONE compiling %s\n", info.compFullName); - printf(""); // in our logic this causes a flush + fflush(jitstdout()); } #if TRACK_ENREG_STATS @@ -8006,7 +8006,7 @@ const CORINFO_FPSTRUCT_LOWERING* Compiler::GetFpStructLowering(CORINFO_CLASS_HAN #ifdef DEBUG if (verbose) { - printf("**** getFpStructInRegistersInfo(0x%x (%s, %u bytes)) =>\n", dspPtr(structHandle), + printf("**** getFpStructInRegistersInfo(%p (%s, %u bytes)) =>\n", (void*)dspPtr(structHandle), eeGetClassName(structHandle), info.compCompHnd->getClassSize(structHandle)); if (lowering->byIntegerCallConv) diff --git a/src/runtime/src/coreclr/jit/compiler.h b/src/runtime/src/coreclr/jit/compiler.h index 0bd46b3783c1..03fa22ec8c54 100644 --- a/src/runtime/src/coreclr/jit/compiler.h +++ b/src/runtime/src/coreclr/jit/compiler.h @@ -21,6 +21,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #define _COMPILER_H_ /*****************************************************************************/ +#include #include "jit.h" #include "opcode.h" #include "varset.h" @@ -664,6 +665,12 @@ class LclVarDsc unsigned char lvIsEnumerator : 1; // Local is assigned exact class where : IEnumerable via GDV + // The local is only ever read on the synchronous path of an async method, i.e. before + // the frame it belongs to has resumed. Suspension does not need to capture it: on + // resumption its value is either re-established (the resumed indicator is stored by + // the resumption path) or dead (the contexts are only read when not resumed). + unsigned char lvOnlyUsedOnSynchronousPath : 1; + private: unsigned char lvIsNeverNegative : 1; // The local is known to be never negative @@ -4406,6 +4413,16 @@ class Compiler unsigned short asyncContextRestoreEHID = USHRT_MAX; + // IDs of every EH clause created by SaveAsyncContexts, both for this method and for + // all frames inlined into it. Maintained on the inline root, since an inlinee's + // clause survives inlining as a clause of the root. EH IDs are stable across + // inlining, so this stays valid after the tables are merged. + typedef JitHashTable, bool> AsyncContextRestoreEHIDSet; + AsyncContextRestoreEHIDSet* m_asyncContextRestoreEHIDs = nullptr; + + bool ehIsAsyncContextRestore(unsigned short ehID); + bool ehIsInsideNonAsyncContextRestoreRegion(BasicBlock* block); + unsigned lvaArg0Var = BAD_VAR_NUM; // The lclNum of arg0. Normally this will be info.compThisArg. // However, if there is a "ldarga 0" or "starg 0" in the IL, // we will redirect all "ldarg(a) 0" and "starg 0" to this temp. @@ -4445,6 +4462,12 @@ class Compiler // Variable representing async continuation argument passed. unsigned lvaAsyncContinuationArg = BAD_VAR_NUM; + // For async methods with CORINFO_ASYNC_SAVE_CONTEXTS: whether the body contains any + // async call, i.e. any point at which this method may suspend. Computed by + // SaveAsyncContexts. When false for an inlinee, its resumed indicator is provably + // always false and no post-inline async frame IR needs to be emitted for it. + bool compAsyncBodyMaySuspend = false; + #if defined(DEBUG) && defined(TARGET_XARCH) unsigned lvaReturnSpCheck = BAD_VAR_NUM; // Stores SP to confirm it is not corrupted on return. @@ -5314,9 +5337,9 @@ class Compiler GenTree** instParam, NamedIntrinsic ni); - void impSetupAsyncCall(GenTreeCall* call, CORINFO_METHOD_HANDLE methHnd, OPCODE opcode, unsigned prefixFlags, NamedIntrinsic ni, const DebugInfo& callDI); + void impSetupAsyncCall(GenTreeCall* call, CORINFO_METHOD_HANDLE methHnd, OPCODE opcode, unsigned prefixFlags, NamedIntrinsic ni, const DebugInfo& callDI, bool* usesOwnContexts); - void impInsertAsyncArgsForLdvirtftnCall(GenTreeCall* call); + void impInsertAsyncArgsForLdvirtftnCall(GenTreeCall* call, bool usesOwnContexts); void impInheritAsyncContextsFromInliner(GenTreeCall* call); CORINFO_CLASS_HANDLE impGetSpecialIntrinsicExactReturnType(GenTreeCall* call); @@ -6315,7 +6338,8 @@ class Compiler jitstd::vector* m_asyncContinuationMembers = nullptr; size_t GetContinuationMemberIndex(const ContinuationMember& member); - size_t GetContinuationMemberCount() const; + bool TryGetContinuationMemberIndex(const ContinuationMember& member, size_t* index); + size_t GetContinuationMemberCount(); const ContinuationMember& GetContinuationMember(size_t index); PhaseStatus SaveAsyncContexts(); @@ -7570,6 +7594,9 @@ class Compiler void fgInsertInlineeArgument(const InlArgInfo& argInfo, BasicBlock* block, Statement** afterStmt, Statement** newStmt, const DebugInfo& callDI); Statement* fgInlinePrependStatements(InlineInfo* inlineInfo); void fgInlineAppendStatements(InlineInfo* inlineInfo, BasicBlock* block, Statement* stmt); + void fgInlineAppendAsyncFrameStatements(InlineInfo* inlineInfo, BasicBlock* joinBlock); + void fgSetupAsyncFrameTransitionCall(GenTreeCall* call, const DebugInfo& di); + GenTree* gtNewContinuationMemberIndir(const struct ContinuationMember& member, var_types type); #ifdef DEBUG static fgWalkPreFn fgDebugCheckInlineCandidates; @@ -11650,7 +11677,7 @@ class Compiler const char* devirtualizationDetailToString(CORINFO_DEVIRTUALIZATION_DETAIL detail); - const char* printfAlloc(const char* format, ...); + const char* printfAlloc(const char* format, ...) MINIPAL_ATTR_FORMAT_PRINTF(2, 3); void convertUtf16ToUtf8ForPrinting(const char16_t* utf16Src, size_t utf16SrcLen, char* utf8Dst, size_t utf8DstLen); @@ -11998,6 +12025,14 @@ class Compiler return (info.compMethodInfo->options & CORINFO_ASYNC_VERSION) != 0; } + // Is general inlining of runtime async calls enabled, i.e. inlining of async callees + // that may suspend? When disabled only the restricted cases are inlined: callees + // without any awaits, async versions of synchronous methods, and tail awaits. + static bool generalAsyncInliningEnabled() + { + return JitConfig.JitAsyncInlining() != 0; + } + //------------------------------------------------------------------------ // compMethodReturnsMultiRegRetType: Does this method return a multi-reg value? // @@ -12451,7 +12486,7 @@ class Compiler // more log information // levels are currently unused: #define JITDUMP(level,...) (); - void JitLogEE(unsigned level, const char* fmt, ...); + void JitLogEE(unsigned level, const char* fmt, ...) MINIPAL_ATTR_FORMAT_PRINTF(3, 4); bool compDebugBreak; diff --git a/src/runtime/src/coreclr/jit/copyprop.cpp b/src/runtime/src/coreclr/jit/copyprop.cpp index 2777fde5f839..3003016fc2f3 100644 --- a/src/runtime/src/coreclr/jit/copyprop.cpp +++ b/src/runtime/src/coreclr/jit/copyprop.cpp @@ -215,6 +215,12 @@ bool Compiler::optCopyProp( continue; } + if (varDsc->lvOnlyUsedOnSynchronousPath || newLclVarDsc->lvOnlyUsedOnSynchronousPath) + { + // Do not touch these -- it will likely cause us to unnecessarily save state to the continuation. + continue; + } + if (optCopyProp_LclVarScore(varDsc, newLclVarDsc, true) <= 0) { continue; diff --git a/src/runtime/src/coreclr/jit/disasm.cpp b/src/runtime/src/coreclr/jit/disasm.cpp index 3eacb3d906fc..6788479ea2cd 100644 --- a/src/runtime/src/coreclr/jit/disasm.cpp +++ b/src/runtime/src/coreclr/jit/disasm.cpp @@ -1510,7 +1510,7 @@ void DisAssembler::disAsmCode(BYTE* hotCodePtr, assert(hotCodeSize > 0); if (coldCodeSize == 0) { - fprintf(disAsmFile, "************************** %hs:%hs size 0x%04IX **************************\n\n", + fprintf(disAsmFile, "************************** %s:%s size 0x%04zX **************************\n\n", disCurClassName, disCurMethodName, hotCodeSize); fprintf(disAsmFile, "Base address : %ph (RW: %ph)\n", dspAddr(hotCodePtr), dspAddr(hotCodePtrRW)); @@ -1518,7 +1518,7 @@ void DisAssembler::disAsmCode(BYTE* hotCodePtr, else { fprintf(disAsmFile, - "************************** %hs:%hs hot size 0x%04IX cold size 0x%04IX **************************\n\n", + "************************** %s:%s hot size 0x%04zX cold size 0x%04zX **************************\n\n", disCurClassName, disCurMethodName, hotCodeSize, coldCodeSize); fprintf(disAsmFile, "Hot address : %ph (RW: %ph)\n", dspAddr(hotCodePtr), dspAddr(hotCodePtrRW)); diff --git a/src/runtime/src/coreclr/jit/ee_il_dll.cpp b/src/runtime/src/coreclr/jit/ee_il_dll.cpp index 47af3c1f9b7e..60427093f3ee 100644 --- a/src/runtime/src/coreclr/jit/ee_il_dll.cpp +++ b/src/runtime/src/coreclr/jit/ee_il_dll.cpp @@ -1538,7 +1538,7 @@ void Compiler::eeGetSystemVAmd64PassStructInRegisterDescriptor( #ifdef DEBUG if (verbose) { - printf("**** getSystemVAmd64PassStructInRegisterDescriptor(0x%x (%s), ...) =>\n", dspPtr(structHnd), + printf("**** getSystemVAmd64PassStructInRegisterDescriptor(%p (%s), ...) =>\n", dspPtr(structHnd), eeGetClassName(structHnd)); printf(" passedInRegisters = %s\n", dspBool(structPassInRegDescPtr->passedInRegisters)); if (structPassInRegDescPtr->passedInRegisters) diff --git a/src/runtime/src/coreclr/jit/emit.cpp b/src/runtime/src/coreclr/jit/emit.cpp index e9e1fc34b99d..4611e0f92ba8 100644 --- a/src/runtime/src/coreclr/jit/emit.cpp +++ b/src/runtime/src/coreclr/jit/emit.cpp @@ -1064,7 +1064,7 @@ insGroup* emitter::emitSavIG(bool emitAdd) // If there's an error during emission, we may want to connect the post-copy address // of an instrDesc with the pre-copy address (the one that was originally created). This // printing enables that. - printf("copying instruction group from [0x%x..0x%x) to [0x%x..0x%x).\n", dspPtr(emitCurIGfreeBase), + printf("copying instruction group from [%p..%p) to [%p..%p).\n", dspPtr(emitCurIGfreeBase), dspPtr(emitCurIGfreeBase + sz), dspPtr(id), dspPtr(id + sz)); } #endif @@ -1890,7 +1890,7 @@ void emitter::emitCheckIGList() if (currIG->igOffs != currentOffset) { - printf("IG%02u has offset %08X, expected %08X\n", currIG->GetDisplayId(), currIG->igOffs, currentOffset); + printf("IG%02u has offset %08X, expected %08zX\n", currIG->GetDisplayId(), currIG->igOffs, currentOffset); assert(!"bad block offset"); } @@ -1981,7 +1981,7 @@ void emitter::emitCheckIGList() if (emitTotalCodeSize != 0 && emitTotalCodeSize != currentOffset) { - printf("Total code size is %08X, expected %08X\n", emitTotalCodeSize, currentOffset); + printf("Total code size is %08X, expected %08zX\n", emitTotalCodeSize, currentOffset); assert(!"bad total code size"); } @@ -3907,7 +3907,7 @@ const size_t hexEncodingSize = 19; // 8 bytes (wasm-objdump default) + 1 space. void emitter::emitDispInsIndent() { size_t indent = m_compiler->opts.disDiffable ? basicIndent : basicIndent + hexEncodingSize; - printf("%.*s", indent, " "); + printf("%.*s", static_cast(indent), " "); } //------------------------------------------------------------------------ // emitDispGCDeltaTitle: Print an appropriately indented title for a GC info delta @@ -4172,7 +4172,7 @@ void emitter::emitDispIG(insGroup* ig, bool displayFunc, bool displayInstruction printf("\n"); - printf("%*s; PrevGCVars=%s ", strlen(buff), "", + printf("%*s; PrevGCVars=%s ", static_cast(strlen(buff)), "", VarSetOps::ToString(m_compiler, igPh->igPhData->igPhPrevGCrefVars)); dumpConvertedVarSet(m_compiler, igPh->igPhData->igPhPrevGCrefVars); printf(", PrevGCrefRegs="); @@ -4183,7 +4183,7 @@ void emitter::emitDispIG(insGroup* ig, bool displayFunc, bool displayInstruction emitDispRegSet(igPh->igPhData->igPhPrevByrefRegs); printf("\n"); - printf("%*s; InitGCVars=%s ", strlen(buff), "", + printf("%*s; InitGCVars=%s ", static_cast(strlen(buff)), "", VarSetOps::ToString(m_compiler, igPh->igPhData->igPhInitGCrefVars)); dumpConvertedVarSet(m_compiler, igPh->igPhData->igPhInitGCrefVars); printf(", InitGCrefRegs="); @@ -4539,7 +4539,7 @@ size_t emitter::emitIssue1Instr(insGroup* ig, instrDesc* id, BYTE** dp) /* Make sure the instruction descriptor size also matches our expectations */ if (is != emitSizeOfInsDsc(id)) { - printf("%s at %u: Expected size = %u , actual size = %u\n", emitIfName(id->idInsFmt()), + printf("%s at %u: Expected size = %zu , actual size = %zu\n", emitIfName(id->idInsFmt()), id->idDebugOnlyInfo()->idNum, is, emitSizeOfInsDsc(id)); assert(is == emitSizeOfInsDsc(id)); } @@ -5354,7 +5354,7 @@ void emitter::emitJumpDistBind() } if (EMITVERBOSE) { - printf("Estimate of fwd jump [%08X/%03u]: %04X -> %04X = %04X\n", dspPtr(jmp), + printf("Estimate of fwd jump [%p/%03u]: %04X -> %04X = %04X\n", dspPtr(jmp), jmp->idDebugOnlyInfo()->idNum, srcInstrOffs, dstOffs, jmpDist); } #endif // DEBUG_EMIT @@ -5397,7 +5397,7 @@ void emitter::emitJumpDistBind() } if (EMITVERBOSE) { - printf("Estimate of bwd jump [%08X/%03u]: %04X -> %04X = %04X\n", dspPtr(jmp), + printf("Estimate of bwd jump [%p/%03u]: %04X -> %04X = %04X\n", dspPtr(jmp), jmp->idDebugOnlyInfo()->idNum, srcInstrOffs, dstOffs, jmpDist); } #endif // DEBUG_EMIT @@ -5591,7 +5591,7 @@ void emitter::emitJumpDistBind() #ifdef DEBUG if (EMITVERBOSE) { - printf("Shrinking jump [%08X/%03u]\n", dspPtr(jmp), jmp->idDebugOnlyInfo()->idNum); + printf("Shrinking jump [%p/%03u]\n", dspPtr(jmp), jmp->idDebugOnlyInfo()->idNum); } #endif noway_assert((unsigned short)sizeDif == sizeDif); @@ -7497,7 +7497,7 @@ unsigned emitter::emitEndCodeGen(Compiler* comp, if (isJccAffectedIns) { unsigned bytesCrossedBoundary = (unsigned)(afterInstrAddr & jccAlignBoundaryMask); - printf("; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (%s: %d ; jcc erratum) %dB boundary " + printf("; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (%s: %d ; jcc erratum) %zuB boundary " "...............................\n", codeGen->genInsDisplayName(curInstrDesc), bytesCrossedBoundary, jccAlignBoundary); } @@ -7542,7 +7542,7 @@ unsigned emitter::emitEndCodeGen(Compiler* comp, #ifdef DEBUG if (m_compiler->opts.disAsm || m_compiler->verbose) { - printf("\t\t\t\t\t\t;; size=%d bbWeight=%s PerfScore %.2f", (cp - bp), refCntWtd2str(ig->igWeight), + printf("\t\t\t\t\t\t;; size=%td bbWeight=%s PerfScore %.2f", (cp - bp), refCntWtd2str(ig->igWeight), ig->igPerfScore); } *instrCount += ig->igInsCnt; @@ -7664,12 +7664,12 @@ unsigned emitter::emitEndCodeGen(Compiler* comp, if (jmp->idjShort) { - printf("[5] Jump is at %08X\n", (adr + 1 - emitCodeBlock)); + printf("[5] Jump is at %08zX\n", static_cast(adr + 1 - emitCodeBlock)); printf("[5] Jump distance is %02X - %02X = %02X\n", *(BYTE*)adr, adj, *(BYTE*)adr - adj); } else { - printf("[5] Jump is at %08X\n", (adr + 4 - emitCodeBlock)); + printf("[5] Jump is at %08zX\n", static_cast(adr + 4 - emitCodeBlock)); printf("[5] Jump distance is %08X - %02X = %08X\n", *(int*)adr, adj, *(int*)adr - adj); } } @@ -8461,7 +8461,7 @@ void emitter::emitOutputDataSec(dataSecDsc* sec, AllocMemChunk* chunks) // absolute label table if (dsc->dsType == dataSection::blockAbsoluteAddr) { - JITDUMP(" section %u, size %u, block absolute addr\n", secNum++, dscSize); + JITDUMP(" section %u, size %zu, block absolute addr\n", secNum++, dscSize); assert(dscSize && dscSize % TARGET_POINTER_SIZE == 0); size_t numElems = dscSize / TARGET_POINTER_SIZE; @@ -8488,13 +8488,13 @@ void emitter::emitOutputDataSec(dataSecDsc* sec, AllocMemChunk* chunks) emitRecordRelocation(&(bDstRW[i]), target, CorInfoReloc::DIRECT); } - JITDUMP(" " FMT_BB ": 0x%p\n", block->bbNum, bDstRW[i]); + JITDUMP(" " FMT_BB ": 0x%llx\n", block->bbNum, static_cast(bDstRW[i])); } } // relative label table else if (dsc->dsType == dataSection::blockRelative32) { - JITDUMP(" section %u, size %u, block relative addr\n", secNum++, dscSize); + JITDUMP(" section %u, size %zu, block relative addr\n", secNum++, dscSize); size_t numElems = dscSize / 4; unsigned* uDstRW = (unsigned*)dstRW; @@ -8515,7 +8515,7 @@ void emitter::emitOutputDataSec(dataSecDsc* sec, AllocMemChunk* chunks) } else if (dsc->dsType == dataSection::asyncResumeInfo) { - JITDUMP(" section %u, size %u, async resume info\n", secNum++, dscSize); + JITDUMP(" section %u, size %zu, async resume info\n", secNum++, dscSize); size_t numElems = dscSize / sizeof(CORINFO_AsyncResumeInfo); @@ -8560,7 +8560,7 @@ void emitter::emitOutputDataSec(dataSecDsc* sec, AllocMemChunk* chunks) #ifdef DEBUG if (EMITVERBOSE) { - printf(" section %3u, size %2u, RWD%2u:\t", secNum++, dscSize, curOffs); + printf(" section %3u, size %2zu, RWD%2zu:\t", secNum++, dscSize, curOffs); for (size_t i = 0; i < dscSize; i++) { @@ -8675,7 +8675,8 @@ void emitter::emitDispDataSec(dataSecDsc* section, AllocMemChunk* dataChunks) } else { - printf("\tdq\t%016llXh", reinterpret_cast(emitOffsetToPtr(ig->igOffs))); + printf("\tdq\t%016llXh", static_cast( + reinterpret_cast(emitOffsetToPtr(ig->igOffs)))); } #endif // TARGET_64BIT } @@ -8755,7 +8756,8 @@ void emitter::emitDispDataSec(dataSecDsc* section, AllocMemChunk* dataChunks) { printf("\t= 4)\n", data->dsSize); } - printf("\tdd\t%08llXh\t", (UINT64) * reinterpret_cast(&data->Data()[i])); + printf("\tdd\t%08llXh\t", static_cast( + (UINT64) * reinterpret_cast(&data->Data()[i]))); printf("\t; %9.6g", FloatingPointUtils::convertToDouble(*reinterpret_cast(&data->Data()[i]))); i += 4; @@ -8766,7 +8768,8 @@ void emitter::emitDispDataSec(dataSecDsc* section, AllocMemChunk* dataChunks) { printf("\t= 8)\n", data->dsSize); } - printf("\tdq\t%016llXh", *reinterpret_cast(&data->Data()[i])); + printf("\tdq\t%016llXh", + static_cast(*reinterpret_cast(&data->Data()[i]))); printf("\t; %12.9g", *reinterpret_cast(&data->Data()[i])); i += 8; break; @@ -8824,12 +8827,14 @@ void emitter::emitDispDataSec(dataSecDsc* section, AllocMemChunk* dataChunks) { printf("\tdsSize); } - printf("\tdq\t%016llXh", *reinterpret_cast(&data->Data()[i])); + printf("\tdq\t%016llXh", + static_cast(*reinterpret_cast(&data->Data()[i]))); for (j = 8; j < 64; j += 8) { if (i + j >= data->dsSize) break; - printf(", %016llXh", *reinterpret_cast(&data->Data()[i + j])); + printf(", %016llXh", static_cast( + *reinterpret_cast(&data->Data()[i + j]))); } i += j; break; diff --git a/src/runtime/src/coreclr/jit/emitarm.cpp b/src/runtime/src/coreclr/jit/emitarm.cpp index d9a1f50f0fc7..c1d99adf93f6 100644 --- a/src/runtime/src/coreclr/jit/emitarm.cpp +++ b/src/runtime/src/coreclr/jit/emitarm.cpp @@ -5352,8 +5352,10 @@ BYTE* emitter::emitOutputLJ(insGroup* ig, BYTE* dst, instrDesc* i) if (INTERESTING_JUMP_NUM == 0) printf("[3] Jump %u:\n", id->idDebugOnlyInfo()->idNum); - printf("[3] Jump block is at %08X - %02X = %08X\n", blkOffs, emitOffsAdj, blkOffs - emitOffsAdj); - printf("[3] Jump is at %08X - %02X = %08X\n", srcOffs, emitOffsAdj, srcOffs - emitOffsAdj); + printf("[3] Jump block is at %08X - %02X = %08X\n", (unsigned)blkOffs, emitOffsAdj, + (unsigned)(blkOffs - emitOffsAdj)); + printf("[3] Jump is at %08X - %02X = %08X\n", (unsigned)srcOffs, emitOffsAdj, + (unsigned)(srcOffs - emitOffsAdj)); printf("[3] Label block is at %08X - %02X = %08X\n", dstOffs, emitOffsAdj, dstOffs - emitOffsAdj); } #endif @@ -5398,8 +5400,8 @@ BYTE* emitter::emitOutputLJ(insGroup* ig, BYTE* dst, instrDesc* i) if (INTERESTING_JUMP_NUM == 0) printf("[4] Jump %u:\n", id->idDebugOnlyInfo()->idNum); - printf("[4] Jump block is at %08X\n", blkOffs); - printf("[4] Jump is at %08X\n", srcOffs); + printf("[4] Jump block is at %08X\n", (unsigned)blkOffs); + printf("[4] Jump is at %08X\n", (unsigned)srcOffs); printf("[4] Label block is at %08X - %02X = %08X\n", dstOffs + emitOffsAdj, emitOffsAdj, dstOffs); } #endif @@ -5415,8 +5417,9 @@ BYTE* emitter::emitOutputLJ(insGroup* ig, BYTE* dst, instrDesc* i) { size_t sz = 4; // Thumb-2 pretends all instructions are 4-bytes long for computing jump offsets? int distValSize = id->idjShort ? 4 : 8; - printf("; %s jump [%08X/%03u] from %0*X to %0*X: dist = 0x%08X\n", (dstOffs <= srcOffs) ? "Fwd" : "Bwd", - dspPtr(id), id->idDebugOnlyInfo()->idNum, distValSize, srcOffs + sz, distValSize, dstOffs, distVal); + printf("; %s jump [%p/%03u] from %0*X to %0*X: dist = 0x%08X\n", (dstOffs <= srcOffs) ? "Fwd" : "Bwd", + dspPtr(id), id->idDebugOnlyInfo()->idNum, distValSize, (unsigned)(srcOffs + sz), distValSize, dstOffs, + (int)distVal); } #endif @@ -6821,7 +6824,7 @@ void emitter::emitDispCond(int cond) const static char* armCond[16] = {"eq", "ne", "hs", "lo", "mi", "pl", "vs", "vc", "hi", "ls", "ge", "lt", "gt", "le", "AL", "NV"}; // The last two are invalid assert(0 <= cond && (unsigned)cond < ArrLen(armCond)); - printf(armCond[cond]); + printf("%s", armCond[cond]); } /***************************************************************************** diff --git a/src/runtime/src/coreclr/jit/emitarm64.cpp b/src/runtime/src/coreclr/jit/emitarm64.cpp index ddacc99a6004..df354db94fe5 100644 --- a/src/runtime/src/coreclr/jit/emitarm64.cpp +++ b/src/runtime/src/coreclr/jit/emitarm64.cpp @@ -10825,7 +10825,7 @@ BYTE* emitter::emitOutputLJ(insGroup* ig, BYTE* dst, instrDesc* i) if (INTERESTING_JUMP_NUM == 0) printf("[3] Jump %u:\n", id->idDebugOnlyInfo()->idNum); - printf("[3] Jump block is at %08X - %02X = %08X\n", blkOffs, emitOffsAdj, blkOffs - emitOffsAdj); + printf("[3] Jump block is at %08zX - %02X = %08zX\n", blkOffs, emitOffsAdj, blkOffs - emitOffsAdj); printf("[3] Jump is at %08X - %02X = %08X\n", srcOffs, emitOffsAdj, srcOffs - emitOffsAdj); printf("[3] Label block is at %08X - %02X = %08X\n", dstOffs, emitOffsAdj, dstOffs - emitOffsAdj); } @@ -10861,7 +10861,7 @@ BYTE* emitter::emitOutputLJ(insGroup* ig, BYTE* dst, instrDesc* i) if (INTERESTING_JUMP_NUM == 0) printf("[4] Jump %u:\n", id->idDebugOnlyInfo()->idNum); - printf("[4] Jump block is at %08X\n", blkOffs); + printf("[4] Jump block is at %08zX\n", blkOffs); printf("[4] Jump is at %08X\n", srcOffs); printf("[4] Label block is at %08X - %02X = %08X\n", dstOffs + emitOffsAdj, emitOffsAdj, dstOffs); } @@ -10873,8 +10873,9 @@ BYTE* emitter::emitOutputLJ(insGroup* ig, BYTE* dst, instrDesc* i) { size_t sz = 4; int distValSize = id->idjShort ? 4 : 8; - printf("; %s jump [%08X/%03u] from %0*X to %0*X: dist = 0x%08X\n", (dstOffs <= srcOffs) ? "Fwd" : "Bwd", - dspPtr(id), id->idDebugOnlyInfo()->idNum, distValSize, srcOffs + sz, distValSize, dstOffs, distVal); + printf("; %s jump [%p/%03u] from %0*zX to %0*X: dist = 0x%08zX\n", (dstOffs <= srcOffs) ? "Fwd" : "Bwd", + dspPtr(id), id->idDebugOnlyInfo()->idNum, distValSize, srcOffs + sz, distValSize, dstOffs, + (size_t)distVal); } #endif @@ -12969,11 +12970,11 @@ void emitter::emitDispImm(ssize_t imm, bool addComma, bool alwaysHex /* =false * { if (isAddrOffset) { - printf("0x%llX", imm); + printf("0x%zX", (size_t)imm); } else { - printf("0x%llx", imm); + printf("0x%zx", (size_t)imm); } } else @@ -12992,7 +12993,7 @@ void emitter::emitDispImm(ssize_t imm, bool addComma, bool alwaysHex /* =false * */ void emitter::emitDispElementIndex(const ssize_t imm, const bool addComma) { - printf("[%d]", imm); + printf("[%zd]", (ssize_t)imm); if (addComma) { @@ -13072,7 +13073,7 @@ void emitter::emitDispCond(insCond cond) "hi", "ls", "ge", "lt", "gt", "le", "AL", "NV"}; // The last two are invalid unsigned imm = (unsigned)cond; assert((0 <= imm) && (imm < ArrLen(armCond))); - printf(armCond[imm]); + printf("%s", armCond[imm]); } /***************************************************************************** @@ -13085,7 +13086,7 @@ void emitter::emitDispFlags(insCflags flags) "n", "nv", "nc", "ncv", "nz", "nzv", "nzc", "nzcv"}; unsigned imm = (unsigned)flags; assert((0 <= imm) && (imm < ArrLen(armFlags))); - printf(armFlags[imm]); + printf("%s", armFlags[imm]); } /***************************************************************************** @@ -13098,7 +13099,7 @@ void emitter::emitDispBarrier(insBarrier barrier) "#8", "ishld", "ishst", "ish", "#12", "ld", "st", "sy"}; unsigned imm = (unsigned)barrier; assert((0 <= imm) && (imm < ArrLen(armBarriers))); - printf(armBarriers[imm]); + printf("%s", armBarriers[imm]); } /***************************************************************************** @@ -13155,7 +13156,7 @@ void emitter::emitDispExtendOpts(insOpts opt) void emitter::emitDispReg(regNumber reg, emitAttr attr, bool addComma) { emitAttr size = EA_SIZE(attr); - printf(emitRegName(reg, size)); + printf("%s", emitRegName(reg, size)); if (addComma) emitDispComma(); @@ -13167,7 +13168,7 @@ void emitter::emitDispReg(regNumber reg, emitAttr attr, bool addComma) void emitter::emitDispVectorReg(regNumber reg, insOpts opt, bool addComma) { assert(isVectorRegister(reg)); - printf(emitVectorRegName(reg)); + printf("%s", emitVectorRegName(reg)); emitDispArrangement(opt); if (addComma) @@ -13180,7 +13181,7 @@ void emitter::emitDispVectorReg(regNumber reg, insOpts opt, bool addComma) void emitter::emitDispVectorRegIndex(regNumber reg, emitAttr elemsize, ssize_t index, bool addComma) { assert(isVectorRegister(reg)); - printf(emitVectorRegName(reg)); + printf("%s", emitVectorRegName(reg)); emitDispElemsize(elemsize); printf("[%d]", (int)index); @@ -13225,7 +13226,7 @@ void emitter::emitDispVectorElemList( printf("{"); for (unsigned i = 0; i < listSize; i++) { - printf(emitVectorRegName(currReg)); + printf("%s", emitVectorRegName(currReg)); emitDispElemsize(elemsize); const bool notLastRegister = (i != listSize - 1); if (notLastRegister) @@ -13300,7 +13301,7 @@ void emitter::emitDispArrangement(insOpts opt) assert(!"Invalid insOpt"); } printf("."); - printf(str); + printf("%s", str); } //------------------------------------------------------------------------ @@ -13330,7 +13331,7 @@ void emitter::emitDispElemsize(emitAttr elemsize) break; } - printf(str); + printf("%s", str); } //------------------------------------------------------------------------ @@ -13342,7 +13343,7 @@ void emitter::emitDispShiftedReg(regNumber reg, insOpts opt, ssize_t imm, emitAt assert((imm & 0x003F) == imm); assert(((imm & 0x0020) == 0) || (size == EA_8BYTE)); - printf(emitRegName(reg, size)); + printf("%s", emitRegName(reg, size)); if (imm > 0) { @@ -13458,14 +13459,14 @@ void emitter::emitDispAddrRI(regNumber reg, insOpts opt, ssize_t imm) if (insOptsPreIndex(opt)) { - printf(operStr); + printf("%s", operStr); } emitDispReg(reg, EA_8BYTE, false); if (insOptsPostIndex(opt)) { - printf(operStr); + printf("%s", operStr); } if (insOptsIndexed(opt)) @@ -13885,7 +13886,7 @@ void emitter::emitDispInsHelp( printf("@RWD%02u", doffs); if (imm != 0) - printf("%+Id", imm); + printf("%+zd", (ssize_t)imm); } else { @@ -17544,7 +17545,7 @@ bool emitter::IsRedundantLdStr( if ((prevReg1 == reg1) && (prevReg2 == reg2) && (imm == prevImm)) { - JITDUMP("\n -- suppressing 'ldr reg%u [reg%u, #%u]' as previous 'str reg%u [reg%u, #%u]' was from same " + JITDUMP("\n -- suppressing 'ldr reg%u [reg%u, #%zd]' as previous 'str reg%u [reg%u, #%zd]' was from same " "location.\n", reg1, reg2, imm, prevReg1, prevReg2, prevImm); return true; @@ -17561,7 +17562,7 @@ bool emitter::IsRedundantLdStr( // since load operation doesn't (and can't) change the value of its destination register. if ((reg1 != reg2) && (prevReg1 == reg1) && (prevReg2 == reg2) && (imm == prevImm) && (reg1 != REG_ZR)) { - JITDUMP("\n -- suppressing 'str reg%u [reg%u, #%u]' as previous 'ldr reg%u [reg%u, #%u]' was from same " + JITDUMP("\n -- suppressing 'str reg%u [reg%u, #%zd]' as previous 'ldr reg%u [reg%u, #%zd]' was from same " "location.\n", reg1, reg2, imm, prevReg1, prevReg2, prevImm); return true; diff --git a/src/runtime/src/coreclr/jit/emitarm64sve.cpp b/src/runtime/src/coreclr/jit/emitarm64sve.cpp index 960fb5a8c716..ab0b9e3e1f0e 100644 --- a/src/runtime/src/coreclr/jit/emitarm64sve.cpp +++ b/src/runtime/src/coreclr/jit/emitarm64sve.cpp @@ -12707,7 +12707,7 @@ void emitter::emitDispSveImmIndex(regNumber reg1, insOpts opt, ssize_t imm) void emitter::emitDispSveReg(regNumber reg, bool addComma) { assert(isVectorRegister(reg)); - printf(emitSveRegName(reg)); + printf("%s", emitSveRegName(reg)); if (addComma) emitDispComma(); @@ -12719,7 +12719,7 @@ void emitter::emitDispSveReg(regNumber reg, bool addComma) void emitter::emitDispSveReg(regNumber reg, insOpts opt, bool addComma) { assert(isVectorRegister(reg)); - printf(emitSveRegName(reg)); + printf("%s", emitSveRegName(reg)); if (opt != INS_OPTS_NONE) { @@ -12737,7 +12737,7 @@ void emitter::emitDispSveReg(regNumber reg, insOpts opt, bool addComma) void emitter::emitDispSveRegIndex(regNumber reg, ssize_t index, bool addComma) { assert(isVectorRegister(reg)); - printf(emitSveRegName(reg)); + printf("%s", emitSveRegName(reg)); emitDispElementIndex(index, addComma); } @@ -12821,7 +12821,7 @@ const char* emitter::emitPredicateRegName(regNumber reg, PredicateType ptype) void emitter::emitDispPredicateReg(regNumber reg, PredicateType ptype, insOpts opt, bool addComma) { assert(isPredicateRegister(reg)); - printf(emitPredicateRegName(reg, ptype)); + printf("%s", emitPredicateRegName(reg, ptype)); if (ptype == PREDICATE_MERGE) { diff --git a/src/runtime/src/coreclr/jit/emitloongarch64.cpp b/src/runtime/src/coreclr/jit/emitloongarch64.cpp index 916fca37914e..63b0b0fe1b5a 100644 --- a/src/runtime/src/coreclr/jit/emitloongarch64.cpp +++ b/src/runtime/src/coreclr/jit/emitloongarch64.cpp @@ -15,6 +15,8 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #pragma hdrstop #endif +#include + #if defined(TARGET_LOONGARCH64) /*****************************************************************************/ @@ -3031,7 +3033,7 @@ void emitter::emitJumpDistBind() } if (EMITVERBOSE) { - printf("Estimate of fwd jump [%08X/%03u]: %04X -> %04X = %04X\n", dspPtr(jmp), + printf("Estimate of fwd jump [%p/%03u]: %04X -> %04X = %04X\n", (void*)dspPtr(jmp), jmp->idDebugOnlyInfo()->idNum, srcInstrOffs, dstOffs, jmpDist); } #endif // DEBUG_EMIT @@ -3119,7 +3121,7 @@ void emitter::emitJumpDistBind() } if (EMITVERBOSE) { - printf("Estimate of bwd jump [%08X/%03u]: %04X -> %04X = %04X\n", dspPtr(jmp), + printf("Estimate of bwd jump [%p/%03u]: %04X -> %04X = %04X\n", (void*)dspPtr(jmp), jmp->idDebugOnlyInfo()->idNum, srcInstrOffs, dstOffs, jmpDist); } #endif // DEBUG_EMIT @@ -4044,7 +4046,7 @@ void emitter::emitDisInsName(code_t code, const BYTE* addr, instrDesc* id) #ifdef DEBUG if (m_compiler->opts.disAddr) { - printf(" 0x%llx", insAdr); + printf(" %p", (void*)insAdr); } printf(" "); @@ -4118,7 +4120,7 @@ void emitter::emitDisInsName(code_t code, const BYTE* addr, instrDesc* id) } else if (ins == INS_jirl) { - printf("%s, %s, 0x%lx\n", RegNames[regd], RegNames[regj], offs16); + printf("%s, %s, 0x%x\n", RegNames[regd], RegNames[regj], offs16); } // only for prolog else if (emitPrologEndPos.Valid() && ((unsigned)(addr - emitCodeBlock) < emitPrologEndPos.CodeOffset(this))) @@ -4134,7 +4136,7 @@ void emitter::emitDisInsName(code_t code, const BYTE* addr, instrDesc* id) } else { - printf("%s, %s, 0x%llx\n", RegNames[regj], RegNames[regd], (int64_t)insAdr + offs16); + printf("%s, %s, 0x%" PRIx64 "\n", RegNames[regj], RegNames[regd], (int64_t)insAdr + offs16); } return; } @@ -4157,7 +4159,7 @@ void emitter::emitDisInsName(code_t code, const BYTE* addr, instrDesc* id) } else { - printf("%s, 0x%llx\n", RegNames[regj], (int64_t)insAdr + tmp); + printf("%s, 0x%" PRIx64 "\n", RegNames[regj], (int64_t)insAdr + tmp); } return; } @@ -4187,7 +4189,7 @@ void emitter::emitDisInsName(code_t code, const BYTE* addr, instrDesc* id) } else { - printf("0x%llx\n", (int64_t)insAdr + tmp); + printf("0x%" PRIx64 "\n", (int64_t)insAdr + tmp); } return; } @@ -4265,7 +4267,7 @@ void emitter::emitDisInsName(code_t code, const BYTE* addr, instrDesc* id) { int offs21 = (((code >> 10) & 0xffff) | ((code & 0x1f) << 16)) << 11; offs21 >>= 9; - printf("fcc%d, 0x%llx\n", (code >> 5) & 0x7, (int64_t)insAdr + offs21); + printf("fcc%d, 0x%" PRIx64 "\n", (code >> 5) & 0x7, (int64_t)insAdr + offs21); return; } case DF_F_GR: diff --git a/src/runtime/src/coreclr/jit/emitriscv64.cpp b/src/runtime/src/coreclr/jit/emitriscv64.cpp index cc157b10facb..bcbabd835c90 100644 --- a/src/runtime/src/coreclr/jit/emitriscv64.cpp +++ b/src/runtime/src/coreclr/jit/emitriscv64.cpp @@ -3528,7 +3528,7 @@ void emitter::emitDispBranchLabel(const instrDesc* id) const { return emitPrintLabel(id->idAddr()->iiaIGlabel); } - printf("L_M%03u_", FMT_BB, m_compiler->compMethodID, id->idAddr()->iiaBBlabel->bbNum); + printf("L_M%03u_" FMT_BB, m_compiler->compMethodID, id->idAddr()->iiaBBlabel->bbNum); } bool emitter::emitDispBranch(unsigned opcode2, diff --git a/src/runtime/src/coreclr/jit/emitwasm.cpp b/src/runtime/src/coreclr/jit/emitwasm.cpp index 86fb74235c5c..3b6c8244023a 100644 --- a/src/runtime/src/coreclr/jit/emitwasm.cpp +++ b/src/runtime/src/coreclr/jit/emitwasm.cpp @@ -6,6 +6,7 @@ #pragma hdrstop #endif +#include #include "codegen.h" // clang-format off @@ -1332,7 +1333,7 @@ void emitter::emitDispIns( case IF_GLOBALIDX: { cnsval_ssize_t imm = emitGetInsSC(id); - printf(" %llu", (uint64_t)imm); + printf(" %" PRIu64, (uint64_t)imm); dispJumpTargetIfAny(); dispHandleIfAny(); dispLclVarInfoIfAny(); @@ -1342,14 +1343,14 @@ void emitter::emitDispIns( case IF_CALL_INDIRECT: { cnsval_ssize_t imm = emitGetInsSC(id); - printf(" %llu 0", (uint64_t)imm); + printf(" %" PRIu64 " 0", (uint64_t)imm); dispHandleIfAny(); } break; case IF_MEMIDX_MEMIDX: { cnsval_ssize_t imm = emitGetInsSC(id); - printf(" %llu %llu", (uint64_t)imm, (uint64_t)imm); + printf(" %" PRIu64 " %" PRIu64, (uint64_t)imm, (uint64_t)imm); } break; case IF_LOCAL_DECL: @@ -1384,7 +1385,7 @@ void emitter::emitDispIns( case IF_SLEB128: { cnsval_ssize_t imm = emitGetInsSC(id); - printf(" %lli", (int64_t)imm); + printf(" %" PRId64, (int64_t)imm); dispLclVarInfoIfAny(); } break; @@ -1393,7 +1394,7 @@ void emitter::emitDispIns( case IF_FUNCLETIDX: { cnsval_ssize_t imm = emitGetInsSC(id); - printf("funclet %lli", (int64_t)imm); + printf("funclet %lli", static_cast(imm)); dispLclVarInfoIfAny(); } break; @@ -1401,7 +1402,7 @@ void emitter::emitDispIns( case IF_DATAOFFS: { cnsval_ssize_t imm = emitGetInsSC(id); - printf("data 0x%llx", (uint64_t)imm); + printf("data 0x%llx", static_cast(imm)); dispLclVarInfoIfAny(); } break; @@ -1422,11 +1423,11 @@ void emitter::emitDispIns( cnsval_ssize_t offset = emitGetInsSC(id); if (id->idIsCnsReloc()) { - printf(" %u reloc 0x%llx", log2align, (uint64_t)offset); + printf(" %u reloc 0x%" PRIx64, log2align, (uint64_t)offset); } else { - printf(" %u %llu", log2align, (uint64_t)offset); + printf(" %u %" PRIu64, log2align, (uint64_t)offset); } dispLclVarInfoIfAny(); } @@ -1501,7 +1502,7 @@ void emitter::emitDispIns( { unsigned log2align = emitGetAlignHintLog2(id); cnsval_ssize_t offset = emitGetInsSC(id); - printf(" %u %llu", log2align, (uint64_t)offset); + printf(" %u %llu", log2align, static_cast(offset)); dispLclVarInfoIfAny(); uint8_t lane = emitGetLaneImmValue(id); diff --git a/src/runtime/src/coreclr/jit/emitxarch.cpp b/src/runtime/src/coreclr/jit/emitxarch.cpp index 6b6d9e4f158c..e6f46e8b7f70 100644 --- a/src/runtime/src/coreclr/jit/emitxarch.cpp +++ b/src/runtime/src/coreclr/jit/emitxarch.cpp @@ -17,6 +17,8 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #if defined(TARGET_XARCH) +#include + /*****************************************************************************/ /*****************************************************************************/ @@ -11806,16 +11808,16 @@ void emitter::emitDispClsVar(CORINFO_FIELD_HANDLE fldHnd, ssize_t offs, bool rel if (offs) { - printf("%+Id", offs); + printf("%+zd", (ssize_t)offs); } } else { - printf("classVar[%#p]", (void*)m_compiler->dspPtr(fldHnd)); + printf("classVar[%p]", (void*)m_compiler->dspPtr(fldHnd)); if (offs) { - printf("%+Id", offs); + printf("%+zd", (ssize_t)offs); } } @@ -11828,7 +11830,7 @@ void emitter::emitDispClsVar(CORINFO_FIELD_HANDLE fldHnd, ssize_t offs, bool rel printf("'%s", m_compiler->eeGetFieldName(fldHnd, true, buffer, sizeof(buffer))); if (offs) { - printf("%+Id", offs); + printf("%+zd", offs); } printf("'"); } @@ -12198,7 +12200,7 @@ void emitter::emitDispEmbBroadcastCount(instrDesc* id) const ssize_t baseSize = GetInputSizeInBytes(id); ssize_t vectorSize = (ssize_t)emitGetMemOpSize(id, /* ignoreEmbeddedBroadcast */ true); - printf(" {1to%d}", vectorSize / baseSize); + printf(" {1to%zu}", (size_t)(vectorSize / baseSize)); } // emitDispEmbRounding: Display the tag where embedded rounding is activated @@ -12656,7 +12658,7 @@ void emitter::emitDispIns( } } - printf(sstr); + printf("%s", sstr); emitDispAddrMode(id); emitDispEmbMasking(id); printf(", %s", emitRegName(id->idReg1(), attr)); @@ -13496,7 +13498,7 @@ void emitter::emitDispIns( } } - printf(sstr); + printf("%s", sstr); offs = emitGetInsDsp(id); emitDispClsVar(id->idAddr()->iiaFieldHnd, offs, ID_INFO_DSP_RELOC); emitDispEmbMasking(id); @@ -13737,7 +13739,7 @@ void emitter::emitDispIns( if (sz != 0 && sz != id->idCodeSize() && (!asmfm || m_compiler->verbose)) { // Code size in the instrDesc is different from the actual code size we've been given! - printf(" (ECS:%d, ACS:%d)", id->idCodeSize(), sz); + printf(" (ECS:%d, ACS:%zu)", id->idCodeSize(), sz); } #endif @@ -17452,9 +17454,11 @@ BYTE* emitter::emitOutputLJ(insGroup* ig, BYTE* dst, instrDesc* i) { printf("[3] Jump %u:\n", id->idDebugOnlyInfo()->idNum); } - printf("[3] Jump block is at %08X - %02X = %08X\n", blkOffs, emitOffsAdj, blkOffs - emitOffsAdj); - printf("[3] Jump is at %08X - %02X = %08X\n", srcOffs, emitOffsAdj, srcOffs - emitOffsAdj); - printf("[3] Label block is at %08X - %02X = %08X\n", dstOffs, emitOffsAdj, dstOffs - emitOffsAdj); + printf("[3] Jump block is at %08zX - %02X = %08zX\n", blkOffs, emitOffsAdj, blkOffs - emitOffsAdj); + printf("[3] Jump is at %08zX - %02X = %08zX\n", (size_t)srcOffs, emitOffsAdj, + (size_t)(srcOffs - emitOffsAdj)); + printf("[3] Label block is at %08zX - %02X = %08zX\n", (size_t)dstOffs, emitOffsAdj, + (size_t)(dstOffs - emitOffsAdj)); } #endif @@ -17495,9 +17499,10 @@ BYTE* emitter::emitOutputLJ(insGroup* ig, BYTE* dst, instrDesc* i) { printf("[4] Jump %u:\n", id->idDebugOnlyInfo()->idNum); } - printf("[4] Jump block is at %08X\n", blkOffs); - printf("[4] Jump is at %08X\n", srcOffs); - printf("[4] Label block is at %08X - %02X = %08X\n", dstOffs + emitOffsAdj, emitOffsAdj, dstOffs); + printf("[4] Jump block is at %08zX\n", blkOffs); + printf("[4] Jump is at %08zX\n", (size_t)srcOffs); + printf("[4] Label block is at %08zX - %02X = %08zX\n", (size_t)(dstOffs + emitOffsAdj), emitOffsAdj, + (size_t)dstOffs); } #endif @@ -17519,9 +17524,9 @@ BYTE* emitter::emitOutputLJ(insGroup* ig, BYTE* dst, instrDesc* i) { size_t sz = id->idjShort ? ssz : lsz; int distValSize = id->idjShort ? 4 : 8; - printf("; %s jump [%08X/%03u] from %0*X to %0*X: dist = 0x%08X\n", (dstOffs <= srcOffs) ? "Fwd" : "Bwd", - m_compiler->dspPtr(id), id->idDebugOnlyInfo()->idNum, distValSize, srcOffs + sz, distValSize, dstOffs, - distVal); + printf("; %s jump [%p/%03u] from %0*zX to %0*zX: dist = 0x%08zX\n", (dstOffs <= srcOffs) ? "Fwd" : "Bwd", + m_compiler->dspPtr(id), id->idDebugOnlyInfo()->idNum, distValSize, srcOffs + sz, distValSize, + (size_t)dstOffs, (size_t)distVal); } #endif @@ -17544,7 +17549,7 @@ BYTE* emitter::emitOutputLJ(insGroup* ig, BYTE* dst, instrDesc* i) if (INDEBUG(m_compiler->verbose ||)(id->idDebugOnlyInfo()->idNum == (unsigned)INTERESTING_JUMP_NUM || INTERESTING_JUMP_NUM == 0)) { - printf("; NOTE: size of jump [%08p] mis-predicted by %d bytes\n", dspPtr(id), offsShrinkage); + printf("; NOTE: size of jump [%p] mis-predicted by %d bytes\n", dspPtr(id), offsShrinkage); } #endif } diff --git a/src/runtime/src/coreclr/jit/error.cpp b/src/runtime/src/coreclr/jit/error.cpp index cb7d1c88481d..8f6d921dc1bb 100644 --- a/src/runtime/src/coreclr/jit/error.cpp +++ b/src/runtime/src/coreclr/jit/error.cpp @@ -280,7 +280,7 @@ extern "C" void assertAbort(const char* why, const char* file, unsigned line) env->compiler->info.compMethodHash(), env->compiler->compGetTieringName(/* short name */ true)); msg = buff; } - printf(""); // null string means flush + fflush(jitstdout()); #if FUNC_INFO_LOGGING if (Compiler::compJitFuncInfoFile != nullptr) diff --git a/src/runtime/src/coreclr/jit/fgdiagnostic.cpp b/src/runtime/src/coreclr/jit/fgdiagnostic.cpp index 3f8cb92a7dc1..5140442a3206 100644 --- a/src/runtime/src/coreclr/jit/fgdiagnostic.cpp +++ b/src/runtime/src/coreclr/jit/fgdiagnostic.cpp @@ -341,7 +341,7 @@ void Compiler::fgDumpTree(FILE* fgxFile, GenTree* const tree) } else if (tree->IsCnsIntOrI()) { - fprintf(fgxFile, "%d", tree->AsIntCon()->IconValue()); + fprintf(fgxFile, "%zd", tree->AsIntCon()->IconValue()); } else if (tree->IsCnsFltOrDbl()) { diff --git a/src/runtime/src/coreclr/jit/fginline.cpp b/src/runtime/src/coreclr/jit/fginline.cpp index 44a03da1706a..ace0e2ccda99 100644 --- a/src/runtime/src/coreclr/jit/fginline.cpp +++ b/src/runtime/src/coreclr/jit/fginline.cpp @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. #include "jitpch.h" +#include "async.h" #ifdef _MSC_VER #pragma hdrstop @@ -28,8 +29,9 @@ // Shuffling is what makes the choice vary between seeds. Without it the // decay would always favor the first call site in a body. // -// Candidates created after this runs, such as ones from late devirtualization, -// keep the default index and are left to the normal policy. +// Candidates created after this runs, such as the frame transition call or ones +// from late devirtualization, keep the default index and are left to the normal +// policy. // void Compiler::fgAsyncStressPrepare(unsigned depth) { @@ -1731,6 +1733,10 @@ void Compiler::fgInsertInlineeBlocks(InlineInfo* pInlineInfo) // Append statements to null out gc ref locals, if necessary. fgInlineAppendStatements(pInlineInfo, iciBlock, stmtAfter); + + // An inlinee that does async context handling always has multiple blocks: its + // SaveAsyncContexts creates a try/fault region and a merged return block. + assert(InlineeCompiler->lvaResumedIndicator == BAD_VAR_NUM); insertInlineeBlocks = false; } else @@ -1977,6 +1983,9 @@ void Compiler::fgInsertInlineeBlocks(InlineInfo* pInlineInfo) // Append statements to null out gc ref locals, if necessary. fgInlineAppendStatements(pInlineInfo, bottomBlock, nullptr); JITDUMPEXEC(fgDispBasicBlocks(InlineeCompiler->fgFirstBB, InlineeCompiler->fgLastBB, true)); + + // Handle the inlined async frame logically returning to its caller. + fgInlineAppendAsyncFrameStatements(pInlineInfo, bottomBlock); } // @@ -2509,6 +2518,248 @@ Statement* Compiler::fgInlinePrependStatements(InlineInfo* inlineInfo) return afterStmt; } +//------------------------------------------------------------------------ +// fgSetupAsyncFrameTransitionCall: Turn a call to AsyncHelpers.RestoreInlinedFrameContexts +// into a proper async call. +// +// Arguments: +// call - the call, with its user arguments already added +// di - debug info to use +// +// Notes: +// The call is an await: it suspends when it has to switch continuation context. +// +// Unlike normal awaits it gets no context pseudo-args. Those model what a frame +// captures and restores when a suspension unwinds through it, and none of that applies +// here: we only run at all because the frame we are returning out of was resumed, so +// every frame in the chain already has a continuation holding the values it captured +// when it first suspended, and a suspension here returns straight back to the +// dispatcher, which restores the thread's contexts itself. +// +void Compiler::fgSetupAsyncFrameTransitionCall(GenTreeCall* call, const DebugInfo& di) +{ + AsyncCallInfo asyncInfo; + // The helper resumes on the requested context, so no further handling is attached to + // this await. + asyncInfo.ContinuationContextHandling = ContinuationContextHandling::None; + asyncInfo.CallAsyncDebugInfo = di; + call->SetIsAsync(new (this, CMK_Async) AsyncCallInfo(asyncInfo)); + + NewCallArg continuationArg = NewCallArg::Primitive(gtNewNull(), TYP_REF).WellKnown(WellKnownArg::AsyncContinuation); + + if (Target::g_tgtArgOrder == Target::ARG_ORDER_R2L) + { + call->gtArgs.PushFront(this, continuationArg); + } + else + { + call->gtArgs.PushBack(this, continuationArg); + } +} + +//------------------------------------------------------------------------ +// gtNewContinuationMemberIndir: Create a load of a continuation member from the +// continuation this method was resumed with. +// +// Arguments: +// member - the continuation member to load +// type - type of the member +// +// Returns: +// A load of the member. +// +// Notes: +// The member offset is not known until the async transformation has laid out the +// continuation, so it is represented symbolically until then. The offset is relative +// to the instance data, hence the additional object header adjustment. +// +GenTree* Compiler::gtNewContinuationMemberIndir(const ContinuationMember& member, var_types type) +{ + size_t const memberIndex = GetContinuationMemberIndex(member); + + GenTree* const memberOffset = + new (this, GT_CONTINUATION_MEMBER_OFFSET) GenTreeVal(GT_CONTINUATION_MEMBER_OFFSET, TYP_I_IMPL, memberIndex); + GenTree* const headerSize = gtNewIconNode(SIZEOF__CORINFO_Object, TYP_I_IMPL); + GenTree* const offset = gtNewOperNode(GT_ADD, TYP_I_IMPL, memberOffset, headerSize); + + GenTree* const continuation = gtNewLclvNode(lvaAsyncContinuationArg, TYP_REF); + GenTree* const addr = gtNewOperNode(GT_ADD, TYP_BYREF, continuation, offset); + + GenTree* const indir = gtNewIndir(type, addr, GTF_IND_NONFAULTING); + return indir; +} + +//------------------------------------------------------------------------ +// fgInlineAppendAsyncFrameStatements: Emit the IR that handles an inlined async +// frame logically returning to its caller. +// +// Arguments: +// inlineInfo - information about the inline +// joinBlock - the block all of the inlinee's returns converge on +// +// Notes: +// When an inlined async callee is resumed inside its own body, the async +// infrastructure only restored the context of the suspension point itself. The work +// it would otherwise have done when the callee's frame returned to its caller has to +// be performed here instead: +// +// if (resumed_callee) +// { +// await AsyncHelpers.RestoreInlinedFrameContexts(continuation.ExecutionContextFor, +// continuation.ContinuationContextFor, +// continuation.FlagsFor); +// resumed_caller = true; +// } +// +// Only the check is expanded as IR; the restore itself is left as a single call. The +// synchronous case is the one worth optimizing, and by the time we get past the check +// we have already suspended and resumed at least once, so one more call is cheap. In +// particular the "are we already on the right context?" test, which is what actually +// decides whether we suspend, stays inside the helper. +// +void Compiler::fgInlineAppendAsyncFrameStatements(InlineInfo* inlineInfo, BasicBlock* joinBlock) +{ + if (!generalAsyncInliningEnabled()) + { + return; + } + + if (InlineeCompiler->lvaResumedIndicator == BAD_VAR_NUM) + { + // Inlinee does not do context handling, so it inherited everything from this + // call and there is no logical frame transition to handle. + return; + } + + if (!InlineeCompiler->compAsyncBodyMaySuspend) + { + // The inlinee has no suspension point, so its resumed indicator is provably + // always false and all of the below would be dead code. + JITDUMP("Inlinee cannot suspend; no async frame transition IR needed\n"); + return; + } + + // The resumed indicator of the frame we are logically returning into. The inlining + // call carries the address of it as the definition of its own frame's indicator, so + // it is something we can store through. + CallArg* const resumedDefArg = inlineInfo->iciCall->gtArgs.FindWellKnownArg(WellKnownArg::AsyncResumedDef); + if (resumedDefArg == nullptr) + { + // The inlining call does no context handling, so there is no enclosing logical + // async frame to hand anything back to. + JITDUMP("Inlining call does no context handling; no async frame transition IR needed\n"); + return; + } + + GenTree* const resumedCallerAddr = resumedDefArg->GetNode(); + + // The depth of the frame being inlined. The inlining call describes the chain of + // frames it sits in, from the frame the call is in out to the root, so the inlinee is + // one frame deeper than the chain is long. + unsigned numCallerSets = 0; + for (CallArg& arg : inlineInfo->iciCall->gtArgs.Args()) + { + if (arg.GetWellKnownArg() == WellKnownArg::AsyncResumedUse) + { + numCallerSets++; + } + } + + assert(numCallerSets >= 1); + unsigned const inlineDepth = numCallerSets; + + unsigned const resumedInlinee = InlineeCompiler->lvaResumedIndicator; + + JITDUMP("Adding async frame transition IR for async frame depth %u: resumed V%02u -> [%06u]\n", inlineDepth, + resumedInlinee, dspTreeID(resumedCallerAddr)); + + const DebugInfo& di = inlineInfo->iciStmt->GetDebugInfo(); + + // An exception unwinding out of the inlinee never reaches the logical return below, + // so mark the caller as resumed from the inlinee's context restore handler instead. + // That handler is the fault half of the try-finally SaveAsyncContexts wrapped the + // inlinee's body in, and it survives inlining as its own clause in this method. + // + // We only need to propagate the indicator here since that's the only state parent + // fault handlers can depend on. + if (InlineeCompiler->asyncContextRestoreEHID != USHRT_MAX) + { + EHblkDsc* const inlineeContextRestore = ehFindEHblkDscById(InlineeCompiler->asyncContextRestoreEHID); + assert((inlineeContextRestore != nullptr) && inlineeContextRestore->HasFaultHandler()); + + // The resumed indicators are always TYP_I_IMPL, and the definition the inlining + // call carries is the address of one. + GenTree* const callerResumed = gtNewLoadValueNode(TYP_I_IMPL, gtCloneExpr(resumedCallerAddr)); + GenTree* const inlineeDidResume = gtNewLclvNode(resumedInlinee, TYP_I_IMPL); + GenTree* const merged = gtNewOperNode(GT_OR, TYP_I_IMPL, callerResumed, inlineeDidResume); + GenTree* const store = gtNewStoreValueNode(TYP_I_IMPL, gtCloneExpr(resumedCallerAddr), merged); + + fgInsertStmtAtBeg(inlineeContextRestore->ebdHndBeg, gtNewStmt(store)); + + JITDUMP("Marking [%06u] as resumed from the inlinee's context restore handler " FMT_BB "\n", + dspTreeID(resumedCallerAddr), inlineeContextRestore->ebdHndBeg->bbNum); + } + + // Split so that the transition IR precedes the remainder of the caller's code. + BasicBlock* const restBlock = fgSplitBlockAtBeginning(joinBlock); + + // joinBlock is now empty and jumps to restBlock. Turn it into the "did we resume + // inside the inlinee?" test. + BasicBlock* const restoreBlock = fgNewBBafter(BBJ_ALWAYS, joinBlock, /* extendRegion */ true); + restoreBlock->inheritWeightPercentage(joinBlock, 0); + + // joinBlock: if (resumed_callee == 0) goto restBlock; else goto restoreBlock + { + GenTree* const resumed = gtNewLclvNode(resumedInlinee, TYP_INT); + GenTree* const isZero = gtNewOperNode(GT_EQ, TYP_INT, resumed, gtNewIconNode(0)); + GenTree* const jtrue = gtNewOperNode(GT_JTRUE, TYP_VOID, isZero); + fgInsertStmtAtEnd(joinBlock, gtNewStmt(jtrue)); + + fgRemoveRefPred(joinBlock->GetTargetEdge()); + FlowEdge* const toRest = fgAddRefPred(restBlock, joinBlock); + FlowEdge* const toRestore = fgAddRefPred(restoreBlock, joinBlock); + joinBlock->SetCond(toRest, toRestore); + // Resuming inside the inlinee is the cold path. + toRest->setLikelihood(1.0); + toRestore->setLikelihood(0.0); + } + + // restoreBlock: restore the contexts the caller's continuation captured, then record + // that the caller's frame has observed a resumption too. + { + CORINFO_ASYNC_INFO* const asyncInfo = eeGetAsyncInfo(); + + GenTree* const execCtx = + gtNewContinuationMemberIndir(ContinuationMember::InlineFrameExecutionContext(inlineDepth), TYP_REF); + GenTree* const contContext = + gtNewContinuationMemberIndir(ContinuationMember::InlineFrameContinuationContext(inlineDepth), TYP_REF); + GenTree* const flags = gtNewContinuationMemberIndir(ContinuationMember::InlineFrameFlags(inlineDepth), TYP_INT); + + GenTreeCall* const restoreCall = gtNewUserCallNode(asyncInfo->restoreInlinedFrameContextsMethHnd, TYP_VOID); + restoreCall->gtArgs.PushFront(this, NewCallArg::Primitive(flags)); + restoreCall->gtArgs.PushFront(this, NewCallArg::Primitive(contContext)); + restoreCall->gtArgs.PushFront(this, NewCallArg::Primitive(execCtx)); + fgSetupAsyncFrameTransitionCall(restoreCall, di); + + // The helper is small on the path that does not suspend, which is the one we care + // about, so let the inliner have a look at it. + CORINFO_CALL_INFO callInfo = {}; + callInfo.hMethod = restoreCall->gtCallMethHnd; + callInfo.methodFlags = info.compCompHnd->getMethodAttribs(callInfo.hMethod); + impMarkInlineCandidate(restoreCall, MAKE_METHODCONTEXT(callInfo.hMethod), &callInfo, compInlineContext); + + fgInsertStmtAtEnd(restoreBlock, gtNewStmt(restoreCall)); + + GenTree* const store = + gtNewStoreValueNode(TYP_I_IMPL, gtCloneExpr(resumedCallerAddr), gtNewIconNode(1, TYP_I_IMPL)); + fgInsertStmtAtEnd(restoreBlock, gtNewStmt(store)); + + restoreBlock->SetKindAndTargetEdge(BBJ_ALWAYS, fgAddRefPred(restBlock, restoreBlock)); + } + + JITDUMPEXEC(fgDispBasicBlocks(joinBlock, restBlock, true)); +} + //------------------------------------------------------------------------ // fgInlineAppendStatements: Append statements that are needed // after the inlined call. diff --git a/src/runtime/src/coreclr/jit/fgprofile.cpp b/src/runtime/src/coreclr/jit/fgprofile.cpp index eed8abc111b6..46c3077ec6b6 100644 --- a/src/runtime/src/coreclr/jit/fgprofile.cpp +++ b/src/runtime/src/coreclr/jit/fgprofile.cpp @@ -2979,8 +2979,8 @@ PhaseStatus Compiler::fgIncorporateProfileData() default: JITDUMP("Unknown PGO record type 0x%x in schema entry %u (offset 0x%x count 0x%x other 0x%x)\n", - fgPgoSchema[iSchema].InstrumentationKind, iSchema, fgPgoSchema[iSchema].ILOffset, - fgPgoSchema[iSchema].Count, fgPgoSchema[iSchema].Other); + static_cast(fgPgoSchema[iSchema].InstrumentationKind), iSchema, + fgPgoSchema[iSchema].ILOffset, fgPgoSchema[iSchema].Count, fgPgoSchema[iSchema].Other); otherRecords++; break; } @@ -4640,7 +4640,7 @@ bool Compiler::fgDebugCheckProfileWeights(ProfileChecks checks, bool dump) return false; } - JITDUMP("Checking Profile Weights (flags:0x%x)\n", checks); + JITDUMP("Checking Profile Weights (flags:0x%x)\n", static_cast(checks)); unsigned problemBlocks = 0; unsigned unprofiledBlocks = 0; unsigned profiledBlocks = 0; @@ -4808,7 +4808,7 @@ bool Compiler::fgDebugCheckProfileWeights(ProfileChecks checks, bool dump) // if (fgFirstBB->bbRefs > 1) { - JITDUMP(" Method entry " FMT_BB " is loop head, can't check entry/exit balance\n"); + JITDUMP(" Method entry " FMT_BB " is loop head, can't check entry/exit balance\n", fgFirstBB->bbNum); } else if (!fgProfileWeightsConsistent(entryWeight, exitWeight)) { diff --git a/src/runtime/src/coreclr/jit/gcencode.cpp b/src/runtime/src/coreclr/jit/gcencode.cpp index e447629de4f1..4630cd276227 100644 --- a/src/runtime/src/coreclr/jit/gcencode.cpp +++ b/src/runtime/src/coreclr/jit/gcencode.cpp @@ -330,7 +330,7 @@ void GCInfo::gcDumpVarPtrDsc(varPtrDsc* desc) const GCtype gcType = (desc->vpdVarNum & byref_OFFSET_FLAG) ? GCT_BYREF : GCT_GCREF; const bool isPin = (desc->vpdVarNum & pinned_OFFSET_FLAG) != 0; - printf("[%08X] %s%s var at [%s", dspPtr(desc), GCtypeStr(gcType), isPin ? "pinned-ptr" : "", + printf("[%p] %s%s var at [%s", dspPtr(desc), GCtypeStr(gcType), isPin ? "pinned-ptr" : "", m_compiler->isFramePointerUsed() ? STR_FPBASE : STR_SPBASE); if (offs < 0) diff --git a/src/runtime/src/coreclr/jit/gentree.cpp b/src/runtime/src/coreclr/jit/gentree.cpp index 17af5fad8b96..f09808f88d6f 100644 --- a/src/runtime/src/coreclr/jit/gentree.cpp +++ b/src/runtime/src/coreclr/jit/gentree.cpp @@ -13278,7 +13278,7 @@ void Compiler::gtDispNode(GenTree* tree, IndentStack* indentStack, _In_ _In_opt_ msgLength = 0; } - printf(isLIR ? " %+*s" : " %-*s", msgLength, msg); + printf(isLIR ? " %*s" : " %-*s", static_cast(msgLength), msg); /* Indent the node accordingly */ if (!isLIR || hasOperands) @@ -13376,11 +13376,7 @@ void Compiler::gtDispNode(GenTree* tree, IndentStack* indentStack, _In_ _In_opt_ if (tree->OperIs(GT_RUNTIMELOOKUP)) { -#ifdef TARGET_64BIT - printf(" 0x%llx", dspPtr(tree->AsRuntimeLookup()->gtHnd)); -#else - printf(" 0x%x", dspPtr(tree->AsRuntimeLookup()->gtHnd)); -#endif + printf(" %p", dspPtr(tree->AsRuntimeLookup()->gtHnd)); switch (tree->AsRuntimeLookup()->gtHndType) { @@ -13748,7 +13744,7 @@ void Compiler::gtDispLclVar(unsigned lclNum, bool padForBiggestDisp) if (padForBiggestDisp && (charsPrinted < (int)LONGEST_COMMON_LCL_VAR_DISPLAY_LENGTH)) { - printf("%*c", LONGEST_COMMON_LCL_VAR_DISPLAY_LENGTH - charsPrinted, ' '); + printf("%*c", static_cast(LONGEST_COMMON_LCL_VAR_DISPLAY_LENGTH) - charsPrinted, ' '); } } @@ -13852,7 +13848,7 @@ void Compiler::gtDispConst(GenTree* tree) case GT_CNS_INT: if (tree->IsIconHandle(GTF_ICON_STR_HDL)) { - printf(" 0x%X [ICON_STR_HDL]", dspPtr(tree->AsIntCon()->IconValue())); + printf(" 0x%zX [ICON_STR_HDL]", static_cast(dspPtr(tree->AsIntCon()->IconValue()))); } else if (tree->IsIconHandle(GTF_ICON_OBJ_HDL)) { @@ -13871,23 +13867,23 @@ void Compiler::gtDispConst(GenTree* tree) } else { - printf(" 0x%llx", dspIconVal); + printf(" 0x%zx", static_cast(dspIconVal)); } } else if ((iconVal > -1000) && (iconVal < 1000)) { - printf(" %ld", dspIconVal); + printf(" %zd", dspIconVal); } #ifdef TARGET_64BIT else if ((iconVal & 0xFFFFFFFF00000000LL) != 0) { if (dspIconVal >= 0) { - printf(" 0x%llx", dspIconVal); + printf(" 0x%zx", static_cast(dspIconVal)); } else { - printf(" -0x%llx", -dspIconVal); + printf(" -0x%zx", static_cast(-dspIconVal)); } } #endif @@ -13895,11 +13891,11 @@ void Compiler::gtDispConst(GenTree* tree) { if (dspIconVal >= 0) { - printf(" 0x%X", dspIconVal); + printf(" 0x%zX", static_cast(dspIconVal)); } else { - printf(" -0x%X", -dspIconVal); + printf(" -0x%zX", static_cast(-dspIconVal)); } } @@ -13963,7 +13959,7 @@ void Compiler::gtDispConst(GenTree* tree) break; case GT_CNS_LNG: - printf(" 0x%016I64x", tree->AsLngCon()->gtLconVal); + printf(" 0x%016llx", static_cast(tree->AsLngCon()->gtLconVal)); break; case GT_CNS_DBL: @@ -13978,7 +13974,7 @@ void Compiler::gtDispConst(GenTree* tree) uint64_t bits; static_assert(sizeof(bits) == sizeof(dcon)); memcpy(&bits, &dcon, sizeof(dcon)); - printf(" %#.17g(0x%llx)\n", dcon, bits); + printf(" %#.17g(0x%llx)\n", dcon, static_cast(bits)); } else { @@ -14031,17 +14027,25 @@ void Compiler::gtDispConst(GenTree* tree) #if defined(TARGET_XARCH) case TYP_SIMD32: { - printf("<0x%016llx, 0x%016llx, 0x%016llx, 0x%016llx>", vecCon->gtSimdVal.u64[0], - vecCon->gtSimdVal.u64[1], vecCon->gtSimdVal.u64[2], vecCon->gtSimdVal.u64[3]); + printf("<0x%016llx, 0x%016llx, 0x%016llx, 0x%016llx>", + static_cast(vecCon->gtSimdVal.u64[0]), + static_cast(vecCon->gtSimdVal.u64[1]), + static_cast(vecCon->gtSimdVal.u64[2]), + static_cast(vecCon->gtSimdVal.u64[3])); break; } case TYP_SIMD64: { printf("<0x%016llx, 0x%016llx, 0x%016llx, 0x%016llx, 0x%016llx, 0x%016llx, 0x%016llx, 0x%016llx>", - vecCon->gtSimdVal.u64[0], vecCon->gtSimdVal.u64[1], vecCon->gtSimdVal.u64[2], - vecCon->gtSimdVal.u64[3], vecCon->gtSimdVal.u64[4], vecCon->gtSimdVal.u64[5], - vecCon->gtSimdVal.u64[6], vecCon->gtSimdVal.u64[7]); + static_cast(vecCon->gtSimdVal.u64[0]), + static_cast(vecCon->gtSimdVal.u64[1]), + static_cast(vecCon->gtSimdVal.u64[2]), + static_cast(vecCon->gtSimdVal.u64[3]), + static_cast(vecCon->gtSimdVal.u64[4]), + static_cast(vecCon->gtSimdVal.u64[5]), + static_cast(vecCon->gtSimdVal.u64[6]), + static_cast(vecCon->gtSimdVal.u64[7])); break; } @@ -14463,8 +14467,8 @@ void Compiler::gtDispTree(GenTree* tree, { if (tree == nullptr) { - printf(" [%08X] \n", tree); - printf(""); // null string means flush + printf(" [%p] \n", tree); + fflush(jitstdout()); return; } @@ -15054,7 +15058,7 @@ void Compiler::gtDispTree(GenTree* tree, else { printf(" :"); - printf(""); // null string means flush + fflush(jitstdout()); } break; } @@ -19889,7 +19893,7 @@ void dispNodeList(GenTree* list, bool verbose) if (verbose) { - printf("%08X -> %08X -> %08X\n", last, list, next); + printf("%p -> %p -> %p\n", last, list, next); } assert(!last || last->gtNext == list); @@ -19904,7 +19908,7 @@ void dispNodeList(GenTree* list, bool verbose) last = list; list = next; } - printf(""); // null string means flush + fflush(jitstdout()); } #endif diff --git a/src/runtime/src/coreclr/jit/gentree.h b/src/runtime/src/coreclr/jit/gentree.h index cce0ecb434e2..7033e6cb81cd 100644 --- a/src/runtime/src/coreclr/jit/gentree.h +++ b/src/runtime/src/coreclr/jit/gentree.h @@ -4539,6 +4539,12 @@ struct AsyncCallInfo // records that behavior. ::ContinuationContextHandling ContinuationContextHandling = ContinuationContextHandling::None; + // Continuation context handling of the inlined frames enclosing this call, innermost + // first: one entry per frame that logically returns to its caller when this call + // suspends, i.e. the handling of the call that inlined that frame. The root method's + // frame has no entry since it never transitions. + jitstd::vector<::ContinuationContextHandling>* InlineFrameContextHandling = nullptr; + // Is this 'await valueTask.AsTask()'? These come with special semantics as // they no longer transparently forward continuation context handling to an // underlying IValueTaskSource, if present. @@ -5273,6 +5279,12 @@ struct GenTreeCall final : public GenTree return *asyncInfo; } + AsyncCallInfo& GetAsyncInfo() + { + assert(IsAsync()); + return *asyncInfo; + } + //--------------------------------------------------------------------------- // GetRegNumByIdx: get i'th return register allocated to this call node. // diff --git a/src/runtime/src/coreclr/jit/hashbv.cpp b/src/runtime/src/coreclr/jit/hashbv.cpp index ac009259afb2..d4f2467a036f 100644 --- a/src/runtime/src/coreclr/jit/hashbv.cpp +++ b/src/runtime/src/coreclr/jit/hashbv.cpp @@ -12,7 +12,7 @@ #ifdef DEBUG void hashBvNode::dump() { - printf("base: %d { ", baseIndex); + printf("base: %llu { ", (unsigned long long)baseIndex); this->foreachBit(pBit); printf("}\n"); } @@ -599,7 +599,7 @@ void hashBv::dump() { printf(" "); } - printf("%d", index); + printf("%llu", (unsigned long long)index); first = false; return HbvWalk::Continue; }); @@ -618,11 +618,11 @@ void hashBv::dumpFancy() { if (last_0 + 1 != last_1) { - printf(" %d-%d", last_0 + 1, last_1); + printf(" %llu-%llu", (unsigned long long)(last_0 + 1), (unsigned long long)last_1); } else { - printf(" %d", last_1); + printf(" %llu", (unsigned long long)last_1); } last_0 = index - 1; } @@ -634,11 +634,11 @@ void hashBv::dumpFancy() // Print the last one if (last_0 + 1 != last_1) { - printf(" %d-%d", last_0 + 1, last_1); + printf(" %llu-%llu", (unsigned long long)(last_0 + 1), (unsigned long long)last_1); } else { - printf(" %d", last_1); + printf(" %llu", (unsigned long long)last_1); } printf("}\n"); @@ -1797,7 +1797,7 @@ void hashBv::InorderTraverseTwo(hashBv* other, dualNodeAction a) #ifdef DEBUG void SimpleDumpNode(hashBvNode* n) { - printf("base: %d\n", n->baseIndex); + printf("base: %llu\n", (unsigned long long)n->baseIndex); } void DumpNode(hashBvNode* n) @@ -1810,7 +1810,7 @@ void SimpleDumpDualNode(hashBv* a, hashBv* b, hashBvNode* n, hashBvNode* m) printf("nodes: "); if (n) { - printf("%d,", n->baseIndex); + printf("%llu,", (unsigned long long)n->baseIndex); } else { @@ -1818,7 +1818,7 @@ void SimpleDumpDualNode(hashBv* a, hashBv* b, hashBvNode* n, hashBvNode* m) } if (m) { - printf("%d\n", m->baseIndex); + printf("%llu\n", (unsigned long long)m->baseIndex); } else { diff --git a/src/runtime/src/coreclr/jit/host.h b/src/runtime/src/coreclr/jit/host.h index 6f5b4427403e..cdb9996cbd81 100644 --- a/src/runtime/src/coreclr/jit/host.h +++ b/src/runtime/src/coreclr/jit/host.h @@ -3,7 +3,9 @@ /*****************************************************************************/ -int jitprintf(const char* fmt, ...); +#include + +int jitprintf(const char* fmt, ...) MINIPAL_ATTR_FORMAT_PRINTF(1, 2); #ifdef DEBUG @@ -30,11 +32,11 @@ class LogEnv bool vlogf(unsigned level, const char* fmt, va_list args); int vflogf(FILE* file, const char* fmt, va_list args); -int logf(const char* fmt, ...); -int flogf(FILE* file, const char* fmt, ...); -void gcDump_logf(const char* fmt, ...); +int logf(const char* fmt, ...) MINIPAL_ATTR_FORMAT_PRINTF(1, 2); +int flogf(FILE* file, const char* fmt, ...) MINIPAL_ATTR_FORMAT_PRINTF(2, 3); +void gcDump_logf(const char* fmt, ...) MINIPAL_ATTR_FORMAT_PRINTF(1, 2); -void logf(unsigned level, const char* fmt, ...); +void logf(unsigned level, const char* fmt, ...) MINIPAL_ATTR_FORMAT_PRINTF(2, 3); extern "C" void ANALYZER_NORETURN assertAbort(const char* why, const char* file, unsigned line); diff --git a/src/runtime/src/coreclr/jit/importer.cpp b/src/runtime/src/coreclr/jit/importer.cpp index 58d842a3383c..e8a53eab7e2d 100644 --- a/src/runtime/src/coreclr/jit/importer.cpp +++ b/src/runtime/src/coreclr/jit/importer.cpp @@ -6802,7 +6802,7 @@ void Compiler::impImportBlockCode(BasicBlock* block) case CEE_LDC_I8: cval.lngVal = getI8LittleEndian(codeAddr); - JITDUMP(" 0x%016llx", cval.lngVal); + JITDUMP(" 0x%016llx", (unsigned long long)cval.lngVal); impPushOnStack(gtNewLconNode(cval.lngVal), typeInfo(TYP_LONG)); break; @@ -11999,7 +11999,11 @@ bool Compiler::impWrapTopOfStackInAwait() AsyncCallInfo* asyncInfo = new (this, CMK_Async) AsyncCallInfo; - if (impInlineRoot()->compIsAsyncVersion()) + bool const hasContextHandling = + compIsForInlining() && + (impInlineInfo->iciCall->gtArgs.FindWellKnownArg(WellKnownArg::AsyncResumedUse) != nullptr); + + if (!hasContextHandling) { asyncInfo->IsTailAwait = !compIsForInlining() || impInlineInfo->iciCall->GetAsyncInfo().IsTailAwait; @@ -12012,22 +12016,27 @@ bool Compiler::impWrapTopOfStackInAwait() awaitCall->gtCallMoreFlags |= GTF_CALL_M_IMPLICIT_TAILCALL; } #endif + + awaitCall->SetIsAsync(asyncInfo); } else { - // We are inlining into an async method. This means we have a proper - // async await, and we require proper handling. + // The await runs inside a frame that does context handling, either because we are + // inlining into an async method or because a context-owning frame encloses this + // one. Either way it is a proper async await and needs that frame's handling. assert(compIsForInlining() && impInlineInfo->iciCall->IsAsync()); GenTreeCall* inlCall = impInlineInfo->iciCall; JITDUMP("Inheriting continuation handling %d from caller [%06u]\n", (unsigned)inlCall->GetAsyncInfo().ContinuationContextHandling, dspTreeID(inlCall)); asyncInfo->ContinuationContextHandling = inlCall->GetAsyncInfo().ContinuationContextHandling; + + // Mark the call async first: inheriting the contexts also inherits the inlined + // frame depth, which lives in the async call info. + awaitCall->SetIsAsync(asyncInfo); impInheritAsyncContextsFromInliner(awaitCall); } - awaitCall->SetIsAsync(asyncInfo); - if (awaitCall->IsInlineCandidate()) { // The struct return fixup does not create a new node for inline @@ -12848,7 +12857,7 @@ void Compiler::impImportBlockPending(BasicBlock* block) #ifdef DEBUG if (verbose && 0) { - printf("Added PendingDsc - %08p for " FMT_BB "\n", dspPtr(dsc), block->bbNum); + printf("Added PendingDsc - %p for " FMT_BB "\n", dspPtr(dsc), block->bbNum); } #endif } @@ -12913,7 +12922,7 @@ void Compiler::impReimportBlockPending(BasicBlock* block) #ifdef DEBUG if (verbose && 0) { - printf("Added PendingDsc - %08p for " FMT_BB "\n", dspPtr(dsc), block->bbNum); + printf("Added PendingDsc - %p for " FMT_BB "\n", dspPtr(dsc), block->bbNum); } #endif } diff --git a/src/runtime/src/coreclr/jit/importercalls.cpp b/src/runtime/src/coreclr/jit/importercalls.cpp index b8fe90e5a3a2..19b001e5026b 100644 --- a/src/runtime/src/coreclr/jit/importercalls.cpp +++ b/src/runtime/src/coreclr/jit/importercalls.cpp @@ -325,9 +325,10 @@ var_types Compiler::impImportCall(OPCODE opcode, NamedIntrinsic ni = NI_Illegal; CORINFO_SIG_INFO calliSig; - GenTree* varArgsCookie = nullptr; - GenTree* instParam = nullptr; - GenTree* asyncContinuation = nullptr; + GenTree* varArgsCookie = nullptr; + GenTree* instParam = nullptr; + GenTree* asyncContinuation = nullptr; + bool asyncCallUsesOwnContexts = false; // Swift calls that might throw use a SwiftError* arg that requires additional IR to handle, // so if we're importing a Swift call, look for this type in the signature @@ -630,7 +631,7 @@ var_types Compiler::impImportCall(OPCODE opcode, if (sig->isAsyncCall()) { - impSetupAsyncCall(call->AsCall(), methHnd, opcode, prefixFlags, ni, di); + impSetupAsyncCall(call->AsCall(), methHnd, opcode, prefixFlags, ni, di, &asyncCallUsesOwnContexts); if (compDonotInline()) { @@ -642,7 +643,7 @@ var_types Compiler::impImportCall(OPCODE opcode, if (call->AsCall()->IsAsync()) { - impInsertAsyncArgsForLdvirtftnCall(call->AsCall()); + impInsertAsyncArgsForLdvirtftnCall(call->AsCall(), asyncCallUsesOwnContexts); } GenTree* thisPtr = impPopStack().val; @@ -952,7 +953,7 @@ var_types Compiler::impImportCall(OPCODE opcode, if (sig->isAsyncCall()) { - impSetupAsyncCall(call->AsCall(), methHnd, opcode, prefixFlags, ni, di); + impSetupAsyncCall(call->AsCall(), methHnd, opcode, prefixFlags, ni, di, &asyncCallUsesOwnContexts); if (compDonotInline()) { @@ -1113,7 +1114,7 @@ var_types Compiler::impImportCall(OPCODE opcode, } } - if (asyncContinuation != nullptr) + if ((asyncContinuation != nullptr) && !asyncCallUsesOwnContexts) { impInheritAsyncContextsFromInliner(call->AsCall()); } @@ -1933,7 +1934,7 @@ GenTree* Compiler::impDuplicateWithProfiledArg(GenTreeCall* call, IL_OFFSET ilOf JITDUMP("%u likely values:\n", valuesCount) for (UINT32 i = 0; i < valuesCount; i++) { - JITDUMP(" %u) %u - %u%%\n", i, likelyValues[i].value, likelyValues[i].likelihood) + JITDUMP(" %u) %zd - %u%%\n", i, likelyValues[i].value, likelyValues[i].likelihood) } // For now, we only do a single guess, but it's pretty straightforward to @@ -1984,7 +1985,7 @@ GenTree* Compiler::impDuplicateWithProfiledArg(GenTreeCall* call, IL_OFFSET ilOf if ((profiledValue >= minValue) && (profiledValue <= maxValue)) { - JITDUMP("Duplicating for popular value = %u\n", profiledValue) + JITDUMP("Duplicating for popular value = %zd\n", profiledValue) DISPTREE(call) if (call->gtArgs.GetUserArgByIndex(argNum)->GetNode()->OperIsConst()) @@ -2601,7 +2602,7 @@ void Compiler::impPopArgsForSwiftCall(GenTreeCall* call, CORINFO_SIG_INFO* sig, } else { - JITDUMP(" Argument %d of type %s must be passed as %d primitive(s)\n", argIndex, + JITDUMP(" Argument %d of type %s must be passed as %zu primitive(s)\n", argIndex, typGetObjLayout(arg->GetSignatureClassHandle())->GetClassName(), lowering->numLoweredElements); for (size_t i = 0; i < lowering->numLoweredElements; i++) { @@ -2734,7 +2735,7 @@ void Compiler::impPopArgsForSwiftCall(GenTreeCall* call, CORINFO_SIG_INFO* sig, } else { - printf(" Call returns %s as %d primitive(s) in registers\n", + printf(" Call returns %s as %zu primitive(s) in registers\n", typGetObjLayout(sig->retTypeClass)->GetClassName(), lowering->numLoweredElements); for (size_t i = 0; i < lowering->numLoweredElements; i++) { @@ -7759,21 +7760,28 @@ void Compiler::impCheckForPInvokeCall( // Register a call as being async and set up context handling information depending on the IL. // // Arguments: -// call - The call -// methHnd - Method handle being called -// opcode - The IL opcode for the call -// prefixFlags - Flags containing context handling information from IL -// ni - Named intrinsic recognized for the callee (or NI_Illegal) -// callDI - Debug info for the async call +// call - The call +// methHnd - Method handle being called +// opcode - The IL opcode for the call +// prefixFlags - Flags containing context handling information from IL +// ni - Named intrinsic recognized for the callee (or NI_Illegal) +// callDI - Debug info for the async call +// usesOwnContexts - [out] Set to true if the call gets the contexts of the frame it is +// in, which is the case for an await that may suspend in an inlinee's +// own frame. Set to false if it should instead inherit the inlining +// call's contexts, which the caller does via +// impInheritAsyncContextsFromInliner. // void Compiler::impSetupAsyncCall(GenTreeCall* call, CORINFO_METHOD_HANDLE methHnd, OPCODE opcode, unsigned prefixFlags, NamedIntrinsic ni, - const DebugInfo& callDI) + const DebugInfo& callDI, + bool* usesOwnContexts) { AsyncCallInfo asyncInfo; + *usesOwnContexts = false; // Some async helpers always suspend when called. For these we can skip the // check for a null continuation after the call and suspend unconditionally. @@ -7791,38 +7799,100 @@ void Compiler::impSetupAsyncCall(GenTreeCall* call, if (compIsForInlining()) { - if (!m_nextAwaitIsTail && !compIsAsyncVersion()) - { - compInlineResult->NoteFatal(InlineObservation::CALLEE_AWAIT); - return; - } + // Two cases are inlined cheaply: async versions of synchronous methods, where + // all async calls are in tail position, and explicit tail awaits. In both the + // inlinee's tail can run in the caller's context, so we can inherit all context + // handling from the inlining call and no logical frame transition is needed when + // the inlinee returns. + bool inheritsCallerContexts = m_nextAwaitIsTail || compIsAsyncVersion(); - // We cannot inline if the callee returns valueTask.AsTask() in an - // async version. We need to preserve the continuation in this case to - // be able to mark it with CORINFO_CONTINUATION_VALUETASK_ADAPTED_TO_TASK. + // We cannot inline if the callee returns valueTask.AsTask(). We need to preserve + // the continuation in this case to be able to mark it with + // CORINFO_CONTINUATION_VALUETASK_ADAPTED_TO_TASK. if ((prefixFlags & PREFIX_IS_ADAPTED_FROM_VALUETASK) != 0) { compInlineResult->NoteFatal(InlineObservation::CALLEE_AWAIT); return; } - // For async versions of synchronous methods all async calls are in - // tail position. Inlining is simple for these cases: we can just - // inherit all context handling from the inlining call. - assert(!compIsAsyncVersion() || ((prefixFlags & PREFIX_IS_ASYNC_VERSION_TAIL_AWAIT) != 0)); + if (!inheritsCallerContexts) + { + if (!generalAsyncInliningEnabled()) + { + compInlineResult->NoteFatal(InlineObservation::CALLEE_AWAIT); + return; + } + + // Calls from non-async into async go through thunks that are passed the + // continuation explicitly, so they cannot be inlined. This is a property of + // the root method being compiled, not of the callee, which inlines fine into + // an async root. + if (!impInlineRoot()->compIsAsync()) + { + JITDUMP("Cannot inline an await into a non-async root method\n"); + compInlineResult->NoteFatal(InlineObservation::CALLSITE_AWAIT_IN_NON_ASYNC_ROOT); + return; + } + + // General case: this is a real await inside the inlinee that may suspend. It + // gets its own context handling below, exactly like an await in a non-inlined + // method, and the inlinee's own contexts (created by its SaveAsyncContexts) + // are used rather than the caller's. + + // The inlined frame must not end up inside a protected region of the caller. + // An exception unwinding out of it skips the post-inline handling, and getting + // back onto the caller's continuation context cannot be recovered from a + // handler because it may suspend. A user 'catch' between the frame and the + // resumption would then run on the wrong continuation context. Doing this + // correctly needs the catch-and-rethrow expansion described in + // docs/design/coreclr/jit/runtime-async-inlining.md, which is not implemented + // yet. + // + // This covers nesting as well: a caller that is itself inlined into a + // protected region was rejected by this same check. + // + // Only user EH matters here. Every async frame has a context restore + // try-fault wrapped around its whole body by SaveAsyncContexts, which by + // this point has run both for the caller and for every frame it was inlined + // into, so those clauses must be ignored. + // + // This is a property of the call site, not of the callee: the same callee + // inlines fine at a call site outside a protected region. + BasicBlock* const callSiteBlock = impInlineInfo->iciBlock; + if (impInlineInfo->InlinerCompiler->ehIsInsideNonAsyncContextRestoreRegion(callSiteBlock)) + { + compInlineResult->NoteFatal(InlineObservation::CALLSITE_AWAIT_IN_TRY_REGION); + return; + } + + // Suspending inside a protected region of the inlinee itself is not handled + // yet either. + if ((compCurBB != nullptr) && (compCurBB->hasTryIndex() || compCurBB->hasHndIndex())) + { + compInlineResult->NoteFatal(InlineObservation::CALLEE_AWAIT_IN_TRY); + return; + } + + JITDUMP("Call [%06u] is an await in an inlinee that may suspend\n", dspTreeID(call)); + *usesOwnContexts = true; + } + else + { + assert(!compIsAsyncVersion() || ((prefixFlags & PREFIX_IS_ASYNC_VERSION_TAIL_AWAIT) != 0)); - GenTreeCall* inlCall = impInlineInfo->iciCall; - JITDUMP("Call [%06u] is to function with a tail async call [%06u]\n", dspTreeID(inlCall), dspTreeID(call)); + GenTreeCall* inlCall = impInlineInfo->iciCall; + JITDUMP("Call [%06u] is to function with a tail async call [%06u]\n", dspTreeID(inlCall), dspTreeID(call)); - assert(inlCall->IsAsync()); + assert(inlCall->IsAsync()); - asyncInfo.ContinuationContextHandling = inlCall->GetAsyncInfo().ContinuationContextHandling; - // Validate that below code won't override the handling - assert((prefixFlags & PREFIX_IS_TASK_AWAIT) == 0); + asyncInfo.ContinuationContextHandling = inlCall->GetAsyncInfo().ContinuationContextHandling; + // Validate that below code won't override the handling + assert((prefixFlags & PREFIX_IS_TASK_AWAIT) == 0); - asyncInfo.IsTailAwait = - inlCall->GetAsyncInfo().IsTailAwait && (m_nextAwaitIsTail || (call->gtReturnType == info.compRetType)); - m_nextAwaitIsTail = false; + asyncInfo.IsTailAwait = + inlCall->GetAsyncInfo().IsTailAwait && (m_nextAwaitIsTail || (call->gtReturnType == info.compRetType)); + m_nextAwaitIsTail = false; + } } else { @@ -7896,9 +7966,14 @@ void Compiler::impSetupAsyncCall(GenTreeCall* call, // call - The async call // // Remarks: -// Currently we only allow inlining of async calls when all awaits are tail -// awaits. In that case inlining is simplified as we can just inherit -// everything from the inlining call. +// For an await that runs in the inlining call's frame rather than a frame of its own, +// which is the case for a tail await of the inlinee and for the transparent await an +// async version forwards through. Such an await has no contexts to use, so it takes the +// inlining call's: a suspension in it then runs exactly the handling that the frame it +// ended up in would have run. +// +// Awaits that may suspend in a frame of their own instead get their own contexts, from +// that frame's SaveAsyncContexts, and are skipped here. // void Compiler::impInheritAsyncContextsFromInliner(GenTreeCall* call) { @@ -7921,12 +7996,8 @@ void Compiler::impInheritAsyncContextsFromInliner(GenTreeCall* call) return; } - // We are inlining an async call that does not save contexts into a call - // that does. We currently allow this only in cases where the tail of the - // inlinee can run in the caller's context, and hence we propagate the - // caller's context here. It means we do not need to worry about switching - // into the caller's context when the inlinee is returning to the caller - // after the await. + // Take the values as they appear in the inlining call, so a suspension restores and + // captures exactly what the frame this await ended up in would have. assert(resumedUseArg->GetNode()->OperIs(GT_LCL_VAR) && resumedDefArg->GetNode()->OperIs(GT_LCL_ADDR) && execArg->GetNode()->OperIs(GT_LCL_VAR) && syncArg->GetNode()->OperIs(GT_LCL_VAR)); JITDUMP("Inheriting resumed use [%06u], resumed def [%06u], and contexts [%06u] and [%06u] from caller node\n", @@ -7939,8 +8010,42 @@ void Compiler::impInheritAsyncContextsFromInliner(GenTreeCall* call) GenTree* syncNode = gtCloneExpr(syncArg->GetNode()); call->gtArgs.PushFront(this, NewCallArg::Primitive(syncNode).WellKnown(WellKnownArg::AsyncSynchronizationContext)); call->gtArgs.PushFront(this, NewCallArg::Primitive(execNode).WellKnown(WellKnownArg::AsyncExecutionContext)); - call->gtArgs.PushFront(this, NewCallArg::Primitive(resumedDefNode).WellKnown(WellKnownArg::AsyncResumedDef)); call->gtArgs.PushFront(this, NewCallArg::Primitive(resumedUseNode).WellKnown(WellKnownArg::AsyncResumedUse)); + call->gtArgs.PushFront(this, NewCallArg::Primitive(resumedDefNode).WellKnown(WellKnownArg::AsyncResumedDef)); + + // The inlining call may carry further sets describing the frames enclosing it, which + // this call inherits as well: it ends up in the same frame, so a suspension in it has + // to run the same chain of frame transitions. Dropping them would silently lose the + // handling for every frame outside the immediate one. + bool skippedFirst = false; + for (CallArg& arg : inlCall->gtArgs.Args()) + { + WellKnownArg wka = arg.GetWellKnownArg(); + if ((wka != WellKnownArg::AsyncResumedUse) && (wka != WellKnownArg::AsyncExecutionContext) && + (wka != WellKnownArg::AsyncSynchronizationContext)) + { + continue; + } + + if ((wka == WellKnownArg::AsyncResumedUse) && !skippedFirst) + { + // Already inherited above, along with the resumed def that only the innermost + // frame has. + skippedFirst = true; + continue; + } + + if (&arg == execArg || &arg == syncArg) + { + continue; + } + + call->gtArgs.PushBack(this, NewCallArg::Primitive(gtCloneExpr(arg.GetNode())).WellKnown(wka)); + } + + // This call ends up in the same frame as the inlining call, so it hands off through + // the same chain of frames in the same way. + call->GetAsyncInfo().InlineFrameContextHandling = inlCall->GetAsyncInfo().InlineFrameContextHandling; } //------------------------------------------------------------------------ @@ -7949,13 +8054,15 @@ void Compiler::impInheritAsyncContextsFromInliner(GenTreeCall* call) // ldvirtftn. // // Arguments: -// call - The call +// call - The call +// usesOwnContexts - Whether the call is an await in an inlinee that gets its own +// contexts, as reported by impSetupAsyncCall // // Remarks: // Should be called before the 'this' arg is inserted, but after other IL args // have been inserted. // -void Compiler::impInsertAsyncArgsForLdvirtftnCall(GenTreeCall* call) +void Compiler::impInsertAsyncArgsForLdvirtftnCall(GenTreeCall* call, bool usesOwnContexts) { assert(call->AsCall()->IsAsync()); @@ -7970,7 +8077,10 @@ void Compiler::impInsertAsyncArgsForLdvirtftnCall(GenTreeCall* call) .WellKnown(WellKnownArg::AsyncContinuation)); } - impInheritAsyncContextsFromInliner(call); + if (!usesOwnContexts) + { + impInheritAsyncContextsFromInliner(call); + } } //------------------------------------------------------------------------ @@ -8178,7 +8288,7 @@ void Compiler::pickGDV(GenTreeCall* call, for (UINT32 i = 0; i < numberOfClasses; i++) { const char* className = eeGetClassName((CORINFO_CLASS_HANDLE)likelyClasses[i].handle); - JITDUMP(" %u) %p (%s) [likelihood:%u%%]\n", i + 1, likelyClasses[i].handle, className, + JITDUMP(" %u) %p (%s) [likelihood:%u%%]\n", i + 1, (void*)likelyClasses[i].handle, className, likelyClasses[i].likelihood); } } diff --git a/src/runtime/src/coreclr/jit/inline.cpp b/src/runtime/src/coreclr/jit/inline.cpp index 959576825ca3..91535236bc27 100644 --- a/src/runtime/src/coreclr/jit/inline.cpp +++ b/src/runtime/src/coreclr/jit/inline.cpp @@ -346,6 +346,7 @@ InlineContext::InlineContext(InlineStrategy* strategy) , m_Devirtualized(false) , m_Guarded(false) , m_Unboxed(false) + , m_IsAsyncCall(false) , m_ILInstsSet(nullptr) #endif { @@ -415,27 +416,33 @@ void InlineContext::Dump(bool verbose, unsigned indent) const char* guarded = m_Guarded ? " GUARDED" : ""; const char* unboxed = m_Unboxed ? " UNBOXED" : ""; + const char* asyncness = ""; + if (compiler->compIsAsync()) + { + asyncness = m_IsAsyncCall ? " ASYNC" : " SYNC"; + } + IL_OFFSET offs = m_ActualCallOffset; if (verbose) { if (offs == BAD_IL_OFFSET) { - printf("%*s[" FMT_INL_CTX " IL=???? TR=%06u %08X] [%s%s: %s%s%s%s] %s\n", indent, "", m_Ordinal, + printf("%*s[" FMT_INL_CTX " IL=???? TR=%06u %08X] [%s%s: %s%s%s%s%s] %s\n", indent, "", m_Ordinal, m_TreeID, calleeToken, inlineResult, inlineTarget, inlineReason, guarded, devirtualized, unboxed, - calleeName); + asyncness, calleeName); } else { - printf("%*s[" FMT_INL_CTX " IL=%04d TR=%06u %08X] [%s%s: %s%s%s%s] %s\n", indent, "", m_Ordinal, offs, + printf("%*s[" FMT_INL_CTX " IL=%04d TR=%06u %08X] [%s%s: %s%s%s%s%s] %s\n", indent, "", m_Ordinal, offs, m_TreeID, calleeToken, inlineResult, inlineTarget, inlineReason, guarded, devirtualized, unboxed, - calleeName); + asyncness, calleeName); } } else { - printf("%*s[%s%s%s%s%s] %s\n", indent, "", inlineResult, inlineReason, guarded, devirtualized, unboxed, - calleeName); + printf("%*s[%s%s%s%s%s%s] %s\n", indent, "", inlineResult, inlineReason, guarded, devirtualized, unboxed, + asyncness, calleeName); } } @@ -1380,6 +1387,7 @@ InlineContext* InlineStrategy::NewContext(InlineContext* parentContext, Statemen context->m_Devirtualized = call->IsDevirtualized(); context->m_Guarded = call->IsGuarded(); context->m_Unboxed = call->IsUnboxed(); + context->m_IsAsyncCall = call->IsAsync(); context->m_TreeID = call->gtTreeID; #endif diff --git a/src/runtime/src/coreclr/jit/inline.def b/src/runtime/src/coreclr/jit/inline.def index 5f23fdfa0b70..a30dbf05c7e4 100644 --- a/src/runtime/src/coreclr/jit/inline.def +++ b/src/runtime/src/coreclr/jit/inline.def @@ -57,6 +57,7 @@ INLINE_OBSERVATION(STFLD_NEEDS_HELPER, bool, "stfld needs helper", INLINE_OBSERVATION(TOO_MANY_ARGUMENTS, bool, "too many arguments", FATAL, CALLEE) INLINE_OBSERVATION(TOO_MANY_LOCALS, bool, "too many locals", FATAL, CALLEE) INLINE_OBSERVATION(AWAIT, bool, "has await", FATAL, CALLEE) +INLINE_OBSERVATION(AWAIT_IN_TRY, bool, "has await inside try region", FATAL, CALLEE) INLINE_OBSERVATION(ASYNC_SUSPEND, bool, "has async suspend", FATAL, CALLEE) // ------ Callee Performance ------- @@ -132,6 +133,8 @@ INLINE_OBSERVATION(ARG_HAS_NULL_THIS, bool, "this pointer argument is INLINE_OBSERVATION(ARG_NO_BASH_TO_INT, bool, "argument can't bash to int", FATAL, CALLSITE) INLINE_OBSERVATION(ARG_NO_BASH_TO_REF, bool, "argument can't bash to ref", FATAL, CALLSITE) INLINE_OBSERVATION(ARG_TYPES_INCOMPATIBLE, bool, "argument types incompatible", FATAL, CALLSITE) +INLINE_OBSERVATION(AWAIT_IN_NON_ASYNC_ROOT, bool, "has await, root method is not async", FATAL, CALLSITE) +INLINE_OBSERVATION(AWAIT_IN_TRY_REGION, bool, "within try region, has await", FATAL, CALLSITE) INLINE_OBSERVATION(CANT_CLASS_INIT, bool, "can't class init", FATAL, CALLSITE) INLINE_OBSERVATION(COMPILATION_ERROR, bool, "compilation error", FATAL, CALLSITE) INLINE_OBSERVATION(COMPILATION_FAILURE, bool, "failed to compile", FATAL, CALLSITE) diff --git a/src/runtime/src/coreclr/jit/inline.h b/src/runtime/src/coreclr/jit/inline.h index f7ca4e3c88c5..7e307f49d50d 100644 --- a/src/runtime/src/coreclr/jit/inline.h +++ b/src/runtime/src/coreclr/jit/inline.h @@ -869,6 +869,11 @@ class InlineContext { return m_Unboxed; } + + bool IsAsyncCall() const + { + return m_IsAsyncCall; + } #endif unsigned GetImportedILSize() const @@ -933,6 +938,7 @@ class InlineContext bool m_Devirtualized : 1; // true if this was a devirtualized call bool m_Guarded : 1; // true if this was a guarded call bool m_Unboxed : 1; // true if this call now invokes the unboxed entry + bool m_IsAsyncCall : 1; // true if the call being inlined was an async call #endif // defined(DEBUG) diff --git a/src/runtime/src/coreclr/jit/inlinepolicy.cpp b/src/runtime/src/coreclr/jit/inlinepolicy.cpp index b0e822e184f8..2641cc16806c 100644 --- a/src/runtime/src/coreclr/jit/inlinepolicy.cpp +++ b/src/runtime/src/coreclr/jit/inlinepolicy.cpp @@ -2778,7 +2778,7 @@ void DiscretionaryPolicy::DumpSchema(FILE* file) const void DiscretionaryPolicy::DumpData(FILE* file) const { fprintf(file, "%u", m_CodeSize); - fprintf(file, ",%u", m_CallsiteFrequency); + fprintf(file, ",%u", (unsigned)m_CallsiteFrequency); fprintf(file, ",%u", m_InstructionCount); fprintf(file, ",%u", m_LoadStoreCount); fprintf(file, ",%u", m_BlockCount); @@ -3227,7 +3227,7 @@ void ProfilePolicy::DetermineProfitability(CORINFO_METHOD_INFO* methodInfo) JITLOG_THIS(m_RootCompiler, (LL_INFO100000, "Inline %s profitable: benefit=%g (perCall=%g, local=%g, global=%g, size=%g)\n", shouldInline ? "is" : "is not", benefit, perCallBenefit, localBenefit, globalImportance, - (double)m_PerCallInstructionEstimate / SIZE_SCALE, (double)m_ModelCodeSizeEstimate / SIZE_SCALE)); + (double)m_ModelCodeSizeEstimate / SIZE_SCALE)); if (!shouldInline) { diff --git a/src/runtime/src/coreclr/jit/jitconfigvalues.h b/src/runtime/src/coreclr/jit/jitconfigvalues.h index ff116667cc70..1e95c26b1e31 100644 --- a/src/runtime/src/coreclr/jit/jitconfigvalues.h +++ b/src/runtime/src/coreclr/jit/jitconfigvalues.h @@ -621,6 +621,12 @@ OPT_CONFIG_STRING(JitAsyncDefaultValueAnalysisRange, // a continuation is being reused. OPT_CONFIG_STRING(JitAsyncPreservedValueAnalysisRange, "JitAsyncPreservedValueAnalysisRange") +// Enable general inlining of runtime async calls, i.e. inlining of async +// callees that may suspend. When zero, only the restricted cases are inlined: +// callees without any awaits, async versions of synchronous methods, and tail +// awaits. +RELEASE_CONFIG_INTEGER(JitAsyncInlining, "JitAsyncInlining", 0) + RELEASE_CONFIG_INTEGER(JitEnableOptRepeat, "JitEnableOptRepeat", 1) // If zero, do not allow JitOptRepeat RELEASE_CONFIG_METHODSET(JitOptRepeat, "JitOptRepeat") // Runs optimizer multiple times on specified methods RELEASE_CONFIG_INTEGER(JitOptRepeatCount, "JitOptRepeatCount", 2) // Number of times to repeat opts when repeating diff --git a/src/runtime/src/coreclr/jit/jitmetadata.cpp b/src/runtime/src/coreclr/jit/jitmetadata.cpp index 9ac4eb66ebf5..671d5cbab568 100644 --- a/src/runtime/src/coreclr/jit/jitmetadata.cpp +++ b/src/runtime/src/coreclr/jit/jitmetadata.cpp @@ -91,7 +91,7 @@ static void printMetric(int value) // static void printMetric(int64_t value) { - printf("%lld", value); + printf("%lld", (long long)value); } //------------------------------------------------------------------------ diff --git a/src/runtime/src/coreclr/jit/lclvars.cpp b/src/runtime/src/coreclr/jit/lclvars.cpp index 578958d7f4c4..b8753896d6e0 100644 --- a/src/runtime/src/coreclr/jit/lclvars.cpp +++ b/src/runtime/src/coreclr/jit/lclvars.cpp @@ -131,7 +131,7 @@ void Compiler::lvaInitTypeRef() } else { - printf("Swift compilation returns %s as %d primitive(s) in registers\n", + printf("Swift compilation returns %s as %zu primitive(s) in registers\n", typGetObjLayout(retTypeHnd)->GetClassName(), lowering->numLoweredElements); for (size_t i = 0; i < lowering->numLoweredElements; i++) { @@ -1807,7 +1807,7 @@ bool Compiler::StructPromotionHelper::CanPromoteStructVar(unsigned lclNum) // (which would result in dependent promotion anyway). if ((m_compiler->info.compCallConv == CorInfoCallConvExtension::Swift) && varDsc->lvIsParam) { - JITDUMP(" struct promotion of V%02u is disabled because it is a parameter to a Swift function"); + JITDUMP(" struct promotion of V%02u is disabled because it is a parameter to a Swift function", lclNum); return false; } #endif @@ -6683,7 +6683,7 @@ void Compiler::lvaTableDump(FrameLayoutState curState) assert(codeGen->regSet.tmpAllFree()); for (TempDsc* temp = codeGen->regSet.tmpListBeg(); temp != nullptr; temp = codeGen->regSet.tmpListNxt(temp)) { - printf("; TEMP_%02u %26s%*s%7s -> ", -temp->tdTempNum(), " ", refCntWtdWidth, " ", + printf("; TEMP_%02u %26s%*s%7s -> ", -temp->tdTempNum(), " ", static_cast(refCntWtdWidth), " ", varTypeName(temp->tdTempType())); int offset = temp->tdTempOffs(); printf(" [%2s%1s0x%02X]\n", isFramePointerUsed() ? STR_FPBASE : STR_SPBASE, (offset < 0 ? "-" : "+"), diff --git a/src/runtime/src/coreclr/jit/lower.cpp b/src/runtime/src/coreclr/jit/lower.cpp index f019a69538ae..71bee8f642fc 100644 --- a/src/runtime/src/coreclr/jit/lower.cpp +++ b/src/runtime/src/coreclr/jit/lower.cpp @@ -2461,7 +2461,7 @@ bool Lowering::LowerCallMemmove(GenTreeCall* call, GenTree** next) if (lengthArg->IsIntegralConst()) { ssize_t cnsSize = lengthArg->AsIntCon()->IconValue(); - JITDUMP("Size=%ld.. ", (LONG)cnsSize); + JITDUMP("Size=%zd.. ", cnsSize); // TODO-CQ: drop the whole thing in case of 0 if ((cnsSize > 0) && (cnsSize <= (ssize_t)m_compiler->getUnrollThreshold(Compiler::UnrollKind::Memmove))) { @@ -2551,7 +2551,7 @@ bool Lowering::LowerCallMemcmp(GenTreeCall* call, GenTree** next) if (lengthArg->IsIntegralConst()) { ssize_t cnsSize = lengthArg->AsIntCon()->IconValue(); - JITDUMP("Size=%ld.. ", (LONG)cnsSize); + JITDUMP("Size=%zd.. ", cnsSize); // The case of 0 has been handled earlier with VN if (cnsSize > 0) { @@ -7830,12 +7830,12 @@ bool Lowering::TryCreateAddrMode(GenTree* addr, bool isContainable, GenTree* par DISPNODE(base); if (index != nullptr) { - JITDUMP(" + Index * %u + %d\n ", scale, offset); + JITDUMP(" + Index * %u + %zd\n ", scale, offset); DISPNODE(index); } else { - JITDUMP(" + %d\n", offset); + JITDUMP(" + %zd\n", offset); } // Save the (potentially) unused operands before changing the address to LEA. @@ -11579,7 +11579,7 @@ void Lowering::LowerStoreCoalescing(GenTree* node) // Later stores must overwrite any overlapping bytes from earlier stores. uint64_t currBitsMask = (currMask << currShift) & newMask; uint64_t val = (prevBits & ~currBitsMask) | currBits; - JITDUMP("Coalesced two stores into a single store with value %lld\n", (int64_t)val); + JITDUMP("Coalesced two stores into a single store with value %lld\n", (long long)(int64_t)val); assert(currData.value->OperIs(GT_CNS_INT)); auto* intCon = currData.value->AsIntCon(); diff --git a/src/runtime/src/coreclr/jit/lsra.cpp b/src/runtime/src/coreclr/jit/lsra.cpp index b9fcf5c6e459..34d7c3d0eda2 100644 --- a/src/runtime/src/coreclr/jit/lsra.cpp +++ b/src/runtime/src/coreclr/jit/lsra.cpp @@ -10867,7 +10867,7 @@ void LinearScan::TupleStyleDump(LsraTupleDumpMode mode) assert(reg == assignedReg || varDsc->lvRegister == false); if (reg != argReg) { - printf(getRegName(argReg)); + printf("%s", getRegName(argReg)); printf("=>"); } printf("%s)", getRegName(reg)); diff --git a/src/runtime/src/coreclr/jit/morph.cpp b/src/runtime/src/coreclr/jit/morph.cpp index 9597f4241508..48b3fe040ca5 100644 --- a/src/runtime/src/coreclr/jit/morph.cpp +++ b/src/runtime/src/coreclr/jit/morph.cpp @@ -13197,7 +13197,7 @@ void Compiler::fgMorphTreeDone(GenTree* tree, bool optAssertionPropDone DEBUGARG { printf("\nfgMorphTree (after %d):\n", morphNum); gtDispTree(tree); - printf(""); // in our logic this causes a flush + fflush(jitstdout()); } #endif diff --git a/src/runtime/src/coreclr/jit/objectalloc.cpp b/src/runtime/src/coreclr/jit/objectalloc.cpp index f4d212c9c3a2..6f9d08189db3 100644 --- a/src/runtime/src/coreclr/jit/objectalloc.cpp +++ b/src/runtime/src/coreclr/jit/objectalloc.cpp @@ -4163,7 +4163,7 @@ bool ObjectAllocator::CheckCanClone(CloneInfo* info) // -1 here since we won't need to clone the allocation site itself. // - JITDUMP("allocation side cloning: %u blocks\n", visited->size() - 1); + JITDUMP("allocation side cloning: %zu blocks\n", visited->size() - 1); // The allocationBlock should not dominate the defBlock. // (if it does, optimization does not require cloning, as @@ -4426,7 +4426,7 @@ bool ObjectAllocator::CheckCanClone(CloneInfo* info) } } - JITDUMP("total cloning including all enumerator uses: %u blocks\n", visited->size() - 1); + JITDUMP("total cloning including all enumerator uses: %zu blocks\n", visited->size() - 1); unsigned numberOfEHRegionsToClone = 0; // Now expand the clone block set to include any try regions that need cloning. diff --git a/src/runtime/src/coreclr/jit/optcse.cpp b/src/runtime/src/coreclr/jit/optcse.cpp index a55dc23f6187..8250d119a4ee 100644 --- a/src/runtime/src/coreclr/jit/optcse.cpp +++ b/src/runtime/src/coreclr/jit/optcse.cpp @@ -827,7 +827,7 @@ unsigned Compiler::optValnumCSE_Index(GenTree* tree, Statement* stmt) else { size_t kVal = Compiler::Decode_Shared_Const_CSE_Value(key); - printf("K_%p", dspPtr(kVal)); + printf("K_%zx", (size_t)dspPtr(kVal)); } printf(" in " FMT_BB ", [cost=%2u, size=%2u]: \n", compCurBB->bbNum, tree->GetCostEx(), tree->GetCostSz()); @@ -3421,7 +3421,7 @@ void CSE_HeuristicRL::Announce() if (m_updateParameters) { - JITDUMP("Operating in update mode with sequence %ls, rewards %ls, and alpha %f\n", JitConfig.JitReplayCSE(), + JITDUMP("Operating in update mode with sequence %s, rewards %s, and alpha %f\n", JitConfig.JitReplayCSE(), JitConfig.JitReplayCSEReward(), m_alpha); } } @@ -4320,15 +4320,16 @@ void CSE_Heuristic::SortCandidates() if (!Compiler::Is_Shared_Const_CSE(dsc->csdHashKey)) { - printf(FMT_CSE ", {$%-3x, $%-3x} useCnt=%d: [def=%3f, use=%3f, cost=%3u%s]\n :: ", dsc->csdIndex, - dsc->csdHashKey, dsc->defExcSetPromise, dsc->csdUseCount, def, use, cost, + printf(FMT_CSE ", {$%-3zx, $%-3x} useCnt=%d: [def=%3f, use=%3f, cost=%3u%s]\n :: ", + dsc->csdIndex, dsc->csdHashKey, dsc->defExcSetPromise, dsc->csdUseCount, def, use, cost, dsc->csdLiveAcrossCall ? ", call" : " "); } else { size_t kVal = Compiler::Decode_Shared_Const_CSE_Value(dsc->csdHashKey); - printf(FMT_CSE ", {K_%p} useCnt=%d: [def=%3f, use=%3f, cost=%3u%s]\n :: ", dsc->csdIndex, - dspPtr(kVal), dsc->csdUseCount, def, use, cost, dsc->csdLiveAcrossCall ? ", call" : " "); + printf(FMT_CSE ", {K_%zx} useCnt=%d: [def=%3f, use=%3f, cost=%3u%s]\n :: ", dsc->csdIndex, + (size_t)dspPtr(kVal), dsc->csdUseCount, def, use, cost, + dsc->csdLiveAcrossCall ? ", call" : " "); } m_compiler->gtDispTree(expr, nullptr, nullptr, true); @@ -4980,8 +4981,8 @@ void CSE_HeuristicCommon::PerformCSE(CSE_Candidate* successfulCandidate) { if (isSharedConst) { - printf("\nWe have shared Const CSE's and selected " FMT_VN " with a value of 0x%p as the base.\n", - dsc->csdConstDefVN, dspPtr(dsc->csdConstDefValue)); + printf("\nWe have shared Const CSE's and selected " FMT_VN " with a value of 0x%zx as the base.\n", + dsc->csdConstDefVN, (size_t)dspPtr(dsc->csdConstDefValue)); } else // !isSharedConst { @@ -5363,15 +5364,15 @@ void CSE_HeuristicCommon::ConsiderCandidates() { if (!Compiler::Is_Shared_Const_CSE(dsc->csdHashKey)) { - printf("\nConsidering " FMT_CSE " {$%-3x, $%-3x} [def=%3f, use=%3f, cost=%3u%s]\n", + printf("\nConsidering " FMT_CSE " {$%-3zx, $%-3x} [def=%3f, use=%3f, cost=%3u%s]\n", candidate.CseIndex(), dsc->csdHashKey, dsc->defExcSetPromise, candidate.DefCount(), candidate.UseCount(), candidate.Cost(), dsc->csdLiveAcrossCall ? ", call" : " "); } else { size_t kVal = Compiler::Decode_Shared_Const_CSE_Value(dsc->csdHashKey); - printf("\nConsidering " FMT_CSE " {K_%p} [def=%3f, use=%3f, cost=%3u%s]\n", candidate.CseIndex(), - dspPtr(kVal), candidate.DefCount(), candidate.UseCount(), candidate.Cost(), + printf("\nConsidering " FMT_CSE " {K_%zx} [def=%3f, use=%3f, cost=%3u%s]\n", candidate.CseIndex(), + (size_t)dspPtr(kVal), candidate.DefCount(), candidate.UseCount(), candidate.Cost(), dsc->csdLiveAcrossCall ? ", call" : " "); } printf("CSE Expression : \n"); diff --git a/src/runtime/src/coreclr/jit/optimizebools.cpp b/src/runtime/src/coreclr/jit/optimizebools.cpp index 093df893e5dc..951da0f59ce6 100644 --- a/src/runtime/src/coreclr/jit/optimizebools.cpp +++ b/src/runtime/src/coreclr/jit/optimizebools.cpp @@ -1074,11 +1074,38 @@ bool OptBoolsDsc::optOptimizeCompareChainCondBlock() // Update the flow. FlowEdge* const removedEdge = m_b1->GetTrueEdge(); FlowEdge* const retainedEdge = m_b1->GetFalseEdge(); + + // Will need to re-adjust the likelihoods of the outgoing edges of the combined b1+b2 block + const weight_t removedEdgeLikelihood = removedEdge->getLikelihood(); + const weight_t fallthroughLikelihood = retainedEdge->getLikelihood(); + BasicBlock* const b1RemovedTarget = removedEdge->getDestinationBlock(); + + // Need to repair b2's profile as b1->b2 flow will be unconditional. + // "fgCompactBlock" will end up using b2's new profile weight + // Don't decrement the removed-edge-target's weight because the same control flow still + // reaches that block. + if (m_b2->hasProfileWeight()) + { + m_b2->increaseBBProfileWeight(removedEdge->getLikelyWeight()); + } + m_compiler->fgRemoveRefPred(removedEdge); m_b1->SetKindAndTargetEdge(BBJ_ALWAYS, retainedEdge); - // Repair profile. - m_compiler->fgRepairProfileCondToUncond(m_b1, retainedEdge, removedEdge); + // The combined b1+b2 block reuses b2's edges, and their likelihoods must be prorated + // based on likelihood of b1->b2 (fallthrough) control flow. + // The edge to shared target (b1RemovedTarget) must also take into account b1->shared + // edge likelihood + FlowEdge* const b2Edges[] = {m_b2->GetTrueEdge(), m_b2->GetFalseEdge()}; + for (FlowEdge* const b2Edge : b2Edges) + { + weight_t combined = fallthroughLikelihood * b2Edge->getLikelihood(); + if (b2Edge->getDestinationBlock() == b1RemovedTarget) + { + combined += removedEdgeLikelihood; + } + b2Edge->setLikelihood(min(1.0, combined)); + } // Fixup flags. m_b2->CopyFlags(m_b1, BBF_COPY_PROPAGATE); diff --git a/src/runtime/src/coreclr/jit/optimizer.cpp b/src/runtime/src/coreclr/jit/optimizer.cpp index 25434eef7bb7..bd37f5731be4 100644 --- a/src/runtime/src/coreclr/jit/optimizer.cpp +++ b/src/runtime/src/coreclr/jit/optimizer.cpp @@ -3684,7 +3684,7 @@ void Compiler::optPerformHoistExpr(GenTree* origExpr, BasicBlock* exprBb, FlowGr printTreeID(origExpr); printf(" was declared as hoistable from loop at nesting depth %d; actually hoisted from loop at depth " "%d.\n", - tlAndN.m_num, depth); + (int)tlAndN.m_num, (int)depth); assert(false); } else @@ -5964,7 +5964,9 @@ void Compiler::optRemoveRedundantZeroInits() } } - if (!removedExplicitZeroInit && isEntire && + // For async methods we may skip an explicit init through the resumption path + // + if (!removedExplicitZeroInit && isEntire && !compIsAsync() && (!hasImplicitControlFlow || (lclDsc->lvTracked && !lclDsc->IsLiveInOutOfHandler()))) { // If compMethodRequiresPInvokeFrame() returns true, lower may later diff --git a/src/runtime/src/coreclr/jit/promotion.cpp b/src/runtime/src/coreclr/jit/promotion.cpp index 36880fe08b2c..3773071534e1 100644 --- a/src/runtime/src/coreclr/jit/promotion.cpp +++ b/src/runtime/src/coreclr/jit/promotion.cpp @@ -645,7 +645,7 @@ class LocalUses if (agg->Replacements.size() >= PHYSICAL_PROMOTION_MAX_PROMOTIONS_PER_STRUCT) { - JITDUMP(" Promoted %zu fields in V%02u; will not promote more\n", agg->Replacements.size()); + JITDUMP(" Promoted %zu fields in V%02u; will not promote more\n", agg->Replacements.size(), lclNum); break; } } diff --git a/src/runtime/src/coreclr/jit/redundantbranchopts.cpp b/src/runtime/src/coreclr/jit/redundantbranchopts.cpp index cef06b995293..2cfd29ebba7b 100644 --- a/src/runtime/src/coreclr/jit/redundantbranchopts.cpp +++ b/src/runtime/src/coreclr/jit/redundantbranchopts.cpp @@ -104,6 +104,17 @@ PhaseStatus Compiler::optRedundantBranches() OptRedundantBranchesDomTreeVisitor visitor(this); visitor.WalkTree(m_domTree); + // BBF_STALE_PREDICATE is only meaningful while this phase runs, since it is tied to + // the dominator info we started with. Clear it so a later run sees a clean slate. + // + if (visitor.madeChanges) + { + for (BasicBlock* const block : Blocks()) + { + block->RemoveFlags(BBF_STALE_PREDICATE); + } + } + #if DEBUG if (verbose && visitor.madeChanges) { @@ -896,6 +907,12 @@ bool Compiler::optRedundantDominatingBranch(BasicBlock* const block) break; } + if (domBlockProbe->HasFlag(BBF_STALE_PREDICATE)) + { + JITDUMP("failed -- dominator " FMT_BB " has a stale predicate\n", domBlockProbe->bbNum); + break; + } + currentBlock = skipSideEffectFreeBlocks(currentBlock); // Make sure this conditional dominator branches to the same @@ -1228,7 +1245,10 @@ bool Compiler::optRedundantBranch(BasicBlock* const block) // Check the current dominator // - if (domBlock->KindIs(BBJ_COND)) + // Blocks flagged BBF_STALE_PREDICATE are skipped: flow was rerouted around them, so + // their condition no longer holds on every path reaching the blocks they appear to dominate. + // + if (domBlock->KindIs(BBJ_COND) && !domBlock->HasFlag(BBF_STALE_PREDICATE)) { Statement* const domJumpStmt = domBlock->lastStmt(); GenTree* const domJumpTree = domJumpStmt->GetRootNode(); @@ -2267,7 +2287,7 @@ bool Compiler::optJumpThreadPhi(BasicBlock* block, GenTree* tree, ValueNum treeN // const unsigned lclNum = phiDef.LclNum; const unsigned ssaDefNum = phiDef.SsaDef; - JITDUMP("... JT-PHI [interestingVN] in " FMT_BB " relop %s operand VN is PhiDef for V%02u\n", block->bbNum, + JITDUMP("... JT-PHI [interestingVN] in " FMT_BB " relop %s operand VN is PhiDef for V%02u.%u\n", block->bbNum, i == 0 ? "first" : "second", lclNum, ssaDefNum); if (!foundPhiDef) { @@ -2677,6 +2697,15 @@ bool Compiler::optJumpThreadCore(JumpThreadInfo& jti) ValueNum treeNewVN = vnStore->VNWithExc(jti.m_ambiguousVN, treeExcVN); tree->SetVN(VNK_Liberal, treeNewVN); + // The preds we just redirected were classified using the old VN, so each of them + // still reaches the successor that the old predicate implies. The sharpened VN, + // however, only describes flow coming from ambBlock, and that is no longer the only + // flow reaching block's successors. Since dominator info is not updated as we thread, + // block can still look like a dominator of those successors, so flag it to keep the + // rest of this phase from inferring anything from its now path-specific predicate. + // + jti.m_block->SetFlags(BBF_STALE_PREDICATE); + JITDUMP("Updating [%06u] liberal VN from " FMT_VN " to " FMT_VN "\n", dspTreeID(tree), treeOldVN, treeNewVN); } diff --git a/src/runtime/src/coreclr/jit/scev.cpp b/src/runtime/src/coreclr/jit/scev.cpp index d2f47b713565..4f81d66a4e5a 100644 --- a/src/runtime/src/coreclr/jit/scev.cpp +++ b/src/runtime/src/coreclr/jit/scev.cpp @@ -132,7 +132,7 @@ void Scev::Dump(Compiler* comp) } else { - printf("%lld", (int64_t)cns->Value); + printf("%lld", (long long)cns->Value); } break; } diff --git a/src/runtime/src/coreclr/jit/ssabuilder.cpp b/src/runtime/src/coreclr/jit/ssabuilder.cpp index e1fa2686ed84..91b7c0f94e97 100644 --- a/src/runtime/src/coreclr/jit/ssabuilder.cpp +++ b/src/runtime/src/coreclr/jit/ssabuilder.cpp @@ -746,7 +746,7 @@ void SsaBuilder::AddMemoryDefToEHSuccessorPhis(MemoryKind memoryKind, BasicBlock } DBG_SSA_JITDUMP(" Added phi arg u:%d for %s to phi defn in handler block " FMT_BB ".\n", ssaNum, - memoryKindNames[memoryKind], memoryKind, succ->bbNum); + memoryKindNames[memoryKind], succ->bbNum); if ((memoryKind == ByrefExposed) && m_compiler->byrefStatesMatchGcHeapStates) { @@ -1340,7 +1340,7 @@ void Compiler::JitTestCheckSSA() printf(" Node: "); printTreeID(lcl); printf(", SSA name = <%d, %d> -- SSA name class %d.\n", lcl->GetLclNum(), lcl->GetSsaNum(), - tlAndN.m_num); + (int)tlAndN.m_num); } SSAName ssaNm; if (labelToSSA->Lookup(tlAndN.m_num, &ssaNm)) @@ -1359,10 +1359,10 @@ void Compiler::JitTestCheckSSA() printf("Node: "); printTreeID(lcl); printf(", SSA name = <%d, %d> was declared in SSA name class %d,\n", lcl->GetLclNum(), - lcl->GetSsaNum(), tlAndN.m_num); + lcl->GetSsaNum(), (int)tlAndN.m_num); printf( "but this SSA name <%d,%d> has already been associated with a different SSA name class: %d.\n", - ssaNm.m_lvNum, ssaNm.m_ssaNum, num2); + ssaNm.m_lvNum, ssaNm.m_ssaNum, (int)num2); unreached(); } // And the current node must be of the specified SSA family. @@ -1371,7 +1371,7 @@ void Compiler::JitTestCheckSSA() printf("Node: "); printTreeID(lcl); printf(", SSA name = <%d, %d> was declared in SSA name class %d,\n", lcl->GetLclNum(), - lcl->GetSsaNum(), tlAndN.m_num); + lcl->GetSsaNum(), (int)tlAndN.m_num); printf("but that name class was previously bound to a different SSA name: <%d,%d>.\n", ssaNm.m_lvNum, ssaNm.m_ssaNum); unreached(); @@ -1388,8 +1388,9 @@ void Compiler::JitTestCheckSSA() printf("Node: "); printTreeID(lcl); printf(", SSA name = <%d, %d> was declared in SSA name class %d,\n", lcl->GetLclNum(), - lcl->GetSsaNum(), tlAndN.m_num); - printf("but this SSA name has already been associated with a different name class: %d.\n", num); + lcl->GetSsaNum(), (int)tlAndN.m_num); + printf("but this SSA name has already been associated with a different name class: %d.\n", + (int)num); unreached(); } // Add to both mappings. diff --git a/src/runtime/src/coreclr/jit/ssarenamestate.cpp b/src/runtime/src/coreclr/jit/ssarenamestate.cpp index 257bb84d6616..b078c37ddaaf 100644 --- a/src/runtime/src/coreclr/jit/ssarenamestate.cpp +++ b/src/runtime/src/coreclr/jit/ssarenamestate.cpp @@ -151,7 +151,7 @@ void SsaRenameState::DumpStack(Stack* stack) } else { - printf("V%02u: ", stack - m_stacks); + printf("V%02td: ", stack - m_stacks); } for (StackNode* i = stack->Top(); i != nullptr; i = i->m_stackPrev) diff --git a/src/runtime/src/coreclr/jit/unwind.cpp b/src/runtime/src/coreclr/jit/unwind.cpp index 34124abe6675..4521c5cbd0c5 100644 --- a/src/runtime/src/coreclr/jit/unwind.cpp +++ b/src/runtime/src/coreclr/jit/unwind.cpp @@ -404,7 +404,7 @@ void Compiler::DumpCfiInfo(bool isHotCode, printf(" CodeOffset: 0x%02X Op: NegateRAState\n", codeOffset); break; default: - printf(" Unrecognized CFI_CODE: 0x%llX\n", *(UINT64*)pCode); + printf(" Unrecognized CFI_CODE: 0x%llX\n", (unsigned long long)*(UINT64*)pCode); break; } } diff --git a/src/runtime/src/coreclr/jit/unwindarmarch.cpp b/src/runtime/src/coreclr/jit/unwindarmarch.cpp index bec6ed64b6f6..02eb50c3755c 100644 --- a/src/runtime/src/coreclr/jit/unwindarmarch.cpp +++ b/src/runtime/src/coreclr/jit/unwindarmarch.cpp @@ -984,10 +984,10 @@ void UnwindPrologCodes::EnsureSize(int requiredSize) #ifdef DEBUG void UnwindPrologCodes::Dump(int indent) { - printf("%*sUnwindPrologCodes @0x%08p, size:%d:\n", indent, "", dspPtr(this), sizeof(*this)); - printf("%*s m_compiler: 0x%08p\n", indent, "", dspPtr(m_compiler)); - printf("%*s &upcMemLocal[0]: 0x%08p\n", indent, "", dspPtr(&upcMemLocal[0])); - printf("%*s upcMem: 0x%08p\n", indent, "", dspPtr(upcMem)); + printf("%*sUnwindPrologCodes @0x%p, size:%zu:\n", indent, "", dspPtr(this), sizeof(*this)); + printf("%*s m_compiler: 0x%p\n", indent, "", dspPtr(m_compiler)); + printf("%*s &upcMemLocal[0]: 0x%p\n", indent, "", dspPtr(&upcMemLocal[0])); + printf("%*s upcMem: 0x%p\n", indent, "", dspPtr(upcMem)); printf("%*s upcMemSize: %d\n", indent, "", upcMemSize); printf("%*s upcCodeSlot: %d\n", indent, "", upcCodeSlot); printf("%*s upcHeaderSlot: %d\n", indent, "", upcHeaderSlot); @@ -1049,10 +1049,10 @@ void UnwindEpilogCodes::EnsureSize(int requiredSize) #ifdef DEBUG void UnwindEpilogCodes::Dump(int indent) { - printf("%*sUnwindEpilogCodes @0x%08p, size:%d:\n", indent, "", dspPtr(this), sizeof(*this)); - printf("%*s m_compiler: 0x%08p\n", indent, "", dspPtr(m_compiler)); - printf("%*s &uecMemLocal[0]: 0x%08p\n", indent, "", dspPtr(&uecMemLocal[0])); - printf("%*s uecMem: 0x%08p\n", indent, "", dspPtr(uecMem)); + printf("%*sUnwindEpilogCodes @0x%p, size:%zu:\n", indent, "", dspPtr(this), sizeof(*this)); + printf("%*s m_compiler: 0x%p\n", indent, "", dspPtr(m_compiler)); + printf("%*s &uecMemLocal[0]: 0x%p\n", indent, "", dspPtr(&uecMemLocal[0])); + printf("%*s uecMem: 0x%p\n", indent, "", dspPtr(uecMem)); printf("%*s uecMemSize: %d\n", indent, "", uecMemSize); printf("%*s uecCodeSlot: %d\n", indent, "", uecCodeSlot); printf("%*s uecFinalized: %s\n", indent, "", dspBool(uecFinalized)); @@ -1124,10 +1124,10 @@ void UnwindEpilogInfo::FinalizeOffset() #ifdef DEBUG void UnwindEpilogInfo::Dump(int indent) { - printf("%*sUnwindEpilogInfo @0x%08p, size:%d:\n", indent, "", dspPtr(this), sizeof(*this)); - printf("%*s m_compiler: 0x%08p\n", indent, "", dspPtr(m_compiler)); - printf("%*s epiNext: 0x%08p\n", indent, "", dspPtr(epiNext)); - printf("%*s epiEmitLocation: 0x%08p\n", indent, "", dspPtr(epiEmitLocation)); + printf("%*sUnwindEpilogInfo @0x%p, size:%zu:\n", indent, "", dspPtr(this), sizeof(*this)); + printf("%*s m_compiler: 0x%p\n", indent, "", dspPtr(m_compiler)); + printf("%*s epiNext: 0x%p\n", indent, "", dspPtr(epiNext)); + printf("%*s epiEmitLocation: 0x%p\n", indent, "", dspPtr(epiEmitLocation)); printf("%*s epiStartOffset: 0x%x\n", indent, "", epiStartOffset); printf("%*s epiMatches: %s\n", indent, "", dspBool(epiMatches)); printf("%*s epiStartIndex: %d\n", indent, "", epiStartIndex); @@ -1713,10 +1713,10 @@ void UnwindFragmentInfo::Dump(int indent) ++count; } - printf("%*sUnwindFragmentInfo #%d, @0x%08p, size:%d:\n", indent, "", ufiNum, dspPtr(this), sizeof(*this)); - printf("%*s m_compiler: 0x%08p\n", indent, "", dspPtr(m_compiler)); - printf("%*s ufiNext: 0x%08p\n", indent, "", dspPtr(ufiNext)); - printf("%*s ufiEmitLoc: 0x%08p ", indent, "", dspPtr(ufiEmitLoc)); + printf("%*sUnwindFragmentInfo #%d, @0x%p, size:%zu:\n", indent, "", ufiNum, dspPtr(this), sizeof(*this)); + printf("%*s m_compiler: 0x%p\n", indent, "", dspPtr(m_compiler)); + printf("%*s ufiNext: 0x%p\n", indent, "", dspPtr(ufiNext)); + printf("%*s ufiEmitLoc: 0x%p ", indent, "", dspPtr(ufiEmitLoc)); if (ufiEmitLoc != nullptr) { ufiEmitLoc->Print(m_compiler->compMethodID); @@ -1724,9 +1724,9 @@ void UnwindFragmentInfo::Dump(int indent) printf("\n"); printf("%*s ufiHasPhantomProlog: %s\n", indent, "", dspBool(ufiHasPhantomProlog)); printf("%*s %d epilog%s\n", indent, "", count, (count != 1) ? "s" : ""); - printf("%*s ufiEpilogList: 0x%08p\n", indent, "", dspPtr(ufiEpilogList)); - printf("%*s ufiEpilogLast: 0x%08p\n", indent, "", dspPtr(ufiEpilogLast)); - printf("%*s ufiCurCodes: 0x%08p\n", indent, "", dspPtr(ufiCurCodes)); + printf("%*s ufiEpilogList: 0x%p\n", indent, "", dspPtr(ufiEpilogList)); + printf("%*s ufiEpilogLast: 0x%p\n", indent, "", dspPtr(ufiEpilogLast)); + printf("%*s ufiCurCodes: 0x%p\n", indent, "", dspPtr(ufiCurCodes)); printf("%*s ufiSize: %u\n", indent, "", ufiSize); printf("%*s ufiSetEBit: %s\n", indent, "", dspBool(ufiSetEBit)); printf("%*s ufiNeedExtendedCodeWordsEpilogCount: %s\n", indent, "", dspBool(ufiNeedExtendedCodeWordsEpilogCount)); @@ -2074,11 +2074,11 @@ void UnwindInfo::Dump(bool isHotCode, int indent) ++count; } - printf("%*sUnwindInfo %s@0x%08p, size:%d:\n", indent, "", isHotCode ? "" : "COLD ", dspPtr(this), sizeof(*this)); - printf("%*s m_compiler: 0x%08p\n", indent, "", dspPtr(m_compiler)); + printf("%*sUnwindInfo %s@0x%p, size:%zu:\n", indent, "", isHotCode ? "" : "COLD ", dspPtr(this), sizeof(*this)); + printf("%*s m_compiler: 0x%p\n", indent, "", dspPtr(m_compiler)); printf("%*s %d fragment%s\n", indent, "", count, (count != 1) ? "s" : ""); - printf("%*s uwiFragmentLast: 0x%08p\n", indent, "", dspPtr(uwiFragmentLast)); - printf("%*s uwiEndLoc: 0x%08p\n", indent, "", dspPtr(uwiEndLoc)); + printf("%*s uwiFragmentLast: 0x%p\n", indent, "", dspPtr(uwiFragmentLast)); + printf("%*s uwiEndLoc: 0x%p\n", indent, "", dspPtr(uwiEndLoc)); printf("%*s uwiInitialized: 0x%08x\n", indent, "", uwiInitialized); for (pFrag = &uwiFragmentFirst; pFrag != NULL; pFrag = pFrag->ufiNext) @@ -2524,7 +2524,7 @@ void DumpUnwindInfo(Compiler* comp, opsize = (b1 == 0xF7) ? 16 : 32; - printf(" %02X %02X %02X add sp, sp, #%-8u", b1, b2, b3, x * 4, opsize); + printf(" %02X %02X %02X add sp, sp, #%-8u", b1, b2, b3, x * 4); DumpOpsize(opCol - 37, opsize); } else if (b1 == 0xF8 || b1 == 0xFA) @@ -2542,7 +2542,7 @@ void DumpUnwindInfo(Compiler* comp, opsize = (b1 == 0xF8) ? 16 : 32; - printf(" %02X %02X %02X %02X add sp, sp, #%-8u", b1, b2, b3, b4, x * 4, opsize); + printf(" %02X %02X %02X %02X add sp, sp, #%-8u", b1, b2, b3, b4, x * 4); DumpOpsize(opCol - 37, opsize); } else if (b1 == 0xFB || b1 == 0xFC) @@ -2552,7 +2552,7 @@ void DumpUnwindInfo(Compiler* comp, opsize = (b1 == 0xFB) ? 16 : 32; - printf(" %02X nop", b1, opsize); + printf(" %02X nop", b1); DumpOpsize(opCol - 19, opsize); } else if (b1 == 0xFD || b1 == 0xFE) @@ -2562,7 +2562,7 @@ void DumpUnwindInfo(Compiler* comp, opsize = (b1 == 0xFD) ? 16 : 32; - printf(" %02X end + nop", b1, opsize); + printf(" %02X end + nop", b1); DumpOpsize(opCol - 25, opsize); } else if (b1 == 0xFF) diff --git a/src/runtime/src/coreclr/jit/unwindloongarch64.cpp b/src/runtime/src/coreclr/jit/unwindloongarch64.cpp index b39f294cb3b5..cf2af1e4c7a4 100644 --- a/src/runtime/src/coreclr/jit/unwindloongarch64.cpp +++ b/src/runtime/src/coreclr/jit/unwindloongarch64.cpp @@ -1270,10 +1270,10 @@ void UnwindPrologCodes::EnsureSize(int requiredSize) #ifdef DEBUG void UnwindPrologCodes::Dump(int indent) { - printf("%*sUnwindPrologCodes @0x%08p, size:%d:\n", indent, "", dspPtr(this), sizeof(*this)); - printf("%*s m_compiler: 0x%08p\n", indent, "", dspPtr(m_compiler)); - printf("%*s &upcMemLocal[0]: 0x%08p\n", indent, "", dspPtr(&upcMemLocal[0])); - printf("%*s upcMem: 0x%08p\n", indent, "", dspPtr(upcMem)); + printf("%*sUnwindPrologCodes @%p, size:%zu:\n", indent, "", dspPtr(this), sizeof(*this)); + printf("%*s m_compiler: %p\n", indent, "", dspPtr(m_compiler)); + printf("%*s &upcMemLocal[0]: %p\n", indent, "", dspPtr(&upcMemLocal[0])); + printf("%*s upcMem: %p\n", indent, "", dspPtr(upcMem)); printf("%*s upcMemSize: %d\n", indent, "", upcMemSize); printf("%*s upcCodeSlot: %d\n", indent, "", upcCodeSlot); printf("%*s upcHeaderSlot: %d\n", indent, "", upcHeaderSlot); @@ -1335,10 +1335,10 @@ void UnwindEpilogCodes::EnsureSize(int requiredSize) #ifdef DEBUG void UnwindEpilogCodes::Dump(int indent) { - printf("%*sUnwindEpilogCodes @0x%08p, size:%d:\n", indent, "", dspPtr(this), sizeof(*this)); - printf("%*s m_compiler: 0x%08p\n", indent, "", dspPtr(m_compiler)); - printf("%*s &uecMemLocal[0]: 0x%08p\n", indent, "", dspPtr(&uecMemLocal[0])); - printf("%*s uecMem: 0x%08p\n", indent, "", dspPtr(uecMem)); + printf("%*sUnwindEpilogCodes @%p, size:%zu:\n", indent, "", dspPtr(this), sizeof(*this)); + printf("%*s m_compiler: %p\n", indent, "", dspPtr(m_compiler)); + printf("%*s &uecMemLocal[0]: %p\n", indent, "", dspPtr(&uecMemLocal[0])); + printf("%*s uecMem: %p\n", indent, "", dspPtr(uecMem)); printf("%*s uecMemSize: %d\n", indent, "", uecMemSize); printf("%*s uecCodeSlot: %d\n", indent, "", uecCodeSlot); printf("%*s uecFinalized: %s\n", indent, "", dspBool(uecFinalized)); @@ -1410,10 +1410,10 @@ void UnwindEpilogInfo::FinalizeOffset() #ifdef DEBUG void UnwindEpilogInfo::Dump(int indent) { - printf("%*sUnwindEpilogInfo @0x%08p, size:%d:\n", indent, "", dspPtr(this), sizeof(*this)); - printf("%*s m_compiler: 0x%08p\n", indent, "", dspPtr(m_compiler)); - printf("%*s epiNext: 0x%08p\n", indent, "", dspPtr(epiNext)); - printf("%*s epiEmitLocation: 0x%08p\n", indent, "", dspPtr(epiEmitLocation)); + printf("%*sUnwindEpilogInfo @%p, size:%zu:\n", indent, "", dspPtr(this), sizeof(*this)); + printf("%*s m_compiler: %p\n", indent, "", dspPtr(m_compiler)); + printf("%*s epiNext: %p\n", indent, "", dspPtr(epiNext)); + printf("%*s epiEmitLocation: %p\n", indent, "", dspPtr(epiEmitLocation)); printf("%*s epiStartOffset: 0x%x\n", indent, "", epiStartOffset); printf("%*s epiMatches: %s\n", indent, "", dspBool(epiMatches)); printf("%*s epiStartIndex: %d\n", indent, "", epiStartIndex); @@ -1965,15 +1965,15 @@ void UnwindFragmentInfo::Dump(int indent) ++count; } - printf("%*sUnwindFragmentInfo #%d, @0x%08p, size:%d:\n", indent, "", ufiNum, dspPtr(this), sizeof(*this)); - printf("%*s m_compiler: 0x%08p\n", indent, "", dspPtr(m_compiler)); - printf("%*s ufiNext: 0x%08p\n", indent, "", dspPtr(ufiNext)); - printf("%*s ufiEmitLoc: 0x%08p\n", indent, "", dspPtr(ufiEmitLoc)); + printf("%*sUnwindFragmentInfo #%d, @%p, size:%zu:\n", indent, "", ufiNum, dspPtr(this), sizeof(*this)); + printf("%*s m_compiler: %p\n", indent, "", dspPtr(m_compiler)); + printf("%*s ufiNext: %p\n", indent, "", dspPtr(ufiNext)); + printf("%*s ufiEmitLoc: %p\n", indent, "", dspPtr(ufiEmitLoc)); printf("%*s ufiHasPhantomProlog: %s\n", indent, "", dspBool(ufiHasPhantomProlog)); printf("%*s %d epilog%s\n", indent, "", count, (count != 1) ? "s" : ""); - printf("%*s ufiEpilogList: 0x%08p\n", indent, "", dspPtr(ufiEpilogList)); - printf("%*s ufiEpilogLast: 0x%08p\n", indent, "", dspPtr(ufiEpilogLast)); - printf("%*s ufiCurCodes: 0x%08p\n", indent, "", dspPtr(ufiCurCodes)); + printf("%*s ufiEpilogList: %p\n", indent, "", dspPtr(ufiEpilogList)); + printf("%*s ufiEpilogLast: %p\n", indent, "", dspPtr(ufiEpilogLast)); + printf("%*s ufiCurCodes: %p\n", indent, "", dspPtr(ufiCurCodes)); printf("%*s ufiSize: %u\n", indent, "", ufiSize); printf("%*s ufiSetEBit: %s\n", indent, "", dspBool(ufiSetEBit)); printf("%*s ufiNeedExtendedCodeWordsEpilogCount: %s\n", indent, "", dspBool(ufiNeedExtendedCodeWordsEpilogCount)); @@ -2277,11 +2277,11 @@ void UnwindInfo::Dump(bool isHotCode, int indent) ++count; } - printf("%*sUnwindInfo %s@0x%08p, size:%d:\n", indent, "", isHotCode ? "" : "COLD ", dspPtr(this), sizeof(*this)); - printf("%*s m_compiler: 0x%08p\n", indent, "", dspPtr(m_compiler)); + printf("%*sUnwindInfo %s@%p, size:%zu:\n", indent, "", isHotCode ? "" : "COLD ", dspPtr(this), sizeof(*this)); + printf("%*s m_compiler: %p\n", indent, "", dspPtr(m_compiler)); printf("%*s %d fragment%s\n", indent, "", count, (count != 1) ? "s" : ""); - printf("%*s uwiFragmentLast: 0x%08p\n", indent, "", dspPtr(uwiFragmentLast)); - printf("%*s uwiEndLoc: 0x%08p\n", indent, "", dspPtr(uwiEndLoc)); + printf("%*s uwiFragmentLast: %p\n", indent, "", dspPtr(uwiFragmentLast)); + printf("%*s uwiEndLoc: %p\n", indent, "", dspPtr(uwiEndLoc)); printf("%*s uwiInitialized: 0x%08x\n", indent, "", uwiInitialized); for (pFrag = &uwiFragmentFirst; pFrag != NULL; pFrag = pFrag->ufiNext) diff --git a/src/runtime/src/coreclr/jit/unwindriscv64.cpp b/src/runtime/src/coreclr/jit/unwindriscv64.cpp index 669cef02ce19..ed0696ed6c3c 100644 --- a/src/runtime/src/coreclr/jit/unwindriscv64.cpp +++ b/src/runtime/src/coreclr/jit/unwindriscv64.cpp @@ -1082,10 +1082,10 @@ void UnwindPrologCodes::EnsureSize(int requiredSize) #ifdef DEBUG void UnwindPrologCodes::Dump(int indent) { - printf("%*sUnwindPrologCodes @0x%08p, size:%d:\n", indent, "", dspPtr(this), sizeof(*this)); - printf("%*s m_compiler: 0x%08p\n", indent, "", dspPtr(m_compiler)); - printf("%*s &upcMemLocal[0]: 0x%08p\n", indent, "", dspPtr(&upcMemLocal[0])); - printf("%*s upcMem: 0x%08p\n", indent, "", dspPtr(upcMem)); + printf("%*sUnwindPrologCodes @%p, size:%zu:\n", indent, "", dspPtr(this), sizeof(*this)); + printf("%*s m_compiler: %p\n", indent, "", dspPtr(m_compiler)); + printf("%*s &upcMemLocal[0]: %p\n", indent, "", dspPtr(&upcMemLocal[0])); + printf("%*s upcMem: %p\n", indent, "", dspPtr(upcMem)); printf("%*s upcMemSize: %d\n", indent, "", upcMemSize); printf("%*s upcCodeSlot: %d\n", indent, "", upcCodeSlot); printf("%*s upcHeaderSlot: %d\n", indent, "", upcHeaderSlot); @@ -1155,10 +1155,10 @@ void UnwindEpilogCodes::EnsureSize(int requiredSize) #ifdef DEBUG void UnwindEpilogCodes::Dump(int indent) { - printf("%*sUnwindEpilogCodes @0x%08p, size:%d:\n", indent, "", dspPtr(this), sizeof(*this)); - printf("%*s m_compiler: 0x%08p\n", indent, "", dspPtr(m_compiler)); - printf("%*s &uecMemLocal[0]: 0x%08p\n", indent, "", dspPtr(&uecMemLocal[0])); - printf("%*s uecMem: 0x%08p\n", indent, "", dspPtr(uecMem)); + printf("%*sUnwindEpilogCodes @%p, size:%zu:\n", indent, "", dspPtr(this), sizeof(*this)); + printf("%*s m_compiler: %p\n", indent, "", dspPtr(m_compiler)); + printf("%*s &uecMemLocal[0]: %p\n", indent, "", dspPtr(&uecMemLocal[0])); + printf("%*s uecMem: %p\n", indent, "", dspPtr(uecMem)); printf("%*s uecMemSize: %d\n", indent, "", uecMemSize); printf("%*s uecCodeSlot: %d\n", indent, "", uecCodeSlot); printf("%*s uecFinalized: %s\n", indent, "", dspBool(uecFinalized)); @@ -1232,10 +1232,10 @@ void UnwindEpilogInfo::FinalizeOffset() #ifdef DEBUG void UnwindEpilogInfo::Dump(int indent) { - printf("%*sUnwindEpilogInfo @0x%08p, size:%d:\n", indent, "", dspPtr(this), sizeof(*this)); - printf("%*s m_compiler: 0x%08p\n", indent, "", dspPtr(m_compiler)); - printf("%*s epiNext: 0x%08p\n", indent, "", dspPtr(epiNext)); - printf("%*s epiEmitLocation: 0x%08p\n", indent, "", dspPtr(epiEmitLocation)); + printf("%*sUnwindEpilogInfo @%p, size:%zu:\n", indent, "", dspPtr(this), sizeof(*this)); + printf("%*s m_compiler: %p\n", indent, "", dspPtr(m_compiler)); + printf("%*s epiNext: %p\n", indent, "", dspPtr(epiNext)); + printf("%*s epiEmitLocation: %p\n", indent, "", dspPtr(epiEmitLocation)); printf("%*s epiStartOffset: 0x%x\n", indent, "", epiStartOffset); printf("%*s epiMatches: %s\n", indent, "", dspBool(epiMatches)); printf("%*s epiStartIndex: %d\n", indent, "", epiStartIndex); @@ -1787,15 +1787,15 @@ void UnwindFragmentInfo::Dump(int indent) ++count; } - printf("%*sUnwindFragmentInfo #%d, @0x%08p, size:%d:\n", indent, "", ufiNum, dspPtr(this), sizeof(*this)); - printf("%*s m_compiler: 0x%08p\n", indent, "", dspPtr(m_compiler)); - printf("%*s ufiNext: 0x%08p\n", indent, "", dspPtr(ufiNext)); - printf("%*s ufiEmitLoc: 0x%08p\n", indent, "", dspPtr(ufiEmitLoc)); + printf("%*sUnwindFragmentInfo #%d, @%p, size:%zu:\n", indent, "", ufiNum, dspPtr(this), sizeof(*this)); + printf("%*s m_compiler: %p\n", indent, "", dspPtr(m_compiler)); + printf("%*s ufiNext: %p\n", indent, "", dspPtr(ufiNext)); + printf("%*s ufiEmitLoc: %p\n", indent, "", dspPtr(ufiEmitLoc)); printf("%*s ufiHasPhantomProlog: %s\n", indent, "", dspBool(ufiHasPhantomProlog)); printf("%*s %d epilog%s\n", indent, "", count, (count != 1) ? "s" : ""); - printf("%*s ufiEpilogList: 0x%08p\n", indent, "", dspPtr(ufiEpilogList)); - printf("%*s ufiEpilogLast: 0x%08p\n", indent, "", dspPtr(ufiEpilogLast)); - printf("%*s ufiCurCodes: 0x%08p\n", indent, "", dspPtr(ufiCurCodes)); + printf("%*s ufiEpilogList: %p\n", indent, "", dspPtr(ufiEpilogList)); + printf("%*s ufiEpilogLast: %p\n", indent, "", dspPtr(ufiEpilogLast)); + printf("%*s ufiCurCodes: %p\n", indent, "", dspPtr(ufiCurCodes)); printf("%*s ufiSize: %u\n", indent, "", ufiSize); printf("%*s ufiSetEBit: %s\n", indent, "", dspBool(ufiSetEBit)); printf("%*s ufiNeedExtendedCodeWordsEpilogCount: %s\n", indent, "", dspBool(ufiNeedExtendedCodeWordsEpilogCount)); @@ -2085,11 +2085,11 @@ void UnwindInfo::Dump(bool isHotCode, int indent) ++count; } - printf("%*sUnwindInfo %s@0x%08p, size:%d:\n", indent, "", isHotCode ? "" : "COLD ", dspPtr(this), sizeof(*this)); - printf("%*s m_compiler: 0x%08p\n", indent, "", dspPtr(m_compiler)); + printf("%*sUnwindInfo %s@%p, size:%zu:\n", indent, "", isHotCode ? "" : "COLD ", dspPtr(this), sizeof(*this)); + printf("%*s m_compiler: %p\n", indent, "", dspPtr(m_compiler)); printf("%*s %d fragment%s\n", indent, "", count, (count != 1) ? "s" : ""); - printf("%*s uwiFragmentLast: 0x%08p\n", indent, "", dspPtr(uwiFragmentLast)); - printf("%*s uwiEndLoc: 0x%08p\n", indent, "", dspPtr(uwiEndLoc)); + printf("%*s uwiFragmentLast: %p\n", indent, "", dspPtr(uwiFragmentLast)); + printf("%*s uwiEndLoc: %p\n", indent, "", dspPtr(uwiEndLoc)); printf("%*s uwiInitialized: 0x%08x\n", indent, "", uwiInitialized); for (pFrag = &uwiFragmentFirst; pFrag != nullptr; pFrag = pFrag->ufiNext) diff --git a/src/runtime/src/coreclr/jit/utils.cpp b/src/runtime/src/coreclr/jit/utils.cpp index 4f8a65595903..fb09f5d6bdf9 100644 --- a/src/runtime/src/coreclr/jit/utils.cpp +++ b/src/runtime/src/coreclr/jit/utils.cpp @@ -565,7 +565,7 @@ unsigned dumpSingleInstr(const BYTE* const codeAddr, IL_OFFSET offs, const char* INT_OP: dumpILBytes(startOpcodePtr, (unsigned)((opcodePtr - startOpcodePtr) + sz), ALIGN_WIDTH); - printf(" %-12s 0x%X", opcodeNames[opcode], iOp); + printf(" %-12s 0x%llX", opcodeNames[opcode], (unsigned long long)iOp); break; case ShortInlineR: diff --git a/src/runtime/src/coreclr/jit/valuenum.cpp b/src/runtime/src/coreclr/jit/valuenum.cpp index 76685c02351a..6bc1336ee93d 100644 --- a/src/runtime/src/coreclr/jit/valuenum.cpp +++ b/src/runtime/src/coreclr/jit/valuenum.cpp @@ -15,6 +15,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #pragma hdrstop #endif +#include #include "valuenum.h" #include "ssaconfig.h" @@ -3543,6 +3544,16 @@ ValueNum ValueNumStore::VNForMapSelectWork(ValueNumKind vnk, return entry.Result; } + // If it's recursive, stop the recursion. This must be checked before the + // budget check below: an outer invocation is in the process of computing a + // value for this same selection, so we cannot assign (and cache) an + // independent value number for it here. + if (SelectIsBeingEvaluatedRecursively(map, index)) + { + *pUsedRecursiveVN = true; + return RecursiveVN; + } + // Give up if we've run out of budget. if (*pBudget == 0) { @@ -3558,13 +3569,6 @@ ValueNum ValueNumStore::VNForMapSelectWork(ValueNumKind vnk, // Reduce our budget by one (*pBudget)--; - // If it's recursive, stop the recursion. - if (SelectIsBeingEvaluatedRecursively(map, index)) - { - *pUsedRecursiveVN = true; - return RecursiveVN; - } - SmallValueNumSet recMemoryDependencies; VNFuncApp funcApp; @@ -4858,8 +4862,8 @@ ValueNum ValueNumStore::VNEvalFoldTypeCompare(var_types type, VNFunc func, Value return NoVN; } - JITDUMP("Asking runtime to compare %p (%s) and %p (%s) for equality\n", dspPtr(compileTimeHandle0), - m_compiler->eeGetClassName(CORINFO_CLASS_HANDLE(compileTimeHandle0)), dspPtr(compileTimeHandle1), + JITDUMP("Asking runtime to compare %p (%s) and %p (%s) for equality\n", (void*)dspPtr(compileTimeHandle0), + m_compiler->eeGetClassName(CORINFO_CLASS_HANDLE(compileTimeHandle0)), (void*)dspPtr(compileTimeHandle1), m_compiler->eeGetClassName(CORINFO_CLASS_HANDLE(compileTimeHandle1))); ValueNum result = NoVN; @@ -6703,7 +6707,7 @@ void Compiler::fgValueNumberLocalStore(GenTree* storeNode, } else if (defSize.IsUnknown()) { - JITDUMP("Tree [%06u] performs store to variable-sized local\n", dspTreeID(storeNode), defLclNum); + JITDUMP("Tree [%06u] performs store to variable-sized local\n", dspTreeID(storeNode)); // We don't know the bounds of this store at compile time, so it's given a unique number. newLclValue = vnStore->VNPairForExpr(compCurBB, defVarDsc->TypeGet()); } @@ -10985,7 +10989,7 @@ void ValueNumStore::vnDump(Compiler* comp, ValueNum vn, bool isPtr) { ssize_t val = ConstantValue(vn); const GenTreeFlags handleFlags = GetHandleFlags(vn); - printf("Hnd const: 0x%p %s", dspPtr(val), GenTree::gtGetHandleKindString(handleFlags)); + printf("Hnd const: 0x%zx %s", (size_t)dspPtr(val), GenTree::gtGetHandleKindString(handleFlags)); if (!comp->IsAot()) { switch (handleFlags & GTF_ICON_HDL_MASK) @@ -11019,14 +11023,14 @@ void ValueNumStore::vnDump(Compiler* comp, ValueNum vn, bool isPtr) int val = ConstantValue(vn); if (isPtr) { - printf("PtrCns[%p]", dspPtr(val)); + printf("PtrCns[0x%x]", dspPtr(val)); } else { printf("IntCns"); if ((val > -1000) && (val < 1000)) { - printf(" %ld", val); + printf(" %d", val); } else { @@ -11041,22 +11045,22 @@ void ValueNumStore::vnDump(Compiler* comp, ValueNum vn, bool isPtr) INT64 val = ConstantValue(vn); if (isPtr) { - printf("LngPtrCns: 0x%p", dspPtr(val)); + printf("LngPtrCns: 0x%" PRIx64, (int64_t)dspPtr(val)); } else { printf("LngCns"); if ((val > -1000) && (val < 1000)) { - printf(" %ld", val); + printf(" %lld", (long long)val); } else if ((val & 0xFFFFFFFF00000000LL) == 0) { - printf(" 0x%X", val); + printf(" 0x%llX", (unsigned long long)val); } else { - printf(" 0x%llx", val); + printf(" 0x%llx", (unsigned long long)val); } } } @@ -11111,8 +11115,9 @@ void ValueNumStore::vnDump(Compiler* comp, ValueNum vn, bool isPtr) case TYP_SIMD32: { simd32_t cnsVal = GetConstantSimd32(vn); - printf("Simd32Cns[0x%016llx, 0x%016llx, 0x%016llx, 0x%016llx]", cnsVal.u64[0], cnsVal.u64[1], - cnsVal.u64[2], cnsVal.u64[3]); + printf("Simd32Cns[0x%016llx, 0x%016llx, 0x%016llx, 0x%016llx]", (unsigned long long)cnsVal.u64[0], + (unsigned long long)cnsVal.u64[1], (unsigned long long)cnsVal.u64[2], + (unsigned long long)cnsVal.u64[3]); break; } @@ -11121,8 +11126,10 @@ void ValueNumStore::vnDump(Compiler* comp, ValueNum vn, bool isPtr) simd64_t cnsVal = GetConstantSimd64(vn); printf( "Simd64Cns[0x%016llx, 0x%016llx, 0x%016llx, 0x%016llx, 0x%016llx, 0x%016llx, 0x%016llx, 0x%016llx]", - cnsVal.u64[0], cnsVal.u64[1], cnsVal.u64[2], cnsVal.u64[3], cnsVal.u64[4], cnsVal.u64[5], - cnsVal.u64[6], cnsVal.u64[7]); + (unsigned long long)cnsVal.u64[0], (unsigned long long)cnsVal.u64[1], + (unsigned long long)cnsVal.u64[2], (unsigned long long)cnsVal.u64[3], + (unsigned long long)cnsVal.u64[4], (unsigned long long)cnsVal.u64[5], + (unsigned long long)cnsVal.u64[6], (unsigned long long)cnsVal.u64[7]); break; } @@ -11135,23 +11142,24 @@ void ValueNumStore::vnDump(Compiler* comp, ValueNum vn, bool isPtr) switch (cnsVal.gtSimdScalableKind) { case SimdScalableRepeated: - printf("0x%016llx, 0x%016llx, 0x%016llx...]", cnsVal.gtSimdScalableIndex, - cnsVal.gtSimdScalableIndex, cnsVal.gtSimdScalableIndex); + printf("0x%016llx, 0x%016llx, 0x%016llx...]", (unsigned long long)cnsVal.gtSimdScalableIndex, + (unsigned long long)cnsVal.gtSimdScalableIndex, + (unsigned long long)cnsVal.gtSimdScalableIndex); break; case SimdScalableSequence: { uint64_t index = cnsVal.gtSimdScalableIndex; - printf("0x%016llx, ", index); + printf("0x%016llx, ", (unsigned long long)index); index += cnsVal.gtSimdScalableStep; - printf("0x%016llx, ", index); + printf("0x%016llx, ", (unsigned long long)index); index += cnsVal.gtSimdScalableStep; - printf("0x%016llx...]", index); + printf("0x%016llx...]", (unsigned long long)index); break; } case SimdScalableScalar: - printf("0x%016llx, 0x0, 0x0...]", cnsVal.gtSimdScalableIndex); + printf("0x%016llx, 0x0, 0x0...]", (unsigned long long)cnsVal.gtSimdScalableIndex); break; default: @@ -16192,7 +16200,7 @@ void Compiler::JitTestCheckVN() { printf(" Node "); Compiler::printTreeID(node); - printf(" -- VN class %d.\n", tlAndN.m_num); + printf(" -- VN class %d.\n", (int)tlAndN.m_num); } if (tlAndN.m_tl == TL_VNNorm) @@ -16216,10 +16224,10 @@ void Compiler::JitTestCheckVN() { printf("Node: "); Compiler::printTreeID(node); - printf(", with value number " FMT_VN ", was declared in VN class %d,\n", nodeVN, tlAndN.m_num); + printf(", with value number " FMT_VN ", was declared in VN class %d,\n", nodeVN, (int)tlAndN.m_num); printf("but this value number " FMT_VN " has already been associated with a different SSA name class: %d.\n", - vn, num2); + vn, (int)num2); assert(false); } // And the current node must be of the specified SSA family. @@ -16227,7 +16235,7 @@ void Compiler::JitTestCheckVN() { printf("Node: "); Compiler::printTreeID(node); - printf(", " FMT_VN " was declared in SSA name class %d,\n", nodeVN, tlAndN.m_num); + printf(", " FMT_VN " was declared in SSA name class %d,\n", nodeVN, (int)tlAndN.m_num); printf("but that name class was previously bound to a different value number: " FMT_VN ".\n", vn); assert(false); } @@ -16240,10 +16248,10 @@ void Compiler::JitTestCheckVN() { printf("Node: "); Compiler::printTreeID(node); - printf(", " FMT_VN " was declared in value number class %d,\n", nodeVN, tlAndN.m_num); + printf(", " FMT_VN " was declared in value number class %d,\n", nodeVN, (int)tlAndN.m_num); printf( "but this value number has already been associated with a different value number class: %d.\n", - num); + (int)num); assert(false); } // Add to both mappings. @@ -16278,7 +16286,7 @@ void Compiler::vnPrint(ValueNum vn, unsigned level) { if (ValueNumStore::isReservedVN(vn)) { - printf(ValueNumStore::reservedName(vn)); + printf("%s", ValueNumStore::reservedName(vn)); } else { diff --git a/src/runtime/src/coreclr/jit/wellknownargs.h b/src/runtime/src/coreclr/jit/wellknownargs.h index 23976312e5e8..24a0f780020c 100644 --- a/src/runtime/src/coreclr/jit/wellknownargs.h +++ b/src/runtime/src/coreclr/jit/wellknownargs.h @@ -36,11 +36,26 @@ WELL_KNOWN_ARG(SwiftSelf, "swift self", true, false) WELL_KNOWN_ARG(X86TailCallSpecialArg, "tail call", false, false) WELL_KNOWN_ARG(StackArrayLocal, "&lcl arr", false, false) WELL_KNOWN_ARG(RuntimeMethodHandle, "meth hnd", false, false) + +// Custom awaiter of a call the importer rewrote into an UnsafeAwaitAwaiter* form. Stored +// into the continuation on suspension. WELL_KNOWN_ARG(AsyncAwaiter, "awaiter", false, false) + +// Contexts of the frame's caller, captured on entry. Restored onto the Thread +// object as the frame suspends, as if it had returned. When inlining there can +// be multiple sets of these, one for each inlined frame, in order from +// innermost inlinee out to the root. WELL_KNOWN_ARG(AsyncExecutionContext, "exec ctx", false, false) WELL_KNOWN_ARG(AsyncSynchronizationContext, "sync ctx", false, false) +// Value of the frame's resumed indicator. The restore above only happens on +// the first suspension in the method, implemented by checking this value. Like +// the contexts there is one for every frame of inlining. WELL_KNOWN_ARG(AsyncResumedUse, "resumed", false, false) + +// Address of that same indicator. The resumption path stores 1 through it to record that +// the frame resumed. WELL_KNOWN_ARG(AsyncResumedDef, "resumed def", false, false) + WELL_KNOWN_ARG(WasmShadowStackPointer, "wasm sp", false, false) WELL_KNOWN_ARG(WasmPortableEntryPoint, "wasm pep", false, false) diff --git a/src/runtime/src/coreclr/md/ceefilegen/blobfetcher.cpp b/src/runtime/src/coreclr/md/ceefilegen/blobfetcher.cpp index f08908147de7..d5236b44a27c 100644 --- a/src/runtime/src/coreclr/md/ceefilegen/blobfetcher.cpp +++ b/src/runtime/src/coreclr/md/ceefilegen/blobfetcher.cpp @@ -236,7 +236,7 @@ char* CBlobFetcher::MakeNewBlock(unsigned len, unsigned align) { m_nIndexMax = nNewMax; m_pIndex = pNewIndex; - STRESS_LOG2(LF_LOADER, LL_INFO10, "CBlobFetcher %08X reallocates m_pIndex %08X\n", this, m_pIndex); + STRESS_LOG2(LF_LOADER, LL_INFO10, "CBlobFetcher %p reallocates m_pIndex %p\n", this, m_pIndex); } m_nIndexUsed ++; // current pillar is full, move to next diff --git a/src/runtime/src/coreclr/md/compiler/disp.cpp b/src/runtime/src/coreclr/md/compiler/disp.cpp index 165d4910c727..bc878ff6710c 100644 --- a/src/runtime/src/coreclr/md/compiler/disp.cpp +++ b/src/runtime/src/coreclr/md/compiler/disp.cpp @@ -70,7 +70,7 @@ Disp::DefineScope( OptionValue optionForNewScope = m_OptionValue; - LOG((LF_METADATA, LL_INFO10, "Disp::DefineScope(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", rclsid, dwCreateFlags, riid, ppIUnk)); + LOG((LF_METADATA, LL_INFO10, "Disp::DefineScope(0x%08x, 0x%08x, 0x%08x, %p)\n", rclsid.Data1, dwCreateFlags, riid.Data1, ppIUnk)); if (dwCreateFlags) IfFailGo(E_INVALIDARG); @@ -105,7 +105,7 @@ Disp::DefineScope( // Add the new RegMeta to the cache. IfFailGo(pMeta->AddToCache()); - LOG((LOGMD, "{%08x} Created new emit scope\n", pMeta)); + LOG((LOGMD, "{%p} Created new emit scope\n", (void*)pMeta)); ErrExit: if (FAILED(hr)) @@ -240,7 +240,7 @@ HRESULT Disp::OpenScopeOnMemory( // Return code. IUnknown **ppIUnk) // [out] Return interface on success. { HRESULT hr; - LOG((LF_METADATA, LL_INFO10, "Disp::OpenScopeOnMemory(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", pData, cbData, dwOpenFlags, riid, ppIUnk)); + LOG((LF_METADATA, LL_INFO10, "Disp::OpenScopeOnMemory(%p, 0x%08x, 0x%08x, 0x%08x, %p)\n", (void*)pData, cbData, dwOpenFlags, riid.Data1, (void*)ppIUnk)); IMDCommon *pMDCommon = NULL; @@ -283,7 +283,7 @@ HRESULT Disp::OpenRawScopeOnMemory( // Return code. // Always initialize the RegMeta's stgdb. IfFailGo(pMeta->OpenExistingMD(0 /* szFileName */, const_cast(pData), cbData, dwOpenFlags)); - LOG((LOGMD, "{%08x} Opened new scope on memory, pData: %08x cbData: %08x\n", pMeta, pData, cbData)); + LOG((LOGMD, "{%p} Opened new scope on memory, pData: %p cbData: %08x\n", (void*)pMeta, (void*)pData, cbData)); // Return the requested interface. IfFailGo( pMeta->QueryInterface(riid, (void **) ppIUnk) ); @@ -388,7 +388,7 @@ Disp::DefinePortablePdbScope( RegMeta* pMeta = 0; OptionValue optionForNewScope = m_OptionValue; - LOG((LF_METADATA, LL_INFO10, "Disp::DefinePortablePdbScope(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", rclsid, dwCreateFlags, riid, ppIUnk)); + LOG((LF_METADATA, LL_INFO10, "Disp::DefinePortablePdbScope(0x%08x, 0x%08x, 0x%08x, %p)\n", rclsid.Data1, dwCreateFlags, riid.Data1, (void*)ppIUnk)); if (dwCreateFlags) IfFailGo(E_INVALIDARG); @@ -420,7 +420,7 @@ Disp::DefinePortablePdbScope( // Add the new RegMeta to the cache. IfFailGo(pMeta->AddToCache()); - LOG((LOGMD, "{%08x} Created new emit scope\n", pMeta)); + LOG((LOGMD, "{%p} Created new emit scope\n", (void*)pMeta)); ErrExit: if (FAILED(hr)) @@ -508,7 +508,7 @@ Disp::SetOption( { HRESULT hr = S_OK; - LOG((LF_METADATA, LL_INFO10, "Disp::SetOption(0x%08x, 0x%08x)\n", optionid, pvalue)); + LOG((LF_METADATA, LL_INFO10, "Disp::SetOption(0x%08x, %p)\n", optionid.Data1, (void*)pvalue)); if (optionid == MetaDataCheckDuplicatesFor) { @@ -677,7 +677,7 @@ HRESULT Disp::GetOption( // Return code. { HRESULT hr = S_OK; - LOG((LF_METADATA, LL_INFO10, "Disp::GetOption(0x%08x, 0x%08x)\n", optionid, pvalue)); + LOG((LF_METADATA, LL_INFO10, "Disp::GetOption(0x%08x, %p)\n", optionid.Data1, (void*)pvalue)); _ASSERTE(pvalue); if (optionid == MetaDataCheckDuplicatesFor) diff --git a/src/runtime/src/coreclr/nativeaot/Runtime/startup.cpp b/src/runtime/src/coreclr/nativeaot/Runtime/startup.cpp index ef91e894dc91..eb219b0d37ac 100644 --- a/src/runtime/src/coreclr/nativeaot/Runtime/startup.cpp +++ b/src/runtime/src/coreclr/nativeaot/Runtime/startup.cpp @@ -172,7 +172,7 @@ bool DetectCPUFeatures() { #if defined(HOST_X86) || defined(HOST_AMD64) PalPrintFatalError("\nThe current CPU is missing one or more of the following instruction sets: SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT\n"); -#elif defined(HOST_ARM64) && (defined(HOST_WINDOWS) || defined(HOST_OSX) || defined(HOST_MACCATALYST)) +#elif defined(HOST_ARM64) && (defined(HOST_OSX) || defined(HOST_MACCATALYST)) PalPrintFatalError("\nThe current CPU is missing one or more of the following instruction sets: AdvSimd, LSE\n"); #elif defined(HOST_ARM64) PalPrintFatalError("\nThe current CPU is missing one or more of the following instruction sets: AdvSimd\n"); diff --git a/src/runtime/src/coreclr/nativeaot/Runtime/unix/PalCreateDump.cpp b/src/runtime/src/coreclr/nativeaot/Runtime/unix/PalCreateDump.cpp index 3577cf8e718f..83d9df67eb67 100644 --- a/src/runtime/src/coreclr/nativeaot/Runtime/unix/PalCreateDump.cpp +++ b/src/runtime/src/coreclr/nativeaot/Runtime/unix/PalCreateDump.cpp @@ -11,7 +11,6 @@ #include #include #include -#define __STDC_FORMAT_MACROS #include #include #include diff --git a/src/runtime/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Resources/Strings.resx b/src/runtime/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Resources/Strings.resx index 4995f4ce2804..957cfd83bad7 100644 --- a/src/runtime/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Resources/Strings.resx +++ b/src/runtime/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Resources/Strings.resx @@ -120,27 +120,9 @@ '{0}' is missing native code or metadata. This can happen for code that is not compatible with trimming or AOT. Inspect and fix trimming and AOT related warnings that were generated when the app was published. For more information see https://aka.ms/nativeaot-compatibility - - Cannot bind to the target method because its signature is not compatible with that of the delegate type. - - - Array may not be empty. - - - Member not found. - - - Hashtable's capacity overflowed and went negative. Check load factor, capacity and the current size of the table. - - - Nullable object must have a value. - Non-static field requires a target. - - Constructor on type '{0}' not found. - Multidimensional arrays of rank {0} are not supported. @@ -153,9 +135,6 @@ Dynamic invocation of delegate constructors is not supported on this runtime. - - An item with the same key has already been added. - An item with the same key has already been added. Key: {0} @@ -168,30 +147,6 @@ '{0}', on '{1}' violates the constraint of type '{2}'. - - At least one object must implement IComparable. - - - The stream is currently in use by a previous operation on the stream. - - - Stream was not readable. - - - Cannot read from a closed TextReader. - - - Positive number required. - - - Buffer cannot be null. - - - Non-negative number required. - - - Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection. - Cannot set a constant field. diff --git a/src/runtime/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/System.Private.Reflection.Execution.csproj b/src/runtime/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/System.Private.Reflection.Execution.csproj index 5648a7deed20..3a70b9965a12 100644 --- a/src/runtime/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/System.Private.Reflection.Execution.csproj +++ b/src/runtime/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/System.Private.Reflection.Execution.csproj @@ -67,8 +67,5 @@ Internal\LowLevelLinq\LowLevelEnumerable.ToArray.cs - - System\Collections\HashHelpers.cs - diff --git a/src/runtime/src/coreclr/pal/src/exception/remote-unwind.cpp b/src/runtime/src/coreclr/pal/src/exception/remote-unwind.cpp index ff0df886735d..c85930355ff9 100644 --- a/src/runtime/src/coreclr/pal/src/exception/remote-unwind.cpp +++ b/src/runtime/src/coreclr/pal/src/exception/remote-unwind.cpp @@ -42,7 +42,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "pal/debug.h" #include "pal_endian.h" #include "pal.h" -#define __STDC_FORMAT_MACROS #include #include @@ -68,7 +67,6 @@ SET_DEFAULT_DEBUG_CHANNEL(EXCEPT); #else // HOST_UNIX #include -#define __STDC_FORMAT_MACROS #include #include #include "debugmacros.h" diff --git a/src/runtime/src/coreclr/pal/src/exception/seh-unwind.cpp b/src/runtime/src/coreclr/pal/src/exception/seh-unwind.cpp index dab13c4fd46b..06f31cd95307 100644 --- a/src/runtime/src/coreclr/pal/src/exception/seh-unwind.cpp +++ b/src/runtime/src/coreclr/pal/src/exception/seh-unwind.cpp @@ -22,7 +22,6 @@ Module Name: #else // HOST_UNIX #include -#define __STDC_FORMAT_MACROS #include #include #include "debugmacros.h" diff --git a/src/runtime/src/coreclr/pal/src/misc/sysinfo.cpp b/src/runtime/src/coreclr/pal/src/misc/sysinfo.cpp index 05659f2e6273..dda375d6874f 100644 --- a/src/runtime/src/coreclr/pal/src/misc/sysinfo.cpp +++ b/src/runtime/src/coreclr/pal/src/misc/sysinfo.cpp @@ -27,7 +27,6 @@ Revision History: #include #include #include -#define __STDC_FORMAT_MACROS #include #include diff --git a/src/runtime/src/coreclr/tools/Common/Compiler/CompilerTypeSystemContext.Wasm.cs b/src/runtime/src/coreclr/tools/Common/Compiler/CompilerTypeSystemContext.Wasm.cs index 1117c09066d9..afa372997379 100644 --- a/src/runtime/src/coreclr/tools/Common/Compiler/CompilerTypeSystemContext.Wasm.cs +++ b/src/runtime/src/coreclr/tools/Common/Compiler/CompilerTypeSystemContext.Wasm.cs @@ -14,6 +14,7 @@ public partial class CompilerTypeSystemContext { private readonly object _structCacheLock = new object(); private readonly Dictionary _structsBySize = new Dictionary(); + private readonly Dictionary _alignedStructsBySize = new Dictionary(); private readonly Dictionary _returnStructsBySize = new Dictionary(); private volatile TypeDesc _cachedEmptyStruct; private volatile TypeDesc _wasmV128Type; @@ -90,10 +91,12 @@ public void CacheEmptyStruct(TypeDesc type) } /// - /// Caches a struct type by its element size, so RaiseSignature can retrieve a real - /// type of that size. Only the first struct encountered for a given size is retained. + /// Caches a struct type by the layout represented in its signature encoding, so + /// RaiseSignature can retrieve a real type with the same argument layout. Structs whose + /// effective argument alignment exceeds 8 use a separate cache because their + /// transition-block slots are 16-byte aligned. /// - public void CacheStructBySize(TypeDesc type) + public void CacheStruct(TypeDesc type, bool requiresAlignedSlot) { int size = type.GetElementSize().AsInt; if (size <= 0) @@ -101,7 +104,14 @@ public void CacheStructBySize(TypeDesc type) lock (_structCacheLock) { - _structsBySize.TryAdd(size, type); + if (requiresAlignedSlot) + { + _alignedStructsBySize.TryAdd(size, type); + } + else + { + _structsBySize.TryAdd(size, type); + } } } @@ -150,5 +160,16 @@ public TypeDesc GetCachedStructOfSize(int size) return null; } + + public TypeDesc GetCachedAlignedStructOfSize(int size) + { + lock (_structCacheLock) + { + if (_alignedStructsBySize.TryGetValue(size, out TypeDesc result)) + return result; + } + + return null; + } } } diff --git a/src/runtime/src/coreclr/tools/Common/InstructionSetHelpers.cs b/src/runtime/src/coreclr/tools/Common/InstructionSetHelpers.cs index c9dee328f1dd..f25320e99f78 100644 --- a/src/runtime/src/coreclr/tools/Common/InstructionSetHelpers.cs +++ b/src/runtime/src/coreclr/tools/Common/InstructionSetHelpers.cs @@ -87,12 +87,6 @@ public static InstructionSetSupport ConfigureInstructionSetSupport(string instru { // We require armv8-a everywhere instructionSetSupportBuilder.AddSupportedInstructionSet("armv8-a"); - - if (targetOS == TargetOS.Windows) - { - // However, Windows also requires LSE - instructionSetSupportBuilder.AddSupportedInstructionSet("lse"); - } } } else if (targetArchitecture == TargetArchitecture.Wasm32) diff --git a/src/runtime/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/runtime/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 801a6b0f4a92..bc751725af31 100644 --- a/src/runtime/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/runtime/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -1350,6 +1350,16 @@ private CorInfoInline canInline(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHO MethodDesc callerMethod = HandleToObject(callerHnd); MethodDesc calleeMethod = HandleToObject(calleeHnd); +#if !READYTORUN + // Some thunks, like DIM instantiation thunks, are compiled as async but are not + // async in the type system. They do not support the suspension points that + // inlining an async callee would introduce. + if (calleeMethod.IsAsyncCall() && !MethodBeingCompiled.IsAsyncCall()) + { + return CorInfoInline.INLINE_FAIL; + } +#endif + EcmaModule rootModule = (MethodBeingCompiled.OwningType as MetadataType)?.Module as EcmaModule; EcmaModule calleeModule = (calleeMethod.OwningType as MetadataType)?.Module as EcmaModule; @@ -2439,12 +2449,12 @@ public static int GetClassAlignmentRequirementStatic(DefType type) if (type is MetadataType metadataType && !metadataType.IsAutoLayout) { - if (metadataType.IsSequentialLayout || MarshalUtils.IsBlittableType(metadataType)) + if (metadataType.IsSequentialLayout || + MarshalUtils.IsBlittableType(metadataType)) { alignment = metadataType.InstanceFieldAlignment.AsInt; } } - if (type.Context.Target.SupportsAlign8 && alignment < 8 && type.RequiresAlign8()) { @@ -3650,6 +3660,10 @@ private void getAsyncInfo(ref CORINFO_ASYNC_INFO pAsyncInfoOut) pAsyncInfoOut.captureContextsMethHnd = ObjectToHandle(asyncHelpers.GetKnownMethod("CaptureContexts"u8, null)); pAsyncInfoOut.restoreContextsMethHnd = ObjectToHandle(asyncHelpers.GetKnownMethod("RestoreContexts"u8, null)); pAsyncInfoOut.restoreContextsOnSuspensionMethHnd = ObjectToHandle(asyncHelpers.GetKnownMethod("RestoreContextsOnSuspension"u8, null)); + pAsyncInfoOut.restoreInlinedFrameContextsMethHnd = ObjectToHandle(asyncHelpers.GetKnownMethod("RestoreInlinedFrameContexts"u8, null)); + pAsyncInfoOut.captureInlinedFrameTransitionWithContinuationContextMethHnd = ObjectToHandle(asyncHelpers.GetKnownMethod("CaptureInlinedFrameTransitionWithContinuationContext"u8, null)); + pAsyncInfoOut.captureInlinedFrameTransitionNoContinuationContextMethHnd = ObjectToHandle(asyncHelpers.GetKnownMethod("CaptureInlinedFrameTransitionNoContinuationContext"u8, null)); + pAsyncInfoOut.captureInlinedFrameTransitionContinueOnThreadPoolMethHnd = ObjectToHandle(asyncHelpers.GetKnownMethod("CaptureInlinedFrameTransitionContinueOnThreadPool"u8, null)); pAsyncInfoOut.finishSuspensionNoContinuationContextMethHnd = ObjectToHandle(asyncHelpers.GetKnownMethod("FinishSuspensionNoContinuationContext"u8, null)); pAsyncInfoOut.finishSuspensionWithContinuationContextMethHnd = ObjectToHandle(asyncHelpers.GetKnownMethod("FinishSuspensionWithContinuationContext"u8, null)); } diff --git a/src/runtime/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/runtime/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs index c11a4cae141e..3ffc55a2b2d7 100644 --- a/src/runtime/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/runtime/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs @@ -972,6 +972,10 @@ public unsafe struct CORINFO_ASYNC_INFO public CORINFO_METHOD_STRUCT_* captureContextsMethHnd; public CORINFO_METHOD_STRUCT_* restoreContextsMethHnd; public CORINFO_METHOD_STRUCT_* restoreContextsOnSuspensionMethHnd; + public CORINFO_METHOD_STRUCT_* restoreInlinedFrameContextsMethHnd; + public CORINFO_METHOD_STRUCT_* captureInlinedFrameTransitionWithContinuationContextMethHnd; + public CORINFO_METHOD_STRUCT_* captureInlinedFrameTransitionNoContinuationContextMethHnd; + public CORINFO_METHOD_STRUCT_* captureInlinedFrameTransitionContinueOnThreadPoolMethHnd; public CORINFO_METHOD_STRUCT_* finishSuspensionNoContinuationContextMethHnd; public CORINFO_METHOD_STRUCT_* finishSuspensionWithContinuationContextMethHnd; } diff --git a/src/runtime/src/coreclr/tools/Common/JitInterface/WasmLowering.cs b/src/runtime/src/coreclr/tools/Common/JitInterface/WasmLowering.cs index 40fe08a2265e..ad6680cafcf5 100644 --- a/src/runtime/src/coreclr/tools/Common/JitInterface/WasmLowering.cs +++ b/src/runtime/src/coreclr/tools/Common/JitInterface/WasmLowering.cs @@ -411,13 +411,14 @@ public static WasmValueType LowerType(TypeDesc type) private static int ParseStructSize(string sig, ref int pos) { - Debug.Assert(sig[pos] == 'S'); - pos++; // skip 'S' + Debug.Assert(sig[pos] is 'S' or 'A'); + pos++; // skip 'S'/'A' int start = pos; while (pos < sig.Length && char.IsDigit(sig[pos])) { pos++; } + return int.Parse(sig.AsSpan(start, pos - start)); } @@ -496,11 +497,16 @@ public static MethodSignature RaiseSignature(WasmSignature wasmSignature, TypeSy parameters.Add(((CompilerTypeSystemContext)context).GetWasmElevatedType(c, elevation)); pos += 2; } - else if (c == 'S') + else if (c is 'S' or 'A') { + bool isAlignedStruct = c == 'A'; int structSize = ParseStructSize(sig, ref pos); - TypeDesc cachedStruct = ((CompilerTypeSystemContext)context).GetCachedStructOfSize(structSize); - Debug.Assert(cachedStruct is not null, $"No cached struct of size {structSize} for parameter in signature '{sig}'"); + CompilerTypeSystemContext compilerContext = (CompilerTypeSystemContext)context; + TypeDesc cachedStruct = isAlignedStruct + ? compilerContext.GetCachedAlignedStructOfSize(structSize) + : compilerContext.GetCachedStructOfSize(structSize); + Debug.Assert(cachedStruct is not null, + $"No cached {(isAlignedStruct ? "aligned " : "")}struct of size {structSize} for parameter in signature '{sig}'"); parameters.Add(cachedStruct); } else @@ -622,7 +628,8 @@ public static WasmSignature GetSignature(MethodSignature signature, LoweringFlag returnContext.CacheReturnStructBySize(returnType); if (!TryGetMultiSegmentLayout(returnType, out _, out _)) { - returnContext.CacheStructBySize(returnType); + int returnAlignment = CorInfoImpl.GetClassAlignmentRequirementStatic((DefType)returnType); + returnContext.CacheStruct(returnType, returnAlignment > 8); } } } @@ -719,9 +726,12 @@ public static WasmSignature GetSignature(MethodSignature signature, LoweringFlag } else { - sigBuilder.Append('S'); + Debug.Assert(paramType is DefType); + int paramAlignment = CorInfoImpl.GetClassAlignmentRequirementStatic((DefType)paramType); + bool requiresAlignedSlot = paramAlignment > 8; + sigBuilder.Append(requiresAlignedSlot ? 'A' : 'S'); sigBuilder.Append(paramSize); - ((CompilerTypeSystemContext)paramType.Context).CacheStructBySize(paramType); + ((CompilerTypeSystemContext)paramType.Context).CacheStruct(paramType, requiresAlignedSlot); result.Add(pointerType); } } diff --git a/src/runtime/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/GenericArgumentDataFlow.cs b/src/runtime/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/GenericArgumentDataFlow.cs index a20e950abc22..762f264deb5f 100644 --- a/src/runtime/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/GenericArgumentDataFlow.cs +++ b/src/runtime/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/GenericArgumentDataFlow.cs @@ -20,9 +20,24 @@ namespace ILCompiler.Dataflow { internal static class GenericArgumentDataFlow { - public static void ProcessGenericArgumentDataFlow(ref DependencyList dependencies, NodeFactory factory, in MessageOrigin origin, TypeDesc type, TypeDesc contextType) + public static void ProcessGenericArgumentDataFlow( + ref DependencyList dependencies, + NodeFactory factory, + in MessageOrigin origin, + TypeDesc type, + TypeDesc contextType, + bool suppressTrimAnalysisWarnings = false, + bool suppressAotAnalysisWarnings = false) { - ProcessGenericArgumentDataFlow(ref dependencies, factory, origin, type, contextType.Instantiation, Instantiation.Empty); + ProcessGenericArgumentDataFlow( + ref dependencies, + factory, + origin, + type, + contextType.Instantiation, + Instantiation.Empty, + suppressTrimAnalysisWarnings, + suppressAotAnalysisWarnings); } public static void ProcessGenericArgumentDataFlow(ref DependencyList dependencies, NodeFactory factory, in MessageOrigin origin, TypeDesc type, MethodDesc contextMethod) @@ -30,7 +45,15 @@ public static void ProcessGenericArgumentDataFlow(ref DependencyList dependencie ProcessGenericArgumentDataFlow(ref dependencies, factory, origin, type, contextMethod.OwningType.Instantiation, contextMethod.Instantiation); } - public static void ProcessGenericArgumentDataFlow(ref DependencyList dependencies, NodeFactory factory, in MessageOrigin origin, TypeDesc type, Instantiation typeContext, Instantiation methodContext) + public static void ProcessGenericArgumentDataFlow( + ref DependencyList dependencies, + NodeFactory factory, + in MessageOrigin origin, + TypeDesc type, + Instantiation typeContext, + Instantiation methodContext, + bool suppressTrimAnalysisWarnings = false, + bool suppressAotAnalysisWarnings = false) { if (!type.HasInstantiation) return; @@ -48,9 +71,18 @@ public static void ProcessGenericArgumentDataFlow(ref DependencyList dependencie var diagnosticContext = new DiagnosticContext( origin, - !logger.ShouldSuppressAnalysisWarningsForRequires(origin.MemberDefinition, DiagnosticUtilities.RequiresUnreferencedCodeAttribute), - logger); - var reflectionMarker = new ReflectionMarker(logger, factory, flowAnnotations, typeHierarchyDataFlowOrigin: null, enabled: true); + suppressTrimmerDiagnostics: suppressTrimAnalysisWarnings || logger.ShouldSuppressAnalysisWarningsForRequires(origin.MemberDefinition, DiagnosticUtilities.RequiresUnreferencedCodeAttribute), + suppressAotDiagnostics: suppressAotAnalysisWarnings || logger.ShouldSuppressAnalysisWarningsForRequires(origin.MemberDefinition, DiagnosticUtilities.RequiresDynamicCodeAttribute), + suppressSingleFileDiagnostics: logger.ShouldSuppressAnalysisWarningsForRequires(origin.MemberDefinition, DiagnosticUtilities.RequiresAssemblyFilesAttribute), + logger: logger); + var reflectionMarker = new ReflectionMarker( + logger, + factory, + flowAnnotations, + typeHierarchyDataFlowOrigin: null, + enabled: true, + suppressTrimAnalysisWarnings: suppressTrimAnalysisWarnings, + suppressAotAnalysisWarnings: suppressAotAnalysisWarnings); ProcessGenericArgumentDataFlow(diagnosticContext, reflectionMarker, instantiatedType); diff --git a/src/runtime/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMarker.cs b/src/runtime/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMarker.cs index b322fce9d82a..bad6655f6747 100644 --- a/src/runtime/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMarker.cs +++ b/src/runtime/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMarker.cs @@ -26,6 +26,8 @@ public class ReflectionMarker private readonly Logger _logger; private readonly MetadataType? _typeHierarchyDataFlowOrigin; private readonly bool _enabled; + private readonly bool _suppressTrimAnalysisWarnings; + private readonly bool _suppressAotAnalysisWarnings; public NodeFactory Factory { get; } public FlowAnnotations Annotations { get; } @@ -39,13 +41,22 @@ internal enum AccessKind TokenAccess } - public ReflectionMarker(Logger logger, NodeFactory factory, FlowAnnotations annotations, MetadataType? typeHierarchyDataFlowOrigin, bool enabled) + public ReflectionMarker( + Logger logger, + NodeFactory factory, + FlowAnnotations annotations, + MetadataType? typeHierarchyDataFlowOrigin, + bool enabled, + bool suppressTrimAnalysisWarnings = false, + bool suppressAotAnalysisWarnings = false) { _logger = logger; Factory = factory; Annotations = annotations; _typeHierarchyDataFlowOrigin = typeHierarchyDataFlowOrigin; _enabled = enabled; + _suppressTrimAnalysisWarnings = suppressTrimAnalysisWarnings; + _suppressAotAnalysisWarnings = suppressAotAnalysisWarnings; } internal void MarkTypeForDynamicallyAccessedMembers(in MessageOrigin origin, TypeDesc typeDefinition, DynamicallyAccessedMemberTypes requiredMemberTypes, TypeSystemEntity reason, bool declaredOnly = false) @@ -298,7 +309,8 @@ private void ReportWarningsForReflectionAccess(in MessageOrigin origin, TypeSyst // This is because reflection access is actually problematic on all members which are in a "requires" scope // so for example even instance methods. See for example https://github.com/dotnet/linker/issues/3140 - it's possible // to call a method on a "null" instance via reflection. - if (_logger.ShouldSuppressAnalysisWarningsForRequires(entity, DiagnosticUtilities.RequiresUnreferencedCodeAttribute, out CustomAttributeValue? requiresAttribute) && + if (!_suppressTrimAnalysisWarnings && + _logger.ShouldSuppressAnalysisWarningsForRequires(entity, DiagnosticUtilities.RequiresUnreferencedCodeAttribute, out CustomAttributeValue? requiresAttribute) && ShouldProduceRequiresWarningForReflectionAccess(entity, accessKind)) ReportRequires(origin, entity, DiagnosticUtilities.RequiresUnreferencedCodeAttribute, requiresAttribute.Value); @@ -306,12 +318,14 @@ private void ReportWarningsForReflectionAccess(in MessageOrigin origin, TypeSyst ShouldProduceRequiresWarningForReflectionAccess(entity, accessKind)) ReportRequires(origin, entity, DiagnosticUtilities.RequiresAssemblyFilesAttribute, requiresAttribute.Value); - if (_logger.ShouldSuppressAnalysisWarningsForRequires(entity, DiagnosticUtilities.RequiresDynamicCodeAttribute, out requiresAttribute) && + if (!_suppressAotAnalysisWarnings && + _logger.ShouldSuppressAnalysisWarningsForRequires(entity, DiagnosticUtilities.RequiresDynamicCodeAttribute, out requiresAttribute) && ShouldProduceRequiresWarningForReflectionAccess(entity, accessKind)) ReportRequires(origin, entity, DiagnosticUtilities.RequiresDynamicCodeAttribute, requiresAttribute.Value); // Below is about accessing DAM annotated members, so only RUC is applicable as a suppression scope - if (_logger.ShouldSuppressAnalysisWarningsForRequires(origin.MemberDefinition, DiagnosticUtilities.RequiresUnreferencedCodeAttribute)) + if (_suppressTrimAnalysisWarnings || + _logger.ShouldSuppressAnalysisWarningsForRequires(origin.MemberDefinition, DiagnosticUtilities.RequiresUnreferencedCodeAttribute)) return; bool isReflectionAccessCoveredByDAM = Annotations.ShouldWarnWhenAccessedForReflection(entity); diff --git a/src/runtime/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/DataflowAnalyzedTypeDefinitionNode.cs b/src/runtime/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/DataflowAnalyzedTypeDefinitionNode.cs index 027709244940..3a67003163c7 100644 --- a/src/runtime/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/DataflowAnalyzedTypeDefinitionNode.cs +++ b/src/runtime/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/DataflowAnalyzedTypeDefinitionNode.cs @@ -69,9 +69,23 @@ public override IEnumerable GetStaticDependencies(NodeFacto if (_typeDefinition is MetadataType metadataType) { + // The generic instantiation in the interface list is only reachable through the members of + // the type which implements the interface, which are all in the Requires scope of a + // type-level Requires attribute, so the matching attribute silences these warnings. Note + // that the data flow still needs to run to mark the members required by the instantiation. + bool suppressTrimAnalysisWarnings = _typeDefinition.DoesTypeRequire(DiagnosticUtilities.RequiresUnreferencedCodeAttribute, out _); + bool suppressAotAnalysisWarnings = _typeDefinition.DoesTypeRequire(DiagnosticUtilities.RequiresDynamicCodeAttribute, out _); + foreach (var interfaceType in metadataType.ExplicitlyImplementedInterfaces) { - GenericArgumentDataFlow.ProcessGenericArgumentDataFlow(ref dependencies, factory, new MessageOrigin(_typeDefinition), interfaceType, _typeDefinition); + GenericArgumentDataFlow.ProcessGenericArgumentDataFlow( + ref dependencies, + factory, + new MessageOrigin(_typeDefinition), + interfaceType, + _typeDefinition, + suppressTrimAnalysisWarnings, + suppressAotAnalysisWarnings); } } diff --git a/src/runtime/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs b/src/runtime/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs index 3f59e6fe137e..764eafc6fcc6 100644 --- a/src/runtime/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs +++ b/src/runtime/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs @@ -1079,6 +1079,13 @@ private void RegisterDependenciesOnAsyncCall() _dependencies.Add(_factory.MethodEntrypoint(asyncHelpers.GetKnownMethod("RestoreContextsOnSuspension"u8, null)), asyncReason); _dependencies.Add(_factory.MethodEntrypoint(asyncHelpers.GetKnownMethod("FinishSuspensionNoContinuationContext"u8, null)), asyncReason); _dependencies.Add(_factory.MethodEntrypoint(asyncHelpers.GetKnownMethod("FinishSuspensionWithContinuationContext"u8, null)), asyncReason); + + // The JIT synthesizes calls to these when it inlines an async callee that may + // suspend, which it can do at any async call site. + _dependencies.Add(_factory.MethodEntrypoint(asyncHelpers.GetKnownMethod("RestoreInlinedFrameContexts"u8, null)), asyncReason); + _dependencies.Add(_factory.MethodEntrypoint(asyncHelpers.GetKnownMethod("CaptureInlinedFrameTransitionWithContinuationContext"u8, null)), asyncReason); + _dependencies.Add(_factory.MethodEntrypoint(asyncHelpers.GetKnownMethod("CaptureInlinedFrameTransitionNoContinuationContext"u8, null)), asyncReason); + _dependencies.Add(_factory.MethodEntrypoint(asyncHelpers.GetKnownMethod("CaptureInlinedFrameTransitionContinueOnThreadPool"u8, null)), asyncReason); } // The JIT rewrites calls to AsyncHelpers.AwaitAwaiter/UnsafeAwaitAwaiter with a struct diff --git a/src/runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCases/MissingVirtualSignature/Dependency.cs b/src/runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCases/MissingVirtualSignature/Dependency.cs new file mode 100644 index 000000000000..26d2184fda0d --- /dev/null +++ b/src/runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCases/MissingVirtualSignature/Dependency.cs @@ -0,0 +1,6 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +public sealed class MissingSignatureType +{ +} diff --git a/src/runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCases/MissingVirtualSignature/Input.cs b/src/runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCases/MissingVirtualSignature/Input.cs new file mode 100644 index 000000000000..4d6d638c6912 --- /dev/null +++ b/src/runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCases/MissingVirtualSignature/Input.cs @@ -0,0 +1,30 @@ +// 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.Runtime.CompilerServices; + +public interface IMissingSignature +{ + MissingSignatureType GetMissingType() => null; +} + +public class MissingSignatureImplementation : IMissingSignature +{ +} + +public class MissingSignatureFactory +{ + [MethodImpl(MethodImplOptions.NoInlining)] + public RuntimeTypeHandle GetTypeHandle() => typeof(MissingSignatureImplementation).TypeHandle; +} + +public static class EntryPoints +{ + [MethodImpl(MethodImplOptions.NoInlining)] + private static MissingSignatureFactory CreateFactory() => new MissingSignatureFactory(); + + public static RuntimeTypeHandle GetTypeHandle() => CreateFactory().GetTypeHandle(); + + public static int CompilableMethod() => 42; +} diff --git a/src/runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCases/R2RTestSuites.cs b/src/runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCases/R2RTestSuites.cs index 61e842aa9269..9bde75896d70 100644 --- a/src/runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCases/R2RTestSuites.cs +++ b/src/runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCases/R2RTestSuites.cs @@ -1183,11 +1183,6 @@ static void Validate(ReadyToRunReader reader) Assert.True(R2RAssert.HasInlinedMethod(reader, "CallReturnTaskNoAwait", "ReturnTaskNoAwait", out diag), diag); Assert.True(R2RAssert.HasInlinedMethod(reader, "CallReturnTaskPrimitiveNoAwait", "ReturnTaskPrimitiveNoAwait", out diag), diag); Assert.True(R2RAssert.HasInlinedMethod(reader, "CallReturnTaskClassNoAwait", "ReturnTaskClassNoAwait", out diag), diag); - - // Async candidates that contain a real await: cannot be inlined by the JIT. - Assert.False(R2RAssert.HasInlinedMethod(reader, "CallReturnTaskWithAwait", "ReturnTaskWithAwait", out diag), diag); - Assert.False(R2RAssert.HasInlinedMethod(reader, "CallReturnTaskPrimitiveWithAwait", "ReturnTaskPrimitiveWithAwait", out diag), diag); - Assert.False(R2RAssert.HasInlinedMethod(reader, "CallReturnTaskClassWithAwait", "ReturnTaskClassWithAwait", out diag), diag); } } @@ -1880,4 +1875,36 @@ static void Validate(ReadyToRunReader reader) Assert.True(R2RAssert.HasCompiledMethod(reader, "TestA`2<__Canon,int>", "TestMethod", out diag), diag); } } + + [Fact] + public void MissingVirtualSignature() + { + var missingDependency = new CompiledAssembly + { + AssemblyName = nameof(MissingVirtualSignature) + "Dependency", + SourceResourceNames = ["MissingVirtualSignature/Dependency.cs"], + }; + var input = new CompiledAssembly + { + AssemblyName = nameof(MissingVirtualSignature), + SourceResourceNames = ["MissingVirtualSignature/Input.cs"], + References = [missingDependency], + }; + + new R2RTestRunner(_output).Run(new R2RTestCase( + nameof(MissingVirtualSignature), + [ + new(nameof(MissingVirtualSignature), [new CrossgenAssembly(input)]) + { + AdditionalArgs = ["--parallelism", "1"], + Validate = Validate, + }, + ])); + + static void Validate(ReadyToRunReader reader) + { + Assert.True(R2RAssert.HasCompiledMethod(reader, "EntryPoints", "CompilableMethod", out string diag), diag); + Assert.False(R2RAssert.HasCompiledMethod(reader, "IMissingSignature`1<__Canon>", "GetMissingType", out diag), diag); + } + } } diff --git a/src/runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RTestRunner.cs b/src/runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RTestRunner.cs index 1fc286f92cb9..f466fd20d336 100644 --- a/src/runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RTestRunner.cs +++ b/src/runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RTestRunner.cs @@ -167,6 +167,10 @@ IEnumerable GetDependencies(CompiledAssembly assembly, List c.SetOutputDir(outputDir)); + foreach (CompiledAssembly assembly in GetAssemblies()) + { + assembly.SetOutputDir(outputDir); + } } } diff --git a/src/runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/WasmArgumentLayoutTests.cs b/src/runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/WasmArgumentLayoutTests.cs index e15b25117f46..2629202df347 100644 --- a/src/runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/WasmArgumentLayoutTests.cs +++ b/src/runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/WasmArgumentLayoutTests.cs @@ -260,6 +260,43 @@ public void SameSizedOrdinaryStructsStayByReference(int fieldCount, string expec Assert.Equal(expectedOffsets, GetArgumentOffsets(context, signature)); } + /// + /// Auto-layout structs use the runtime's effective aggregate alignment for argument placement, + /// which can be smaller than the alignment crossgen uses while laying out their fields. + /// + [Fact] + public void AutoLayoutStructUsesRuntimeAggregateAlignment() + { + ReadyToRunCompilerContext context = CreateWasmContext(); + DefType alignedEight = MakeAlignedEightBlob(context, 32); + DefType int128 = InstantiateMultiSlotType(context, Int128Type); + DefType autoLayout = MakeValueTuple(context, int128, int128); + + Assert.Equal(32, alignedEight.InstanceFieldSize.AsInt); + Assert.Equal(8, alignedEight.InstanceFieldAlignment.AsInt); + Assert.Equal(32, autoLayout.InstanceFieldSize.AsInt); + Assert.Equal(16, autoLayout.InstanceFieldAlignment.AsInt); + Assert.Equal(8, CorInfoImpl.GetClassAlignmentRequirementStatic(autoLayout)); + + MethodSignature autoLayoutSignature = MakeProbeSignature(context, autoLayout); + MethodSignature alignedEightSignature = MakeProbeSignature(context, alignedEight); + + WasmSignature autoLayoutLowered = + WasmLowering.GetSignature(autoLayoutSignature, WasmLowering.LoweringFlags.None); + WasmSignature alignedEightLowered = + WasmLowering.GetSignature(alignedEightSignature, WasmLowering.LoweringFlags.None); + + Assert.Equal("vlS32ip", autoLayoutLowered.SignatureString); + Assert.Equal("vlS32ip", alignedEightLowered.SignatureString); + Assert.Equal(new[] { 0, 8, 40 }, GetArgumentOffsets(context, autoLayoutSignature)); + Assert.Equal( + GetArgumentOffsets(context, autoLayoutSignature), + GetArgumentOffsets(context, WasmLowering.RaiseSignature(autoLayoutLowered, context))); + Assert.Equal( + GetArgumentOffsets(context, alignedEightSignature), + GetArgumentOffsets(context, WasmLowering.RaiseSignature(alignedEightLowered, context))); + } + /// /// Narrow vectors are not multi-slot. is a /// single ulong field, so it unwraps to a scalar i64 rather than to any slot form. diff --git a/src/runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/InheritedVirtualMethodsNode.cs b/src/runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/InheritedVirtualMethodsNode.cs index f5bae2f5afec..39a9d8502b49 100644 --- a/src/runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/InheritedVirtualMethodsNode.cs +++ b/src/runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/InheritedVirtualMethodsNode.cs @@ -75,63 +75,70 @@ public override IEnumerable GetConditionalStaticDep result.Add(new CombinedDependencyListEntry(implNode, factory.VirtualMethodUse(decl), "Virtual method")); } - // Interface method path: for each interface implemented by this type, - // compile the implementation if the interface method slot is used. - DefType[] runtimeInterfaces = defType.RuntimeInterfaces; - DefType defTypeDefinition = (DefType)defType.GetTypeDefinition(); - DefType[] definitionRuntimeInterfaces = defTypeDefinition.RuntimeInterfaces; - - for (int interfaceIndex = 0; interfaceIndex < runtimeInterfaces.Length; interfaceIndex++) + try { - DefType interfaceType = runtimeInterfaces[interfaceIndex]; - DefType definitionInterfaceType = definitionRuntimeInterfaces[interfaceIndex]; + // Interface method path: for each interface implemented by this type, + // compile the implementation if the interface method slot is used. + DefType[] runtimeInterfaces = defType.RuntimeInterfaces; + DefType defTypeDefinition = (DefType)defType.GetTypeDefinition(); + DefType[] definitionRuntimeInterfaces = defTypeDefinition.RuntimeInterfaces; - foreach (MethodDesc interfaceMethod in interfaceType.EnumAllVirtualSlots()) + for (int interfaceIndex = 0; interfaceIndex < runtimeInterfaces.Length; interfaceIndex++) { - // GVMs handled in GVMDependenciesNode. SVMs handled at call site. - if (interfaceMethod.HasInstantiation || interfaceMethod.Signature.IsStatic) - continue; - - MethodDesc interfaceMethodDefinition = interfaceMethod; - if (interfaceType != definitionInterfaceType) - interfaceMethodDefinition = factory.TypeSystemContext.GetMethodForInstantiatedType( - interfaceMethodDefinition.GetTypicalMethodDefinition(), - (InstantiatedType)definitionInterfaceType); - - MethodDesc implMethod = defTypeDefinition.InstantiateAsOpen().ResolveInterfaceMethodTarget(interfaceMethodDefinition); - if (implMethod is null) - { - // The method might be implemented through a default interface method - var resolution = defTypeDefinition.InstantiateAsOpen().ResolveInterfaceMethodToDefaultImplementationOnType(interfaceMethodDefinition, out implMethod); - if (resolution != DefaultInterfaceMethodResolution.DefaultImplementation) - { - implMethod = null; - } - } + DefType interfaceType = runtimeInterfaces[interfaceIndex]; + DefType definitionInterfaceType = definitionRuntimeInterfaces[interfaceIndex]; - if (implMethod is not null) + foreach (MethodDesc interfaceMethod in interfaceType.EnumAllVirtualSlots()) { - implMethod = implMethod.InstantiateSignature(defType.Instantiation, Instantiation.Empty); - - if (implMethod.IsVirtual && !implMethod.IsFinal && !implMethod.OwningType.IsInterface) + // GVMs handled in GVMDependenciesNode. SVMs handled at call site. + if (interfaceMethod.HasInstantiation || interfaceMethod.Signature.IsStatic) + continue; + + MethodDesc interfaceMethodDefinition = interfaceMethod; + if (interfaceType != definitionInterfaceType) + interfaceMethodDefinition = factory.TypeSystemContext.GetMethodForInstantiatedType( + interfaceMethodDefinition.GetTypicalMethodDefinition(), + (InstantiatedType)definitionInterfaceType); + + MethodDesc implMethod = defTypeDefinition.InstantiateAsOpen().ResolveInterfaceMethodTarget(interfaceMethodDefinition); + if (implMethod is null) { - // The interface resolves to a virtual method that can be overridden. - // Mark the class virtual slot as used so the class path compiles the - // actual final target (which may be an override further down the hierarchy). - result.Add(new CombinedDependencyListEntry(factory.VirtualMethodUse(implMethod), factory.VirtualMethodUse(interfaceMethod), "Interface method")); + // The method might be implemented through a default interface method + var resolution = defTypeDefinition.InstantiateAsOpen().ResolveInterfaceMethodToDefaultImplementationOnType(interfaceMethodDefinition, out implMethod); + if (resolution != DefaultInterfaceMethodResolution.DefaultImplementation) + { + implMethod = null; + } } - else + + if (implMethod is not null) { - MethodDesc canonImpl = implMethod.GetCanonMethodTarget(CanonicalFormKind.Specific); - DependencyNodeCore implNode = GetVirtualMethodImplNode(factory, canonImpl); - if (implNode is not null) + implMethod = implMethod.InstantiateSignature(defType.Instantiation, Instantiation.Empty); + + if (implMethod.IsVirtual && !implMethod.IsFinal && !implMethod.OwningType.IsInterface) + { + // The interface resolves to a virtual method that can be overridden. + // Mark the class virtual slot as used so the class path compiles the + // actual final target (which may be an override further down the hierarchy). + result.Add(new CombinedDependencyListEntry(factory.VirtualMethodUse(implMethod), factory.VirtualMethodUse(interfaceMethod), "Interface method")); + } + else { - result.Add(new CombinedDependencyListEntry(implNode, factory.VirtualMethodUse(interfaceMethod), "Interface method")); + MethodDesc canonImpl = implMethod.GetCanonMethodTarget(CanonicalFormKind.Specific); + DependencyNodeCore implNode = GetVirtualMethodImplNode(factory, canonImpl); + if (implNode is not null) + { + result.Add(new CombinedDependencyListEntry(implNode, factory.VirtualMethodUse(interfaceMethod), "Interface method")); + } } } } } } + catch (TypeSystemException) + { + // TODO: https://github.com/dotnet/runtime/issues/132338 - Gate this recovery on --resilient and report a warning. + } return result; } diff --git a/src/runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TypeHandle.cs b/src/runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TypeHandle.cs index 38d0f673a5de..c0741f6f9c42 100644 --- a/src/runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TypeHandle.cs +++ b/src/runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TypeHandle.cs @@ -178,7 +178,7 @@ public bool IsTrivialPointerSizedStruct() public int GetFieldAlignment() { - return ((DefType)_type).InstanceFieldAlignment.AsInt; + return CorInfoImpl.GetClassAlignmentRequirementStatic((DefType)_type); } /// diff --git a/src/runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs b/src/runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs index b75b07697f1b..b1429ca933e7 100644 --- a/src/runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs +++ b/src/runtime/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs @@ -1055,6 +1055,10 @@ private void AddNecessaryAsyncReferences(MethodDesc method) asyncHelpers.GetKnownMethod("RestoreContextsOnSuspension"u8, null), asyncHelpers.GetKnownMethod("FinishSuspensionNoContinuationContext"u8, null), asyncHelpers.GetKnownMethod("FinishSuspensionWithContinuationContext"u8, null), + asyncHelpers.GetKnownMethod("RestoreInlinedFrameContexts"u8, null), + asyncHelpers.GetKnownMethod("CaptureInlinedFrameTransitionWithContinuationContext"u8, null), + asyncHelpers.GetKnownMethod("CaptureInlinedFrameTransitionNoContinuationContext"u8, null), + asyncHelpers.GetKnownMethod("CaptureInlinedFrameTransitionContinueOnThreadPool"u8, null), // R2R Helpers asyncHelpers.GetKnownMethod("AllocContinuation"u8, null), diff --git a/src/runtime/src/coreclr/tools/metainfo/mdinfo.cpp b/src/runtime/src/coreclr/tools/metainfo/mdinfo.cpp index e8807d77af71..c28e71f7549e 100644 --- a/src/runtime/src/coreclr/tools/metainfo/mdinfo.cpp +++ b/src/runtime/src/coreclr/tools/metainfo/mdinfo.cpp @@ -17,6 +17,7 @@ #include #include +#include #include "mdinfo.h" diff --git a/src/runtime/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h b/src/runtime/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h index eaf9e7c90532..11a8b046e080 100644 --- a/src/runtime/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h +++ b/src/runtime/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h @@ -237,6 +237,10 @@ struct Agnostic_CORINFO_ASYNC_INFO DWORDLONG captureContextsMethHnd; DWORDLONG restoreContextsMethHnd; DWORDLONG restoreContextsOnSuspensionMethHnd; + DWORDLONG restoreInlinedFrameContextsMethHnd; + DWORDLONG captureInlinedFrameTransitionWithContinuationContextMethHnd; + DWORDLONG captureInlinedFrameTransitionNoContinuationContextMethHnd; + DWORDLONG captureInlinedFrameTransitionContinueOnThreadPoolMethHnd; DWORDLONG finishSuspensionNoContinuationContextMethHnd; DWORDLONG finishSuspensionWithContinuationContextMethHnd; }; diff --git a/src/runtime/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/runtime/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index 560bfb720197..f04fcff92cab 100644 --- a/src/runtime/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/runtime/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -4394,6 +4394,10 @@ void MethodContext::recGetAsyncInfo(const CORINFO_ASYNC_INFO* pAsyncInfo) value.captureContextsMethHnd = CastHandle(pAsyncInfo->captureContextsMethHnd); value.restoreContextsMethHnd = CastHandle(pAsyncInfo->restoreContextsMethHnd); value.restoreContextsOnSuspensionMethHnd = CastHandle(pAsyncInfo->restoreContextsOnSuspensionMethHnd); + value.restoreInlinedFrameContextsMethHnd = CastHandle(pAsyncInfo->restoreInlinedFrameContextsMethHnd); + value.captureInlinedFrameTransitionWithContinuationContextMethHnd = CastHandle(pAsyncInfo->captureInlinedFrameTransitionWithContinuationContextMethHnd); + value.captureInlinedFrameTransitionNoContinuationContextMethHnd = CastHandle(pAsyncInfo->captureInlinedFrameTransitionNoContinuationContextMethHnd); + value.captureInlinedFrameTransitionContinueOnThreadPoolMethHnd = CastHandle(pAsyncInfo->captureInlinedFrameTransitionContinueOnThreadPoolMethHnd); value.finishSuspensionNoContinuationContextMethHnd = CastHandle(pAsyncInfo->finishSuspensionNoContinuationContextMethHnd); value.finishSuspensionWithContinuationContextMethHnd = CastHandle(pAsyncInfo->finishSuspensionWithContinuationContextMethHnd); @@ -4420,6 +4424,10 @@ void MethodContext::repGetAsyncInfo(CORINFO_ASYNC_INFO* pAsyncInfoOut) pAsyncInfoOut->captureContextsMethHnd = (CORINFO_METHOD_HANDLE)value.captureContextsMethHnd; pAsyncInfoOut->restoreContextsMethHnd = (CORINFO_METHOD_HANDLE)value.restoreContextsMethHnd; pAsyncInfoOut->restoreContextsOnSuspensionMethHnd = (CORINFO_METHOD_HANDLE)value.restoreContextsOnSuspensionMethHnd; + pAsyncInfoOut->restoreInlinedFrameContextsMethHnd = (CORINFO_METHOD_HANDLE)value.restoreInlinedFrameContextsMethHnd; + pAsyncInfoOut->captureInlinedFrameTransitionWithContinuationContextMethHnd = (CORINFO_METHOD_HANDLE)value.captureInlinedFrameTransitionWithContinuationContextMethHnd; + pAsyncInfoOut->captureInlinedFrameTransitionNoContinuationContextMethHnd = (CORINFO_METHOD_HANDLE)value.captureInlinedFrameTransitionNoContinuationContextMethHnd; + pAsyncInfoOut->captureInlinedFrameTransitionContinueOnThreadPoolMethHnd = (CORINFO_METHOD_HANDLE)value.captureInlinedFrameTransitionContinueOnThreadPoolMethHnd; pAsyncInfoOut->finishSuspensionNoContinuationContextMethHnd = (CORINFO_METHOD_HANDLE)value.finishSuspensionNoContinuationContextMethHnd; pAsyncInfoOut->finishSuspensionWithContinuationContextMethHnd = (CORINFO_METHOD_HANDLE)value.finishSuspensionWithContinuationContextMethHnd; DEBUG_REP(dmpGetAsyncInfo(0, value)); diff --git a/src/runtime/src/coreclr/tools/superpmi/superpmi-shared/standardpch.h b/src/runtime/src/coreclr/tools/superpmi/superpmi-shared/standardpch.h index e18cb57a76a0..affc2f6ef968 100644 --- a/src/runtime/src/coreclr/tools/superpmi/superpmi-shared/standardpch.h +++ b/src/runtime/src/coreclr/tools/superpmi/superpmi-shared/standardpch.h @@ -63,6 +63,7 @@ #include #include #include +#include #include #include diff --git a/src/runtime/src/coreclr/utilcode/loaderheap.cpp b/src/runtime/src/coreclr/utilcode/loaderheap.cpp index 28f31c0fef16..38748fd8d733 100644 --- a/src/runtime/src/coreclr/utilcode/loaderheap.cpp +++ b/src/runtime/src/coreclr/utilcode/loaderheap.cpp @@ -539,15 +539,15 @@ void UnlockedLoaderHeap::UnlockedBackoutMem(void *pMem, "The arguments to BackoutMem() were:\n" "\n" " Pointer: 0x%p\n" - " Size: %lu (0x%lx)\n" + " Size: %zu (0x%zx)\n" "\n" ,szFile ,lineNum ,szAllocFile ,allocLineNum ,pMem - ,(ULONG)dwRequestedSize - ,(ULONG)dwRequestedSize + ,dwRequestedSize + ,dwRequestedSize ); @@ -862,7 +862,7 @@ void UnlockedLoaderHeap::DumpFreeList() if (sizeunaligned) buf.AppendUTF8(" *** ERROR: size not a multiple of ALLOC_ALIGN_CONSTANT ***"); buf.AppendUTF8("\n"); - minipal_log_print_info(buf.GetUTF8()); + minipal_log_print_info("%s", buf.GetUTF8()); buf.Clear(); pBlock = pBlock->m_pNext; diff --git a/src/runtime/src/coreclr/utilcode/loaderheap_shared.cpp b/src/runtime/src/coreclr/utilcode/loaderheap_shared.cpp index d286db2568c1..c4d50eb50d9b 100644 --- a/src/runtime/src/coreclr/utilcode/loaderheap_shared.cpp +++ b/src/runtime/src/coreclr/utilcode/loaderheap_shared.cpp @@ -121,13 +121,13 @@ void LoaderHeapEvent::Describe(SString *pSString) { StackSString buf; - buf.Printf(" Requested size: %lu (0x%lx)\n", (ULONG)m_dwRequestedSize, (ULONG)m_dwRequestedSize); + buf.Printf(" Requested size: %zu (0x%zx)\n", m_dwRequestedSize, m_dwRequestedSize); pSString->Append(buf); } { StackSString buf; - buf.Printf(" Actual size: %lu (0x%lx)\n", (ULONG)m_dwSize, (ULONG)m_dwSize); + buf.Printf(" Actual size: %zu (0x%zx)\n", m_dwSize, m_dwSize); pSString->Append(buf); } diff --git a/src/runtime/src/coreclr/vm/amd64/cgenamd64.cpp b/src/runtime/src/coreclr/vm/amd64/cgenamd64.cpp index 9fad047de12f..8a88987d9093 100644 --- a/src/runtime/src/coreclr/vm/amd64/cgenamd64.cpp +++ b/src/runtime/src/coreclr/vm/amd64/cgenamd64.cpp @@ -99,7 +99,7 @@ void TransitionFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFl SyncRegDisplayToCurrentContext(pRD); - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK TransitionFrame::UpdateRegDisplay_Impl(rip:%p, rsp:%p)\n", pRD->ControlPC, pRD->SP)); + LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK TransitionFrame::UpdateRegDisplay_Impl(rip:%p, rsp:%p)\n", (void*)pRD->ControlPC, (void*)pRD->SP)); } #ifdef FEATURE_RESOLVE_HELPER_DISPATCH @@ -212,7 +212,7 @@ void InlinedCallFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateF } #endif // FEATURE_INTERPRETER - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK InlinedCallFrame::UpdateRegDisplay_Impl(rip:%p, rsp:%p)\n", pRD->ControlPC, pRD->SP)); + LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK InlinedCallFrame::UpdateRegDisplay_Impl(rip:%p, rsp:%p)\n", (void*)pRD->ControlPC, (void*)pRD->SP)); } void FaultingExceptionFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats) diff --git a/src/runtime/src/coreclr/vm/amd64/excepamd64.cpp b/src/runtime/src/coreclr/vm/amd64/excepamd64.cpp index b25dd5c7f09f..c489f8a913a9 100644 --- a/src/runtime/src/coreclr/vm/amd64/excepamd64.cpp +++ b/src/runtime/src/coreclr/vm/amd64/excepamd64.cpp @@ -194,7 +194,7 @@ RtlVirtualUnwind_Worker ( // that the debugger is attched when we get here. _ASSERTE(CORDebuggerAttached()); - LOG((LF_CORDB, LL_EVERYTHING, "RVU_CBSW: in RtlVirtualUnwind_ClrDbgSafeWorker, ControlPc=0x%p\n", ControlPc)); + LOG((LF_CORDB, LL_EVERYTHING, "RVU_CBSW: in RtlVirtualUnwind_ClrDbgSafeWorker, ControlPc=%p\n", (void*)ControlPc)); BOOL InEpilogue = FALSE; BOOL HasManagedBreakpoint = FALSE; @@ -402,7 +402,7 @@ RtlVirtualUnwind_Worker ( if (InEpilogue && HasUnmanagedBreakpoint) { - STRESS_LOG1(LF_CORDB, LL_ERROR, "RtlVirtualUnwind is about to fail b/c the ControlPc (0x%p) is in the epilog of a function which has a 0xCC in its epilog.", ControlPc); + STRESS_LOG1(LF_CORDB, LL_ERROR, "RtlVirtualUnwind is about to fail b/c the ControlPc (0x%p) is in the epilog of a function which has a 0xCC in its epilog.", (void*)ControlPc); _ASSERTE(!"RtlVirtualUnwind is about to fail b/c you are unwinding through\n" "the epilogue of a function and have a 0xCC in the codestream. This is\n" "probably caused by having set that breakpoint yourself in the debugger,\n" diff --git a/src/runtime/src/coreclr/vm/appdomain.cpp b/src/runtime/src/coreclr/vm/appdomain.cpp index 0afca0aec69e..5e610ed1967c 100644 --- a/src/runtime/src/coreclr/vm/appdomain.cpp +++ b/src/runtime/src/coreclr/vm/appdomain.cpp @@ -859,11 +859,11 @@ void SystemDomain::Init() LOG(( LF_EEMEM, LL_INFO10, - "sizeof(EEClass) = %d\n" - "sizeof(MethodTable) = %d\n" - "sizeof(MethodDesc)= %d\n" - "sizeof(FieldDesc) = %d\n" - "sizeof(Module) = %d\n", + "sizeof(EEClass) = %zu\n" + "sizeof(MethodTable) = %zu\n" + "sizeof(MethodDesc)= %zu\n" + "sizeof(FieldDesc) = %zu\n" + "sizeof(Module) = %zu\n", sizeof(EEClass), sizeof(MethodTable), sizeof(MethodDesc), @@ -1503,7 +1503,7 @@ void SystemDomain::PublishAppDomainAndInformDebugger (AppDomain *pDomain) } CONTRACTL_END; - LOG((LF_CORDB, LL_INFO100, "SD::PADAID: Adding 0x%x\n", pDomain)); + LOG((LF_CORDB, LL_INFO100, "SD::PADAID: Adding %p\n", (void*)pDomain)); // // We need to synchronize this routine with the attach logic. The "normal" @@ -3503,7 +3503,7 @@ void AppDomain::NotifyDebuggerUnload() if (!IsDebuggerAttached()) return; - LOG((LF_CORDB, LL_INFO10, "AD::NDD domain %#08x\n", this)); + LOG((LF_CORDB, LL_INFO10, "AD::NDD domain %p\n", (void*)this)); LOG((LF_CORDB, LL_INFO100, "AD::NDD: Interating domain bound assemblies\n")); AssemblyIterator i = IterateAssembliesEx((AssemblyIterationFlags)(kIncludeLoaded | kIncludeLoading | kIncludeExecution)); diff --git a/src/runtime/src/coreclr/vm/arm/stubs.cpp b/src/runtime/src/coreclr/vm/arm/stubs.cpp index aac4fc192116..92eb4a625ee8 100644 --- a/src/runtime/src/coreclr/vm/arm/stubs.cpp +++ b/src/runtime/src/coreclr/vm/arm/stubs.cpp @@ -1237,7 +1237,7 @@ void TransitionFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFl // Finally, syncup the regdisplay with the context SyncRegDisplayToCurrentContext(pRD); - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK TransitionFrame::UpdateRegDisplay_Impl(rip:%p, rsp:%p)\n", pRD->ControlPC, pRD->SP)); + LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK TransitionFrame::UpdateRegDisplay_Impl(rip:%p, rsp:%p)\n", (void*)(size_t)pRD->ControlPC, (void*)(size_t)pRD->SP)); } #ifdef FEATURE_INTERPRETER diff --git a/src/runtime/src/coreclr/vm/arm64/singlestepper.cpp b/src/runtime/src/coreclr/vm/arm64/singlestepper.cpp index 7da626de2a07..03feffaf5dc8 100644 --- a/src/runtime/src/coreclr/vm/arm64/singlestepper.cpp +++ b/src/runtime/src/coreclr/vm/arm64/singlestepper.cpp @@ -7,6 +7,7 @@ // #include "common.h" +#include #include "arm64singlestepper.h" inline uint64_t SignExtend(uint64_t value, unsigned int signbit) @@ -104,7 +105,7 @@ void Arm64SingleStepper::Bypass(uint64_t ip, uint32_t opcode) } - LOG((LF_CORDB, LL_INFO100000, "Arm64SingleStepper::Bypass(pc=%lx, opcode=%x)\n", ip, opcode)); + LOG((LF_CORDB, LL_INFO100000, "Arm64SingleStepper::Bypass(pc=%" PRIx64 ", opcode=%x)\n", ip, opcode)); m_fBypass = true; m_originalPc = ip; @@ -133,7 +134,7 @@ void Arm64SingleStepper::Apply(T_CONTEXT *pCtx) uint32_t opcode = m_opcodes[0]; - LOG((LF_CORDB, LL_INFO100000, "Arm64SingleStepper::Apply(pc=%lx, opcode=%x)\n", (uint64_t)pCtx->Pc, opcode)); + LOG((LF_CORDB, LL_INFO100000, "Arm64SingleStepper::Apply(pc=%" PRIx64 ", opcode=%x)\n", (uint64_t)pCtx->Pc, opcode)); #ifdef _DEBUG // Make sure that we aren't trying to step through our own buffer. If this asserts, something is horribly @@ -276,7 +277,7 @@ bool Arm64SingleStepper::Fixup(T_CONTEXT *pCtx, DWORD dwExceptionCode) { if (m_rgCode[0] != kBreakpointOp) { - LOG((LF_CORDB, LL_INFO100000, "Arm64SingleStepper::Fixup executed code, ip = %lx\n", m_targetPc)); + LOG((LF_CORDB, LL_INFO100000, "Arm64SingleStepper::Fixup executed code, ip = %" PRIx64 "\n", m_targetPc)); pCtx->Pc = m_targetPc; } @@ -299,7 +300,7 @@ bool Arm64SingleStepper::Fixup(T_CONTEXT *pCtx, DWORD dwExceptionCode) pCtx->Pc = m_targetPc; - LOG((LF_CORDB, LL_INFO100000, "Arm64SingleStepper::Fixup emulated, ip = %lx\n", pCtx->Pc)); + LOG((LF_CORDB, LL_INFO100000, "Arm64SingleStepper::Fixup emulated, ip = %" PRIx64 "\n", pCtx->Pc)); } } else @@ -309,7 +310,7 @@ bool Arm64SingleStepper::Fixup(T_CONTEXT *pCtx, DWORD dwExceptionCode) _ASSERTE(m_fEmulate == false); pCtx->Pc = m_originalPc; - LOG((LF_CORDB, LL_INFO100000, "Arm64SingleStepper::Fixup hit exception pc = %lx ex = %x\n", pCtx->Pc, dwExceptionCode)); + LOG((LF_CORDB, LL_INFO100000, "Arm64SingleStepper::Fixup hit exception pc = %" PRIx64 " ex = %x\n", pCtx->Pc, dwExceptionCode)); } _ASSERTE((pCtx->Pc & 0x3) == 0); diff --git a/src/runtime/src/coreclr/vm/arm64/stubs.cpp b/src/runtime/src/coreclr/vm/arm64/stubs.cpp index 3513feefd9c7..285ee91b92f3 100644 --- a/src/runtime/src/coreclr/vm/arm64/stubs.cpp +++ b/src/runtime/src/coreclr/vm/arm64/stubs.cpp @@ -236,7 +236,7 @@ void TransitionFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFl // Finally, syncup the regdisplay with the context SyncRegDisplayToCurrentContext(pRD); - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK TransitionFrame::UpdateRegDisplay_Impl(pc:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); + LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK TransitionFrame::UpdateRegDisplay_Impl(pc:%p, sp:%p)\n", (void*)pRD->ControlPC, (void*)pRD->SP)); } #ifdef FEATURE_RESOLVE_HELPER_DISPATCH @@ -340,7 +340,7 @@ void FaultingExceptionFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool u pRD->IsCallerContextValid = FALSE; - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK FaultingExceptionFrame::UpdateRegDisplay_Impl(pc:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); + LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK FaultingExceptionFrame::UpdateRegDisplay_Impl(pc:%p, sp:%p)\n", (void*)pRD->ControlPC, (void*)pRD->SP)); } void InlinedCallFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats) @@ -407,7 +407,7 @@ void InlinedCallFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateF } #endif // FEATURE_INTERPRETER - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK InlinedCallFrame::UpdateRegDisplay_Impl(pc:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); + LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK InlinedCallFrame::UpdateRegDisplay_Impl(pc:%p, sp:%p)\n", (void*)pRD->ControlPC, (void*)pRD->SP)); } #ifdef FEATURE_HIJACK @@ -453,7 +453,7 @@ void ResumableFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFlo pRD->IsCallerContextValid = FALSE; - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK ResumableFrame::UpdateRegDisplay_Impl(pc:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); + LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK ResumableFrame::UpdateRegDisplay_Impl(pc:%p, sp:%p)\n", (void*)pRD->ControlPC, (void*)pRD->SP)); } void HijackFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats) @@ -505,7 +505,7 @@ void HijackFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats SyncRegDisplayToCurrentContext(pRD); - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK HijackFrame::UpdateRegDisplay_Impl(pc:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); + LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK HijackFrame::UpdateRegDisplay_Impl(pc:%p, sp:%p)\n", (void*)pRD->ControlPC, (void*)pRD->SP)); } #endif // FEATURE_HIJACK diff --git a/src/runtime/src/coreclr/vm/ceeload.cpp b/src/runtime/src/coreclr/vm/ceeload.cpp index 91490382dd40..c75a5b6bb266 100644 --- a/src/runtime/src/coreclr/vm/ceeload.cpp +++ b/src/runtime/src/coreclr/vm/ceeload.cpp @@ -683,7 +683,7 @@ void Module::Destruct() } CONTRACTL_END; - LOG((LF_EEMEM, INFO3, "Deleting module %x\n", this)); + LOG((LF_EEMEM, INFO3, "Deleting module %p\n", (void*)this)); #ifdef PROFILING_SUPPORTED { BEGIN_PROFILER_CALLBACK(CORProfilerTrackModuleLoads()); @@ -3355,7 +3355,7 @@ void Module::FixupVTables() #ifdef _DEBUG if (pMD->IsPInvoke()) { - LOG((LF_INTEROP, LL_INFO10, "[0x%lx] <-- PINV thunk for \"%s\" (target = 0x%lx)\n", + LOG((LF_INTEROP, LL_INFO10, "[0x%zx] <-- PINV thunk for \"%s\" (target = 0x%zx)\n", (size_t)&(pPointers[iMethod]), pMD->m_pszDebugMethodName, (size_t)(((PInvokeMethodDesc*)pMD)->GetPInvokeTarget()))); } diff --git a/src/runtime/src/coreclr/vm/ceemain.cpp b/src/runtime/src/coreclr/vm/ceemain.cpp index c3258d390988..e59c29fed207 100644 --- a/src/runtime/src/coreclr/vm/ceemain.cpp +++ b/src/runtime/src/coreclr/vm/ceemain.cpp @@ -977,7 +977,7 @@ void EEStartupHelper() // This should be done before assemblies/modules are loaded into it (i.e. SystemDomain::Init) // and after its OK to switch GC modes and synchronize for sending events to the debugger. // @dbgtodo synchronization: this can probably be simplified in V3 - LOG((LF_CORDB | LF_SYNC | LF_STARTUP, LL_INFO1000, "EEStartup: adding default domain 0x%x\n", + LOG((LF_CORDB | LF_SYNC | LF_STARTUP, LL_INFO1000, "EEStartup: adding default domain %p\n", SystemDomain::System()->DefaultDomain())); SystemDomain::System()->PublishAppDomainAndInformDebugger(SystemDomain::System()->DefaultDomain()); #endif diff --git a/src/runtime/src/coreclr/vm/class.cpp b/src/runtime/src/coreclr/vm/class.cpp index 0fa9beba441e..281ea7e7c11c 100644 --- a/src/runtime/src/coreclr/vm/class.cpp +++ b/src/runtime/src/coreclr/vm/class.cpp @@ -2773,7 +2773,7 @@ MethodTable::DebugDumpGCDesc( { if (fDebug) { - ssBuff.Printf(" offset %5d (%d w/o Object), size %5d (%5d w/o BaseSize subtr)\n", + ssBuff.Printf(" offset %5zu (%zu w/o Object), size %5zu (%5zu w/o BaseSize subtr)\n", pSeries->GetSeriesOffset(), pSeries->GetSeriesOffset() - OBJECT_SIZE, pSeries->GetSeriesSize(), @@ -2783,7 +2783,7 @@ MethodTable::DebugDumpGCDesc( else { //LF_ALWAYS allowed here because this is controlled by special env var ShouldDumpOnClassLoad - LOG((LF_ALWAYS, LL_ALWAYS, " offset %5d (%d w/o Object), size %5d (%5d w/o BaseSize subtr)\n", + LOG((LF_ALWAYS, LL_ALWAYS, " offset %5zu (%zu w/o Object), size %5zu (%5zu w/o BaseSize subtr)\n", pSeries->GetSeriesOffset(), pSeries->GetSeriesOffset() - OBJECT_SIZE, pSeries->GetSeriesSize(), diff --git a/src/runtime/src/coreclr/vm/classlayoutinfo.cpp b/src/runtime/src/coreclr/vm/classlayoutinfo.cpp index 99f11a0299c9..10c037e9ddf3 100644 --- a/src/runtime/src/coreclr/vm/classlayoutinfo.cpp +++ b/src/runtime/src/coreclr/vm/classlayoutinfo.cpp @@ -1140,8 +1140,8 @@ EEClassNativeLayoutInfo* EEClassNativeLayoutInfo::CollectNativeLayoutFieldMetada LOG((LF_INTEROP, LL_INFO100000, "\n\n")); LOG((LF_INTEROP, LL_INFO100000, "%s.%s\n", szNamespace, szName)); - 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, "Packsize = %lu\n", (unsigned long)pEEClassLayoutInfo->GetPackingSize())); + LOG((LF_INTEROP, LL_INFO100000, "Max align req = %lu\n", (unsigned long)(pNativeLayoutInfo->GetLargestAlignmentRequirement()))); LOG((LF_INTEROP, LL_INFO100000, "----------------------------\n")); for (LayoutRawFieldInfo* pfwalk = pInfoArray; pfwalk->m_token != mdFieldDefNil; pfwalk++) { @@ -1150,12 +1150,12 @@ EEClassNativeLayoutInfo* EEClassNativeLayoutInfo::CollectNativeLayoutFieldMetada { fieldname = "??"; } - LOG((LF_INTEROP, LL_INFO100000, "+%-5lu ", (ULONG)(pfwalk->m_placement.m_offset))); + LOG((LF_INTEROP, LL_INFO100000, "+%-5lu ", (unsigned long)(pfwalk->m_placement.m_offset))); LOG((LF_INTEROP, LL_INFO100000, "%s", fieldname)); LOG((LF_INTEROP, LL_INFO100000, "\n")); } - LOG((LF_INTEROP, LL_INFO100000, "+%-5lu EOS\n", (ULONG)(pNativeLayoutInfo->GetSize()))); + LOG((LF_INTEROP, LL_INFO100000, "+%-5lu EOS\n", (unsigned long)(pNativeLayoutInfo->GetSize()))); LOG((LF_INTEROP, LL_INFO100000, "Allocated %d %s field marshallers for %s.%s\n", numTotalInstanceFields, (!isMarshalable ? "pointless" : "usable"), szNamespace, szName)); } #endif diff --git a/src/runtime/src/coreclr/vm/clrex.cpp b/src/runtime/src/coreclr/vm/clrex.cpp index 700532f2ac45..474c6c298aa0 100644 --- a/src/runtime/src/coreclr/vm/clrex.cpp +++ b/src/runtime/src/coreclr/vm/clrex.cpp @@ -47,7 +47,7 @@ CLRException::~CLRException() OBJECTHANDLE throwableHandle = GetThrowableHandle(); if (throwableHandle != NULL) { - STRESS_LOG1(LF_EH, LL_INFO100, "CLRException::~CLRException destroying throwable: obj = %x\n", GetThrowableHandle()); + STRESS_LOG1(LF_EH, LL_INFO100, "CLRException::~CLRException destroying throwable: obj = %p\n", (void*)GetThrowableHandle()); // clear the handle first, so if we SO on destroying it, we don't have a dangling reference SetThrowableHandle(NULL); DestroyHandle(throwableHandle); diff --git a/src/runtime/src/coreclr/vm/clrex.h b/src/runtime/src/coreclr/vm/clrex.h index b2d7a1599a1f..a2ec2ee15fdd 100644 --- a/src/runtime/src/coreclr/vm/clrex.h +++ b/src/runtime/src/coreclr/vm/clrex.h @@ -966,7 +966,7 @@ inline CLRException::CLRException() inline void CLRException::SetThrowableHandle(OBJECTHANDLE throwable) { - STRESS_LOG1(LF_EH, LL_INFO100, "in CLRException::SetThrowableHandle: obj = %x\n", throwable); + STRESS_LOG1(LF_EH, LL_INFO100, "in CLRException::SetThrowableHandle: obj = %p\n", (void*)throwable); m_throwableHandle = throwable; } diff --git a/src/runtime/src/coreclr/vm/clsload.cpp b/src/runtime/src/coreclr/vm/clsload.cpp index b1d5adc2bf27..58b35055b4c5 100644 --- a/src/runtime/src/coreclr/vm/clsload.cpp +++ b/src/runtime/src/coreclr/vm/clsload.cpp @@ -3345,7 +3345,7 @@ ClassLoader::LoadTypeHandleForTypeKey_Body( } EX_HOOK { - LOG((LF_CLASSLOADER, LL_INFO10, "Caught an exception loading: %x, %0x (Module)\n", pTypeKey->IsConstructed() ? HashTypeKey(pTypeKey) : pTypeKey->GetTypeToken(), pTypeKey->GetModule())); + LOG((LF_CLASSLOADER, LL_INFO10, "Caught an exception loading: %x, %p (Module)\n", pTypeKey->IsConstructed() ? HashTypeKey(pTypeKey) : pTypeKey->GetTypeToken(), (void*)pTypeKey->GetModule())); if (!GetThread()->HasThreadStateNC(Thread::TSNC_LoadsTypeViolation)) { diff --git a/src/runtime/src/coreclr/vm/codeman.cpp b/src/runtime/src/coreclr/vm/codeman.cpp index 20bd504cacd1..b9041ad1ed51 100644 --- a/src/runtime/src/coreclr/vm/codeman.cpp +++ b/src/runtime/src/coreclr/vm/codeman.cpp @@ -1402,7 +1402,7 @@ void EEJitManager::SetCpuInfo() { #if defined(TARGET_X86) || defined(TARGET_AMD64) EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("\nThe current CPU is missing one or more of the following instruction sets: SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT\n")); -#elif defined(TARGET_ARM64) && (defined(TARGET_WINDOWS) || defined(TARGET_OSX) || defined(TARGET_MACCATALYST)) +#elif defined(TARGET_ARM64) && (defined(TARGET_OSX) || defined(TARGET_MACCATALYST)) EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("\nThe current CPU is missing one or more of the following instruction sets: AdvSimd, LSE\n")); #elif defined(TARGET_ARM64) EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("\nThe current CPU is missing one or more of the following instruction sets: AdvSimd\n")); @@ -2849,7 +2849,7 @@ extern "C" PT_RUNTIME_FUNCTION GetRuntimeFunctionCallback(IN ULONG ControlPc if (codeInfo.IsValid()) prf = codeInfo.GetFunctionEntry(); - LOG((LF_EH, LL_INFO1000000, "GetRuntimeFunctionCallback(%p) returned %p\n", ControlPc, prf)); + LOG((LF_EH, LL_INFO1000000, "GetRuntimeFunctionCallback(%p) returned %p\n", (void*)(size_t)ControlPc, (void*)(size_t)prf)); return prf; } diff --git a/src/runtime/src/coreclr/vm/comdelegate.cpp b/src/runtime/src/coreclr/vm/comdelegate.cpp index a60a97875a5c..dc7f140946e6 100644 --- a/src/runtime/src/coreclr/vm/comdelegate.cpp +++ b/src/runtime/src/coreclr/vm/comdelegate.cpp @@ -1453,7 +1453,7 @@ OBJECTREF COMDelegate::ConvertToDelegate(LPVOID pCallback, MethodTable* pMT) // Wire up the stubs to the new delegate instance. // - LOG((LF_INTEROP, LL_INFO10000, "Created delegate for function pointer: entrypoint: %p\n", pMarshalStub)); + LOG((LF_INTEROP, LL_INFO10000, "Created delegate for function pointer: entrypoint: %p\n", (void*)pMarshalStub)); // Create the new delegate DELEGATEREF delObj = (DELEGATEREF) pMT->Allocate(); diff --git a/src/runtime/src/coreclr/vm/common.h b/src/runtime/src/coreclr/vm/common.h index 0ecd3dac69b1..ea9bc813d19b 100644 --- a/src/runtime/src/coreclr/vm/common.h +++ b/src/runtime/src/coreclr/vm/common.h @@ -343,7 +343,8 @@ extern DummyGlobalContract ___contract; #undef FPO_ON #endif -void LogErrorToHost(const char* format, ...); +#include +void LogErrorToHost(const char* format, ...) MINIPAL_ATTR_FORMAT_PRINTF(1, 2); #endif // !_common_h_ diff --git a/src/runtime/src/coreclr/vm/comutilnative.cpp b/src/runtime/src/coreclr/vm/comutilnative.cpp index b9c4653f4422..4444343d4404 100644 --- a/src/runtime/src/coreclr/vm/comutilnative.cpp +++ b/src/runtime/src/coreclr/vm/comutilnative.cpp @@ -1275,7 +1275,7 @@ void GCInterface::AddMemoryPressure(UINT64 bytesAllocated) UINT64 rem = m_remPressure[0] + m_remPressure[1] + m_remPressure[2] + m_remPressure[3] - m_remPressure[p]; STRESS_LOG4(LF_GCINFO, LL_INFO10000, "AMP Add: %llu => added=%llu total_added=%llu total_removed=%llu", - bytesAllocated, newMemValue, add, rem); + (unsigned long long)bytesAllocated, (unsigned long long)newMemValue, (unsigned long long)add, (unsigned long long)rem); SendEtwAddMemoryPressureEvent(bytesAllocated); @@ -1317,7 +1317,8 @@ void GCInterface::AddMemoryPressure(UINT64 bytesAllocated) if ((size_t)(pGCHeap->GetNow() - pGCHeap->GetLastGCStartTime(2)) > (pGCHeap->GetLastGCDuration(2) * 5)) { STRESS_LOG6(LF_GCINFO, LL_INFO10000, "AMP Budget: pressure=%llu ? budget=%llu (total_added=%llu, total_removed=%llu, mng_heap=%llu) pos=%d", - newMemValue, budget, add, rem, heapOver3 * 3, m_iteration); + (unsigned long long)newMemValue, (unsigned long long)budget, (unsigned long long)add, (unsigned long long)rem, + (unsigned long long)(heapOver3 * 3), m_iteration); GarbageCollectModeAny(2); @@ -1356,7 +1357,7 @@ void GCInterface::RemoveMemoryPressure(UINT64 bytesAllocated) InterlockedAdd(&m_remPressure[p], bytesAllocated); STRESS_LOG2(LF_GCINFO, LL_INFO10000, "AMP Remove: %llu => removed=%llu", - bytesAllocated, m_remPressure[p]); + (unsigned long long)bytesAllocated, (unsigned long long)m_remPressure[p]); } inline void GCInterface::SendEtwAddMemoryPressureEvent(UINT64 bytesAllocated) diff --git a/src/runtime/src/coreclr/vm/corelib.h b/src/runtime/src/coreclr/vm/corelib.h index c955c16b2a52..972fb1580d20 100644 --- a/src/runtime/src/coreclr/vm/corelib.h +++ b/src/runtime/src/coreclr/vm/corelib.h @@ -732,6 +732,10 @@ DEFINE_METHOD(ASYNC_HELPERS, CAPTURE_CONTINUATION_CONTEXT, CaptureContinuat DEFINE_METHOD(ASYNC_HELPERS, CAPTURE_CONTEXTS, CaptureContexts, NoSig) DEFINE_METHOD(ASYNC_HELPERS, RESTORE_CONTEXTS, RestoreContexts, NoSig) DEFINE_METHOD(ASYNC_HELPERS, RESTORE_CONTEXTS_ON_SUSPENSION, RestoreContextsOnSuspension, NoSig) +DEFINE_METHOD(ASYNC_HELPERS, RESTORE_INLINED_FRAME_CONTEXTS, RestoreInlinedFrameContexts, NoSig) +DEFINE_METHOD(ASYNC_HELPERS, CAPTURE_INLINED_FRAME_TRANSITION_WITH_CONTINUATION_CONTEXT, CaptureInlinedFrameTransitionWithContinuationContext, NoSig) +DEFINE_METHOD(ASYNC_HELPERS, CAPTURE_INLINED_FRAME_TRANSITION_NO_CONTINUATION_CONTEXT, CaptureInlinedFrameTransitionNoContinuationContext, NoSig) +DEFINE_METHOD(ASYNC_HELPERS, CAPTURE_INLINED_FRAME_TRANSITION_CONTINUE_ON_THREAD_POOL, CaptureInlinedFrameTransitionContinueOnThreadPool, NoSig) DEFINE_METHOD(ASYNC_HELPERS, FINISH_SUSPENSION_NO_CONTINUATION_CONTEXT, FinishSuspensionNoContinuationContext, NoSig) DEFINE_METHOD(ASYNC_HELPERS, FINISH_SUSPENSION_WITH_CONTINUATION_CONTEXT, FinishSuspensionWithContinuationContext, NoSig) DEFINE_METHOD(ASYNC_HELPERS, ASYNC_CALL_CONTINUATION, AsyncCallContinuation, NoSig) diff --git a/src/runtime/src/coreclr/vm/crst.cpp b/src/runtime/src/coreclr/vm/crst.cpp index 76139417c32d..44e20d60ed90 100644 --- a/src/runtime/src/coreclr/vm/crst.cpp +++ b/src/runtime/src/coreclr/vm/crst.cpp @@ -671,15 +671,15 @@ BOOL CrstBase::IsSafeToTake() || (pcrst->m_crstlevel == m_crstlevel && (m_dwFlags & CRST_UNSAFE_SAMELEVEL) != 0); if (!fSafe) { - LOG((LF_SYNC, INFO3, "Crst Level violation: Can't take level %lu lock %s because you already holding level %lu lock %s\n", - (ULONG)m_crstlevel, m_tag, (ULONG)(pcrst->m_crstlevel), pcrst->m_tag)); + LOG((LF_SYNC, INFO3, "Crst Level violation: Can't take level %d lock %s because you already holding level %d lock %s\n", + m_crstlevel, m_tag, pcrst->m_crstlevel, pcrst->m_tag)); // So that we can debug here. if (!g_fEEShutDown) { - CONSISTENCY_CHECK_MSGF(false, ("Crst Level violation: Can't take level %lu lock %s because you already holding level %lu lock %s\n", - (ULONG)m_crstlevel, + CONSISTENCY_CHECK_MSGF(false, ("Crst Level violation: Can't take level %d lock %s because you already holding level %d lock %s\n", + m_crstlevel, m_tag, - (ULONG)(pcrst->m_crstlevel), + pcrst->m_crstlevel, pcrst->m_tag)); } break; diff --git a/src/runtime/src/coreclr/vm/dllimport.cpp b/src/runtime/src/coreclr/vm/dllimport.cpp index 613e358e862f..def576c508e2 100644 --- a/src/runtime/src/coreclr/vm/dllimport.cpp +++ b/src/runtime/src/coreclr/vm/dllimport.cpp @@ -841,8 +841,8 @@ class ILStubState PrettyPrintSig(pManagedSig, cManagedSig, "*", &qbManaged, pStubMD->GetMDImport(), NULL); PrettyPrintSig(pILHeader->LocalVarSig, pILHeader->cbLocalVarSig, NULL, &qbLocal, pIMDI, NULL); - LOG((LF_STUBS, LL_INFO1000, "incoming managed sig: %p: %s\n", pManagedSig, qbManaged.Ptr())); - LOG((LF_STUBS, LL_INFO1000, "locals sig: %p: %s\n", pILHeader->LocalVarSig, qbLocal.Ptr())); + LOG((LF_STUBS, LL_INFO1000, "incoming managed sig: %p: %s\n", pManagedSig, (const char*)qbManaged.Ptr())); + LOG((LF_STUBS, LL_INFO1000, "locals sig: %p: %s\n", pILHeader->LocalVarSig, (const char*)qbLocal.Ptr())); if (cleanupTryFinally.cbHandlerLength != 0) { @@ -1061,7 +1061,7 @@ class ILStubState LIMITED_METHOD_CONTRACT; if (flags & flag) { - LOG((facility, level, str)); + LOG((facility, level, "%s", str)); } } diff --git a/src/runtime/src/coreclr/vm/dynamicmethod.cpp b/src/runtime/src/coreclr/vm/dynamicmethod.cpp index 0079a0cb8c3e..335621ea1b8b 100644 --- a/src/runtime/src/coreclr/vm/dynamicmethod.cpp +++ b/src/runtime/src/coreclr/vm/dynamicmethod.cpp @@ -334,7 +334,7 @@ HeapList* HostCodeHeap::CreateCodeHeap(CodeHeapRequestInfo *pInfo, EECodeGenMana return NULL; } - LOG((LF_BCL, LL_INFO100, "Level2 - CodeHeap creation {0x%p} - base addr 0x%p, size available 0x%p, nibble map ptr 0x%p\n", + LOG((LF_BCL, LL_INFO100, "Level2 - CodeHeap creation {0x%p} - base addr 0x%p, size available 0x%zx, nibble map ptr 0x%p\n", (HostCodeHeap*)pCodeHeap, pCodeHeap->m_pBaseAddr, pCodeHeap->m_TotalBytesAvailable, pCodeHeap->m_pHeapList->pHdrMap)); pCodeHeap.SuppressRelease(); @@ -459,7 +459,7 @@ HeapList* HostCodeHeap::InitializeHeapList(CodeHeapRequestInfo *pInfo) // wire it back m_pHeapList = (PTR_HeapList)pHp; - LOG((LF_BCL, LL_INFO100, "Level2 - CodeHeap creation {0x%p} - size available 0x%p, private data ptr [0x%p, 0x%p]\n", + LOG((LF_BCL, LL_INFO100, "Level2 - CodeHeap creation {0x%p} - size available 0x%zx, private data ptr [0x%p, 0x%zx]\n", (HostCodeHeap*)this, m_TotalBytesAvailable, pTracker, (pTracker ? pTracker->size : 0))); // It is important to exclude the CLRPersonalityRoutine from the tracked range @@ -498,7 +498,7 @@ HostCodeHeap::TrackAllocation* HostCodeHeap::AllocFromFreeList(size_t header, si if (m_pFreeList) { - LOG((LF_BCL, LL_INFO100, "Level2 - CodeHeap [0x%p] - Alloc size corrected 0x%X for free list\n", this, size)); + LOG((LF_BCL, LL_INFO100, "Level2 - CodeHeap [0x%p] - Alloc size corrected 0x%zx for free list\n", this, size)); // walk the list looking for a block with enough capacity TrackAllocation *pCurrent = m_pFreeList; TrackAllocation *pPrevious = NULL; @@ -509,7 +509,7 @@ HostCodeHeap::TrackAllocation* HostCodeHeap::AllocFromFreeList(size_t header, si if (pCurrent->size >= realSize + reserveForJumpStubs) { // found a block - LOG((LF_BCL, LL_INFO100, "Level2 - CodeHeap [0x%p] - Block found, size 0x%X\n", this, pCurrent->size)); + LOG((LF_BCL, LL_INFO100, "Level2 - CodeHeap [0x%p] - Block found, size 0x%zx\n", this, pCurrent->size)); ExecutableWriterHolderNoLog previousWriterHolder; if (pPrevious) @@ -523,7 +523,7 @@ HostCodeHeap::TrackAllocation* HostCodeHeap::AllocFromFreeList(size_t header, si // update the TrackAllocation record for the current block if (pCurrent->size - realSize < max(HOST_CODEHEAP_SIZE_ALIGN, sizeof(TrackAllocation))) { - LOG((LF_BCL, LL_INFO100, "Level2 - CodeHeap [0x%p] - Item removed %p, size 0x%X\n", this, pCurrent, pCurrent->size)); + LOG((LF_BCL, LL_INFO100, "Level2 - CodeHeap [0x%p] - Item removed %p, size 0x%zx\n", this, pCurrent, pCurrent->size)); // remove current if (pPrevious) { @@ -543,7 +543,7 @@ HostCodeHeap::TrackAllocation* HostCodeHeap::AllocFromFreeList(size_t header, si newCurrentWriterHolder.GetRW()->pNext = pCurrent->pNext; newCurrentWriterHolder.GetRW()->size = pCurrent->size - realSize; - LOG((LF_BCL, LL_INFO100, "Level2 - CodeHeap [0x%p] - Item changed %p, new size 0x%X\n", this, pNewCurrent, pNewCurrent->size)); + LOG((LF_BCL, LL_INFO100, "Level2 - CodeHeap [0x%p] - Item changed %p, new size 0x%zx\n", this, pNewCurrent, pNewCurrent->size)); if (pPrevious) { previousWriterHolder.GetRW()->pNext = pNewCurrent; @@ -559,14 +559,14 @@ HostCodeHeap::TrackAllocation* HostCodeHeap::AllocFromFreeList(size_t header, si currentWriterHolder.GetRW()->pHeap = this; - LOG((LF_BCL, LL_INFO100, "Level2 - CodeHeap [0x%p] - Allocation returned %p, size 0x%X - data -> %p\n", this, pCurrent, pCurrent->size, pPointer)); + LOG((LF_BCL, LL_INFO100, "Level2 - CodeHeap [0x%p] - Allocation returned %p, size 0x%zx - data -> %p\n", this, pCurrent, pCurrent->size, pPointer)); return pCurrent; } pPrevious = pCurrent; pCurrent = pCurrent->pNext; } } - LOG((LF_BCL, LL_INFO100, "Level2 - CodeHeap [0x%p] - No block in free list for size 0x%X\n", this, size)); + LOG((LF_BCL, LL_INFO100, "Level2 - CodeHeap [0x%p] - No block in free list for size 0x%zx\n", this, size)); return NULL; } @@ -580,7 +580,7 @@ void HostCodeHeap::AddToFreeList(TrackAllocation *pBlockToInsert, TrackAllocatio } CONTRACTL_END; - LOG((LF_BCL, LL_INFO100, "Level2 - CodeHeap [0x%p] - Add to FreeList [%p, 0x%X]\n", this, pBlockToInsert, pBlockToInsert->size)); + LOG((LF_BCL, LL_INFO100, "Level2 - CodeHeap [0x%p] - Add to FreeList [%p, 0x%zx]\n", this, pBlockToInsert, pBlockToInsert->size)); // append to the list in the proper position and coalesce if needed if (m_pFreeList) @@ -599,7 +599,7 @@ void HostCodeHeap::AddToFreeList(TrackAllocation *pBlockToInsert, TrackAllocatio { previousWriterHolder.AssignExecutableWriterHolder(pPrevious, sizeof(TrackAllocation)); previousWriterHolder.GetRW()->pNext = pBlockToInsert; - LOG((LF_BCL, LL_INFO100, "Level2 - CodeHeap [0x%p] - Insert block [%p, 0x%X] -> [%p, 0x%X] -> [%p, 0x%X]\n", this, + LOG((LF_BCL, LL_INFO100, "Level2 - CodeHeap [0x%p] - Insert block [%p, 0x%zx] -> [%p, 0x%zx] -> [%p, 0x%zx]\n", this, pPrevious, pPrevious->size, pBlockToInsert, pBlockToInsert->size, pCurrent, pCurrent->size)); @@ -607,17 +607,17 @@ void HostCodeHeap::AddToFreeList(TrackAllocation *pBlockToInsert, TrackAllocatio else { m_pFreeList = pBlockToInsert; - LOG((LF_BCL, LL_INFO100, "Level2 - CodeHeap [0x%p] - Insert block [%p, 0x%X] to head\n", this, pBlockToInsert, pBlockToInsert->size)); + LOG((LF_BCL, LL_INFO100, "Level2 - CodeHeap [0x%p] - Insert block [%p, 0x%zx] to head\n", this, pBlockToInsert, pBlockToInsert->size)); } // check for coalescing if ((BYTE*)pBlockToInsert + pBlockToInsert->size == (BYTE*)pCurrent) { // coalesce with next - LOG((LF_BCL, LL_INFO100, "Level2 - CodeHeap [0x%p] - Coalesce block [%p, 0x%X] with [%p, 0x%X] - new size 0x%X\n", this, - pBlockToInsert, pBlockToInsert->size, - pCurrent, pCurrent->size, - pCurrent->size + pBlockToInsert->size)); + LOG((LF_BCL, LL_INFO100, "Level2 - CodeHeap [0x%p] - Coalesce block [%p, 0x%zx] with [%p, 0x%zx] - new size 0x%zx\n", this, + pBlockToInsert, pBlockToInsert->size, + pCurrent, pCurrent->size, + pCurrent->size + pBlockToInsert->size)); pBlockToInsertRW->pNext = pCurrent->pNext; pBlockToInsertRW->size += pCurrent->size; } @@ -625,7 +625,7 @@ void HostCodeHeap::AddToFreeList(TrackAllocation *pBlockToInsert, TrackAllocatio if (pPrevious && (BYTE*)pPrevious + pPrevious->size == (BYTE*)pBlockToInsert) { // coalesce with previous - LOG((LF_BCL, LL_INFO100, "Level2 - CodeHeap [0x%p] - Coalesce block [%p, 0x%X] with [%p, 0x%X] - new size 0x%X\n", this, + LOG((LF_BCL, LL_INFO100, "Level2 - CodeHeap [0x%p] - Coalesce block [%p, 0x%zx] with [%p, 0x%zx] - new size 0x%zx\n", this, pPrevious, pPrevious->size, pBlockToInsert, pBlockToInsert->size, pPrevious->size + pBlockToInsert->size)); @@ -646,7 +646,7 @@ void HostCodeHeap::AddToFreeList(TrackAllocation *pBlockToInsert, TrackAllocatio if ((BYTE*)pPrevious + pPrevious->size == (BYTE*)pBlockToInsert) { // coalesce with previous - LOG((LF_BCL, LL_INFO100, "Level2 - CodeHeap [0x%p] - Coalesce block [%p, 0x%X] with [%p, 0x%X] - new size 0x%X\n", this, + LOG((LF_BCL, LL_INFO100, "Level2 - CodeHeap [0x%p] - Coalesce block [%p, 0x%zx] with [%p, 0x%zx] - new size 0x%zx\n", this, pPrevious, pPrevious->size, pBlockToInsert, pBlockToInsert->size, pPrevious->size + pBlockToInsert->size)); @@ -655,7 +655,7 @@ void HostCodeHeap::AddToFreeList(TrackAllocation *pBlockToInsert, TrackAllocatio else { previousWriterHolder2.GetRW()->pNext = pBlockToInsert; - LOG((LF_BCL, LL_INFO100, "Level2 - CodeHeap [0x%p] - Insert block [%p, 0x%X] to end after [%p, 0x%X]\n", this, + LOG((LF_BCL, LL_INFO100, "Level2 - CodeHeap [0x%p] - Insert block [%p, 0x%zx] to end after [%p, 0x%zx]\n", this, pBlockToInsert, pBlockToInsert->size, pPrevious, pPrevious->size)); } @@ -666,7 +666,7 @@ void HostCodeHeap::AddToFreeList(TrackAllocation *pBlockToInsert, TrackAllocatio // first in the list pBlockToInsertRW->pNext = m_pFreeList; m_pFreeList = pBlockToInsert; - LOG((LF_BCL, LL_INFO100, "Level2 - CodeHeap [0x%p] - Insert block [%p, 0x%X] to head\n", this, + LOG((LF_BCL, LL_INFO100, "Level2 - CodeHeap [0x%p] - Insert block [%p, 0x%zx] to head\n", this, m_pFreeList, m_pFreeList->size)); } @@ -741,7 +741,7 @@ HostCodeHeap::TrackAllocation* HostCodeHeap::AllocMemory_NoThrow(size_t header, if (totalRequiredSize > m_ApproximateLargestBlock) return NULL; - LOG((LF_BCL, LL_INFO100, "Level2 - CodeHeap [0x%p] - Allocation requested 0x%X\n", this, size)); + LOG((LF_BCL, LL_INFO100, "Level2 - CodeHeap [0x%p] - Allocation requested 0x%zx\n", this, size)); TrackAllocation* pTracker = AllocFromFreeList(header, size, alignment, reserveForJumpStubs); if (!pTracker) @@ -784,7 +784,7 @@ HostCodeHeap::TrackAllocation* HostCodeHeap::AllocMemory_NoThrow(size_t header, } else { - LOG((LF_BCL, LL_INFO100, "Level2 - CodeHeap [0x%p] - allocation failed:\n\tm_pLastAvailableCommittedAddr: 0x%X\n\tsizeToCommit: 0x%X\n\tm_pBaseAddr: 0x%X\n\tm_TotalBytesAvailable: 0x%X\n", this, m_pLastAvailableCommittedAddr, sizeToCommit, m_pBaseAddr, m_TotalBytesAvailable)); + LOG((LF_BCL, LL_INFO100, "Level2 - CodeHeap [0x%p] - allocation failed:\n\tm_pLastAvailableCommittedAddr: %p\n\tsizeToCommit: 0x%zx\n\tm_pBaseAddr: %p\n\tm_TotalBytesAvailable: 0x%zx\n", this, m_pLastAvailableCommittedAddr, sizeToCommit, m_pBaseAddr, m_TotalBytesAvailable)); // Update largest available block size m_ApproximateLargestBlock = totalRequiredSize - 1; } @@ -1631,7 +1631,7 @@ void* ChunkAllocator::New(size_t size) size = ALIGN_UP(size, sizeof(void *)); BYTE *pNewBlock = NULL; - LOG((LF_BCL, LL_INFO100, "Level2 - DM - Allocator [0x%p] - allocation requested 0x%X, available 0x%X\n", this, size, (m_pData) ? ((size_t*)m_pData)[1] : 0)); + LOG((LF_BCL, LL_INFO100, "Level2 - DM - Allocator [0x%p] - allocation requested 0x%zx, available 0x%zx\n", this, size, (m_pData) ? ((size_t*)m_pData)[1] : 0)); if (m_pData) { // we may have room available @@ -1641,7 +1641,7 @@ void* ChunkAllocator::New(size_t size) LOG((LF_BCL, LL_INFO100, "Level2 - DM - Allocator [0x%p] - reusing block {0x%p}\n", this, m_pData)); ((size_t*)m_pData)[1] = available - size; pNewBlock = (m_pData + CHUNK_SIZE - available); - LOG((LF_BCL, LL_INFO100, "Level2 - DM - Allocator [0x%p] - ptr -> 0x%p, available 0x%X\n", this, pNewBlock, ((size_t*)m_pData)[1])); + LOG((LF_BCL, LL_INFO100, "Level2 - DM - Allocator [0x%p] - ptr -> 0x%p, available 0x%zx\n", this, pNewBlock, ((size_t*)m_pData)[1])); return pNewBlock; } } @@ -1689,7 +1689,7 @@ void* ChunkAllocator::New(size_t size) } pNewBlock += (sizeof(void*) * 2); - LOG((LF_BCL, LL_INFO100, "Level2 - DM - Allocator [0x%p] - ptr -> 0x%p, available 0x%X\n", this, pNewBlock, ((size_t*)m_pData)[1])); + LOG((LF_BCL, LL_INFO100, "Level2 - DM - Allocator [0x%p] - ptr -> 0x%p, available 0x%zx\n", this, pNewBlock, ((size_t*)m_pData)[1])); return pNewBlock; } diff --git a/src/runtime/src/coreclr/vm/eedbginterfaceimpl.cpp b/src/runtime/src/coreclr/vm/eedbginterfaceimpl.cpp index 4c15f57eba34..e6dc526fca9e 100644 --- a/src/runtime/src/coreclr/vm/eedbginterfaceimpl.cpp +++ b/src/runtime/src/coreclr/vm/eedbginterfaceimpl.cpp @@ -189,15 +189,15 @@ OBJECTHANDLE EEDbgInterfaceImpl::GetHandleFromObject(void *obj, { oh = pAppDomain->CreateStrongHandle(ObjectToOBJECTREF((Object *)obj)); - LOG((LF_CORDB, LL_INFO1000, "EEI::GHFO: Given objectref 0x%x," - "created strong handle 0x%x!\n", obj, oh)); + LOG((LF_CORDB, LL_INFO1000, "EEI::GHFO: Given objectref %p," + "created strong handle %p!\n", obj, oh)); } else { oh = pAppDomain->CreateLongWeakHandle( ObjectToOBJECTREF((Object *)obj)); - LOG((LF_CORDB, LL_INFO1000, "EEI::GHFO: Given objectref 0x%x," - "created long weak handle 0x%x!\n", obj, oh)); + LOG((LF_CORDB, LL_INFO1000, "EEI::GHFO: Given objectref %p," + "created long weak handle %p!\n", obj, oh)); } return oh; @@ -213,7 +213,7 @@ void EEDbgInterfaceImpl::DbgDestroyHandle(OBJECTHANDLE oh, } CONTRACTL_END; - LOG((LF_CORDB, LL_INFO1000, "EEI::GHFO: Destroyed given handle 0x%x," + LOG((LF_CORDB, LL_INFO1000, "EEI::GHFO: Destroyed given handle %p," "fStrong: 0x%x!\n", oh, fStrongNewRef)); if (fStrongNewRef) @@ -282,7 +282,7 @@ bool EEDbgInterfaceImpl::StartSuspendForDebug(AppDomain *pAppDomain, } CONTRACTL_END; - LOG((LF_CORDB,LL_INFO1000, "EEDbgII:SSFD: start suspend on AD:0x%x\n", + LOG((LF_CORDB,LL_INFO1000, "EEDbgII:SSFD: start suspend on AD:%p\n", pAppDomain)); bool result = Thread::SysStartSuspendForDebug(pAppDomain); @@ -1334,7 +1334,7 @@ void EEDbgInterfaceImpl::SetDebugState(Thread *pThread, _ASSERTE(state == THREAD_SUSPEND || state == THREAD_RUN); - LOG((LF_CORDB,LL_INFO10000,"EEDbg:Setting thread 0x%x (ID:0x%x) to 0x%x\n", pThread, pThread->GetThreadId(), state)); + LOG((LF_CORDB,LL_INFO10000,"EEDbg:Setting thread %p (ID:0x%x) to 0x%x\n", pThread, pThread->GetThreadId(), state)); if (state == THREAD_SUSPEND) { @@ -1405,7 +1405,7 @@ CorDebugUserState EEDbgInterfaceImpl::GetPartialUserState(Thread *pThread) ret |= (unsigned)USER_WAIT_SLEEP_JOIN; } - LOG((LF_CORDB,LL_INFO1000, "EEDbgII::GUS: thread 0x%x (id:0x%x)" + LOG((LF_CORDB,LL_INFO1000, "EEDbgII::GUS: thread %p (id:0x%x)" " userThreadState is 0x%x\n", pThread, pThread->GetThreadId(), ret)); return (CorDebugUserState)ret; diff --git a/src/runtime/src/coreclr/vm/eetoprofinterfaceimpl.cpp b/src/runtime/src/coreclr/vm/eetoprofinterfaceimpl.cpp index 1230467d2467..ce72d2b75278 100644 --- a/src/runtime/src/coreclr/vm/eetoprofinterfaceimpl.cpp +++ b/src/runtime/src/coreclr/vm/eetoprofinterfaceimpl.cpp @@ -1086,7 +1086,7 @@ UINT_PTR EEToProfInterfaceImpl::EEFunctionIDMapper(FunctionID funcId, BOOL * pbH CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO100, "**PROF: Calling profiler's FunctionIDMapper2. funcId: 0x%p. clientData: 0x%p.\n", - funcId, + (void*)funcId, m_pProfilersFuncIDMapper2ClientData)); // The attached profiler may not want to hook this function, so ask it @@ -1098,7 +1098,7 @@ UINT_PTR EEToProfInterfaceImpl::EEFunctionIDMapper(FunctionID funcId, BOOL * pbH CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO100, "**PROF: Calling profiler's FunctionIDMapper. funcId: 0x%p.\n", - funcId)); + (void*)funcId)); // The attached profiler may not want to hook this function, so ask it clientId = m_pProfilersFuncIDMapper(funcId, pbHookFunction); @@ -2885,7 +2885,7 @@ HRESULT EEToProfInterfaceImpl::ThreadCreated(ThreadID threadId) (LF_CORPROF, LL_INFO100, "**PROF: Notifying profiler of created thread. ThreadId: 0x%p.\n", - threadId)); + (void*)threadId)); // Notify the profiler of the newly created thread. { @@ -2949,7 +2949,7 @@ HRESULT EEToProfInterfaceImpl::ThreadDestroyed(ThreadID threadId) (LF_CORPROF, LL_INFO100, "**PROF: Notifying profiler of destroyed thread. ThreadId: 0x%p.\n", - threadId)); + (void*)threadId)); // From now on, issue no more callbacks for this thread SetProfilerCallbacksAllowedForThread((Thread *) threadId, FALSE); @@ -2993,7 +2993,7 @@ HRESULT EEToProfInterfaceImpl::ThreadAssignedToOSThread(ThreadID managedThreadId (LF_CORPROF, LL_INFO100, "**PROF: Notifying profiler of thread assignment. ThreadId: 0x%p, OSThreadId: 0x%08x\n", - managedThreadId, + (void*)managedThreadId, osThreadId)); // Notify the profiler of the thread being assigned to the OS thread @@ -3113,7 +3113,7 @@ HRESULT EEToProfInterfaceImpl::JITCompilationFinished(FunctionID functionId, CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO1000, "**PROF: JITCompilationFinished 0x%p, hr=0x%08x.\n", - functionId, + (void*)functionId, hrStatus)); _ASSERTE(functionId); @@ -3152,7 +3152,7 @@ HRESULT EEToProfInterfaceImpl::JITCompilationStarted(FunctionID functionId, CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO1000, "**PROF: JITCompilationStarted 0x%p.\n", - functionId)); + (void*)functionId)); // Currently JITCompilationStarted is always called with fIsSafeToBlock==TRUE. If this ever changes, // it's safe to remove this assert, but this should serve as a trigger to change our @@ -3183,7 +3183,7 @@ HRESULT EEToProfInterfaceImpl::DynamicMethodUnloaded(FunctionID functionId) CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO1000, "**PROF: DynamicMethodUnloaded 0x%p.\n", - functionId)); + (void*)functionId)); _ASSERTE(functionId); @@ -3219,7 +3219,7 @@ HRESULT EEToProfInterfaceImpl::DynamicMethodJITCompilationFinished(FunctionID fu CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO1000, "**PROF: DynamicMethodJITCompilationFinished 0x%p.\n", - functionId)); + (void*)functionId)); _ASSERTE(functionId); @@ -3256,7 +3256,7 @@ HRESULT EEToProfInterfaceImpl::DynamicMethodJITCompilationStarted(FunctionID fun CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO1000, "**PROF: DynamicMethodJITCompilationStarted 0x%p.\n", - functionId)); + (void*)functionId)); _ASSERTE(functionId); @@ -3304,7 +3304,7 @@ HRESULT EEToProfInterfaceImpl::JITCachedFunctionSearchStarted( CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO1000, "**PROF: JITCachedFunctionSearchStarted 0x%p.\n", - functionId)); + (void*)functionId)); _ASSERTE(functionId); _ASSERTE(pbUseCachedFunction != NULL); @@ -3342,7 +3342,7 @@ HRESULT EEToProfInterfaceImpl::JITCachedFunctionSearchFinished( CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO1000, "**PROF: JITCachedFunctionSearchFinished 0x%p, %s.\n", - functionId, + (void*)functionId, (result == COR_PRF_CACHED_FUNCTION_FOUND ? "Cached function found" : "Cached function not found"))); @@ -3391,8 +3391,8 @@ HRESULT EEToProfInterfaceImpl::JITInlining( CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO1000, "**PROF: JITInlining caller: 0x%p, callee: 0x%p.\n", - callerId, - calleeId)); + (void*)callerId, + (void*)calleeId)); _ASSERTE(callerId); _ASSERTE(calleeId); @@ -3432,7 +3432,7 @@ HRESULT EEToProfInterfaceImpl::ReJITCompilationStarted( CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO1000, "**PROF: ReJITCompilationStarted 0x%p 0x%p.\n", - functionId, reJitId)); + (void*)functionId, (void*)reJitId)); // Should only be called on profilers that support ICorProfilerCallback4 _ASSERTE(m_pCallback4 != NULL); @@ -3480,8 +3480,8 @@ HRESULT EEToProfInterfaceImpl::GetReJITParameters( CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO1000, - "**PROF: GetReJITParameters 0x%p 0x%p.\n", - moduleId, methodId)); + "**PROF: GetReJITParameters 0x%p 0x%x.\n", + (void*)moduleId, methodId)); // Should only be called on profilers that support ICorProfilerCallback4 _ASSERTE(m_pCallback4 != NULL); @@ -3524,7 +3524,7 @@ HRESULT EEToProfInterfaceImpl::ReJITCompilationFinished( CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO1000, "**PROF: ReJITCompilationFinished 0x%p 0x%p hr=0x%x.\n", - functionId, reJitId, hrStatus)); + (void*)functionId, (void*)reJitId, hrStatus)); // Should only be called on profilers that support ICorProfilerCallback4 _ASSERTE(m_pCallback4 != NULL); @@ -3567,7 +3567,7 @@ HRESULT EEToProfInterfaceImpl::ReJITError( CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO1000, "**PROF: ReJITError 0x%p 0x%x 0x%p 0x%x.\n", - moduleId, methodId, functionId, hrStatus)); + (void*)moduleId, methodId, (void*)functionId, hrStatus)); // Should only be called on profilers that support ICorProfilerCallback4 _ASSERTE(m_pCallback4 != NULL); @@ -3608,7 +3608,7 @@ HRESULT EEToProfInterfaceImpl::ModuleLoadStarted(ModuleID moduleId) CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO10, "**PROF: ModuleLoadStarted 0x%p.\n", - moduleId)); + (void*)moduleId)); _ASSERTE(moduleId != 0); @@ -3646,7 +3646,7 @@ HRESULT EEToProfInterfaceImpl::ModuleLoadFinished( CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO10, "**PROF: ModuleLoadFinished 0x%p.\n", - moduleId)); + (void*)moduleId)); _ASSERTE(moduleId != 0); @@ -3683,7 +3683,7 @@ HRESULT EEToProfInterfaceImpl::ModuleUnloadStarted( CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO10, "**PROF: ModuleUnloadStarted 0x%p.\n", - moduleId)); + (void*)moduleId)); _ASSERTE(moduleId != 0); @@ -3720,7 +3720,7 @@ HRESULT EEToProfInterfaceImpl::ModuleUnloadFinished( CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO10, "**PROF: ModuleUnloadFinished 0x%p.\n", - moduleId)); + (void*)moduleId)); _ASSERTE(moduleId != 0); { // All callbacks are really NOTHROW, but that's enforced partially by the profiler, @@ -3755,8 +3755,8 @@ HRESULT EEToProfInterfaceImpl::ModuleAttachedToAssembly( CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO10, "**PROF: ModuleAttachedToAssembly 0x%p, 0x%p.\n", - moduleId, - AssemblyId)); + (void*)moduleId, + (void*)AssemblyId)); _ASSERTE(moduleId != 0); @@ -3790,7 +3790,7 @@ HRESULT EEToProfInterfaceImpl::ModuleInMemorySymbolsUpdated(ModuleID moduleId) CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO10, "**PROF: ModuleInMemorySymbolsUpdated. moduleId: 0x%p.\n", - moduleId + (void*)moduleId )); HRESULT hr = S_OK; @@ -3835,7 +3835,7 @@ HRESULT EEToProfInterfaceImpl::ClassLoadStarted( CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO100, "**PROF: ClassLoadStarted 0x%p.\n", - classId)); + (void*)classId)); _ASSERTE(classId); @@ -3874,7 +3874,7 @@ HRESULT EEToProfInterfaceImpl::ClassLoadFinished( CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO100, "**PROF: ClassLoadFinished 0x%p, 0x%08x.\n", - classId, + (void*)classId, hrStatus)); _ASSERTE(classId); @@ -3916,7 +3916,7 @@ HRESULT EEToProfInterfaceImpl::ClassUnloadStarted( CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO100, "**PROF: ClassUnloadStarted 0x%p.\n", - classId)); + (void*)classId)); _ASSERTE(classId); @@ -3955,7 +3955,7 @@ HRESULT EEToProfInterfaceImpl::ClassUnloadFinished( CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO100, "**PROF: ClassUnloadFinished 0x%p, 0x%08x.\n", - classId, + (void*)classId, hrStatus)); _ASSERTE(classId); @@ -3995,7 +3995,7 @@ HRESULT EEToProfInterfaceImpl::AppDomainCreationStarted( CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO10, "**PROF: AppDomainCreationStarted 0x%p.\n", - appDomainId)); + (void*)appDomainId)); _ASSERTE(appDomainId != 0); @@ -4032,7 +4032,7 @@ HRESULT EEToProfInterfaceImpl::AppDomainCreationFinished( CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO10, "**PROF: AppDomainCreationFinished 0x%p, 0x%08x.\n", - appDomainId, + (void*)appDomainId, hrStatus)); _ASSERTE(appDomainId != 0); @@ -4068,7 +4068,7 @@ HRESULT EEToProfInterfaceImpl::AppDomainShutdownStarted( CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO10, "**PROF: AppDomainShutdownStarted 0x%p.\n", - appDomainId)); + (void*)appDomainId)); _ASSERTE(appDomainId != 0); @@ -4104,7 +4104,7 @@ HRESULT EEToProfInterfaceImpl::AppDomainShutdownFinished( CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO10, "**PROF: AppDomainShutdownFinished 0x%p, 0x%08x.\n", - appDomainId, + (void*)appDomainId, hrStatus)); _ASSERTE(appDomainId != 0); @@ -4146,7 +4146,7 @@ HRESULT EEToProfInterfaceImpl::AssemblyLoadStarted( CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO10, "**PROF: AssemblyLoadStarted 0x%p.\n", - assemblyId)); + (void*)assemblyId)); _ASSERTE(assemblyId != 0); @@ -4184,7 +4184,7 @@ HRESULT EEToProfInterfaceImpl::AssemblyLoadFinished( CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO10, "**PROF: AssemblyLoadFinished 0x%p, 0x%08x.\n", - assemblyId, + (void*)assemblyId, hrStatus)); _ASSERTE(assemblyId != 0); @@ -4220,7 +4220,7 @@ HRESULT EEToProfInterfaceImpl::AssemblyUnloadStarted( CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO10, "**PROF: AssemblyUnloadStarted 0x%p.\n", - assemblyId)); + (void*)assemblyId)); _ASSERTE(assemblyId != 0); @@ -4256,7 +4256,7 @@ HRESULT EEToProfInterfaceImpl::AssemblyUnloadFinished( CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO10, "**PROF: AssemblyUnloadFinished 0x%p, 0x%08x.\n", - assemblyId, + (void*)assemblyId, hrStatus)); _ASSERTE(assemblyId != 0); @@ -4297,7 +4297,7 @@ HRESULT EEToProfInterfaceImpl::UnmanagedToManagedTransition( CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO10000, "**PROF: UnmanagedToManagedTransition 0x%p.\n", - functionId)); + (void*)functionId)); _ASSERTE(reason == COR_PRF_TRANSITION_CALL || reason == COR_PRF_TRANSITION_RETURN); @@ -4334,7 +4334,7 @@ HRESULT EEToProfInterfaceImpl::ManagedToUnmanagedTransition( CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO10000, "**PROF: ManagedToUnmanagedTransition 0x%p.\n", - functionId)); + (void*)functionId)); { // All callbacks are really NOTHROW, but that's enforced partially by the profiler, @@ -4371,7 +4371,7 @@ HRESULT EEToProfInterfaceImpl::ExceptionThrown( CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO1000, "**PROF: ExceptionThrown. ObjectID: 0x%p. ThreadID: 0x%p\n", - thrownObjectId, + (void*)thrownObjectId, GetThreadNULLOk())); { @@ -4406,7 +4406,7 @@ HRESULT EEToProfInterfaceImpl::ExceptionSearchFunctionEnter( LL_INFO1000, "**PROF: ExceptionSearchFunctionEnter. ThreadID: 0x%p, functionId: 0x%p\n", GetThreadNULLOk(), - functionId)); + (void*)functionId)); { // All callbacks are really NOTHROW, but that's enforced partially by the profiler, @@ -4471,7 +4471,7 @@ HRESULT EEToProfInterfaceImpl::ExceptionSearchFilterEnter(FunctionID functionId) LL_INFO1000, "**PROF: ExceptionSearchFilterEnter. ThreadID: 0x%p, functionId: 0x%p\n", GetThreadNULLOk(), - functionId)); + (void*)functionId)); { // All callbacks are really NOTHROW, but that's enforced partially by the profiler, @@ -4583,7 +4583,7 @@ HRESULT EEToProfInterfaceImpl::ExceptionUnwindFunctionEnter(FunctionID functionI LL_INFO1000, "**PROF: ExceptionUnwindFunctionEnter. ThreadID: 0x%p, functionId: 0x%p\n", GetThreadNULLOk(), - functionId)); + (void*)functionId)); { // All callbacks are really NOTHROW, but that's enforced partially by the profiler, @@ -4654,7 +4654,7 @@ HRESULT EEToProfInterfaceImpl::ExceptionUnwindFinallyEnter(FunctionID functionId LL_INFO1000, "**PROF: ExceptionUnwindFinallyEnter. ThreadID: 0x%p, functionId: 0x%p\n", GetThreadNULLOk(), - functionId)); + (void*)functionId)); { // All callbacks are really NOTHROW, but that's enforced partially by the profiler, @@ -4724,7 +4724,7 @@ HRESULT EEToProfInterfaceImpl::ExceptionCatcherEnter(FunctionID functionId, Obje (LF_CORPROF, LL_INFO1000, "**PROF: ExceptionCatcherEnter. ThreadID: 0x%p, functionId: 0x%p\n", GetThreadNULLOk(), - functionId)); + (void*)functionId)); { // All callbacks are really NOTHROW, but that's enforced partially by the profiler, @@ -4798,8 +4798,8 @@ HRESULT EEToProfInterfaceImpl::COMClassicVTableCreated( CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO100, - "**PROF: COMClassicWrapperCreated %#x %#08x... %#x %d.\n", - classId, + "**PROF: COMClassicWrapperCreated %#lx %#08x... %p %d.\n", + (unsigned long)classId, implementedIID.Data1, pVTable, cSlots)); @@ -4841,8 +4841,8 @@ HRESULT EEToProfInterfaceImpl::COMClassicVTableDestroyed( CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO100, - "**PROF: COMClassicWrapperDestroyed %#x %#08x... %#x.\n", - classId, + "**PROF: COMClassicWrapperDestroyed %#lx %#08x... %p.\n", + (unsigned long)classId, implementedIID.Data1, pVTable)); @@ -5083,8 +5083,8 @@ HRESULT EEToProfInterfaceImpl::RuntimeThreadSuspended(ThreadID suspendedThreadId CHECK_PROFILER_STATUS(kEE2PNone); - LOG((LF_CORPROF, LL_INFO1000, "**PROF: RuntimeThreadSuspended. ThreadID 0x%p.\n", - suspendedThreadId)); + LOG((LF_CORPROF, LL_INFO1000, "**PROF: RuntimeThreadSuspended. ThreadID 0x%p.\n", + (void*)suspendedThreadId)); // NOTE: We're notrigger, so we cannot switch to preemptive mode. @@ -5179,7 +5179,7 @@ HRESULT EEToProfInterfaceImpl::RuntimeThreadResumed(ThreadID resumedThreadId) CHECK_PROFILER_STATUS(kEE2PNone); - LOG((LF_CORPROF, LL_INFO1000, "**PROF: RuntimeThreadResumed. ThreadID 0x%p.\n", resumedThreadId)); + LOG((LF_CORPROF, LL_INFO1000, "**PROF: RuntimeThreadResumed. ThreadID 0x%p.\n", (void*)resumedThreadId)); // NOTE: We're notrigger, so we cannot switch to preemptive mode. @@ -5233,8 +5233,8 @@ HRESULT EEToProfInterfaceImpl::ObjectAllocated( CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, LL_INFO1000, "**PROF: ObjectAllocated. ObjectID: 0x%p. ClassID: 0x%p\n", - objectId, - classId)); + (void*)objectId, + (void*)classId)); { // All callbacks are really NOTHROW, but that's enforced partially by the profiler, diff --git a/src/runtime/src/coreclr/vm/eetwain.cpp b/src/runtime/src/coreclr/vm/eetwain.cpp index 1a7dad8946a6..57ef77862b02 100644 --- a/src/runtime/src/coreclr/vm/eetwain.cpp +++ b/src/runtime/src/coreclr/vm/eetwain.cpp @@ -1796,7 +1796,8 @@ void EECodeManager::ResumeAfterCatch(CONTEXT *pContext, size_t targetSSP, bool f if (uAbortAddr) { - STRESS_LOG2(LF_EH, LL_INFO10, "Thread abort in progress, resuming under control: IP=%p, SP=%p\n", dwResumePC, GetSP(pContext)); + STRESS_LOG2(LF_EH, LL_INFO10, "Thread abort in progress, resuming under control: IP=%p, SP=%p\n", + (void*)dwResumePC, (void*)GetSP(pContext)); // The dwResumePC is passed to the THROW_CONTROL_FOR_THREAD_FUNCTION ASM helper so that // it can establish it as its return address and native stack unwinding can work properly. @@ -1818,7 +1819,8 @@ void EECodeManager::ResumeAfterCatch(CONTEXT *pContext, size_t targetSSP, bool f } else { - STRESS_LOG2(LF_EH, LL_INFO100, "Resuming after exception at IP=%p, SP=%p\n", GetIP(pContext), GetSP(pContext)); + STRESS_LOG2(LF_EH, LL_INFO100, "Resuming after exception at IP=%p, SP=%p\n", (void*)GetIP(pContext), + (void*)GetSP(pContext)); } ClrRestoreNonvolatileContext(pContext, targetSSP); diff --git a/src/runtime/src/coreclr/vm/encee.cpp b/src/runtime/src/coreclr/vm/encee.cpp index 7349ce9f415c..8471ed781a80 100644 --- a/src/runtime/src/coreclr/vm/encee.cpp +++ b/src/runtime/src/coreclr/vm/encee.cpp @@ -650,7 +650,7 @@ PCODE EditAndContinueModule::JitUpdatedFunction( MethodDesc *pMD, "EACM::JITUpdatedFunction JIT failed with the following exception:\n\n"); errorMessage.Append(exceptionMessage); DbgAssertDialog(__FILE__, __LINE__, errorMessage.GetUTF8()); - LOG((LF_ENC, LL_INFO100, errorMessage.GetUTF8())); + LOG((LF_ENC, LL_INFO100, "%s", errorMessage.GetUTF8())); } #endif } EX_END_CATCH @@ -895,7 +895,7 @@ NOINLINE void EditAndContinueModule::FixContextAndResume( // Set the new IP // Note that all we're really doing here is setting the IP register. We unfortunately don't // share any code with the implementation of debugger SetIP, despite the similarities. - LOG((LF_ENC, LL_INFO100, "EACM::ResumeInUpdatedFunction: Resume at EIP=%p\n", pNewCodeInfo->GetCodeAddress())); + LOG((LF_ENC, LL_INFO100, "EACM::ResumeInUpdatedFunction: Resume at EIP=%p\n", (void*)pNewCodeInfo->GetCodeAddress())); Thread *pCurThread = GetThread(); pCurThread->SetFilterContext(pContext); @@ -1203,7 +1203,7 @@ EnCAddedField *EnCAddedField::Allocate(OBJECTREF thisPointer, EnCFieldDesc *pFD) } CONTRACTL_END; - LOG((LF_ENC, LL_INFO1000, "\tEnCAF:Allocate for this %p, FD %p\n", OBJECTREFToObject(thisPointer), pFD->GetMemberDef())); + LOG((LF_ENC, LL_INFO1000, "\tEnCAF:Allocate for this %p, FD 0x%x\n", OBJECTREFToObject(thisPointer), pFD->GetMemberDef())); // Create a new EnCAddedField instance EnCAddedField *pEntry = new EnCAddedField; diff --git a/src/runtime/src/coreclr/vm/excep.cpp b/src/runtime/src/coreclr/vm/excep.cpp index 24cc25534928..f252a2c2c161 100644 --- a/src/runtime/src/coreclr/vm/excep.cpp +++ b/src/runtime/src/coreclr/vm/excep.cpp @@ -1138,7 +1138,7 @@ EHRangeTree::EHRangeTree(IJitManager* pIJM, } } - LOG((LF_CORDB, LL_INFO10000, "EHRT::CC: m_ehcount:0x%x, m_rgClauses:0%x\n", + LOG((LF_CORDB, LL_INFO10000, "EHRT::CC: m_ehcount:0x%x, m_rgClauses:%p\n", m_EHCount, m_rgClauses)); m_rgNodes = new (nothrow) EHRangeTreeNode[m_EHCount+1]; @@ -1152,7 +1152,7 @@ EHRangeTree::EHRangeTree(IJitManager* pIJM, m_root = &(m_rgNodes[m_EHCount]); m_root->MarkAsRoot(methodSize + 1); - LOG((LF_CORDB, LL_INFO10000, "EHRT::CC: rgNodes:0x%x\n", m_rgNodes)); + LOG((LF_CORDB, LL_INFO10000, "EHRT::CC: rgNodes:%p\n", m_rgNodes)); if (m_EHCount ==0) { @@ -1171,10 +1171,10 @@ EHRangeTree::EHRangeTree(IJitManager* pIJM, pIJM->GetNextEHClause(&pEnumState, pEHClause); - LOG((LF_CORDB, LL_INFO10000, "EHRT::CC: EHRTT_JIT_MANAGER got clause\n", i)); + LOG((LF_CORDB, LL_INFO10000, "EHRT::CC: EHRTT_JIT_MANAGER got clause\n")); LOG((LF_CORDB, LL_INFO10000, "EHRT::CC: clause 0x%x," - "addrof:0x%x\n", i, pEHClause )); + "addrof:%p\n", i, pEHClause )); _ASSERTE(pEHClause->HandlerEndPC != (DWORD) -1); // remove, only protects against a deprecated convention @@ -1922,7 +1922,7 @@ ReplaceExceptionContextRecord(CONTEXT *pTarget, CONTEXT *pSource) memcpy(pTarget, pSource, offsetof(CONTEXT, ExtendedRegisters)); } STRESS_LOG3(LF_SYNC, LL_INFO1000, "ReSet thread context EIP = %p ESP = %p EBP = %p\n", - GetIP((CONTEXT*)pTarget), GetSP((CONTEXT*)pTarget), GetFP((CONTEXT*)pTarget)); + (void*)GetIP((CONTEXT*)pTarget), (void*)GetSP((CONTEXT*)pTarget), (void*)GetFP((CONTEXT*)pTarget)); #else // !CONTEXT_EXTENDED_REGISTERS @@ -2569,7 +2569,8 @@ void StackTraceInfo::AppendElement(OBJECTREF pThrowable, UINT_PTR currentIP, UIN BOOL fRaisingForeignException = pCurTES->IsRaisingForeignException(); pCurTES->ResetRaisingForeignException(); - LOG((LF_EH, LL_INFO10000, "StackTraceInfo::AppendElement IP = %p, SP = %p, %s::%s\n", currentIP, currentSP, pFunc ? pFunc->m_pszDebugClassName : "", pFunc ? pFunc->m_pszDebugMethodName : "" )); + LOG((LF_EH, LL_INFO10000, "StackTraceInfo::AppendElement IP = %p, SP = %p, %s::%s\n", (void*)currentIP, + (void*)currentSP, pFunc ? pFunc->m_pszDebugClassName : "", pFunc ? pFunc->m_pszDebugMethodName : "" )); // Do not save stacktrace to preallocated exception. These are shared. if (CLRException::IsPreallocatedExceptionObject(pThrowable)) @@ -6832,8 +6833,9 @@ LONG NotifyOfCHFFilterWrapper( if (pThread) { LOG((LF_EH, LL_INFO1000, ", Thread SP: %p, Exception SP: %p", - pThread->GetExceptionState()->GetContextRecord() ? GetSP(pThread->GetExceptionState()->GetContextRecord()) : (TADDR)NULL, - pExceptionInfo->ContextRecord ? GetSP(pExceptionInfo->ContextRecord) : (TADDR)NULL )); + (void*)(pThread->GetExceptionState()->GetContextRecord() ? + GetSP(pThread->GetExceptionState()->GetContextRecord()) : (TADDR)NULL), + (void*)(pExceptionInfo->ContextRecord ? GetSP(pExceptionInfo->ContextRecord) : (TADDR)NULL) )); } LOG((LF_EH, LL_INFO1000, "\n")); return ret; diff --git a/src/runtime/src/coreclr/vm/exceptionhandling.cpp b/src/runtime/src/coreclr/vm/exceptionhandling.cpp index ce81d4fdee39..b5227bca0507 100644 --- a/src/runtime/src/coreclr/vm/exceptionhandling.cpp +++ b/src/runtime/src/coreclr/vm/exceptionhandling.cpp @@ -131,8 +131,8 @@ void FixContext(PCONTEXT pContextRecord) #define FIXUPREG(reg, value) \ do { \ STRESS_LOG2(LF_GCROOTS, LL_INFO100, "Updating " #reg " %p to %p\n", \ - pContextRecord->reg, \ - (value)); \ + (void*)(size_t)(pContextRecord->reg), \ + (void*)(size_t)(value)); \ pContextRecord->reg = (value); \ } while (0) @@ -319,8 +319,8 @@ void ExInfo::UpdateNonvolatileRegisters(CONTEXT *pContextRecord, REGDISPLAY *pRe if (pRegDisplay->pCurrentContextPointers->reg != NULL) \ { \ STRESS_LOG3(LF_GCROOTS, LL_INFO100, "Updating " #reg " %p to %p from %p\n", \ - pContextRecord->reg, \ - *pRegDisplay->pCurrentContextPointers->reg, \ + (void*)(size_t)pContextRecord->reg, \ + (void*)(size_t)*pRegDisplay->pCurrentContextPointers->reg, \ pRegDisplay->pCurrentContextPointers->reg); \ pContextRecord->reg = *pRegDisplay->pCurrentContextPointers->reg; \ } \ @@ -885,7 +885,7 @@ static void DoEHLog( memset(pPadding, '.', cch); pPadding[cch] = 0; - LOG((LF_EH, lvl, pPadding)); + LOG((LF_EH, lvl, "%s", pPadding)); } LogSpewValist(LF_EH, lvl, fmt, args); @@ -2419,7 +2419,7 @@ void ExInfo::StackRange::CombineWith(StackFrame sfCurrent, StackRange* pPrevious // previous tracker once they "escape" the previous tracker. STRESS_LOG3(LF_EH, LL_INFO100, "Initializing current StackRange with previous tracker's StackRange. sfCurrent: %p, prev low: %p, prev high: %p\n", - sfCurrent.SP, pPreviousRange->m_sfLowBound.SP, pPreviousRange->m_sfHighBound.SP); + (void*)sfCurrent.SP, (void*)pPreviousRange->m_sfLowBound.SP, (void*)pPreviousRange->m_sfHighBound.SP); *this = *pPreviousRange; } @@ -2517,7 +2517,7 @@ bool ExInfo::StackRange::IsConsistent() return true; } - LOG((LF_EH, LL_ERROR, "sp: low: %p high: %p\n", m_sfLowBound.SP, m_sfHighBound.SP)); + LOG((LF_EH, LL_ERROR, "sp: low: %p high: %p\n", (void*)m_sfLowBound.SP, (void*)m_sfHighBound.SP)); return false; } @@ -2670,7 +2670,7 @@ bool ExInfo::HasFrameBeenUnwoundByAnyActiveException(CrawlFrame * pCF) csfToCheck = CallerStackFrame((UINT_PTR)pCF->GetFrame()); } STRESS_LOG4(LF_EH|LF_GCROOTS, LL_INFO100, "CrawlFrame (%p): Frameless: %s %s: %p\n", - pCF, pCF->IsFrameless() ? "Yes" : "No", pCF->IsFrameless() ? "CallerSP" : "Address", csfToCheck.SP); + pCF, pCF->IsFrameless() ? "Yes" : "No", pCF->IsFrameless() ? "CallerSP" : "Address", (void*)csfToCheck.SP); } PTR_ExInfo pTopExInfo = (PTR_ExInfo)pTargetThread->GetExceptionState()->GetCurrentExceptionTracker(); @@ -2975,7 +2975,7 @@ StackFrame ExInfo::FindParentStackFrameHelper(CrawlFrame* pCF, lExit: ; STRESS_LOG3(LF_EH|LF_GCROOTS, LL_INFO100, "Returning 0x%p as the parent stack frame for %s 0x%p\n", - sfResult.SP, fIsFilterFunclet ? "filter funclet" : "funclet", csfCurrent.SP); + (void*)sfResult.SP, fIsFilterFunclet ? "filter funclet" : "funclet", (void*)csfCurrent.SP); return sfResult; } @@ -3393,7 +3393,7 @@ void CallCatchFunclet(OBJECTREF throwable, BYTE* pHandlerIP, REGDISPLAY* pvRegDi if (propagateExceptionCallback) { // A propagation callback was supplied. - STRESS_LOG3(LF_EH, LL_INFO100, "Deferring exception propagation to Callback = %p, IP = %p, SP = %p \n", propagateExceptionCallback, GetIP(pvRegDisplay->pCurrentContext), GetSP(pvRegDisplay->pCurrentContext)); + STRESS_LOG3(LF_EH, LL_INFO100, "Deferring exception propagation to Callback = %p, IP = %p, SP = %p \n", propagateExceptionCallback, (void*)GetIP(pvRegDisplay->pCurrentContext), (void*)GetSP(pvRegDisplay->pCurrentContext)); UpdateContextForPropagationCallback(propagateExceptionCallback, propagateExceptionContext, pvRegDisplay->pCurrentContext); GCX_PREEMP_NO_DTOR(); @@ -3441,7 +3441,7 @@ void CallCatchFunclet(OBJECTREF throwable, BYTE* pHandlerIP, REGDISPLAY* pvRegDi else #endif { - STRESS_LOG2(LF_EH, LL_INFO100, "Resuming propagation of managed exception through native frames at IP=%p, SP=%p\n", GetIP(pvRegDisplay->pCurrentContext), GetSP(pvRegDisplay->pCurrentContext)); + STRESS_LOG2(LF_EH, LL_INFO100, "Resuming propagation of managed exception through native frames at IP=%p, SP=%p\n", (void*)GetIP(pvRegDisplay->pCurrentContext), (void*)GetSP(pvRegDisplay->pCurrentContext)); #ifdef TARGET_WASM // wasm cannot unwind frames, so we let C++ exception handling do all the work PropagateExceptionThroughNativeFrames(OBJECTREFToObject(throwable), targetSp); @@ -3498,7 +3498,7 @@ void ResumeAtInterceptionLocation(REGDISPLAY* pvRegDisplay) SetIP(pvRegDisplay->pCurrentContext, uResumePC); - STRESS_LOG2(LF_EH, LL_INFO100, "Resuming at interception location at IP=%p, SP=%p\n", uResumePC, GetSP(pvRegDisplay->pCurrentContext)); + STRESS_LOG2(LF_EH, LL_INFO100, "Resuming at interception location at IP=%p, SP=%p\n", (void*)uResumePC, (void*)GetSP(pvRegDisplay->pCurrentContext)); codeInfo.GetCodeManager()->ResumeAfterCatch(pvRegDisplay->pCurrentContext, targetSSP, /* fIntercepted */ true); } diff --git a/src/runtime/src/coreclr/vm/gcenv.ee.common.cpp b/src/runtime/src/coreclr/vm/gcenv.ee.common.cpp index 6175c61a3b77..fb2e6b52f493 100644 --- a/src/runtime/src/coreclr/vm/gcenv.ee.common.cpp +++ b/src/runtime/src/coreclr/vm/gcenv.ee.common.cpp @@ -280,10 +280,10 @@ StackWalkAction GcStackCrawlCallBack(CrawlFrame* pCF, VOID* pData) #ifdef TARGET_X86 STRESS_LOG3(LF_GCROOTS, LL_INFO1000, "Scanning Frameless method %pM EIP = %p &EIP = %p\n", - pMD, GetControlPC(pCF->GetRegisterSet()), GetRegdisplayPCTAddr(pCF->GetRegisterSet())); + pMD, (void*)(size_t)GetControlPC(pCF->GetRegisterSet()), (void*)(size_t)GetRegdisplayPCTAddr(pCF->GetRegisterSet())); #else STRESS_LOG2(LF_GCROOTS, LL_INFO1000, "Scanning Frameless method %pM ControlPC = %p\n", - pMD, GetControlPC(pCF->GetRegisterSet())); + pMD, (void*)GetControlPC(pCF->GetRegisterSet())); #endif _ASSERTE(pMD != 0); @@ -312,7 +312,7 @@ StackWalkAction GcStackCrawlCallBack(CrawlFrame* pCF, VOID* pData) _ASSERTE(relOffsetOverride != NO_OVERRIDE_OFFSET); STRESS_LOG3(LF_GCROOTS, LL_INFO1000, "Setting override offset = %u for method %pM ControlPC = %p\n", - relOffsetOverride, pMD, GetControlPC(pCF->GetRegisterSet())); + relOffsetOverride, pMD, (void*)GetControlPC(pCF->GetRegisterSet())); } pCM->EnumGcRefs(pCF->GetRegisterSet(), @@ -336,7 +336,7 @@ StackWalkAction GcStackCrawlCallBack(CrawlFrame* pCF, VOID* pData) else { STRESS_LOG2(LF_GCROOTS, LL_INFO1000, "Skipping GC scanning in frame method at SP: %p, PC: %p\n", - GetRegdisplaySP(pCF->GetRegisterSet()), GetControlPC(pCF->GetRegisterSet())); + (void*)GetRegdisplaySP(pCF->GetRegisterSet()), (void*)GetControlPC(pCF->GetRegisterSet())); } // If we're executing a LCG dynamic method then we must promote the associated resolver to ensure it diff --git a/src/runtime/src/coreclr/vm/gcheaputilities.cpp b/src/runtime/src/coreclr/vm/gcheaputilities.cpp index 987e75fc22a0..e86508ab207f 100644 --- a/src/runtime/src/coreclr/vm/gcheaputilities.cpp +++ b/src/runtime/src/coreclr/vm/gcheaputilities.cpp @@ -184,7 +184,8 @@ HMODULE LoadStandaloneGc(LPCWSTR libFileName, LPCWSTR libFilePath) // if (!ValidateModuleName(libFileName)) { - LOG((LF_GC, LL_INFO100, "Invalid GC name found %s\n", libFileName)); + MAKE_UTF8PTR_FROMWIDE(libFileNameUtf8, libFileName); + LOG((LF_GC, LL_INFO100, "Invalid GC name found %s\n", libFileNameUtf8)); return nullptr; } diff --git a/src/runtime/src/coreclr/vm/gchelpers.cpp b/src/runtime/src/coreclr/vm/gchelpers.cpp index c961814b4966..ff0c2cbb656e 100644 --- a/src/runtime/src/coreclr/vm/gchelpers.cpp +++ b/src/runtime/src/coreclr/vm/gchelpers.cpp @@ -550,7 +550,7 @@ inline void LogAlloc(Object* object) if (LoggingOn(LF_GCALLOC, LL_INFO10)) { - LogSpewAlways("Allocated %5d bytes for %s_TYPE" FMT_ADDR FMT_CLASS "\n", + LogSpewAlways("Allocated %5zu bytes for %s_TYPE" FMT_ADDR FMT_CLASS "\n", size, pMT->IsValueType() ? "VAL" : "REF", DBG_ADDR(object), diff --git a/src/runtime/src/coreclr/vm/generics.cpp b/src/runtime/src/coreclr/vm/generics.cpp index 1fed75d3ca63..b4307ca7902b 100644 --- a/src/runtime/src/coreclr/vm/generics.cpp +++ b/src/runtime/src/coreclr/vm/generics.cpp @@ -717,7 +717,7 @@ void RecursionGraph::AddEdge(TypeVarTypeDesc *pFromVar, TypeVarTypeDesc *pToVar, } CONTRACTL_END - LOG((LF_CLASSLOADER, LL_INFO10000, "GENERICS: Adding %s edge: from %x(0x%x) to %x(0x%x) into recursion graph owned by MT: %x\n", + LOG((LF_CLASSLOADER, LL_INFO10000, "GENERICS: Adding %s edge: from %x(%p) to %x(%p) into recursion graph owned by MT: %p\n", (fExpanding ? "EXPANDING" : "NON-EXPANDING"), pFromVar->GetToken(), pFromVar->GetModule(), pToVar->GetToken(), pToVar->GetModule(), diff --git a/src/runtime/src/coreclr/vm/i386/cgenx86.cpp b/src/runtime/src/coreclr/vm/i386/cgenx86.cpp index 1500b80f9003..e3972879f294 100644 --- a/src/runtime/src/coreclr/vm/i386/cgenx86.cpp +++ b/src/runtime/src/coreclr/vm/i386/cgenx86.cpp @@ -81,7 +81,7 @@ void TransitionFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFl UpdateRegDisplayHelper(pRD, pFunc->CbStackPop()); - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK TransitionFrame::UpdateRegDisplay_Impl(ip:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); + LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK TransitionFrame::UpdateRegDisplay_Impl(ip:%p, sp:%p)\n", (void*)(size_t)pRD->ControlPC, (void*)(size_t)pRD->SP)); } void TransitionFrame::UpdateRegDisplayHelper(const PREGDISPLAY pRD, UINT cbStackPop) @@ -124,7 +124,7 @@ void ExternalMethodFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool upda UpdateRegDisplayHelper(pRD, CbStackPopUsingGCRefMap(GetGCRefMap())); - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK ExternalMethodFrane::UpdateRegDisplay_Impl(ip:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); + LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK ExternalMethodFrane::UpdateRegDisplay_Impl(ip:%p, sp:%p)\n", (void*)(size_t)pRD->ControlPC, (void*)(size_t)pRD->SP)); } @@ -166,7 +166,7 @@ void StubDispatchFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool update pRD->pCurrentContext->Eip = pRD->ControlPC; } - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK StubDispatchFrame::UpdateRegDisplay_Impl(ip:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); + LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK StubDispatchFrame::UpdateRegDisplay_Impl(ip:%p, sp:%p)\n", (void*)(size_t)pRD->ControlPC, (void*)(size_t)pRD->SP)); } PCODE StubDispatchFrame::GetReturnAddress_Impl() @@ -228,7 +228,7 @@ void FaultingExceptionFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool u pRD->IsCallerContextValid = FALSE; - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK FaultingExceptionFrame::UpdateRegDisplay_Impl(ip:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); + LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK FaultingExceptionFrame::UpdateRegDisplay_Impl(ip:%p, sp:%p)\n", (void*)(size_t)pRD->ControlPC, (void*)(size_t)pRD->SP)); } void InlinedCallFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats) @@ -295,7 +295,7 @@ void InlinedCallFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateF SyncRegDisplayToCurrentContext(pRD); - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK InlinedCallFrame::UpdateRegDisplay_Impl(ip:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); + LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK InlinedCallFrame::UpdateRegDisplay_Impl(ip:%p, sp:%p)\n", (void*)(size_t)pRD->ControlPC, (void*)(size_t)pRD->SP)); } #ifdef FEATURE_HIJACK @@ -335,7 +335,7 @@ void ResumableFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFlo pRD->IsCallerContextValid = FALSE; - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK ResumableFrame::UpdateRegDisplay_Impl(ip:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); + LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK ResumableFrame::UpdateRegDisplay_Impl(ip:%p, sp:%p)\n", (void*)(size_t)pRD->ControlPC, (void*)(size_t)pRD->SP)); } // The HijackFrame has to know the registers that are pushed by OnHijackTripThread @@ -367,7 +367,7 @@ void HijackFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats SyncRegDisplayToCurrentContext(pRD); - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK HijackFrame::UpdateRegDisplay_Impl(ip:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); + LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK HijackFrame::UpdateRegDisplay_Impl(ip:%p, sp:%p)\n", (void*)(size_t)pRD->ControlPC, (void*)(size_t)pRD->SP)); } #endif // FEATURE_HIJACK @@ -386,7 +386,7 @@ void PInvokeCalliFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool update VASigCookie *pVASigCookie = GetVASigCookie(); UpdateRegDisplayHelper(pRD, pVASigCookie->sizeOfArgs); - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK PInvokeCalliFrame::UpdateRegDisplay_Impl(ip:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); + LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK PInvokeCalliFrame::UpdateRegDisplay_Impl(ip:%p, sp:%p)\n", (void*)(size_t)pRD->ControlPC, (void*)(size_t)pRD->SP)); } #ifndef UNIX_X86_ABI @@ -412,7 +412,7 @@ void TailCallFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloa SyncRegDisplayToCurrentContext(pRD); - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK TailCallFrame::UpdateRegDisplay_Impl(ip:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); + LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK TailCallFrame::UpdateRegDisplay_Impl(ip:%p, sp:%p)\n", (void*)(size_t)pRD->ControlPC, (void*)(size_t)pRD->SP)); } #endif // !UNIX_X86_ABI diff --git a/src/runtime/src/coreclr/vm/ilstubcache.cpp b/src/runtime/src/coreclr/vm/ilstubcache.cpp index 5ec773a34841..63e8119ffb09 100644 --- a/src/runtime/src/coreclr/vm/ilstubcache.cpp +++ b/src/runtime/src/coreclr/vm/ilstubcache.cpp @@ -666,7 +666,7 @@ MethodDesc* ILStubCache::GetStubMethodDesc( #ifdef _DEBUG CQuickBytes qbManaged; PrettyPrintSig(pSig, cbSig, "*", &qbManaged, pSigModule->GetMDImport(), NULL); - LOG((LF_STUBS, LL_INFO1000, "ILSTUBCACHE: ILStubCache::GetStubMethodDesc %s StubMD: %p module: %p blob: %p sig: %s\n", pszResult, pMD, pSigModule, pBlob, qbManaged.Ptr())); + LOG((LF_STUBS, LL_INFO1000, "ILSTUBCACHE: ILStubCache::GetStubMethodDesc %s StubMD: %p module: %p blob: %p sig: %s\n", pszResult, pMD, pSigModule, pBlob, (char*)qbManaged.Ptr())); #endif // _DEBUG #endif // DACCESS_COMPILE diff --git a/src/runtime/src/coreclr/vm/jithelpers.cpp b/src/runtime/src/coreclr/vm/jithelpers.cpp index 8ceb8647a238..6330135b6f1c 100644 --- a/src/runtime/src/coreclr/vm/jithelpers.cpp +++ b/src/runtime/src/coreclr/vm/jithelpers.cpp @@ -1339,7 +1339,7 @@ static PCODE PatchpointOptimizationPolicy(TransitionBlock* pTransitionBlock, int if ((ppInfo->m_flags & PerPatchpointInfo::patchpoint_invalid) == PerPatchpointInfo::patchpoint_invalid) { LOG((LF_TIEREDCOMPILATION, LL_INFO1000, "PatchpointOptimizationPolicy: invalid patchpoint [%d] (0x%p) in Method=0x%pM (%s::%s) at offset %d\n", - ppId, ip, pMD, pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName, ilOffset)); + ppId, (void*)ip, pMD, pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName, ilOffset)); goto DONE; } @@ -1364,7 +1364,7 @@ static PCODE PatchpointOptimizationPolicy(TransitionBlock* pTransitionBlock, int if ((ppId < lowId) || (ppId > highId)) { LOG((LF_TIEREDCOMPILATION, LL_INFO10, "PatchpointOptimizationPolicy: ignoring patchpoint [%d] (0x%p) in Method=0x%pM (%s::%s) at offset %d\n", - ppId, ip, pMD, pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName, ilOffset)); + ppId, (void*)ip, pMD, pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName, ilOffset)); goto DONE; } #endif @@ -1401,7 +1401,7 @@ static PCODE PatchpointOptimizationPolicy(TransitionBlock* pTransitionBlock, int const int hitLogLevel = (hitCount == 1) ? LL_INFO10 : LL_INFO1000; LOG((LF_TIEREDCOMPILATION, hitLogLevel, "PatchpointOptimizationPolicy: patchpoint [%d] (0x%p) hit %d in Method=0x%pM (%s::%s) [il offset %d] (limit %d)\n", - ppId, ip, hitCount, pMD, pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName, ilOffset, hitLimit)); + ppId, (void*)ip, hitCount, pMD, pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName, ilOffset, hitLimit)); // Defer, if we haven't yet reached the limit if (hitCount < hitLimit) @@ -1413,7 +1413,7 @@ static PCODE PatchpointOptimizationPolicy(TransitionBlock* pTransitionBlock, int LONG oldFlags = ppInfo->m_flags; if ((oldFlags & PerPatchpointInfo::patchpoint_triggered) == PerPatchpointInfo::patchpoint_triggered) { - LOG((LF_TIEREDCOMPILATION, LL_INFO1000, "PatchpointOptimizationPolicy: AWAITING OSR method for patchpoint [%d] (0x%p)\n", ppId, ip)); + LOG((LF_TIEREDCOMPILATION, LL_INFO1000, "PatchpointOptimizationPolicy: AWAITING OSR method for patchpoint [%d] (0x%p)\n", ppId, (void*)ip)); goto DONE; } @@ -1422,7 +1422,7 @@ static PCODE PatchpointOptimizationPolicy(TransitionBlock* pTransitionBlock, int if (!triggerTransition) { - LOG((LF_TIEREDCOMPILATION, LL_INFO1000, "PatchpointOptimizationPolicy: (lost race) AWAITING OSR method for patchpoint [%d] (0x%p)\n", ppId, ip)); + LOG((LF_TIEREDCOMPILATION, LL_INFO1000, "PatchpointOptimizationPolicy: (lost race) AWAITING OSR method for patchpoint [%d] (0x%p)\n", ppId, (void*)ip)); goto DONE; } @@ -1460,7 +1460,7 @@ static PCODE PatchpointOptimizationPolicy(TransitionBlock* pTransitionBlock, int // // We want to expose bugs in the jitted code // for OSR methods, so we stick with synchronous creation. - LOG((LF_TIEREDCOMPILATION, LL_INFO10, "PatchpointOptimizationPolicy: patchpoint [%d] (0x%p) TRIGGER at count %d\n", ppId, ip, hitCount)); + LOG((LF_TIEREDCOMPILATION, LL_INFO10, "PatchpointOptimizationPolicy: patchpoint [%d] (0x%p) TRIGGER at count %d\n", ppId, (void*)ip, hitCount)); // Invoke the helper to build the OSR method osrMethodCode = JitPatchpointWorker(pMD, codeInfo, ilOffset); @@ -1470,7 +1470,7 @@ static PCODE PatchpointOptimizationPolicy(TransitionBlock* pTransitionBlock, int { // Unexpected, but not fatal STRESS_LOG3(LF_TIEREDCOMPILATION, LL_WARNING, "PatchpointOptimizationPolicy: patchpoint (0x%p) OSR method creation failed," - " marking patchpoint invalid for Method=0x%pM il offset %d\n", ip, pMD, ilOffset); + " marking patchpoint invalid for Method=0x%pM il offset %d\n", (void*)ip, pMD, ilOffset); InterlockedOr(&ppInfo->m_flags, (LONG)PerPatchpointInfo::patchpoint_invalid); } @@ -1510,7 +1510,7 @@ static PCODE PatchpointRequiredPolicy(TransitionBlock* pTransitionBlock, int* co if ((ppInfo->m_flags & PerPatchpointInfo::patchpoint_invalid) == PerPatchpointInfo::patchpoint_invalid) { LOG((LF_TIEREDCOMPILATION, LL_FATALERROR, "PatchpointRequiredPolicy: invalid patchpoint [%d] (0x%p) in Method=0x%pM (%s::%s) at offset %d\n", - ppId, ip, pMD, pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName, ilOffset)); + ppId, (void*)ip, pMD, pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName, ilOffset)); EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE); } @@ -1540,7 +1540,7 @@ static PCODE PatchpointRequiredPolicy(TransitionBlock* pTransitionBlock, int* co if ((ppInfo->m_flags & PerPatchpointInfo::patchpoint_invalid) == PerPatchpointInfo::patchpoint_invalid) { LOG((LF_TIEREDCOMPILATION, LL_FATALERROR, "PatchpointRequiredPolicy: invalid patchpoint [%d] (0x%p) in Method=0x%pM (%s::%s) at offset %d\n", - ppId, ip, pMD, pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName, ilOffset)); + ppId, (void*)ip, pMD, pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName, ilOffset)); EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE); } @@ -1549,7 +1549,7 @@ static PCODE PatchpointRequiredPolicy(TransitionBlock* pTransitionBlock, int* co LONG oldFlags = ppInfo->m_flags; if ((oldFlags & PerPatchpointInfo::patchpoint_triggered) == PerPatchpointInfo::patchpoint_triggered) { - LOG((LF_TIEREDCOMPILATION, LL_INFO1000, "PatchpointRequiredPolicy: AWAITING OSR method for patchpoint [%d] (0x%p)\n", ppId, ip)); + LOG((LF_TIEREDCOMPILATION, LL_INFO1000, "PatchpointRequiredPolicy: AWAITING OSR method for patchpoint [%d] (0x%p)\n", ppId, (void*)ip)); __SwitchToThread(0, backoffs++); continue; } @@ -1561,7 +1561,7 @@ static PCODE PatchpointRequiredPolicy(TransitionBlock* pTransitionBlock, int* co if (!triggerTransition) { - LOG((LF_TIEREDCOMPILATION, LL_INFO1000, "PatchpointRequiredPolicy: (lost race) AWAITING OSR method for patchpoint [%d] (0x%p)\n", ppId, ip)); + LOG((LF_TIEREDCOMPILATION, LL_INFO1000, "PatchpointRequiredPolicy: (lost race) AWAITING OSR method for patchpoint [%d] (0x%p)\n", ppId, (void*)ip)); __SwitchToThread(0, backoffs++); continue; } @@ -1573,7 +1573,7 @@ static PCODE PatchpointRequiredPolicy(TransitionBlock* pTransitionBlock, int* co // // (but consider: throw path in method with try/catch, OSR method will contain more than just the throw?) // - LOG((LF_TIEREDCOMPILATION, LL_INFO10, "PatchpointRequiredPolicy: patchpoint [%d] (0x%p) TRIGGER\n", ppId, ip)); + LOG((LF_TIEREDCOMPILATION, LL_INFO10, "PatchpointRequiredPolicy: patchpoint [%d] (0x%p) TRIGGER\n", ppId, (void*)ip)); PCODE newMethodCode = JitPatchpointWorker(pMD, codeInfo, ilOffset); // If that failed, mark the patchpoint as invalid. @@ -1582,7 +1582,7 @@ static PCODE PatchpointRequiredPolicy(TransitionBlock* pTransitionBlock, int* co if (newMethodCode == (PCODE)NULL) { STRESS_LOG3(LF_TIEREDCOMPILATION, LL_WARNING, "PatchpointRequiredPolicy: patchpoint (0x%p) OSR method creation failed," - " marking patchpoint invalid for Method=0x%pM il offset %d\n", ip, pMD, ilOffset); + " marking patchpoint invalid for Method=0x%pM il offset %d\n", (void*)ip, pMD, ilOffset); InterlockedOr(&ppInfo->m_flags, (LONG)PerPatchpointInfo::patchpoint_invalid); EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE); break; @@ -1693,7 +1693,7 @@ extern "C" PCODE JIT_PatchpointWorkerWorkerWithPolicy(TransitionBlock * pTransit // code at the patchpoint handles the actual SP/FP setup and jump. { const int transitionLogLevel = isNewMethod ? LL_INFO10 : LL_INFO1000; - LOG((LF_TIEREDCOMPILATION, transitionLogLevel, "Jit_Patchpoint: patchpoint [%d] (0x%p) TRANSITION to ip 0x%p\n", ppId, ip, osrMethodCode)); + LOG((LF_TIEREDCOMPILATION, transitionLogLevel, "Jit_Patchpoint: patchpoint [%d] (0x%p) TRANSITION to ip 0x%p\n", ppId, (void*)ip, (void*)osrMethodCode)); } DONE: diff --git a/src/runtime/src/coreclr/vm/jitinterface.cpp b/src/runtime/src/coreclr/vm/jitinterface.cpp index 63f5380933ad..8fc64fc082d3 100644 --- a/src/runtime/src/coreclr/vm/jitinterface.cpp +++ b/src/runtime/src/coreclr/vm/jitinterface.cpp @@ -6,6 +6,7 @@ // =========================================================================== #include "common.h" +#include #include "jitinterface.h" #include "codeman.h" #include "method.hpp" @@ -1951,7 +1952,6 @@ unsigned CEEInfo::getClassAlignmentRequirementStatic(TypeHandle clsHnd) result = pInfo->GetAlignmentRequirement(); } } - #ifdef FEATURE_64BIT_ALIGNMENT if (result < 8 && pMT->RequiresAlign8()) { @@ -10445,6 +10445,10 @@ void CEEInfo::getAsyncInfo(CORINFO_ASYNC_INFO* pAsyncInfoOut) pAsyncInfoOut->captureContextsMethHnd = CORINFO_METHOD_HANDLE(CoreLibBinder::GetMethod(METHOD__ASYNC_HELPERS__CAPTURE_CONTEXTS)); pAsyncInfoOut->restoreContextsMethHnd = CORINFO_METHOD_HANDLE(CoreLibBinder::GetMethod(METHOD__ASYNC_HELPERS__RESTORE_CONTEXTS)); pAsyncInfoOut->restoreContextsOnSuspensionMethHnd = CORINFO_METHOD_HANDLE(CoreLibBinder::GetMethod(METHOD__ASYNC_HELPERS__RESTORE_CONTEXTS_ON_SUSPENSION)); + pAsyncInfoOut->restoreInlinedFrameContextsMethHnd = CORINFO_METHOD_HANDLE(CoreLibBinder::GetMethod(METHOD__ASYNC_HELPERS__RESTORE_INLINED_FRAME_CONTEXTS)); + pAsyncInfoOut->captureInlinedFrameTransitionWithContinuationContextMethHnd = CORINFO_METHOD_HANDLE(CoreLibBinder::GetMethod(METHOD__ASYNC_HELPERS__CAPTURE_INLINED_FRAME_TRANSITION_WITH_CONTINUATION_CONTEXT)); + pAsyncInfoOut->captureInlinedFrameTransitionNoContinuationContextMethHnd = CORINFO_METHOD_HANDLE(CoreLibBinder::GetMethod(METHOD__ASYNC_HELPERS__CAPTURE_INLINED_FRAME_TRANSITION_NO_CONTINUATION_CONTEXT)); + pAsyncInfoOut->captureInlinedFrameTransitionContinueOnThreadPoolMethHnd = CORINFO_METHOD_HANDLE(CoreLibBinder::GetMethod(METHOD__ASYNC_HELPERS__CAPTURE_INLINED_FRAME_TRANSITION_CONTINUE_ON_THREAD_POOL)); pAsyncInfoOut->finishSuspensionNoContinuationContextMethHnd = CORINFO_METHOD_HANDLE(CoreLibBinder::GetMethod(METHOD__ASYNC_HELPERS__FINISH_SUSPENSION_NO_CONTINUATION_CONTEXT)); pAsyncInfoOut->finishSuspensionWithContinuationContextMethHnd = CORINFO_METHOD_HANDLE(CoreLibBinder::GetMethod(METHOD__ASYNC_HELPERS__FINISH_SUSPENSION_WITH_CONTINUATION_CONTEXT)); @@ -11026,7 +11030,7 @@ void CEEInfo::reportFatalError(CorJitResult result) JIT_TO_EE_TRANSITION_LEAF(); STRESS_LOG2(LF_JIT,LL_ERROR, "Jit reported error 0x%x while compiling 0x%p\n", - (int)result, (INT_PTR)getMethodBeingCompiled()); + (int)result, (void*)(INT_PTR)getMethodBeingCompiled()); EE_TO_JIT_TRANSITION_LEAF(); } @@ -12348,8 +12352,8 @@ void CEEJitInfo::recordRelocation(void * location, } } - LOG((LF_JIT, LL_INFO100000, "Encoded a PCREL32 at" FMT_ADDR "to" FMT_ADDR "+%d, delta is 0x%04x\n", - DBG_ADDR(fixupLocation), DBG_ADDR(target), addlDelta, delta)); + LOG((LF_JIT, LL_INFO100000, "Encoded a PCREL32 at" FMT_ADDR "to" FMT_ADDR "+%d, delta is 0x%04x\n", + DBG_ADDR(fixupLocation), DBG_ADDR(target), addlDelta, (UINT32)delta)); // Write the 32-bits pc-relative delta into location *fixupLocationRW = (INT32) delta; @@ -12436,8 +12440,8 @@ void CEEJitInfo::recordRelocation(void * location, DBG_ADDR(jumpStubAddr), DBG_ADDR(target))); } - LOG((LF_JIT, LL_INFO100000, "Encoded a BRANCH26 at" FMT_ADDR "to" FMT_ADDR ", delta is 0x%04x\n", - DBG_ADDR(fixupLocation), DBG_ADDR(target), delta)); + LOG((LF_JIT, LL_INFO100000, "Encoded a BRANCH26 at" FMT_ADDR "to" FMT_ADDR ", delta is 0x%04x\n", + DBG_ADDR(fixupLocation), DBG_ADDR(target), (UINT32)delta)); _ASSERTE(FitsInRel28(delta)); @@ -12554,8 +12558,8 @@ void CEEJitInfo::recordRelocation(void * location, bool isStype = (fRelocType == CorInfoReloc::RISCV64_PCREL_S); PutRiscV64AuipcCombo((UINT32 *)locationRW, delta, isStype); - LOG((LF_JIT, LL_INFO100000, "Fixed up an auipc + %c-type relocation at" FMT_ADDR "to" FMT_ADDR ", delta is 0x%08x\n", - (isStype ? 'S' : 'I'), DBG_ADDR(location), DBG_ADDR(target), delta)); + LOG((LF_JIT, LL_INFO100000, "Fixed up an auipc + %c-type relocation at" FMT_ADDR "to" FMT_ADDR ", delta is 0x%08" PRIx64 "\n", + (isStype ? 'S' : 'I'), DBG_ADDR(location), DBG_ADDR(target), (uint64_t)delta)); break; } #endif // TARGET_RISCV64 @@ -13316,13 +13320,13 @@ void CEECodeGenInfo::setEHinfoWorker( pEHClause->Flags = (CorExceptionFlag)clause->Flags; LOG((LF_EH, LL_INFO1000000, "Setting EH clause #%d for %s::%s\n", EHnumber, m_pMethodBeingCompiled->m_pszDebugClassName, m_pMethodBeingCompiled->m_pszDebugMethodName)); - LOG((LF_EH, LL_INFO1000000, " Flags : 0x%08lx -> 0x%08lx\n", clause->Flags, pEHClause->Flags)); - LOG((LF_EH, LL_INFO1000000, " TryOffset : 0x%08lx -> 0x%08lx (startpc)\n", clause->TryOffset, pEHClause->TryStartPC)); - LOG((LF_EH, LL_INFO1000000, " TryLength : 0x%08lx -> 0x%08lx (endpc)\n", clause->TryLength, pEHClause->TryEndPC)); - LOG((LF_EH, LL_INFO1000000, " HandlerOffset : 0x%08lx -> 0x%08lx\n", clause->HandlerOffset, pEHClause->HandlerStartPC)); - LOG((LF_EH, LL_INFO1000000, " HandlerLength : 0x%08lx -> 0x%08lx\n", clause->HandlerLength, pEHClause->HandlerEndPC)); - LOG((LF_EH, LL_INFO1000000, " ClassToken : 0x%08lx -> 0x%08lx\n", clause->ClassToken, pEHClause->ClassToken)); - LOG((LF_EH, LL_INFO1000000, " FilterOffset : 0x%08lx -> 0x%08lx\n", clause->FilterOffset, pEHClause->FilterOffset)); + LOG((LF_EH, LL_INFO1000000, " Flags : 0x%08x -> 0x%08x\n", clause->Flags, pEHClause->Flags)); + LOG((LF_EH, LL_INFO1000000, " TryOffset : 0x%08x -> 0x%08x (startpc)\n", clause->TryOffset, pEHClause->TryStartPC)); + LOG((LF_EH, LL_INFO1000000, " TryLength : 0x%08x -> 0x%08x (endpc)\n", clause->TryLength, pEHClause->TryEndPC)); + LOG((LF_EH, LL_INFO1000000, " HandlerOffset : 0x%08x -> 0x%08x\n", clause->HandlerOffset, pEHClause->HandlerStartPC)); + LOG((LF_EH, LL_INFO1000000, " HandlerLength : 0x%08x -> 0x%08x\n", clause->HandlerLength, pEHClause->HandlerEndPC)); + LOG((LF_EH, LL_INFO1000000, " ClassToken : 0x%08x -> 0x%08x\n", clause->ClassToken, pEHClause->ClassToken)); + LOG((LF_EH, LL_INFO1000000, " FilterOffset : 0x%08x -> 0x%08x\n", clause->FilterOffset, pEHClause->FilterOffset)); if (IsDynamicScope(m_MethodInfo.scope) && ((pEHClause->Flags & (COR_ILEXCEPTION_CLAUSE_FILTER | COR_ILEXCEPTION_CLAUSE_FINALLY | COR_ILEXCEPTION_CLAUSE_FAULT)) == 0) && diff --git a/src/runtime/src/coreclr/vm/loongarch64/singlestepper.cpp b/src/runtime/src/coreclr/vm/loongarch64/singlestepper.cpp index 867894a8d365..94c6f8539138 100644 --- a/src/runtime/src/coreclr/vm/loongarch64/singlestepper.cpp +++ b/src/runtime/src/coreclr/vm/loongarch64/singlestepper.cpp @@ -7,6 +7,7 @@ // #include "common.h" +#include #include "loongarch64singlestepper.h" inline uint64_t SignExtend(uint64_t value, unsigned int signbit) @@ -102,7 +103,7 @@ void LoongArch64SingleStepper::Bypass(uint64_t ip, uint32_t opcode) } } - LOG((LF_CORDB, LL_INFO100000, "LoongArch64SingleStepper::Bypass(pc=%lx, opcode=%x)\n", ip, opcode)); + LOG((LF_CORDB, LL_INFO100000, "LoongArch64SingleStepper::Bypass(pc=%" PRIx64 ", opcode=%x)\n", ip, opcode)); m_fBypass = true; m_originalPc = ip; @@ -131,7 +132,7 @@ void LoongArch64SingleStepper::Apply(T_CONTEXT *pCtx) uint32_t opcode = m_opcodes[0]; - LOG((LF_CORDB, LL_INFO100000, "LoongArch64SingleStepper::Apply(pc=%lx, opcode=%x)\n", (uint64_t)pCtx->Pc, opcode)); + LOG((LF_CORDB, LL_INFO100000, "LoongArch64SingleStepper::Apply(pc=%" PRIx64 ", opcode=%x)\n", (uint64_t)pCtx->Pc, opcode)); #ifdef _DEBUG // Make sure that we aren't trying to step through our own buffer. If this asserts, something is horribly @@ -274,7 +275,7 @@ bool LoongArch64SingleStepper::Fixup(T_CONTEXT *pCtx, DWORD dwExceptionCode) { if (m_rgCode[0] != kBreakpointOp) { - LOG((LF_CORDB, LL_INFO100000, "LoongArch64SingleStepper::Fixup executed code, ip = %lx\n", m_targetPc)); + LOG((LF_CORDB, LL_INFO100000, "LoongArch64SingleStepper::Fixup executed code, ip = %" PRIx64 "\n", m_targetPc)); pCtx->Pc = m_targetPc; } @@ -297,7 +298,7 @@ bool LoongArch64SingleStepper::Fixup(T_CONTEXT *pCtx, DWORD dwExceptionCode) pCtx->Pc = m_targetPc; - LOG((LF_CORDB, LL_INFO100000, "LoongArch64SingleStepper::Fixup emulated, ip = %lx\n", pCtx->Pc)); + LOG((LF_CORDB, LL_INFO100000, "LoongArch64SingleStepper::Fixup emulated, ip = %" PRIx64 "\n", pCtx->Pc)); } } else @@ -307,7 +308,7 @@ bool LoongArch64SingleStepper::Fixup(T_CONTEXT *pCtx, DWORD dwExceptionCode) _ASSERTE(m_fEmulate == false); pCtx->Pc = m_originalPc; - LOG((LF_CORDB, LL_INFO100000, "LoongArch64SingleStepper::Fixup hit exception pc = %lx ex = %x\n", pCtx->Pc, dwExceptionCode)); + LOG((LF_CORDB, LL_INFO100000, "LoongArch64SingleStepper::Fixup hit exception pc = %" PRIx64 " ex = %x\n", pCtx->Pc, dwExceptionCode)); } _ASSERTE((pCtx->Pc & 0x3) == 0); diff --git a/src/runtime/src/coreclr/vm/loongarch64/stubs.cpp b/src/runtime/src/coreclr/vm/loongarch64/stubs.cpp index a71bd2db1d36..67638db687f9 100644 --- a/src/runtime/src/coreclr/vm/loongarch64/stubs.cpp +++ b/src/runtime/src/coreclr/vm/loongarch64/stubs.cpp @@ -287,7 +287,8 @@ void TransitionFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFl // Finally, syncup the regdisplay with the context SyncRegDisplayToCurrentContext(pRD); - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK TransitionFrame::UpdateRegDisplay_Impl(pc:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); + LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK TransitionFrame::UpdateRegDisplay_Impl(pc:%p, sp:%p)\n", + reinterpret_cast(pRD->ControlPC), reinterpret_cast(pRD->SP))); } #ifdef FEATURE_INTERPRETER @@ -350,7 +351,8 @@ void FaultingExceptionFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool u pRD->IsCallerContextValid = FALSE; - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK FaultingExceptionFrame::UpdateRegDisplay_Impl(pc:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); + LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK FaultingExceptionFrame::UpdateRegDisplay_Impl(pc:%p, sp:%p)\n", + reinterpret_cast(pRD->ControlPC), reinterpret_cast(pRD->SP))); } void InlinedCallFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats) @@ -408,7 +410,8 @@ void InlinedCallFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateF // Update the frame pointer in the current context. pRD->pCurrentContextPointers->Fp = &m_pCalleeSavedFP; - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK InlinedCallFrame::UpdateRegDisplay_Impl(pc:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); + LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK InlinedCallFrame::UpdateRegDisplay_Impl(pc:%p, sp:%p)\n", + reinterpret_cast(pRD->ControlPC), reinterpret_cast(pRD->SP))); } #ifdef FEATURE_HIJACK @@ -468,7 +471,8 @@ void ResumableFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFlo pRD->IsCallerContextValid = FALSE; - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK ResumableFrame::UpdateRegDisplay_Impl(pc:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); + LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK ResumableFrame::UpdateRegDisplay_Impl(pc:%p, sp:%p)\n", + reinterpret_cast(pRD->ControlPC), reinterpret_cast(pRD->SP))); } void HijackFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats) @@ -517,7 +521,8 @@ void HijackFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats pRD->pCurrentContextPointers->Ra = NULL; SyncRegDisplayToCurrentContext(pRD); - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK HijackFrame::UpdateRegDisplay_Impl(pc:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); + LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK HijackFrame::UpdateRegDisplay_Impl(pc:%p, sp:%p)\n", + reinterpret_cast(pRD->ControlPC), reinterpret_cast(pRD->SP))); } #endif // FEATURE_HIJACK diff --git a/src/runtime/src/coreclr/vm/methodtable.cpp b/src/runtime/src/coreclr/vm/methodtable.cpp index 7e424d7de4ea..e8c610b5fa60 100644 --- a/src/runtime/src/coreclr/vm/methodtable.cpp +++ b/src/runtime/src/coreclr/vm/methodtable.cpp @@ -2919,7 +2919,7 @@ static bool FlattenFields(TypeHandle th, uint32_t structOffset, FpStructInRegist { LOG((LF_JIT, LL_EVERYTHING, "FpStructInRegistersInfo:%*s " " * field %s [%i..%i) overlaps with other fields (occupied bytes map: 0x%04x), treat as union\n", - nestingLevel * 4, "", fields[i].GetFieldDesc()->GetDebugName(), startOffset, endOffset)); + nestingLevel * 4, "", fields[i].GetFieldDesc()->GetDebugName(), startOffset, endOffset, occupiedBytesMap)); return false; } occupiedBytesMap |= fieldOccupation; diff --git a/src/runtime/src/coreclr/vm/methodtablebuilder.cpp b/src/runtime/src/coreclr/vm/methodtablebuilder.cpp index 1a11877ea5b6..f8e9ef66c54c 100644 --- a/src/runtime/src/coreclr/vm/methodtablebuilder.cpp +++ b/src/runtime/src/coreclr/vm/methodtablebuilder.cpp @@ -7092,8 +7092,8 @@ VOID MethodTableBuilder::ValidateInterfaceMethodConstraints() pMTItf->GetModule(), mdTok)) { - LOG((LF_CLASSLOADER, LL_INFO1000, - "BADCONSTRAINTS on interface method implementation: %x\n", pTargetMD)); + LOG((LF_CLASSLOADER, LL_INFO1000, + "BADCONSTRAINTS on interface method implementation: %p\n", pTargetMD)); // This exception will be due to an implicit implementation, since explicit errors // will be detected in MethodImplCompareSignatures (for now, anyway). CONSISTENCY_CHECK(!it.IsMethodImpl()); diff --git a/src/runtime/src/coreclr/vm/mlinfo.cpp b/src/runtime/src/coreclr/vm/mlinfo.cpp index b89c18524f1e..eb9521936719 100644 --- a/src/runtime/src/coreclr/vm/mlinfo.cpp +++ b/src/runtime/src/coreclr/vm/mlinfo.cpp @@ -2832,7 +2832,7 @@ VOID MarshalInfo::DumpMarshalInfo(Module* pModule, SigPointer sig, const SigType IMDInternalImport *pInternalImport = pModule->GetMDImport(); logbuf.AppendASCII("------------------------------------------------------------\n"); - LOG((LF_MARSHALER, LL_INFO10, logbuf.GetUTF8())); + LOG((LF_MARSHALER, LL_INFO10, "%s", logbuf.GetUTF8())); logbuf.Clear(); logbuf.AppendASCII("Managed type: "); @@ -2850,7 +2850,7 @@ VOID MarshalInfo::DumpMarshalInfo(Module* pModule, SigPointer sig, const SigType } logbuf.AppendASCII("\n"); - LOG((LF_MARSHALER, LL_INFO10, logbuf.GetUTF8())); + LOG((LF_MARSHALER, LL_INFO10, "%s", logbuf.GetUTF8())); logbuf.Clear(); logbuf.AppendASCII("NativeType : "); @@ -3005,7 +3005,7 @@ VOID MarshalInfo::DumpMarshalInfo(Module* pModule, SigPointer sig, const SigType } } logbuf.AppendASCII("\n"); - LOG((LF_MARSHALER, LL_INFO10, logbuf.GetUTF8())); + LOG((LF_MARSHALER, LL_INFO10, "%s", logbuf.GetUTF8())); logbuf.Clear(); logbuf.AppendASCII("MarshalType : "); @@ -3065,7 +3065,7 @@ VOID MarshalInfo::DumpMarshalInfo(Module* pModule, SigPointer sig, const SigType logbuf.AppendASCII("\n"); - LOG((LF_MARSHALER, LL_INFO10, logbuf.GetUTF8())); + LOG((LF_MARSHALER, LL_INFO10, "%s", logbuf.GetUTF8())); logbuf.Clear(); } } // MarshalInfo::DumpMarshalInfo diff --git a/src/runtime/src/coreclr/vm/multicorejitimpl.h b/src/runtime/src/coreclr/vm/multicorejitimpl.h index 81663650e907..062800c284ec 100644 --- a/src/runtime/src/coreclr/vm/multicorejitimpl.h +++ b/src/runtime/src/coreclr/vm/multicorejitimpl.h @@ -730,7 +730,8 @@ class MulticoreJitRecorder #ifdef MULTICOREJIT_LOGGING -void _MulticoreJitTrace(const char * format, ...); +#include +void _MulticoreJitTrace(const char * format, ...) MINIPAL_ATTR_FORMAT_PRINTF(1, 2); #define MulticoreJitTrace(x) do { _MulticoreJitTrace x; } while (0) diff --git a/src/runtime/src/coreclr/vm/multicorejitplayer.cpp b/src/runtime/src/coreclr/vm/multicorejitplayer.cpp index 0ccd4057d103..61e52528b1f7 100644 --- a/src/runtime/src/coreclr/vm/multicorejitplayer.cpp +++ b/src/runtime/src/coreclr/vm/multicorejitplayer.cpp @@ -87,7 +87,7 @@ void MulticoreJitCodeStorage::StoreMethodCode(MethodDesc * pMD, MulticoreJitCode MulticoreJitTrace(( "%p %p %d %d StoredMethodCode", pMD, - codeInfo.GetEntryPoint(), + (void*)codeInfo.GetEntryPoint(), (int)codeInfo.WasTier0(), (int)codeInfo.JitSwitchedToOptimized())); } @@ -145,7 +145,7 @@ MulticoreJitCodeInfo MulticoreJitCodeStorage::QueryAndRemoveMethodCode(MethodDes MulticoreJitTrace(( "%p %p %d %d QueryAndRemoveMethodCode", pMethod, - codeInfo.GetEntryPoint(), + (void*)codeInfo.GetEntryPoint(), (int)codeInfo.WasTier0(), (int)codeInfo.JitSwitchedToOptimized())); } @@ -1127,9 +1127,12 @@ HRESULT MulticoreJitProfilePlayer::PlayProfile() unsigned nSize = m_nFileSize; - MulticoreJitTrace(("PlayProfile %d bytes in (%s)", - nSize, - GetAppDomain()->GetFriendlyName())); + { + MAKE_UTF8PTR_FROMWIDE(pFriendlyName, GetAppDomain()->GetFriendlyName()); + MulticoreJitTrace(("PlayProfile %d bytes in (%s)", + nSize, + pFriendlyName)); + } while ((SUCCEEDED(hr)) && (nSize > sizeof(unsigned))) { diff --git a/src/runtime/src/coreclr/vm/object.cpp b/src/runtime/src/coreclr/vm/object.cpp index 2bb5865114d0..fe18eef978ba 100644 --- a/src/runtime/src/coreclr/vm/object.cpp +++ b/src/runtime/src/coreclr/vm/object.cpp @@ -622,7 +622,8 @@ VOID Object::ValidateInner(BOOL bDeep, BOOL bVerifyNextHeader, BOOL bVerifySyncB } EX_CATCH { - STRESS_LOG3(LF_ASSERT, LL_ALWAYS, "Detected use of corrupted OBJECTREF: %p [MT=%p] (lastTest=%d)", this, lastTest > 0 ? (*(size_t*)this) : 0, lastTest); + STRESS_LOG3(LF_ASSERT, LL_ALWAYS, "Detected use of corrupted OBJECTREF: %p [MT=%p] (lastTest=%d)", this, + (void*)(size_t)(lastTest > 0 ? (*(size_t*)this) : 0), lastTest); CHECK_AND_TEAR_DOWN(!"Detected use of a corrupted OBJECTREF. Possible GC hole."); } EX_END_CATCH diff --git a/src/runtime/src/coreclr/vm/peimagelayout.cpp b/src/runtime/src/coreclr/vm/peimagelayout.cpp index 04836c1b4729..c560e78ed5a7 100644 --- a/src/runtime/src/coreclr/vm/peimagelayout.cpp +++ b/src/runtime/src/coreclr/vm/peimagelayout.cpp @@ -299,7 +299,7 @@ void PEImageLayout::ApplyBaseRelocations(bool relocationMustWriteCopy) return; } - LOG((LF_LOADER, LL_INFO100, "PEImage: Applying base relocations (preferred: %x, actual: %x)\n", + LOG((LF_LOADER, LL_INFO100, "PEImage: Applying base relocations (preferred: %p, actual: %p)\n", GetPreferredBase(), GetBase())); COUNT_T dirSize; diff --git a/src/runtime/src/coreclr/vm/perfmap.cpp b/src/runtime/src/coreclr/vm/perfmap.cpp index 6755eef86604..e782ef3de1f1 100644 --- a/src/runtime/src/coreclr/vm/perfmap.cpp +++ b/src/runtime/src/coreclr/vm/perfmap.cpp @@ -341,7 +341,7 @@ void PerfMap::LogJITCompiledMethod(MethodDesc * pMethod, PCODE pCode, size_t cod name.AppendPrintf("[%s]", optimizationTier); } SString line; - line.Printf(FMT_CODE_ADDR " %x %s\n", pCode, codeSize, name.GetUTF8()); + line.Printf(FMT_CODE_ADDR " %zx %s\n", (void*)pCode, codeSize, name.GetUTF8()); { CrstHolder ch(&(s_csPerfMap)); @@ -442,7 +442,8 @@ void PerfMap::LogInterpreterMethod(MethodDesc * pMethod, PCODE irAddress, size_t pMethod->GetFullMethodInfo(name); SString line; - line.Printf(FMT_CODE_ADDR " %x [Interpreter] %s\n", irAddress, irSize, name.GetUTF8()); + line.Printf(FMT_CODE_ADDR " %zx [Interpreter] %s\n", (void*)irAddress, irSize, + name.GetUTF8()); { CrstHolder ch(&(s_csPerfMap)); @@ -503,7 +504,7 @@ void PerfMap::LogStubs(const char* stubType, const char* stubOwner, PCODE pCode, name.Printf("stub<%d> %s<%s>", ++(s_StubsMapped), stubType, stubOwner); } SString line; - line.Printf(FMT_CODE_ADDR " %x %s\n", pCode, codeSize, name.GetUTF8()); + line.Printf(FMT_CODE_ADDR " %zx %s\n", (void*)pCode, codeSize, name.GetUTF8()); { CrstHolder ch(&(s_csPerfMap)); diff --git a/src/runtime/src/coreclr/vm/proftoeeinterfaceimpl.cpp b/src/runtime/src/coreclr/vm/proftoeeinterfaceimpl.cpp index dd65cdb956ec..36b070111300 100644 --- a/src/runtime/src/coreclr/vm/proftoeeinterfaceimpl.cpp +++ b/src/runtime/src/coreclr/vm/proftoeeinterfaceimpl.cpp @@ -1593,7 +1593,7 @@ HRESULT ProfToEEInterfaceImpl::GetHandleFromThread(ThreadID threadId, HANDLE *ph (LF_CORPROF, LL_INFO1000, "**PROF: GetHandleFromThread 0x%p.\n", - threadId)); + (void*)threadId)); if (!IsManagedThread(threadId)) { @@ -1639,7 +1639,7 @@ HRESULT ProfToEEInterfaceImpl::GetObjectSize(ObjectID objectId, ULONG *pcSize) (LF_CORPROF, LL_INFO1000, "**PROF: GetObjectSize 0x%p.\n", - objectId)); + (void*)objectId)); if (objectId == 0) { @@ -1703,7 +1703,7 @@ HRESULT ProfToEEInterfaceImpl::GetObjectSize2(ObjectID objectId, SIZE_T *pcSize) (LF_CORPROF, LL_INFO1000, "**PROF: GetObjectSize2 0x%p.\n", - objectId)); + (void*)objectId)); if (objectId == 0) { @@ -1765,7 +1765,7 @@ HRESULT ProfToEEInterfaceImpl::IsArrayClass( (LF_CORPROF, LL_INFO1000, "**PROF: IsArrayClass 0x%p.\n", - classId)); + (void*)classId)); HRESULT hr; @@ -1843,7 +1843,7 @@ HRESULT ProfToEEInterfaceImpl::GetThreadInfo(ThreadID threadId, DWORD *pdwWin32T (LF_CORPROF, LL_INFO1000, "**PROF: GetThreadInfo 0x%p.\n", - threadId)); + (void*)threadId)); if (!IsManagedThread(threadId)) { @@ -2133,7 +2133,7 @@ HRESULT ProfToEEInterfaceImpl::GetTokenAndMetaDataFromFunction( (LF_CORPROF, LL_INFO1000, "**PROF: GetTokenAndMetaDataFromFunction 0x%p.\n", - functionId)); + (void*)functionId)); if (functionId == 0) { @@ -2382,7 +2382,7 @@ HRESULT ProfToEEInterfaceImpl::GetCodeInfo(FunctionID functionId, LPCBYTE * pSta (LF_CORPROF, LL_INFO1000, "**PROF: GetCodeInfo 0x%p.\n", - functionId)); + (void*)functionId)); // GetCodeInfo may be called asynchronously, and the JIT functions take a reader // lock. So we need to ensure the current thread hasn't been hijacked by a profiler while @@ -2464,7 +2464,7 @@ HRESULT ProfToEEInterfaceImpl::GetCodeInfo2(FunctionID functionId, (LF_CORPROF, LL_INFO1000, "**PROF: GetCodeInfo2 0x%p.\n", - functionId)); + (void*)functionId)); HRESULT hr = S_OK; @@ -2527,7 +2527,7 @@ HRESULT ProfToEEInterfaceImpl::GetCodeInfo3(FunctionID functionId, (LF_CORPROF, LL_INFO1000, "**PROF: GetCodeInfo3 0x%p 0x%p.\n", - functionId, reJitId)); + (void*)functionId, (void*)reJitId)); HRESULT hr = S_OK; @@ -2695,7 +2695,7 @@ HRESULT ProfToEEInterfaceImpl::EnumModuleFrozenObjects(ModuleID moduleID, (LF_CORPROF, LL_INFO1000, "**PROF: EnumModuleFrozenObjects 0x%p.\n", - moduleID)); + (void*)moduleID)); if (NULL == ppEnum) { @@ -2757,7 +2757,7 @@ HRESULT ProfToEEInterfaceImpl::GetArrayObjectInfo(ObjectID objectId, (LF_CORPROF, LL_INFO1000, "**PROF: GetArrayObjectInfo 0x%p.\n", - objectId)); + (void*)objectId)); if (objectId == 0) { @@ -2883,7 +2883,7 @@ HRESULT ProfToEEInterfaceImpl::GetBoxClassLayout(ClassID classId, (LF_CORPROF, LL_INFO1000, "**PROF: GetBoxClassLayout 0x%p.\n", - classId)); + (void*)classId)); if (pBufferOffset == NULL) { @@ -2944,7 +2944,7 @@ HRESULT ProfToEEInterfaceImpl::GetThreadAppDomain(ThreadID threadId, (LF_CORPROF, LL_INFO1000, "**PROF: GetThreadAppDomain 0x%p.\n", - threadId)); + (void*)threadId)); if (pAppDomainId == NULL) { @@ -3019,7 +3019,7 @@ HRESULT ProfToEEInterfaceImpl::GetRVAStaticAddress(ClassID classId, (LF_CORPROF, LL_INFO1000, "**PROF: GetRVAStaticAddress 0x%p, 0x%08x.\n", - classId, + (void*)classId, fieldToken)); // @@ -3136,9 +3136,9 @@ HRESULT ProfToEEInterfaceImpl::GetAppDomainStaticAddress(ClassID classId, (LF_CORPROF, LL_INFO1000, "**PROF: GetAppDomainStaticAddress 0x%p, 0x%08x, 0x%p.\n", - classId, + (void*)classId, fieldToken, - appDomainId)); + (void*)appDomainId)); // // Check for NULL parameters @@ -3282,9 +3282,9 @@ HRESULT ProfToEEInterfaceImpl::GetThreadStaticAddress(ClassID classId, (LF_CORPROF, LL_INFO1000, "**PROF: GetThreadStaticAddress 0x%p, 0x%08x, 0x%p.\n", - classId, + (void*)classId, fieldToken, - threadId)); + (void*)threadId)); // // Verify the value of threadId, which must be the current thread ID or NULL, which means using curernt thread ID. @@ -3358,10 +3358,10 @@ HRESULT ProfToEEInterfaceImpl::GetThreadStaticAddress2(ClassID classId, (LF_CORPROF, LL_INFO1000, "**PROF: GetThreadStaticAddress2 0x%p, 0x%08x, 0x%p, 0x%p.\n", - classId, + (void*)classId, fieldToken, - appDomainId, - threadId)); + (void*)appDomainId, + (void*)threadId)); if (threadId == 0) @@ -3479,9 +3479,9 @@ HRESULT ProfToEEInterfaceImpl::GetContextStaticAddress(ClassID classId, (LF_CORPROF, LL_INFO1000, "**PROF: GetContextStaticAddress 0x%p, 0x%08x, 0x%p.\n", - classId, + (void*)classId, fieldToken, - contextId)); + (void*)contextId)); return E_NOTIMPL; } @@ -3534,7 +3534,7 @@ HRESULT ProfToEEInterfaceImpl::GetAppDomainsContainingModule(ModuleID moduleId, (LF_CORPROF, LL_INFO1000, "**PROF: GetAppDomainsContainingModule 0x%p, 0x%08x, 0x%p, 0x%p.\n", - moduleId, + (void*)moduleId, cAppDomainIds, pcAppDomainIds, appDomainIds)); @@ -3612,7 +3612,7 @@ HRESULT ProfToEEInterfaceImpl::GetStaticFieldInfo(ClassID classId, (LF_CORPROF, LL_INFO1000, "**PROF: GetStaticFieldInfo 0x%p, 0x%08x.\n", - classId, + (void*)classId, fieldToken)); // @@ -3716,7 +3716,7 @@ HRESULT ProfToEEInterfaceImpl::GetClassIDInfo2(ClassID classId, (LF_CORPROF, LL_INFO1000, "**PROF: GetClassIDInfo2 0x%p.\n", - classId)); + (void*)classId)); // // Verify parameters. @@ -3880,7 +3880,7 @@ HRESULT ProfToEEInterfaceImpl::GetModuleInfo(ModuleID moduleId, (LF_CORPROF, LL_INFO1000, "**PROF: GetModuleInfo 0x%p.\n", - moduleId)); + (void*)moduleId)); // Parameter validation is taken care of in GetModuleInfo2. @@ -4003,7 +4003,7 @@ HRESULT ProfToEEInterfaceImpl::GetModuleInfo2(ModuleID moduleId, (LF_CORPROF, LL_INFO1000, "**PROF: GetModuleInfo2 0x%p.\n", - moduleId)); + (void*)moduleId)); if (moduleId == 0) { @@ -4155,7 +4155,7 @@ HRESULT ProfToEEInterfaceImpl::GetModuleMetaData(ModuleID moduleId, (LF_CORPROF, LL_INFO1000, "**PROF: GetModuleMetaData 0x%p, 0x%08x.\n", - moduleId, + (void*)moduleId, dwOpenFlags)); if (moduleId == 0) @@ -4238,7 +4238,7 @@ HRESULT ProfToEEInterfaceImpl::GetILFunctionBody(ModuleID moduleId, (LF_CORPROF, LL_INFO1000, "**PROF: GetILFunctionBody 0x%p, 0x%08x.\n", - moduleId, + (void*)moduleId, methodId)); Module * pModule; // Working pointer for real class. @@ -4366,7 +4366,7 @@ HRESULT ProfToEEInterfaceImpl::GetILFunctionBodyAllocator(ModuleID modul (LF_CORPROF, LL_INFO1000, "**PROF: GetILFunctionBodyAllocator 0x%p.\n", - moduleId)); + (void*)moduleId)); if ((moduleId == 0) || (ppMalloc == NULL)) { @@ -4420,7 +4420,7 @@ HRESULT ProfToEEInterfaceImpl::SetILFunctionBody(ModuleID moduleId, (LF_CORPROF, LL_INFO1000, "**PROF: SetILFunctionBody 0x%p, 0x%08x.\n", - moduleId, + (void*)moduleId, methodId)); if ((moduleId == 0) || @@ -4495,7 +4495,7 @@ HRESULT ProfToEEInterfaceImpl::SetILInstrumentedCodeMap(FunctionID functionId, (LF_CORPROF, LL_INFO1000, "**PROF: SetILInstrumentedCodeMap 0x%p, %d.\n", - functionId, + (void*)functionId, fStartJit)); if (functionId == 0) @@ -4652,7 +4652,7 @@ HRESULT ProfToEEInterfaceImpl::GetThreadContext(ThreadID threadId, (LF_CORPROF, LL_INFO1000, "**PROF: GetThreadContext 0x%p.\n", - threadId)); + (void*)threadId)); if (!IsManagedThread(threadId)) { @@ -4702,7 +4702,7 @@ HRESULT ProfToEEInterfaceImpl::GetClassIDInfo(ClassID classId, (LF_CORPROF, LL_INFO1000, "**PROF: GetClassIDInfo 0x%p.\n", - classId)); + (void*)classId)); if (classId == 0) { @@ -4795,7 +4795,7 @@ HRESULT ProfToEEInterfaceImpl::GetFunctionInfo(FunctionID functionId, (LF_CORPROF, LL_INFO1000, "**PROF: GetFunctionInfo 0x%p.\n", - functionId)); + (void*)functionId)); if (functionId == 0) { @@ -4865,7 +4865,7 @@ HRESULT ProfToEEInterfaceImpl::GetILToNativeMapping(FunctionID functionId, (LF_CORPROF, LL_INFO1000, "**PROF: GetILToNativeMapping 0x%p.\n", - functionId)); + (void*)functionId)); return GetILToNativeMapping2(functionId, 0, cMap, pcMap, map); } @@ -4901,7 +4901,7 @@ HRESULT ProfToEEInterfaceImpl::GetILToNativeMapping2(FunctionID functionId, (LF_CORPROF, LL_INFO1000, "**PROF: GetILToNativeMapping2 0x%p 0x%p.\n", - functionId, reJitId)); + (void*)functionId, (void*)reJitId)); if (functionId == 0) { @@ -4990,7 +4990,7 @@ HRESULT ProfToEEInterfaceImpl::GetClassFromObject(ObjectID objectId, (LF_CORPROF, LL_INFO1000, "**PROF: GetClassFromObject 0x%p.\n", - objectId)); + (void*)objectId)); if (objectId == 0) { @@ -5045,7 +5045,7 @@ HRESULT ProfToEEInterfaceImpl::GetClassFromToken(ModuleID moduleId, (LF_CORPROF, LL_INFO1000, "**PROF: GetClassFromToken 0x%p, 0x%08x.\n", - moduleId, + (void*)moduleId, typeDef)); if ((moduleId == 0) || (typeDef == mdTypeDefNil) || (typeDef == mdTokenNil)) @@ -5141,7 +5141,7 @@ HRESULT ProfToEEInterfaceImpl::GetClassFromTokenAndTypeArgs(ModuleID moduleID, (LF_CORPROF, LL_INFO1000, "**PROF: GetClassFromTokenAndTypeArgs 0x%p, 0x%08x.\n", - moduleID, + (void*)moduleID, typeDef)); if (!g_profControlBlock.fBaseSystemClassesLoaded) @@ -5278,7 +5278,7 @@ HRESULT ProfToEEInterfaceImpl::GetFunctionFromToken(ModuleID moduleId, (LF_CORPROF, LL_INFO1000, "**PROF: GetFunctionFromToken 0x%p, 0x%08x.\n", - moduleId, + (void*)moduleId, typeDef)); if ((moduleId == 0) || (typeDef == mdTokenNil)) @@ -5370,9 +5370,9 @@ HRESULT ProfToEEInterfaceImpl::GetFunctionFromTokenAndTypeArgs(ModuleID moduleID (LF_CORPROF, LL_INFO1000, "**PROF: GetFunctionFromTokenAndTypeArgs 0x%p, 0x%08x, 0x%p.\n", - moduleID, + (void*)moduleID, funcDef, - classId)); + (void*)classId)); TypeHandle typeHandle = TypeHandle::FromPtr((void *)classId); Module* pModule = reinterpret_cast< Module* >(moduleID); @@ -5482,7 +5482,7 @@ HRESULT ProfToEEInterfaceImpl::GetAppDomainInfo(AppDomainID appDomainId, (LF_CORPROF, LL_INFO1000, "**PROF: GetAppDomainInfo 0x%p.\n", - appDomainId)); + (void*)appDomainId)); if (appDomainId == 0) { @@ -5576,7 +5576,7 @@ HRESULT ProfToEEInterfaceImpl::GetAssemblyInfo(AssemblyID assemblyId, (LF_CORPROF, LL_INFO1000, "**PROF: GetAssemblyInfo 0x%p.\n", - assemblyId)); + (void*)assemblyId)); if (assemblyId == 0) { @@ -5968,7 +5968,7 @@ HRESULT ProfToEEInterfaceImpl::GetFunctionInfo2(FunctionID funcId, (LF_CORPROF, LL_INFO1000, "**PROF: GetFunctionInfo2 0x%p.\n", - funcId)); + (void*)funcId)); // // Verify parameters. @@ -6166,7 +6166,7 @@ HRESULT ProfToEEInterfaceImpl::IsFunctionDynamic(FunctionID functionId, BOOL *is (LF_CORPROF, LL_INFO1000, "**PROF: IsFunctionDynamic 0x%p.\n", - functionId)); + (void*)functionId)); // // Verify parameters. @@ -6319,7 +6319,7 @@ HRESULT ProfToEEInterfaceImpl::GetDynamicFunctionInfo(FunctionID functionId, (LF_CORPROF, LL_INFO1000, "**PROF: GetDynamicFunctionInfo 0x%p.\n", - functionId)); + (void*)functionId)); // // Verify parameters. @@ -6441,7 +6441,7 @@ HRESULT ProfToEEInterfaceImpl::GetNativeCodeStartAddresses(FunctionID functionID (LF_CORPROF, LL_INFO1000, "**PROF: GetNativeCodeStartAddresses 0x%p 0x%p.\n", - functionID, reJitId)); + (void*)functionID, (void*)reJitId)); HRESULT hr = S_OK; @@ -6543,7 +6543,7 @@ HRESULT ProfToEEInterfaceImpl::GetILToNativeMapping3(UINT_PTR pNativeCodeStartAd (LF_CORPROF, LL_INFO1000, "**PROF: GetILToNativeMapping3 0x%p.\n", - pNativeCodeStartAddress)); + (void*)pNativeCodeStartAddress)); if (pNativeCodeStartAddress == (PCODE)NULL) { @@ -6609,7 +6609,7 @@ HRESULT ProfToEEInterfaceImpl::GetCodeInfo4(UINT_PTR pNativeCodeStartAddress, (LF_CORPROF, LL_INFO1000, "**PROF: GetCodeInfo4 0x%p.\n", - pNativeCodeStartAddress)); + (void*)pNativeCodeStartAddress)); if ((cCodeInfos != 0) && (codeInfos == NULL)) { @@ -6721,7 +6721,7 @@ HRESULT ProfToEEInterfaceImpl::EnumerateObjectReferences(ObjectID objectId, Obje (LF_CORPROF, LL_INFO1000, "**PROF: EnumerateObjectReferences 0x%p.\n", - objectId)); + (void*)objectId)); if (callback == nullptr) { @@ -6771,7 +6771,7 @@ HRESULT ProfToEEInterfaceImpl::IsFrozenObject(ObjectID objectId, BOOL *pbFrozen) (LF_CORPROF, LL_INFO1000, "**PROF: IsFrozenObject 0x%p.\n", - objectId)); + (void*)objectId)); *pbFrozen = GCHeapUtilities::GetGCHeap()->IsInFrozenSegment((Object*)objectId) ? TRUE : FALSE; @@ -7938,7 +7938,7 @@ HRESULT ProfToEEInterfaceImpl::GetClassLayout(ClassID classID, (LF_CORPROF, LL_INFO1000, "**PROF: GetClassLayout 0x%p.\n", - classID)); + (void*)classID)); // // Verify parameters @@ -8554,7 +8554,7 @@ HRESULT ProfToEEInterfaceImpl::DoStackSnapshot(ThreadID thread, (LF_CORPROF, LL_INFO1000, "**PROF: DoStackSnapshot 0x%p, 0x%p, 0x%08x, 0x%p, 0x%p, 0x%08x.\n", - thread, + (void*)thread, callback, infoFlags, clientData, @@ -9197,7 +9197,7 @@ HRESULT ProfToEEInterfaceImpl::GetObjectGeneration(ObjectID objectId, (LF_CORPROF, LL_INFO1000, "**PROF: GetObjectGeneration 0x%p.\n", - objectId)); + (void*)objectId)); _ASSERTE((GetThreadNULLOk() == NULL) || (GetThreadNULLOk()->PreemptiveGCDisabled())); @@ -9260,7 +9260,7 @@ HRESULT ProfToEEInterfaceImpl::GetReJITIDs( (LF_CORPROF, LL_INFO1000, "**PROF: GetReJITIDs 0x%p.\n", - functionId)); + (void*)functionId)); if (functionId == 0) { diff --git a/src/runtime/src/coreclr/vm/rcwrefcache.cpp b/src/runtime/src/coreclr/vm/rcwrefcache.cpp index dd3dd63ab83b..4a4e14dfce7e 100644 --- a/src/runtime/src/coreclr/vm/rcwrefcache.cpp +++ b/src/runtime/src/coreclr/vm/rcwrefcache.cpp @@ -125,7 +125,7 @@ void RCWRefCache::ShrinkDependentHandles() { LOG((LF_INTEROP, LL_INFO100, - "\t[RCWRefCache 0x%p] Shrinking dependent handle cache. Total SLOTS = %d\n", + "\t[RCWRefCache 0x%p] Shrinking dependent handle cache. Total SLOTS = %zu\n", this, m_depHndList.Size() )); diff --git a/src/runtime/src/coreclr/vm/riscv64/singlestepper.cpp b/src/runtime/src/coreclr/vm/riscv64/singlestepper.cpp index 21e8e8e221b9..6865133d361a 100644 --- a/src/runtime/src/coreclr/vm/riscv64/singlestepper.cpp +++ b/src/runtime/src/coreclr/vm/riscv64/singlestepper.cpp @@ -7,6 +7,7 @@ // #include "common.h" +#include #include "riscv64singlestepper.h" // @@ -79,7 +80,7 @@ void RiscV64SingleStepper::Bypass(uint64_t ip, uint32_t opcode) } } - LOG((LF_CORDB, LL_INFO100000, "RiscV64SingleStepper::Bypass(pc=%lx, opcode=%x)\n", ip, opcode)); + LOG((LF_CORDB, LL_INFO100000, "RiscV64SingleStepper::Bypass(pc=%" PRIx64 ", opcode=%x)\n", ip, opcode)); m_fBypass = true; m_originalPc = ip; @@ -108,7 +109,7 @@ void RiscV64SingleStepper::Apply(T_CONTEXT *pCtx) uint32_t opcode = m_opcodes[0]; - LOG((LF_CORDB, LL_INFO100000, "RiscV64SingleStepper::Apply(pc=%lx, opcode=%x)\n", (uint64_t)pCtx->Pc, opcode)); + LOG((LF_CORDB, LL_INFO100000, "RiscV64SingleStepper::Apply(pc=%" PRIx64 ", opcode=%x)\n", (uint64_t)pCtx->Pc, opcode)); #ifdef _DEBUG // Make sure that we aren't trying to step through our own buffer. If this asserts, something is horribly @@ -252,7 +253,7 @@ bool RiscV64SingleStepper::Fixup(T_CONTEXT *pCtx, DWORD dwExceptionCode) { if (m_rgCode[0] != kBreakpointOp) { - LOG((LF_CORDB, LL_INFO100000, "RiscV64SingleStepper::Fixup executed code, ip = %lx\n", m_targetPc)); + LOG((LF_CORDB, LL_INFO100000, "RiscV64SingleStepper::Fixup executed code, ip = %" PRIx64 "\n", m_targetPc)); pCtx->Pc = m_targetPc; } @@ -275,7 +276,7 @@ bool RiscV64SingleStepper::Fixup(T_CONTEXT *pCtx, DWORD dwExceptionCode) pCtx->Pc = m_targetPc; - LOG((LF_CORDB, LL_INFO100000, "RiscV64SingleStepper::Fixup emulated, ip = %lx\n", pCtx->Pc)); + LOG((LF_CORDB, LL_INFO100000, "RiscV64SingleStepper::Fixup emulated, ip = %" PRIx64 "\n", pCtx->Pc)); } } else @@ -285,7 +286,7 @@ bool RiscV64SingleStepper::Fixup(T_CONTEXT *pCtx, DWORD dwExceptionCode) _ASSERTE(m_fEmulate == false); pCtx->Pc = m_originalPc; - LOG((LF_CORDB, LL_INFO100000, "RiscV64SingleStepper::Fixup hit exception pc = %lx ex = %x\n", pCtx->Pc, dwExceptionCode)); + LOG((LF_CORDB, LL_INFO100000, "RiscV64SingleStepper::Fixup hit exception pc = %" PRIx64 " ex = %x\n", pCtx->Pc, dwExceptionCode)); } // Note, 2 bytes alignment assertion here, since during managed stepping we could step/return diff --git a/src/runtime/src/coreclr/vm/riscv64/stubs.cpp b/src/runtime/src/coreclr/vm/riscv64/stubs.cpp index 8f175101a7f2..a5d6820bbb61 100644 --- a/src/runtime/src/coreclr/vm/riscv64/stubs.cpp +++ b/src/runtime/src/coreclr/vm/riscv64/stubs.cpp @@ -241,7 +241,8 @@ void TransitionFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFl // Finally, syncup the regdisplay with the context SyncRegDisplayToCurrentContext(pRD); - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK TransitionFrame::UpdateRegDisplay_Impl(pc:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); + LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK TransitionFrame::UpdateRegDisplay_Impl(pc:%p, sp:%p)\n", + reinterpret_cast(pRD->ControlPC), reinterpret_cast(pRD->SP))); } #ifdef FEATURE_INTERPRETER @@ -315,7 +316,8 @@ void FaultingExceptionFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool u pRD->IsCallerContextValid = FALSE; - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK FaultingExceptionFrame::UpdateRegDisplay_Impl(pc:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); + LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK FaultingExceptionFrame::UpdateRegDisplay_Impl(pc:%p, sp:%p)\n", + reinterpret_cast(pRD->ControlPC), reinterpret_cast(pRD->SP))); } void InlinedCallFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats) @@ -377,7 +379,8 @@ void InlinedCallFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateF // Update the frame pointer in the current context. pRD->pCurrentContextPointers->Fp = &m_pCalleeSavedFP; - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK InlinedCallFrame::UpdateRegDisplay_Impl(pc:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); + LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK InlinedCallFrame::UpdateRegDisplay_Impl(pc:%p, sp:%p)\n", + reinterpret_cast(pRD->ControlPC), reinterpret_cast(pRD->SP))); } #ifdef FEATURE_HIJACK @@ -438,7 +441,8 @@ void ResumableFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFlo pRD->IsCallerContextValid = FALSE; - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK ResumableFrame::UpdateRegDisplay_Impl(pc:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); + LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK ResumableFrame::UpdateRegDisplay_Impl(pc:%p, sp:%p)\n", + reinterpret_cast(pRD->ControlPC), reinterpret_cast(pRD->SP))); } void HijackFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats) @@ -496,7 +500,8 @@ void HijackFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats pRD->pCurrentContextPointers->Ra = NULL; SyncRegDisplayToCurrentContext(pRD); - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK HijackFrame::UpdateRegDisplay_Impl(pc:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); + LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK HijackFrame::UpdateRegDisplay_Impl(pc:%p, sp:%p)\n", + reinterpret_cast(pRD->ControlPC), reinterpret_cast(pRD->SP))); } #endif // FEATURE_HIJACK diff --git a/src/runtime/src/coreclr/vm/stackwalk.cpp b/src/runtime/src/coreclr/vm/stackwalk.cpp index cda43ae7f97c..82fb3c16e54c 100644 --- a/src/runtime/src/coreclr/vm/stackwalk.cpp +++ b/src/runtime/src/coreclr/vm/stackwalk.cpp @@ -1661,7 +1661,7 @@ StackWalkAction StackFrameIterator::Filter(void) { STRESS_LOG2(LF_GCROOTS, LL_INFO100, "STACKWALK: Reached parent of filter funclet @ CallerSP: %p, m_crawl.pFunc = %p\n", - m_sfFuncletParent.SP, m_crawl.pFunc); + (void*)m_sfFuncletParent.SP, m_crawl.pFunc); // Dev11 376329 - ARM: GC hole during filter funclet dispatch. // Filters are invoked during the first pass so we cannot skip @@ -1729,7 +1729,8 @@ StackWalkAction StackFrameIterator::Filter(void) STRESS_LOG4(LF_GCROOTS, LL_INFO100, "STACKWALK: Found %sFilter funclet @ SP: %p, m_crawl.pFunc = %p; FuncletParentCallerSP: %p\n", - (fIsFilterFunclet) ? "" : "Non-", GetRegdisplaySP(m_crawl.GetRegisterSet()), m_crawl.pFunc, m_sfFuncletParent.SP); + (fIsFilterFunclet) ? "" : "Non-", (void*)GetRegdisplaySP(m_crawl.GetRegisterSet()), + m_crawl.pFunc, (void*)m_sfFuncletParent.SP); if (!fIsFilterFunclet) { @@ -1833,7 +1834,7 @@ StackWalkAction StackFrameIterator::Filter(void) { STRESS_LOG2(LF_GCROOTS, LL_INFO100, "STACKWALK: Reached parent of non-filter funclet @ CallerSP: %p, m_crawl.pFunc = %p\n", - m_sfParent.SP, m_crawl.pFunc); + (void*)m_sfParent.SP, m_crawl.pFunc); // landing here indicates that the funclet's parent has been unwound so // this will always be true, no need to predicate on the state of the funclet @@ -1888,7 +1889,7 @@ StackWalkAction StackFrameIterator::Filter(void) STRESS_LOG2(LF_GCROOTS, LL_INFO100, "STACKWALK: Reached parent of non-filter funclet @ CallerSP: %p, m_crawl.pFunc = %p\n", - m_sfParent.SP, m_crawl.pFunc); + (void*)m_sfParent.SP, m_crawl.pFunc); // by default a funclet's parent won't report its GC roots since they would have already // been reported by the funclet. however there is a small window during unwind before @@ -1988,7 +1989,7 @@ StackWalkAction StackFrameIterator::Filter(void) "STACKWALK: %s: not making callback for this frame, SPOfParent = %p, \ isDiagnosticsHidden = %d, m_crawl.pFunc = %pM\n", (!m_sfParent.IsNull() ? "SKIPPING_TO_FUNCLET_PARENT" : "IS_DIAGNOSTICS_HIDDEN"), - m_sfParent.SP, + (void*)m_sfParent.SP, (m_crawl.pFunc->IsDiagnosticsHidden() ? 1 : 0), m_crawl.pFunc); @@ -2004,7 +2005,7 @@ StackWalkAction StackFrameIterator::Filter(void) "STACKWALK: %s: not making callback for this frame, SPOfParent = %p, \ isDiagnosticsHidden = %d, m_crawl.pFunc = %pM\n", (!m_sfParent.IsNull() ? "SKIPPING_TO_FUNCLET_PARENT" : "IS_DIAGNOSTICS_HIDDEN"), - m_sfParent.SP, + (void*)m_sfParent.SP, (m_crawl.pFunc->IsDiagnosticsHidden() ? 1 : 0), m_crawl.pFunc); @@ -2223,7 +2224,7 @@ StackWalkAction StackFrameIterator::NextRaw(void) { PTR_InterpreterFrame pInterpreterFrame = dac_cast(GetSP(m_crawl.pRD->pCurrentContext)); pInterpreterFrame->UpdateRegDisplay(m_crawl.pRD, m_flags & UNWIND_FLOATS); - LOG((LF_GCROOTS, LL_INFO10000, "STACKWALK: Transitioning from last interpreted frame under InterpreterFrame %p to native frame (IP=%p, SP=%p)\n", pInterpreterFrame, GetControlPC(m_crawl.pRD), GetRegdisplaySP(m_crawl.pRD))); + LOG((LF_GCROOTS, LL_INFO10000, "STACKWALK: Transitioning from last interpreted frame under InterpreterFrame %p to native frame (IP=%p, SP=%p)\n", pInterpreterFrame, (void*)GetControlPC(m_crawl.pRD), (void*)GetRegdisplaySP(m_crawl.pRD))); } #endif // FEATURE_INTERPRETER diff --git a/src/runtime/src/coreclr/vm/stubgen.cpp b/src/runtime/src/coreclr/vm/stubgen.cpp index 622a5b987a98..b6e2ec3a0e0d 100644 --- a/src/runtime/src/coreclr/vm/stubgen.cpp +++ b/src/runtime/src/coreclr/vm/stubgen.cpp @@ -10,6 +10,7 @@ #include "common.h" #include +#include #include "stubgen.h" #include "jitinterface.h" #include "ilstubcache.h" @@ -530,11 +531,11 @@ ILStubLinker::LogILInstruction( case ShortInlineVar: case ShortInlineI: case InlineI: - strArgument.Printf("0x%p", pInstruction->uArg); + strArgument.Printf("0x%zx", (size_t)pInstruction->uArg); break; case InlineI8: - strArgument.Printf("0x%llx", (uint64_t)pInstruction->uArg); + strArgument.Printf("0x%" PRIx64, (uint64_t)pInstruction->uArg); break; case InlineMethod: @@ -546,7 +547,7 @@ ILStubLinker::LogILInstruction( case InlineTok: // No token value when we dump IL for ETW if (pDumpILStubCode == NULL) - strArgument.Printf("0x%08p", pInstruction->uArg); + strArgument.Printf("0x%08zx", (size_t)pInstruction->uArg); // Dump to szTokenNameBuffer if logging, otherwise dump to szArgumentBuffer to avoid an extra space because we are omitting the token _ASSERTE(FitsIn(pInstruction->uArg)); diff --git a/src/runtime/src/coreclr/vm/stubhelpers.cpp b/src/runtime/src/coreclr/vm/stubhelpers.cpp index f122b797fad4..135d7a07c6d0 100644 --- a/src/runtime/src/coreclr/vm/stubhelpers.cpp +++ b/src/runtime/src/coreclr/vm/stubhelpers.cpp @@ -652,11 +652,11 @@ FCIMPL2(void, StubHelpers::LogPinnedArgument, MethodDesc *target, Object *pinned if (target != NULL) { - STRESS_LOG3(LF_STUBS, LL_INFO100, "Managed object %#X with size '%#X' pinned for interop to Method [%pM]\n", pinnedArg, managedSize, target); + STRESS_LOG3(LF_STUBS, LL_INFO100, "Managed object %p with size '%zu' pinned for interop to Method [%pM]\n", (void*)pinnedArg, managedSize, target); } else { - STRESS_LOG2(LF_STUBS, LL_INFO100, "Managed object %#X pinned for interop with size '%#X'", pinnedArg, managedSize); + STRESS_LOG2(LF_STUBS, LL_INFO100, "Managed object %p pinned for interop with size '%zu'", (void*)pinnedArg, managedSize); } } FCIMPLEND diff --git a/src/runtime/src/coreclr/vm/stubmgr.cpp b/src/runtime/src/coreclr/vm/stubmgr.cpp index 87c559554f2e..d4521dc8930c 100644 --- a/src/runtime/src/coreclr/vm/stubmgr.cpp +++ b/src/runtime/src/coreclr/vm/stubmgr.cpp @@ -42,13 +42,13 @@ void LogTraceDestination(const char * szHint, PCODE stubAddr, TraceDestination * MethodDesc * md = pTrace->GetMethodDesc(); LOG((LF_CORDB, LL_INFO10000, "'%s' yields '%s' to method %p for input %p.\n", szHint, GetTType(pTrace->GetTraceType()), - md, stubAddr)); + md, (void*)stubAddr)); } else { LOG((LF_CORDB, LL_INFO10000, "'%s' yields '%s' to address %p for input %p.\n", szHint, GetTType(pTrace->GetTraceType()), - pTrace->GetAddress(), stubAddr)); + (void*)pTrace->GetAddress(), (void*)stubAddr)); } } #endif @@ -84,22 +84,22 @@ const CHAR * TraceDestination::DbgToString(SString & buffer) switch(this->type) { case TRACE_ENTRY_STUB: - buffer.Printf("TRACE_ENTRY_STUB(addr=%p)", GetAddress()); + buffer.Printf("TRACE_ENTRY_STUB(addr=%p)", (void*)GetAddress()); pValue = buffer.GetUTF8(); break; case TRACE_STUB: - buffer.Printf("TRACE_STUB(addr=%p)", GetAddress()); + buffer.Printf("TRACE_STUB(addr=%p)", (void*)GetAddress()); pValue = buffer.GetUTF8(); break; case TRACE_UNMANAGED: - buffer.Printf("TRACE_UNMANAGED(addr=%p)", GetAddress()); + buffer.Printf("TRACE_UNMANAGED(addr=%p)", (void*)GetAddress()); pValue = buffer.GetUTF8(); break; case TRACE_MANAGED: - buffer.Printf("TRACE_MANAGED(addr=%p)", GetAddress()); + buffer.Printf("TRACE_MANAGED(addr=%p)", (void*)GetAddress()); pValue = buffer.GetUTF8(); break; @@ -112,12 +112,13 @@ const CHAR * TraceDestination::DbgToString(SString & buffer) break; case TRACE_FRAME_PUSH: - buffer.Printf("TRACE_FRAME_PUSH(addr=%p)", GetAddress()); + buffer.Printf("TRACE_FRAME_PUSH(addr=%p)", (void*)GetAddress()); pValue = buffer.GetUTF8(); break; case TRACE_MGR_PUSH: - buffer.Printf("TRACE_MGR_PUSH(addr=%p, sm=%s)", GetAddress(), this->GetStubManager()->DbgGetName()); + buffer.Printf("TRACE_MGR_PUSH(addr=%p, sm=%s)", (void*)GetAddress(), + this->GetStubManager()->DbgGetName()); pValue = buffer.GetUTF8(); break; @@ -518,13 +519,13 @@ PTR_StubManager StubManager::FindStubManager(PCODE stubAddress) _ASSERTE_IMPL(IsSingleOwner(stubAddress, it.Current())); LOG((LF_CORDB, LL_INFO10000, "SM::FSM: %p claims %p\n", - it.Current(), stubAddress)); + it.Current(), reinterpret_cast(stubAddress))); return it.Current(); } } LOG((LF_CORDB, LL_INFO10000, "SM::FSM: no stub manager claims %p\n", - stubAddress)); + reinterpret_cast(stubAddress))); return NULL; } @@ -544,7 +545,8 @@ BOOL StubManager::TraceStub(PCODE stubStartAddress, TraceDestination *trace) continue; LOG((LF_CORDB, LL_INFO10000, - "StubManager::TraceStub: '%s' (%p) claimed %p.\n", pCurrent->DbgGetName(), pCurrent, stubStartAddress)); + "StubManager::TraceStub: '%s' (%p) claimed %p.\n", pCurrent->DbgGetName(), pCurrent, + reinterpret_cast(stubStartAddress))); _ASSERTE_IMPL(IsSingleOwner(stubStartAddress, pCurrent)); @@ -552,7 +554,8 @@ BOOL StubManager::TraceStub(PCODE stubStartAddress, TraceDestination *trace) #ifdef _DEBUG if (IsStubLoggingEnabled()) { - DbgWriteLog("Doing TraceStub for %p, claimed by '%s' (%p)\n", stubStartAddress, pCurrent->DbgGetName(), pCurrent); + DbgWriteLog("Doing TraceStub for %p, claimed by '%s' (%p)\n", + reinterpret_cast(stubStartAddress), pCurrent->DbgGetName(), pCurrent); if (fValid) { SUPPRESS_ALLOCATION_ASSERTS_IN_THIS_SCOPE; @@ -573,22 +576,23 @@ BOOL StubManager::TraceStub(PCODE stubStartAddress, TraceDestination *trace) { LOG((LF_CORDB, LL_INFO10000, "StubManager::TraceStub: addr %p is managed code\n", - stubStartAddress)); + reinterpret_cast(stubStartAddress))); trace->InitForManaged(stubStartAddress); #ifdef _DEBUG - DbgWriteLog("Doing TraceStub for Address %p is jitted code claimed by codemanager\n", stubStartAddress); + DbgWriteLog("Doing TraceStub for Address %p is jitted code claimed by codemanager\n", + reinterpret_cast(stubStartAddress)); #endif return TRUE; } LOG((LF_CORDB, LL_INFO10000, "StubManager::TraceStub: addr %p unknown. TRACE_OTHER...\n", - stubStartAddress)); + reinterpret_cast(stubStartAddress))); #ifdef _DEBUG - DbgWriteLog("Doing TraceStub for Address %p is unknown!!!\n", stubStartAddress); + DbgWriteLog("Doing TraceStub for Address %p is unknown!!!\n", reinterpret_cast(stubStartAddress)); #endif trace->InitForOther(stubStartAddress); @@ -607,7 +611,7 @@ BOOL StubManager::FollowTrace(TraceDestination *trace) { LOG((LF_CORDB, LL_INFO10000, "StubManager::FollowTrace: TRACE_STUB for %p\n", - trace->GetAddress())); + reinterpret_cast(trace->GetAddress()))); if (!TraceStub(trace->GetAddress(), trace)) { @@ -1289,7 +1293,7 @@ BOOL StubLinkStubManager::DoTraceStub(PCODE stubStartAddress, LOG((LF_CORDB, LL_INFO10000, "StubLinkStubManager::DoTraceStub: stubStartAddress=%p\n", - stubStartAddress)); + reinterpret_cast(stubStartAddress))); StubCodeBlockKind kind = RangeSectionStubManager::GetStubKind(stubStartAddress); if (kind == STUB_CODE_BLOCK_WRAPPER_STUB) @@ -1353,7 +1357,7 @@ static BOOL TraceShuffleThunk( DELEGATEREF orDelegate = (DELEGATEREF)ObjectToOBJECTREF(StubManagerHelpers::GetThisPtr(pContext)); PCODE destAddr = orDelegate->GetMethodPtrAux(); - LOG((LF_CORDB,LL_INFO10000, "TraceShuffleThunk: ppbDest: %p\n", destAddr)); + LOG((LF_CORDB,LL_INFO10000, "TraceShuffleThunk: ppbDest: %p\n", reinterpret_cast(destAddr))); BOOL res = StubManager::TraceStub(destAddr, trace); LOG((LF_CORDB,LL_INFO10000, "TraceShuffleThunk: res: %d, result type: %d\n", res, trace->GetTraceType())); @@ -1716,7 +1720,7 @@ BOOL ILStubManager::TraceManager(Thread *thread, TADDR arg = StubManagerHelpers::GetHiddenArg(pContext); Object* pThis = StubManagerHelpers::GetThisPtr(pContext); LOG((LF_CORDB, LL_INFO1000, "ILSM::TraceManager: Enter: StubMD %p, HiddenArg %p, ThisPtr %p\n", - pStubMD, arg, pThis)); + pStubMD, reinterpret_cast(arg), pThis)); // See code:ILStubCache.CreateNewMethodDesc for the code that sets flags on stub MDs PCODE target = (PCODE)NULL; @@ -1733,7 +1737,8 @@ BOOL ILStubManager::TraceManager(Thread *thread, // This is reverse P/Invoke or COM-to-CLR stub, the argument is UMEntryThunkData UMEntryThunkData *pEntryThunk = (UMEntryThunkData*)arg; target = pEntryThunk->GetManagedTarget(); - LOG((LF_CORDB, LL_INFO10000, "ILSM::TraceManager: Reverse P/Invoke or COM-to-CLR case %p\n", target)); + LOG((LF_CORDB, LL_INFO10000, "ILSM::TraceManager: Reverse P/Invoke or COM-to-CLR case %p\n", + reinterpret_cast(target))); if (target == (PCODE)NULL) { @@ -1750,7 +1755,8 @@ BOOL ILStubManager::TraceManager(Thread *thread, DelegateObject *pDel = (DelegateObject *)pThis; target = pDel->GetMethodPtrAux(); - LOG((LF_CORDB, LL_INFO10000, "ILSM::TraceManager: Forward delegate P/Invoke case %p\n", target)); + LOG((LF_CORDB, LL_INFO10000, "ILSM::TraceManager: Forward delegate P/Invoke case %p\n", + reinterpret_cast(target))); trace->InitForUnmanaged(target); } else if (pStubMD->IsPInvokeCalliStub()) @@ -1758,7 +1764,8 @@ BOOL ILStubManager::TraceManager(Thread *thread, // This is unmanaged CALLI stub, the argument is the target target = (PCODE)arg; - LOG((LF_CORDB, LL_INFO10000, "ILSM::TraceManager: Unmanaged CALLI case %p\n", target)); + LOG((LF_CORDB, LL_INFO10000, "ILSM::TraceManager: Unmanaged CALLI case %p\n", + reinterpret_cast(target))); trace->InitForUnmanaged(target); } else if (pStubMD->IsStepThroughStub()) @@ -1789,7 +1796,8 @@ BOOL ILStubManager::TraceManager(Thread *thread, PInvokeMethodDesc* pNMD = reinterpret_cast(pMD); _ASSERTE_IMPL(!pNMD->PInvokeTargetIsImportThunk()); target = (PCODE)pNMD->GetPInvokeTarget(); - LOG((LF_CORDB, LL_INFO10000, "ILSM::TraceManager: Forward P/Invoke case 0x%p\n", target)); + LOG((LF_CORDB, LL_INFO10000, "ILSM::TraceManager: Forward P/Invoke case %p\n", + reinterpret_cast(target))); trace->InitForUnmanaged(target); } #ifdef FEATURE_COMINTEROP @@ -1805,7 +1813,8 @@ BOOL ILStubManager::TraceManager(Thread *thread, if (pThis != NULL) { target = SF_IsCOMLateBoundStub(dwStubFlags) ? GetLateBoundCOMTarget(pThis, pInfo) : GetCOMTarget(pThis, pInfo); - LOG((LF_CORDB, LL_INFO10000, "ILSM::TraceManager: CLR-to-COM case %p\n", target)); + LOG((LF_CORDB, LL_INFO10000, "ILSM::TraceManager: CLR-to-COM case %p\n", + reinterpret_cast(target))); trace->InitForUnmanaged(target); } } @@ -1890,7 +1899,7 @@ BOOL PInvokeStubManager::DoTraceStub(PCODE stubStartAddress, // between this read and the debugger setting a breakpoint, but this is // low priority to address. PCODE target = (PCODE)pNMD->GetPInvokeTarget(); - LOG((LF_CORDB, LL_INFO10000, "PISM::DoTraceStub: PInvoke target 0x%p\n", target)); + LOG((LF_CORDB, LL_INFO10000, "PISM::DoTraceStub: PInvoke target %p\n", reinterpret_cast(target))); trace->InitForUnmanaged(target); LOG_TRACE_DESTINATION(trace, target, "PInvokeStubManager::DoTraceStub"); @@ -2014,7 +2023,8 @@ BOOL InteropDispatchStubManager::TraceManager(Thread *thread, PInvokeMethodDesc *pNMD = (PInvokeMethodDesc *)arg; PCODE target = (PCODE)pNMD->GetPInvokeTarget(); - LOG((LF_CORDB, LL_INFO10000, "IDSM::TraceManager: Vararg P/Invoke case %p\n", target)); + LOG((LF_CORDB, LL_INFO10000, "IDSM::TraceManager: Vararg P/Invoke case %p\n", + reinterpret_cast(target))); trace->InitForUnmanaged(target); #endif //defined(TARGET_ARM64) && defined(__APPLE__) } @@ -2026,7 +2036,8 @@ BOOL InteropDispatchStubManager::TraceManager(Thread *thread, return FALSE; #else PCODE target = (PCODE)arg; - LOG((LF_CORDB, LL_INFO10000, "IDSM::TraceManager: Unmanaged CALLI case %p\n", target)); + LOG((LF_CORDB, LL_INFO10000, "IDSM::TraceManager: Unmanaged CALLI case %p\n", + reinterpret_cast(target))); trace->InitForUnmanaged(target); #endif //defined(TARGET_ARM64) && defined(__APPLE__) } diff --git a/src/runtime/src/coreclr/vm/syncblk.cpp b/src/runtime/src/coreclr/vm/syncblk.cpp index 33cfe3654937..3fa07e433449 100644 --- a/src/runtime/src/coreclr/vm/syncblk.cpp +++ b/src/runtime/src/coreclr/vm/syncblk.cpp @@ -1060,7 +1060,9 @@ BOOL SyncBlockCache::GCWeakPtrScanElement (int nb, HANDLESCANPROC scanProc, LPAR #ifdef VERIFY_HEAP if (g_pConfig->GetHeapVerifyLevel () & EEConfig::HEAPVERIFY_SYNCBLK) { - STRESS_LOG3 (LF_GC | LF_SYNC, LL_INFO100000, "scanning syncblk[%d, %p, %p]\n", nb, (size_t)SyncTableEntry::GetSyncTableEntry()[nb].m_SyncBlock, (size_t)*keyv); + STRESS_LOG3 (LF_GC | LF_SYNC, LL_INFO100000, "scanning syncblk[%d, %p, %p]\n", nb, + (void*)(size_t)SyncTableEntry::GetSyncTableEntry()[nb].m_SyncBlock, + (void*)(size_t)*keyv); } #endif @@ -1071,7 +1073,8 @@ BOOL SyncBlockCache::GCWeakPtrScanElement (int nb, HANDLESCANPROC scanProc, LPAR #ifdef VERIFY_HEAP if (g_pConfig->GetHeapVerifyLevel () & EEConfig::HEAPVERIFY_SYNCBLK) { - STRESS_LOG3 (LF_GC | LF_SYNC, LL_INFO100000, "freeing syncblk[%d, %p, %p]\n", nb, (size_t)pSB, (size_t)*keyv); + STRESS_LOG3 (LF_GC | LF_SYNC, LL_INFO100000, "freeing syncblk[%d, %p, %p]\n", nb, + (void*)(size_t)pSB, (void*)(size_t)*keyv); } #endif @@ -1296,7 +1299,7 @@ void DumpSyncBlockCache() descrip = buffer; } if (dumpSBStyle < 2) - LogSpewAlways("[%4.4d]: %zx %s\n", nb, oref, descrip); + LogSpewAlways("[%4.4d]: %p %s\n", nb, (void*)oref, descrip); else if (dumpSBStyle == 2) LogSpewAlways("[%4.4d]: %s\n", nb, descrip); } diff --git a/src/runtime/src/coreclr/vm/threads.cpp b/src/runtime/src/coreclr/vm/threads.cpp index 4519b127bb32..3a8d4d1901be 100644 --- a/src/runtime/src/coreclr/vm/threads.cpp +++ b/src/runtime/src/coreclr/vm/threads.cpp @@ -5204,7 +5204,7 @@ static void DebugLogStackRegionMBIs(UINT_PTR uLowAddress, UINT_PTR uHighAddress) if (sizeof(meminfo) != res) { - LOG((LF_EH, LL_INFO1000, "VirtualQuery failed on %p\n", uStartOfThisRegion)); + LOG((LF_EH, LL_INFO1000, "VirtualQuery failed on %p\n", (void*)uStartOfThisRegion)); break; } @@ -5217,7 +5217,8 @@ static void DebugLogStackRegionMBIs(UINT_PTR uLowAddress, UINT_PTR uHighAddress) UINT_PTR uRegionSize = uStartOfNextRegion - uStartOfThisRegion; - LOG((LF_EH, LL_INFO1000, "0x%p -> 0x%p (%d pg) ", uStartOfThisRegion, uStartOfNextRegion - 1, (int)(uRegionSize / minipal_getpagesize()))); + LOG((LF_EH, LL_INFO1000, "%p -> %p (%d pg) ", (void*)uStartOfThisRegion, + (void*)(uStartOfNextRegion - 1), (int)(uRegionSize / minipal_getpagesize()))); DebugLogMBIFlags(meminfo.State, meminfo.Protect); LOG((LF_EH, LL_INFO1000, "\n")); @@ -5255,10 +5256,12 @@ void Thread::DebugLogStackMBIs() UINT_PTR uStackSize = uStackBase - uStackLimit; LOG((LF_EH, LL_INFO1000, "----------------------------------------------------------------------\n")); - LOG((LF_EH, LL_INFO1000, "Stack Snapshot 0x%p -> 0x%p (%d pg)\n", uStackLimit, uStackBase, (int)(uStackSize / minipal_getpagesize()))); + LOG((LF_EH, LL_INFO1000, "Stack Snapshot %p -> %p (%d pg)\n", (void*)uStackLimit, + (void*)uStackBase, (int)(uStackSize / minipal_getpagesize()))); if (pThread) { - LOG((LF_EH, LL_INFO1000, "Last normal addr: 0x%p\n", pThread->GetLastNormalStackAddress())); + LOG((LF_EH, LL_INFO1000, "Last normal addr: %p\n", + (void*)pThread->GetLastNormalStackAddress())); } DebugLogStackRegionMBIs(uStackLimit, uStackBase); diff --git a/src/runtime/src/coreclr/vm/threadsuspend.cpp b/src/runtime/src/coreclr/vm/threadsuspend.cpp index fa8eaa26aba4..6b7bae1fa63e 100644 --- a/src/runtime/src/coreclr/vm/threadsuspend.cpp +++ b/src/runtime/src/coreclr/vm/threadsuspend.cpp @@ -536,7 +536,7 @@ BOOL EEGetThreadContext(Thread *pThread, CONTEXT *pContext) BOOL ret = pThread->GetThreadContext(pContext); STRESS_LOG6(LF_SYNC, LL_INFO1000, "Got thread context ret = %d EIP = %p ESP = %p EBP = %p, pThread = %p, ContextFlags = 0x%x\n", - ret, GetIP(pContext), GetSP(pContext), GetFP(pContext), pThread, pContext->ContextFlags); + ret, (void*)GetIP(pContext), (void*)GetSP(pContext), (void*)GetFP(pContext), pThread, pContext->ContextFlags); return ret; @@ -557,7 +557,7 @@ BOOL EESetThreadContext(Thread *pThread, const CONTEXT *pContext) BOOL ret = pThread->SetThreadContext(pContext); STRESS_LOG6(LF_SYNC, LL_INFO1000, "Set thread context ret = %d EIP = %p ESP = %p EBP = %p, pThread = %p, ContextFlags = 0x%x\n", - ret, GetIP((CONTEXT*)pContext), GetSP((CONTEXT*)pContext), GetFP((CONTEXT*)pContext), pThread, pContext->ContextFlags); + ret, (void*)GetIP((CONTEXT*)pContext), (void*)GetSP((CONTEXT*)pContext), (void*)GetFP((CONTEXT*)pContext), pThread, pContext->ContextFlags); return ret; } @@ -4314,7 +4314,7 @@ void Thread::SysResumeFromDebug(AppDomain *pAppDomain) return; } - LOG((LF_CORDB, LL_INFO1000, "RESUME: starting resume AD:0x%x.\n", pAppDomain)); + LOG((LF_CORDB, LL_INFO1000, "RESUME: starting resume AD:%p.\n", pAppDomain)); // Make sure we completed the previous sync @@ -4352,8 +4352,8 @@ void Thread::SysResumeFromDebug(AppDomain *pAppDomain) { // Thread will remain suspended due to a request from the debugger. - LOG((LF_CORDB,LL_INFO10000,"Didn't unsuspend thread 0x%x" - "(ID:0x%x)\n", thread, thread->GetThreadId())); + LOG((LF_CORDB,LL_INFO10000,"Didn't unsuspend thread %p" + "(ID:0x%x)\n", thread, thread->GetThreadId())); LOG((LF_CORDB,LL_INFO10000,"Suspending:0x%x\n", thread->m_State & TS_DebugSuspendPending)); _ASSERTE((thread->m_State & TS_DebugWillSync) == 0); @@ -4663,7 +4663,7 @@ StackWalkAction SWCB_GetExecutionState(CrawlFrame *pCF, VOID *pData) // current EIP for the penultimate stack frame. pES->m_ppvRetAddrPtr = (void **) GetRegdisplayPCTAddr(pRDT); - STRESS_LOG2(LF_SYNC, LL_INFO1000, "Partially Int case hijack address = 0x%x val = 0x%x\n", pES->m_ppvRetAddrPtr, *pES->m_ppvRetAddrPtr); + STRESS_LOG2(LF_SYNC, LL_INFO1000, "Partially Int case hijack address = %p val = %p\n", pES->m_ppvRetAddrPtr, *pES->m_ppvRetAddrPtr); } return action; } @@ -4687,7 +4687,7 @@ StackWalkAction SWCB_GetExecutionState(CrawlFrame *pCF, VOID *pData) pES->m_pJitManager = pCF->GetJitManager(); STRESS_LOG3(LF_SYNC, LL_INFO1000, "Stopped in Jitted code at pc = %p sp = %p fullyInt=%d\n", - GetControlPC(pCF->GetRegisterSet()), GetRegdisplaySP(pCF->GetRegisterSet()), pES->m_IsInterruptible); + (void*)GetControlPC(pCF->GetRegisterSet()), (void*)GetRegdisplaySP(pCF->GetRegisterSet()), pES->m_IsInterruptible); #if defined(FEATURE_CONSERVATIVE_GC) && !defined(USE_GC_INFO_DECODER) if (g_pConfig->GetGCConservative()) @@ -4808,9 +4808,9 @@ StackWalkAction SWCB_GetExecutionState(CrawlFrame *pCF, VOID *pData) else { #ifdef TARGET_X86 - STRESS_LOG2(LF_SYNC, LL_INFO1000, "Not in Jitted code at EIP = %p, &EIP = %p\n", GetControlPC(pCF->GetRegisterSet()), GetRegdisplayPCTAddr(pCF->GetRegisterSet())); + STRESS_LOG2(LF_SYNC, LL_INFO1000, "Not in Jitted code at EIP = %p, &EIP = %p\n", (void*)GetControlPC(pCF->GetRegisterSet()), (void*)GetRegdisplayPCTAddr(pCF->GetRegisterSet())); #else - STRESS_LOG1(LF_SYNC, LL_INFO1000, "Not in Jitted code at pc = %p\n", GetControlPC(pCF->GetRegisterSet())); + STRESS_LOG1(LF_SYNC, LL_INFO1000, "Not in Jitted code at pc = %p\n", (void*)GetControlPC(pCF->GetRegisterSet())); #endif notJittedCase = true; } diff --git a/src/runtime/src/coreclr/vm/tieredcompilation.cpp b/src/runtime/src/coreclr/vm/tieredcompilation.cpp index 3a77393aae43..ae74980df008 100644 --- a/src/runtime/src/coreclr/vm/tieredcompilation.cpp +++ b/src/runtime/src/coreclr/vm/tieredcompilation.cpp @@ -936,7 +936,7 @@ BOOL TieredCompilationManager::CompileCodeVersion(NativeCodeVersion nativeCodeVe LOG((LF_TIEREDCOMPILATION, LL_INFO10000, "TieredCompilationManager::CompileCodeVersion Method=0x%pM (%s::%s), code version id=0x%x, code ptr=0x%p\n", pMethod, pMethod->m_pszDebugClassName, pMethod->m_pszDebugMethodName, nativeCodeVersion.GetVersionId(), - pCode)); + (void*)pCode)); if (config->JitSwitchedToMinOpt()) { diff --git a/src/runtime/src/coreclr/vm/util.cpp b/src/runtime/src/coreclr/vm/util.cpp index 2c1b6ec4b3b3..c94c7fcc8214 100644 --- a/src/runtime/src/coreclr/vm/util.cpp +++ b/src/runtime/src/coreclr/vm/util.cpp @@ -581,7 +581,7 @@ SIZE_T *NativeVarStackAddr(const ICorDebugInfo::VarLoc & varLoc, { dwAddr = (SIZE_T*)(*dwAddr); } - LOG((LF_CORDB, LL_INFO100, "NVSA: VLT_REG @ 0x%x (by ref = %d)\n", dwAddr, fByRef)); + LOG((LF_CORDB, LL_INFO100, "NVSA: VLT_REG @ %p (by ref = %d)\n", dwAddr, fByRef)); break; case ICorDebugInfo::VLT_STK_BYREF: @@ -595,7 +595,7 @@ SIZE_T *NativeVarStackAddr(const ICorDebugInfo::VarLoc & varLoc, { dwAddr = (SIZE_T*)(*dwAddr); } - LOG((LF_CORDB, LL_INFO100, "NVSA: VLT_STK @ 0x%x (by ref = %d)\n", dwAddr, fByRef)); + LOG((LF_CORDB, LL_INFO100, "NVSA: VLT_STK @ %p (by ref = %d)\n", dwAddr, fByRef)); break; case ICorDebugInfo::VLT_STK2: @@ -605,21 +605,21 @@ SIZE_T *NativeVarStackAddr(const ICorDebugInfo::VarLoc & varLoc, regOffs = GetRegOffsInCONTEXT(varLoc.vlStk2.vls2BaseReg); baseReg = (const BYTE *)*(SIZE_T *)(regOffs + (BYTE*)pCtx); dwAddr = (SIZE_T *)(baseReg + varLoc.vlStk2.vls2Offset); - LOG((LF_CORDB, LL_INFO100, "NVSA: VLT_STK_2 @ 0x%x\n",dwAddr)); + LOG((LF_CORDB, LL_INFO100, "NVSA: VLT_STK_2 @ %p\n", dwAddr)); break; case ICorDebugInfo::VLT_REG_STK: regOffs = GetRegOffsInCONTEXT(varLoc.vlRegStk.vlrsStk.vlrssBaseReg); baseReg = (const BYTE *)*(SIZE_T *)(regOffs + (BYTE*)pCtx); dwAddr = (SIZE_T *)(baseReg + varLoc.vlRegStk.vlrsStk.vlrssOffset); - LOG((LF_CORDB, LL_INFO100, "NVSA: REG_STK @ 0x%x\n",dwAddr)); + LOG((LF_CORDB, LL_INFO100, "NVSA: REG_STK @ %p\n", dwAddr)); break; case ICorDebugInfo::VLT_STK_REG: regOffs = GetRegOffsInCONTEXT(varLoc.vlStkReg.vlsrStk.vlsrsBaseReg); baseReg = (const BYTE *)*(SIZE_T *)(regOffs + (BYTE*)pCtx); dwAddr = (SIZE_T *)(baseReg + varLoc.vlStkReg.vlsrStk.vlsrsOffset); - LOG((LF_CORDB, LL_INFO100, "NVSA: STK_REG @ 0x%x\n",dwAddr)); + LOG((LF_CORDB, LL_INFO100, "NVSA: STK_REG @ %p\n", dwAddr)); break; case ICorDebugInfo::VLT_REG_REG: @@ -692,20 +692,20 @@ bool GetNativeVarVal(const ICorDebugInfo::VarLoc & varLoc, case ICorDebugInfo::VLT_REG_REG: regOffs = GetRegOffsInCONTEXT(varLoc.vlRegReg.vlrrReg1); *pVal1 = *(SIZE_T *)(regOffs + (BYTE*)pCtx); - LOG((LF_CORDB, LL_INFO100, "GNVV: STK_REG_REG 1 @ 0x%x\n", - (SIZE_T *)(regOffs + (BYTE*)pCtx))); + LOG((LF_CORDB, LL_INFO100, "GNVV: STK_REG_REG 1 @ %p\n", + (void*)(regOffs + (BYTE*)pCtx))); regOffs = GetRegOffsInCONTEXT(varLoc.vlRegReg.vlrrReg2); *pVal2 = *(SIZE_T *)(regOffs + (BYTE*)pCtx); - LOG((LF_CORDB, LL_INFO100, "GNVV: STK_REG_REG 2 @ 0x%x\n", - (SIZE_T *)(regOffs + (BYTE*)pCtx))); + LOG((LF_CORDB, LL_INFO100, "GNVV: STK_REG_REG 2 @ %p\n", + (void*)(regOffs + (BYTE*)pCtx))); break; case ICorDebugInfo::VLT_REG_STK: regOffs = GetRegOffsInCONTEXT(varLoc.vlRegStk.vlrsReg); *pVal1 = *(SIZE_T *)(regOffs + (BYTE*)pCtx); - LOG((LF_CORDB, LL_INFO100, "GNVV: STK_REG_STK reg @ 0x%x\n", - (SIZE_T *)(regOffs + (BYTE*)pCtx))); + LOG((LF_CORDB, LL_INFO100, "GNVV: STK_REG_STK reg @ %p\n", + (void*)(regOffs + (BYTE*)pCtx))); *pVal2 = *NativeVarStackAddr(varLoc,pCtx); break; @@ -713,8 +713,8 @@ bool GetNativeVarVal(const ICorDebugInfo::VarLoc & varLoc, *pVal1 = *NativeVarStackAddr(varLoc,pCtx); regOffs = GetRegOffsInCONTEXT(varLoc.vlStkReg.vlsrReg); *pVal2 = *(SIZE_T *)(regOffs + (BYTE*)pCtx); - LOG((LF_CORDB, LL_INFO100, "GNVV: STK_STK_REG reg @ 0x%x\n", - (SIZE_T *)(regOffs + (BYTE*)pCtx))); + LOG((LF_CORDB, LL_INFO100, "GNVV: STK_STK_REG reg @ %p\n", + (void*)(regOffs + (BYTE*)pCtx))); break; case ICorDebugInfo::VLT_FPSTK: @@ -798,20 +798,20 @@ bool SetNativeVarVal(const ICorDebugInfo::VarLoc & varLoc, case ICorDebugInfo::VLT_REG_REG: regOffs = GetRegOffsInCONTEXT(varLoc.vlRegReg.vlrrReg1); *(SIZE_T *)(regOffs + (BYTE*)pCtx) = val1; - LOG((LF_CORDB, LL_INFO100, "SNVV: STK_REG_REG 1 @ 0x%x\n", - (SIZE_T *)(regOffs + (BYTE*)pCtx))); + LOG((LF_CORDB, LL_INFO100, "SNVV: STK_REG_REG 1 @ %p\n", + (void*)(regOffs + (BYTE*)pCtx))); regOffs = GetRegOffsInCONTEXT(varLoc.vlRegReg.vlrrReg2); *(SIZE_T *)(regOffs + (BYTE*)pCtx) = val2; - LOG((LF_CORDB, LL_INFO100, "SNVV: STK_REG_REG 2 @ 0x%x\n", - (SIZE_T *)(regOffs + (BYTE*)pCtx))); + LOG((LF_CORDB, LL_INFO100, "SNVV: STK_REG_REG 2 @ %p\n", + (void*)(regOffs + (BYTE*)pCtx))); break; case ICorDebugInfo::VLT_REG_STK: regOffs = GetRegOffsInCONTEXT(varLoc.vlRegStk.vlrsReg); *(SIZE_T *)(regOffs + (BYTE*)pCtx) = val1; - LOG((LF_CORDB, LL_INFO100, "SNVV: STK_REG_STK reg @ 0x%x\n", - (SIZE_T *)(regOffs + (BYTE*)pCtx))); + LOG((LF_CORDB, LL_INFO100, "SNVV: STK_REG_STK reg @ %p\n", + (void*)(regOffs + (BYTE*)pCtx))); *NativeVarStackAddr(varLoc,pCtx) = val2; break; @@ -819,8 +819,8 @@ bool SetNativeVarVal(const ICorDebugInfo::VarLoc & varLoc, *NativeVarStackAddr(varLoc,pCtx) = val1; regOffs = GetRegOffsInCONTEXT(varLoc.vlStkReg.vlsrReg); *(SIZE_T *)(regOffs + (BYTE*)pCtx) = val2; - LOG((LF_CORDB, LL_INFO100, "SNVV: STK_STK_REG reg @ 0x%x\n", - (SIZE_T *)(regOffs + (BYTE*)pCtx))); + LOG((LF_CORDB, LL_INFO100, "SNVV: STK_STK_REG reg @ %p\n", + (void*)(regOffs + (BYTE*)pCtx))); break; case ICorDebugInfo::VLT_FPSTK: diff --git a/src/runtime/src/coreclr/vm/wasm/helpers.cpp b/src/runtime/src/coreclr/vm/wasm/helpers.cpp index 6eeec6218433..0fce10ac0ac4 100644 --- a/src/runtime/src/coreclr/vm/wasm/helpers.cpp +++ b/src/runtime/src/coreclr/vm/wasm/helpers.cpp @@ -517,7 +517,7 @@ void InlinedCallFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateF } #endif // FEATURE_INTERPRETER - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK InlinedCallFrame::UpdateRegDisplay_Impl(rip:%p, rsp:%p)\n", pRD->ControlPC, pRD->SP)); + LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK InlinedCallFrame::UpdateRegDisplay_Impl(rip:%p, rsp:%p)\n", (void*)(size_t)pRD->ControlPC, (void*)(size_t)pRD->SP)); } void FaultingExceptionFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats) @@ -546,7 +546,7 @@ void TransitionFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFl SyncRegDisplayToCurrentContext(pRD); - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK TransitionFrame::UpdateRegDisplay_Impl(rip:%p, rsp:%p)\n", pRD->ControlPC, pRD->SP)); + LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK TransitionFrame::UpdateRegDisplay_Impl(rip:%p, rsp:%p)\n", (void*)(size_t)pRD->ControlPC, (void*)(size_t)pRD->SP)); } size_t CallDescrWorkerInternalReturnAddressOffset = 0; @@ -1049,14 +1049,15 @@ namespace ToV128, ToSlotsI64, // Passed by value as several i64 slots (Int128/UInt128) ToSlotsV128, // Passed by value as several v128 slots (Vector256, Vector512) - ToStruct, // S — multi-field struct passed by pointer, structSize holds the size + ToStruct, // S/A — multi-field struct passed by pointer ToEmpty, // e — empty struct, takes no wasm argument }; struct ConvertResult { ConvertType type; - uint32_t structSize; // only meaningful when type == ToStruct + uint32_t structSize; // meaningful for struct and multi-slot types + bool requiresAlignedStructSlot; // only meaningful when type == ToStruct }; // Lowers a TypeHandle to a ConvertResult, unwrapping single-field structs @@ -1237,7 +1238,7 @@ namespace // One field with padding — treat as multi-field struct } - return { ConvertType::ToStruct, size }; + return { ConvertType::ToStruct, size, CEEInfo::getClassAlignmentRequirementStatic(th) > INTERP_STACK_SLOT_SIZE }; } ConvertResult ConvertibleTo(CorElementType argType, MetaSig& sig, bool isReturn) @@ -1316,9 +1317,11 @@ namespace case ConvertType::ToEmpty: c = 'e'; break; case ConvertType::ToStruct: { - // Encode as S where N is the struct size in decimal + // A struct whose alignment exceeds 8 is placed at a 16-byte aligned transition-block + // slot. The interpreter stack does not support a larger placement alignment. char sizeBuf[16]; - int len = sprintf_s(sizeBuf, sizeof(sizeBuf), "S%u", cr.structSize); + int len = sprintf_s(sizeBuf, sizeof(sizeBuf), "%c%u", + cr.requiresAlignedStructSlot ? 'A' : 'S', cr.structSize); for (int j = 0; j < len; j++) { if (pos + (uint32_t)j < maxSize) @@ -1378,6 +1381,7 @@ namespace { cr.type = ConvertType::ToStruct; } + cr.requiresAlignedStructSlot = false; pos += AppendTypeCode(cr, keyBuffer, pos, maxSize); } diff --git a/src/runtime/src/libraries/Common/src/System/Net/Http/aspnetcore/Http3/QPack/QPackDecoder.cs b/src/runtime/src/libraries/Common/src/System/Net/Http/aspnetcore/Http3/QPack/QPackDecoder.cs index 155bb5fc8ca6..f4b3691e9320 100644 --- a/src/runtime/src/libraries/Common/src/System/Net/Http/aspnetcore/Http3/QPack/QPackDecoder.cs +++ b/src/runtime/src/libraries/Common/src/System/Net/Http/aspnetcore/Http3/QPack/QPackDecoder.cs @@ -712,6 +712,8 @@ private static bool IsHuffmanEncoded(byte b) private void OnIndexedHeaderName(int index) { + ThrowIfInvalidStaticIndex(index); + _headerStaticIndex = index; _state = State.HeaderValueLength; } @@ -751,10 +753,20 @@ private void OnRequiredInsertCount(int requiredInsertCount) private void OnIndexedHeaderField(int index, IHttpStreamHeadersHandler handler) { + ThrowIfInvalidStaticIndex(index); + handler.OnStaticIndexedHeader(index); _state = State.CompressedHeaders; } + private static void ThrowIfInvalidStaticIndex(int index) + { + if (index >= H3StaticTable.Count) + { + throw new QPackDecodingException(SR.Format(SR.net_http_qpack_invalid_index, index)); + } + } + private static void ThrowDynamicTableNotSupported() { throw new QPackDecodingException(SR.net_http_qpack_no_dynamic_table); diff --git a/src/runtime/src/libraries/Common/src/System/Net/Http/aspnetcore/SR.resx b/src/runtime/src/libraries/Common/src/System/Net/Http/aspnetcore/SR.resx index 9c5ece61a779..54ec7fab30c2 100644 --- a/src/runtime/src/libraries/Common/src/System/Net/Http/aspnetcore/SR.resx +++ b/src/runtime/src/libraries/Common/src/System/Net/Http/aspnetcore/SR.resx @@ -150,6 +150,9 @@ Received an invalid header name: '{0}'. + + Invalid header index: {0} is outside of the static table. + No dynamic table support diff --git a/src/runtime/src/libraries/Common/tests/Tests/System/Net/aspnetcore/Http3/QPackDecoderTest.cs b/src/runtime/src/libraries/Common/tests/Tests/System/Net/aspnetcore/Http3/QPackDecoderTest.cs index e78b93517aa0..6414acbc3635 100644 --- a/src/runtime/src/libraries/Common/tests/Tests/System/Net/aspnetcore/Http3/QPackDecoderTest.cs +++ b/src/runtime/src/libraries/Common/tests/Tests/System/Net/aspnetcore/Http3/QPackDecoderTest.cs @@ -340,6 +340,20 @@ public void DecodesIncompleteHeaderBlock_Error(byte[] encoded) Assert.Empty(_handler.DecodedHeaders); } + [Theory] + // Indexed Field Line - Static Table - Index 99 (out of range) + [InlineData(new byte[] { 0xff, 0x24 }, 99)] + // Literal Header Field With Name Reference - Static Table - Index 99 (out of range) + [InlineData(new byte[] { 0x5f, 0x54, 0x01, 0x61 }, 99)] + public void DecodesIndexOutsideStaticTable_Error(byte[] encoded, int index) + { + _decoder.Decode([0x00, 0x00], endHeaders: false, handler: _handler); + + var exception = Assert.Throws(() => _decoder.Decode(encoded, endHeaders: true, handler: _handler)); + Assert.Equal(SR.Format(SR.net_http_qpack_invalid_index, index), exception.Message); + Assert.Empty(_handler.DecodedHeaders); + } + private static void TestDecodeWithoutIndexing(byte[] encoded, string expectedHeaderName, string expectedHeaderValue) { KeyValuePair[] expectedValues = new[] { new KeyValuePair(expectedHeaderName, expectedHeaderValue) }; diff --git a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/DiagDescriptors.cs b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/DiagDescriptors.cs index 49562a0a128c..1b66b8f58063 100644 --- a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/DiagDescriptors.cs +++ b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/DiagDescriptors.cs @@ -119,5 +119,11 @@ internal sealed class DiagDescriptors : DiagDescriptorsBase messageFormat: SR.TypeCannotBeUsedWithTheValidationAttributeMessage, category: Category, defaultSeverity: DiagnosticSeverity.Warning); + + public static DiagnosticDescriptor AlreadyImplementsValidateAsyncMethod { get; } = Make( + id: "SYSLIB1219", + title: SR.AlreadyImplementsValidateAsyncMethodTitle, + messageFormat: SR.AlreadyImplementsValidateAsyncMethodMessage, + category: Category); } } diff --git a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Emitter.cs b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Emitter.cs index 4318990dd942..954d9368d9de 100644 --- a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Emitter.cs +++ b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Emitter.cs @@ -129,7 +129,20 @@ private void GenValidatorType(ValidatorType vt, ref Dictionary (_symbolHolder.HasTryValidateValueAsyncMethod && vm.ValidationAttributes.Count > 0) + || vm.TransValidatorEmitsAsync + || vm.EnumerationValidatorEmitsAsync; + + // Whether this member can actually suspend. Synchronous validation attributes are still invoked through + // TryValidateValueAsync, but that call completes synchronously and does not justify the per-member allocations + // required by the concurrent validation path. + private bool MemberAsyncValidationCanSuspend(ValidatedMember vm) + => (_symbolHolder.HasTryValidateValueAsyncMethod && vm.ValidationAttributes.Any(static attr => attr.IsAsyncValidationAttribute)) + || vm.TransValidatorEmitsAsync + || vm.EnumerationValidatorEmitsAsync; + + private void GenAsyncModelValidationMethod( + ValidatedModel modelToValidate, + bool makeStatic, + ref Dictionary staticValidationAttributesDict, + ref Dictionary staticValidatorsDict) + { + bool concurrentMembers = modelToValidate.MembersToValidate.Count >= 2 + && modelToValidate.MembersToValidate.Any(MemberAsyncValidationCanSuspend); + + // Determine whether the generated method body will contain any await. The method is always declared + // async regardless (so that cancellationToken.ThrowIfCancellationRequested() below surfaces as a + // faulted/canceled Task instead of throwing synchronously to the caller - a plain non-async method + // would throw directly). When the body genuinely contains no await (e.g. the model only self-validates + // synchronously via IValidatableObject and has no members), we suppress the resulting CS1998 warning. + // Running two or more members concurrently always awaits Task.WhenAll. + bool willAwait = concurrentMembers || modelToValidate.SelfValidatesAsync; + if (!willAwait) + { + foreach (var vm in modelToValidate.MembersToValidate) + { + if (MemberAsyncValidationHasAwait(vm)) + { + willAwait = true; + break; + } + } + } + + OutLn($"/// "); + OutLn($"/// Validates a specific named options instance asynchronously (or all when is )."); + OutLn($"/// "); + OutLn($"/// The name of the options instance being validated."); + OutLn($"/// The options instance."); + OutLn($"/// The to monitor for cancellation requests."); + OutLn($"/// A task representing the asynchronous validation operation, containing the validation result."); + OutGeneratedCodeAttribute(); + + if (_symbolHolder.UnconditionalSuppressMessageAttributeSymbol is not null) + { + // We disable the warning on `new ValidationContext(object)` usage as we use it in a safe way that not require executing the reflection code. + // This is done by initializing the DisplayName in the context which is the part trigger reflection if it is not initialized. For + // projects targeting .NET 10 and above, we can avoid the suppression since we use the new trim-safe constructor. + OutLn("#if !NET"); + OutLn($"[global::System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessage(\"Trimming\", \"IL2026:RequiresUnreferencedCode\","); + OutLn($" Justification = \"The created ValidationContext object is used in a way that never call reflection\")]"); + OutLn("#endif"); + } + + if (!willAwait) + { + OutLn("#pragma warning disable CS1998 // The method is declared async so cancellationToken.ThrowIfCancellationRequested() below surfaces on the returned Task rather than throwing synchronously."); + } + + OutLn($"public {(makeStatic ? "static " : string.Empty)}async global::System.Threading.Tasks.Task ValidateAsync(string? name, {modelToValidate.Name} options, global::System.Threading.CancellationToken cancellationToken = default)"); + OutOpenBrace(); + OutLn($"cancellationToken.ThrowIfCancellationRequested();"); + OutLn(); + OutLn($"global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null;"); + + bool contextDeclared = false; + if (concurrentMembers) + { + GenConcurrentAsyncMemberValidations(modelToValidate, ref staticValidationAttributesDict, ref staticValidatorsDict); + } + else + { + OutLn("#if NET"); + OutLn($"var context = new {StaticValidationContextType}(options, \"{modelToValidate.SimpleName}\", null, null);"); + OutLn("#else"); + OutLn($"var context = new {StaticValidationContextType}(options);"); + OutLn("#endif"); + contextDeclared = true; + + int capacity = modelToValidate.MembersToValidate.Count == 0 ? 0 : modelToValidate.MembersToValidate.Max(static vm => vm.ValidationAttributes.Count); + if (capacity > 0) + { + OutLn($"var validationResults = new {StaticListType}<{StaticValidationResultType}>();"); + OutLn($"var validationAttributes = new {StaticListType}<{StaticValidationAttributeType}>({capacity});"); + } + OutLn(); + + bool cleanListsBeforeUse = false; + foreach (var vm in modelToValidate.MembersToValidate) + { + if (vm.ValidationAttributes.Count > 0) + { + GenAsyncMemberValidation(vm, ref staticValidationAttributesDict, cleanListsBeforeUse); + cleanListsBeforeUse = true; + OutLn(); + } + + if (vm.TransValidatorType is not null) + { + GenAsyncTransitiveValidation(vm, ref staticValidatorsDict); + OutLn(); + } + + if (vm.EnumerationValidatorType is not null) + { + GenAsyncEnumerationValidation(vm, ref staticValidatorsDict); + OutLn(); + } + } + } + + if (!contextDeclared && (modelToValidate.SelfValidatesAsync || modelToValidate.SelfValidates)) + { + OutLn("#if NET"); + OutLn($"var context = new {StaticValidationContextType}(options, \"{modelToValidate.SimpleName}\", null, null);"); + OutLn("#else"); + OutLn($"var context = new {StaticValidationContextType}(options);"); + OutLn("#endif"); + } + + GenAsyncModelSelfValidationIfNecessary(modelToValidate); + + GenValidateOptionsResultReturn("builder"); + OutCloseBrace(); + + if (!willAwait) + { + OutLn("#pragma warning restore CS1998"); + } + } + + // Emits one async local function per member (each owning its own ValidationContext, ValidationResult list, + // ValidationAttribute list, and ValidateOptionsResultBuilder - no mutable state is shared between members), + // starts them all, and awaits their completion together via Task.WhenAll so member validation for a model + // with 2+ MembersToValidate runs concurrently (see dotnet/runtime issue #128882). The per-member results are + // then merged into the outer builder in original declaration order, regardless of completion order, so + // existing failure ordering remains deterministic. + private void GenConcurrentAsyncMemberValidations( + ValidatedModel modelToValidate, + ref Dictionary staticValidationAttributesDict, + ref Dictionary staticValidatorsDict) + { + var members = modelToValidate.MembersToValidate; + var taskVarNames = new string[members.Count]; + + for (int i = 0; i < members.Count; i++) + { + var vm = members[i]; + bool memberHasAwait = MemberAsyncValidationHasAwait(vm); + string builderVar = $"memberBuilder{i}"; + string contextVar = $"memberContext{i}"; + string resultsVar = $"memberValidationResults{i}"; + string attributesVar = $"memberValidationAttributes{i}"; + + if (!memberHasAwait) + { + OutLn("#pragma warning disable CS1998 // This member's validation never awaits, but the local function is declared async to participate uniformly in Task.WhenAll below."); + } + + OutLn($"async global::System.Threading.Tasks.Task Validate{i}Async()"); + OutOpenBrace(); + OutLn($"global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? {builderVar} = null;"); + + if (vm.ValidationAttributes.Count > 0) + { + OutLn("#if NET"); + OutLn($"var {contextVar} = new {StaticValidationContextType}(options, \"{modelToValidate.SimpleName}\", null, null);"); + OutLn("#else"); + OutLn($"var {contextVar} = new {StaticValidationContextType}(options);"); + OutLn("#endif"); + OutLn($"var {resultsVar} = new {StaticListType}<{StaticValidationResultType}>();"); + OutLn($"var {attributesVar} = new {StaticListType}<{StaticValidationAttributeType}>({vm.ValidationAttributes.Count});"); + + GenAsyncMemberValidation(vm, ref staticValidationAttributesDict, cleanListsBeforeUse: false, contextVar, builderVar, resultsVar, attributesVar); + } + + if (vm.TransValidatorType is not null) + { + GenAsyncTransitiveValidation(vm, ref staticValidatorsDict, builderVar); + } + + if (vm.EnumerationValidatorType is not null) + { + GenAsyncEnumerationValidation(vm, ref staticValidatorsDict, builderVar); + } + + GenValidateOptionsResultReturn(builderVar); + OutCloseBrace(); + + if (!memberHasAwait) + { + OutLn("#pragma warning restore CS1998"); + } + + OutLn(); + + taskVarNames[i] = $"memberTask{i}"; + } + + for (int i = 0; i < members.Count; i++) + { + OutLn($"var {taskVarNames[i]} = Validate{i}Async();"); + } + + OutLn($"var memberResults = await global::System.Threading.Tasks.Task.WhenAll({string.Join(", ", taskVarNames)}).ConfigureAwait(false);"); + OutLn(); + + for (int i = 0; i < members.Count; i++) + { + OutLn($"if (memberResults[{i}].Failed)"); + OutOpenBrace(); + OutLn($"(builder ??= new()).AddResult(memberResults[{i}]);"); + OutCloseBrace(); + } + } + + private void GenValidateOptionsResultReturn(string builderVariable) + { + OutLn($"return {builderVariable} is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : {builderVariable}.Build();"); + } + + private void GenAsyncMemberValidation( + ValidatedMember vm, + ref Dictionary staticValidationAttributesDict, + bool cleanListsBeforeUse, + string contextVar = "context", + string builderVar = "builder", + string resultsVar = "validationResults", + string attributesVar = "validationAttributes") + { + OutLn($"{contextVar}.MemberName = \"{vm.Name}\";"); + OutLn($"{contextVar}.DisplayName = string.IsNullOrEmpty(name) ? \"{vm.Name}\" : $\"{{name}}.{vm.Name}\";"); + + if (cleanListsBeforeUse) + { + OutLn($"{resultsVar}.Clear();"); + OutLn($"{attributesVar}.Clear();"); + } + + foreach (var attr in vm.ValidationAttributes) + { + var staticValidationAttributeInstance = GetOrAddStaticValidationAttribute(ref staticValidationAttributesDict, attr); + OutLn($"{attributesVar}.Add({_staticValidationAttributeHolderClassFQN}.{staticValidationAttributeInstance.FieldName});"); + } + + if (_symbolHolder.HasTryValidateValueAsyncMethod) + { + OutLn($"if (!await global::System.ComponentModel.DataAnnotations.Validator.TryValidateValueAsync(options.{EscapeIdentifier(vm.Name)}{_TryGetValueNullableAnnotation}, {contextVar}, {resultsVar}, {attributesVar}, cancellationToken).ConfigureAwait(false))"); + } + else + { + OutLn($"if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.{EscapeIdentifier(vm.Name)}{_TryGetValueNullableAnnotation}, {contextVar}, {resultsVar}, {attributesVar}))"); + } + + OutOpenBrace(); + OutLn($"({builderVar} ??= new()).AddResults({resultsVar});"); + OutCloseBrace(); + } + + private void GenAsyncTransitiveValidation(ValidatedMember vm, ref Dictionary staticValidatorsDict, string builderVar = "builder") + { + string callSequence; + if (vm.TransValidateTypeIsSynthetic) + { + callSequence = vm.TransValidatorType!; + } + else + { + var staticValidatorInstance = GetOrAddStaticValidator(ref staticValidatorsDict, vm.TransValidatorType!); + + callSequence = $"{_staticValidatorHolderClassFQN}.{staticValidatorInstance.FieldName}"; + } + + var valueAccess = (vm.IsNullable && vm.IsValueType) ? ".Value" : string.Empty; + + var baseName = $"string.IsNullOrEmpty(name) ? \"{vm.Name}\" : $\"{{name}}.{vm.Name}\""; + var memberAccess = $"options.{EscapeIdentifier(vm.Name)}"; + string asyncCallSequence = vm.TransValidatorAsyncInterfaceType is null + ? callSequence + : $"(({vm.TransValidatorAsyncInterfaceType}){callSequence})"; + + // A nested validator emits an awaited ValidateAsync call only when it was synthesized for an async context or + // when it implements IAsyncValidateOptions for the member type. + // Otherwise we fall back to its synchronous Validate method to guarantee the generated code compiles. + string resultExpression = vm.TransValidatorEmitsAsync + ? $"await {asyncCallSequence}.ValidateAsync({baseName}, {memberAccess}{valueAccess}, cancellationToken).ConfigureAwait(false)" + : $"{callSequence}.Validate({baseName}, {memberAccess}{valueAccess})"; + + if (vm.IsNullable) + { + OutLn($"if ({memberAccess} is not null)"); + OutOpenBrace(); + OutLn($"({builderVar} ??= new()).AddResult({resultExpression});"); + OutCloseBrace(); + } + else + { + OutLn($"({builderVar} ??= new()).AddResult({resultExpression});"); + } + } + + private void GenAsyncEnumerationValidation(ValidatedMember vm, ref Dictionary staticValidatorsDict, string builderVar = "builder") + { + var valueAccess = (vm.IsValueType && vm.IsNullable) ? ".Value" : string.Empty; + var enumeratedValueAccess = (vm.EnumeratedIsNullable && vm.EnumeratedIsValueType) ? ".Value" : string.Empty; + string callSequence; + if (vm.EnumerationValidatorTypeIsSynthetic) + { + callSequence = vm.EnumerationValidatorType!; + } + else + { + var staticValidatorInstance = GetOrAddStaticValidator(ref staticValidatorsDict, vm.EnumerationValidatorType!); + + callSequence = $"{_staticValidatorHolderClassFQN}.{staticValidatorInstance.FieldName}"; + } + + bool awaitItem = vm.EnumerationValidatorEmitsAsync; + var memberAccess = $"options.{EscapeIdentifier(vm.Name)}"; + string asyncCallSequence = vm.EnumerationValidatorAsyncInterfaceType is null + ? callSequence + : $"(({vm.EnumerationValidatorAsyncInterfaceType}){callSequence})"; + + if (vm.IsNullable) + { + OutLn($"if ({memberAccess} is not null)"); + } + + OutOpenBrace(); + + OutLn($"var count = 0;"); + OutLn($"foreach (var o in {memberAccess}{valueAccess})"); + OutOpenBrace(); + + if (vm.EnumeratedIsNullable) + { + OutLn($"if (o is not null)"); + OutOpenBrace(); + var propertyName = $"string.IsNullOrEmpty(name) ? $\"{vm.Name}[{{count}}]\" : $\"{{name}}.{vm.Name}[{{count}}]\""; + string itemResult = awaitItem + ? $"await {asyncCallSequence}.ValidateAsync({propertyName}, o{enumeratedValueAccess}, cancellationToken).ConfigureAwait(false)" + : $"{callSequence}.Validate({propertyName}, o{enumeratedValueAccess})"; + OutLn($"({builderVar} ??= new()).AddResult({itemResult});"); + OutCloseBrace(); + + if (!vm.EnumeratedMayBeNull) + { + OutLn($"else"); + OutOpenBrace(); + var error = $"string.IsNullOrEmpty(name) ? $\"{vm.Name}[{{count}}] is null\" : $\"{{name}}.{vm.Name}[{{count}}] is null\""; + OutLn($"({builderVar} ??= new()).AddError({error});"); + OutCloseBrace(); + } + + OutLn($"count++;"); + } + else + { + var propertyName = $"string.IsNullOrEmpty(name) ? $\"{vm.Name}[{{count++}}]\" : $\"{{name}}.{vm.Name}[{{count++}}]\""; + string itemResult = awaitItem + ? $"await {asyncCallSequence}.ValidateAsync({propertyName}, o{enumeratedValueAccess}, cancellationToken).ConfigureAwait(false)" + : $"{callSequence}.Validate({propertyName}, o{enumeratedValueAccess})"; + OutLn($"({builderVar} ??= new()).AddResult({itemResult});"); + } + + OutCloseBrace(); + OutCloseBrace(); + } + + private void GenAsyncModelSelfValidationIfNecessary(ValidatedModel modelToValidate) + { + if (modelToValidate.SelfValidatesAsync) + { + OutLn($"context.MemberName = \"ValidateAsync\";"); + OutLn($"context.DisplayName = string.IsNullOrEmpty(name) ? \"ValidateAsync\" : $\"{{name}}.ValidateAsync\";"); + OutLn($"var asyncSelfValidationResults = ((global::System.ComponentModel.DataAnnotations.IAsyncValidatableObject)options).ValidateAsync(context, cancellationToken);"); + OutLn($"if (asyncSelfValidationResults is not null)"); + OutOpenBrace(); + OutLn($"await foreach (var asyncValidationResult in global::System.Threading.Tasks.TaskAsyncEnumerableExtensions.ConfigureAwait(asyncSelfValidationResults, false))"); + OutOpenBrace(); + OutLn($"(builder ??= new()).AddResult(asyncValidationResult);"); + OutCloseBrace(); + OutCloseBrace(); + OutLn(); + } + else if (modelToValidate.SelfValidates) + { + OutLn($"context.MemberName = \"Validate\";"); + OutLn($"context.DisplayName = string.IsNullOrEmpty(name) ? \"Validate\" : $\"{{name}}.Validate\";"); + OutLn($"(builder ??= new()).AddResults(((global::System.ComponentModel.DataAnnotations.IValidatableObject)options).Validate(context));"); + OutLn(); + } + } + private void GenMemberValidation(ValidatedMember vm, ref Dictionary staticValidationAttributesDict, bool cleanListsBeforeUse) { OutLn($"context.MemberName = \"{vm.Name}\";"); diff --git a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Model/ValidatedMember.cs b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Model/ValidatedMember.cs index cfed01359167..1271693a40bf 100644 --- a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Model/ValidatedMember.cs +++ b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Model/ValidatedMember.cs @@ -16,5 +16,9 @@ internal sealed record class ValidatedMember( bool IsValueType, bool EnumeratedIsNullable, bool EnumeratedIsValueType, - bool EnumeratedMayBeNull); + bool EnumeratedMayBeNull, + bool TransValidatorEmitsAsync = false, + bool EnumerationValidatorEmitsAsync = false, + string? TransValidatorAsyncInterfaceType = null, + string? EnumerationValidatorAsyncInterfaceType = null); } diff --git a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Model/ValidatedModel.cs b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Model/ValidatedModel.cs index 0d40d930051b..ad3df5e534f2 100644 --- a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Model/ValidatedModel.cs +++ b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Model/ValidatedModel.cs @@ -9,5 +9,8 @@ internal sealed record class ValidatedModel( string Name, string SimpleName, bool SelfValidates, + bool SelfValidatesAsync, + bool GenerateValidateMethod, + bool GenerateAsyncValidateMethod, List MembersToValidate); } diff --git a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Model/ValidationAttributeInfo.cs b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Model/ValidationAttributeInfo.cs index 419ceca3e1d2..acb12cec639c 100644 --- a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Model/ValidationAttributeInfo.cs +++ b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Model/ValidationAttributeInfo.cs @@ -5,7 +5,7 @@ namespace Microsoft.Extensions.Options.Generators { - internal sealed record class ValidationAttributeInfo(string AttributeName) + internal sealed record class ValidationAttributeInfo(string AttributeName, bool IsAsyncValidationAttribute) { public List ConstructorArguments { get; } = new(); public Dictionary Properties { get; } = new(); diff --git a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Parser.cs b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Parser.cs index 3e99e2f31985..29f1bd2ddb3d 100644 --- a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Parser.cs +++ b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Parser.cs @@ -26,8 +26,19 @@ internal sealed class Parser private readonly Action _reportDiagnostic; private readonly SymbolHolder _symbolHolder; private readonly OptionsSourceGenContext _optionsSourceGenContext; - private readonly Dictionary _synthesizedValidators = new(SymbolEqualityComparer.Default); + // Synthesized validators are cached per model type. A model reached from a synchronous root and a model + // reached from an asynchronous root produce different generated types (the latter also emits ValidateAsync), + // so each model caches its synchronous and asynchronous validators separately. Keying by model type alone + // would let an asynchronous root reuse a synchronous-only validator (or vice versa) depending on discovery + // order, which would silently drop nested async validation. + private readonly Dictionary _synthesizedValidators = new(SymbolEqualityComparer.Default); private readonly HashSet _visitedModelTypes = new(SymbolEqualityComparer.Default); + // Tracks synthesized validator type names already handed out per namespace, so that a synchronous and an + // asynchronous synthesized validator whose default names collide (e.g. model "Foo" validated asynchronously + // and model "FooAsync" validated synchronously both default to "__FooAsyncValidator__") get deterministically + // uniquified instead of emitting two same-named types in the same namespace. Names are preserved unchanged + // when no collision occurs. + private readonly Dictionary> _usedSynthesizedValidatorNames = new(StringComparer.Ordinal); public Parser( Compilation compilation, @@ -90,10 +101,36 @@ public IReadOnlyList GetValidatorTypes(IEnumerable<(TypeDeclarati _ = _visitedModelTypes.Add(modelType.WithNullableAnnotation(NullableAnnotation.None)); } + // Decide, per model, whether we additionally emit a ValidateAsync method. We do so when the + // validator type explicitly implements IAsyncValidateOptions for this specific model. A + // multi-model validator therefore only gets async validation for the models it opted into. + // The async requirement is propagated to any synthesized child validators reached from this model. + bool wantsAsync = GetAsyncValidateOptionsInterfaceFor(validatorType, modelType) is not null; + bool generateValidate = true; + if (AlreadyImplementsValidateMethod(validatorType, modelType)) { - // this type already implements a validation function, we can't auto-generate a new one + // A user-supplied Validate conflicts with generation. For an async validator, continue + // parsing so ValidateAsync can still be emitted and the compiler doesn't also report CS0535. Diag(DiagDescriptors.AlreadyImplementsValidateMethod, syntax.GetLocation(), validatorType.Name); + generateValidate = false; + } + + if (wantsAsync && AlreadyImplementsValidateAsyncMethod(validatorType, modelType)) + { + // The user hand-wrote a matching ValidateAsync on an [OptionsValidator] type. This is an + // error (symmetric with SYSLIB1205 for a hand-written Validate): a generated synchronous + // Validate combined with a hand-written ValidateAsync would validate differently on the + // sync vs async access paths, silently skipping the generated attribute validation on the + // async path. Report it and skip only the async generation - the synchronous Validate is + // still generated so the sole failure surfaced is this diagnostic, not a cascading CS0535. + Diag(DiagDescriptors.AlreadyImplementsValidateAsyncMethod, syntax.GetLocation(), validatorType.Name); + wantsAsync = false; + } + + bool generateAsync = wantsAsync; + if (!generateValidate && !generateAsync) + { continue; } @@ -102,9 +139,10 @@ public IReadOnlyList GetValidatorTypes(IEnumerable<(TypeDeclarati ? modelTypeLocation : syntax.GetLocation(); - var membersToValidate = GetMembersToValidate(modelType, true, lowerLocationInCompilation, validatorType); + var membersToValidate = GetMembersToValidate(modelType, true, lowerLocationInCompilation, validatorType, generateAsync); bool selfValidate = ModelSelfValidates(modelType); - if (membersToValidate.Count == 0 && !selfValidate) + bool selfValidateAsync = generateAsync && ModelSelfValidatesAsync(modelType); + if (membersToValidate.Count == 0 && !selfValidate && !selfValidateAsync) { // this type lacks any eligible members Diag(DiagDescriptors.NoEligibleMembersFromValidator, syntax.GetLocation(), modelType.ToString(), validatorType.ToString()); @@ -115,6 +153,9 @@ public IReadOnlyList GetValidatorTypes(IEnumerable<(TypeDeclarati GetFQN(modelType), modelType.Name, selfValidate, + selfValidateAsync, + generateValidate, + generateAsync, membersToValidate)); } @@ -145,8 +186,21 @@ public IReadOnlyList GetValidatorTypes(IEnumerable<(TypeDeclarati } } - results.AddRange(_synthesizedValidators.Values); + foreach (var entry in _synthesizedValidators.Values) + { + if (entry.Sync is not null) + { + results.Add(entry.Sync); + } + + if (entry.Async is not null) + { + results.Add(entry.Async); + } + } + _synthesizedValidators.Clear(); + _usedSynthesizedValidatorNames.Clear(); if (results.Count > 0 && _compilation is CSharpCompilation { LanguageVersion : LanguageVersion version and < LanguageVersion.CSharp8 }) { @@ -205,16 +259,60 @@ private static string GetMinimalFQNWithoutGenerics(ISymbol type) => type.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat.WithGenericsOptions(SymbolDisplayGenericsOptions.None)); /// - /// Checks whether the given validator already implement the IValidationOptions>T< interface. + /// Checks whether the given validator already declares the generated Validate method. /// - private static bool AlreadyImplementsValidateMethod(INamespaceOrTypeSymbol validatorType, ISymbol modelType) + private bool AlreadyImplementsValidateMethod(INamespaceOrTypeSymbol validatorType, ISymbol modelType) + => validatorType + .GetMembers() + .OfType() + .Any(m => MatchesGeneratedValidateSignature(m, "Validate", NumValidationMethodArgs, modelType, requireCancellationToken: false)); + + // Detects a user-supplied ValidateAsync(string, TModel, CancellationToken) overload so the generator doesn't emit + // a duplicate member for a validator that already provides its own asynchronous implementation. + private bool AlreadyImplementsValidateAsyncMethod(INamespaceOrTypeSymbol validatorType, ISymbol modelType) => validatorType - .GetMembers("Validate") - .Where(m => m.Kind == SymbolKind.Method) - .Select(m => (IMethodSymbol)m) - .Any(m => m.Parameters.Length == NumValidationMethodArgs - && m.Parameters[0].Type.SpecialType == SpecialType.System_String - && SymbolEqualityComparer.Default.Equals(m.Parameters[1].Type, modelType)); + .GetMembers() + .OfType() + .Any(m => MatchesGeneratedValidateSignature(m, "ValidateAsync", NumValidationMethodArgs + 1, modelType, requireCancellationToken: true)); + + // Matches a method with the signature the generator would emit, whether declared implicitly or as an explicit + // interface implementation. The return type is intentionally ignored (C# does not overload on return type), and + // no display-string comparison is used. + // + // An explicit interface implementation is only considered a match when the interface member it implements + // belongs to the actual IValidateOptions{T}/IAsyncValidateOptions{T} interface for this specific model type. + // Otherwise an unrelated interface that happens to declare a same-named/same-shaped method (e.g. some + // application-defined IFoo.Validate(string, TModel)) would incorrectly suppress generation. + private bool MatchesGeneratedValidateSignature(IMethodSymbol method, string name, int parameterCount, ISymbol modelType, bool requireCancellationToken) + { + bool nameMatches; + if (method.ExplicitInterfaceImplementations.Length > 0) + { + INamedTypeSymbol? expectedInterface = requireCancellationToken ? _symbolHolder.AsyncValidateOptionsSymbol : _symbolHolder.ValidateOptionsSymbol; + nameMatches = expectedInterface is not null + && method.ExplicitInterfaceImplementations.Any(impl => + impl.Name == name + && SymbolEqualityComparer.Default.Equals(impl.ContainingType.OriginalDefinition, expectedInterface) + && impl.ContainingType.TypeArguments.Length == 1 + && SymbolEqualityComparer.Default.Equals(impl.ContainingType.TypeArguments[0], modelType)); + } + else + { + nameMatches = method.Name == name; + } + + if (method.Arity != 0 + || !nameMatches + || method.Parameters.Length != parameterCount + || method.Parameters[0].Type.SpecialType != SpecialType.System_String + || method.Parameters.Any(p => p.RefKind != RefKind.None) + || !SymbolEqualityComparer.Default.Equals(method.Parameters[1].Type, modelType)) + { + return false; + } + + return !requireCancellationToken || SymbolEqualityComparer.Default.Equals(method.Parameters[parameterCount - 1].Type, _symbolHolder.CancellationTokenSymbol); + } /// /// Checks whether the given type contain any unbound generic type arguments. @@ -275,7 +373,7 @@ private static bool HasOpenGenerics(ITypeSymbol type, out string genericType) return null; } - private List GetMembersToValidate(ITypeSymbol modelType, bool speculate, Location lowerLocationInCompilation, ITypeSymbol validatorType) + private List GetMembersToValidate(ITypeSymbol modelType, bool speculate, Location lowerLocationInCompilation, ITypeSymbol validatorType, bool isAsync) { // make a list of the most derived members in the model type @@ -309,7 +407,7 @@ private List GetMembersToValidate(ITypeSymbol modelType, bool s ? memberLocation : lowerLocationInCompilation; - var memberInfo = GetMemberInfo(member, speculate, location, modelType, validatorType); + var memberInfo = GetMemberInfo(member, speculate, location, modelType, validatorType, isAsync); if (memberInfo is not null) { if (member.DeclaredAccessibility != Accessibility.Public) @@ -325,7 +423,7 @@ private List GetMembersToValidate(ITypeSymbol modelType, bool s return membersToValidate; } - private ValidatedMember? GetMemberInfo(ISymbol member, bool speculate, Location location, ITypeSymbol modelType, ITypeSymbol validatorType) + private ValidatedMember? GetMemberInfo(ISymbol member, bool speculate, Location location, ITypeSymbol modelType, ITypeSymbol validatorType, bool isAsync) { ITypeSymbol memberType; switch (member) @@ -358,6 +456,10 @@ private List GetMembersToValidate(ITypeSymbol modelType, bool s var enumeratedMayBeNull = false; var transValidatorIsSynthetic = false; var enumerationValidatorIsSynthetic = false; + var transValidatorEmitsAsync = false; + var enumerationValidatorEmitsAsync = false; + string? transValidatorAsyncInterfaceType = null; + string? enumerationValidatorAsyncInterfaceType = null; foreach (var attribute in member.GetAttributes().Where(a => a.AttributeClass is not null)) { @@ -385,6 +487,9 @@ private List GetMembersToValidate(ITypeSymbol modelType, bool s if (transValidatorType.Constructors.Where(c => !c.Parameters.Any()).Any()) { transValidatorTypeName = transValidatorType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); + INamedTypeSymbol? asyncInterface = isAsync ? GetAsyncValidateOptionsInterfaceFor(transValidatorType, memberType) : null; + transValidatorEmitsAsync = asyncInterface is not null; + transValidatorAsyncInterfaceType = asyncInterface is null ? null : GetFQN(asyncInterface); } else { @@ -411,7 +516,7 @@ private List GetMembersToValidate(ITypeSymbol modelType, bool s if (transValidatorTypeName == null) { transValidatorIsSynthetic = true; - transValidatorTypeName = AddSynthesizedValidator(memberType, member, location, validatorType); + transValidatorTypeName = AddSynthesizedValidator(memberType, member, location, validatorType, isAsync, out transValidatorEmitsAsync); } // pop the stack @@ -448,6 +553,9 @@ private List GetMembersToValidate(ITypeSymbol modelType, bool s if (enumerationValidatorType.Constructors.Where(c => c.Parameters.Length == 0).Any()) { enumerationValidatorTypeName = enumerationValidatorType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); + INamedTypeSymbol? asyncInterface = isAsync ? GetAsyncValidateOptionsInterfaceFor(enumerationValidatorType, enumeratedType) : null; + enumerationValidatorEmitsAsync = asyncInterface is not null; + enumerationValidatorAsyncInterfaceType = asyncInterface is null ? null : GetFQN(asyncInterface); } else { @@ -474,7 +582,7 @@ private List GetMembersToValidate(ITypeSymbol modelType, bool s if (enumerationValidatorTypeName == null) { enumerationValidatorIsSynthetic = true; - enumerationValidatorTypeName = AddSynthesizedValidator(enumeratedType, member, location, validatorType); + enumerationValidatorTypeName = AddSynthesizedValidator(enumeratedType, member, location, validatorType, isAsync, out enumerationValidatorEmitsAsync); } // pop the stack @@ -507,7 +615,9 @@ private List GetMembersToValidate(ITypeSymbol modelType, bool s TrackRangeAttributeForSubstitution(attribute, memberType, ref attributeFullQualifiedName); } - var validationAttr = new ValidationAttributeInfo(attributeFullQualifiedName); + bool isAsyncAttribute = _symbolHolder.AsyncValidationAttributeSymbol is not null + && ConvertTo(attributeType, _symbolHolder.AsyncValidationAttributeSymbol); + var validationAttr = new ValidationAttributeInfo(attributeFullQualifiedName, isAsyncAttribute); validationAttrs.Add(validationAttr); ImmutableArray parameters = attribute.AttributeConstructor?.Parameters ?? ImmutableArray.Empty; @@ -563,7 +673,7 @@ private List GetMembersToValidate(ITypeSymbol modelType, bool s { if (!HasOpenGenerics(memberType, out var genericType)) { - var membersToValidate = GetMembersToValidate(memberType, false, location, validatorType); + var membersToValidate = GetMembersToValidate(memberType, false, location, validatorType, isAsync); if (membersToValidate.Count > 0) { Diag(DiagDescriptors.PotentiallyMissingTransitiveValidation, location, memberType.Name, member.Name); @@ -579,7 +689,7 @@ private List GetMembersToValidate(ITypeSymbol modelType, bool s { if (!HasOpenGenerics(enumeratedType, out var genericType)) { - var membersToValidate = GetMembersToValidate(enumeratedType, false, location, validatorType); + var membersToValidate = GetMembersToValidate(enumeratedType, false, location, validatorType, isAsync); if (membersToValidate.Count > 0) { Diag(DiagDescriptors.PotentiallyMissingEnumerableValidation, location, enumeratedType.Name, member.Name); @@ -601,7 +711,11 @@ private List GetMembersToValidate(ITypeSymbol modelType, bool s memberType.IsValueType, enumeratedIsNullable, enumeratedIsValueType, - enumeratedMayBeNull); + enumeratedMayBeNull, + transValidatorEmitsAsync, + enumerationValidatorEmitsAsync, + transValidatorAsyncInterfaceType, + enumerationValidatorAsyncInterfaceType); } return null; @@ -693,8 +807,9 @@ private void TrackRangeAttributeForSubstitution(AttributeData attribute, ITypeSy } } - private string? AddSynthesizedValidator(ITypeSymbol modelType, ISymbol member, Location location, ITypeSymbol validatorType) + private string? AddSynthesizedValidator(ITypeSymbol modelType, ISymbol member, Location location, ITypeSymbol validatorType, bool isAsync, out bool emitsAsync) { + emitsAsync = false; var mt = modelType.WithNullableAnnotation(NullableAnnotation.None); if (mt.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T) { @@ -702,14 +817,19 @@ private void TrackRangeAttributeForSubstitution(AttributeData attribute, ITypeSy mt = ((INamedTypeSymbol)mt).TypeArguments[0]; } - if (_synthesizedValidators.TryGetValue(mt, out var validator)) + _synthesizedValidators.TryGetValue(mt, out var cached); + ValidatorType? reusable = isAsync ? cached.Async : cached.Sync; + if (reusable is not null) { - return "global::" + validator.Namespace + "." + validator.Name; + // A validator matching the requested capability was already synthesized for this model, so reuse it. + emitsAsync = isAsync; + return "global::" + (reusable.Namespace.Length > 0 ? reusable.Namespace + "." + reusable.Name : reusable.Name); } bool selfValidate = ModelSelfValidates(mt); - var membersToValidate = GetMembersToValidate(mt, true, location, validatorType); - if (membersToValidate.Count == 0 && !selfValidate) + bool selfValidateAsync = isAsync && ModelSelfValidatesAsync(mt); + var membersToValidate = GetMembersToValidate(mt, true, location, validatorType, isAsync); + if (membersToValidate.Count == 0 && !selfValidate && !selfValidateAsync) { // this type lacks any eligible members Diag(DiagDescriptors.NoEligibleMember, location, mt.ToString(), member.ToString()); @@ -720,12 +840,19 @@ private void TrackRangeAttributeForSubstitution(AttributeData attribute, ITypeSy GetFQN(mt), mt.Name, selfValidate, + selfValidateAsync, + GenerateValidateMethod: true, + isAsync, membersToValidate); - var validatorTypeName = "__" + mt.Name + "Validator__"; + // Asynchronous validators get a distinct name so a model reached from both a synchronous and an + // asynchronous root can emit two non-conflicting synthesized types. Synchronous naming is unchanged. + string @namespace = GetNamespace(mt); + string candidateName = "__" + mt.Name + (isAsync ? "AsyncValidator__" : "Validator__"); + string validatorTypeName = GetUniqueSynthesizedValidatorName(@namespace, candidateName); var result = new ValidatorType( - GetNamespace(mt), + @namespace, validatorTypeName, validatorTypeName, "class", @@ -733,10 +860,32 @@ private void TrackRangeAttributeForSubstitution(AttributeData attribute, ITypeSy true, new[] { model }); - _synthesizedValidators[mt] = result; + _synthesizedValidators[mt] = isAsync ? (cached.Sync, result) : (result, cached.Async); + emitsAsync = isAsync; return "global::" + (result.Namespace.Length > 0 ? result.Namespace + "." + result.Name : result.Name); } + // Returns candidateName unchanged unless it was already handed out in the same namespace, in which case a + // deterministic numeric suffix is appended until the name is unique. This keeps existing generated names + // stable when no collision occurs, while still guaranteeing the emitted source compiles when two distinct + // model types happen to produce the same default synthesized validator name (see field comment above). + private string GetUniqueSynthesizedValidatorName(string @namespace, string candidateName) + { + if (!_usedSynthesizedValidatorNames.TryGetValue(@namespace, out var namesInNamespace)) + { + namesInNamespace = new HashSet(StringComparer.Ordinal); + _usedSynthesizedValidatorNames[@namespace] = namesInNamespace; + } + + string uniqueName = candidateName; + for (int suffix = 2; !namesInNamespace.Add(uniqueName); suffix++) + { + uniqueName = candidateName + "_" + suffix.ToString(CultureInfo.InvariantCulture); + } + + return uniqueName; + } + private bool ConvertTo(ITypeSymbol source, ITypeSymbol dest) { var conversion = _compilation.ClassifyConversion(source, dest); @@ -756,6 +905,43 @@ private bool ModelSelfValidates(ITypeSymbol modelType) return false; } + private bool ModelSelfValidatesAsync(ITypeSymbol modelType) + { + if (_symbolHolder.IAsyncValidatableObjectSymbol is null) + { + return false; + } + + foreach (var implementingInterface in modelType.AllInterfaces) + { + if (SymbolEqualityComparer.Default.Equals(implementingInterface.OriginalDefinition, _symbolHolder.IAsyncValidatableObjectSymbol)) + { + return true; + } + } + + return false; + } + + private INamedTypeSymbol? GetAsyncValidateOptionsInterfaceFor(ITypeSymbol validatorType, ITypeSymbol modelType) + { + if (_symbolHolder.AsyncValidateOptionsSymbol is null) + { + return null; + } + + foreach (var implementingInterface in validatorType.AllInterfaces) + { + if (SymbolEqualityComparer.Default.Equals(implementingInterface.OriginalDefinition, _symbolHolder.AsyncValidateOptionsSymbol) + && SymbolEqualityComparer.Default.Equals(implementingInterface.TypeArguments.First(), modelType)) + { + return implementingInterface; + } + } + + return null; + } + private List GetModelTypes(ITypeSymbol validatorType) { var result = new List(); diff --git a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/Strings.resx b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/Strings.resx index be9fe963b837..cb0d66afb47a 100644 --- a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/Strings.resx +++ b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/Strings.resx @@ -117,6 +117,12 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + Type {0} already implements the ValidateAsync method. + + + A type already includes an implementation of the 'ValidateAsync' method. + Type {0} already implements the Validate method. diff --git a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.cs.xlf b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.cs.xlf index c8490d951761..b64de2925b40 100644 --- a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.cs.xlf +++ b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.cs.xlf @@ -2,6 +2,16 @@ + + Type {0} already implements the ValidateAsync method. + Type {0} already implements the ValidateAsync method. + + + + A type already includes an implementation of the 'ValidateAsync' method. + A type already includes an implementation of the 'ValidateAsync' method. + + Type {0} already implements the Validate method. Typ {0} již implementuje metodu Validate. diff --git a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.de.xlf b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.de.xlf index eb7a7f423a3e..38e26dbc6c19 100644 --- a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.de.xlf +++ b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.de.xlf @@ -2,6 +2,16 @@ + + Type {0} already implements the ValidateAsync method. + Type {0} already implements the ValidateAsync method. + + + + A type already includes an implementation of the 'ValidateAsync' method. + A type already includes an implementation of the 'ValidateAsync' method. + + Type {0} already implements the Validate method. Der Typ "{0}" implementiert bereits die Validate-Methode. diff --git a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.es.xlf b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.es.xlf index 19c69bb8c864..58a29411f893 100644 --- a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.es.xlf +++ b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.es.xlf @@ -2,6 +2,16 @@ + + Type {0} already implements the ValidateAsync method. + Type {0} already implements the ValidateAsync method. + + + + A type already includes an implementation of the 'ValidateAsync' method. + A type already includes an implementation of the 'ValidateAsync' method. + + Type {0} already implements the Validate method. El tipo {0} ya implementa el método Validate. diff --git a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.fr.xlf b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.fr.xlf index 651ab8b30371..946fb41eab64 100644 --- a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.fr.xlf +++ b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.fr.xlf @@ -2,6 +2,16 @@ + + Type {0} already implements the ValidateAsync method. + Type {0} already implements the ValidateAsync method. + + + + A type already includes an implementation of the 'ValidateAsync' method. + A type already includes an implementation of the 'ValidateAsync' method. + + Type {0} already implements the Validate method. Le type {0} implémente déjà la méthode Validate. diff --git a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.it.xlf b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.it.xlf index 575f60469e48..3b886990758e 100644 --- a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.it.xlf +++ b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.it.xlf @@ -2,6 +2,16 @@ + + Type {0} already implements the ValidateAsync method. + Type {0} already implements the ValidateAsync method. + + + + A type already includes an implementation of the 'ValidateAsync' method. + A type already includes an implementation of the 'ValidateAsync' method. + + Type {0} already implements the Validate method. Il tipo {0} implementa già il metodo Validate. diff --git a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ja.xlf b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ja.xlf index 8251ac27c6da..df07dacbff5c 100644 --- a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ja.xlf +++ b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ja.xlf @@ -2,6 +2,16 @@ + + Type {0} already implements the ValidateAsync method. + Type {0} already implements the ValidateAsync method. + + + + A type already includes an implementation of the 'ValidateAsync' method. + A type already includes an implementation of the 'ValidateAsync' method. + + Type {0} already implements the Validate method. 型 {0} に Validate メソッドが既に実装されています。 diff --git a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ko.xlf b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ko.xlf index 4c8ce2865d10..339841dcc0a5 100644 --- a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ko.xlf +++ b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ko.xlf @@ -2,6 +2,16 @@ + + Type {0} already implements the ValidateAsync method. + Type {0} already implements the ValidateAsync method. + + + + A type already includes an implementation of the 'ValidateAsync' method. + A type already includes an implementation of the 'ValidateAsync' method. + + Type {0} already implements the Validate method. 형식 {0}은(는) Validate 메서드를 이미 구현하고 있습니다. diff --git a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.pl.xlf b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.pl.xlf index e07e568d1318..fb3bcf07dbf7 100644 --- a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.pl.xlf +++ b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.pl.xlf @@ -2,6 +2,16 @@ + + Type {0} already implements the ValidateAsync method. + Type {0} already implements the ValidateAsync method. + + + + A type already includes an implementation of the 'ValidateAsync' method. + A type already includes an implementation of the 'ValidateAsync' method. + + Type {0} already implements the Validate method. Typ {0} już implementuje metodę Validate. diff --git a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.pt-BR.xlf b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.pt-BR.xlf index d422309a4099..5045687dbdf7 100644 --- a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.pt-BR.xlf +++ b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.pt-BR.xlf @@ -2,6 +2,16 @@ + + Type {0} already implements the ValidateAsync method. + Type {0} already implements the ValidateAsync method. + + + + A type already includes an implementation of the 'ValidateAsync' method. + A type already includes an implementation of the 'ValidateAsync' method. + + Type {0} already implements the Validate method. O tipo {0} já implementa o método Validar. diff --git a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ru.xlf b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ru.xlf index bd3a0be55eb2..1b16715ada57 100644 --- a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ru.xlf +++ b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ru.xlf @@ -2,6 +2,16 @@ + + Type {0} already implements the ValidateAsync method. + Type {0} already implements the ValidateAsync method. + + + + A type already includes an implementation of the 'ValidateAsync' method. + A type already includes an implementation of the 'ValidateAsync' method. + + Type {0} already implements the Validate method. Тип {0} уже реализует метод Validate. diff --git a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.tr.xlf b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.tr.xlf index e478a77cd3c2..4bb9f863ec93 100644 --- a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.tr.xlf +++ b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.tr.xlf @@ -2,6 +2,16 @@ + + Type {0} already implements the ValidateAsync method. + Type {0} already implements the ValidateAsync method. + + + + A type already includes an implementation of the 'ValidateAsync' method. + A type already includes an implementation of the 'ValidateAsync' method. + + Type {0} already implements the Validate method. {0} türü Doğrulama yöntemini zaten uyguluyor. diff --git a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.zh-Hans.xlf b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.zh-Hans.xlf index 76a26db32a67..3d881264d02f 100644 --- a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.zh-Hans.xlf @@ -2,6 +2,16 @@ + + Type {0} already implements the ValidateAsync method. + Type {0} already implements the ValidateAsync method. + + + + A type already includes an implementation of the 'ValidateAsync' method. + A type already includes an implementation of the 'ValidateAsync' method. + + Type {0} already implements the Validate method. 类型 {0} 已实现 Validate 方法。 diff --git a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.zh-Hant.xlf b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.zh-Hant.xlf index 9997092e3be6..6157a800a7bd 100644 --- a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.zh-Hant.xlf @@ -2,6 +2,16 @@ + + Type {0} already implements the ValidateAsync method. + Type {0} already implements the ValidateAsync method. + + + + A type already includes an implementation of the 'ValidateAsync' method. + A type already includes an implementation of the 'ValidateAsync' method. + + Type {0} already implements the Validate method. 類型 {0} 已實作 [驗證] 方法。 diff --git a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/SymbolHolder.cs b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/SymbolHolder.cs index 8e7073f8ec21..949cb3066e6e 100644 --- a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/SymbolHolder.cs +++ b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/SymbolHolder.cs @@ -25,5 +25,10 @@ internal sealed record class SymbolHolder( INamedTypeSymbol TypeSymbol, INamedTypeSymbol TimeSpanSymbol, INamedTypeSymbol ValidateObjectMembersAttributeSymbol, - INamedTypeSymbol ValidateEnumeratedItemsAttributeSymbol); + INamedTypeSymbol ValidateEnumeratedItemsAttributeSymbol, + INamedTypeSymbol CancellationTokenSymbol, + INamedTypeSymbol? IAsyncValidatableObjectSymbol = null, + bool HasTryValidateValueAsyncMethod = false, + INamedTypeSymbol? AsyncValidateOptionsSymbol = null, + INamedTypeSymbol? AsyncValidationAttributeSymbol = null); } diff --git a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/SymbolLoader.cs b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/SymbolLoader.cs index 5be4932d8d6c..e7e5ad3cdc43 100644 --- a/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/SymbolLoader.cs +++ b/src/runtime/src/libraries/Microsoft.Extensions.Options/gen/SymbolLoader.cs @@ -8,6 +8,7 @@ namespace Microsoft.Extensions.Options.Generators internal static class SymbolLoader { public const string OptionsValidatorAttribute = "Microsoft.Extensions.Options.OptionsValidatorAttribute"; + internal const string AsyncValidationAttributeType = "System.ComponentModel.DataAnnotations.AsyncValidationAttribute"; internal const string ValidationAttribute = "System.ComponentModel.DataAnnotations.ValidationAttribute"; internal const string MaxLengthAttribute = "System.ComponentModel.DataAnnotations.MaxLengthAttribute"; internal const string MinLengthAttribute = "System.ComponentModel.DataAnnotations.MinLengthAttribute"; @@ -24,6 +25,10 @@ internal static class SymbolLoader internal const string ValidateEnumeratedItemsAttribute = "Microsoft.Extensions.Options.ValidateEnumeratedItemsAttribute"; internal const string GenericIEnumerableType = "System.Collections.Generic.IEnumerable`1"; internal const string UnconditionalSuppressMessageAttributeType = "System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute"; + internal const string IAsyncValidatableObjectType = "System.ComponentModel.DataAnnotations.IAsyncValidatableObject"; + internal const string IAsyncValidateOptionsType = "Microsoft.Extensions.Options.IAsyncValidateOptions`1"; + internal const string CancellationTokenType = "System.Threading.CancellationToken"; + internal const string ValidatorType = "System.ComponentModel.DataAnnotations.Validator"; public static bool TryLoad(Compilation compilation, out SymbolHolder? symbolHolder) { @@ -46,6 +51,7 @@ public static bool TryLoad(Compilation compilation, out SymbolHolder? symbolHold var timeSpanSymbol = GetSymbol(TimeSpanType); var validateObjectMembersAttribute = GetSymbol(ValidateObjectMembersAttribute); var validateEnumeratedItemsAttribute = GetSymbol(ValidateEnumeratedItemsAttribute); + var cancellationTokenSymbol = GetSymbol(CancellationTokenType); var unconditionalSuppressMessageAttributeSymbol = GetSymbol(UnconditionalSuppressMessageAttributeType); if (unconditionalSuppressMessageAttributeSymbol is not null) { @@ -74,13 +80,22 @@ public static bool TryLoad(Compilation compilation, out SymbolHolder? symbolHold typeSymbol == null || timeSpanSymbol == null || validateObjectMembersAttribute == null || - validateEnumeratedItemsAttribute == null) + validateEnumeratedItemsAttribute == null || + cancellationTokenSymbol == null) { symbolHolder = default; return false; } #pragma warning restore S1067 // Expressions should not be too complex + // IAsyncValidateOptions is available on every package TFM, while the asynchronous + // DataAnnotations APIs are available only on .NET 11 and later. + var iAsyncValidatableObjectSymbol = GetSymbol(IAsyncValidatableObjectType); + var asyncValidateOptionsSymbol = GetSymbol(IAsyncValidateOptionsType); + var asyncValidationAttributeSymbol = GetSymbol(AsyncValidationAttributeType); + var validatorSymbol = GetSymbol(ValidatorType); + bool hasTryValidateValueAsyncMethod = validatorSymbol?.GetMembers("TryValidateValueAsync").Length > 0; + symbolHolder = new( optionsValidatorSymbol, validationAttributeSymbol, @@ -98,7 +113,12 @@ public static bool TryLoad(Compilation compilation, out SymbolHolder? symbolHold typeSymbol, timeSpanSymbol, validateObjectMembersAttribute, - validateEnumeratedItemsAttribute); + validateEnumeratedItemsAttribute, + cancellationTokenSymbol, + iAsyncValidatableObjectSymbol, + hasTryValidateValueAsyncMethod, + asyncValidateOptionsSymbol, + asyncValidationAttributeSymbol); return true; } diff --git a/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Main.cs b/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Main.cs index 4815d029ebc4..26106efb0727 100644 --- a/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Main.cs +++ b/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Main.cs @@ -512,6 +512,553 @@ public void Validate(string name, FirstModel fm) Assert.Equal(DiagDescriptors.AlreadyImplementsValidateMethod.Id, diagnostics[0].Id); } + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] + public async Task ExplicitValidateInterfaceImplementationReportsDiagnostic() + { + var (diagnostics, generatedSources) = await RunGenerator(@" + public class FirstModel + { + [Required] + public string One { get; set; } = string.Empty; + } + + [OptionsValidator] + public partial class FirstValidator : IValidateOptions + { + ValidateOptionsResult IValidateOptions.Validate(string? name, FirstModel options) + => ValidateOptionsResult.Success; + } + "); + + Diagnostic diagnostic = Assert.Single(diagnostics); + Assert.Equal(DiagDescriptors.AlreadyImplementsValidateMethod.Id, diagnostic.Id); + Assert.DoesNotContain( + "public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::Test.FirstModel options)", + Assert.Single(generatedSources).SourceText.ToString()); + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] + public async Task HandWrittenValidateDoesNotPreventAsyncMethodEmission() + { + string source = """ + using System.ComponentModel.DataAnnotations; + using Microsoft.Extensions.Options; + + namespace Test + { + public class FirstModel + { + [Required] + public string One { get; set; } = string.Empty; + } + + [OptionsValidator] + public partial class FirstValidator : IAsyncValidateOptions + { + public ValidateOptionsResult Validate(string? name, FirstModel options) + => ValidateOptionsResult.Success; + } + } + """; + + var (diagnostics, generatedSources) = await RunGeneratorOnOptionsSource(source); + + Diagnostic diagnostic = Assert.Single(diagnostics); + Assert.Equal(DiagDescriptors.AlreadyImplementsValidateMethod.Id, diagnostic.Id); + + string generatedSource = Assert.Single(generatedSources).SourceText.ToString(); + Assert.Contains("ValidateAsync(string? name, global::Test.FirstModel options,", generatedSource); + + CSharpCompilation compilation = CreateCompilationForOptionsSource( + Path.GetRandomFileName(), + source + Environment.NewLine + generatedSource); + + using MemoryStream output = new(); + EmitResult emitResult = compilation.Emit(output); + Assert.True(emitResult.Success, string.Join(Environment.NewLine, emitResult.Diagnostics)); + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] + public async Task ExplicitHandWrittenValidateDoesNotPreventAsyncMethodEmission() + { + string source = """ + using System.ComponentModel.DataAnnotations; + using Microsoft.Extensions.Options; + + namespace Test + { + public class FirstModel + { + [Required] + public string One { get; set; } = string.Empty; + } + + [OptionsValidator] + public partial class FirstValidator : IAsyncValidateOptions + { + ValidateOptionsResult IValidateOptions.Validate(string? name, FirstModel options) + => ValidateOptionsResult.Success; + } + } + """; + + var (diagnostics, generatedSources) = await RunGeneratorOnOptionsSource(source); + + Diagnostic diagnostic = Assert.Single(diagnostics); + Assert.Equal(DiagDescriptors.AlreadyImplementsValidateMethod.Id, diagnostic.Id); + + string generatedSource = Assert.Single(generatedSources).SourceText.ToString(); + Assert.DoesNotContain( + "Validate(string? name, global::Test.FirstModel options)", + generatedSource); + Assert.Contains( + "ValidateAsync(string? name, global::Test.FirstModel options,", + generatedSource); + + CSharpCompilation compilation = CreateCompilationForOptionsSource( + Path.GetRandomFileName(), + source + Environment.NewLine + generatedSource); + + using MemoryStream output = new(); + EmitResult emitResult = compilation.Emit(output); + Assert.True(emitResult.Success, string.Join(Environment.NewLine, emitResult.Diagnostics)); + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] + public async Task HandWrittenValidateAndValidateAsyncSuppressGeneration() + { + var (diagnostics, generatedSources) = await RunGenerator(""" + public class FirstModel + { + [Required] + public string One { get; set; } = string.Empty; + } + + [OptionsValidator] + public partial class FirstValidator : IAsyncValidateOptions + { + public ValidateOptionsResult Validate(string? name, FirstModel options) + => ValidateOptionsResult.Success; + + public System.Threading.Tasks.Task ValidateAsync( + string? name, + FirstModel options, + System.Threading.CancellationToken cancellationToken = default) + => System.Threading.Tasks.Task.FromResult(ValidateOptionsResult.Success); + } + """); + + Assert.Collection( + diagnostics, + diagnostic => Assert.Equal(DiagDescriptors.AlreadyImplementsValidateMethod.Id, diagnostic.Id), + diagnostic => Assert.Equal(DiagDescriptors.AlreadyImplementsValidateAsyncMethod.Id, diagnostic.Id)); + + string generatedSource = Assert.Single(generatedSources).SourceText.ToString(); + Assert.DoesNotContain( + "Validate(string? name, global::Test.FirstModel options)", + generatedSource); + Assert.DoesNotContain( + "ValidateAsync(string? name, global::Test.FirstModel options,", + generatedSource); + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] + public async Task AlreadyImplementedAsync() + { + var (diagnostics, _) = await RunGenerator(@" + public class FirstModel + { + [Required] + public string One { get; set; } = string.Empty; + } + + [OptionsValidator] + public partial class FirstValidator : IAsyncValidateOptions + { + public System.Threading.Tasks.Task ValidateAsync(string? name, FirstModel options, System.Threading.CancellationToken cancellationToken = default) + => System.Threading.Tasks.Task.FromResult(ValidateOptionsResult.Success); + } + "); + + _ = Assert.Single(diagnostics); + Assert.Equal(DiagDescriptors.AlreadyImplementsValidateAsyncMethod.Id, diagnostics[0].Id); + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] + public async Task AlreadyImplementedAsyncExplicitInterface() + { + var (diagnostics, _) = await RunGenerator(@" + public class FirstModel + { + [Required] + public string One { get; set; } = string.Empty; + } + + [OptionsValidator] + public partial class FirstValidator : IAsyncValidateOptions + { + System.Threading.Tasks.Task IAsyncValidateOptions.ValidateAsync(string? name, FirstModel options, System.Threading.CancellationToken cancellationToken) + => System.Threading.Tasks.Task.FromResult(ValidateOptionsResult.Success); + } + "); + + _ = Assert.Single(diagnostics); + Assert.Equal(DiagDescriptors.AlreadyImplementsValidateAsyncMethod.Id, diagnostics[0].Id); + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] + public async Task ValidateAsyncOverloadWithWrongThirdParameterDoesNotSuppressGeneration() + { + var (diagnostics, generatedSources) = await RunGenerator(""" + public class FirstModel + { + [Required] + public string One { get; set; } = string.Empty; + } + + [OptionsValidator] + public partial class FirstValidator : IAsyncValidateOptions + { + public System.Threading.Tasks.Task ValidateAsync( + string? name, + FirstModel options, + object state) + => System.Threading.Tasks.Task.FromResult(ValidateOptionsResult.Success); + } + """); + + Assert.Empty(diagnostics); + string generatedSource = Assert.Single(generatedSources).SourceText.ToString(); + Assert.Contains( + "global::System.Threading.CancellationToken cancellationToken = default", + generatedSource); + } + +#if NET + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] + [InlineData(false)] + [InlineData(true)] + public async Task ConcurrentMemberEmissionRequiresGenuinelyAsyncWork(bool useAsyncValidationAttribute) + { + string attributeDefinition = useAsyncValidationAttribute + ? """ + public sealed class TestAsyncAttribute : AsyncValidationAttribute + { + protected override ValidationResult? IsValid(object? value, ValidationContext validationContext) + => ValidationResult.Success; + + protected override async Task IsValidAsync( + object? value, + ValidationContext validationContext, + CancellationToken cancellationToken) + { + await Task.Yield(); + return ValidationResult.Success; + } + } + + """ + : string.Empty; + string attributeName = useAsyncValidationAttribute ? "TestAsync" : "Required"; + string source = $$""" + using System.ComponentModel.DataAnnotations; + using System.Threading; + using System.Threading.Tasks; + using Microsoft.Extensions.Options; + + namespace Test + { + {{attributeDefinition}}public class FirstModel + { + [{{attributeName}}] + public string First { get; set; } = string.Empty; + + [{{attributeName}}] + public string Second { get; set; } = string.Empty; + } + + [OptionsValidator] + public partial class FirstValidator : IAsyncValidateOptions + { + } + } + """; + + var (diagnostics, generatedSources) = await RunGeneratorOnOptionsSource(source); + + Assert.Empty(diagnostics); + string generatedSource = Assert.Single(generatedSources).SourceText.ToString(); + Assert.Contains("TryValidateValueAsync", generatedSource); + if (useAsyncValidationAttribute) + { + Assert.Contains("global::Test.TestAsyncAttribute", generatedSource); + Assert.Contains("Task.WhenAll(", generatedSource); + } + else + { + Assert.DoesNotContain("Task.WhenAll(", generatedSource); + } + } +#endif // NET + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] + public async Task MultiModelValidatorEmitsAsyncOnlyForOptedInModel() + { + var (diagnostics, generatedSources) = await RunGenerator(""" + public class AsyncModel + { + [Required] + public string? Value { get; set; } + } + + public class SyncModel + { + [Required] + public string? Value { get; set; } + } + + [OptionsValidator] + public partial class MultiValidator : + IAsyncValidateOptions, + IValidateOptions + { + } + """); + + Assert.Empty(diagnostics); + string generatedSource = Assert.Single(generatedSources).SourceText.ToString(); + Assert.Contains("Validate(string? name, global::Test.AsyncModel options)", generatedSource); + Assert.Contains("ValidateAsync(string? name, global::Test.AsyncModel options,", generatedSource); + Assert.Contains("Validate(string? name, global::Test.SyncModel options)", generatedSource); + Assert.DoesNotContain("ValidateAsync(string? name, global::Test.SyncModel options,", generatedSource); + } + + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] + [InlineData(false)] +#if NET + [InlineData(true)] +#endif + public async Task GenericValidateOverloadDoesNotSuppressGeneration(bool isAsync) + { + string validatorInterface = isAsync + ? "IAsyncValidateOptions" + : "IValidateOptions"; + string genericMethod = isAsync + ? """ + public System.Threading.Tasks.Task ValidateAsync( + string? name, + FirstModel options, + System.Threading.CancellationToken cancellationToken) + => System.Threading.Tasks.Task.FromResult(ValidateOptionsResult.Success); + """ + : "public void Validate(string name, FirstModel options) { }"; + + var (diagnostics, generatedSources) = await RunGenerator($$""" + public class FirstModel + { + [Required] + public string One { get; set; } = string.Empty; + } + + [OptionsValidator] + public partial class FirstValidator : {{validatorInterface}} + { + {{genericMethod}} + } + """); + + Assert.Empty(diagnostics); + _ = Assert.Single(generatedSources); + + string expectedMethod = isAsync + ? "ValidateAsync(string? name, global::Test.FirstModel options," + : "Validate(string? name, global::Test.FirstModel options)"; + Assert.Contains(expectedMethod, generatedSources[0].SourceText.ToString()); + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] + public async Task UnrelatedExplicitInterfaceImplementationDoesNotSuppressGeneration() + { + var (diagnostics, generatedSources) = await RunGenerator(@" + public interface IUnrelatedValidator + { + void Validate(string name, FirstModel fm); + } + + public class FirstModel + { + [Required] + public string One { get; set; } = string.Empty; + } + + [OptionsValidator] + public partial class FirstValidator : IValidateOptions, IUnrelatedValidator + { + void IUnrelatedValidator.Validate(string name, FirstModel fm) + { + } + } + "); + + // The explicit implementation satisfies IUnrelatedValidator.Validate, not IValidateOptions.Validate + // (same name/signature, unrelated interface), so it must not suppress generation of the real method. + Assert.Empty(diagnostics); + _ = Assert.Single(generatedSources); + Assert.Contains( + "public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::Test.FirstModel options)", + generatedSources[0].SourceText.ToString()); + } + + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] + [InlineData("ref")] + [InlineData("in")] + [InlineData("out")] + public async Task RefKindMismatchDoesNotCountAsExistingImplementation(string refKind) + { + string body = refKind == "out" ? "fm = null;" : string.Empty; + var (diagnostics, generatedSources) = await RunGenerator($@" + public class FirstModel + {{ + [Required] + public string One {{ get; set; }} = string.Empty; + }} + + [OptionsValidator] + public partial class FirstValidator : IValidateOptions + {{ + public void Validate(string name, {refKind} FirstModel fm) + {{ + {body} + }} + }} + "); + + // A "Validate" overload whose model parameter has a ref/in/out modifier cannot implicitly implement + // IValidateOptions.Validate(string, FirstModel) - parameter modifiers must match exactly for + // implicit interface implementation - so it is an unrelated overload and must not suppress generation. + Assert.Empty(diagnostics); + _ = Assert.Single(generatedSources); + Assert.Contains( + "public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::Test.FirstModel options)", + generatedSources[0].SourceText.ToString()); + } + +#if NET + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] + public async Task AsyncValidateMethodWithNoAwaitedWorkRemainsAsync() + { + // The model validates only synchronously (IValidatableObject, no attributes, no async children) but is validated + // by an IAsyncValidateOptions validator, so the generated ValidateAsync body contains no await. The method is + // still emitted as `async Task` (with the resulting CS1998 warning suppressed) so that + // cancellationToken.ThrowIfCancellationRequested() at the top of the method surfaces as a canceled/faulted Task + // instead of throwing synchronously to the caller, keeping the TAP contract intact even on the no-await path. + var (diagnostics, generatedSources) = await RunGenerator(@" + using System.Collections.Generic; + + public class SyncSelfModel : IValidatableObject + { + public string? Name { get; set; } + public IEnumerable Validate(ValidationContext validationContext) + { + yield break; + } + } + + [OptionsValidator] + public partial class SyncSelfModelValidator : IAsyncValidateOptions + { + } + "); + + Assert.Empty(diagnostics); + _ = Assert.Single(generatedSources); + string emitted = generatedSources[0].SourceText.ToString(); + + // The method is always declared async and never falls back to Task.FromResult(...). + Assert.Contains("public async global::System.Threading.Tasks.Task ValidateAsync", emitted); + Assert.DoesNotContain("global::System.Threading.Tasks.Task.FromResult", emitted); + // No await occurs on this path, so the CS1998 warning is explicitly suppressed rather than avoided by dropping async. + Assert.Contains("#pragma warning disable CS1998", emitted); + Assert.Contains("#pragma warning restore CS1998", emitted); + Assert.DoesNotContain("await ", emitted); + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] + public async Task UnrelatedExplicitInterfaceImplementationDoesNotSuppressAsyncGeneration() + { + var (diagnostics, generatedSources) = await RunGenerator(@" + public interface IUnrelatedAsyncValidator + { + System.Threading.Tasks.Task ValidateAsync(string? name, FirstModel options, System.Threading.CancellationToken cancellationToken); + } + + public class FirstModel + { + [Required] + public string One { get; set; } = string.Empty; + } + + [OptionsValidator] + public partial class FirstValidator : IAsyncValidateOptions, IUnrelatedAsyncValidator + { + System.Threading.Tasks.Task IUnrelatedAsyncValidator.ValidateAsync(string? name, FirstModel options, System.Threading.CancellationToken cancellationToken) + => System.Threading.Tasks.Task.FromResult(ValidateOptionsResult.Success); + } + "); + + // The explicit implementation satisfies IUnrelatedAsyncValidator.ValidateAsync, not + // IAsyncValidateOptions.ValidateAsync (same name/signature, unrelated interface), so it must not + // suppress generation of the real method. + Assert.DoesNotContain(diagnostics, d => d.Id == DiagDescriptors.AlreadyImplementsValidateAsyncMethod.Id); + _ = Assert.Single(generatedSources); + Assert.Contains("ValidateAsync(string? name, global::Test.FirstModel options,", generatedSources[0].SourceText.ToString()); + } +#endif // NET + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] + public async Task AsyncValidationUsesAvailableDataAnnotationsApis() + { + string source = """ + using System.ComponentModel.DataAnnotations; + using Microsoft.Extensions.Options; + + namespace Test + { + public class FirstModel + { + [Required] + public string One { get; set; } = string.Empty; + } + + [OptionsValidator] + public partial class FirstValidator : IAsyncValidateOptions + { + } + } + """; + + var (diagnostics, generatedSources) = await RunGeneratorOnOptionsSource(source); + + Assert.Empty(diagnostics); + string generatedSource = Assert.Single(generatedSources).SourceText.ToString(); + Assert.Contains("ValidateAsync(string? name, global::Test.FirstModel options,", generatedSource); + +#if NET + Assert.Contains("Validator.TryValidateValueAsync(", generatedSource); +#else + Assert.DoesNotContain("Validator.TryValidateValueAsync(", generatedSource); + Assert.Contains("Validator.TryValidateValue(", generatedSource); +#endif // NET + + CSharpCompilation compilation = CreateCompilationForOptionsSource( + Path.GetRandomFileName(), + source + Environment.NewLine + generatedSource); + + using MemoryStream output = new(); + EmitResult emitResult = compilation.Emit(output); + Assert.True(emitResult.Success, string.Join(Environment.NewLine, emitResult.Diagnostics)); + } + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] public async Task ShouldNotProduceInfoWhenTheClassHasABaseClass() { diff --git a/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Microsoft.Extensions.Options.SourceGeneration.Unit.Tests.csproj b/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Microsoft.Extensions.Options.SourceGeneration.Unit.Tests.csproj index fdbeb98a17d0..df3d5517764d 100644 --- a/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Microsoft.Extensions.Options.SourceGeneration.Unit.Tests.csproj +++ b/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Microsoft.Extensions.Options.SourceGeneration.Unit.Tests.csproj @@ -24,6 +24,7 @@ + diff --git a/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/OptionsRuntimeTests.cs b/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/OptionsRuntimeTests.cs index 736f8251b6bd..69a163936346 100644 --- a/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/OptionsRuntimeTests.cs +++ b/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/OptionsRuntimeTests.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Microsoft.Extensions.Options; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; @@ -9,6 +8,8 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; using Xunit; namespace Microsoft.Gen.OptionsValidation.Unit.Test @@ -417,6 +418,375 @@ select Task.Factory.StartNew(() => Assert.True(result.Succeeded); }, TaskCreationOptions.LongRunning)).ToArray()); } + +#if NET + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + public async Task TestAsyncValidationSucceeds() + { + AsyncOptions options = new() + { + Name = "Valid", + Age = 30, + Nested = new() + { + Level = 5, + Id = "1", + Children = new() { new AsyncChildOptions { Name = "C1" } } + } + }; + + AsyncOptionsValidator validator = new(); + + ValidateOptionsResult asyncResult = await validator.ValidateAsync("AsyncOptions", options, default); + Assert.True(asyncResult.Succeeded); + + // The generated ValidateAsync must agree with the synchronous Validate for the same input. + ValidateOptionsResult syncResult = validator.Validate("AsyncOptions", options); + Assert.True(syncResult.Succeeded); + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + public async Task TestAsyncValidationFailures() + { + AsyncOptions options = new() + { + Name = "Invalid", // trips self-validation + Age = 0, // out of [Range(1, 100)] + Nested = new() + { + Level = 50, // out of [Range(0, 10)] + Id = null, // [Required] + Children = new() { new AsyncChildOptions { Name = null } } // [Required] on enumerated item + } + }; + + AsyncOptionsValidator validator = new(); + + ValidateOptionsResult asyncResult = await validator.ValidateAsync("AsyncOptions", options, default); + Assert.True(asyncResult.Failed); + + // Attribute, nested object-member, enumerated-item failures, plus the async self-validation failure, + // are all surfaced. The self-validation entry ("Async self-validation failed.") proves the generated + // ValidateAsync dispatches to IAsyncValidatableObject.ValidateAsync (await foreach) rather than the + // synchronous IValidatableObject.Validate path. + Assert.Equal(new List + { + "Age: The field AsyncOptions.Age must be between 1 and 100.", + "Level: The field AsyncOptions.Nested.Level must be between 0 and 10.", + "Id: The AsyncOptions.Nested.Id field is required.", + "Name: The AsyncOptions.Nested.Children[0].Name field is required.", + "Async self-validation failed.", + }, + asyncResult.Failures); + + // The synchronous Validate path uses the synchronous self-validation instead, confirming the two code + // paths are genuinely distinct and the async test would not pass if ValidateAsync silently ran the sync path. + ValidateOptionsResult syncResult = validator.Validate("AsyncOptions", options); + Assert.True(syncResult.Failed); + Assert.Contains("Sync self-validation failed.", syncResult.Failures); + Assert.DoesNotContain("Async self-validation failed.", syncResult.Failures); + Assert.DoesNotContain("Sync self-validation failed.", asyncResult.Failures); + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + public void TestAsyncOnlyValidatorInheritedSyncValidateRunsSyncValidation() + { + IValidateOptions validator = new AsyncParityOptionsValidator(); + + // Async self-validation alone must not make the generated synchronous path fail because + // IAsyncValidatableObject requires an IValidatableObject fallback. + ValidateOptionsResult syncResult = validator.Validate( + "AsyncParity", + new AsyncParityOptions { Name = "reserved", Age = 30 }); + Assert.True(syncResult.Succeeded); + + ValidateOptionsResult attributeResult = validator.Validate( + "AsyncParity", + new AsyncParityOptions { Name = "ok", Age = 0 }); + Assert.Equal( + ["Age: The field AsyncParity.Age must be between 1 and 100."], + attributeResult.Failures); + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + public async Task TestAsyncValidationWithSharedSynthesizedValidator() + { + // The async AsyncOptionsValidator and the synchronous SyncRootReusingNestedOptionsValidator both nest + // AsyncNestedOptions, so they share a single synthesized child validator. Exercise both roots to confirm the + // shared child validates correctly from an async caller and a sync caller alike. + AsyncOptions asyncOptions = new() + { + Name = "Valid", + Age = 30, + Nested = new() { Level = 50, Id = null, Children = new() { new AsyncChildOptions { Name = "C1" } } } + }; + + ValidateOptionsResult asyncResult = await new AsyncOptionsValidator().ValidateAsync("AsyncOptions", asyncOptions, default); + Assert.True(asyncResult.Failed); + Assert.Contains("Level: The field AsyncOptions.Nested.Level must be between 0 and 10.", asyncResult.Failures); + Assert.Contains("Id: The AsyncOptions.Nested.Id field is required.", asyncResult.Failures); + + SyncRootReusingNestedOptions syncOptions = new() + { + Nested = new() { Level = 5, Id = "1", Children = new() { new AsyncChildOptions { Name = "C1" } } } + }; + + ValidateOptionsResult syncResult = new SyncRootReusingNestedOptionsValidator().Validate("SyncRoot", syncOptions); + Assert.True(syncResult.Succeeded); + + // AsyncNestedOptions self-validates asynchronously. The async root must run that + // nested async self-validation, while the synchronous root sharing the same nested model type must not. + // Keying synthesized validators by model type alone would let the async root reuse a synchronous-only + // child (depending on discovery order) and silently skip nested async self-validation. + AsyncOptions asyncSelfValidating = new() + { + Name = "Valid", + Age = 30, + Nested = new() { Level = 5, Id = "trigger-async", Children = new() { new AsyncChildOptions { Name = "C1" } } } + }; + + ValidateOptionsResult nestedAsyncResult = await new AsyncOptionsValidator().ValidateAsync("AsyncOptions", asyncSelfValidating, default); + Assert.True(nestedAsyncResult.Failed); + Assert.Contains("Nested async self-validation failed.", nestedAsyncResult.Failures); + + SyncRootReusingNestedOptions syncSelfValidating = new() + { + Nested = new() { Level = 5, Id = "trigger-async", Children = new() { new AsyncChildOptions { Name = "C1" } } } + }; + + ValidateOptionsResult syncNestedResult = new SyncRootReusingNestedOptionsValidator().Validate("SyncRoot", syncSelfValidating); + Assert.True(syncNestedResult.Succeeded); + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + public async Task TestExplicitTypeTransitiveAndEnumeratedAsyncValidatorsAreAwaited() + { + // Both the explicit-type transitive validator ([ValidateObjectMembers(typeof(...))]) and the explicit-type + // enumerated-items validator ([ValidateEnumeratedItems(typeof(...))]) implement ValidateAsync explicitly, so + // the async parent must dispatch through IAsyncValidateOptions. Calling the concrete validator type would + // fail to compile, while dispatching through its synchronous Validate would silently skip the failure. + var options = new ExplicitAsyncRootOptions + { + Nested = new AsyncNestedOptions { Level = 5, Id = "trigger-async" }, + Items = new() { new AsyncNestedOptions { Level = 5, Id = "trigger-async" } } + }; + + ValidateOptionsResult result = await new ExplicitAsyncRootOptionsValidator().ValidateAsync("Root", options, default); + + Assert.True(result.Failed); + Assert.Equal(2, result.Failures.Count(f => f.Contains("Explicit async validation failed."))); + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + public async Task TestExplicitTypeTransitiveAndEnumeratedSyncValidatorsUseSyncFallback() + { + var options = new ExplicitSyncRootOptions + { + Nested = new AsyncNestedOptions(), + Items = [new AsyncNestedOptions()] + }; + + ValidateOptionsResult result = await new ExplicitSyncRootOptionsValidator().ValidateAsync("Root", options, default); + + Assert.True(result.Failed); + Assert.Equal(2, result.Failures.Count(f => f.Contains("Explicit sync validation failed."))); + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + public async Task TestGeneratedValidateAsyncForwardsCancellationTokenToChildValidatorsAndSelfValidation() + { + using var cts = new CancellationTokenSource(); + var nested = new CancellationObservingChildOptions(); + var item = new CancellationObservingChildOptions(); + var options = new CancellationObservingOptions + { + Name = "valid", + Nested = nested, + Items = [item] + }; + + ValidateOptionsResult result = await new CancellationObservingOptionsValidator().ValidateAsync("opt", options, cts.Token); + + Assert.True(result.Succeeded); + Assert.Equal(cts.Token, nested.ValidatorCancellationToken); + Assert.Equal(cts.Token, item.ValidatorCancellationToken); + Assert.Equal(cts.Token, options.SelfValidationCancellationToken); + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + public async Task TestGeneratedValidateAsyncForwardsCancellationToAsyncValidationAttribute() + { + using var cts = new CancellationTokenSource(); + var options = new AsyncAttributeCancellationOptions { Name = "valid" }; + Task validationTask = + new AsyncAttributeCancellationOptionsValidator().ValidateAsync("opt", options, cts.Token); + + try + { + await options.AttributeStarted.Task.WaitAsync(TimeSpan.FromSeconds(30)); + cts.Cancel(); + + await Assert.ThrowsAnyAsync( + () => validationTask.WaitAsync(TimeSpan.FromSeconds(30))); + } + finally + { + options.AttributeRelease.TrySetResult(true); + } + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + public async Task TestGeneratedValidateAsyncNoAwaitPathRunsSynchronously() + { + var validator = new SyncSelfValidatingOptionsValidator(); + + // The generated ValidateAsync for this model contains no genuine await, so the emitter wraps it in + // #pragma warning disable/restore CS1998 rather than falling back to a non-async method returning + // Task.FromResult(...); the method is still declared async so cancellationToken.ThrowIfCancellationRequested() + // surfaces on the returned Task instead of throwing synchronously (see the dedicated cancellation test below). + // A synchronously-completing async method still finishes eagerly without yielding, so this still runs synchronously. + Task successTask = validator.ValidateAsync("opt", new SyncSelfValidatingOptions { Name = "ok" }, default); + Assert.True(successTask.IsCompletedSuccessfully); + Assert.True((await successTask).Succeeded); + + ValidateOptionsResult failure = await validator.ValidateAsync("opt", new SyncSelfValidatingOptions { Name = "bad" }, default); + Assert.True(failure.Failed); + Assert.Contains(failure.Failures, f => f.Contains("Sync self-validation failed.")); + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + public async Task TestGeneratedValidateAsyncNoAwaitPathDoesNotThrowSynchronously() + { + var validator = new SyncSelfValidatingOptionsValidator(); + using var cts = new CancellationTokenSource(); + cts.Cancel(); + + // Even though this model's generated ValidateAsync body has no genuine await (see the test above), the + // method must still be declared async so that cancellationToken.ThrowIfCancellationRequested() surfaces + // on the returned Task rather than throwing synchronously out of the call. Calling it here, without + // await, must not throw synchronously even with an already-canceled token. + Task task = validator.ValidateAsync("opt", new SyncSelfValidatingOptions { Name = "ok" }, cts.Token); + + await Assert.ThrowsAnyAsync(() => task); + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + public async Task TestAsyncSelfValidationToleratesNullEnumerable() + { + var validator = new NullAsyncEnumerableOptionsValidator(); + + // IAsyncValidatableObject.ValidateAsync returns null here despite its non-nullable contract. The + // generated ValidateAsync must guard against this before "await foreach" (matching the runtime + // Validator's own null-check) instead of throwing a NullReferenceException. + ValidateOptionsResult success = await validator.ValidateAsync("opt", new NullAsyncEnumerableOptions { Name = "ok" }, default); + Assert.True(success.Succeeded); + + ValidateOptionsResult failure = await validator.ValidateAsync("opt", new NullAsyncEnumerableOptions { Name = null }, default); + Assert.True(failure.Failed); + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + public async Task TestSynthesizedValidatorNamesDoNotCollide() + { + // The synthesized child validator name for an implicitly-typed async transitive member is + // "__" + modelName + "AsyncValidator__"; for a synchronous one it's "__" + modelName + "Validator__". A + // model literally named "Foo" reached asynchronously ("__FooAsyncValidator__") and a model literally + // named "FooAsync" reached synchronously ("__" + "FooAsync" + "Validator__" == "__FooAsyncValidator__") + // therefore collide unless the generator deterministically de-duplicates. The mere presence of both + // generated validators below in this compiled assembly proves the collision was resolved (otherwise the + // assembly would not compile at all); the assertions confirm each root still validates correctly. + var asyncRootValidator = new SynthesizedNameCollisionAsyncRootValidator(); + ValidateOptionsResult asyncResult = await asyncRootValidator.ValidateAsync( + "opt", new SynthesizedNameCollisionAsyncRoot { Nested = new Foo { Name = null } }, default); + Assert.True(asyncResult.Failed); + + var syncRootValidator = new SynthesizedNameCollisionSyncRootValidator(); + ValidateOptionsResult syncResult = syncRootValidator.Validate( + "opt", new SynthesizedNameCollisionSyncRoot { Nested = new FooAsync { Name = null } }); + Assert.True(syncResult.Failed); + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + public async Task TestConcurrentMemberValidationRunsMembersConcurrently() + { + var gate = new ConcurrencyGate(); + var options = new ConcurrentMembersOptions + { + MemberA = new GateOptionsA { Gate = gate }, + MemberB = new GateOptionsB { Gate = gate } + }; + + var validator = new ConcurrentMembersOptionsValidator(); + + ValidateOptionsResult result = await validator.ValidateAsync("opt", options, default); + + // Each member's transitive validator signals its own rendezvous slot and waits for the other member. + // Sequential validation times out; success proves both member validations started before either completed. + Assert.True(result.Succeeded); + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + public async Task TestGeneratedValidateAsyncMatchesValidatorParity() + { + var validator = new AsyncParityOptionsValidator(); + + var valid = new AsyncParityOptions { Name = "ok", Age = 30 }; + var validResults = new List(); + bool validatorValid = await Validator.TryValidateObjectAsync(valid, new ValidationContext(valid), validResults, validateAllProperties: true); + ValidateOptionsResult generatedValid = await validator.ValidateAsync("AsyncParityOptions", valid, default); + Assert.True(validatorValid); + Assert.True(generatedValid.Succeeded); + Assert.Empty(validResults); + + // Attribute-only failure (Age out of range, name is valid and not reserved). Note: Validator.TryValidateObjectAsync + // skips IAsyncValidatableObject.ValidateAsync once property validation fails, whereas the generated method always + // runs it; the two agree here only because the self-validation yields nothing for this input, so we deliberately + // avoid combining an attribute failure with a self-validation failure in one instance. + var attributeFailure = new AsyncParityOptions { Name = "ok", Age = 0 }; + var attributeResults = new List(); + bool validatorAttr = await Validator.TryValidateObjectAsync(attributeFailure, new ValidationContext(attributeFailure), attributeResults, validateAllProperties: true); + ValidateOptionsResult generatedAttr = await validator.ValidateAsync("AsyncParityOptions", attributeFailure, default); + Assert.False(validatorAttr); + Assert.True(generatedAttr.Failed); + Assert.Equal(attributeResults.Count, generatedAttr.Failures.Count()); + + // Self-validation-only failure (attributes pass, reserved name). Validator runs the async self-validation because + // property validation succeeds, so both report the same single failure. + var selfFailure = new AsyncParityOptions { Name = "reserved", Age = 30 }; + var selfResults = new List(); + bool validatorSelf = await Validator.TryValidateObjectAsync(selfFailure, new ValidationContext(selfFailure), selfResults, validateAllProperties: true); + ValidateOptionsResult generatedSelf = await validator.ValidateAsync("AsyncParityOptions", selfFailure, default); + Assert.False(validatorSelf); + Assert.True(generatedSelf.Failed); + Assert.Equal(selfResults.Count, generatedSelf.Failures.Count()); + Assert.Contains(generatedSelf.Failures, f => f.Contains("Name is reserved.")); + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + public async Task TestGeneratedValidatorRunsThroughAsyncStartupValidation() + { + var services = new ServiceCollection(); + services.AddOptions() + .Configure(options => + { + options.Name = "reserved"; + options.Age = 30; + }) + .Validate() + .ValidateOnStart(); + + using ServiceProvider serviceProvider = services.BuildServiceProvider(); + IValidateOptions registered = + Assert.Single(serviceProvider.GetServices>()); + + Assert.IsAssignableFrom>(registered); + + OptionsValidationException error = await Assert.ThrowsAsync( + () => serviceProvider.GetRequiredService().ValidateAsync()); + + Assert.Contains(error.Failures, failure => failure.Contains("Name is reserved.")); + } +#endif // NET } public class FakeCount(int count) { public int Count { get { return count; } } } @@ -637,4 +1007,413 @@ public class OptionsWithTimeSpanRangeAttribute public partial class TimeSpanRangeAttributeValidator : IValidateOptions { } + +#if NET + public class AsyncChildOptions + { + [Required] + public string? Name { get; set; } + } + + public class AsyncNestedOptions : IAsyncValidatableObject + { + [Range(0, 10)] + public int Level { get; set; } + + [Required] + public string? Id { get; set; } + + [ValidateEnumeratedItems] + public List? Children { get; set; } + + public async IAsyncEnumerable ValidateAsync( + ValidationContext validationContext, + [global::System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default) + { + await Task.Yield(); + if (Id == "trigger-async") + { + yield return new ValidationResult("Nested async self-validation failed."); + } + } + + public IEnumerable Validate(ValidationContext validationContext) + { + yield break; + } + } + + public class AsyncOptions : IAsyncValidatableObject + { + [Required] + public string? Name { get; set; } + + [Range(1, 100)] + public int Age { get; set; } + + [ValidateObjectMembers] + public AsyncNestedOptions? Nested { get; set; } + + public async IAsyncEnumerable ValidateAsync( + ValidationContext validationContext, + [global::System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default) + { + await Task.Yield(); + if (Name == "Invalid") + { + yield return new ValidationResult("Async self-validation failed."); + } + } + + public IEnumerable Validate(ValidationContext validationContext) + { + if (Name == "Invalid") + { + yield return new ValidationResult("Sync self-validation failed."); + } + } + } + + [OptionsValidator] + public partial class AsyncOptionsValidator : IAsyncValidateOptions + { + } + + // Regression: a synchronous validator that nests the same type (AsyncNestedOptions) as the async + // AsyncOptionsValidator. Synthesized child validators are cached per model type and per capability + // (synchronous vs asynchronous), so the async root gets an async-capable child and the synchronous root gets a + // synchronous one regardless of discovery order. This guards against the async root emitting + // "await child.ValidateAsync(...)" against a synthesized child generated without a ValidateAsync method, and + // against the async root silently falling back to the synchronous child's Validate path. + public class SyncRootReusingNestedOptions + { + [ValidateObjectMembers] + public AsyncNestedOptions? Nested { get; set; } + } + + [OptionsValidator] + public partial class SyncRootReusingNestedOptionsValidator : IValidateOptions + { + } + + // An explicitly specified transitive/enumerated validator (typeof(...)) that implements + // IAsyncValidateOptions must be dispatched through ValidateAsync by an async parent. Otherwise the parent calls + // the child's synchronous Validate and silently skips the child's async-only validation. + public class ExplicitAsyncRootOptions + { + [ValidateObjectMembers(typeof(ExplicitAsyncNestedValidator))] + public AsyncNestedOptions? Nested { get; set; } + + [ValidateEnumeratedItems(typeof(ExplicitAsyncNestedValidator))] + public List? Items { get; set; } + } + + public sealed class ExplicitAsyncNestedValidator : IAsyncValidateOptions + { + public ValidateOptionsResult Validate(string? name, AsyncNestedOptions options) => ValidateOptionsResult.Success; + + Task IAsyncValidateOptions.ValidateAsync( + string? name, + AsyncNestedOptions options, + CancellationToken cancellationToken) + => Task.FromResult(ValidateOptionsResult.Fail("Explicit async validation failed.")); + } + + [OptionsValidator] + public partial class ExplicitAsyncRootOptionsValidator : IAsyncValidateOptions + { + } + + public class ExplicitSyncRootOptions + { + [ValidateObjectMembers(typeof(ExplicitSyncNestedValidator))] + public AsyncNestedOptions? Nested { get; set; } + + [ValidateEnumeratedItems(typeof(ExplicitSyncNestedValidator))] + public List? Items { get; set; } + } + + public sealed class ExplicitSyncNestedValidator : IValidateOptions + { + public ValidateOptionsResult Validate(string? name, AsyncNestedOptions options) + => ValidateOptionsResult.Fail("Explicit sync validation failed."); + } + + [OptionsValidator] + public partial class ExplicitSyncRootOptionsValidator : IAsyncValidateOptions + { + } + + [AttributeUsage(AttributeTargets.Property)] + public sealed class CancellationObservingAttribute : AsyncValidationAttribute + { + protected override ValidationResult? IsValid(object? value, ValidationContext validationContext) + => ValidationResult.Success; + + protected override Task IsValidAsync( + object? value, + ValidationContext validationContext, + CancellationToken cancellationToken) + { + AsyncAttributeCancellationOptions options = + (AsyncAttributeCancellationOptions)validationContext.ObjectInstance; + options.AttributeStarted.TrySetResult(true); + return WaitForReleaseAsync(options, cancellationToken); + } + + private static async Task WaitForReleaseAsync( + AsyncAttributeCancellationOptions options, + CancellationToken cancellationToken) + { + await options.AttributeRelease.Task.WaitAsync(cancellationToken).ConfigureAwait(false); + return ValidationResult.Success; + } + } + + public sealed class AsyncAttributeCancellationOptions + { + [CancellationObserving] + public string? Name { get; set; } + + public TaskCompletionSource AttributeStarted { get; } = + new(TaskCreationOptions.RunContinuationsAsynchronously); + + public TaskCompletionSource AttributeRelease { get; } = + new(TaskCreationOptions.RunContinuationsAsynchronously); + } + + [OptionsValidator] + public partial class AsyncAttributeCancellationOptionsValidator : + IAsyncValidateOptions + { + } + + public sealed class CancellationObservingChildOptions + { + public CancellationToken ValidatorCancellationToken { get; set; } + } + + public sealed class CancellationObservingChildValidator : IAsyncValidateOptions + { + public ValidateOptionsResult Validate(string? name, CancellationObservingChildOptions options) + => ValidateOptionsResult.Success; + + public Task ValidateAsync( + string? name, + CancellationObservingChildOptions options, + CancellationToken cancellationToken = default) + { + options.ValidatorCancellationToken = cancellationToken; + return Task.FromResult(ValidateOptionsResult.Success); + } + } + + public class CancellationObservingOptions : IAsyncValidatableObject + { + [Required] + public string? Name { get; set; } + + [ValidateObjectMembers(typeof(CancellationObservingChildValidator))] + public CancellationObservingChildOptions? Nested { get; set; } + + [ValidateEnumeratedItems(typeof(CancellationObservingChildValidator))] + public List? Items { get; set; } + + public CancellationToken SelfValidationCancellationToken { get; set; } + + public async IAsyncEnumerable ValidateAsync( + ValidationContext validationContext, + [global::System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default) + { + SelfValidationCancellationToken = cancellationToken; + await Task.Yield(); + yield break; + } + + public IEnumerable Validate(ValidationContext validationContext) + { + yield break; + } + } + + [OptionsValidator] + public partial class CancellationObservingOptionsValidator : IAsyncValidateOptions + { + } + + // Model that validates only synchronously (IValidatableObject, no attributes, no async children) but is validated by + // an async validator, so the generated ValidateAsync body contains no genuine await and the emitter must suppress + // CS1998 rather than dropping the async keyword (dropping it would make ThrowIfCancellationRequested() throw + // synchronously instead of surfacing on the returned Task). + public class SyncSelfValidatingOptions : IValidatableObject + { + public string? Name { get; set; } + + public IEnumerable Validate(ValidationContext validationContext) + { + if (Name == "bad") + { + yield return new ValidationResult("Sync self-validation failed.", new[] { nameof(Name) }); + } + } + } + + [OptionsValidator] + public partial class SyncSelfValidatingOptionsValidator : IAsyncValidateOptions + { + } + + // Flat model (attributes + async self-validation, no nested members) so the generated ValidateAsync can be compared + // for parity against Validator.TryValidateObjectAsync, which does not recurse into nested members. + public class AsyncParityOptions : IAsyncValidatableObject + { + [Required] + public string? Name { get; set; } + + [Range(1, 100)] + public int Age { get; set; } + + public async IAsyncEnumerable ValidateAsync( + ValidationContext validationContext, + [global::System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default) + { + await Task.Yield(); + if (Name == "reserved") + { + yield return new ValidationResult("Name is reserved.", new[] { nameof(Name) }); + } + } + + public IEnumerable Validate(ValidationContext validationContext) + { + yield break; + } + } + + [OptionsValidator] + public partial class AsyncParityOptionsValidator : IAsyncValidateOptions + { + } + + // Self-validation whose IAsyncValidatableObject.ValidateAsync returns null despite the interface's non-nullable + // contract. The generated ValidateAsync must guard against this (matching the runtime Validator's own + // null-check) rather than throwing a NullReferenceException from "await foreach". + public class NullAsyncEnumerableOptions : IAsyncValidatableObject + { + [Required] + public string? Name { get; set; } + + public IAsyncEnumerable ValidateAsync(ValidationContext validationContext, CancellationToken cancellationToken = default) => null!; + + public IEnumerable Validate(ValidationContext validationContext) + { + yield break; + } + } + + [OptionsValidator] + public partial class NullAsyncEnumerableOptionsValidator : IAsyncValidateOptions + { + } + + // Regression: the synthesized child validator name for an implicitly-typed async transitive member is + // "__" + modelName + "AsyncValidator__", while for a synchronous one it's "__" + modelName + "Validator__". A + // model literally named "Foo" reached asynchronously synthesizes "__FooAsyncValidator__", and a model literally + // named "FooAsync" reached synchronously synthesizes the exact same candidate name + // ("__" + "FooAsync" + "Validator__" == "__FooAsyncValidator__"). Without deterministic de-duplication these two + // distinct synthesized validator types collide and the assembly fails to compile (duplicate type definition). + public class Foo + { + [Required] + public string? Name { get; set; } + } + + public class FooAsync + { + [Required] + public string? Name { get; set; } + } + + public class SynthesizedNameCollisionAsyncRoot + { + [ValidateObjectMembers] + public Foo? Nested { get; set; } + } + + [OptionsValidator] + public partial class SynthesizedNameCollisionAsyncRootValidator : IAsyncValidateOptions + { + } + + public class SynthesizedNameCollisionSyncRoot + { + [ValidateObjectMembers] + public FooAsync? Nested { get; set; } + } + + [OptionsValidator] + public partial class SynthesizedNameCollisionSyncRootValidator : IValidateOptions + { + } + + // Shared rendezvous used to prove that two members of ConcurrentMembersOptions are validated concurrently + // (via Task.WhenAll) rather than sequentially. + public sealed class ConcurrencyGate + { + public TaskCompletionSource ReachedA { get; } = new(TaskCreationOptions.RunContinuationsAsynchronously); + public TaskCompletionSource ReachedB { get; } = new(TaskCreationOptions.RunContinuationsAsynchronously); + } + + public class GateOptionsA + { + public ConcurrencyGate? Gate { get; set; } + } + + public class GateOptionsB + { + public ConcurrencyGate? Gate { get; set; } + } + + // Hand-written (not source-generated) explicit-type transitive validators: each signals its own rendezvous slot + // and waits for the other's, so the overall ValidateAsync succeeds only if both run concurrently. + public sealed class GateOptionsAValidator : IAsyncValidateOptions + { + public ValidateOptionsResult Validate(string? name, GateOptionsA options) => ValidateOptionsResult.Success; + + public async Task ValidateAsync(string? name, GateOptionsA options, CancellationToken cancellationToken = default) + { + ConcurrencyGate gate = options.Gate!; + gate.ReachedA.TrySetResult(true); + await gate.ReachedB.Task.WaitAsync(TimeSpan.FromSeconds(30), cancellationToken).ConfigureAwait(false); + return ValidateOptionsResult.Success; + } + } + + public sealed class GateOptionsBValidator : IAsyncValidateOptions + { + public ValidateOptionsResult Validate(string? name, GateOptionsB options) => ValidateOptionsResult.Success; + + public async Task ValidateAsync(string? name, GateOptionsB options, CancellationToken cancellationToken = default) + { + ConcurrencyGate gate = options.Gate!; + gate.ReachedB.TrySetResult(true); + await gate.ReachedA.Task.WaitAsync(TimeSpan.FromSeconds(30), cancellationToken).ConfigureAwait(false); + return ValidateOptionsResult.Success; + } + } + + public class ConcurrentMembersOptions + { + [ValidateObjectMembers(typeof(GateOptionsAValidator))] + public GateOptionsA? MemberA { get; set; } + + [ValidateObjectMembers(typeof(GateOptionsBValidator))] + public GateOptionsB? MemberB { get; set; } + } + + [OptionsValidator] + public partial class ConcurrentMembersOptionsValidator : IAsyncValidateOptions + { + } +#endif // NET } diff --git a/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Resources/Strings.resx b/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Resources/Strings.resx index 19dc7159a40c..4260ea9ab788 100644 --- a/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Resources/Strings.resx +++ b/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Resources/Strings.resx @@ -189,6 +189,12 @@ Type {0} already implements the Validate method. + + A type already includes an implementation of the 'ValidateAsync' method. + + + Type {0} already implements the ValidateAsync method. + 'OptionsValidatorAttribute' can't be applied to a static class. diff --git a/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Baselines/NetCoreApp/Validators.g.cs b/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Baselines/NetCoreApp/Validators.g.cs index ab87bf77a3cd..26b00895f606 100644 --- a/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Baselines/NetCoreApp/Validators.g.cs +++ b/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Baselines/NetCoreApp/Validators.g.cs @@ -695,7 +695,7 @@ partial class FirstValidator namespace KeywordNames { [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] - internal sealed partial class __classValidator__ + internal sealed partial class __classAsyncValidator__ { /// /// Validates a specific named options instance (or all when is ). @@ -730,6 +730,43 @@ internal sealed partial class __classValidator__ return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } + + /// + /// Validates a specific named options instance asynchronously (or all when is ). + /// + /// The name of the options instance being validated. + /// The options instance. + /// The to monitor for cancellation requests. + /// A task representing the asynchronous validation operation, containing the validation result. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] + #if !NET + [global::System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessage("Trimming", "IL2026:RequiresUnreferencedCode", + Justification = "The created ValidationContext object is used in a way that never call reflection")] + #endif + public static async global::System.Threading.Tasks.Task ValidateAsync(string? name, global::KeywordNames.@class options, global::System.Threading.CancellationToken cancellationToken = default) + { + cancellationToken.ThrowIfCancellationRequested(); + + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; + #if NET + var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options, "class", null, null); + #else + var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); + #endif + var validationResults = new global::System.Collections.Generic.List(); + var validationAttributes = new global::System.Collections.Generic.List(2); + + context.MemberName = "string"; + context.DisplayName = string.IsNullOrEmpty(name) ? "string" : $"{name}.string"; + validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); + validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); + if (!await global::System.ComponentModel.DataAnnotations.Validator.TryValidateValueAsync(options.@string, context, validationResults, validationAttributes, cancellationToken).ConfigureAwait(false)) + { + (builder ??= new()).AddResults(validationResults); + } + + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); + } } } namespace KeywordNames @@ -779,7 +816,7 @@ partial class FirstValidator if (options.@event is not null) { - (builder ??= new()).AddResult(global::KeywordNames.__classValidator__.Validate(string.IsNullOrEmpty(name) ? "event" : $"{name}.event", options.@event)); + (builder ??= new()).AddResult(global::KeywordNames.__classAsyncValidator__.Validate(string.IsNullOrEmpty(name) ? "event" : $"{name}.event", options.@event)); } if (options.@const is not null) @@ -789,7 +826,7 @@ partial class FirstValidator { if (o is not null) { - (builder ??= new()).AddResult(global::KeywordNames.__classValidator__.Validate(string.IsNullOrEmpty(name) ? $"const[{count}]" : $"{name}.const[{count}]", o)); + (builder ??= new()).AddResult(global::KeywordNames.__classAsyncValidator__.Validate(string.IsNullOrEmpty(name) ? $"const[{count}]" : $"{name}.const[{count}]", o)); } else { @@ -801,6 +838,121 @@ partial class FirstValidator return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } + + /// + /// Validates a specific named options instance asynchronously (or all when is ). + /// + /// The name of the options instance being validated. + /// The options instance. + /// The to monitor for cancellation requests. + /// A task representing the asynchronous validation operation, containing the validation result. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] + #if !NET + [global::System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessage("Trimming", "IL2026:RequiresUnreferencedCode", + Justification = "The created ValidationContext object is used in a way that never call reflection")] + #endif + public async global::System.Threading.Tasks.Task ValidateAsync(string? name, global::KeywordNames.FirstModel options, global::System.Threading.CancellationToken cancellationToken = default) + { + cancellationToken.ThrowIfCancellationRequested(); + + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; + async global::System.Threading.Tasks.Task Validate0Async() + { + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? memberBuilder0 = null; + #if NET + var memberContext0 = new global::System.ComponentModel.DataAnnotations.ValidationContext(options, "FirstModel", null, null); + #else + var memberContext0 = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); + #endif + var memberValidationResults0 = new global::System.Collections.Generic.List(); + var memberValidationAttributes0 = new global::System.Collections.Generic.List(2); + memberContext0.MemberName = "namespace"; + memberContext0.DisplayName = string.IsNullOrEmpty(name) ? "namespace" : $"{name}.namespace"; + memberValidationAttributes0.Add(global::__OptionValidationStaticInstances.__Attributes.A1); + memberValidationAttributes0.Add(global::__OptionValidationStaticInstances.__Attributes.A2); + if (!await global::System.ComponentModel.DataAnnotations.Validator.TryValidateValueAsync(options.@namespace, memberContext0, memberValidationResults0, memberValidationAttributes0, cancellationToken).ConfigureAwait(false)) + { + (memberBuilder0 ??= new()).AddResults(memberValidationResults0); + } + return memberBuilder0 is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : memberBuilder0.Build(); + } + + async global::System.Threading.Tasks.Task Validate1Async() + { + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? memberBuilder1 = null; + #if NET + var memberContext1 = new global::System.ComponentModel.DataAnnotations.ValidationContext(options, "FirstModel", null, null); + #else + var memberContext1 = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); + #endif + var memberValidationResults1 = new global::System.Collections.Generic.List(); + var memberValidationAttributes1 = new global::System.Collections.Generic.List(1); + memberContext1.MemberName = "if"; + memberContext1.DisplayName = string.IsNullOrEmpty(name) ? "if" : $"{name}.if"; + memberValidationAttributes1.Add(global::__OptionValidationStaticInstances.__Attributes.A7); + if (!await global::System.ComponentModel.DataAnnotations.Validator.TryValidateValueAsync(options.@if, memberContext1, memberValidationResults1, memberValidationAttributes1, cancellationToken).ConfigureAwait(false)) + { + (memberBuilder1 ??= new()).AddResults(memberValidationResults1); + } + return memberBuilder1 is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : memberBuilder1.Build(); + } + + async global::System.Threading.Tasks.Task Validate2Async() + { + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? memberBuilder2 = null; + if (options.@event is not null) + { + (memberBuilder2 ??= new()).AddResult(await global::KeywordNames.__classAsyncValidator__.ValidateAsync(string.IsNullOrEmpty(name) ? "event" : $"{name}.event", options.@event, cancellationToken).ConfigureAwait(false)); + } + return memberBuilder2 is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : memberBuilder2.Build(); + } + + async global::System.Threading.Tasks.Task Validate3Async() + { + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? memberBuilder3 = null; + if (options.@const is not null) + { + var count = 0; + foreach (var o in options.@const) + { + if (o is not null) + { + (memberBuilder3 ??= new()).AddResult(await global::KeywordNames.__classAsyncValidator__.ValidateAsync(string.IsNullOrEmpty(name) ? $"const[{count}]" : $"{name}.const[{count}]", o, cancellationToken).ConfigureAwait(false)); + } + else + { + (memberBuilder3 ??= new()).AddError(string.IsNullOrEmpty(name) ? $"const[{count}] is null" : $"{name}.const[{count}] is null"); + } + count++; + } + } + return memberBuilder3 is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : memberBuilder3.Build(); + } + + var memberTask0 = Validate0Async(); + var memberTask1 = Validate1Async(); + var memberTask2 = Validate2Async(); + var memberTask3 = Validate3Async(); + var memberResults = await global::System.Threading.Tasks.Task.WhenAll(memberTask0, memberTask1, memberTask2, memberTask3).ConfigureAwait(false); + + if (memberResults[0].Failed) + { + (builder ??= new()).AddResult(memberResults[0]); + } + if (memberResults[1].Failed) + { + (builder ??= new()).AddResult(memberResults[1]); + } + if (memberResults[2].Failed) + { + (builder ??= new()).AddResult(memberResults[2]); + } + if (memberResults[3].Failed) + { + (builder ??= new()).AddResult(memberResults[3]); + } + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); + } } } namespace KeywordNamesNested @@ -1602,6 +1754,95 @@ internal sealed partial class __SecondModelValidator__ } } namespace SelfValidation +{ + partial class AsyncSelfValidatingValidator + { + /// + /// Validates a specific named options instance (or all when is ). + /// + /// The name of the options instance being validated. + /// The options instance. + /// Validation result. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] + #if !NET + [global::System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessage("Trimming", "IL2026:RequiresUnreferencedCode", + Justification = "The created ValidationContext object is used in a way that never call reflection")] + #endif + public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::SelfValidation.AsyncSelfValidatingModel options) + { + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; + #if NET + var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options, "AsyncSelfValidatingModel", null, null); + #else + var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); + #endif + var validationResults = new global::System.Collections.Generic.List(); + var validationAttributes = new global::System.Collections.Generic.List(1); + + context.MemberName = "Name"; + context.DisplayName = string.IsNullOrEmpty(name) ? "Name" : $"{name}.Name"; + validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Name, context, validationResults, validationAttributes)) + { + (builder ??= new()).AddResults(validationResults); + } + + context.MemberName = "Validate"; + context.DisplayName = string.IsNullOrEmpty(name) ? "Validate" : $"{name}.Validate"; + (builder ??= new()).AddResults(((global::System.ComponentModel.DataAnnotations.IValidatableObject)options).Validate(context)); + + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); + } + + /// + /// Validates a specific named options instance asynchronously (or all when is ). + /// + /// The name of the options instance being validated. + /// The options instance. + /// The to monitor for cancellation requests. + /// A task representing the asynchronous validation operation, containing the validation result. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] + #if !NET + [global::System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessage("Trimming", "IL2026:RequiresUnreferencedCode", + Justification = "The created ValidationContext object is used in a way that never call reflection")] + #endif + public async global::System.Threading.Tasks.Task ValidateAsync(string? name, global::SelfValidation.AsyncSelfValidatingModel options, global::System.Threading.CancellationToken cancellationToken = default) + { + cancellationToken.ThrowIfCancellationRequested(); + + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; + #if NET + var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options, "AsyncSelfValidatingModel", null, null); + #else + var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); + #endif + var validationResults = new global::System.Collections.Generic.List(); + var validationAttributes = new global::System.Collections.Generic.List(1); + + context.MemberName = "Name"; + context.DisplayName = string.IsNullOrEmpty(name) ? "Name" : $"{name}.Name"; + validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); + if (!await global::System.ComponentModel.DataAnnotations.Validator.TryValidateValueAsync(options.Name, context, validationResults, validationAttributes, cancellationToken).ConfigureAwait(false)) + { + (builder ??= new()).AddResults(validationResults); + } + + context.MemberName = "ValidateAsync"; + context.DisplayName = string.IsNullOrEmpty(name) ? "ValidateAsync" : $"{name}.ValidateAsync"; + var asyncSelfValidationResults = ((global::System.ComponentModel.DataAnnotations.IAsyncValidatableObject)options).ValidateAsync(context, cancellationToken); + if (asyncSelfValidationResults is not null) + { + await foreach (var asyncValidationResult in global::System.Threading.Tasks.TaskAsyncEnumerableExtensions.ConfigureAwait(asyncSelfValidationResults, false)) + { + (builder ??= new()).AddResult(asyncValidationResult); + } + } + + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); + } + } +} +namespace SelfValidation { partial struct FirstValidator { diff --git a/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Baselines/NetFX/Validators.g.cs b/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Baselines/NetFX/Validators.g.cs index ba771f09ae58..53729e22c40e 100644 --- a/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Baselines/NetFX/Validators.g.cs +++ b/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Baselines/NetFX/Validators.g.cs @@ -639,7 +639,7 @@ partial class FirstValidator namespace KeywordNames { [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] - internal sealed partial class __classValidator__ + internal sealed partial class __classAsyncValidator__ { /// /// Validates a specific named options instance (or all when is ). @@ -670,6 +670,41 @@ internal sealed partial class __classValidator__ return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } + + /// + /// Validates a specific named options instance asynchronously (or all when is ). + /// + /// The name of the options instance being validated. + /// The options instance. + /// The to monitor for cancellation requests. + /// A task representing the asynchronous validation operation, containing the validation result. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] + #pragma warning disable CS1998 // The method is declared async so cancellationToken.ThrowIfCancellationRequested() below surfaces on the returned Task rather than throwing synchronously. + public static async global::System.Threading.Tasks.Task ValidateAsync(string? name, global::KeywordNames.@class options, global::System.Threading.CancellationToken cancellationToken = default) + { + cancellationToken.ThrowIfCancellationRequested(); + + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; + #if NET + var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options, "class", null, null); + #else + var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); + #endif + var validationResults = new global::System.Collections.Generic.List(); + var validationAttributes = new global::System.Collections.Generic.List(2); + + context.MemberName = "string"; + context.DisplayName = string.IsNullOrEmpty(name) ? "string" : $"{name}.string"; + validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); + validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.@string, context, validationResults, validationAttributes)) + { + (builder ??= new()).AddResults(validationResults); + } + + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); + } + #pragma warning restore CS1998 } } namespace KeywordNames @@ -715,7 +750,7 @@ partial class FirstValidator if (options.@event is not null) { - (builder ??= new()).AddResult(global::KeywordNames.__classValidator__.Validate(string.IsNullOrEmpty(name) ? "event" : $"{name}.event", options.@event)); + (builder ??= new()).AddResult(global::KeywordNames.__classAsyncValidator__.Validate(string.IsNullOrEmpty(name) ? "event" : $"{name}.event", options.@event)); } if (options.@const is not null) @@ -725,7 +760,7 @@ partial class FirstValidator { if (o is not null) { - (builder ??= new()).AddResult(global::KeywordNames.__classValidator__.Validate(string.IsNullOrEmpty(name) ? $"const[{count}]" : $"{name}.const[{count}]", o)); + (builder ??= new()).AddResult(global::KeywordNames.__classAsyncValidator__.Validate(string.IsNullOrEmpty(name) ? $"const[{count}]" : $"{name}.const[{count}]", o)); } else { @@ -737,6 +772,121 @@ partial class FirstValidator return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } + + /// + /// Validates a specific named options instance asynchronously (or all when is ). + /// + /// The name of the options instance being validated. + /// The options instance. + /// The to monitor for cancellation requests. + /// A task representing the asynchronous validation operation, containing the validation result. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] + public async global::System.Threading.Tasks.Task ValidateAsync(string? name, global::KeywordNames.FirstModel options, global::System.Threading.CancellationToken cancellationToken = default) + { + cancellationToken.ThrowIfCancellationRequested(); + + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; + #pragma warning disable CS1998 // This member's validation never awaits, but the local function is declared async to participate uniformly in Task.WhenAll below. + async global::System.Threading.Tasks.Task Validate0Async() + { + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? memberBuilder0 = null; + #if NET + var memberContext0 = new global::System.ComponentModel.DataAnnotations.ValidationContext(options, "FirstModel", null, null); + #else + var memberContext0 = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); + #endif + var memberValidationResults0 = new global::System.Collections.Generic.List(); + var memberValidationAttributes0 = new global::System.Collections.Generic.List(2); + memberContext0.MemberName = "namespace"; + memberContext0.DisplayName = string.IsNullOrEmpty(name) ? "namespace" : $"{name}.namespace"; + memberValidationAttributes0.Add(global::__OptionValidationStaticInstances.__Attributes.A1); + memberValidationAttributes0.Add(global::__OptionValidationStaticInstances.__Attributes.A2); + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.@namespace, memberContext0, memberValidationResults0, memberValidationAttributes0)) + { + (memberBuilder0 ??= new()).AddResults(memberValidationResults0); + } + return memberBuilder0 is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : memberBuilder0.Build(); + } + #pragma warning restore CS1998 + + #pragma warning disable CS1998 // This member's validation never awaits, but the local function is declared async to participate uniformly in Task.WhenAll below. + async global::System.Threading.Tasks.Task Validate1Async() + { + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? memberBuilder1 = null; + #if NET + var memberContext1 = new global::System.ComponentModel.DataAnnotations.ValidationContext(options, "FirstModel", null, null); + #else + var memberContext1 = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); + #endif + var memberValidationResults1 = new global::System.Collections.Generic.List(); + var memberValidationAttributes1 = new global::System.Collections.Generic.List(1); + memberContext1.MemberName = "if"; + memberContext1.DisplayName = string.IsNullOrEmpty(name) ? "if" : $"{name}.if"; + memberValidationAttributes1.Add(global::__OptionValidationStaticInstances.__Attributes.A7); + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.@if, memberContext1, memberValidationResults1, memberValidationAttributes1)) + { + (memberBuilder1 ??= new()).AddResults(memberValidationResults1); + } + return memberBuilder1 is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : memberBuilder1.Build(); + } + #pragma warning restore CS1998 + + async global::System.Threading.Tasks.Task Validate2Async() + { + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? memberBuilder2 = null; + if (options.@event is not null) + { + (memberBuilder2 ??= new()).AddResult(await global::KeywordNames.__classAsyncValidator__.ValidateAsync(string.IsNullOrEmpty(name) ? "event" : $"{name}.event", options.@event, cancellationToken).ConfigureAwait(false)); + } + return memberBuilder2 is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : memberBuilder2.Build(); + } + + async global::System.Threading.Tasks.Task Validate3Async() + { + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? memberBuilder3 = null; + if (options.@const is not null) + { + var count = 0; + foreach (var o in options.@const) + { + if (o is not null) + { + (memberBuilder3 ??= new()).AddResult(await global::KeywordNames.__classAsyncValidator__.ValidateAsync(string.IsNullOrEmpty(name) ? $"const[{count}]" : $"{name}.const[{count}]", o, cancellationToken).ConfigureAwait(false)); + } + else + { + (memberBuilder3 ??= new()).AddError(string.IsNullOrEmpty(name) ? $"const[{count}] is null" : $"{name}.const[{count}] is null"); + } + count++; + } + } + return memberBuilder3 is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : memberBuilder3.Build(); + } + + var memberTask0 = Validate0Async(); + var memberTask1 = Validate1Async(); + var memberTask2 = Validate2Async(); + var memberTask3 = Validate3Async(); + var memberResults = await global::System.Threading.Tasks.Task.WhenAll(memberTask0, memberTask1, memberTask2, memberTask3).ConfigureAwait(false); + + if (memberResults[0].Failed) + { + (builder ??= new()).AddResult(memberResults[0]); + } + if (memberResults[1].Failed) + { + (builder ??= new()).AddResult(memberResults[1]); + } + if (memberResults[2].Failed) + { + (builder ??= new()).AddResult(memberResults[2]); + } + if (memberResults[3].Failed) + { + (builder ??= new()).AddResult(memberResults[3]); + } + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); + } } } namespace KeywordNamesNested diff --git a/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Generated/KeywordNamesTests.cs b/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Generated/KeywordNamesTests.cs index 71580f249b1e..659b942bfb08 100644 --- a/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Generated/KeywordNamesTests.cs +++ b/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Generated/KeywordNamesTests.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.Threading.Tasks; using KeywordNames; using Microsoft.Extensions.Options; using Xunit; @@ -42,6 +43,38 @@ public void Valid() Assert.Equal(ValidateOptionsResult.Success, validator.Validate("KeywordNames", model)); } + [Fact] + public async Task InvalidAsync() + { + var model = new FirstModel + { + @namespace = "XXX", + @if = "YYY", + @event = new @class(), + @const = new List<@class> { new @class { @string = "XXX" } }, + }; + + var validator = new FirstValidator(); + var vr = await validator.ValidateAsync("KeywordNames", model, default); + + Utils.VerifyValidateOptionsResult(vr, 4, "namespace", "if", "event", "const"); + } + + [Fact] + public async Task ValidAsync() + { + var model = new FirstModel + { + @namespace = "ABCDE", + @if = "ABCDE", + @event = new @class { @string = "ABCDE" }, + @const = new List<@class> { new @class { @string = "ABCDE" } }, + }; + + var validator = new FirstValidator(); + Assert.Equal(ValidateOptionsResult.Success, await validator.ValidateAsync("KeywordNames", model, default)); + } + [Fact] public void KeywordValidatorTypeInvalid() { diff --git a/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Resources/Strings.resx b/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Resources/Strings.resx index 19dc7159a40c..4260ea9ab788 100644 --- a/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Resources/Strings.resx +++ b/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Resources/Strings.resx @@ -189,6 +189,12 @@ Type {0} already implements the Validate method. + + A type already includes an implementation of the 'ValidateAsync' method. + + + Type {0} already implements the ValidateAsync method. + 'OptionsValidatorAttribute' can't be applied to a static class. diff --git a/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/TestClasses/KeywordNames.cs b/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/TestClasses/KeywordNames.cs index 163ac47722b8..8d059e9c2a17 100644 --- a/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/TestClasses/KeywordNames.cs +++ b/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/TestClasses/KeywordNames.cs @@ -34,7 +34,7 @@ public class FirstModel } [OptionsValidator] - public partial class FirstValidator : IValidateOptions + public partial class FirstValidator : IAsyncValidateOptions { } } diff --git a/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/TestClasses/SelfValidation.cs b/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/TestClasses/SelfValidation.cs index 30351aa893f5..c736e161ee94 100644 --- a/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/TestClasses/SelfValidation.cs +++ b/src/runtime/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/TestClasses/SelfValidation.cs @@ -4,6 +4,8 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.Threading; +using System.Threading.Tasks; using Microsoft.Extensions.Options; namespace SelfValidation @@ -61,4 +63,30 @@ public IEnumerable Validate(ValidationContext context) return new[] { new ValidationResult($"Display: {context.DisplayName}, Member: {context.MemberName}") }; } } + +#if NET + public sealed class AsyncSelfValidatingModel : IAsyncValidatableObject + { + [Required] + public string? Name { get; set; } + + public async IAsyncEnumerable ValidateAsync( + ValidationContext validationContext, + [global::System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default) + { + await Task.Yield(); + yield break; + } + + public IEnumerable Validate(ValidationContext validationContext) + { + yield break; + } + } + + [OptionsValidator] + public partial class AsyncSelfValidatingValidator : IAsyncValidateOptions + { + } +#endif // NET } diff --git a/src/runtime/src/libraries/Microsoft.XmlSerializer.Generator/tests/Expected.SerializableAssembly.XmlSerializers.cs b/src/runtime/src/libraries/Microsoft.XmlSerializer.Generator/tests/Expected.SerializableAssembly.XmlSerializers.cs index 0aef341fce44..898403fa7b81 100644 --- a/src/runtime/src/libraries/Microsoft.XmlSerializer.Generator/tests/Expected.SerializableAssembly.XmlSerializers.cs +++ b/src/runtime/src/libraries/Microsoft.XmlSerializer.Generator/tests/Expected.SerializableAssembly.XmlSerializers.cs @@ -5549,7 +5549,7 @@ public object Read148_DogBreed() { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id18_DogBreed && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -5856,15 +5856,15 @@ public object Read164_ArrayOfDateTime() { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id36_ArrayOfDateTime && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { if ((object)(o) == null) o = new global::MyCollection1(); global::MyCollection1 a_0_0 = (global::MyCollection1)o; if ((Reader.IsEmptyElement)) { @@ -5877,7 +5877,7 @@ public object Read164_ArrayOfDateTime() { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id37_dateTime && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -6372,15 +6372,15 @@ public object Read190_ArrayOfAnyType() { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id64_ArrayOfAnyType && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { if ((object)(o) == null) o = new global::SerializationTypes.MyList(); global::SerializationTypes.MyList a_0_0 = (global::SerializationTypes.MyList)o; if ((Reader.IsEmptyElement)) { @@ -6428,7 +6428,7 @@ public object Read191_MyEnum() { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id66_MyEnum && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -6762,7 +6762,7 @@ public object Read209_EnumFlags() { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id85_EnumFlags && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -6880,7 +6880,7 @@ public object Read215_ByteEnum() { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id91_ByteEnum && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -6908,7 +6908,7 @@ public object Read216_SByteEnum() { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id92_SByteEnum && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -6936,7 +6936,7 @@ public object Read217_ShortEnum() { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id93_ShortEnum && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -6964,7 +6964,7 @@ public object Read218_IntEnum() { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id94_IntEnum && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -6992,7 +6992,7 @@ public object Read219_UIntEnum() { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id95_UIntEnum && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -7020,7 +7020,7 @@ public object Read220_LongEnum() { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id96_LongEnum && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -7048,7 +7048,7 @@ public object Read221_ULongEnum() { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id97_ULongEnum && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -7094,7 +7094,7 @@ public object Read223_ItemChoiceType() { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id99_ItemChoiceType && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -7638,7 +7638,7 @@ public object Read253_MoreChoices() { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id128_MoreChoices && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -7835,7 +7835,7 @@ public object Read261_Person() { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id137_FirstName && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -7850,7 +7850,7 @@ public object Read261_Person() { break; } if (!paramsRead[1] && ((object) Reader.LocalName == (object)id138_MiddleName && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -7865,7 +7865,7 @@ public object Read261_Person() { break; } if (!paramsRead[2] && ((object) Reader.LocalName == (object)id139_LastName && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -7922,7 +7922,7 @@ public object Read261_Person() { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id140_Name && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -7979,7 +7979,7 @@ public object Read261_Person() { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id140_Name && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -8358,15 +8358,15 @@ public object Read261_Person() { } if (((object) ((System.Xml.XmlQualifiedName)xsiType).Name == (object)id150_ArrayOfOrderedItem && (object) ((System.Xml.XmlQualifiedName)xsiType).Namespace == (object)id30_httpwwwcontoso1com)) { global::OrderedItem[] a = null; - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { global::OrderedItem[] z_0_0 = null; int cz_0_0 = 0; if ((Reader.IsEmptyElement)) { @@ -8398,15 +8398,15 @@ public object Read261_Person() { } if (((object) ((System.Xml.XmlQualifiedName)xsiType).Name == (object)id151_ArrayOfInt && (object) ((System.Xml.XmlQualifiedName)xsiType).Namespace == (object)id2_Item)) { global::System.Collections.Generic.List a = null; - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { if ((object)(a) == null) a = new global::System.Collections.Generic.List(); global::System.Collections.Generic.List z_0_0 = (global::System.Collections.Generic.List)a; if ((Reader.IsEmptyElement)) { @@ -8419,7 +8419,7 @@ public object Read261_Person() { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id152_int && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -8447,15 +8447,15 @@ public object Read261_Person() { } if (((object) ((System.Xml.XmlQualifiedName)xsiType).Name == (object)id153_ArrayOfString && (object) ((System.Xml.XmlQualifiedName)xsiType).Namespace == (object)id2_Item)) { global::System.Collections.Generic.List a = null; - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { if ((object)(a) == null) a = new global::System.Collections.Generic.List(); global::System.Collections.Generic.List z_0_0 = (global::System.Collections.Generic.List)a; if ((Reader.IsEmptyElement)) { @@ -8468,19 +8468,21 @@ public object Read261_Person() { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id154_string && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); - } - } - Reader.MoveToElement(); - } if (ReadNull()) { z_0_0.Add(null); } else { - z_0_0.Add(Reader.ReadElementString()); + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } + } + Reader.MoveToElement(); + } + { + z_0_0.Add(Reader.ReadElementString()); + } } break; } @@ -8499,15 +8501,15 @@ public object Read261_Person() { } if (((object) ((System.Xml.XmlQualifiedName)xsiType).Name == (object)id155_ArrayOfDouble && (object) ((System.Xml.XmlQualifiedName)xsiType).Namespace == (object)id2_Item)) { global::System.Collections.Generic.List a = null; - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { if ((object)(a) == null) a = new global::System.Collections.Generic.List(); global::System.Collections.Generic.List z_0_0 = (global::System.Collections.Generic.List)a; if ((Reader.IsEmptyElement)) { @@ -8520,7 +8522,7 @@ public object Read261_Person() { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id156_double && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -8548,15 +8550,15 @@ public object Read261_Person() { } if (((object) ((System.Xml.XmlQualifiedName)xsiType).Name == (object)id36_ArrayOfDateTime && (object) ((System.Xml.XmlQualifiedName)xsiType).Namespace == (object)id2_Item)) { global::MyCollection1 a = null; - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { if ((object)(a) == null) a = new global::MyCollection1(); global::MyCollection1 z_0_0 = (global::MyCollection1)a; if ((Reader.IsEmptyElement)) { @@ -8569,7 +8571,7 @@ public object Read261_Person() { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id37_dateTime && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -8597,15 +8599,15 @@ public object Read261_Person() { } if (((object) ((System.Xml.XmlQualifiedName)xsiType).Name == (object)id157_ArrayOfInstrument && (object) ((System.Xml.XmlQualifiedName)xsiType).Namespace == (object)id2_Item)) { global::Instrument[] a = null; - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { global::Instrument[] z_0_0 = null; int cz_0_0 = 0; if ((Reader.IsEmptyElement)) { @@ -8637,15 +8639,15 @@ public object Read261_Person() { } if (((object) ((System.Xml.XmlQualifiedName)xsiType).Name == (object)id158_ArrayOfTypeWithLinkedProperty && (object) ((System.Xml.XmlQualifiedName)xsiType).Namespace == (object)id2_Item)) { global::System.Collections.Generic.List a = null; - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { if ((object)(a) == null) a = new global::System.Collections.Generic.List(); global::System.Collections.Generic.List z_0_0 = (global::System.Collections.Generic.List)a; if ((Reader.IsEmptyElement)) { @@ -8676,15 +8678,15 @@ public object Read261_Person() { } if (((object) ((System.Xml.XmlQualifiedName)xsiType).Name == (object)id159_ArrayOfParameter && (object) ((System.Xml.XmlQualifiedName)xsiType).Namespace == (object)id2_Item)) { global::System.Collections.Generic.List a = null; - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { if ((object)(a) == null) a = new global::System.Collections.Generic.List(); global::System.Collections.Generic.List z_0_0 = (global::System.Collections.Generic.List)a; if ((Reader.IsEmptyElement)) { @@ -8715,15 +8717,15 @@ public object Read261_Person() { } if (((object) ((System.Xml.XmlQualifiedName)xsiType).Name == (object)id160_ArrayOfXElement && (object) ((System.Xml.XmlQualifiedName)xsiType).Namespace == (object)id2_Item)) { global::System.Xml.Linq.XElement[] a = null; - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { global::System.Xml.Linq.XElement[] z_0_0 = null; int cz_0_0 = 0; if ((Reader.IsEmptyElement)) { @@ -8756,15 +8758,15 @@ public object Read261_Person() { } if (((object) ((System.Xml.XmlQualifiedName)xsiType).Name == (object)id162_ArrayOfSimpleType && (object) ((System.Xml.XmlQualifiedName)xsiType).Namespace == (object)id2_Item)) { global::SerializationTypes.SimpleType[] a = null; - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { global::SerializationTypes.SimpleType[] z_0_0 = null; int cz_0_0 = 0; if ((Reader.IsEmptyElement)) { @@ -8796,15 +8798,15 @@ public object Read261_Person() { } if (((object) ((System.Xml.XmlQualifiedName)xsiType).Name == (object)id64_ArrayOfAnyType && (object) ((System.Xml.XmlQualifiedName)xsiType).Namespace == (object)id2_Item)) { global::SerializationTypes.MyList a = null; - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { if ((object)(a) == null) a = new global::SerializationTypes.MyList(); global::SerializationTypes.MyList z_0_0 = (global::SerializationTypes.MyList)a; if ((Reader.IsEmptyElement)) { @@ -8841,15 +8843,15 @@ public object Read261_Person() { } if (((object) ((System.Xml.XmlQualifiedName)xsiType).Name == (object)id163_ArrayOfTypeA && (object) ((System.Xml.XmlQualifiedName)xsiType).Namespace == (object)id2_Item)) { global::SerializationTypes.TypeA[] a = null; - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { global::SerializationTypes.TypeA[] z_0_0 = null; int cz_0_0 = 0; if ((Reader.IsEmptyElement)) { @@ -8935,15 +8937,15 @@ public object Read261_Person() { } if (((object) ((System.Xml.XmlQualifiedName)xsiType).Name == (object)id164_ArrayOfItemChoiceType && (object) ((System.Xml.XmlQualifiedName)xsiType).Namespace == (object)id2_Item)) { global::SerializationTypes.ItemChoiceType[] a = null; - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { global::SerializationTypes.ItemChoiceType[] z_0_0 = null; int cz_0_0 = 0; if ((Reader.IsEmptyElement)) { @@ -8956,7 +8958,7 @@ public object Read261_Person() { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id99_ItemChoiceType && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -8985,15 +8987,15 @@ public object Read261_Person() { } if (((object) ((System.Xml.XmlQualifiedName)xsiType).Name == (object)id153_ArrayOfString && (object) ((System.Xml.XmlQualifiedName)xsiType).Namespace == (object)id165_httpmynamespace)) { global::System.Object[] a = null; - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { global::System.Object[] z_0_0 = null; int cz_0_0 = 0; if ((Reader.IsEmptyElement)) { @@ -9006,19 +9008,21 @@ public object Read261_Person() { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id154_string && (object) Reader.NamespaceURI == (object)id165_httpmynamespace)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); - } - } - Reader.MoveToElement(); - } if (ReadNull()) { z_0_0 = (global::System.Object[])EnsureArrayIndex(z_0_0, cz_0_0, typeof(global::System.Object));z_0_0[cz_0_0++] = null; } else { - z_0_0 = (global::System.Object[])EnsureArrayIndex(z_0_0, cz_0_0, typeof(global::System.Object));z_0_0[cz_0_0++] = Reader.ReadElementString(); + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } + } + Reader.MoveToElement(); + } + { + z_0_0 = (global::System.Object[])EnsureArrayIndex(z_0_0, cz_0_0, typeof(global::System.Object));z_0_0[cz_0_0++] = Reader.ReadElementString(); + } } break; } @@ -9038,15 +9042,15 @@ public object Read261_Person() { } if (((object) ((System.Xml.XmlQualifiedName)xsiType).Name == (object)id166_ArrayOfString1 && (object) ((System.Xml.XmlQualifiedName)xsiType).Namespace == (object)id2_Item)) { global::System.Collections.Generic.List a = null; - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { if ((object)(a) == null) a = new global::System.Collections.Generic.List(); global::System.Collections.Generic.List z_0_0 = (global::System.Collections.Generic.List)a; if ((Reader.IsEmptyElement)) { @@ -9059,7 +9063,7 @@ public object Read261_Person() { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id167_NoneParameter && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -9087,15 +9091,15 @@ public object Read261_Person() { } if (((object) ((System.Xml.XmlQualifiedName)xsiType).Name == (object)id168_ArrayOfBoolean && (object) ((System.Xml.XmlQualifiedName)xsiType).Namespace == (object)id2_Item)) { global::System.Collections.Generic.List a = null; - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { if ((object)(a) == null) a = new global::System.Collections.Generic.List(); global::System.Collections.Generic.List z_0_0 = (global::System.Collections.Generic.List)a; if ((Reader.IsEmptyElement)) { @@ -9108,7 +9112,7 @@ public object Read261_Person() { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id169_QualifiedParameter && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -9136,15 +9140,15 @@ public object Read261_Person() { } if (((object) ((System.Xml.XmlQualifiedName)xsiType).Name == (object)id170_ArrayOfArrayOfSimpleType && (object) ((System.Xml.XmlQualifiedName)xsiType).Namespace == (object)id2_Item)) { global::SerializationTypes.SimpleType[][] a = null; - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); - } - } - Reader.MoveToElement(); - } if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } + } + Reader.MoveToElement(); + } global::SerializationTypes.SimpleType[][] z_0_0 = null; int cz_0_0 = 0; if ((Reader.IsEmptyElement)) { @@ -9157,15 +9161,15 @@ public object Read261_Person() { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id57_SimpleType && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { global::SerializationTypes.SimpleType[] z_0_0_0 = null; int cz_0_0_0 = 0; if ((Reader.IsEmptyElement)) { @@ -9287,7 +9291,7 @@ public object Read261_Person() { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id171_P1 && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -9302,7 +9306,7 @@ public object Read261_Person() { break; } if (!paramsRead[1] && ((object) Reader.LocalName == (object)id172_P2 && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -9452,7 +9456,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id140_Name && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -9568,7 +9572,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[1] && ((object) Reader.LocalName == (object)id173_Value && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -9632,15 +9636,15 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (((object) Reader.LocalName == (object)id175_Children && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { if ((object)(o.@Children) == null) o.@Children = new global::System.Collections.Generic.List(); global::System.Collections.Generic.List a_1_0 = (global::System.Collections.Generic.List)o.@Children; if ((Reader.IsEmptyElement)) { @@ -9716,7 +9720,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id140_Name && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -9773,7 +9777,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id140_Name && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -9788,7 +9792,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[1] && ((object) Reader.LocalName == (object)id176_IsValved && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -9803,7 +9807,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[2] && ((object) Reader.LocalName == (object)id177_Modulation && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -9862,7 +9866,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id140_Name && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -9877,7 +9881,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[1] && ((object) Reader.LocalName == (object)id176_IsValved && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -9934,7 +9938,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id178_ItemName && (object) Reader.NamespaceURI == (object)id30_httpwwwcontoso1com)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -9949,7 +9953,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[1] && ((object) Reader.LocalName == (object)id179_Description && (object) Reader.NamespaceURI == (object)id30_httpwwwcontoso1com)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -9964,7 +9968,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[2] && ((object) Reader.LocalName == (object)id180_UnitPrice && (object) Reader.NamespaceURI == (object)id30_httpwwwcontoso1com)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -9979,7 +9983,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[3] && ((object) Reader.LocalName == (object)id181_Quantity && (object) Reader.NamespaceURI == (object)id30_httpwwwcontoso1com)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -9994,7 +9998,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[4] && ((object) Reader.LocalName == (object)id182_LineTotal && (object) Reader.NamespaceURI == (object)id30_httpwwwcontoso1com)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -10150,7 +10154,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id183_BinaryHexContent && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -10165,7 +10169,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[1] && ((object) Reader.LocalName == (object)id184_Base64Content && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -10222,7 +10226,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id185_DTO && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -10243,7 +10247,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[1] && ((object) Reader.LocalName == (object)id186_DTO2 && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -10264,7 +10268,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[2] && ((object) Reader.LocalName == (object)id187_DefaultDTO && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -10313,7 +10317,7 @@ internal System.Collections.Hashtable EnumFlagsValues { global::System.Nullable o = default(global::System.Nullable); if (ReadNull()) return o; - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -10364,7 +10368,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id190_Today && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -10385,7 +10389,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[1] && ((object) Reader.LocalName == (object)id191_MyDate && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -10406,7 +10410,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[2] && ((object) Reader.LocalName == (object)id192_DefaultDate && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -10445,7 +10449,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[6] && ((object) Reader.LocalName == (object)id196_Now && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -10466,7 +10470,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[7] && ((object) Reader.LocalName == (object)id197_MyTime && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -10487,7 +10491,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[8] && ((object) Reader.LocalName == (object)id198_DefaultTime && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -10541,7 +10545,7 @@ internal System.Collections.Hashtable EnumFlagsValues { global::System.Nullable o = default(global::System.Nullable); if (ReadNull()) return o; - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -10565,7 +10569,7 @@ internal System.Collections.Hashtable EnumFlagsValues { global::System.Nullable o = default(global::System.Nullable); if (ReadNull()) return o; - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -10616,7 +10620,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id202_TestValue && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -10679,7 +10683,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id202_TestValue && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -10742,7 +10746,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id202_TestValue && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -10805,7 +10809,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id202_TestValue && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -10862,7 +10866,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id202_TestValue && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -10919,7 +10923,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id203_TimeSpanProperty && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -10982,7 +10986,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id203_TimeSpanProperty && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -11006,7 +11010,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[1] && ((object) Reader.LocalName == (object)id204_TimeSpanProperty2 && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -11072,7 +11076,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id205_ByteProperty && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -11180,7 +11184,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id206_Age && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -11195,7 +11199,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[1] && ((object) Reader.LocalName == (object)id140_Name && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -11210,7 +11214,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[2] && ((object) Reader.LocalName == (object)id207_Breed && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -11269,7 +11273,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id206_Age && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -11284,7 +11288,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[1] && ((object) Reader.LocalName == (object)id140_Name && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -11341,7 +11345,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id208_LicenseNumber && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -11398,7 +11402,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id209_GroupName && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -11460,7 +11464,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id211_EmployeeName && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -11517,7 +11521,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id173_Value && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -11532,7 +11536,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[1] && ((object) Reader.LocalName == (object)id212_value && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -11591,7 +11595,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id173_Value && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -11606,7 +11610,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[1] && ((object) Reader.LocalName == (object)id212_value && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -11769,7 +11773,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[1] && ((object) Reader.LocalName == (object)id216_Line1 && (object) Reader.NamespaceURI == (object)id30_httpwwwcontoso1com)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -11784,7 +11788,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[2] && ((object) Reader.LocalName == (object)id217_City && (object) Reader.NamespaceURI == (object)id30_httpwwwcontoso1com)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -11799,7 +11803,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[3] && ((object) Reader.LocalName == (object)id218_State && (object) Reader.NamespaceURI == (object)id30_httpwwwcontoso1com)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -11814,7 +11818,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[4] && ((object) Reader.LocalName == (object)id219_Zip && (object) Reader.NamespaceURI == (object)id30_httpwwwcontoso1com)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -11878,7 +11882,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[1] && ((object) Reader.LocalName == (object)id221_OrderDate && (object) Reader.NamespaceURI == (object)id30_httpwwwcontoso1com)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -11893,15 +11897,15 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (((object) Reader.LocalName == (object)id222_Items && (object) Reader.NamespaceURI == (object)id30_httpwwwcontoso1com)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { global::OrderedItem[] a_2_0 = null; int ca_2_0 = 0; if ((Reader.IsEmptyElement)) { @@ -11932,7 +11936,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[3] && ((object) Reader.LocalName == (object)id223_SubTotal && (object) Reader.NamespaceURI == (object)id30_httpwwwcontoso1com)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -11947,7 +11951,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[4] && ((object) Reader.LocalName == (object)id224_ShipCost && (object) Reader.NamespaceURI == (object)id30_httpwwwcontoso1com)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -11962,7 +11966,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[5] && ((object) Reader.LocalName == (object)id225_TotalCost && (object) Reader.NamespaceURI == (object)id30_httpwwwcontoso1com)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -12023,7 +12027,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[1] && ((object) Reader.LocalName == (object)id216_Line1 && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -12038,7 +12042,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[2] && ((object) Reader.LocalName == (object)id217_City && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -12053,7 +12057,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[3] && ((object) Reader.LocalName == (object)id218_State && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -12068,7 +12072,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[4] && ((object) Reader.LocalName == (object)id219_Zip && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -12125,7 +12129,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id178_ItemName && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -12140,7 +12144,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[1] && ((object) Reader.LocalName == (object)id179_Description && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -12155,7 +12159,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[2] && ((object) Reader.LocalName == (object)id180_UnitPrice && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -12170,7 +12174,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[3] && ((object) Reader.LocalName == (object)id181_Quantity && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -12185,7 +12189,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[4] && ((object) Reader.LocalName == (object)id182_LineTotal && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -12242,15 +12246,15 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id226_X && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { if ((object)(o.@Aliased) == null) o.@Aliased = new global::System.Collections.Generic.List(); global::System.Collections.Generic.List a_0_0 = (global::System.Collections.Generic.List)o.@Aliased; if ((Reader.IsEmptyElement)) { @@ -12263,7 +12267,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id152_int && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -12291,15 +12295,15 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[0] && ((object) Reader.LocalName == (object)id227_Y && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { if ((object)(o.@Aliased) == null) o.@Aliased = new global::System.Collections.Generic.List(); global::System.Collections.Generic.List a_0_0 = (global::System.Collections.Generic.List)o.@Aliased; if ((Reader.IsEmptyElement)) { @@ -12312,19 +12316,21 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id154_string && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); - } - } - Reader.MoveToElement(); - } if (ReadNull()) { a_0_0.Add(null); } else { - a_0_0.Add(Reader.ReadElementString()); + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } + } + Reader.MoveToElement(); + } + { + a_0_0.Add(Reader.ReadElementString()); + } } break; } @@ -12343,15 +12349,15 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[0] && ((object) Reader.LocalName == (object)id228_Z && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { if ((object)(o.@Aliased) == null) o.@Aliased = new global::System.Collections.Generic.List(); global::System.Collections.Generic.List a_0_0 = (global::System.Collections.Generic.List)o.@Aliased; if ((Reader.IsEmptyElement)) { @@ -12364,7 +12370,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id156_double && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -12436,7 +12442,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id229_Prop && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -12496,7 +12502,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id229_Prop && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -12554,15 +12560,15 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id230_Instruments && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { global::Instrument[] a_0_0 = null; int ca_0_0 = 0; if ((Reader.IsEmptyElement)) { @@ -12635,7 +12641,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id16_Animal && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -12650,7 +12656,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[1] && ((object) Reader.LocalName == (object)id231_Comment2 && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -12707,7 +12713,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id232_DoubleField && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -12725,7 +12731,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[1] && ((object) Reader.LocalName == (object)id233_SingleField && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -12743,7 +12749,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[2] && ((object) Reader.LocalName == (object)id234_DoubleProp && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -12761,7 +12767,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[3] && ((object) Reader.LocalName == (object)id235_FloatProp && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -12821,7 +12827,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id232_DoubleField && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -12839,7 +12845,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[1] && ((object) Reader.LocalName == (object)id233_SingleField && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -12857,7 +12863,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[2] && ((object) Reader.LocalName == (object)id234_DoubleProp && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -12875,7 +12881,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[3] && ((object) Reader.LocalName == (object)id235_FloatProp && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -12935,7 +12941,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id232_DoubleField && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -12953,7 +12959,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[1] && ((object) Reader.LocalName == (object)id233_SingleField && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -12971,7 +12977,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[2] && ((object) Reader.LocalName == (object)id234_DoubleProp && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -12989,7 +12995,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[3] && ((object) Reader.LocalName == (object)id235_FloatProp && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -13150,15 +13156,15 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id239_Parameters && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { if ((object)(o.@Parameters) == null) o.@Parameters = new global::System.Collections.Generic.List(); global::System.Collections.Generic.List a_0_0 = (global::System.Collections.Generic.List)o.@Parameters; if ((Reader.IsEmptyElement)) { @@ -13334,15 +13340,15 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id241_xelements && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { global::System.Xml.Linq.XElement[] a_0_0 = null; int ca_0_0 = 0; if ((Reader.IsEmptyElement)) { @@ -13416,7 +13422,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id242_DateTimeString && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -13431,7 +13437,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[1] && ((object) Reader.LocalName == (object)id243_CurrentDateTime && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -13496,15 +13502,15 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id244_F1 && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { global::SerializationTypes.SimpleType[] a_0_0 = null; int ca_0_0 = 0; if ((Reader.IsEmptyElement)) { @@ -13535,15 +13541,15 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (((object) Reader.LocalName == (object)id245_F2 && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { global::System.Int32[] a_1_0 = null; int ca_1_0 = 0; if ((Reader.IsEmptyElement)) { @@ -13556,7 +13562,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id152_int && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -13584,15 +13590,15 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (((object) Reader.LocalName == (object)id171_P1 && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { global::SerializationTypes.SimpleType[] a_2_0 = null; int ca_2_0 = 0; if ((Reader.IsEmptyElement)) { @@ -13623,15 +13629,15 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (((object) Reader.LocalName == (object)id172_P2 && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { global::System.Int32[] a_3_0 = null; int ca_3_0 = 0; if ((Reader.IsEmptyElement)) { @@ -13644,7 +13650,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id152_int && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -13770,15 +13776,15 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id246_IntAField && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { global::System.Int32[] a_0_0 = null; int ca_0_0 = 0; if ((Reader.IsEmptyElement)) { @@ -13791,7 +13797,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id152_int && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -13819,15 +13825,15 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (((object) Reader.LocalName == (object)id247_NIntAField && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { global::System.Int32[] a_1_0 = null; int ca_1_0 = 0; if ((Reader.IsEmptyElement)) { @@ -13840,7 +13846,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id152_int && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -13868,15 +13874,15 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (((object) Reader.LocalName == (object)id248_IntLField && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { if ((object)(o.@IntLField) == null) o.@IntLField = new global::System.Collections.Generic.List(); global::System.Collections.Generic.List a_2_0 = (global::System.Collections.Generic.List)o.@IntLField; if ((Reader.IsEmptyElement)) { @@ -13889,7 +13895,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id152_int && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -13916,15 +13922,15 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (((object) Reader.LocalName == (object)id249_NIntLField && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { if ((object)(o.@NIntLField) == null) o.@NIntLField = new global::System.Collections.Generic.List(); global::System.Collections.Generic.List a_3_0 = (global::System.Collections.Generic.List)o.@NIntLField; if ((Reader.IsEmptyElement)) { @@ -13937,7 +13943,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id152_int && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -13968,15 +13974,15 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (((object) Reader.LocalName == (object)id250_IntAProp && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { global::System.Int32[] a_4_0 = null; int ca_4_0 = 0; if ((Reader.IsEmptyElement)) { @@ -13989,7 +13995,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id152_int && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -14017,15 +14023,15 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (((object) Reader.LocalName == (object)id251_NIntAProp && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { global::System.Int32[] a_5_0 = null; int ca_5_0 = 0; if ((Reader.IsEmptyElement)) { @@ -14038,7 +14044,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id152_int && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -14071,15 +14077,15 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (((object) Reader.LocalName == (object)id252_IntLProp && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { if ((object)(o.@IntLProp) == null) o.@IntLProp = new global::System.Collections.Generic.List(); global::System.Collections.Generic.List a_6_0 = (global::System.Collections.Generic.List)o.@IntLProp; if ((Reader.IsEmptyElement)) { @@ -14092,7 +14098,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id152_int && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -14119,15 +14125,15 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (((object) Reader.LocalName == (object)id253_NIntLProp && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { if ((object)(o.@NIntLProp) == null) o.@NIntLProp = new global::System.Collections.Generic.List(); global::System.Collections.Generic.List a_7_0 = (global::System.Collections.Generic.List)o.@NIntLProp; if ((Reader.IsEmptyElement)) { @@ -14140,7 +14146,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id152_int && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -14215,7 +14221,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id212_value && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -14274,15 +14280,15 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id254_Collection && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { if ((object)(o.@Collection) == null) o.@Collection = new global::SerializationTypes.MyCollection(); global::SerializationTypes.MyCollection a_0_0 = (global::SerializationTypes.MyCollection)o.@Collection; if ((Reader.IsEmptyElement)) { @@ -14295,19 +14301,21 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id154_string && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); - } - } - Reader.MoveToElement(); - } if (ReadNull()) { a_0_0.Add(null); } else { - a_0_0.Add(Reader.ReadElementString()); + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } + } + Reader.MoveToElement(); + } + { + a_0_0.Add(Reader.ReadElementString()); + } } break; } @@ -14368,15 +14376,15 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id254_Collection && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { global::SerializationTypes.MyCollection a_0_0 = (global::SerializationTypes.MyCollection)o.@Collection; if (((object)(a_0_0) == null) || (Reader.IsEmptyElement)) { Reader.Skip(); @@ -14388,19 +14396,21 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id154_string && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); - } - } - Reader.MoveToElement(); - } if (ReadNull()) { a_0_0.Add(null); } else { - a_0_0.Add(Reader.ReadElementString()); + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } + } + Reader.MoveToElement(); + } + { + a_0_0.Add(Reader.ReadElementString()); + } } break; } @@ -14460,7 +14470,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id244_F1 && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -14475,7 +14485,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[1] && ((object) Reader.LocalName == (object)id171_P1 && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -14538,7 +14548,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id255_Data && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -14600,7 +14610,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[1] && ((object) Reader.LocalName == (object)id257_MyEnum1 && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -14657,7 +14667,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id258_ByteArray && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -14718,7 +14728,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id259_StringMember && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -14733,7 +14743,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[1] && ((object) Reader.LocalName == (object)id260_IntMember && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -14753,15 +14763,15 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (((object) Reader.LocalName == (object)id262_ListMember && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { if ((object)(o.@ListMember) == null) o.@ListMember = new global::System.Collections.Generic.List(); global::System.Collections.Generic.List a_3_0 = (global::System.Collections.Generic.List)o.@ListMember; if ((Reader.IsEmptyElement)) { @@ -14774,19 +14784,21 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id154_string && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); - } - } - Reader.MoveToElement(); - } if (ReadNull()) { a_3_0.Add(null); } else { - a_3_0.Add(Reader.ReadElementString()); + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } + } + Reader.MoveToElement(); + } + { + a_3_0.Add(Reader.ReadElementString()); + } } break; } @@ -14804,15 +14816,15 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (((object) Reader.LocalName == (object)id263_ArrayMember && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { global::System.Int32[] a_4_0 = null; int ca_4_0 = 0; if ((Reader.IsEmptyElement)) { @@ -14825,7 +14837,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id152_int && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -14868,7 +14880,7 @@ internal System.Collections.Hashtable EnumFlagsValues { global::System.Nullable o = default(global::System.Nullable); if (ReadNull()) return o; - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -14917,19 +14929,21 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id259_StringMember && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); - } - } - Reader.MoveToElement(); - } if (ReadNull()) { o.@StringMember = null; } else { - o.@StringMember = Reader.ReadElementString(); + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } + } + Reader.MoveToElement(); + } + { + o.@StringMember = Reader.ReadElementString(); + } } paramsRead[0] = true; break; @@ -14940,15 +14954,15 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (((object) Reader.LocalName == (object)id263_ArrayMember && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { global::System.Int32[] a_2_0 = null; int ca_2_0 = 0; if ((Reader.IsEmptyElement)) { @@ -14961,7 +14975,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id152_int && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -14989,15 +15003,15 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (((object) Reader.LocalName == (object)id262_ListMember && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { if ((object)(o.@ListMember) == null) o.@ListMember = new global::System.Collections.Generic.List(); global::System.Collections.Generic.List a_3_0 = (global::System.Collections.Generic.List)o.@ListMember; if ((Reader.IsEmptyElement)) { @@ -15010,19 +15024,21 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id154_string && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); - } - } - Reader.MoveToElement(); - } if (ReadNull()) { a_3_0.Add(null); } else { - a_3_0.Add(Reader.ReadElementString()); + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } + } + Reader.MoveToElement(); + } + { + a_3_0.Add(Reader.ReadElementString()); + } } break; } @@ -15082,7 +15098,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id140_Name && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -15141,15 +15157,15 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id222_Items && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { global::SerializationTypes.TypeA[] a_0_0 = null; int ca_0_0 = 0; if ((Reader.IsEmptyElement)) { @@ -15222,7 +15238,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id264_Item && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -15281,7 +15297,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id265_StringProperty && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -15296,7 +15312,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[1] && ((object) Reader.LocalName == (object)id266_IntProperty && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -15311,7 +15327,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[2] && ((object) Reader.LocalName == (object)id267_DateTimeProperty && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -15326,15 +15342,15 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (((object) Reader.LocalName == (object)id268_ListProperty && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { if ((object)(o.@ListProperty) == null) o.@ListProperty = new global::System.Collections.Generic.List(); global::System.Collections.Generic.List a_3_0 = (global::System.Collections.Generic.List)o.@ListProperty; if ((Reader.IsEmptyElement)) { @@ -15347,19 +15363,21 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id154_string && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); - } - } - Reader.MoveToElement(); - } if (ReadNull()) { a_3_0.Add(null); } else { - a_3_0.Add(Reader.ReadElementString()); + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } + } + Reader.MoveToElement(); + } + { + a_3_0.Add(Reader.ReadElementString()); + } } break; } @@ -15423,7 +15441,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id265_StringProperty && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -15438,7 +15456,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[1] && ((object) Reader.LocalName == (object)id266_IntProperty && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -15453,7 +15471,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[2] && ((object) Reader.LocalName == (object)id267_DateTimeProperty && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -15468,15 +15486,15 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (((object) Reader.LocalName == (object)id268_ListProperty && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { if ((object)(o.@ListProperty) == null) o.@ListProperty = new global::System.Collections.Generic.List(); global::System.Collections.Generic.List a_3_0 = (global::System.Collections.Generic.List)o.@ListProperty; if ((Reader.IsEmptyElement)) { @@ -15489,19 +15507,21 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id154_string && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); - } - } - Reader.MoveToElement(); - } if (ReadNull()) { a_3_0.Add(null); } else { - a_3_0.Add(Reader.ReadElementString()); + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } + } + Reader.MoveToElement(); + } + { + a_3_0.Add(Reader.ReadElementString()); + } } break; } @@ -15567,7 +15587,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id265_StringProperty && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -15582,7 +15602,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[1] && ((object) Reader.LocalName == (object)id266_IntProperty && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -15597,7 +15617,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[2] && ((object) Reader.LocalName == (object)id267_DateTimeProperty && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -15612,15 +15632,15 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (((object) Reader.LocalName == (object)id268_ListProperty && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { if ((object)(o.@ListProperty) == null) o.@ListProperty = new global::System.Collections.Generic.List(); global::System.Collections.Generic.List a_3_0 = (global::System.Collections.Generic.List)o.@ListProperty; if ((Reader.IsEmptyElement)) { @@ -15633,19 +15653,21 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id154_string && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); - } - } - Reader.MoveToElement(); - } if (ReadNull()) { a_3_0.Add(null); } else { - a_3_0.Add(Reader.ReadElementString()); + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } + } + Reader.MoveToElement(); + } + { + a_3_0.Add(Reader.ReadElementString()); + } } break; } @@ -15799,7 +15821,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id255_Data && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -15911,7 +15933,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id269_ClassID && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -15926,7 +15948,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[1] && ((object) Reader.LocalName == (object)id270_DisplayName && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -15941,7 +15963,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[2] && ((object) Reader.LocalName == (object)id271_Id && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -15956,7 +15978,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[3] && ((object) Reader.LocalName == (object)id272_IsLoaded && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -16019,7 +16041,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id142_A && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -16034,7 +16056,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[1] && ((object) Reader.LocalName == (object)id143_B && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -16138,7 +16160,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id274_Int && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -16153,7 +16175,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[1] && ((object) Reader.LocalName == (object)id275_Short && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -16263,7 +16285,7 @@ internal System.Collections.Hashtable EnumFlagsValues { global::System.Nullable o = default(global::System.Nullable); if (ReadNull()) return o; - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -16317,7 +16339,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id283_Word && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -16333,7 +16355,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[0] && ((object) Reader.LocalName == (object)id284_Number && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -16349,7 +16371,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[0] && ((object) Reader.LocalName == (object)id285_DecimalNumber && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -16370,15 +16392,15 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (((object) Reader.LocalName == (object)id287_XmlEnumProperty && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { global::SerializationTypes.ItemChoiceType[] a_2_0 = null; int ca_2_0 = 0; if ((Reader.IsEmptyElement)) { @@ -16391,7 +16413,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id99_ItemChoiceType && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -16419,7 +16441,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[4] && ((object) Reader.LocalName == (object)id288_Item && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -16434,7 +16456,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[5] && ((object) Reader.LocalName == (object)id289_XmlElementPropertyNode && (object) Reader.NamespaceURI == (object)id290_httpelement)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -16449,15 +16471,15 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (((object) Reader.LocalName == (object)id291_CustomXmlArrayProperty && (object) Reader.NamespaceURI == (object)id165_httpmynamespace)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { global::System.Object[] a_7_0 = null; int ca_7_0 = 0; if ((Reader.IsEmptyElement)) { @@ -16470,19 +16492,21 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id154_string && (object) Reader.NamespaceURI == (object)id165_httpmynamespace)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); - } - } - Reader.MoveToElement(); - } if (ReadNull()) { a_7_0 = (global::System.Object[])EnsureArrayIndex(a_7_0, ca_7_0, typeof(global::System.Object));a_7_0[ca_7_0++] = null; } else { - a_7_0 = (global::System.Object[])EnsureArrayIndex(a_7_0, ca_7_0, typeof(global::System.Object));a_7_0[ca_7_0++] = Reader.ReadElementString(); + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } + } + Reader.MoveToElement(); + } + { + a_7_0 = (global::System.Object[])EnsureArrayIndex(a_7_0, ca_7_0, typeof(global::System.Object));a_7_0[ca_7_0++] = Reader.ReadElementString(); + } } break; } @@ -16560,7 +16584,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id140_Name && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -16670,7 +16694,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id294_StrProperty && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -16728,7 +16752,7 @@ internal System.Collections.Hashtable EnumFlagsValues { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id295_MyField && (object) Reader.NamespaceURI == (object)id2_Item)) { o.@MyFieldSpecified = true; - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -16744,7 +16768,7 @@ internal System.Collections.Hashtable EnumFlagsValues { } if (!paramsRead[1] && ((object) Reader.LocalName == (object)id296_MyFieldIgnored && (object) Reader.NamespaceURI == (object)id2_Item)) { o.@MyFieldIgnoredSpecified = true; - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -16807,15 +16831,15 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id297_Item && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { if ((object)(o.@UnqualifiedSchemaFormListProperty) == null) o.@UnqualifiedSchemaFormListProperty = new global::System.Collections.Generic.List(); global::System.Collections.Generic.List a_0_0 = (global::System.Collections.Generic.List)o.@UnqualifiedSchemaFormListProperty; if ((Reader.IsEmptyElement)) { @@ -16828,7 +16852,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id152_int && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -16855,15 +16879,15 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (((object) Reader.LocalName == (object)id298_NoneSchemaFormListProperty && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { if ((object)(o.@NoneSchemaFormListProperty) == null) o.@NoneSchemaFormListProperty = new global::System.Collections.Generic.List(); global::System.Collections.Generic.List a_1_0 = (global::System.Collections.Generic.List)o.@NoneSchemaFormListProperty; if ((Reader.IsEmptyElement)) { @@ -16876,7 +16900,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id167_NoneParameter && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -16903,15 +16927,15 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (((object) Reader.LocalName == (object)id299_Item && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { if ((object)(o.@QualifiedSchemaFormListProperty) == null) o.@QualifiedSchemaFormListProperty = new global::System.Collections.Generic.List(); global::System.Collections.Generic.List a_2_0 = (global::System.Collections.Generic.List)o.@QualifiedSchemaFormListProperty; if ((Reader.IsEmptyElement)) { @@ -16924,7 +16948,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id169_QualifiedParameter && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -17155,7 +17179,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id140_Name && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -17212,7 +17236,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id303_DS2Root && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -17227,7 +17251,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[1] && ((object) Reader.LocalName == (object)id304_MetricConfigUrl && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -17284,7 +17308,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id173_Value && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -17343,15 +17367,15 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id305_TwoDArrayOfSimpleType && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { global::SerializationTypes.SimpleType[][] a_0_0 = null; int ca_0_0 = 0; if ((Reader.IsEmptyElement)) { @@ -17364,15 +17388,15 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id57_SimpleType && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { - while (Reader.MoveToNextAttribute()) { - if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode(null); + if (!ReadNull()) { + if (Reader.HasAttributes) { + while (Reader.MoveToNextAttribute()) { + if (!IsXmlnsAttribute(Reader.Name)) { + UnknownNode(null); + } } + Reader.MoveToElement(); } - Reader.MoveToElement(); - } - if (!ReadNull()) { global::SerializationTypes.SimpleType[] a_0_0_0 = null; int ca_0_0_0 = 0; if ((Reader.IsEmptyElement)) { @@ -17459,7 +17483,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id306_EmptyStringProperty && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -17474,7 +17498,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[1] && ((object) Reader.LocalName == (object)id265_StringProperty && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -17489,7 +17513,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[2] && ((object) Reader.LocalName == (object)id266_IntProperty && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -17507,7 +17531,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[3] && ((object) Reader.LocalName == (object)id307_CharProperty && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -17567,7 +17591,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id308_EnumProperty && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -17627,7 +17651,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id308_EnumProperty && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -17687,7 +17711,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id309_Foo && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -17748,7 +17772,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id309_Foo && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -17811,7 +17835,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id309_Foo && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -17869,7 +17893,7 @@ internal System.Collections.Hashtable EnumFlagsValues { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id309_Foo && (object) Reader.NamespaceURI == (object)id2_Item)) { o.@FooSpecified = true; - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -18025,7 +18049,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id313_DateTimeContent && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -18040,7 +18064,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[1] && ((object) Reader.LocalName == (object)id314_QNameContent && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -18055,7 +18079,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[2] && ((object) Reader.LocalName == (object)id315_DateContent && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -18070,7 +18094,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[3] && ((object) Reader.LocalName == (object)id316_NameContent && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -18085,7 +18109,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[4] && ((object) Reader.LocalName == (object)id317_NCNameContent && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -18100,7 +18124,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[5] && ((object) Reader.LocalName == (object)id318_NMTOKENContent && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -18115,7 +18139,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[6] && ((object) Reader.LocalName == (object)id319_NMTOKENSContent && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -18130,7 +18154,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[7] && ((object) Reader.LocalName == (object)id320_Base64BinaryContent && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -18145,7 +18169,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (!paramsRead[8] && ((object) Reader.LocalName == (object)id321_HexBinaryContent && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -18208,7 +18232,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (((object) Reader.LocalName == (object)id322_Item && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -18223,7 +18247,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (((object) Reader.LocalName == (object)id323_Amount && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -18282,7 +18306,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id140_Name && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -18341,7 +18365,7 @@ internal System.Collections.Hashtable EnumFlagsValues { if (Reader.NodeType == System.Xml.XmlNodeType.Element) { do { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id140_Name && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -18409,7 +18433,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; } if (((object) Reader.LocalName == (object)id323_Amount && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -18470,7 +18494,7 @@ internal System.Collections.Hashtable EnumFlagsValues { switch (state) { case 0: if (((object) Reader.LocalName == (object)id324_IntField2 && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -18486,7 +18510,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; case 1: if (((object) Reader.LocalName == (object)id325_IntField1 && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -18502,7 +18526,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; case 2: if (((object) Reader.LocalName == (object)id326_strfld && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -18518,7 +18542,7 @@ internal System.Collections.Hashtable EnumFlagsValues { break; case 3: if (((object) Reader.LocalName == (object)id326_strfld && (object) Reader.NamespaceURI == (object)id2_Item)) { - if (!GetNullAttr()) { + if (Reader.HasAttributes) { while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) { UnknownNode(null); @@ -18593,666 +18617,666 @@ internal System.Collections.Hashtable EnumFlagsValues { protected override void InitCallbacks() { } - string id191_MyDate; - string id310_Bar; - string id309_Foo; - string id143_B; - string id131_TypeWithFieldsOrdered; - string id113_ServerSettings; - string id118_Item; - string id263_ArrayMember; - string id237_id; - string id226_X; - string id327_TestProperty; - string id243_CurrentDateTime; - string id152_int; - string id132_Item; - string id276_Optional; - string id293_SimpleTypeValue; - string id81_TypeWithByteArrayAsXmlText; - string id216_Line1; - string id139_LastName; - string id171_P1; - string id123_Item; - string id262_ListMember; + string id24_SimpleBaseClass; string id303_DS2Root; - string id284_Number; - string id278_OptionalInt; - string id318_NMTOKENContent; - string id106_TypeWithPropertyNameSpecified; - string id214_DateTimeValue; - string id225_TotalCost; - string id280_Struct1; - string id141_ContainerType; - string id250_IntAProp; - string id203_TimeSpanProperty; - string id1_TypeWithXmlElementProperty; - string id224_ShipCost; - string id60_TypeWithArraylikeMembers; - string id23_DerivedClass; - string id25_SimpleDerivedClass; - string id107_TypeWithXmlSchemaFormAttribute; - string id156_double; - string id254_Collection; - string id182_LineTotal; - string id164_ArrayOfItemChoiceType; - string id249_NIntLField; - string id135_TypeClashA; - string id88_SomeStruct; - string id71_TypeWithBuiltInTypedMembers; + string id111_CustomElement; + string id246_IntAField; + string id62_TypeWithMyCollectionField; + string id66_MyEnum; + string id207_Breed; + string id265_StringProperty; + string id47_TypeWithLinkedProperty; + string id26_BaseIXmlSerializable; + string id319_NMTOKENSContent; + string id213_AttributeString; + string id57_SimpleType; + string id38_Orchestra; + string id323_Amount; + string id87_WithStruct; + string id199_NullableTime; + string id277_Optionull; + string id248_IntLField; + string id7_DateOnlyWrapper; + string id168_ArrayOfBoolean; + string id175_Children; + string id227_Y; + string id206_Age; + string id188_NullableDTO; + string id11_DateTimeTimeWrapper; + string id81_TypeWithByteArrayAsXmlText; + string id2_Item; + string id98_AttributeTesting; string id89_WithEnums; - string id69_DCClassWithEnumAndStruct; + string id40_Brass; + string id174_Child; + string id112_Item; string id127_Item; - string id270_DisplayName; - string id257_MyEnum1; - string id189_NullableDefaultDTO; - string id242_DateTimeString; - string id306_EmptyStringProperty; - string id157_ArrayOfInstrument; - string id167_NoneParameter; - string id91_ByteEnum; - string id178_ItemName; - string id290_httpelement; - string id213_AttributeString; - string id44_Item; string id239_Parameters; + string id197_MyTime; + string id186_DTO2; + string id218_State; + string id244_F1; + string id203_TimeSpanProperty; + string id114_TypeWithXmlQualifiedName; + string id116_Item; + string id281_Struct2; + string id178_ItemName; + string id79_DerivedClassWithSameProperty2; + string id148_MsgDocumentType; + string id304_MetricConfigUrl; string id144_Value1; - string id209_GroupName; - string id55_Item; - string id61_StructNotSerializable; - string id133_Root; - string id222_Items; - string id58_TypeWithGetSetArrayMembers; - string id187_DefaultDTO; - string id15_TypeWithXmlNodeArrayProperty; - string id8_TimeOnlyWrapper; - string id104_Item; - string id185_DTO; - string id40_Brass; - string id198_DefaultTime; - string id80_Item; - string id174_Child; - string id291_CustomXmlArrayProperty; string id180_UnitPrice; - string id256_MyStruct; - string id38_Orchestra; - string id62_TypeWithMyCollectionField; - string id116_Item; - string id192_DefaultDate; + string id318_NMTOKENContent; + string id250_IntAProp; + string id194_NullableDateWithValue; + string id225_TotalCost; + string id105_Item; + string id161_XElement; + string id289_XmlElementPropertyNode; + string id9_TimeOnlyAsXsdTimeWrapper; + string id78_DerivedClassWithSameProperty; + string id270_DisplayName; + string id208_LicenseNumber; string id241_xelements; - string id259_StringMember; - string id30_httpwwwcontoso1com; - string id193_NullableDate; - string id296_MyFieldIgnored; - string id160_ArrayOfXElement; - string id328_httptestcom; - string id230_Instruments; - string id39_Instrument; - string id288_Item; - string id24_SimpleBaseClass; - string id59_TypeWithGetOnlyArrayProperties; + string id254_Collection; + string id216_Line1; string id121_Item; - string id246_IntAField; - string id110_CustomDocument; - string id49_httpexamplecom; - string id66_MyEnum; - string id252_IntLProp; - string id140_Name; - string id16_Animal; - string id159_ArrayOfParameter; - string id148_MsgDocumentType; - string id321_HexBinaryContent; - string id27_Item; - string id228_Z; - string id255_Data; + string id287_XmlEnumProperty; + string id14_TypeWithByteProperty; + string id209_GroupName; + string id220_ShipTo; + string id147_ParameterOfString; string id99_ItemChoiceType; - string id165_httpmynamespace; - string id251_NIntAProp; - string id301_name; - string id76_Item; - string id168_ArrayOfBoolean; - string id176_IsValved; - string id172_P2; - string id221_OrderDate; - string id311_StringArrayValue; + string id234_DoubleProp; string id269_ClassID; - string id196_Now; - string id274_Int; - string id78_DerivedClassWithSameProperty; - string id47_TypeWithLinkedProperty; - string id64_ArrayOfAnyType; - string id75_TypeHasArrayOfASerializedAsB; - string id20_Vehicle; - string id147_ParameterOfString; - string id218_State; - string id272_IsLoaded; - string id204_TimeSpanProperty2; - string id298_NoneSchemaFormListProperty; - string id260_IntMember; - string id268_ListProperty; + string id13_Item; + string id30_httpwwwcontoso1com; + string id151_ArrayOfInt; + string id126_Item; + string id320_Base64BinaryContent; + string id1_TypeWithXmlElementProperty; string id93_ShortEnum; - string id314_QNameContent; - string id245_F2; - string id83_Item; - string id142_A; - string id68_DCStruct; - string id120_Item; - string id261_NullableIntMember; - string id258_ByteArray; - string id138_MiddleName; - string id267_DateTimeProperty; - string id279_OptionullInt; - string id207_Breed; - string id244_F1; - string id17_Dog; - string id9_TimeOnlyAsXsdTimeWrapper; - string id308_EnumProperty; - string id22_BaseClass; - string id325_IntField1; - string id129_ComplexChoiceA; - string id253_NIntLProp; - string id6_Item; - string id92_SByteEnum; - string id173_Value; - string id3_TypeWithXmlDocumentProperty; - string id109_Item; - string id14_TypeWithByteProperty; - string id11_DateTimeTimeWrapper; - string id114_TypeWithXmlQualifiedName; - string id286_XmlIncludeProperty; + string id53_XElementStruct; string id155_ArrayOfDouble; - string id32_OrderedItem; - string id158_ArrayOfTypeWithLinkedProperty; - string id82_SimpleDC; - string id181_Quantity; - string id312_IntArrayValue; - string id45_Item; - string id183_BinaryHexContent; - string id37_dateTime; - string id205_ByteProperty; - string id289_XmlElementPropertyNode; + string id25_SimpleDerivedClass; + string id77_BaseClassWithSamePropertyName; string id273_Some; - string id35_DerivedClass1; - string id315_DateContent; - string id186_DTO2; - string id271_Id; + string id8_TimeOnlyWrapper; + string id135_TypeClashA; + string id113_ServerSettings; + string id202_TestValue; + string id80_Item; + string id310_Bar; + string id296_MyFieldIgnored; + string id130_ComplexChoiceB; + string id238_refs; + string id137_FirstName; + string id123_Item; + string id23_DerivedClass; + string id146_XmlSerializerAttributes; + string id233_SingleField; + string id249_NIntLField; + string id39_Instrument; + string id196_Now; + string id268_ListProperty; + string id160_ArrayOfXElement; + string id279_OptionullInt; + string id293_SimpleTypeValue; + string id60_TypeWithArraylikeMembers; + string id285_DecimalNumber; + string id101_KnownTypesThroughConstructor; + string id118_Item; string id201_NullableDefaultTime; - string id117_Item; - string id73_TypeA; - string id195_NullableDefaultDate; - string id219_Zip; - string id197_MyTime; - string id145_Value2; - string id211_EmployeeName; - string id316_NameContent; - string id161_XElement; - string id307_CharProperty; - string id95_UIntEnum; - string id319_NMTOKENSContent; - string id322_Item; - string id65_anyType; - string id275_Short; - string id94_IntEnum; - string id4_TypeWithBinaryProperty; - string id108_MyXmlType; - string id277_Optionull; + string id31_Address; + string id34_BaseClass1; + string id46_RootElement; string id10_DateTimeDateWrapper; - string id232_DoubleField; - string id247_NIntAField; - string id84_Item; - string id2_Item; - string id48_Document; - string id217_City; - string id50_RootClass; - string id236_IntValue; + string id115_TypeWith2DArrayProperty2; + string id261_NullableIntMember; + string id19_Group; + string id143_B; + string id69_DCClassWithEnumAndStruct; + string id134_TypeClashB; + string id165_httpmynamespace; + string id154_string; + string id74_TypeB; + string id312_IntArrayValue; + string id294_StrProperty; + string id322_Item; string id210_GroupVehicle; - string id282_XmlAttributeName; - string id302_customElement; - string id101_KnownTypesThroughConstructor; - string id283_Word; - string id126_Item; - string id150_ArrayOfOrderedItem; - string id90_WithNullables; + string id190_Today; + string id3_TypeWithXmlDocumentProperty; + string id309_Foo; + string id280_Struct1; + string id142_A; + string id36_ArrayOfDateTime; string id169_QualifiedParameter; - string id153_ArrayOfString; - string id285_DecimalNumber; - string id323_Amount; - string id128_MoreChoices; - string id305_TwoDArrayOfSimpleType; - string id151_ArrayOfInt; - string id227_Y; - string id281_Struct2; - string id26_BaseIXmlSerializable; - string id13_Item; - string id265_StringProperty; - string id212_value; - string id200_NullableTimeWithValue; - string id56_TypeWithDateTimeStringProperty; + string id272_IsLoaded; + string id311_StringArrayValue; + string id326_strfld; + string id290_httpelement; + string id284_Number; + string id300_XmlAttributeForm; + string id313_DateTimeContent; string id5_Item; - string id223_SubTotal; - string id266_IntProperty; - string id100_TypeWithAnyAttribute; - string id21_Employee; + string id52_XElementWrapper; + string id257_MyEnum1; + string id162_ArrayOfSimpleType; + string id55_Item; + string id138_MiddleName; + string id259_StringMember; string id324_IntField2; - string id112_Item; - string id299_Item; + string id164_ArrayOfItemChoiceType; + string id230_Instruments; + string id109_Item; + string id256_MyStruct; + string id193_NullableDate; + string id28_DerivedIXmlSerializable; + string id176_IsValved; + string id166_ArrayOfString1; + string id129_ComplexChoiceA; + string id158_ArrayOfTypeWithLinkedProperty; + string id141_ContainerType; + string id191_MyDate; + string id159_ArrayOfParameter; + string id102_SimpleKnownTypeValue; + string id50_RootClass; + string id325_IntField1; + string id263_ArrayMember; + string id65_anyType; + string id92_SByteEnum; + string id317_NCNameContent; + string id35_DerivedClass1; + string id73_TypeA; + string id91_ByteEnum; + string id243_CurrentDateTime; + string id104_Item; + string id37_dateTime; + string id305_TwoDArrayOfSimpleType; + string id171_P1; + string id70_BuiltInTypes; + string id237_id; + string id251_NIntAProp; + string id132_Item; + string id215_BoolValue; string id124_Item; - string id46_RootElement; - string id149_Item; - string id190_Today; - string id188_NullableDTO; - string id320_Base64BinaryContent; - string id74_TypeB; - string id231_Comment2; - string id86_ClassImplementsInterface; + string id44_Item; + string id179_Description; + string id217_City; + string id4_TypeWithBinaryProperty; + string id170_ArrayOfArrayOfSimpleType; + string id122_Item; + string id308_EnumProperty; + string id167_NoneParameter; + string id51_Parameter; + string id97_ULongEnum; + string id152_int; + string id189_NullableDefaultDTO; + string id212_value; + string id301_name; + string id276_Optional; + string id316_NameContent; + string id252_IntLProp; + string id286_XmlIncludeProperty; + string id156_double; + string id56_TypeWithDateTimeStringProperty; + string id182_LineTotal; + string id266_IntProperty; + string id22_BaseClass; + string id306_EmptyStringProperty; + string id12_TypeWithTimeSpanProperty; + string id214_DateTimeValue; + string id236_IntValue; + string id274_Int; string id292_EnumValue; + string id17_Dog; + string id247_NIntAField; + string id83_Item; + string id94_IntEnum; + string id240_xelement; + string id42_Pet; + string id298_NoneSchemaFormListProperty; + string id49_httpexamplecom; + string id120_Item; + string id231_Comment2; + string id76_Item; + string id68_DCStruct; + string id163_ArrayOfTypeA; + string id145_Value2; + string id64_ArrayOfAnyType; + string id187_DefaultDTO; + string id192_DefaultDate; + string id107_TypeWithXmlSchemaFormAttribute; + string id108_MyXmlType; + string id253_NIntLProp; + string id328_httptestcom; string id103_Item; - string id41_Trumpet; - string id137_FirstName; - string id162_ArrayOfSimpleType; - string id34_BaseClass1; - string id98_AttributeTesting; + string id82_SimpleDC; + string id204_TimeSpanProperty2; + string id32_OrderedItem; + string id153_ArrayOfString; + string id84_Item; string id67_TypeWithEnumMembers; - string id119_TypeWithShouldSerializeMethod; - string id304_MetricConfigUrl; - string id166_ArrayOfString1; - string id295_MyField; - string id36_ArrayOfDateTime; - string id175_Children; - string id313_DateTimeContent; - string id220_ShipTo; - string id31_Address; - string id33_AliasedTestType; string id43_DefaultValuesSetToNaN; - string id294_StrProperty; - string id215_BoolValue; - string id51_Parameter; - string id206_Age; + string id117_Item; + string id136_Person; + string id185_DTO; + string id222_Items; + string id41_Trumpet; + string id110_CustomDocument; + string id295_MyField; + string id219_Zip; + string id223_SubTotal; + string id149_Item; + string id100_TypeWithAnyAttribute; + string id106_TypeWithPropertyNameSpecified; + string id195_NullableDefaultDate; + string id211_EmployeeName; + string id245_F2; + string id16_Animal; + string id307_CharProperty; + string id139_LastName; + string id75_TypeHasArrayOfASerializedAsB; string id229_Prop; - string id79_DerivedClassWithSameProperty2; - string id53_XElementStruct; + string id95_UIntEnum; + string id258_ByteArray; + string id184_Base64Content; + string id278_OptionalInt; + string id226_X; + string id172_P2; + string id59_TypeWithGetOnlyArrayProperties; + string id133_Root; + string id131_TypeWithFieldsOrdered; + string id125_Item; + string id315_DateContent; + string id255_Data; + string id205_ByteProperty; + string id177_Modulation; + string id198_DefaultTime; + string id242_DateTimeString; + string id267_DateTimeProperty; + string id119_TypeWithShouldSerializeMethod; + string id58_TypeWithGetSetArrayMembers; + string id86_ClassImplementsInterface; + string id20_Vehicle; + string id128_MoreChoices; + string id314_QNameContent; + string id61_StructNotSerializable; + string id6_Item; + string id48_Document; + string id221_OrderDate; + string id21_Employee; + string id291_CustomXmlArrayProperty; + string id54_XElementArrayWrapper; + string id150_ArrayOfOrderedItem; + string id228_Z; + string id45_Item; + string id275_Short; + string id235_FloatProp; + string id29_PurchaseOrder; + string id72_Item; + string id299_Item; string id264_Item; - string id130_ComplexChoiceB; + string id157_ArrayOfInstrument; + string id288_Item; + string id224_ShipCost; + string id173_Value; + string id271_Id; + string id15_TypeWithXmlNodeArrayProperty; + string id85_EnumFlags; + string id283_Word; + string id327_TestProperty; string id18_DogBreed; - string id96_LongEnum; + string id262_ListMember; + string id181_Quantity; + string id140_Name; + string id88_SomeStruct; string id297_Item; - string id111_CustomElement; - string id115_TypeWith2DArrayProperty2; - string id317_NCNameContent; - string id234_DoubleProp; - string id235_FloatProp; - string id300_XmlAttributeForm; - string id85_EnumFlags; - string id146_XmlSerializerAttributes; - string id199_NullableTime; - string id7_DateOnlyWrapper; - string id177_Modulation; - string id57_SimpleType; - string id52_XElementWrapper; - string id97_ULongEnum; - string id42_Pet; - string id154_string; - string id70_BuiltInTypes; - string id134_TypeClashB; - string id202_TestValue; - string id233_SingleField; - string id54_XElementArrayWrapper; - string id125_Item; - string id208_LicenseNumber; - string id105_Item; - string id12_TypeWithTimeSpanProperty; + string id90_WithNullables; + string id321_HexBinaryContent; + string id282_XmlAttributeName; + string id200_NullableTimeWithValue; + string id260_IntMember; + string id232_DoubleField; + string id96_LongEnum; + string id71_TypeWithBuiltInTypedMembers; + string id183_BinaryHexContent; string id63_Item; - string id238_refs; - string id72_Item; - string id122_Item; - string id102_SimpleKnownTypeValue; - string id163_ArrayOfTypeA; - string id240_xelement; - string id194_NullableDateWithValue; - string id19_Group; - string id248_IntLField; - string id28_DerivedIXmlSerializable; - string id136_Person; - string id170_ArrayOfArrayOfSimpleType; - string id326_strfld; - string id77_BaseClassWithSamePropertyName; - string id29_PurchaseOrder; - string id184_Base64Content; - string id179_Description; - string id287_XmlEnumProperty; - string id87_WithStruct; + string id33_AliasedTestType; + string id27_Item; + string id302_customElement; static readonly char[] xmlListSeparators = System.AppContext.TryGetSwitch("Switch.System.Xml.Serialization.UseLegacyXmlListSeparation", out bool useLegacyXmlListSeparation) && useLegacyXmlListSeparation ? null : new char[] { ' ', '\t', '\n', '\r' }; protected override void InitIDs() { - id191_MyDate = Reader.NameTable.Add(@"MyDate"); - id310_Bar = Reader.NameTable.Add(@"Bar"); - id309_Foo = Reader.NameTable.Add(@"Foo"); - id143_B = Reader.NameTable.Add(@"B"); - id131_TypeWithFieldsOrdered = Reader.NameTable.Add(@"TypeWithFieldsOrdered"); - id113_ServerSettings = Reader.NameTable.Add(@"ServerSettings"); - id118_Item = Reader.NameTable.Add(@"TypeWithEnumFlagPropertyHavingDefaultValue"); - id263_ArrayMember = Reader.NameTable.Add(@"ArrayMember"); - id237_id = Reader.NameTable.Add(@"id"); - id226_X = Reader.NameTable.Add(@"X"); - id327_TestProperty = Reader.NameTable.Add(@"TestProperty"); - id243_CurrentDateTime = Reader.NameTable.Add(@"CurrentDateTime"); - id152_int = Reader.NameTable.Add(@"int"); - id132_Item = Reader.NameTable.Add(@"TypeWithKnownTypesOfCollectionsWithConflictingXmlName"); - id276_Optional = Reader.NameTable.Add(@"Optional"); - id293_SimpleTypeValue = Reader.NameTable.Add(@"SimpleTypeValue"); - id81_TypeWithByteArrayAsXmlText = Reader.NameTable.Add(@"TypeWithByteArrayAsXmlText"); - id216_Line1 = Reader.NameTable.Add(@"Line1"); - id139_LastName = Reader.NameTable.Add(@"LastName"); - id171_P1 = Reader.NameTable.Add(@"P1"); - id123_Item = Reader.NameTable.Add(@"KnownTypesThroughConstructorWithArrayProperties"); - id262_ListMember = Reader.NameTable.Add(@"ListMember"); + id24_SimpleBaseClass = Reader.NameTable.Add(@"SimpleBaseClass"); id303_DS2Root = Reader.NameTable.Add(@"DS2Root"); - id284_Number = Reader.NameTable.Add(@"Number"); - id278_OptionalInt = Reader.NameTable.Add(@"OptionalInt"); - id318_NMTOKENContent = Reader.NameTable.Add(@"NMTOKENContent"); - id106_TypeWithPropertyNameSpecified = Reader.NameTable.Add(@"TypeWithPropertyNameSpecified"); - id214_DateTimeValue = Reader.NameTable.Add(@"DateTimeValue"); - id225_TotalCost = Reader.NameTable.Add(@"TotalCost"); - id280_Struct1 = Reader.NameTable.Add(@"Struct1"); - id141_ContainerType = Reader.NameTable.Add(@"ContainerType"); - id250_IntAProp = Reader.NameTable.Add(@"IntAProp"); - id203_TimeSpanProperty = Reader.NameTable.Add(@"TimeSpanProperty"); - id1_TypeWithXmlElementProperty = Reader.NameTable.Add(@"TypeWithXmlElementProperty"); - id224_ShipCost = Reader.NameTable.Add(@"ShipCost"); - id60_TypeWithArraylikeMembers = Reader.NameTable.Add(@"TypeWithArraylikeMembers"); - id23_DerivedClass = Reader.NameTable.Add(@"DerivedClass"); - id25_SimpleDerivedClass = Reader.NameTable.Add(@"SimpleDerivedClass"); - id107_TypeWithXmlSchemaFormAttribute = Reader.NameTable.Add(@"TypeWithXmlSchemaFormAttribute"); - id156_double = Reader.NameTable.Add(@"double"); - id254_Collection = Reader.NameTable.Add(@"Collection"); - id182_LineTotal = Reader.NameTable.Add(@"LineTotal"); - id164_ArrayOfItemChoiceType = Reader.NameTable.Add(@"ArrayOfItemChoiceType"); - id249_NIntLField = Reader.NameTable.Add(@"NIntLField"); - id135_TypeClashA = Reader.NameTable.Add(@"TypeClashA"); - id88_SomeStruct = Reader.NameTable.Add(@"SomeStruct"); - id71_TypeWithBuiltInTypedMembers = Reader.NameTable.Add(@"TypeWithBuiltInTypedMembers"); + id111_CustomElement = Reader.NameTable.Add(@"CustomElement"); + id246_IntAField = Reader.NameTable.Add(@"IntAField"); + id62_TypeWithMyCollectionField = Reader.NameTable.Add(@"TypeWithMyCollectionField"); + id66_MyEnum = Reader.NameTable.Add(@"MyEnum"); + id207_Breed = Reader.NameTable.Add(@"Breed"); + id265_StringProperty = Reader.NameTable.Add(@"StringProperty"); + id47_TypeWithLinkedProperty = Reader.NameTable.Add(@"TypeWithLinkedProperty"); + id26_BaseIXmlSerializable = Reader.NameTable.Add(@"BaseIXmlSerializable"); + id319_NMTOKENSContent = Reader.NameTable.Add(@"NMTOKENSContent"); + id213_AttributeString = Reader.NameTable.Add(@"AttributeString"); + id57_SimpleType = Reader.NameTable.Add(@"SimpleType"); + id38_Orchestra = Reader.NameTable.Add(@"Orchestra"); + id323_Amount = Reader.NameTable.Add(@"Amount"); + id87_WithStruct = Reader.NameTable.Add(@"WithStruct"); + id199_NullableTime = Reader.NameTable.Add(@"NullableTime"); + id277_Optionull = Reader.NameTable.Add(@"Optionull"); + id248_IntLField = Reader.NameTable.Add(@"IntLField"); + id7_DateOnlyWrapper = Reader.NameTable.Add(@"DateOnlyWrapper"); + id168_ArrayOfBoolean = Reader.NameTable.Add(@"ArrayOfBoolean"); + id175_Children = Reader.NameTable.Add(@"Children"); + id227_Y = Reader.NameTable.Add(@"Y"); + id206_Age = Reader.NameTable.Add(@"Age"); + id188_NullableDTO = Reader.NameTable.Add(@"NullableDTO"); + id11_DateTimeTimeWrapper = Reader.NameTable.Add(@"DateTimeTimeWrapper"); + id81_TypeWithByteArrayAsXmlText = Reader.NameTable.Add(@"TypeWithByteArrayAsXmlText"); + id2_Item = Reader.NameTable.Add(@""); + id98_AttributeTesting = Reader.NameTable.Add(@"AttributeTesting"); id89_WithEnums = Reader.NameTable.Add(@"WithEnums"); - id69_DCClassWithEnumAndStruct = Reader.NameTable.Add(@"DCClassWithEnumAndStruct"); + id40_Brass = Reader.NameTable.Add(@"Brass"); + id174_Child = Reader.NameTable.Add(@"Child"); + id112_Item = Reader.NameTable.Add(@"TypeWithNonPublicDefaultConstructor"); id127_Item = Reader.NameTable.Add(@"TypeWithPropertyHavingComplexChoice"); - id270_DisplayName = Reader.NameTable.Add(@"DisplayName"); - id257_MyEnum1 = Reader.NameTable.Add(@"MyEnum1"); - id189_NullableDefaultDTO = Reader.NameTable.Add(@"NullableDefaultDTO"); - id242_DateTimeString = Reader.NameTable.Add(@"DateTimeString"); - id306_EmptyStringProperty = Reader.NameTable.Add(@"EmptyStringProperty"); - id157_ArrayOfInstrument = Reader.NameTable.Add(@"ArrayOfInstrument"); - id167_NoneParameter = Reader.NameTable.Add(@"NoneParameter"); - id91_ByteEnum = Reader.NameTable.Add(@"ByteEnum"); - id178_ItemName = Reader.NameTable.Add(@"ItemName"); - id290_httpelement = Reader.NameTable.Add(@"http://element"); - id213_AttributeString = Reader.NameTable.Add(@"AttributeString"); - id44_Item = Reader.NameTable.Add(@"DefaultValuesSetToPositiveInfinity"); id239_Parameters = Reader.NameTable.Add(@"Parameters"); + id197_MyTime = Reader.NameTable.Add(@"MyTime"); + id186_DTO2 = Reader.NameTable.Add(@"DTO2"); + id218_State = Reader.NameTable.Add(@"State"); + id244_F1 = Reader.NameTable.Add(@"F1"); + id203_TimeSpanProperty = Reader.NameTable.Add(@"TimeSpanProperty"); + id114_TypeWithXmlQualifiedName = Reader.NameTable.Add(@"TypeWithXmlQualifiedName"); + id116_Item = Reader.NameTable.Add(@"TypeWithPropertiesHavingDefaultValue"); + id281_Struct2 = Reader.NameTable.Add(@"Struct2"); + id178_ItemName = Reader.NameTable.Add(@"ItemName"); + id79_DerivedClassWithSameProperty2 = Reader.NameTable.Add(@"DerivedClassWithSameProperty2"); + id148_MsgDocumentType = Reader.NameTable.Add(@"MsgDocumentType"); + id304_MetricConfigUrl = Reader.NameTable.Add(@"MetricConfigUrl"); id144_Value1 = Reader.NameTable.Add(@"Value1"); - id209_GroupName = Reader.NameTable.Add(@"GroupName"); - id55_Item = Reader.NameTable.Add(@"DateTimeOffsetIXmlSerializableContainer"); - id61_StructNotSerializable = Reader.NameTable.Add(@"StructNotSerializable"); - id133_Root = Reader.NameTable.Add(@"Root"); - id222_Items = Reader.NameTable.Add(@"Items"); - id58_TypeWithGetSetArrayMembers = Reader.NameTable.Add(@"TypeWithGetSetArrayMembers"); - id187_DefaultDTO = Reader.NameTable.Add(@"DefaultDTO"); - id15_TypeWithXmlNodeArrayProperty = Reader.NameTable.Add(@"TypeWithXmlNodeArrayProperty"); - id8_TimeOnlyWrapper = Reader.NameTable.Add(@"TimeOnlyWrapper"); - id104_Item = Reader.NameTable.Add(@"StructImplementingIXmlSerializableWithoutParameterlessConstructor"); - id185_DTO = Reader.NameTable.Add(@"DTO"); - id40_Brass = Reader.NameTable.Add(@"Brass"); - id198_DefaultTime = Reader.NameTable.Add(@"DefaultTime"); - id80_Item = Reader.NameTable.Add(@"TypeWithDateTimePropertyAsXmlTime"); - id174_Child = Reader.NameTable.Add(@"Child"); - id291_CustomXmlArrayProperty = Reader.NameTable.Add(@"CustomXmlArrayProperty"); id180_UnitPrice = Reader.NameTable.Add(@"UnitPrice"); - id256_MyStruct = Reader.NameTable.Add(@"MyStruct"); - id38_Orchestra = Reader.NameTable.Add(@"Orchestra"); - id62_TypeWithMyCollectionField = Reader.NameTable.Add(@"TypeWithMyCollectionField"); - id116_Item = Reader.NameTable.Add(@"TypeWithPropertiesHavingDefaultValue"); - id192_DefaultDate = Reader.NameTable.Add(@"DefaultDate"); + id318_NMTOKENContent = Reader.NameTable.Add(@"NMTOKENContent"); + id250_IntAProp = Reader.NameTable.Add(@"IntAProp"); + id194_NullableDateWithValue = Reader.NameTable.Add(@"NullableDateWithValue"); + id225_TotalCost = Reader.NameTable.Add(@"TotalCost"); + id105_Item = Reader.NameTable.Add(@"StructImplementingIXmlSerializableWithParameterlessConstructor"); + id161_XElement = Reader.NameTable.Add(@"XElement"); + id289_XmlElementPropertyNode = Reader.NameTable.Add(@"XmlElementPropertyNode"); + id9_TimeOnlyAsXsdTimeWrapper = Reader.NameTable.Add(@"TimeOnlyAsXsdTimeWrapper"); + id78_DerivedClassWithSameProperty = Reader.NameTable.Add(@"DerivedClassWithSameProperty"); + id270_DisplayName = Reader.NameTable.Add(@"DisplayName"); + id208_LicenseNumber = Reader.NameTable.Add(@"LicenseNumber"); id241_xelements = Reader.NameTable.Add(@"xelements"); - id259_StringMember = Reader.NameTable.Add(@"StringMember"); - id30_httpwwwcontoso1com = Reader.NameTable.Add(@"http://www.contoso1.com"); - id193_NullableDate = Reader.NameTable.Add(@"NullableDate"); - id296_MyFieldIgnored = Reader.NameTable.Add(@"MyFieldIgnored"); - id160_ArrayOfXElement = Reader.NameTable.Add(@"ArrayOfXElement"); - id328_httptestcom = Reader.NameTable.Add(@"http://test.com"); - id230_Instruments = Reader.NameTable.Add(@"Instruments"); - id39_Instrument = Reader.NameTable.Add(@"Instrument"); - id288_Item = Reader.NameTable.Add(@"XmlNamespaceDeclarationsProperty"); - id24_SimpleBaseClass = Reader.NameTable.Add(@"SimpleBaseClass"); - id59_TypeWithGetOnlyArrayProperties = Reader.NameTable.Add(@"TypeWithGetOnlyArrayProperties"); + id254_Collection = Reader.NameTable.Add(@"Collection"); + id216_Line1 = Reader.NameTable.Add(@"Line1"); id121_Item = Reader.NameTable.Add(@"DerivedTypeWithInheritedShouldSerialize"); - id246_IntAField = Reader.NameTable.Add(@"IntAField"); - id110_CustomDocument = Reader.NameTable.Add(@"CustomDocument"); - id49_httpexamplecom = Reader.NameTable.Add(@"http://example.com"); - id66_MyEnum = Reader.NameTable.Add(@"MyEnum"); - id252_IntLProp = Reader.NameTable.Add(@"IntLProp"); - id140_Name = Reader.NameTable.Add(@"Name"); - id16_Animal = Reader.NameTable.Add(@"Animal"); - id159_ArrayOfParameter = Reader.NameTable.Add(@"ArrayOfParameter"); - id148_MsgDocumentType = Reader.NameTable.Add(@"MsgDocumentType"); - id321_HexBinaryContent = Reader.NameTable.Add(@"HexBinaryContent"); - id27_Item = Reader.NameTable.Add(@"http://example.com/serializer-test-namespace"); - id228_Z = Reader.NameTable.Add(@"Z"); - id255_Data = Reader.NameTable.Add(@"Data"); + id287_XmlEnumProperty = Reader.NameTable.Add(@"XmlEnumProperty"); + id14_TypeWithByteProperty = Reader.NameTable.Add(@"TypeWithByteProperty"); + id209_GroupName = Reader.NameTable.Add(@"GroupName"); + id220_ShipTo = Reader.NameTable.Add(@"ShipTo"); + id147_ParameterOfString = Reader.NameTable.Add(@"ParameterOfString"); id99_ItemChoiceType = Reader.NameTable.Add(@"ItemChoiceType"); - id165_httpmynamespace = Reader.NameTable.Add(@"http://mynamespace"); - id251_NIntAProp = Reader.NameTable.Add(@"NIntAProp"); - id301_name = Reader.NameTable.Add(@"name"); - id76_Item = Reader.NameTable.Add(@"__TypeNameWithSpecialCharacters漢ñ"); - id168_ArrayOfBoolean = Reader.NameTable.Add(@"ArrayOfBoolean"); - id176_IsValved = Reader.NameTable.Add(@"IsValved"); - id172_P2 = Reader.NameTable.Add(@"P2"); - id221_OrderDate = Reader.NameTable.Add(@"OrderDate"); - id311_StringArrayValue = Reader.NameTable.Add(@"StringArrayValue"); + id234_DoubleProp = Reader.NameTable.Add(@"DoubleProp"); id269_ClassID = Reader.NameTable.Add(@"ClassID"); + id13_Item = Reader.NameTable.Add(@"TypeWithDefaultTimeSpanProperty"); + id30_httpwwwcontoso1com = Reader.NameTable.Add(@"http://www.contoso1.com"); + id151_ArrayOfInt = Reader.NameTable.Add(@"ArrayOfInt"); + id126_Item = Reader.NameTable.Add(@"TypeWithArrayPropertyHavingChoice"); + id320_Base64BinaryContent = Reader.NameTable.Add(@"Base64BinaryContent"); + id1_TypeWithXmlElementProperty = Reader.NameTable.Add(@"TypeWithXmlElementProperty"); + id93_ShortEnum = Reader.NameTable.Add(@"ShortEnum"); + id53_XElementStruct = Reader.NameTable.Add(@"XElementStruct"); + id155_ArrayOfDouble = Reader.NameTable.Add(@"ArrayOfDouble"); + id25_SimpleDerivedClass = Reader.NameTable.Add(@"SimpleDerivedClass"); + id77_BaseClassWithSamePropertyName = Reader.NameTable.Add(@"BaseClassWithSamePropertyName"); + id273_Some = Reader.NameTable.Add(@"Some"); + id8_TimeOnlyWrapper = Reader.NameTable.Add(@"TimeOnlyWrapper"); + id135_TypeClashA = Reader.NameTable.Add(@"TypeClashA"); + id113_ServerSettings = Reader.NameTable.Add(@"ServerSettings"); + id202_TestValue = Reader.NameTable.Add(@"TestValue"); + id80_Item = Reader.NameTable.Add(@"TypeWithDateTimePropertyAsXmlTime"); + id310_Bar = Reader.NameTable.Add(@"Bar"); + id296_MyFieldIgnored = Reader.NameTable.Add(@"MyFieldIgnored"); + id130_ComplexChoiceB = Reader.NameTable.Add(@"ComplexChoiceB"); + id238_refs = Reader.NameTable.Add(@"refs"); + id137_FirstName = Reader.NameTable.Add(@"FirstName"); + id123_Item = Reader.NameTable.Add(@"KnownTypesThroughConstructorWithArrayProperties"); + id23_DerivedClass = Reader.NameTable.Add(@"DerivedClass"); + id146_XmlSerializerAttributes = Reader.NameTable.Add(@"XmlSerializerAttributes"); + id233_SingleField = Reader.NameTable.Add(@"SingleField"); + id249_NIntLField = Reader.NameTable.Add(@"NIntLField"); + id39_Instrument = Reader.NameTable.Add(@"Instrument"); id196_Now = Reader.NameTable.Add(@"Now"); - id274_Int = Reader.NameTable.Add(@"Int"); - id78_DerivedClassWithSameProperty = Reader.NameTable.Add(@"DerivedClassWithSameProperty"); - id47_TypeWithLinkedProperty = Reader.NameTable.Add(@"TypeWithLinkedProperty"); - id64_ArrayOfAnyType = Reader.NameTable.Add(@"ArrayOfAnyType"); - id75_TypeHasArrayOfASerializedAsB = Reader.NameTable.Add(@"TypeHasArrayOfASerializedAsB"); - id20_Vehicle = Reader.NameTable.Add(@"Vehicle"); - id147_ParameterOfString = Reader.NameTable.Add(@"ParameterOfString"); - id218_State = Reader.NameTable.Add(@"State"); - id272_IsLoaded = Reader.NameTable.Add(@"IsLoaded"); - id204_TimeSpanProperty2 = Reader.NameTable.Add(@"TimeSpanProperty2"); - id298_NoneSchemaFormListProperty = Reader.NameTable.Add(@"NoneSchemaFormListProperty"); - id260_IntMember = Reader.NameTable.Add(@"IntMember"); id268_ListProperty = Reader.NameTable.Add(@"ListProperty"); - id93_ShortEnum = Reader.NameTable.Add(@"ShortEnum"); - id314_QNameContent = Reader.NameTable.Add(@"QNameContent"); - id245_F2 = Reader.NameTable.Add(@"F2"); - id83_Item = Reader.NameTable.Add(@"TypeWithXmlTextAttributeOnArray"); - id142_A = Reader.NameTable.Add(@"A"); - id68_DCStruct = Reader.NameTable.Add(@"DCStruct"); - id120_Item = Reader.NameTable.Add(@"BaseTypeWithShouldSerializeMethod"); + id160_ArrayOfXElement = Reader.NameTable.Add(@"ArrayOfXElement"); + id279_OptionullInt = Reader.NameTable.Add(@"OptionullInt"); + id293_SimpleTypeValue = Reader.NameTable.Add(@"SimpleTypeValue"); + id60_TypeWithArraylikeMembers = Reader.NameTable.Add(@"TypeWithArraylikeMembers"); + id285_DecimalNumber = Reader.NameTable.Add(@"DecimalNumber"); + id101_KnownTypesThroughConstructor = Reader.NameTable.Add(@"KnownTypesThroughConstructor"); + id118_Item = Reader.NameTable.Add(@"TypeWithEnumFlagPropertyHavingDefaultValue"); + id201_NullableDefaultTime = Reader.NameTable.Add(@"NullableDefaultTime"); + id31_Address = Reader.NameTable.Add(@"Address"); + id34_BaseClass1 = Reader.NameTable.Add(@"BaseClass1"); + id46_RootElement = Reader.NameTable.Add(@"RootElement"); + id10_DateTimeDateWrapper = Reader.NameTable.Add(@"DateTimeDateWrapper"); + id115_TypeWith2DArrayProperty2 = Reader.NameTable.Add(@"TypeWith2DArrayProperty2"); id261_NullableIntMember = Reader.NameTable.Add(@"NullableIntMember"); - id258_ByteArray = Reader.NameTable.Add(@"ByteArray"); + id19_Group = Reader.NameTable.Add(@"Group"); + id143_B = Reader.NameTable.Add(@"B"); + id69_DCClassWithEnumAndStruct = Reader.NameTable.Add(@"DCClassWithEnumAndStruct"); + id134_TypeClashB = Reader.NameTable.Add(@"TypeClashB"); + id165_httpmynamespace = Reader.NameTable.Add(@"http://mynamespace"); + id154_string = Reader.NameTable.Add(@"string"); + id74_TypeB = Reader.NameTable.Add(@"TypeB"); + id312_IntArrayValue = Reader.NameTable.Add(@"IntArrayValue"); + id294_StrProperty = Reader.NameTable.Add(@"StrProperty"); + id322_Item = Reader.NameTable.Add(@"Item"); + id210_GroupVehicle = Reader.NameTable.Add(@"GroupVehicle"); + id190_Today = Reader.NameTable.Add(@"Today"); + id3_TypeWithXmlDocumentProperty = Reader.NameTable.Add(@"TypeWithXmlDocumentProperty"); + id309_Foo = Reader.NameTable.Add(@"Foo"); + id280_Struct1 = Reader.NameTable.Add(@"Struct1"); + id142_A = Reader.NameTable.Add(@"A"); + id36_ArrayOfDateTime = Reader.NameTable.Add(@"ArrayOfDateTime"); + id169_QualifiedParameter = Reader.NameTable.Add(@"QualifiedParameter"); + id272_IsLoaded = Reader.NameTable.Add(@"IsLoaded"); + id311_StringArrayValue = Reader.NameTable.Add(@"StringArrayValue"); + id326_strfld = Reader.NameTable.Add(@"strfld"); + id290_httpelement = Reader.NameTable.Add(@"http://element"); + id284_Number = Reader.NameTable.Add(@"Number"); + id300_XmlAttributeForm = Reader.NameTable.Add(@"XmlAttributeForm"); + id313_DateTimeContent = Reader.NameTable.Add(@"DateTimeContent"); + id5_Item = Reader.NameTable.Add(@"TypeWithDateTimeOffsetProperties"); + id52_XElementWrapper = Reader.NameTable.Add(@"XElementWrapper"); + id257_MyEnum1 = Reader.NameTable.Add(@"MyEnum1"); + id162_ArrayOfSimpleType = Reader.NameTable.Add(@"ArrayOfSimpleType"); + id55_Item = Reader.NameTable.Add(@"DateTimeOffsetIXmlSerializableContainer"); id138_MiddleName = Reader.NameTable.Add(@"MiddleName"); - id267_DateTimeProperty = Reader.NameTable.Add(@"DateTimeProperty"); - id279_OptionullInt = Reader.NameTable.Add(@"OptionullInt"); - id207_Breed = Reader.NameTable.Add(@"Breed"); - id244_F1 = Reader.NameTable.Add(@"F1"); - id17_Dog = Reader.NameTable.Add(@"Dog"); - id9_TimeOnlyAsXsdTimeWrapper = Reader.NameTable.Add(@"TimeOnlyAsXsdTimeWrapper"); + id259_StringMember = Reader.NameTable.Add(@"StringMember"); + id324_IntField2 = Reader.NameTable.Add(@"IntField2"); + id164_ArrayOfItemChoiceType = Reader.NameTable.Add(@"ArrayOfItemChoiceType"); + id230_Instruments = Reader.NameTable.Add(@"Instruments"); + id109_Item = Reader.NameTable.Add(@"TypeWithSchemaFormInXmlAttribute"); + id256_MyStruct = Reader.NameTable.Add(@"MyStruct"); + id193_NullableDate = Reader.NameTable.Add(@"NullableDate"); + id28_DerivedIXmlSerializable = Reader.NameTable.Add(@"DerivedIXmlSerializable"); + id176_IsValved = Reader.NameTable.Add(@"IsValved"); + id166_ArrayOfString1 = Reader.NameTable.Add(@"ArrayOfString1"); + id129_ComplexChoiceA = Reader.NameTable.Add(@"ComplexChoiceA"); + id158_ArrayOfTypeWithLinkedProperty = Reader.NameTable.Add(@"ArrayOfTypeWithLinkedProperty"); + id141_ContainerType = Reader.NameTable.Add(@"ContainerType"); + id191_MyDate = Reader.NameTable.Add(@"MyDate"); + id159_ArrayOfParameter = Reader.NameTable.Add(@"ArrayOfParameter"); + id102_SimpleKnownTypeValue = Reader.NameTable.Add(@"SimpleKnownTypeValue"); + id50_RootClass = Reader.NameTable.Add(@"RootClass"); + id325_IntField1 = Reader.NameTable.Add(@"IntField1"); + id263_ArrayMember = Reader.NameTable.Add(@"ArrayMember"); + id65_anyType = Reader.NameTable.Add(@"anyType"); + id92_SByteEnum = Reader.NameTable.Add(@"SByteEnum"); + id317_NCNameContent = Reader.NameTable.Add(@"NCNameContent"); + id35_DerivedClass1 = Reader.NameTable.Add(@"DerivedClass1"); + id73_TypeA = Reader.NameTable.Add(@"TypeA"); + id91_ByteEnum = Reader.NameTable.Add(@"ByteEnum"); + id243_CurrentDateTime = Reader.NameTable.Add(@"CurrentDateTime"); + id104_Item = Reader.NameTable.Add(@"StructImplementingIXmlSerializableWithoutParameterlessConstructor"); + id37_dateTime = Reader.NameTable.Add(@"dateTime"); + id305_TwoDArrayOfSimpleType = Reader.NameTable.Add(@"TwoDArrayOfSimpleType"); + id171_P1 = Reader.NameTable.Add(@"P1"); + id70_BuiltInTypes = Reader.NameTable.Add(@"BuiltInTypes"); + id237_id = Reader.NameTable.Add(@"id"); + id251_NIntAProp = Reader.NameTable.Add(@"NIntAProp"); + id132_Item = Reader.NameTable.Add(@"TypeWithKnownTypesOfCollectionsWithConflictingXmlName"); + id215_BoolValue = Reader.NameTable.Add(@"BoolValue"); + id124_Item = Reader.NameTable.Add(@"KnownTypesThroughConstructorWithValue"); + id44_Item = Reader.NameTable.Add(@"DefaultValuesSetToPositiveInfinity"); + id179_Description = Reader.NameTable.Add(@"Description"); + id217_City = Reader.NameTable.Add(@"City"); + id4_TypeWithBinaryProperty = Reader.NameTable.Add(@"TypeWithBinaryProperty"); + id170_ArrayOfArrayOfSimpleType = Reader.NameTable.Add(@"ArrayOfArrayOfSimpleType"); + id122_Item = Reader.NameTable.Add(@"TypeWithFieldBackedSpecifiedMember"); id308_EnumProperty = Reader.NameTable.Add(@"EnumProperty"); + id167_NoneParameter = Reader.NameTable.Add(@"NoneParameter"); + id51_Parameter = Reader.NameTable.Add(@"Parameter"); + id97_ULongEnum = Reader.NameTable.Add(@"ULongEnum"); + id152_int = Reader.NameTable.Add(@"int"); + id189_NullableDefaultDTO = Reader.NameTable.Add(@"NullableDefaultDTO"); + id212_value = Reader.NameTable.Add(@"value"); + id301_name = Reader.NameTable.Add(@"name"); + id276_Optional = Reader.NameTable.Add(@"Optional"); + id316_NameContent = Reader.NameTable.Add(@"NameContent"); + id252_IntLProp = Reader.NameTable.Add(@"IntLProp"); + id286_XmlIncludeProperty = Reader.NameTable.Add(@"XmlIncludeProperty"); + id156_double = Reader.NameTable.Add(@"double"); + id56_TypeWithDateTimeStringProperty = Reader.NameTable.Add(@"TypeWithDateTimeStringProperty"); + id182_LineTotal = Reader.NameTable.Add(@"LineTotal"); + id266_IntProperty = Reader.NameTable.Add(@"IntProperty"); id22_BaseClass = Reader.NameTable.Add(@"BaseClass"); - id325_IntField1 = Reader.NameTable.Add(@"IntField1"); - id129_ComplexChoiceA = Reader.NameTable.Add(@"ComplexChoiceA"); + id306_EmptyStringProperty = Reader.NameTable.Add(@"EmptyStringProperty"); + id12_TypeWithTimeSpanProperty = Reader.NameTable.Add(@"TypeWithTimeSpanProperty"); + id214_DateTimeValue = Reader.NameTable.Add(@"DateTimeValue"); + id236_IntValue = Reader.NameTable.Add(@"IntValue"); + id274_Int = Reader.NameTable.Add(@"Int"); + id292_EnumValue = Reader.NameTable.Add(@"EnumValue"); + id17_Dog = Reader.NameTable.Add(@"Dog"); + id247_NIntAField = Reader.NameTable.Add(@"NIntAField"); + id83_Item = Reader.NameTable.Add(@"TypeWithXmlTextAttributeOnArray"); + id94_IntEnum = Reader.NameTable.Add(@"IntEnum"); + id240_xelement = Reader.NameTable.Add(@"xelement"); + id42_Pet = Reader.NameTable.Add(@"Pet"); + id298_NoneSchemaFormListProperty = Reader.NameTable.Add(@"NoneSchemaFormListProperty"); + id49_httpexamplecom = Reader.NameTable.Add(@"http://example.com"); + id120_Item = Reader.NameTable.Add(@"BaseTypeWithShouldSerializeMethod"); + id231_Comment2 = Reader.NameTable.Add(@"Comment2"); + id76_Item = Reader.NameTable.Add(@"__TypeNameWithSpecialCharacters漢ñ"); + id68_DCStruct = Reader.NameTable.Add(@"DCStruct"); + id163_ArrayOfTypeA = Reader.NameTable.Add(@"ArrayOfTypeA"); + id145_Value2 = Reader.NameTable.Add(@"Value2"); + id64_ArrayOfAnyType = Reader.NameTable.Add(@"ArrayOfAnyType"); + id187_DefaultDTO = Reader.NameTable.Add(@"DefaultDTO"); + id192_DefaultDate = Reader.NameTable.Add(@"DefaultDate"); + id107_TypeWithXmlSchemaFormAttribute = Reader.NameTable.Add(@"TypeWithXmlSchemaFormAttribute"); + id108_MyXmlType = Reader.NameTable.Add(@"MyXmlType"); id253_NIntLProp = Reader.NameTable.Add(@"NIntLProp"); - id6_Item = Reader.NameTable.Add(@"TypeWithDateAndTimeOnlyProperties"); - id92_SByteEnum = Reader.NameTable.Add(@"SByteEnum"); - id173_Value = Reader.NameTable.Add(@"Value"); - id3_TypeWithXmlDocumentProperty = Reader.NameTable.Add(@"TypeWithXmlDocumentProperty"); - id109_Item = Reader.NameTable.Add(@"TypeWithSchemaFormInXmlAttribute"); - id14_TypeWithByteProperty = Reader.NameTable.Add(@"TypeWithByteProperty"); - id11_DateTimeTimeWrapper = Reader.NameTable.Add(@"DateTimeTimeWrapper"); - id114_TypeWithXmlQualifiedName = Reader.NameTable.Add(@"TypeWithXmlQualifiedName"); - id286_XmlIncludeProperty = Reader.NameTable.Add(@"XmlIncludeProperty"); - id155_ArrayOfDouble = Reader.NameTable.Add(@"ArrayOfDouble"); - id32_OrderedItem = Reader.NameTable.Add(@"OrderedItem"); - id158_ArrayOfTypeWithLinkedProperty = Reader.NameTable.Add(@"ArrayOfTypeWithLinkedProperty"); + id328_httptestcom = Reader.NameTable.Add(@"http://test.com"); + id103_Item = Reader.NameTable.Add(@"ClassImplementingIXmlSerializable"); id82_SimpleDC = Reader.NameTable.Add(@"SimpleDC"); - id181_Quantity = Reader.NameTable.Add(@"Quantity"); - id312_IntArrayValue = Reader.NameTable.Add(@"IntArrayValue"); - id45_Item = Reader.NameTable.Add(@"DefaultValuesSetToNegativeInfinity"); - id183_BinaryHexContent = Reader.NameTable.Add(@"BinaryHexContent"); - id37_dateTime = Reader.NameTable.Add(@"dateTime"); - id205_ByteProperty = Reader.NameTable.Add(@"ByteProperty"); - id289_XmlElementPropertyNode = Reader.NameTable.Add(@"XmlElementPropertyNode"); - id273_Some = Reader.NameTable.Add(@"Some"); - id35_DerivedClass1 = Reader.NameTable.Add(@"DerivedClass1"); - id315_DateContent = Reader.NameTable.Add(@"DateContent"); - id186_DTO2 = Reader.NameTable.Add(@"DTO2"); - id271_Id = Reader.NameTable.Add(@"Id"); - id201_NullableDefaultTime = Reader.NameTable.Add(@"NullableDefaultTime"); + id204_TimeSpanProperty2 = Reader.NameTable.Add(@"TimeSpanProperty2"); + id32_OrderedItem = Reader.NameTable.Add(@"OrderedItem"); + id153_ArrayOfString = Reader.NameTable.Add(@"ArrayOfString"); + id84_Item = Reader.NameTable.Add(@"http://schemas.xmlsoap.org/ws/2005/04/discovery"); + id67_TypeWithEnumMembers = Reader.NameTable.Add(@"TypeWithEnumMembers"); + id43_DefaultValuesSetToNaN = Reader.NameTable.Add(@"DefaultValuesSetToNaN"); id117_Item = Reader.NameTable.Add(@"TypeWithEnumPropertyHavingDefaultValue"); - id73_TypeA = Reader.NameTable.Add(@"TypeA"); - id195_NullableDefaultDate = Reader.NameTable.Add(@"NullableDefaultDate"); + id136_Person = Reader.NameTable.Add(@"Person"); + id185_DTO = Reader.NameTable.Add(@"DTO"); + id222_Items = Reader.NameTable.Add(@"Items"); + id41_Trumpet = Reader.NameTable.Add(@"Trumpet"); + id110_CustomDocument = Reader.NameTable.Add(@"CustomDocument"); + id295_MyField = Reader.NameTable.Add(@"MyField"); id219_Zip = Reader.NameTable.Add(@"Zip"); - id197_MyTime = Reader.NameTable.Add(@"MyTime"); - id145_Value2 = Reader.NameTable.Add(@"Value2"); + id223_SubTotal = Reader.NameTable.Add(@"SubTotal"); + id149_Item = Reader.NameTable.Add(@"TypeWithMismatchBetweenAttributeAndPropertyType"); + id100_TypeWithAnyAttribute = Reader.NameTable.Add(@"TypeWithAnyAttribute"); + id106_TypeWithPropertyNameSpecified = Reader.NameTable.Add(@"TypeWithPropertyNameSpecified"); + id195_NullableDefaultDate = Reader.NameTable.Add(@"NullableDefaultDate"); id211_EmployeeName = Reader.NameTable.Add(@"EmployeeName"); - id316_NameContent = Reader.NameTable.Add(@"NameContent"); - id161_XElement = Reader.NameTable.Add(@"XElement"); + id245_F2 = Reader.NameTable.Add(@"F2"); + id16_Animal = Reader.NameTable.Add(@"Animal"); id307_CharProperty = Reader.NameTable.Add(@"CharProperty"); + id139_LastName = Reader.NameTable.Add(@"LastName"); + id75_TypeHasArrayOfASerializedAsB = Reader.NameTable.Add(@"TypeHasArrayOfASerializedAsB"); + id229_Prop = Reader.NameTable.Add(@"Prop"); id95_UIntEnum = Reader.NameTable.Add(@"UIntEnum"); - id319_NMTOKENSContent = Reader.NameTable.Add(@"NMTOKENSContent"); - id322_Item = Reader.NameTable.Add(@"Item"); - id65_anyType = Reader.NameTable.Add(@"anyType"); - id275_Short = Reader.NameTable.Add(@"Short"); - id94_IntEnum = Reader.NameTable.Add(@"IntEnum"); - id4_TypeWithBinaryProperty = Reader.NameTable.Add(@"TypeWithBinaryProperty"); - id108_MyXmlType = Reader.NameTable.Add(@"MyXmlType"); - id277_Optionull = Reader.NameTable.Add(@"Optionull"); - id10_DateTimeDateWrapper = Reader.NameTable.Add(@"DateTimeDateWrapper"); - id232_DoubleField = Reader.NameTable.Add(@"DoubleField"); - id247_NIntAField = Reader.NameTable.Add(@"NIntAField"); - id84_Item = Reader.NameTable.Add(@"http://schemas.xmlsoap.org/ws/2005/04/discovery"); - id2_Item = Reader.NameTable.Add(@""); - id48_Document = Reader.NameTable.Add(@"Document"); - id217_City = Reader.NameTable.Add(@"City"); - id50_RootClass = Reader.NameTable.Add(@"RootClass"); - id236_IntValue = Reader.NameTable.Add(@"IntValue"); - id210_GroupVehicle = Reader.NameTable.Add(@"GroupVehicle"); - id282_XmlAttributeName = Reader.NameTable.Add(@"XmlAttributeName"); - id302_customElement = Reader.NameTable.Add(@"customElement"); - id101_KnownTypesThroughConstructor = Reader.NameTable.Add(@"KnownTypesThroughConstructor"); - id283_Word = Reader.NameTable.Add(@"Word"); - id126_Item = Reader.NameTable.Add(@"TypeWithArrayPropertyHavingChoice"); - id150_ArrayOfOrderedItem = Reader.NameTable.Add(@"ArrayOfOrderedItem"); - id90_WithNullables = Reader.NameTable.Add(@"WithNullables"); - id169_QualifiedParameter = Reader.NameTable.Add(@"QualifiedParameter"); - id153_ArrayOfString = Reader.NameTable.Add(@"ArrayOfString"); - id285_DecimalNumber = Reader.NameTable.Add(@"DecimalNumber"); - id323_Amount = Reader.NameTable.Add(@"Amount"); + id258_ByteArray = Reader.NameTable.Add(@"ByteArray"); + id184_Base64Content = Reader.NameTable.Add(@"Base64Content"); + id278_OptionalInt = Reader.NameTable.Add(@"OptionalInt"); + id226_X = Reader.NameTable.Add(@"X"); + id172_P2 = Reader.NameTable.Add(@"P2"); + id59_TypeWithGetOnlyArrayProperties = Reader.NameTable.Add(@"TypeWithGetOnlyArrayProperties"); + id133_Root = Reader.NameTable.Add(@"Root"); + id131_TypeWithFieldsOrdered = Reader.NameTable.Add(@"TypeWithFieldsOrdered"); + id125_Item = Reader.NameTable.Add(@"TypeWithTypesHavingCustomFormatter"); + id315_DateContent = Reader.NameTable.Add(@"DateContent"); + id255_Data = Reader.NameTable.Add(@"Data"); + id205_ByteProperty = Reader.NameTable.Add(@"ByteProperty"); + id177_Modulation = Reader.NameTable.Add(@"Modulation"); + id198_DefaultTime = Reader.NameTable.Add(@"DefaultTime"); + id242_DateTimeString = Reader.NameTable.Add(@"DateTimeString"); + id267_DateTimeProperty = Reader.NameTable.Add(@"DateTimeProperty"); + id119_TypeWithShouldSerializeMethod = Reader.NameTable.Add(@"TypeWithShouldSerializeMethod"); + id58_TypeWithGetSetArrayMembers = Reader.NameTable.Add(@"TypeWithGetSetArrayMembers"); + id86_ClassImplementsInterface = Reader.NameTable.Add(@"ClassImplementsInterface"); + id20_Vehicle = Reader.NameTable.Add(@"Vehicle"); id128_MoreChoices = Reader.NameTable.Add(@"MoreChoices"); - id305_TwoDArrayOfSimpleType = Reader.NameTable.Add(@"TwoDArrayOfSimpleType"); - id151_ArrayOfInt = Reader.NameTable.Add(@"ArrayOfInt"); - id227_Y = Reader.NameTable.Add(@"Y"); - id281_Struct2 = Reader.NameTable.Add(@"Struct2"); - id26_BaseIXmlSerializable = Reader.NameTable.Add(@"BaseIXmlSerializable"); - id13_Item = Reader.NameTable.Add(@"TypeWithDefaultTimeSpanProperty"); - id265_StringProperty = Reader.NameTable.Add(@"StringProperty"); - id212_value = Reader.NameTable.Add(@"value"); - id200_NullableTimeWithValue = Reader.NameTable.Add(@"NullableTimeWithValue"); - id56_TypeWithDateTimeStringProperty = Reader.NameTable.Add(@"TypeWithDateTimeStringProperty"); - id5_Item = Reader.NameTable.Add(@"TypeWithDateTimeOffsetProperties"); - id223_SubTotal = Reader.NameTable.Add(@"SubTotal"); - id266_IntProperty = Reader.NameTable.Add(@"IntProperty"); - id100_TypeWithAnyAttribute = Reader.NameTable.Add(@"TypeWithAnyAttribute"); + id314_QNameContent = Reader.NameTable.Add(@"QNameContent"); + id61_StructNotSerializable = Reader.NameTable.Add(@"StructNotSerializable"); + id6_Item = Reader.NameTable.Add(@"TypeWithDateAndTimeOnlyProperties"); + id48_Document = Reader.NameTable.Add(@"Document"); + id221_OrderDate = Reader.NameTable.Add(@"OrderDate"); id21_Employee = Reader.NameTable.Add(@"Employee"); - id324_IntField2 = Reader.NameTable.Add(@"IntField2"); - id112_Item = Reader.NameTable.Add(@"TypeWithNonPublicDefaultConstructor"); + id291_CustomXmlArrayProperty = Reader.NameTable.Add(@"CustomXmlArrayProperty"); + id54_XElementArrayWrapper = Reader.NameTable.Add(@"XElementArrayWrapper"); + id150_ArrayOfOrderedItem = Reader.NameTable.Add(@"ArrayOfOrderedItem"); + id228_Z = Reader.NameTable.Add(@"Z"); + id45_Item = Reader.NameTable.Add(@"DefaultValuesSetToNegativeInfinity"); + id275_Short = Reader.NameTable.Add(@"Short"); + id235_FloatProp = Reader.NameTable.Add(@"FloatProp"); + id29_PurchaseOrder = Reader.NameTable.Add(@"PurchaseOrder"); + id72_Item = Reader.NameTable.Add(@"TypeWithNullableBuiltInTypedMembers"); id299_Item = Reader.NameTable.Add(@"QualifiedSchemaFormListProperty"); - id124_Item = Reader.NameTable.Add(@"KnownTypesThroughConstructorWithValue"); - id46_RootElement = Reader.NameTable.Add(@"RootElement"); - id149_Item = Reader.NameTable.Add(@"TypeWithMismatchBetweenAttributeAndPropertyType"); - id190_Today = Reader.NameTable.Add(@"Today"); - id188_NullableDTO = Reader.NameTable.Add(@"NullableDTO"); - id320_Base64BinaryContent = Reader.NameTable.Add(@"Base64BinaryContent"); - id74_TypeB = Reader.NameTable.Add(@"TypeB"); - id231_Comment2 = Reader.NameTable.Add(@"Comment2"); - id86_ClassImplementsInterface = Reader.NameTable.Add(@"ClassImplementsInterface"); - id292_EnumValue = Reader.NameTable.Add(@"EnumValue"); - id103_Item = Reader.NameTable.Add(@"ClassImplementingIXmlSerializable"); - id41_Trumpet = Reader.NameTable.Add(@"Trumpet"); - id137_FirstName = Reader.NameTable.Add(@"FirstName"); - id162_ArrayOfSimpleType = Reader.NameTable.Add(@"ArrayOfSimpleType"); - id34_BaseClass1 = Reader.NameTable.Add(@"BaseClass1"); - id98_AttributeTesting = Reader.NameTable.Add(@"AttributeTesting"); - id67_TypeWithEnumMembers = Reader.NameTable.Add(@"TypeWithEnumMembers"); - id119_TypeWithShouldSerializeMethod = Reader.NameTable.Add(@"TypeWithShouldSerializeMethod"); - id304_MetricConfigUrl = Reader.NameTable.Add(@"MetricConfigUrl"); - id166_ArrayOfString1 = Reader.NameTable.Add(@"ArrayOfString1"); - id295_MyField = Reader.NameTable.Add(@"MyField"); - id36_ArrayOfDateTime = Reader.NameTable.Add(@"ArrayOfDateTime"); - id175_Children = Reader.NameTable.Add(@"Children"); - id313_DateTimeContent = Reader.NameTable.Add(@"DateTimeContent"); - id220_ShipTo = Reader.NameTable.Add(@"ShipTo"); - id31_Address = Reader.NameTable.Add(@"Address"); - id33_AliasedTestType = Reader.NameTable.Add(@"AliasedTestType"); - id43_DefaultValuesSetToNaN = Reader.NameTable.Add(@"DefaultValuesSetToNaN"); - id294_StrProperty = Reader.NameTable.Add(@"StrProperty"); - id215_BoolValue = Reader.NameTable.Add(@"BoolValue"); - id51_Parameter = Reader.NameTable.Add(@"Parameter"); - id206_Age = Reader.NameTable.Add(@"Age"); - id229_Prop = Reader.NameTable.Add(@"Prop"); - id79_DerivedClassWithSameProperty2 = Reader.NameTable.Add(@"DerivedClassWithSameProperty2"); - id53_XElementStruct = Reader.NameTable.Add(@"XElementStruct"); id264_Item = Reader.NameTable.Add(@"PropertyNameWithSpecialCharacters漢ñ"); - id130_ComplexChoiceB = Reader.NameTable.Add(@"ComplexChoiceB"); - id18_DogBreed = Reader.NameTable.Add(@"DogBreed"); - id96_LongEnum = Reader.NameTable.Add(@"LongEnum"); - id297_Item = Reader.NameTable.Add(@"UnqualifiedSchemaFormListProperty"); - id111_CustomElement = Reader.NameTable.Add(@"CustomElement"); - id115_TypeWith2DArrayProperty2 = Reader.NameTable.Add(@"TypeWith2DArrayProperty2"); - id317_NCNameContent = Reader.NameTable.Add(@"NCNameContent"); - id234_DoubleProp = Reader.NameTable.Add(@"DoubleProp"); - id235_FloatProp = Reader.NameTable.Add(@"FloatProp"); - id300_XmlAttributeForm = Reader.NameTable.Add(@"XmlAttributeForm"); + id157_ArrayOfInstrument = Reader.NameTable.Add(@"ArrayOfInstrument"); + id288_Item = Reader.NameTable.Add(@"XmlNamespaceDeclarationsProperty"); + id224_ShipCost = Reader.NameTable.Add(@"ShipCost"); + id173_Value = Reader.NameTable.Add(@"Value"); + id271_Id = Reader.NameTable.Add(@"Id"); + id15_TypeWithXmlNodeArrayProperty = Reader.NameTable.Add(@"TypeWithXmlNodeArrayProperty"); id85_EnumFlags = Reader.NameTable.Add(@"EnumFlags"); - id146_XmlSerializerAttributes = Reader.NameTable.Add(@"XmlSerializerAttributes"); - id199_NullableTime = Reader.NameTable.Add(@"NullableTime"); - id7_DateOnlyWrapper = Reader.NameTable.Add(@"DateOnlyWrapper"); - id177_Modulation = Reader.NameTable.Add(@"Modulation"); - id57_SimpleType = Reader.NameTable.Add(@"SimpleType"); - id52_XElementWrapper = Reader.NameTable.Add(@"XElementWrapper"); - id97_ULongEnum = Reader.NameTable.Add(@"ULongEnum"); - id42_Pet = Reader.NameTable.Add(@"Pet"); - id154_string = Reader.NameTable.Add(@"string"); - id70_BuiltInTypes = Reader.NameTable.Add(@"BuiltInTypes"); - id134_TypeClashB = Reader.NameTable.Add(@"TypeClashB"); - id202_TestValue = Reader.NameTable.Add(@"TestValue"); - id233_SingleField = Reader.NameTable.Add(@"SingleField"); - id54_XElementArrayWrapper = Reader.NameTable.Add(@"XElementArrayWrapper"); - id125_Item = Reader.NameTable.Add(@"TypeWithTypesHavingCustomFormatter"); - id208_LicenseNumber = Reader.NameTable.Add(@"LicenseNumber"); - id105_Item = Reader.NameTable.Add(@"StructImplementingIXmlSerializableWithParameterlessConstructor"); - id12_TypeWithTimeSpanProperty = Reader.NameTable.Add(@"TypeWithTimeSpanProperty"); + id283_Word = Reader.NameTable.Add(@"Word"); + id327_TestProperty = Reader.NameTable.Add(@"TestProperty"); + id18_DogBreed = Reader.NameTable.Add(@"DogBreed"); + id262_ListMember = Reader.NameTable.Add(@"ListMember"); + id181_Quantity = Reader.NameTable.Add(@"Quantity"); + id140_Name = Reader.NameTable.Add(@"Name"); + id88_SomeStruct = Reader.NameTable.Add(@"SomeStruct"); + id297_Item = Reader.NameTable.Add(@"UnqualifiedSchemaFormListProperty"); + id90_WithNullables = Reader.NameTable.Add(@"WithNullables"); + id321_HexBinaryContent = Reader.NameTable.Add(@"HexBinaryContent"); + id282_XmlAttributeName = Reader.NameTable.Add(@"XmlAttributeName"); + id200_NullableTimeWithValue = Reader.NameTable.Add(@"NullableTimeWithValue"); + id260_IntMember = Reader.NameTable.Add(@"IntMember"); + id232_DoubleField = Reader.NameTable.Add(@"DoubleField"); + id96_LongEnum = Reader.NameTable.Add(@"LongEnum"); + id71_TypeWithBuiltInTypedMembers = Reader.NameTable.Add(@"TypeWithBuiltInTypedMembers"); + id183_BinaryHexContent = Reader.NameTable.Add(@"BinaryHexContent"); id63_Item = Reader.NameTable.Add(@"TypeWithReadOnlyMyCollectionProperty"); - id238_refs = Reader.NameTable.Add(@"refs"); - id72_Item = Reader.NameTable.Add(@"TypeWithNullableBuiltInTypedMembers"); - id122_Item = Reader.NameTable.Add(@"TypeWithFieldBackedSpecifiedMember"); - id102_SimpleKnownTypeValue = Reader.NameTable.Add(@"SimpleKnownTypeValue"); - id163_ArrayOfTypeA = Reader.NameTable.Add(@"ArrayOfTypeA"); - id240_xelement = Reader.NameTable.Add(@"xelement"); - id194_NullableDateWithValue = Reader.NameTable.Add(@"NullableDateWithValue"); - id19_Group = Reader.NameTable.Add(@"Group"); - id248_IntLField = Reader.NameTable.Add(@"IntLField"); - id28_DerivedIXmlSerializable = Reader.NameTable.Add(@"DerivedIXmlSerializable"); - id136_Person = Reader.NameTable.Add(@"Person"); - id170_ArrayOfArrayOfSimpleType = Reader.NameTable.Add(@"ArrayOfArrayOfSimpleType"); - id326_strfld = Reader.NameTable.Add(@"strfld"); - id77_BaseClassWithSamePropertyName = Reader.NameTable.Add(@"BaseClassWithSamePropertyName"); - id29_PurchaseOrder = Reader.NameTable.Add(@"PurchaseOrder"); - id184_Base64Content = Reader.NameTable.Add(@"Base64Content"); - id179_Description = Reader.NameTable.Add(@"Description"); - id287_XmlEnumProperty = Reader.NameTable.Add(@"XmlEnumProperty"); - id87_WithStruct = Reader.NameTable.Add(@"WithStruct"); + id33_AliasedTestType = Reader.NameTable.Add(@"AliasedTestType"); + id27_Item = Reader.NameTable.Add(@"http://example.com/serializer-test-namespace"); + id302_customElement = Reader.NameTable.Add(@"customElement"); } } @@ -21503,136 +21527,136 @@ public override System.Collections.Hashtable TypedSerializers { get { if (typedSerializers == null) { System.Collections.Hashtable _tmp = new System.Collections.Hashtable(); + _tmp.Add(@"Animal::", new AnimalSerializer()); + _tmp.Add(@"XElementStruct::", new XElementStructSerializer()); + _tmp.Add(@"SerializationTypes.TypeNameClashB.TypeNameClash::", new TypeNameClashSerializer()); + _tmp.Add(@"SerializationTypes.TypeWithFieldsOrdered::", new TypeWithFieldsOrderedSerializer()); + _tmp.Add(@"SerializationTypes.TypeWithArrayPropertyHavingChoice::", new TypeWithArrayPropertyHavingChoiceSerializer()); + _tmp.Add(@"SerializationTypes.WithStruct::", new WithStructSerializer()); + _tmp.Add(@"SerializationTypes.SimpleKnownTypeValue::", new SimpleKnownTypeValueSerializer()); + _tmp.Add(@"AliasedTestType::", new AliasedTestTypeSerializer()); + _tmp.Add(@"XmlSerializableDerivedClass::", new XmlSerializableDerivedClassSerializer()); + _tmp.Add(@"SerializationTypes.TypeWithXmlQualifiedName::", new TypeWithXmlQualifiedNameSerializer()); + _tmp.Add(@"SerializationTypes.StructNotSerializable::", new StructNotSerializableSerializer()); + _tmp.Add(@"DateTimeDateWrapper::", new DateTimeDateWrapperSerializer()); + _tmp.Add(@"TypeWithXmlDocumentProperty::", new TypeWithXmlDocumentPropertySerializer()); + _tmp.Add(@"SerializationTypes.TypeWithMyCollectionField::", new TypeWithMyCollectionFieldSerializer()); + _tmp.Add(@"SerializationTypes.KnownTypesThroughConstructor::", new KnownTypesThroughConstructorSerializer()); + _tmp.Add(@"XmlSerializableBaseClass:http://example.com/serializer-test-namespace::True:", new XmlSerializableBaseClassSerializer()); + _tmp.Add(@"SerializationTypes.BuiltInTypes::", new BuiltInTypesSerializer()); + _tmp.Add(@"DefaultValuesSetToNegativeInfinity::", new DefaultValuesSetToNegativeInfinitySerializer()); + _tmp.Add(@"DerivedClass1::", new DerivedClass1Serializer()); + _tmp.Add(@"SerializationTypes.SomeStruct::", new SomeStructSerializer()); + _tmp.Add(@"TypeWithXmlElementProperty::", new TypeWithXmlElementPropertySerializer()); + _tmp.Add(@"SerializationTypes.TypeWithEnumPropertyHavingDefaultValue::", new TypeWithEnumPropertyHavingDefaultValueSerializer()); + _tmp.Add(@"Parameter::", new ParameterSerializer()); + _tmp.Add(@"Brass::", new BrassSerializer()); + _tmp.Add(@"SerializationTypes.BaseTypeWithShouldSerializeMethod::", new BaseTypeWithShouldSerializeMethodSerializer()); + _tmp.Add(@"SerializationTypes.TypeB::", new TypeBSerializer()); + _tmp.Add(@"SerializationTypes.StructImplementingIXmlSerializableWithoutParameterlessConstructor::", new StructImplementingIXmlSerializableWithoutParameterlessConstructorSerializer()); + _tmp.Add(@"SerializationTypes.TypeWithAnyAttribute::", new TypeWithAnyAttributeSerializer()); + _tmp.Add(@"SerializationTypes.TypeWithDateTimePropertyAsXmlTime::", new TypeWithDateTimePropertyAsXmlTimeSerializer()); + _tmp.Add(@"TypeWithLinkedProperty::", new TypeWithLinkedPropertySerializer()); + _tmp.Add(@"SerializationTypes.TypeWithSchemaFormInXmlAttribute::", new TypeWithSchemaFormInXmlAttributeSerializer()); + _tmp.Add(@"SerializationTypes.TypeWithTypeNameInXmlTypeAttribute::", new TypeWithTypeNameInXmlTypeAttributeSerializer()); _tmp.Add(@"SerializationTypes.DerivedTypeWithInheritedShouldSerialize::", new DerivedTypeWithInheritedShouldSerializeSerializer()); - _tmp.Add(@"SerializationTypes.ComplexChoiceB::", new ComplexChoiceBSerializer()); - _tmp.Add(@"SerializationTypes.TypeWithTypesHavingCustomFormatter::", new TypeWithTypesHavingCustomFormatterSerializer()); + _tmp.Add(@"SerializationTypes.TypeHasArrayOfASerializedAsB::", new TypeHasArrayOfASerializedAsBSerializer()); + _tmp.Add(@"SerializationTypes.ULongEnum::", new ULongEnumSerializer()); + _tmp.Add(@"SerializationTypes.LongEnum::", new LongEnumSerializer()); + _tmp.Add(@"DerivedClass::", new DerivedClassSerializer()); + _tmp.Add(@"BaseClass::", new BaseClassSerializer()); _tmp.Add(@"DateOnlyWrapper::", new DateOnlyWrapperSerializer()); - _tmp.Add(@"SerializationTypes.EnumFlags::", new EnumFlagsSerializer()); - _tmp.Add(@"SerializationTypes.TypeWithTypeNameInXmlTypeAttribute::", new TypeWithTypeNameInXmlTypeAttributeSerializer()); + _tmp.Add(@"DateTimeTimeWrapper::", new DateTimeTimeWrapperSerializer()); + _tmp.Add(@"SerializationTypes.NamespaceTypeNameClashContainer::Root:True:", new NamespaceTypeNameClashContainerSerializer()); + _tmp.Add(@"SerializationTypes.SimpleDC::", new SimpleDCSerializer()); + _tmp.Add(@"XElementArrayWrapper::", new XElementArrayWrapperSerializer()); + _tmp.Add(@"Orchestra::", new OrchestraSerializer()); + _tmp.Add(@"SerializationTypes.TypeWithBuiltInTypedMembers::", new TypeWithBuiltInTypedMembersSerializer()); + _tmp.Add(@"SerializationTypes.__TypeNameWithSpecialCharacters漢ñ::", new __TypeNameWithSpecialCharacters漢ñSerializer()); _tmp.Add(@"XElementWrapper::", new XElementWrapperSerializer()); - _tmp.Add(@"XmlSerializableDerivedClass::", new XmlSerializableDerivedClassSerializer()); - _tmp.Add(@"SimpleDerivedClass::", new SimpleDerivedClassSerializer()); + _tmp.Add(@"SerializationTypes.XmlSerializerAttributes::AttributeTesting:False:", new XmlSerializerAttributesSerializer()); _tmp.Add(@"DogBreed::", new DogBreedSerializer()); - _tmp.Add(@"XElementArrayWrapper::", new XElementArrayWrapperSerializer()); + _tmp.Add(@"SerializationTypes.DerivedClassWithSameProperty::", new DerivedClassWithSamePropertySerializer()); + _tmp.Add(@"SerializationTypes.TypeWithXmlTextAttributeOnArray:http://schemas.xmlsoap.org/ws/2005/04/discovery::False:", new TypeWithXmlTextAttributeOnArraySerializer()); + _tmp.Add(@"Instrument::", new InstrumentSerializer()); + _tmp.Add(@"SerializationTypes.TypeNameClashA.TypeNameClash::", new TypeNameClashSerializer1()); + _tmp.Add(@"SerializationTypes.MyList::", new MyListSerializer()); + _tmp.Add(@"SerializationTypes.EnumFlags::", new EnumFlagsSerializer()); + _tmp.Add(@"SerializationTypes.TypeWithReadOnlyMyCollectionProperty::", new TypeWithReadOnlyMyCollectionPropertySerializer()); _tmp.Add(@"SerializationTypes.IntEnum::", new IntEnumSerializer()); - _tmp.Add(@"SerializationTypes.DerivedClassWithSameProperty2::", new DerivedClassWithSameProperty2Serializer()); - _tmp.Add(@"SerializationTypes.KnownTypesThroughConstructorWithArrayProperties::", new KnownTypesThroughConstructorWithArrayPropertiesSerializer()); - _tmp.Add(@"Vehicle::", new VehicleSerializer()); + _tmp.Add(@"SerializationTypes.ByteEnum::", new ByteEnumSerializer()); + _tmp.Add(@"SerializationTypes.UIntEnum::", new UIntEnumSerializer()); + _tmp.Add(@"Pet::", new PetSerializer()); + _tmp.Add(@"DefaultValuesSetToNaN::", new DefaultValuesSetToNaNSerializer()); + _tmp.Add(@"SerializationTypes.MyEnum::", new MyEnumSerializer()); + _tmp.Add(@"SerializationTypes.TypeA::", new TypeASerializer()); + _tmp.Add(@"SerializationTypes.TypeWith2DArrayProperty2::", new TypeWith2DArrayProperty2Serializer()); _tmp.Add(@"TypeWithDateAndTimeOnlyProperties::", new TypeWithDateAndTimeOnlyPropertiesSerializer()); - _tmp.Add(@"SerializationTypes.ShortEnum::", new ShortEnumSerializer()); - _tmp.Add(@"SerializationTypes.WithEnums::", new WithEnumsSerializer()); - _tmp.Add(@"SerializationTypes.ServerSettings::", new ServerSettingsSerializer()); - _tmp.Add(@"TypeWithXmlElementProperty::", new TypeWithXmlElementPropertySerializer()); + _tmp.Add(@"SerializationTypes.TypeWithGetOnlyArrayProperties::", new TypeWithGetOnlyArrayPropertiesSerializer()); + _tmp.Add(@"SerializationTypes.TypeWithNonPublicDefaultConstructor::", new TypeWithNonPublicDefaultConstructorSerializer()); + _tmp.Add(@"SerializationTypes.TypeWithPropertyNameSpecified::", new TypeWithPropertyNameSpecifiedSerializer()); + _tmp.Add(@"SimpleDerivedClass::", new SimpleDerivedClassSerializer()); + _tmp.Add(@"BaseClass1::", new BaseClass1Serializer()); + _tmp.Add(@"SerializationTypes.BaseClassWithSamePropertyName::", new BaseClassWithSamePropertyNameSerializer()); + _tmp.Add(@"Group::", new GroupSerializer()); _tmp.Add(@"Address::", new AddressSerializer()); - _tmp.Add(@"RootClass::", new RootClassSerializer()); - _tmp.Add(@"SerializationTypes.MoreChoices::", new MoreChoicesSerializer()); - _tmp.Add(@"SerializationTypes.ClassImplementingIXmlSerializable::", new ClassImplementingIXmlSerializableSerializer()); + _tmp.Add(@"SerializationTypes.ComplexChoiceB::", new ComplexChoiceBSerializer()); _tmp.Add(@"SerializationTypes.SimpleType::", new SimpleTypeSerializer()); - _tmp.Add(@"SerializationTypes.KnownTypesThroughConstructorWithValue::", new KnownTypesThroughConstructorWithValueSerializer()); - _tmp.Add(@"DefaultValuesSetToPositiveInfinity::", new DefaultValuesSetToPositiveInfinitySerializer()); - _tmp.Add(@"SerializationTypes.TypeWithFieldBackedSpecifiedMember::", new TypeWithFieldBackedSpecifiedMemberSerializer()); + _tmp.Add(@"SerializationTypes.ServerSettings::", new ServerSettingsSerializer()); _tmp.Add(@"SerializationTypes.TypeWithEnumFlagPropertyHavingDefaultValue::", new TypeWithEnumFlagPropertyHavingDefaultValueSerializer()); - _tmp.Add(@"SerializationTypes.SimpleKnownTypeValue::", new SimpleKnownTypeValueSerializer()); - _tmp.Add(@"TimeOnlyAsXsdTimeWrapper::", new TimeOnlyAsXsdTimeWrapperSerializer()); - _tmp.Add(@"TypeWithLinkedProperty::", new TypeWithLinkedPropertySerializer()); - _tmp.Add(@"TimeOnlyWrapper::", new TimeOnlyWrapperSerializer()); - _tmp.Add(@"SerializationTypes.TypeWithNullableBuiltInTypedMembers::", new TypeWithNullableBuiltInTypedMembersSerializer()); - _tmp.Add(@"SerializationTypes.TypeWith2DArrayProperty2::", new TypeWith2DArrayProperty2Serializer()); - _tmp.Add(@"SerializationTypes.TypeWithPropertyNameSpecified::", new TypeWithPropertyNameSpecifiedSerializer()); - _tmp.Add(@"SerializationTypes.StructNotSerializable::", new StructNotSerializableSerializer()); - _tmp.Add(@"TypeWithXmlDocumentProperty::", new TypeWithXmlDocumentPropertySerializer()); - _tmp.Add(@"SerializationTypes.TypeWithXmlSchemaFormAttribute:::True:", new TypeWithXmlSchemaFormAttributeSerializer()); - _tmp.Add(@"SerializationTypes.DCClassWithEnumAndStruct::", new DCClassWithEnumAndStructSerializer()); - _tmp.Add(@"SerializationTypes.TypeNameClashA.TypeNameClash::", new TypeNameClashSerializer1()); - _tmp.Add(@"Instrument::", new InstrumentSerializer()); - _tmp.Add(@"SerializationTypes.KnownTypesThroughConstructor::", new KnownTypesThroughConstructorSerializer()); - _tmp.Add(@"SerializationTypes.BaseClassWithSamePropertyName::", new BaseClassWithSamePropertyNameSerializer()); - _tmp.Add(@"Trumpet::", new TrumpetSerializer()); + _tmp.Add(@"SerializationTypes.CustomElement::", new CustomElementSerializer()); + _tmp.Add(@"SerializationTypes.TypeWithArraylikeMembers::", new TypeWithArraylikeMembersSerializer()); + _tmp.Add(@"SerializationTypes.TypeWithShouldSerializeMethod::", new TypeWithShouldSerializeMethodSerializer()); + _tmp.Add(@"Dog::", new DogSerializer()); + _tmp.Add(@"SerializationTypes.SByteEnum::", new SByteEnumSerializer()); _tmp.Add(@"SerializationTypes.ComplexChoiceA::", new ComplexChoiceASerializer()); - _tmp.Add(@"SerializationTypes.TypeWithXmlQualifiedName::", new TypeWithXmlQualifiedNameSerializer()); - _tmp.Add(@"SerializationTypes.TypeWithXmlTextAttributeOnArray:http://schemas.xmlsoap.org/ws/2005/04/discovery::False:", new TypeWithXmlTextAttributeOnArraySerializer()); - _tmp.Add(@"DateTimeOffsetIXmlSerializableContainer::", new DateTimeOffsetIXmlSerializableContainerSerializer()); _tmp.Add(@"TypeWithMismatchBetweenAttributeAndPropertyType::RootElement:True:", new TypeWithMismatchBetweenAttributeAndPropertyTypeSerializer()); - _tmp.Add(@"Employee::", new EmployeeSerializer()); - _tmp.Add(@"AliasedTestType::", new AliasedTestTypeSerializer()); - _tmp.Add(@"SerializationTypes.ByteEnum::", new ByteEnumSerializer()); - _tmp.Add(@"SerializationTypes.MyEnum::", new MyEnumSerializer()); - _tmp.Add(@"SerializationTypes.TypeWithGetOnlyArrayProperties::", new TypeWithGetOnlyArrayPropertiesSerializer()); - _tmp.Add(@"DefaultValuesSetToNegativeInfinity::", new DefaultValuesSetToNegativeInfinitySerializer()); - _tmp.Add(@"Outer+Person::", new PersonSerializer()); + _tmp.Add(@"TimeOnlyWrapper::", new TimeOnlyWrapperSerializer()); + _tmp.Add(@"SerializationTypes.TypeWithEnumMembers::", new TypeWithEnumMembersSerializer()); + _tmp.Add(@"SerializationTypes.CustomDocument::", new CustomDocumentSerializer()); _tmp.Add(@"SerializationTypes.TypeWithKnownTypesOfCollectionsWithConflictingXmlName::", new TypeWithKnownTypesOfCollectionsWithConflictingXmlNameSerializer()); - _tmp.Add(@"Orchestra::", new OrchestraSerializer()); - _tmp.Add(@"DerivedClass::", new DerivedClassSerializer()); - _tmp.Add(@"SerializationTypes.TypeWithGetSetArrayMembers::", new TypeWithGetSetArrayMembersSerializer()); - _tmp.Add(@"SerializationTypes.WithNullables::", new WithNullablesSerializer()); - _tmp.Add(@"SerializationTypes.TypeWithArrayPropertyHavingChoice::", new TypeWithArrayPropertyHavingChoiceSerializer()); - _tmp.Add(@"SerializationTypes.TypeHasArrayOfASerializedAsB::", new TypeHasArrayOfASerializedAsBSerializer()); - _tmp.Add(@"Dog::", new DogSerializer()); - _tmp.Add(@"DerivedClass1::", new DerivedClass1Serializer()); - _tmp.Add(@"SimpleBaseClass::", new SimpleBaseClassSerializer()); - _tmp.Add(@"Pet::", new PetSerializer()); - _tmp.Add(@"SerializationTypes.TypeWithMyCollectionField::", new TypeWithMyCollectionFieldSerializer()); + _tmp.Add(@"SerializationTypes.MoreChoices::", new MoreChoicesSerializer()); + _tmp.Add(@"RootClass::", new RootClassSerializer()); + _tmp.Add(@"SerializationTypes.ShortEnum::", new ShortEnumSerializer()); + _tmp.Add(@"SerializationTypes.TypeWithPropertiesHavingDefaultValue::", new TypeWithPropertiesHavingDefaultValueSerializer()); + _tmp.Add(@"DateTimeOffsetIXmlSerializableContainer::", new DateTimeOffsetIXmlSerializableContainerSerializer()); _tmp.Add(@"SerializationTypes.DCStruct::", new DCStructSerializer()); - _tmp.Add(@"SerializationTypes.StructImplementingIXmlSerializableWithParameterlessConstructor::", new StructImplementingIXmlSerializableWithParameterlessConstructorSerializer()); - _tmp.Add(@"SerializationTypes.TypeWithArraylikeMembers::", new TypeWithArraylikeMembersSerializer()); - _tmp.Add(@"SerializationTypes.TypeWithPropertyHavingComplexChoice::", new TypeWithPropertyHavingComplexChoiceSerializer()); - _tmp.Add(@"SerializationTypes.ItemChoiceType::", new ItemChoiceTypeSerializer()); - _tmp.Add(@"SerializationTypes.SimpleDC::", new SimpleDCSerializer()); - _tmp.Add(@"SerializationTypes.XmlSerializerAttributes::AttributeTesting:False:", new XmlSerializerAttributesSerializer()); - _tmp.Add(@"OrderedItem::", new OrderedItemSerializer()); - _tmp.Add(@"SerializationTypes.CustomElement::", new CustomElementSerializer()); - _tmp.Add(@"BaseClass1::", new BaseClass1Serializer()); - _tmp.Add(@"SerializationTypes.__TypeNameWithSpecialCharacters漢ñ::", new __TypeNameWithSpecialCharacters漢ñSerializer()); - _tmp.Add(@"SerializationTypes.TypeWithDateTimePropertyAsXmlTime::", new TypeWithDateTimePropertyAsXmlTimeSerializer()); - _tmp.Add(@"SerializationTypes.TypeWithBuiltInTypedMembers::", new TypeWithBuiltInTypedMembersSerializer()); - _tmp.Add(@"Animal::", new AnimalSerializer()); - _tmp.Add(@"SerializationTypes.TypeWithShouldSerializeMethod::", new TypeWithShouldSerializeMethodSerializer()); - _tmp.Add(@"SerializationTypes.TypeWithDateTimeStringProperty::", new TypeWithDateTimeStringPropertySerializer()); - _tmp.Add(@"SerializationTypes.TypeWithFieldsOrdered::", new TypeWithFieldsOrderedSerializer()); - _tmp.Add(@"Group::", new GroupSerializer()); - _tmp.Add(@"SerializationTypes.CustomDocument::", new CustomDocumentSerializer()); - _tmp.Add(@"SerializationTypes.ClassImplementsInterface::", new ClassImplementsInterfaceSerializer()); - _tmp.Add(@"SerializationTypes.LongEnum::", new LongEnumSerializer()); - _tmp.Add(@"SerializationTypes.DerivedClassWithSameProperty::", new DerivedClassWithSamePropertySerializer()); - _tmp.Add(@"Parameter::", new ParameterSerializer()); - _tmp.Add(@"SerializationTypes.SByteEnum::", new SByteEnumSerializer()); - _tmp.Add(@"SerializationTypes.ULongEnum::", new ULongEnumSerializer()); + _tmp.Add(@"TimeOnlyAsXsdTimeWrapper::", new TimeOnlyAsXsdTimeWrapperSerializer()); + _tmp.Add(@"TypeWithByteProperty::", new TypeWithBytePropertySerializer()); _tmp.Add(@"SerializationTypes.TypeWithByteArrayAsXmlText::", new TypeWithByteArrayAsXmlTextSerializer()); - _tmp.Add(@"TypeWithTimeSpanProperty::", new TypeWithTimeSpanPropertySerializer()); - _tmp.Add(@"MsgDocumentType:http://example.com:Document:True:", new MsgDocumentTypeSerializer()); - _tmp.Add(@"SerializationTypes.StructImplementingIXmlSerializableWithoutParameterlessConstructor::", new StructImplementingIXmlSerializableWithoutParameterlessConstructorSerializer()); - _tmp.Add(@"SerializationTypes.NamespaceTypeNameClashContainer::Root:True:", new NamespaceTypeNameClashContainerSerializer()); - _tmp.Add(@"SerializationTypes.TypeWithEnumPropertyHavingDefaultValue::", new TypeWithEnumPropertyHavingDefaultValueSerializer()); - _tmp.Add(@"DateTimeTimeWrapper::", new DateTimeTimeWrapperSerializer()); - _tmp.Add(@"MyCollection1::", new MyCollection1Serializer()); - _tmp.Add(@"TypeWithDateTimeOffsetProperties::", new TypeWithDateTimeOffsetPropertiesSerializer()); - _tmp.Add(@"SerializationTypes.WithStruct::", new WithStructSerializer()); - _tmp.Add(@"SerializationTypes.TypeWithAnyAttribute::", new TypeWithAnyAttributeSerializer()); - _tmp.Add(@"SerializationTypes.BuiltInTypes::", new BuiltInTypesSerializer()); _tmp.Add(@"SerializationTypes.CustomAttribute::", new CustomAttributeSerializer()); - _tmp.Add(@"SerializationTypes.TypeWithReadOnlyMyCollectionProperty::", new TypeWithReadOnlyMyCollectionPropertySerializer()); - _tmp.Add(@"SerializationTypes.TypeWithNonPublicDefaultConstructor::", new TypeWithNonPublicDefaultConstructorSerializer()); - _tmp.Add(@"XmlSerializableBaseClass:http://example.com/serializer-test-namespace::True:", new XmlSerializableBaseClassSerializer()); - _tmp.Add(@"TypeWithBinaryProperty::", new TypeWithBinaryPropertySerializer()); - _tmp.Add(@"SerializationTypes.TypeWithEnumMembers::", new TypeWithEnumMembersSerializer()); - _tmp.Add(@"SerializationTypes.SomeStruct::", new SomeStructSerializer()); + _tmp.Add(@"SerializationTypes.ItemChoiceType::", new ItemChoiceTypeSerializer()); + _tmp.Add(@"Vehicle::", new VehicleSerializer()); _tmp.Add(@"TypeWithDefaultTimeSpanProperty::", new TypeWithDefaultTimeSpanPropertySerializer()); - _tmp.Add(@"SerializationTypes.UIntEnum::", new UIntEnumSerializer()); - _tmp.Add(@"SerializationTypes.TypeWithSchemaFormInXmlAttribute::", new TypeWithSchemaFormInXmlAttributeSerializer()); - _tmp.Add(@"SerializationTypes.BaseTypeWithShouldSerializeMethod::", new BaseTypeWithShouldSerializeMethodSerializer()); - _tmp.Add(@"BaseClass::", new BaseClassSerializer()); - _tmp.Add(@"XElementStruct::", new XElementStructSerializer()); - _tmp.Add(@"Brass::", new BrassSerializer()); - _tmp.Add(@"DateTimeDateWrapper::", new DateTimeDateWrapperSerializer()); - _tmp.Add(@"TypeWithByteProperty::", new TypeWithBytePropertySerializer()); + _tmp.Add(@"DefaultValuesSetToPositiveInfinity::", new DefaultValuesSetToPositiveInfinitySerializer()); + _tmp.Add(@"SerializationTypes.TypeWithXmlSchemaFormAttribute:::True:", new TypeWithXmlSchemaFormAttributeSerializer()); + _tmp.Add(@"SerializationTypes.TypeWithPropertyHavingComplexChoice::", new TypeWithPropertyHavingComplexChoiceSerializer()); + _tmp.Add(@"SerializationTypes.KnownTypesThroughConstructorWithArrayProperties::", new KnownTypesThroughConstructorWithArrayPropertiesSerializer()); _tmp.Add(@"TypeWithXmlNodeArrayProperty:::True:", new TypeWithXmlNodeArrayPropertySerializer()); - _tmp.Add(@"SerializationTypes.TypeB::", new TypeBSerializer()); - _tmp.Add(@"SerializationTypes.MyList::", new MyListSerializer()); - _tmp.Add(@"SerializationTypes.TypeWithPropertiesHavingDefaultValue::", new TypeWithPropertiesHavingDefaultValueSerializer()); + _tmp.Add(@"TypeWithDateTimeOffsetProperties::", new TypeWithDateTimeOffsetPropertiesSerializer()); _tmp.Add(@"PurchaseOrder:http://www.contoso1.com:PurchaseOrder:False:", new PurchaseOrderSerializer()); - _tmp.Add(@"DefaultValuesSetToNaN::", new DefaultValuesSetToNaNSerializer()); - _tmp.Add(@"SerializationTypes.TypeA::", new TypeASerializer()); - _tmp.Add(@"SerializationTypes.TypeNameClashB.TypeNameClash::", new TypeNameClashSerializer()); + _tmp.Add(@"MyCollection1::", new MyCollection1Serializer()); + _tmp.Add(@"SerializationTypes.TypeWithTypesHavingCustomFormatter::", new TypeWithTypesHavingCustomFormatterSerializer()); + _tmp.Add(@"TypeWithBinaryProperty::", new TypeWithBinaryPropertySerializer()); + _tmp.Add(@"SerializationTypes.KnownTypesThroughConstructorWithValue::", new KnownTypesThroughConstructorWithValueSerializer()); + _tmp.Add(@"SerializationTypes.TypeWithDateTimeStringProperty::", new TypeWithDateTimeStringPropertySerializer()); + _tmp.Add(@"MsgDocumentType:http://example.com:Document:True:", new MsgDocumentTypeSerializer()); + _tmp.Add(@"SerializationTypes.StructImplementingIXmlSerializableWithParameterlessConstructor::", new StructImplementingIXmlSerializableWithParameterlessConstructorSerializer()); + _tmp.Add(@"SerializationTypes.DerivedClassWithSameProperty2::", new DerivedClassWithSameProperty2Serializer()); + _tmp.Add(@"SimpleBaseClass::", new SimpleBaseClassSerializer()); + _tmp.Add(@"SerializationTypes.DCClassWithEnumAndStruct::", new DCClassWithEnumAndStructSerializer()); + _tmp.Add(@"SerializationTypes.ClassImplementsInterface::", new ClassImplementsInterfaceSerializer()); + _tmp.Add(@"TypeWithTimeSpanProperty::", new TypeWithTimeSpanPropertySerializer()); + _tmp.Add(@"SerializationTypes.TypeWithFieldBackedSpecifiedMember::", new TypeWithFieldBackedSpecifiedMemberSerializer()); + _tmp.Add(@"SerializationTypes.WithEnums::", new WithEnumsSerializer()); + _tmp.Add(@"Employee::", new EmployeeSerializer()); + _tmp.Add(@"OrderedItem::", new OrderedItemSerializer()); + _tmp.Add(@"SerializationTypes.TypeWithGetSetArrayMembers::", new TypeWithGetSetArrayMembersSerializer()); + _tmp.Add(@"SerializationTypes.ClassImplementingIXmlSerializable::", new ClassImplementingIXmlSerializableSerializer()); + _tmp.Add(@"SerializationTypes.WithNullables::", new WithNullablesSerializer()); + _tmp.Add(@"Trumpet::", new TrumpetSerializer()); + _tmp.Add(@"SerializationTypes.TypeWithNullableBuiltInTypedMembers::", new TypeWithNullableBuiltInTypedMembersSerializer()); + _tmp.Add(@"Outer+Person::", new PersonSerializer()); if (typedSerializers == null) typedSerializers = _tmp; } return typedSerializers; diff --git a/src/runtime/src/libraries/System.Diagnostics.Process/src/Microsoft/Win32/SafeHandles/SafeProcessHandle.Unix.cs b/src/runtime/src/libraries/System.Diagnostics.Process/src/Microsoft/Win32/SafeHandles/SafeProcessHandle.Unix.cs index e78f8c8acf8c..258c5edbc54c 100644 --- a/src/runtime/src/libraries/System.Diagnostics.Process/src/Microsoft/Win32/SafeHandles/SafeProcessHandle.Unix.cs +++ b/src/runtime/src/libraries/System.Diagnostics.Process/src/Microsoft/Win32/SafeHandles/SafeProcessHandle.Unix.cs @@ -374,7 +374,7 @@ private static SafeProcessHandle StartWithShellExecute(ProcessStartInfo startInf if (verb != string.Empty && !string.Equals(verb, "open", StringComparison.OrdinalIgnoreCase)) { - throw new Win32Exception(Interop.Errors.ERROR_NO_ASSOCIATION); + throw new Win32Exception(Interop.Errors.ERROR_NO_ASSOCIATION, SR.Format(SR.UseShellExecuteVerbNotSupported, verb)); } // On Windows, UseShellExecute of executables and scripts causes those files to be executed. @@ -405,7 +405,7 @@ private static SafeProcessHandle StartWithShellExecute(ProcessStartInfo startInf } // use default program to open file/url - filename = Process.GetPathToOpenFile() ?? throw new Win32Exception(Interop.Errors.ERROR_NO_ASSOCIATION); + filename = Process.GetPathToOpenFile() ?? throw new Win32Exception(Interop.Errors.ERROR_NO_ASSOCIATION, SR.UseShellExecuteNoOpenProgram); string[] openFileArgv = ProcessUtils.ParseArgv(startInfo, filename, ignoreArguments: true); SafeProcessHandle result = ForkAndExecProcess( diff --git a/src/runtime/src/libraries/System.Diagnostics.Process/src/Resources/Strings.resx b/src/runtime/src/libraries/System.Diagnostics.Process/src/Resources/Strings.resx index df17778b76ff..ee9ffac8b7ab 100644 --- a/src/runtime/src/libraries/System.Diagnostics.Process/src/Resources/Strings.resx +++ b/src/runtime/src/libraries/System.Diagnostics.Process/src/Resources/Strings.resx @@ -390,4 +390,10 @@ The callback must return a positive process ID for the newly created process. + + The verb '{0}' is not supported for UseShellExecute on this platform. Only the default verb (an empty string or "open") is supported. + + + No program was found to handle opening files or URLs with UseShellExecute on this platform. Ensure one such as 'xdg-open' or 'open' is installed and available on the PATH. + diff --git a/src/runtime/src/libraries/System.Net.Http/src/Resources/Strings.resx b/src/runtime/src/libraries/System.Net.Http/src/Resources/Strings.resx index bafb9a33c7da..3f166bb04d13 100644 --- a/src/runtime/src/libraries/System.Net.Http/src/Resources/Strings.resx +++ b/src/runtime/src/libraries/System.Net.Http/src/Resources/Strings.resx @@ -501,6 +501,9 @@ Unable to write content to request stream; content would exceed Content-Length. + + The HTTP/3 server attempted to reference the static table index {0}, which does not exist. + The HTTP/3 server attempted to reference a dynamic table index that does not exist. @@ -592,7 +595,7 @@ The HTTP/1.1 response chunk was too large. - Failed to establish web socket connection over HTTP/2 because extended CONNECT is not supported. Try to downgrade the request version to HTTP/1.1. + The HTTP/2 server does not support extended CONNECT requests. Try to downgrade the request version to HTTP/1.1. The HTTP/2 server didn't respond to a ping request within the configured KeepAlivePingDelay. diff --git a/src/runtime/src/libraries/System.Net.Http/tests/StressTests/HttpStress/HttpStress.csproj b/src/runtime/src/libraries/System.Net.Http/tests/StressTests/HttpStress/HttpStress.csproj index 55c0d1e2d7fc..46dcb42d89af 100644 --- a/src/runtime/src/libraries/System.Net.Http/tests/StressTests/HttpStress/HttpStress.csproj +++ b/src/runtime/src/libraries/System.Net.Http/tests/StressTests/HttpStress/HttpStress.csproj @@ -5,7 +5,7 @@ enable true - https://api.nuget.org/v3/index.json;https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-libraries/nuget/v3/index.json + https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public/nuget/v3/index.json;https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-libraries/nuget/v3/index.json diff --git a/src/runtime/src/libraries/System.Net.HttpListener/src/System/Net/Managed/HttpListenerRequest.Managed.cs b/src/runtime/src/libraries/System.Net.HttpListener/src/System/Net/Managed/HttpListenerRequest.Managed.cs index 098782eec221..95157b7b4555 100644 --- a/src/runtime/src/libraries/System.Net.HttpListener/src/System/Net/Managed/HttpListenerRequest.Managed.cs +++ b/src/runtime/src/libraries/System.Net.HttpListener/src/System/Net/Managed/HttpListenerRequest.Managed.cs @@ -208,26 +208,20 @@ internal void FinishInitialization() internal void AddHeader(string header) { int colon = header.IndexOf(':'); - if (colon == -1 || colon == 0) + if (colon <= 0) { _context.ErrorMessage = HttpStatusDescription.Get(400); _context.ErrorStatus = 400; return; } - string name = header.AsSpan(0, colon).Trim().ToString(); - string val = header.AsSpan(colon + 1).Trim().ToString(); + string name = header.AsSpan(0, colon).ToString(); + string val = header.AsSpan(colon + 1).Trim(" \t").ToString(); if (name.Equals("content-length", StringComparison.OrdinalIgnoreCase)) { - // To match Windows behavior: - // Content lengths >= 0 and <= long.MaxValue are accepted as is. - // Content lengths > long.MaxValue and <= ulong.MaxValue are treated as 0. - // Content lengths < 0 cause the requests to fail. - // Other input is a failure, too. - long parsedContentLength = - ulong.TryParse(val, out ulong parsedUlongContentLength) ? (parsedUlongContentLength <= long.MaxValue ? (long)parsedUlongContentLength : 0) : - long.Parse(val); - if (parsedContentLength < 0 || (_clSet && parsedContentLength != _contentLength)) + // Match the Windows parser shape: strict decimal parsing, and reject on parse failure. + bool success = long.TryParse(val, NumberStyles.None, CultureInfo.InvariantCulture.NumberFormat, out long parsedContentLength); + if (!success || (_clSet && parsedContentLength != _contentLength)) { _context.ErrorMessage = "Invalid Content-Length."; } diff --git a/src/runtime/src/libraries/System.Net.HttpListener/src/System/Net/Windows/WebSockets/WebSocketBase.cs b/src/runtime/src/libraries/System.Net.HttpListener/src/System/Net/Windows/WebSockets/WebSocketBase.cs index 982a4766538d..a574b3890bf8 100644 --- a/src/runtime/src/libraries/System.Net.HttpListener/src/System/Net/Windows/WebSockets/WebSocketBase.cs +++ b/src/runtime/src/libraries/System.Net.HttpListener/src/System/Net/Windows/WebSockets/WebSocketBase.cs @@ -636,6 +636,13 @@ private async Task CloseAsyncCore(WebSocketCloseStatus closeStatus, { _closeReceivedTaskCompletionSource ??= new TaskCompletionSource(); + // _thisLock MUST be released before starting the CloseOutput operation: it acquires the + // SessionHandle-lock, which MUST always be acquired before _thisLock (see TakeLocks). + // Acquiring the locks in the opposite order here would deadlock with a thread that is + // processing a received close frame, as that one holds the SessionHandle-lock while + // acquiring _thisLock in StartOnCloseReceived. + ReleaseLock(_thisLock, ref lockTaken); + closeOutputTask = CloseOutputAsync(closeStatus, statusDescription, linkedCancellationToken); @@ -716,9 +723,13 @@ private async Task CloseAsyncCore(WebSocketCloseStatus closeStatus, ArraySegment closeMessageBuffer = new ArraySegment(new byte[HttpWebSocket.MinReceiveBufferSize]); EnsureReceiveOperation(); + + // As above, _thisLock MUST be released before starting the receive operation, because + // WebSocketOperation.Process acquires the SessionHandle-lock. + ReleaseLock(_thisLock, ref lockTaken); + Task receiveAsyncTask = _receiveOperation!.Process(closeMessageBuffer, linkedCancellationToken); - ReleaseLock(_thisLock, ref lockTaken); WebSocketReceiveResult? receiveResult = null; try @@ -816,6 +827,11 @@ private async Task CloseAsyncCore(WebSocketCloseStatus closeStatus, catch (Exception exception) { bool aborted = linkedCancellationToken.IsCancellationRequested; + + // As above, _thisLock MUST be released before calling Abort, because it acquires the + // SessionHandle-lock. + ReleaseLock(_thisLock, ref lockTaken); + Abort(); ThrowIfConvertibleException(nameof(CloseAsync), exception, cancellationToken, aborted); throw; diff --git a/src/runtime/src/libraries/System.Net.HttpListener/tests/HttpListenerRequestTests.cs b/src/runtime/src/libraries/System.Net.HttpListener/tests/HttpListenerRequestTests.cs index 9e32572bb832..b6f41a169e72 100644 --- a/src/runtime/src/libraries/System.Net.HttpListener/tests/HttpListenerRequestTests.cs +++ b/src/runtime/src/libraries/System.Net.HttpListener/tests/HttpListenerRequestTests.cs @@ -126,8 +126,6 @@ public async Task ContentEncoding_NoBody_ReturnsDefault() [Theory] [InlineData("POST", "Content-Length: 9223372036854775807", 9223372036854775807, true)] // long.MaxValue - [InlineData("POST", "Content-Length: 9223372036854775808", 0, false)] // long.MaxValue + 1 - [InlineData("POST", "Content-Length: 18446744073709551615 ", 0, false)] // ulong.MaxValue [InlineData("POST", "Content-Length: 0", 0, false)] [InlineData("PUT", "Content-Length: 0", 0, false)] [InlineData("PUT", "Content-Length: 1", 1, true)] diff --git a/src/runtime/src/libraries/System.Net.HttpListener/tests/HttpListenerWebSocketTests.cs b/src/runtime/src/libraries/System.Net.HttpListener/tests/HttpListenerWebSocketTests.cs index d1ede4096ba0..80106810b4c6 100644 --- a/src/runtime/src/libraries/System.Net.HttpListener/tests/HttpListenerWebSocketTests.cs +++ b/src/runtime/src/libraries/System.Net.HttpListener/tests/HttpListenerWebSocketTests.cs @@ -360,6 +360,52 @@ public async Task Abort_CallAfterAborted_Nop() Assert.Equal(WebSocketState.Aborted, context.WebSocket.State); } + [ConditionalFact(typeof(Helpers), nameof(Helpers.IsWindowsImplementation))] + public async Task CloseAsync_ConcurrentWithCloseFrameFromClient_DoesNotDeadlock() + { + // Closing a WebSocket from both ends at the same time used to deadlock: the thread processing + // an incoming close frame holds the session handle lock while acquiring the state lock, while + // CloseAsync held the state lock while acquiring the session handle lock. + const int Iterations = 100; + Random random = new Random(42); + + for (int i = 0; i < Iterations; i++) + { + using ClientWebSocket client = new ClientWebSocket(); + HttpListenerWebSocketContext context = await GetWebSocketContext(client); + WebSocket server = context.WebSocket; + + // The pending receive makes a separate thread process the close frame sent by the client. + Task serverReceiveTask = IgnoreExpectedExceptionsAsync( + server.ReceiveAsync(new ArraySegment(new byte[16]), CancellationToken.None)); + + Task clientCloseTask = IgnoreExpectedExceptionsAsync( + client.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, null, CancellationToken.None)); + + // Sweep the (very short) window in which the deadlock can happen. + Thread.SpinWait(random.Next(200_000)); + + Task serverCloseTask = IgnoreExpectedExceptionsAsync(Task.Run( + () => server.CloseAsync(WebSocketCloseStatus.NormalClosure, null, CancellationToken.None))); + + Task allTasks = Task.WhenAll(serverReceiveTask, clientCloseTask, serverCloseTask); + await allTasks.WaitAsync(TimeSpan.FromSeconds(30)); + + server.Dispose(); + } + + static async Task IgnoreExpectedExceptionsAsync(Task task) + { + try + { + await task; + } + catch (Exception e) when (e is WebSocketException or InvalidOperationException or ObjectDisposedException or OperationCanceledException) + { + } + } + } + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows))] public async Task ReceiveAsync_ReadBuffer_WithWindowsAuthScheme_Success() { @@ -430,5 +476,23 @@ private async Task GetWebSocketContext(string[] su HttpListenerContext context = await serverContextTask; return await context.AcceptWebSocketAsync(null); } + + private async Task GetWebSocketContext(ClientWebSocket client) + { + var uriBuilder = new UriBuilder(Factory.ListeningUrl) { Scheme = "ws" }; + Task serverContextTask = Factory.GetListener().GetContextAsync(); + + Task clientConnectTask = client.ConnectAsync(uriBuilder.Uri, CancellationToken.None); + if (clientConnectTask == await Task.WhenAny(serverContextTask, clientConnectTask)) + { + await clientConnectTask; + Assert.Fail("Client should not have completed prior to server sending response"); + } + + HttpListenerContext context = await serverContextTask; + HttpListenerWebSocketContext webSocketContext = await context.AcceptWebSocketAsync(null); + await clientConnectTask; + return webSocketContext; + } } } diff --git a/src/runtime/src/libraries/System.Net.HttpListener/tests/InvalidClientRequestTests.cs b/src/runtime/src/libraries/System.Net.HttpListener/tests/InvalidClientRequestTests.cs index 67e7c187225f..a9703669b6bd 100644 --- a/src/runtime/src/libraries/System.Net.HttpListener/tests/InvalidClientRequestTests.cs +++ b/src/runtime/src/libraries/System.Net.HttpListener/tests/InvalidClientRequestTests.cs @@ -74,6 +74,8 @@ public static IEnumerable InvalidRequest_TestData() yield return new object[] { "GET {path} HTTP/1.1", null, new string[] { "Content-Length: -9223372036854775809" }, "\r\n", "Bad Request" }; yield return new object[] { "GET {path} HTTP/1.1", null, new string[] { "Content-Length: 1", "Content-Length: 2" }, "\r\n", "Bad Request" }; + yield return new object[] { "POST {path} HTTP/1.1", null, new string[] { "Content-Length: 9223372036854775808" }, "\r\n", "Bad Request" }; // long.MaxValue + 1 + yield return new object[] { "POST {path} HTTP/1.1", null, new string[] { "Content-Length: 18446744073709551615" }, "\r\n", "Bad Request" }; // ulong.MaxValue yield return new object[] { "GET {path} HTTP/1.1", null, new string[] { "Transfer-Encoding: garbage" }, "\r\n", "Not Implemented" }; yield return new object[] { "POST {path} HTTP/1.1", null, new string[] { "Transfer-Encoding: garbage" }, "\r\n", "Not Implemented" }; @@ -84,6 +86,13 @@ public static IEnumerable InvalidRequest_TestData() yield return new object[] { "GET {path} HTTP/1.1", null, new string[] { ":" }, null, "Bad Request" }; yield return new object[] { "GET {path} HTTP/1.1", null, new string[] { "\0:value" }, null, "Bad Request" }; yield return new object[] { "GET {path} HTTP/1.1", null, new string[] { "value:\0" }, null, "Bad Request" }; + if (Helpers.IsManagedImplementation) + { + yield return new object[] { "GET {path} HTTP/1.1", null, new string[] { " Header: value" }, null, "Bad Request" }; + yield return new object[] { "GET {path} HTTP/1.1", null, new string[] { "\tHeader: value" }, null, "Bad Request" }; + yield return new object[] { "GET {path} HTTP/1.1", null, new string[] { "Header : value" }, null, "Bad Request" }; + yield return new object[] { "GET {path} HTTP/1.1", null, new string[] { "Header\t: value" }, null, "Bad Request" }; + } yield return new object[] { "GET {path} HTTP/1.1", "", null, null, "Bad Request" }; yield return new object[] { "GET {path} HTTP/1.1", "Host: \r\n", null, null, "Bad Request" }; diff --git a/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mail/MailAddress.cs b/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mail/MailAddress.cs index 3c19b90c149e..3439c676f5ce 100644 --- a/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mail/MailAddress.cs +++ b/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mail/MailAddress.cs @@ -141,6 +141,17 @@ private static bool TryParse([NotNullWhen(true)] string? address, string? displa return false; } + if (MailBnfHelper.HasCROrLF(displayName)) + { + if (throwExceptionIfFail) + { + throw new FormatException(SR.MailAddressInvalidFormat); + } + + parsedData = default; + return false; + } + if (displayName.Length >= 2 && displayName.StartsWith('\"') && displayName.EndsWith('\"')) { // Peel bounding quotes, they'll get re-added later. diff --git a/src/runtime/src/libraries/System.Net.Mail/tests/Unit/MailAddressTests/MailAddressDisplayNameTest.cs b/src/runtime/src/libraries/System.Net.Mail/tests/Unit/MailAddressTests/MailAddressDisplayNameTest.cs index e08151c9195b..f3f6fb9de4b4 100644 --- a/src/runtime/src/libraries/System.Net.Mail/tests/Unit/MailAddressTests/MailAddressDisplayNameTest.cs +++ b/src/runtime/src/libraries/System.Net.Mail/tests/Unit/MailAddressTests/MailAddressDisplayNameTest.cs @@ -66,5 +66,21 @@ public void MailAddress_Ctor_FullString_Succeeds(string address, string displayN Assert.Equal(expectedDisplayName ?? displayName, mailAddress.DisplayName); Assert.Equal(expectedToString, mailAddress.ToString()); } + + [Theory] + [InlineData("Display\rName")] + [InlineData("Display\nName")] + [InlineData("Display\r\nName")] + [InlineData("DisplayName\r")] + [InlineData("DisplayName\n")] + [InlineData("DisplayName\r\n")] + [InlineData("\rDisplayName")] + [InlineData("\nDisplayName")] + [InlineData("\"Display\r\nName\"")] + public void MailAddress_Ctor_DisplayNameContainsCRLF_Throws(string displayName) + { + Assert.Throws(() => new MailAddress(Address, displayName)); + Assert.False(MailAddress.TryCreate(Address, displayName, out _)); + } } } diff --git a/src/runtime/src/libraries/System.Net.Mail/tests/Unit/MailAddressTests/MailAddressParserTest.cs b/src/runtime/src/libraries/System.Net.Mail/tests/Unit/MailAddressTests/MailAddressParserTest.cs index 1648320bc5a6..0fd5a7c8eddd 100644 --- a/src/runtime/src/libraries/System.Net.Mail/tests/Unit/MailAddressTests/MailAddressParserTest.cs +++ b/src/runtime/src/libraries/System.Net.Mail/tests/Unit/MailAddressTests/MailAddressParserTest.cs @@ -567,5 +567,16 @@ public void ParseMultipleAddresses_WithCROrLF_ShouldThrow() Assert.Throws(() => MailAddressParser.ParseMultipleAddresses("test\n@example.com, a@b.com")); Assert.Throws(() => MailAddressParser.ParseMultipleAddresses("a@b.com, c@d.com, e\r@f.com")); } + + [Theory] + [InlineData("Display\rName ")] + [InlineData("Display\nName ")] + [InlineData("Display\r\nName ")] + public void MailAddressCollection_Add_DisplayNameContainsCROrLF_ShouldThrow(string address) + { + MailAddressCollection addresses = new MailAddressCollection(); + + Assert.Throws(() => addresses.Add(address)); + } } } diff --git a/src/runtime/src/libraries/System.Net.Mail/tests/Unit/MailAddressTests/MailAddressParsingTest.cs b/src/runtime/src/libraries/System.Net.Mail/tests/Unit/MailAddressTests/MailAddressParsingTest.cs index 0f91df3d42e2..18e7203df1db 100644 --- a/src/runtime/src/libraries/System.Net.Mail/tests/Unit/MailAddressTests/MailAddressParsingTest.cs +++ b/src/runtime/src/libraries/System.Net.Mail/tests/Unit/MailAddressTests/MailAddressParsingTest.cs @@ -130,7 +130,6 @@ public static IEnumerable GetInvalidEmailTestData() yield return new object[] { "\"test\r\n test\"@mail.com" }; yield return new object[] { "testuser@[mail\u3069.com]" }; // No unicode allowed in square brackets yield return new object[] { "invalid@unicode\uD800.com" }; // D800 is a high surrogate - yield return new object[] { "invalid@unicode\uD800.com" }; // D800 is a high surrogate yield return new object[] { "invalid\uD800@unicode.com" }; // D800 is a high surrogate yield return new object[] { "\uD800 invalid@unicode.com" }; // D800 is a high surrogate yield return new object[] { null }; diff --git a/src/runtime/src/libraries/System.Net.NameResolution/ref/System.Net.NameResolution.cs b/src/runtime/src/libraries/System.Net.NameResolution/ref/System.Net.NameResolution.cs index 2b8269024144..d77bf945f454 100644 --- a/src/runtime/src/libraries/System.Net.NameResolution/ref/System.Net.NameResolution.cs +++ b/src/runtime/src/libraries/System.Net.NameResolution/ref/System.Net.NameResolution.cs @@ -56,27 +56,65 @@ public static partial class Dns public static string GetHostName() { throw null; } [System.ObsoleteAttribute("Resolve has been deprecated. Use GetHostEntry instead.")] public static System.Net.IPHostEntry Resolve(string hostName) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] + [System.Runtime.Versioning.UnsupportedOSPlatform("wasi")] public static System.Net.DnsResult ResolveAddresses(string name) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] + [System.Runtime.Versioning.UnsupportedOSPlatform("wasi")] public static System.Net.DnsResult ResolveAddresses(string name, System.Net.Sockets.AddressFamily addressFamily) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] + [System.Runtime.Versioning.UnsupportedOSPlatform("wasi")] public static System.Threading.Tasks.Task> ResolveAddressesAsync(string name, System.Net.Sockets.AddressFamily addressFamily, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] + [System.Runtime.Versioning.UnsupportedOSPlatform("wasi")] public static System.Threading.Tasks.Task> ResolveAddressesAsync(string name, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] + [System.Runtime.Versioning.UnsupportedOSPlatform("wasi")] public static System.Net.DnsResult ResolveCName(string name) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] + [System.Runtime.Versioning.UnsupportedOSPlatform("wasi")] public static System.Threading.Tasks.Task> ResolveCNameAsync(string name, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] + [System.Runtime.Versioning.UnsupportedOSPlatform("wasi")] public static System.Net.DnsResult ResolveMx(string name) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] + [System.Runtime.Versioning.UnsupportedOSPlatform("wasi")] public static System.Threading.Tasks.Task> ResolveMxAsync(string name, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] + [System.Runtime.Versioning.UnsupportedOSPlatform("wasi")] public static System.Net.DnsResult ResolveNs(string name) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] + [System.Runtime.Versioning.UnsupportedOSPlatform("wasi")] public static System.Threading.Tasks.Task> ResolveNsAsync(string name, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] + [System.Runtime.Versioning.UnsupportedOSPlatform("wasi")] public static System.Net.DnsResult ResolvePtr(System.Net.IPAddress address) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] + [System.Runtime.Versioning.UnsupportedOSPlatform("wasi")] public static System.Net.DnsResult ResolvePtr(string name) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] + [System.Runtime.Versioning.UnsupportedOSPlatform("wasi")] public static System.Threading.Tasks.Task> ResolvePtrAsync(System.Net.IPAddress address, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] + [System.Runtime.Versioning.UnsupportedOSPlatform("wasi")] public static System.Threading.Tasks.Task> ResolvePtrAsync(string name, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] + [System.Runtime.Versioning.UnsupportedOSPlatform("wasi")] public static System.Net.DnsResult ResolveSrv(string name) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] + [System.Runtime.Versioning.UnsupportedOSPlatform("wasi")] public static System.Threading.Tasks.Task> ResolveSrvAsync(string name, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] + [System.Runtime.Versioning.UnsupportedOSPlatform("wasi")] public static System.Net.DnsResult ResolveTxt(string name) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] + [System.Runtime.Versioning.UnsupportedOSPlatform("wasi")] public static System.Threading.Tasks.Task> ResolveTxtAsync(string name, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } } + [System.Runtime.Versioning.UnsupportedOSPlatform("wasi")] public sealed partial class DnsResolver : System.IAsyncDisposable, System.IDisposable { + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public DnsResolver() { } public DnsResolver(System.Net.DnsResolverOptions options) { } public void Dispose() { } diff --git a/src/runtime/src/libraries/System.Net.NameResolution/src/Resources/Strings.resx b/src/runtime/src/libraries/System.Net.NameResolution/src/Resources/Strings.resx index e067c921ed8a..3d5d407c77b5 100644 --- a/src/runtime/src/libraries/System.Net.NameResolution/src/Resources/Strings.resx +++ b/src/runtime/src/libraries/System.Net.NameResolution/src/Resources/Strings.resx @@ -90,6 +90,9 @@ The DNS server list must not contain null entries. + + The system-configured DNS servers cannot be determined on this platform. Specify the servers explicitly using DnsResolverOptions.Servers. + Only the InterNetwork and InterNetworkV6 address families are supported. diff --git a/src/runtime/src/libraries/System.Net.NameResolution/src/System/Net/Dns.Resolve.cs b/src/runtime/src/libraries/System.Net.NameResolution/src/System/Net/Dns.Resolve.cs index 1ddc2cb31bb1..790f98bf51ed 100644 --- a/src/runtime/src/libraries/System.Net.NameResolution/src/System/Net/Dns.Resolve.cs +++ b/src/runtime/src/libraries/System.Net.NameResolution/src/System/Net/Dns.Resolve.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Net.Sockets; +using System.Runtime.Versioning; using System.Threading; using System.Threading.Tasks; @@ -13,6 +14,8 @@ public static partial class Dns // Uses the system-configured DNS servers. A benign race may construct more // than one instance, but only one is published; DnsResolver holds no // unmanaged state, so the extra instance is simply collected. + [UnsupportedOSPlatform("android")] + [UnsupportedOSPlatform("wasi")] private static DnsResolver DefaultResolver => field ??= new(); /// @@ -22,6 +25,9 @@ public static partial class Dns /// A containing the address records. /// is . /// is empty. + /// The system-configured DNS servers cannot be determined on this platform. + [UnsupportedOSPlatform("android")] + [UnsupportedOSPlatform("wasi")] public static DnsResult ResolveAddresses(string name) => DefaultResolver.ResolveAddresses(name); @@ -37,6 +43,9 @@ public static DnsResult ResolveAddresses(string name) /// A containing the address records. /// is . /// is empty. + /// The system-configured DNS servers cannot be determined on this platform. + [UnsupportedOSPlatform("android")] + [UnsupportedOSPlatform("wasi")] public static DnsResult ResolveAddresses(string name, AddressFamily addressFamily) => DefaultResolver.ResolveAddresses(name, addressFamily); @@ -48,6 +57,9 @@ public static DnsResult ResolveAddresses(string name, AddressFami /// A task that completes with a containing the address records. /// is . /// is empty. + /// The system-configured DNS servers cannot be determined on this platform. + [UnsupportedOSPlatform("android")] + [UnsupportedOSPlatform("wasi")] public static Task> ResolveAddressesAsync(string name, CancellationToken cancellationToken = default) => DefaultResolver.ResolveAddressesAsync(name, cancellationToken); @@ -64,6 +76,9 @@ public static Task> ResolveAddressesAsync(string name, /// A task that completes with a containing the address records. /// is . /// is empty. + /// The system-configured DNS servers cannot be determined on this platform. + [UnsupportedOSPlatform("android")] + [UnsupportedOSPlatform("wasi")] public static Task> ResolveAddressesAsync(string name, AddressFamily addressFamily, CancellationToken cancellationToken = default) => DefaultResolver.ResolveAddressesAsync(name, addressFamily, cancellationToken); @@ -74,6 +89,9 @@ public static Task> ResolveAddressesAsync(string name, /// A containing the SRV records. /// is . /// is empty. + /// The system-configured DNS servers cannot be determined on this platform. + [UnsupportedOSPlatform("android")] + [UnsupportedOSPlatform("wasi")] public static DnsResult ResolveSrv(string name) => DefaultResolver.ResolveSrv(name); @@ -85,6 +103,9 @@ public static DnsResult ResolveSrv(string name) /// A task that completes with a containing the SRV records. /// is . /// is empty. + /// The system-configured DNS servers cannot be determined on this platform. + [UnsupportedOSPlatform("android")] + [UnsupportedOSPlatform("wasi")] public static Task> ResolveSrvAsync(string name, CancellationToken cancellationToken = default) => DefaultResolver.ResolveSrvAsync(name, cancellationToken); @@ -95,6 +116,9 @@ public static Task> ResolveSrvAsync(string name, Cancellati /// A containing the MX records. /// is . /// is empty. + /// The system-configured DNS servers cannot be determined on this platform. + [UnsupportedOSPlatform("android")] + [UnsupportedOSPlatform("wasi")] public static DnsResult ResolveMx(string name) => DefaultResolver.ResolveMx(name); @@ -106,6 +130,9 @@ public static DnsResult ResolveMx(string name) /// A task that completes with a containing the MX records. /// is . /// is empty. + /// The system-configured DNS servers cannot be determined on this platform. + [UnsupportedOSPlatform("android")] + [UnsupportedOSPlatform("wasi")] public static Task> ResolveMxAsync(string name, CancellationToken cancellationToken = default) => DefaultResolver.ResolveMxAsync(name, cancellationToken); @@ -116,6 +143,9 @@ public static Task> ResolveMxAsync(string name, Cancellation /// A containing the TXT records. /// is . /// is empty. + /// The system-configured DNS servers cannot be determined on this platform. + [UnsupportedOSPlatform("android")] + [UnsupportedOSPlatform("wasi")] public static DnsResult ResolveTxt(string name) => DefaultResolver.ResolveTxt(name); @@ -127,6 +157,9 @@ public static DnsResult ResolveTxt(string name) /// A task that completes with a containing the TXT records. /// is . /// is empty. + /// The system-configured DNS servers cannot be determined on this platform. + [UnsupportedOSPlatform("android")] + [UnsupportedOSPlatform("wasi")] public static Task> ResolveTxtAsync(string name, CancellationToken cancellationToken = default) => DefaultResolver.ResolveTxtAsync(name, cancellationToken); @@ -137,6 +170,9 @@ public static Task> ResolveTxtAsync(string name, Cancellati /// A containing the CNAME records. /// is . /// is empty. + /// The system-configured DNS servers cannot be determined on this platform. + [UnsupportedOSPlatform("android")] + [UnsupportedOSPlatform("wasi")] public static DnsResult ResolveCName(string name) => DefaultResolver.ResolveCName(name); @@ -148,6 +184,9 @@ public static DnsResult ResolveCName(string name) /// A task that completes with a containing the CNAME records. /// is . /// is empty. + /// The system-configured DNS servers cannot be determined on this platform. + [UnsupportedOSPlatform("android")] + [UnsupportedOSPlatform("wasi")] public static Task> ResolveCNameAsync(string name, CancellationToken cancellationToken = default) => DefaultResolver.ResolveCNameAsync(name, cancellationToken); @@ -158,6 +197,9 @@ public static Task> ResolveCNameAsync(string name, Cancel /// A containing the PTR records. /// is . /// is empty. + /// The system-configured DNS servers cannot be determined on this platform. + [UnsupportedOSPlatform("android")] + [UnsupportedOSPlatform("wasi")] public static DnsResult ResolvePtr(string name) => DefaultResolver.ResolvePtr(name); @@ -167,6 +209,9 @@ public static DnsResult ResolvePtr(string name) /// The IP address to perform a reverse lookup for. /// A containing the PTR records. /// is . + /// The system-configured DNS servers cannot be determined on this platform. + [UnsupportedOSPlatform("android")] + [UnsupportedOSPlatform("wasi")] public static DnsResult ResolvePtr(IPAddress address) => DefaultResolver.ResolvePtr(address); @@ -178,6 +223,9 @@ public static DnsResult ResolvePtr(IPAddress address) /// A task that completes with a containing the PTR records. /// is . /// is empty. + /// The system-configured DNS servers cannot be determined on this platform. + [UnsupportedOSPlatform("android")] + [UnsupportedOSPlatform("wasi")] public static Task> ResolvePtrAsync(string name, CancellationToken cancellationToken = default) => DefaultResolver.ResolvePtrAsync(name, cancellationToken); @@ -188,6 +236,9 @@ public static Task> ResolvePtrAsync(string name, Cancellati /// A token to cancel the asynchronous operation. /// A task that completes with a containing the PTR records. /// is . + /// The system-configured DNS servers cannot be determined on this platform. + [UnsupportedOSPlatform("android")] + [UnsupportedOSPlatform("wasi")] public static Task> ResolvePtrAsync(IPAddress address, CancellationToken cancellationToken = default) => DefaultResolver.ResolvePtrAsync(address, cancellationToken); @@ -198,6 +249,9 @@ public static Task> ResolvePtrAsync(IPAddress address, Canc /// A containing the NS records. /// is . /// is empty. + /// The system-configured DNS servers cannot be determined on this platform. + [UnsupportedOSPlatform("android")] + [UnsupportedOSPlatform("wasi")] public static DnsResult ResolveNs(string name) => DefaultResolver.ResolveNs(name); @@ -209,6 +263,9 @@ public static DnsResult ResolveNs(string name) /// A task that completes with a containing the NS records. /// is . /// is empty. + /// The system-configured DNS servers cannot be determined on this platform. + [UnsupportedOSPlatform("android")] + [UnsupportedOSPlatform("wasi")] public static Task> ResolveNsAsync(string name, CancellationToken cancellationToken = default) => DefaultResolver.ResolveNsAsync(name, cancellationToken); } diff --git a/src/runtime/src/libraries/System.Net.NameResolution/src/System/Net/DnsResolver.cs b/src/runtime/src/libraries/System.Net.NameResolution/src/System/Net/DnsResolver.cs index 948bd0f07ebb..d48114ed6ded 100644 --- a/src/runtime/src/libraries/System.Net.NameResolution/src/System/Net/DnsResolver.cs +++ b/src/runtime/src/libraries/System.Net.NameResolution/src/System/Net/DnsResolver.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Net.Sockets; +using System.Runtime.Versioning; using System.Threading; using System.Threading.Tasks; @@ -20,6 +21,7 @@ namespace System.Net /// and used to issue multiple concurrent resolutions. /// /// + [UnsupportedOSPlatform("wasi")] public sealed partial class DnsResolver : IAsyncDisposable, IDisposable { private readonly IPEndPoint[] _servers; @@ -29,6 +31,8 @@ public sealed partial class DnsResolver : IAsyncDisposable, IDisposable /// Initializes a new instance of the class that uses the /// system-configured DNS servers. /// + /// The system-configured DNS servers cannot be determined on this platform. + [UnsupportedOSPlatform("android")] public DnsResolver() : this(new DnsResolverOptions()) { } /// diff --git a/src/runtime/src/libraries/System.Net.NameResolution/src/System/Net/DnsResolverPal.Managed.cs b/src/runtime/src/libraries/System.Net.NameResolution/src/System/Net/DnsResolverPal.Managed.cs index c9532997d804..c8ef589914ef 100644 --- a/src/runtime/src/libraries/System.Net.NameResolution/src/System/Net/DnsResolverPal.Managed.cs +++ b/src/runtime/src/libraries/System.Net.NameResolution/src/System/Net/DnsResolverPal.Managed.cs @@ -51,6 +51,16 @@ internal static partial class DnsResolverPal // (InterNetwork / InterNetworkV6) are supported. public static void ValidateServers(IPEndPoint[] servers) { + if (servers.Length == 0 && OperatingSystem.IsAndroid()) + { + // With no explicit servers the resolver falls back to the system configuration, + // which on Android cannot be read: there is no accessible /etc/resolv.conf and + // IPInterfaceProperties.DnsAddresses is unsupported there for the same reason. + // Rather than silently querying an unreachable fallback address, reject the + // configuration up front. See https://github.com/dotnet/runtime/issues/132212. + throw new PlatformNotSupportedException(SR.net_dns_system_servers_not_supported); + } + foreach (IPEndPoint server in servers) { if (server.AddressFamily is not (AddressFamily.InterNetwork or AddressFamily.InterNetworkV6)) @@ -854,6 +864,9 @@ private static IReadOnlyList GetServers(IList servers) return systemServers; } + // Matches glibc: resolv.conf(5) specifies that when the file is missing or contains + // no nameserver entries, the name server on the local machine is queried. Hosts + // running a local resolver (dnsmasq, unbound, a container sidecar) rely on this. return new IPEndPoint[] { new IPEndPoint(IPAddress.Loopback, ResolvConf.DefaultDnsPort) }; } diff --git a/src/runtime/src/libraries/System.Net.NameResolution/src/System/Net/DnsResolverPal.Unsupported.cs b/src/runtime/src/libraries/System.Net.NameResolution/src/System/Net/DnsResolverPal.Unsupported.cs index ab5dda344b9e..6d28f863aee3 100644 --- a/src/runtime/src/libraries/System.Net.NameResolution/src/System/Net/DnsResolverPal.Unsupported.cs +++ b/src/runtime/src/libraries/System.Net.NameResolution/src/System/Net/DnsResolverPal.Unsupported.cs @@ -7,6 +7,8 @@ namespace System.Net { + // DnsResolver is not implemented on Browser or WASI. Enabling the managed resolver on + // WASI is tracked by https://github.com/dotnet/runtime/issues/132215. internal static partial class DnsResolverPal { // No platform-specific server restrictions to enforce; resolution itself is diff --git a/src/runtime/src/libraries/System.Net.NameResolution/tests/FunctionalTests/DnsResolverLoopbackTest.cs b/src/runtime/src/libraries/System.Net.NameResolution/tests/FunctionalTests/DnsResolverLoopbackTest.cs index 788e71c474bd..0bddf7bd2183 100644 --- a/src/runtime/src/libraries/System.Net.NameResolution/tests/FunctionalTests/DnsResolverLoopbackTest.cs +++ b/src/runtime/src/libraries/System.Net.NameResolution/tests/FunctionalTests/DnsResolverLoopbackTest.cs @@ -109,7 +109,7 @@ private static async Task> ResolveNs(bool async, DnsResolver // ---- Address resolution ---- - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMobile), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] [InlineData(false)] [InlineData(true)] public async Task ResolveAddresses_Unspecified_ReturnsBothV4AndV6(bool async) @@ -126,7 +126,7 @@ public async Task ResolveAddresses_Unspecified_ReturnsBothV4AndV6(bool async) Assert.Contains(result.Records, a => a.Address.ToString() == "fd00::1"); } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMobile), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] [InlineData(false)] [InlineData(true)] public async Task ResolveAddresses_IPv4Only_ReturnsOnlyV4(bool async) @@ -143,7 +143,7 @@ public async Task ResolveAddresses_IPv4Only_ReturnsOnlyV4(bool async) Assert.Equal("10.0.0.2", record.Address.ToString()); } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMobile), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] [InlineData(false)] [InlineData(true)] public async Task ResolveAddresses_IPv6Only_ReturnsOnlyV6(bool async) @@ -159,7 +159,7 @@ public async Task ResolveAddresses_IPv6Only_ReturnsOnlyV6(bool async) Assert.Equal("fd00::1", record.Address.ToString()); } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMobile), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] [InlineData(false)] [InlineData(true)] public async Task ResolveAddresses_AddressFamilyV4_QueriesOnlyA(bool async) @@ -174,7 +174,7 @@ public async Task ResolveAddresses_AddressFamilyV4_QueriesOnlyA(bool async) Assert.Equal("192.0.2.7", record.Address.ToString()); } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMobile), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] [InlineData(false)] [InlineData(true)] public async Task ResolveAddresses_HasTtl(bool async) @@ -195,7 +195,7 @@ public async Task ResolveAddresses_HasTtl(bool async) // The following behaviors are specific to the managed resolver; the Windows PAL // delegates server failover and record validation to DnsQueryEx. - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMobile), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] [InlineData(false)] [InlineData(true)] public async Task ResolveAddresses_ServerFailure_FailsOverToNextServer(bool async) @@ -219,7 +219,7 @@ public async Task ResolveAddresses_ServerFailure_FailsOverToNextServer(bool asyn Assert.True(failing.RequestCount > 0, "The first (failing) server should have been queried."); } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMobile), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] [InlineData(false)] [InlineData(true)] public async Task ResolveAddresses_AllServersFail_ReturnsServerFailure(bool async) @@ -234,7 +234,7 @@ public async Task ResolveAddresses_AllServersFail_ReturnsServerFailure(bool asyn Assert.Empty(result.Records); } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMobile), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] [InlineData(false)] [InlineData(true)] public async Task ResolveAddresses_MalformedARecord_Throws(bool async) @@ -248,7 +248,7 @@ public async Task ResolveAddresses_MalformedARecord_Throws(bool async) } #endif - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMobile), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] [InlineData(false)] [InlineData(true)] public async Task ResolveAddresses_Nxdomain_ReturnsNxDomain(bool async) @@ -278,7 +278,7 @@ public async Task ResolveAddresses_Nxdomain_ReturnsNxDomain(bool async) #endif } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMobile), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] [InlineData(false)] [InlineData(true)] public async Task ResolveAddresses_NoData_ReturnsNoErrorWithEmptyRecords(bool async) @@ -307,7 +307,7 @@ public async Task ResolveAddresses_NoData_ReturnsNoErrorWithEmptyRecords(bool as #endif } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMobile), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] [InlineData(false)] [InlineData(true)] public async Task ResolveAddresses_NoData_And_Nxdomain_AreDistinguishable(bool async) @@ -341,7 +341,7 @@ public async Task ResolveAddresses_NoData_And_Nxdomain_AreDistinguishable(bool a // ---- SRV ---- - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMobile), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] [InlineData(false)] [InlineData(true)] public async Task ResolveSrv_ReturnsRecords(bool async) @@ -366,7 +366,7 @@ public async Task ResolveSrv_ReturnsRecords(bool async) Assert.Equal((ushort)20, s2.Priority); } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMobile), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] [InlineData(false)] [InlineData(true)] public async Task ResolveSrv_IncludesAdditionalAddresses(bool async) @@ -391,7 +391,7 @@ public async Task ResolveSrv_IncludesAdditionalAddresses(bool async) Assert.Equal(2, s2.Addresses.Count); } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMobile), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] [InlineData(false)] [InlineData(true)] public async Task ResolveSrv_NoAdditionalAddresses(bool async) @@ -409,7 +409,7 @@ public async Task ResolveSrv_NoAdditionalAddresses(bool async) // ---- MX / TXT / CNAME / PTR / NS ---- - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMobile), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] [InlineData(false)] [InlineData(true)] public async Task ResolveMx_ReturnsRecords(bool async) @@ -429,7 +429,7 @@ public async Task ResolveMx_ReturnsRecords(bool async) Assert.Single(result.Records, m => m.Exchange == "mail2.test" && m.Preference == 20); } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMobile), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] [InlineData(false)] [InlineData(true)] public async Task ResolveTxt_ReturnsValues(bool async) @@ -447,7 +447,7 @@ public async Task ResolveTxt_ReturnsValues(bool async) Assert.Contains(result.Records, t => t.Values.Count == 2 && t.Values[0] == "part1" && t.Values[1] == "part2"); } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMobile), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] [InlineData(false)] [InlineData(true)] public async Task ResolveCName_ReturnsCanonicalName(bool async) @@ -463,7 +463,7 @@ public async Task ResolveCName_ReturnsCanonicalName(bool async) Assert.Equal("canonical.test", record.CanonicalName); } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMobile), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] [InlineData(false)] [InlineData(true)] public async Task ResolvePtr_ReturnsName(bool async) @@ -479,7 +479,7 @@ public async Task ResolvePtr_ReturnsName(bool async) Assert.Equal("host.test", record.Name); } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMobile), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] [InlineData(false)] [InlineData(true)] public async Task ResolveNs_ReturnsRecords(bool async) @@ -523,7 +523,7 @@ public async Task CustomServer_DefaultPortZero_IsAccepted(bool async) // ---- Cancellation while a query is in flight ---- - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMobile), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] public async Task ResolveAddresses_CancellationInFlight_Throws() { using SemaphoreSlim queryReceived = new(0, 1); @@ -554,7 +554,7 @@ public async Task ResolveAddresses_CancellationInFlight_Throws() // ---- Telemetry ---- - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMobile), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] [InlineData(false)] [InlineData(true)] public async Task ResolveAddresses_RecordsDurationMetric_CoversQueryTime(bool async) diff --git a/src/runtime/src/libraries/System.Net.NameResolution/tests/FunctionalTests/DnsResolverTest.cs b/src/runtime/src/libraries/System.Net.NameResolution/tests/FunctionalTests/DnsResolverTest.cs index 1140ff0fe39d..f91183c4e5c8 100644 --- a/src/runtime/src/libraries/System.Net.NameResolution/tests/FunctionalTests/DnsResolverTest.cs +++ b/src/runtime/src/libraries/System.Net.NameResolution/tests/FunctionalTests/DnsResolverTest.cs @@ -21,6 +21,16 @@ public class DnsResolverTest private const string TestNsHost = "microsoft.com"; private const string NonExistentHost = "this-name-definitely-does-not-exist.dotnet-test.invalid"; + // DnsResolver has no implementation on Browser or WASI; every query throws + // PlatformNotSupportedException there. + public static bool IsDnsResolverUnsupported => PlatformDetection.IsBrowser || PlatformDetection.IsWasi; + + // Android cannot report the system-configured DNS servers, so the parameterless + // constructor throws there. Tests that never send a query specify a server explicitly + // so that they remain platform independent. + private static DnsResolver CreateResolver() => + new DnsResolver(new DnsResolverOptions { Servers = { new IPEndPoint(IPAddress.Loopback, 53) } }); + // ---- Cross-platform argument-validation tests ---- [Fact] @@ -29,17 +39,33 @@ public void DnsResolver_Construct_NullOptions_Throws() Assert.Throws(() => new DnsResolver(null!)); } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotAndroid))] public void DnsResolver_Construct_DefaultOptions_DoesNotThrow() { using DnsResolver r = new DnsResolver(); Assert.NotNull(r); } + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAndroid))] + public void DnsResolver_Construct_DefaultOptions_ThrowsPlatformNotSupported() + { + // Android exposes no readable resolver configuration, so a resolver that would + // have to use the system-configured servers cannot be created. + Assert.Throws(() => new DnsResolver()); + Assert.Throws(() => Dns.ResolveAddresses(TestHost)); + } + + [ConditionalFact(nameof(IsDnsResolverUnsupported))] + public async Task DnsResolver_UnsupportedPlatform_ThrowsPlatformNotSupported() + { + Assert.Throws(() => Dns.ResolveAddresses(TestHost)); + await Assert.ThrowsAsync(() => Dns.ResolveAddressesAsync(TestHost)); + } + [Fact] public async Task DnsResolver_NullName_Throws() { - using DnsResolver r = new DnsResolver(); + using DnsResolver r = CreateResolver(); await Assert.ThrowsAsync(() => r.ResolveAddressesAsync(null!)); await Assert.ThrowsAsync(() => r.ResolveSrvAsync(null!)); await Assert.ThrowsAsync(() => r.ResolveMxAsync(null!)); @@ -53,7 +79,7 @@ public async Task DnsResolver_NullName_Throws() [Fact] public void DnsResolver_NullName_Throws_Sync() { - using DnsResolver r = new DnsResolver(); + using DnsResolver r = CreateResolver(); Assert.Throws(() => r.ResolveAddresses(null!)); Assert.Throws(() => r.ResolveSrv(null!)); Assert.Throws(() => r.ResolveMx(null!)); @@ -66,7 +92,7 @@ public void DnsResolver_NullName_Throws_Sync() [Fact] public async Task DnsResolver_EmptyName_Throws() { - using DnsResolver r = new DnsResolver(); + using DnsResolver r = CreateResolver(); await Assert.ThrowsAsync(() => r.ResolveAddressesAsync(string.Empty)); Assert.Throws(() => r.ResolveAddresses(string.Empty)); } @@ -74,7 +100,7 @@ public async Task DnsResolver_EmptyName_Throws() [Fact] public async Task DnsResolver_Disposed_Throws() { - DnsResolver r = new DnsResolver(); + DnsResolver r = CreateResolver(); r.Dispose(); await Assert.ThrowsAsync(() => r.ResolveAddressesAsync(TestHost)); await Assert.ThrowsAsync(() => r.ResolveSrvAsync(TestSrv)); @@ -87,7 +113,7 @@ public async Task DnsResolver_Disposed_Throws() [Fact] public async Task DnsResolver_DisposeAsync_ThrowsOnUse() { - DnsResolver r = new DnsResolver(); + DnsResolver r = CreateResolver(); await r.DisposeAsync(); await Assert.ThrowsAsync(() => r.ResolveAddressesAsync(TestHost)); } @@ -139,15 +165,22 @@ public static TheoryData SynchronouslyCompletingQueryNames() }; } - // ---- Windows network tests (require outbound DNS) ---- + // ---- Network tests (require outbound DNS) ---- + // + // DnsResolver is implemented on Windows (DnsQueryEx) and on all Unix-like platforms + // (the managed stub resolver); it is unsupported on Browser and WASI. These tests use + // the system-configured DNS servers, which the managed resolver reads from + // /etc/resolv.conf. Android has no readable resolver configuration (its + // IPInterfaceProperties.DnsAddresses throws PlatformNotSupportedException for the same + // reason), so it is excluded until the servers can be obtained from the platform. - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotAndroid), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] public async Task DnsResolver_PreCanceledToken_ReturnsCanceled() { using DnsResolver r = new DnsResolver(); CancellationTokenSource cts = new CancellationTokenSource(); cts.Cancel(); - await Assert.ThrowsAsync(() => r.ResolveAddressesAsync(TestHost, cts.Token)); + await Assert.ThrowsAnyAsync(() => r.ResolveAddressesAsync(TestHost, cts.Token)); } // Regression test for the Windows 10 DnsQueryEx bug where an asynchronous query @@ -189,7 +222,7 @@ public async Task ResolveAddresses_SynchronouslyCompletingQuery_DoesNotHang(bool } } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotAndroid), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] [InlineData(false)] [InlineData(true)] [OuterLoop] @@ -206,7 +239,7 @@ public async Task ResolveAddresses_KnownName_ReturnsRecords(bool async) } } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotAndroid), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] [InlineData(false)] [InlineData(true)] [OuterLoop] @@ -221,7 +254,7 @@ public async Task ResolveAddresses_IPv4Only_ReturnsOnlyIPv4(bool async) } } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotAndroid), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] [InlineData(false)] [InlineData(true)] [OuterLoop] @@ -234,7 +267,7 @@ public async Task ResolveAddresses_NonExistent_ReturnsNxDomain(bool async) Assert.Empty(result.Records); } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotAndroid), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] [InlineData(false)] [InlineData(true)] [OuterLoop] @@ -250,7 +283,7 @@ public async Task ResolveMx_KnownName_ReturnsRecords(bool async) } } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotAndroid), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] [InlineData(false)] [InlineData(true)] [OuterLoop] @@ -266,7 +299,7 @@ public async Task ResolveTxt_KnownName_ReturnsRecords(bool async) } } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotAndroid), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] [InlineData(false)] [InlineData(true)] [OuterLoop] @@ -282,7 +315,7 @@ public async Task ResolveCName_KnownName_ReturnsRecord(bool async) } } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotAndroid), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] [InlineData(false)] [InlineData(true)] [OuterLoop] @@ -298,7 +331,7 @@ public async Task ResolveNs_KnownName_ReturnsRecords(bool async) } } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotAndroid), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] [InlineData(false)] [InlineData(true)] [OuterLoop] @@ -311,7 +344,7 @@ public async Task ResolvePtr_ByIPAddress_ReturnsRecord(bool async) Assert.False(string.IsNullOrEmpty(result.Records[0].Name)); } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotAndroid), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] [InlineData(false)] [InlineData(true)] [OuterLoop] @@ -322,7 +355,7 @@ public async Task Static_Dns_ResolveAddresses_Works(bool async) Assert.NotEmpty(result.Records); } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotAndroid), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] [InlineData(false)] [InlineData(true)] [OuterLoop] @@ -360,6 +393,19 @@ public void DnsResolver_CustomServer_NonStandardPort_ThrowsPlatformNotSupported( Assert.Throws(() => new DnsResolver(opts)); } + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] + public void DnsResolver_CustomServer_NonStandardPort_IsAccepted() + { + // The managed resolver talks to each server endpoint directly, so a non-default + // port is supported. + DnsResolverOptions opts = new DnsResolverOptions + { + Servers = { new IPEndPoint(IPAddress.Loopback, 5353) } + }; + using DnsResolver r = new DnsResolver(opts); + Assert.NotNull(r); + } + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows))] public void DnsResolver_CustomServers_MixedAddressFamilies_ThrowsArgumentException() { @@ -376,9 +422,26 @@ public void DnsResolver_CustomServers_MixedAddressFamilies_ThrowsArgumentExcepti Assert.Throws(() => new DnsResolver(opts)); } + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] + public void DnsResolver_CustomServers_MixedAddressFamilies_IsAccepted() + { + // The managed resolver opens a socket matching each server's address family, so a + // mixed IPv4/IPv6 server list is supported. + DnsResolverOptions opts = new DnsResolverOptions + { + Servers = + { + new IPEndPoint(IPAddress.Loopback, 53), + new IPEndPoint(IPAddress.IPv6Loopback, 53), + } + }; + using DnsResolver r = new DnsResolver(opts); + Assert.NotNull(r); + } + // ---- Reverse-arpa name building (covers both IPv4 and IPv6 paths used by ResolvePtr(IPAddress)) ---- - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows))] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotAndroid), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.IsNotWasi))] [InlineData(false)] [InlineData(true)] [OuterLoop] diff --git a/src/runtime/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkAddressChange.OSX.cs b/src/runtime/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkAddressChange.OSX.cs index 6d303bf66647..98cadd10d427 100644 --- a/src/runtime/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkAddressChange.OSX.cs +++ b/src/runtime/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkAddressChange.OSX.cs @@ -222,7 +222,19 @@ private static void RunLoopThreadStart() private static void StopRunLoop() { - Debug.Assert(s_runLoop != IntPtr.Zero); + if (s_runLoop == IntPtr.Zero) + { + // The listener thread already exited on its own: CFRunLoopRun() returns as soon as the + // SCDynamicStore run loop source is invalidated (e.g. configd restart, sleep/wake), and + // the thread's epilogue below zeroes s_runLoop and disposes the store. There is nothing + // left to stop, and passing the null handle to CFRunLoopIsWaiting would fault inside + // CoreFoundation (EXC_BAD_ACCESS at 0x8), taking the whole process down. Consume the + // ended-event that thread has set, or is about to set, so a subsequent + // CreateAndStartRunLoop/StopRunLoop pair starts from a clean state. + s_runLoopEndedEvent.WaitOne(); + return; + } + Debug.Assert(s_runLoopSource != null); Debug.Assert(s_dynamicStoreRef != null); diff --git a/src/runtime/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicStream.cs b/src/runtime/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicStream.cs index bb7300d55900..819e0912c917 100644 --- a/src/runtime/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicStream.cs +++ b/src/runtime/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicStream.cs @@ -321,9 +321,10 @@ public override async ValueTask ReadAsync(Memory buffer, Cancellation cancellationToken.ThrowIfCancellationRequested(); } - // The following loop will repeat at most twice depending whether some data are readily available in the buffer (one iteration) or not. - // In which case, it'll wait on RECEIVE or any of PEER_SEND_(SHUTDOWN|ABORTED) event and attempt to copy data in the second iteration. + // Loop copying available data and/or waiting on RECEIVE or PEER_SEND_(SHUTDOWN|ABORTED) events. + // Keeps waiting while nothing was copied and the buffer is empty (and not final) to ignore stale wake-ups on _receiveTcs. int totalCopied = 0; + bool empty; do { // Concurrent call, this one lost the race. @@ -333,7 +334,7 @@ public override async ValueTask ReadAsync(Memory buffer, Cancellation } // Copy data from the buffer, reduce target and increment total. - int copied = _receiveBuffers.CopyTo(buffer, out bool complete, out bool empty); + int copied = _receiveBuffers.CopyTo(buffer, out bool complete, out empty); buffer = buffer.Slice(copied); totalCopied += copied; @@ -357,7 +358,7 @@ public override async ValueTask ReadAsync(Memory buffer, Cancellation { break; } - } while (!buffer.IsEmpty && totalCopied == 0); // Exit the loop if target buffer is full we at least copied something. + } while (totalCopied == 0 && empty); // Keep waiting while we haven't copied anything and no data is available. if (totalCopied > 0 && Interlocked.CompareExchange(ref _receivedNeedsEnable, 0, 1) == 1) { diff --git a/src/runtime/src/libraries/System.Net.Security/tests/UnitTests/SslAuthenticationOptionsTests.Desktop.cs b/src/runtime/src/libraries/System.Net.Security/tests/UnitTests/SslAuthenticationOptionsTests.Desktop.cs new file mode 100644 index 000000000000..1185ccf583c9 --- /dev/null +++ b/src/runtime/src/libraries/System.Net.Security/tests/UnitTests/SslAuthenticationOptionsTests.Desktop.cs @@ -0,0 +1,85 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; +using Xunit; + +namespace System.Net.Security.Tests +{ + public partial class SslAuthenticationOptionsTests + { + // This test exercises SslStreamCertificateContext.Create with intermediate certificates, which + // triggers a generic Dictionary instantiation whose IL body is stripped from the Apple-mobile + // CoreCLR ReadyToRun composite image, crashing the test app at startup. Compile it on desktop + // platforms only. + [Fact] + public void UpdateOptions_ServerCertificateContextProvided_DoesNotDisposeCallerContext() + { + // Build a certificate chain: root → intermediate → leaf. + // Use ECDSA P-256 keys: fast and accepted on FIPS-mode platforms. + DateTimeOffset now = DateTimeOffset.UtcNow; + + using ECDsa rootKey = ECDsa.Create(ECCurve.NamedCurves.nistP256); + var rootReq = new CertificateRequest("CN=TestRoot", rootKey, HashAlgorithmName.SHA256); + rootReq.CertificateExtensions.Add(new X509BasicConstraintsExtension(true, false, 0, true)); + using X509Certificate2 rootCert = rootReq.CreateSelfSigned(now.AddDays(-1), now.AddDays(365)); + + using ECDsa intermediateKey = ECDsa.Create(ECCurve.NamedCurves.nistP256); + var intermediateReq = new CertificateRequest("CN=TestIntermediate", intermediateKey, HashAlgorithmName.SHA256); + intermediateReq.CertificateExtensions.Add(new X509BasicConstraintsExtension(true, false, 0, true)); + using X509Certificate2 intermediatePub = intermediateReq.Create(rootCert, now.AddDays(-1), now.AddDays(365), new byte[] { 1 }); + using X509Certificate2 intermediateWithKey = intermediatePub.CopyWithPrivateKey(intermediateKey); + + using ECDsa leafKey = ECDsa.Create(ECCurve.NamedCurves.nistP256); + var leafReq = new CertificateRequest("CN=TestLeaf", leafKey, HashAlgorithmName.SHA256); + using X509Certificate2 leafPub = leafReq.Create(intermediateWithKey, now.AddDays(-1), now.AddDays(365), new byte[] { 2 }); + using X509Certificate2 leafWithKey = leafPub.CopyWithPrivateKey(leafKey); + + // Create a caller-owned context with an intermediate certificate + SslStreamCertificateContext callerContext = SslStreamCertificateContext.Create( + leafWithKey, + new X509Certificate2Collection { intermediateWithKey }, + offline: true); + + // Simulate first UpdateOptions call: bare ServerCertificate creates and owns a context + var options = new SslAuthenticationOptions(); + SslStreamCertificateContext ownedContext = SslStreamCertificateContext.Create( + leafWithKey, + new X509Certificate2Collection { intermediateWithKey }, + offline: true); + // Capture the internal intermediate cert object before it is released + Assert.NotEmpty(ownedContext.IntermediateCertificates); + X509Certificate2 ownedIntermediate = ownedContext.IntermediateCertificates[0]; + options.CertificateContext = ownedContext; + options.OwnsCertificateContext = true; + + // Simulate second UpdateOptions call: caller provides a ServerCertificateContext. + // Before the fix, OwnsCertificateContext was not reset to false here, causing Dispose() + // to incorrectly call ReleaseResources() on the caller-owned context. + options.UpdateOptions(new SslServerAuthenticationOptions + { + ServerCertificateContext = callerContext, + }); + + Assert.False(options.OwnsCertificateContext); + Assert.Same(callerContext, options.CertificateContext); + + // UpdateOptions should have released the previously-owned context's resources. + // After X509Certificate2.Dispose(), Handle returns IntPtr.Zero. + Assert.NotNull(ownedIntermediate); + Assert.Equal(IntPtr.Zero, ownedIntermediate.Handle); + + // Dispose should NOT release the caller's context + options.Dispose(); + + // Verify that the caller's intermediate certificates were not disposed + Assert.Equal(1, callerContext.IntermediateCertificates.Count); + // Export() requires the native certificate handle; a CryptographicException would indicate the certificate was incorrectly disposed. + foreach (X509Certificate2 cert in callerContext.IntermediateCertificates) + { + Assert.Null(Record.Exception(() => cert.Export(X509ContentType.Cert))); + } + } + } +} diff --git a/src/runtime/src/libraries/System.Net.Security/tests/UnitTests/SslAuthenticationOptionsTests.cs b/src/runtime/src/libraries/System.Net.Security/tests/UnitTests/SslAuthenticationOptionsTests.cs index 314f2404662f..74a7a6024baf 100644 --- a/src/runtime/src/libraries/System.Net.Security/tests/UnitTests/SslAuthenticationOptionsTests.cs +++ b/src/runtime/src/libraries/System.Net.Security/tests/UnitTests/SslAuthenticationOptionsTests.cs @@ -9,7 +9,7 @@ namespace System.Net.Security.Tests { - public class SslAuthenticationOptionsTests + public partial class SslAuthenticationOptionsTests { private readonly SslClientAuthenticationOptions _clientOptions = new SslClientAuthenticationOptions(); private readonly SslServerAuthenticationOptions _serverOptions = new SslServerAuthenticationOptions(); @@ -164,74 +164,5 @@ public void EncryptionPolicy_Get_Set_Succeeds() Assert.Throws(() => _clientOptions.EncryptionPolicy = (EncryptionPolicy)3); Assert.Throws(() => _serverOptions.EncryptionPolicy = (EncryptionPolicy)3); } - - [Fact] - public void UpdateOptions_ServerCertificateContextProvided_DoesNotDisposeCallerContext() - { - // Build a certificate chain: root → intermediate → leaf. - // Use ECDSA P-256 keys: fast and accepted on FIPS-mode platforms. - DateTimeOffset now = DateTimeOffset.UtcNow; - - using ECDsa rootKey = ECDsa.Create(ECCurve.NamedCurves.nistP256); - var rootReq = new CertificateRequest("CN=TestRoot", rootKey, HashAlgorithmName.SHA256); - rootReq.CertificateExtensions.Add(new X509BasicConstraintsExtension(true, false, 0, true)); - using X509Certificate2 rootCert = rootReq.CreateSelfSigned(now.AddDays(-1), now.AddDays(365)); - - using ECDsa intermediateKey = ECDsa.Create(ECCurve.NamedCurves.nistP256); - var intermediateReq = new CertificateRequest("CN=TestIntermediate", intermediateKey, HashAlgorithmName.SHA256); - intermediateReq.CertificateExtensions.Add(new X509BasicConstraintsExtension(true, false, 0, true)); - using X509Certificate2 intermediatePub = intermediateReq.Create(rootCert, now.AddDays(-1), now.AddDays(365), new byte[] { 1 }); - using X509Certificate2 intermediateWithKey = intermediatePub.CopyWithPrivateKey(intermediateKey); - - using ECDsa leafKey = ECDsa.Create(ECCurve.NamedCurves.nistP256); - var leafReq = new CertificateRequest("CN=TestLeaf", leafKey, HashAlgorithmName.SHA256); - using X509Certificate2 leafPub = leafReq.Create(intermediateWithKey, now.AddDays(-1), now.AddDays(365), new byte[] { 2 }); - using X509Certificate2 leafWithKey = leafPub.CopyWithPrivateKey(leafKey); - - // Create a caller-owned context with an intermediate certificate - SslStreamCertificateContext callerContext = SslStreamCertificateContext.Create( - leafWithKey, - new X509Certificate2Collection { intermediateWithKey }, - offline: true); - - // Simulate first UpdateOptions call: bare ServerCertificate creates and owns a context - var options = new SslAuthenticationOptions(); - SslStreamCertificateContext ownedContext = SslStreamCertificateContext.Create( - leafWithKey, - new X509Certificate2Collection { intermediateWithKey }, - offline: true); - // Capture the internal intermediate cert object before it is released - Assert.NotEmpty(ownedContext.IntermediateCertificates); - X509Certificate2 ownedIntermediate = ownedContext.IntermediateCertificates[0]; - options.CertificateContext = ownedContext; - options.OwnsCertificateContext = true; - - // Simulate second UpdateOptions call: caller provides a ServerCertificateContext. - // Before the fix, OwnsCertificateContext was not reset to false here, causing Dispose() - // to incorrectly call ReleaseResources() on the caller-owned context. - options.UpdateOptions(new SslServerAuthenticationOptions - { - ServerCertificateContext = callerContext, - }); - - Assert.False(options.OwnsCertificateContext); - Assert.Same(callerContext, options.CertificateContext); - - // UpdateOptions should have released the previously-owned context's resources. - // After X509Certificate2.Dispose(), Handle returns IntPtr.Zero. - Assert.NotNull(ownedIntermediate); - Assert.Equal(IntPtr.Zero, ownedIntermediate.Handle); - - // Dispose should NOT release the caller's context - options.Dispose(); - - // Verify that the caller's intermediate certificates were not disposed - Assert.Equal(1, callerContext.IntermediateCertificates.Count); - // Export() requires the native certificate handle; a CryptographicException would indicate the certificate was incorrectly disposed. - foreach (X509Certificate2 cert in callerContext.IntermediateCertificates) - { - Assert.Null(Record.Exception(() => cert.Export(X509ContentType.Cert))); - } - } } } diff --git a/src/runtime/src/libraries/System.Net.Security/tests/UnitTests/System.Net.Security.Unit.Tests.csproj b/src/runtime/src/libraries/System.Net.Security/tests/UnitTests/System.Net.Security.Unit.Tests.csproj index 4fc175a78197..9670e22d2bb1 100644 --- a/src/runtime/src/libraries/System.Net.Security/tests/UnitTests/System.Net.Security.Unit.Tests.csproj +++ b/src/runtime/src/libraries/System.Net.Security/tests/UnitTests/System.Net.Security.Unit.Tests.csproj @@ -134,6 +134,11 @@ Link="Common\System\Net\Security\SslKeyLogger.cs" /> + + + + + diff --git a/src/runtime/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx b/src/runtime/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx index 23635bf8653a..8d6acae094ad 100644 --- a/src/runtime/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx +++ b/src/runtime/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx @@ -2739,7 +2739,7 @@ Underlying type information on enumeration is not specified. - Nullable object must have a value. + Cannot read the Value property of a Nullable object that has no value. Check HasValue before reading Value. The underlying array is null. diff --git a/src/runtime/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.cs b/src/runtime/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.cs index 551f84fc1ec3..84c316b88039 100644 --- a/src/runtime/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.cs +++ b/src/runtime/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Threading; @@ -1296,10 +1297,64 @@ internal void RemoveWrappersFromCache(IEnumerable wrappers) _rcwCache.RemoveAll(wrappers); } - private sealed class RcwCache + /// + /// The cache mapping COM instances to the objects tracking their RCWs. + /// + /// + /// The cache is partitioned into several independent buckets, each with its own lock, so that operations on + /// COM instances that map to different buckets don't contend with one another. Reducing that contention is + /// important because the cache is consulted on essentially every transition from native to managed code, and + /// because the finalizer thread concurrently takes write locks to remove entries for collected RCWs. + /// + private readonly struct RcwCache { - private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(); - private readonly Dictionary _cache = []; + /// + /// The most buckets to partition the cache into, regardless of how many processors there are. + /// + private const int MaxBucketCount = 16; + + private readonly Bucket[] _buckets; + + public RcwCache() + { + // Use as many buckets as there are processors, matching the default concurrency level of + // 'ConcurrentDictionary', up to the cap above. The count is rounded up to a power of two so that + // the bucket for a given COM instance can be selected with a mask rather than a division. + uint bucketCount = BitOperations.RoundUpToPowerOf2((uint)Math.Min(Environment.ProcessorCount, MaxBucketCount)); + Bucket[] buckets = new Bucket[bucketCount]; + + for (int i = 0; i < buckets.Length; i++) + { + buckets[i] = new Bucket(); + } + + _buckets = buckets; + } + + /// + /// Gets the bucket owning the entries for a given COM instance. + /// + /// The com instance to get the bucket for. + /// The bucket owning the entries for . + private unsafe ref readonly Bucket GetBucket(IntPtr comPointer) + { + Bucket[] buckets = _buckets; + + // COM instances are always at least pointer aligned, and in practice more than that. Their low + // bits are therefore constant and can't be used to select a bucket directly. Multiplying by a + // large odd constant (2 raised to the width of a pointer, divided by the golden ratio) mixes + // every input bit into the high half of the product, which is then masked to produce the index. + // The whole sequence lowers to a multiply, a shift and a mask, which is negligible next to the + // lookup that follows. + uint hash = sizeof(nint) == 8 + ? (uint)(((ulong)(nuint)comPointer * 0x9E3779B97F4A7C15) >> 32) + : ((uint)(nuint)comPointer * 0x9E3779B9) >> 16; + + uint index = hash & (uint)(buckets.Length - 1); + + // Return the bucket by reference, so that it's addressed in place in the array rather than copied + return ref buckets[index]; + } /// /// Gets the current RCW proxy object for if it exists in the cache or inserts a new entry with . @@ -1310,139 +1365,183 @@ private sealed class RcwCache /// The proxy object currently in the cache for or the proxy object owned by if no entry exists and the corresponding native wrapper. public (NativeObjectWrapper actualWrapper, object actualProxy) GetOrAddProxyForComInstance(IntPtr comPointer, NativeObjectWrapper wrapper, object comProxy) { - _lock.EnterWriteLock(); - try - { - Debug.Assert(wrapper.ProxyHandle.Target == comProxy); - ref GCHandle rcwEntry = ref CollectionsMarshal.GetValueRefOrAddDefault(_cache, comPointer, out bool exists); - if (!exists) - { - // Someone else didn't beat us to adding the entry to the cache. - // Add our entry here. - rcwEntry = GCHandle.Alloc(wrapper, GCHandleType.Weak); - } - else if (rcwEntry.Target is not (NativeObjectWrapper cachedWrapper)) - { - Debug.Assert(rcwEntry.IsAllocated); - // The target was collected, so we need to update the cache entry. - rcwEntry.Target = wrapper; - } - else - { - object? existingProxy = cachedWrapper.ProxyHandle.Target; - // The target NativeObjectWrapper was not collected, but we need to make sure - // that the proxy object is still alive. - if (existingProxy is not null) - { - // The existing proxy object is still alive, we will use that. - return (cachedWrapper, existingProxy); - } + return GetBucket(comPointer).GetOrAddProxyForComInstance(comPointer, wrapper, comProxy); + } - // The proxy object was collected, so we need to update the cache entry. - rcwEntry.Target = wrapper; - } + /// + /// Gets the current RCW proxy object for , if it exists in the cache and is still alive. + /// + /// The com instance we want to get the RCW for. + /// The proxy object currently in the cache for , if any. + public object? FindProxyForComInstance(IntPtr comPointer) + { + return GetBucket(comPointer).FindProxyForComInstance(comPointer); + } - // We either added an entry to the cache or updated an existing entry that was dead. - // Return our target object. - return (wrapper, comProxy); - } - finally + /// + /// Removes the entry associating with , if present. + /// + /// The com instance to remove the entry for. + /// The that is expected to be in the cache. + public void Remove(IntPtr comPointer, NativeObjectWrapper wrapper) + { + GetBucket(comPointer).Remove(comPointer, wrapper); + } + + /// + /// Removes the entries for all input objects, if present. + /// + /// The objects to remove the entries for. + public void RemoveAll(IEnumerable wrappers) + { + // The wrappers can span multiple buckets, so they're removed one at a time. This is only used when + // tearing down an apartment, so the extra lock acquisitions don't matter. Note that entries are not + // removed atomically as a batch anymore, but that was never something callers could rely on: the + // cache is only ever observed one entry at a time. + foreach (NativeObjectWrapper wrapper in wrappers) { - _lock.ExitWriteLock(); + IntPtr comPointer = wrapper.ExternalComObject; + + GetBucket(comPointer).Remove(comPointer, wrapper); } } - public object? FindProxyForComInstance(IntPtr comPointer) + /// + /// A single partition of the RCW cache, holding the entries for all COM instances that map to it. + /// + /// + /// This is a struct so that buckets are stored inline in the containing array. That saves a dereference + /// on each lookup, and lets several buckets share a cache line. There is no false sharing to worry about, + /// as the fields are only ever read: all mutable state lives in the referenced lock and dictionary. + /// + private readonly struct Bucket { - _lock.EnterReadLock(); - try + private readonly ReaderWriterLockSlim _lock; + private readonly Dictionary> _cache; + + public Bucket() + { + _lock = new ReaderWriterLockSlim(); + _cache = []; + } + + /// + public (NativeObjectWrapper actualWrapper, object actualProxy) GetOrAddProxyForComInstance(IntPtr comPointer, NativeObjectWrapper wrapper, object comProxy) { - if (!_cache.TryGetValue(comPointer, out GCHandle existingHandle)) + _lock.EnterWriteLock(); + try { - // No entry in the cache. - return null; + Debug.Assert(wrapper.ProxyHandle.Target == comProxy); + ref WeakGCHandle rcwEntry = ref CollectionsMarshal.GetValueRefOrAddDefault(_cache, comPointer, out bool exists); + if (!exists) + { + // Someone else didn't beat us to adding the entry to the cache. + // Add our entry here. + rcwEntry = new WeakGCHandle(wrapper); + } + else if (!rcwEntry.TryGetTarget(out NativeObjectWrapper? cachedWrapper)) + { + Debug.Assert(rcwEntry.IsAllocated); + // The target was collected, so we need to update the cache entry. + rcwEntry.SetTarget(wrapper); + } + else + { + object? existingProxy = cachedWrapper.ProxyHandle.Target; + // The target NativeObjectWrapper was not collected, but we need to make sure + // that the proxy object is still alive. + if (existingProxy is not null) + { + // The existing proxy object is still alive, we will use that. + return (cachedWrapper, existingProxy); + } + + // The proxy object was collected, so we need to update the cache entry. + rcwEntry.SetTarget(wrapper); + } + + // We either added an entry to the cache or updated an existing entry that was dead. + // Return our target object. + return (wrapper, comProxy); } - if (existingHandle.Target is NativeObjectWrapper { ProxyHandle.Target: object cachedProxy }) + finally { - // The target exists and is still alive. Return it. - return cachedProxy; + _lock.ExitWriteLock(); } - // The target was collected, so we need to remove the entry from the cache. - // We'll do this in a write lock after we exit the read lock. - // We don't use an upgradeable lock here as only one thread can hold an upgradeable lock at a time, - // effectively eliminating the benefit of using a reader-writer lock. - } - finally - { - _lock.ExitReadLock(); } - _lock.EnterWriteLock(); - try + /// + public object? FindProxyForComInstance(IntPtr comPointer) { - // Someone else could have removed the entry or added a new one in the time - // between us releasing the read lock and acquiring the write lock. - if (_cache.TryGetValue(comPointer, out GCHandle existingHandle) - && existingHandle.Target is null) + _lock.EnterReadLock(); + try + { + if (!_cache.TryGetValue(comPointer, out WeakGCHandle existingHandle)) + { + // No entry in the cache. + return null; + } + if (existingHandle.TryGetTarget(out NativeObjectWrapper? cachedWrapper) + && cachedWrapper.ProxyHandle.Target is object cachedProxy) + { + // The target exists and is still alive. Return it. + return cachedProxy; + } + // The target was collected, so we need to remove the entry from the cache. + // We'll do this in a write lock after we exit the read lock. + // We don't use an upgradeable lock here as only one thread can hold an upgradeable lock at a time, + // effectively eliminating the benefit of using a reader-writer lock. + } + finally { - // There's still a dead entry in the cache, - // remove it. - _cache.Remove(comPointer); - existingHandle.Free(); + _lock.ExitReadLock(); } - } - finally - { - _lock.ExitWriteLock(); - } - return null; - } + _lock.EnterWriteLock(); + try + { + // Someone else could have removed the entry or added a new one in the time + // between us releasing the read lock and acquiring the write lock. + if (_cache.TryGetValue(comPointer, out WeakGCHandle existingHandle) + && !existingHandle.TryGetTarget(out _)) + { + // There's still a dead entry in the cache, + // remove it. + _cache.Remove(comPointer); + existingHandle.Dispose(); + } + } + finally + { + _lock.ExitWriteLock(); + } - public void Remove(IntPtr comPointer, NativeObjectWrapper wrapper) - { - _lock.EnterWriteLock(); - try - { - Remove_Locked(comPointer, wrapper); - } - finally - { - _lock.ExitWriteLock(); + return null; } - } - public void RemoveAll(IEnumerable wrappers) - { - _lock.EnterWriteLock(); - try + /// + public void Remove(IntPtr comPointer, NativeObjectWrapper wrapper) { - foreach (NativeObjectWrapper wrapper in wrappers) + _lock.EnterWriteLock(); + try { - Remove_Locked(wrapper.ExternalComObject, wrapper); + // TryGetOrCreateObjectForComInstanceInternal may have put a new entry into the cache + // in the time between the GC cleared the contents of the GC handle but before the + // NativeObjectWrapper finalizer ran. + // Only remove the entry if the target of the GC handle is the NativeObjectWrapper + // or is null (indicating that the corresponding NativeObjectWrapper has been scheduled for finalization). + if (_cache.TryGetValue(comPointer, out WeakGCHandle cachedRef) + && (!cachedRef.TryGetTarget(out NativeObjectWrapper? cachedWrapper) + || cachedWrapper == wrapper)) + { + _cache.Remove(comPointer); + cachedRef.Dispose(); + } + } + finally + { + _lock.ExitWriteLock(); } - } - finally - { - _lock.ExitWriteLock(); - } - } - - private void Remove_Locked(IntPtr comPointer, NativeObjectWrapper wrapper) - { - Debug.Assert(_lock.IsWriteLockHeld); - // This method is used in a scenario where we already have a lock on the cache, so we can skip acquiring the lock again. - // TryGetOrCreateObjectForComInstanceInternal may have put a new entry into the cache - // in the time between the GC cleared the contents of the GC handle but before the - // NativeObjectWrapper finalizer ran. - // Only remove the entry if the target of the GC handle is the NativeObjectWrapper - // or is null (indicating that the corresponding NativeObjectWrapper has been scheduled for finalization). - if (_cache.TryGetValue(comPointer, out GCHandle cachedRef) - && (wrapper == cachedRef.Target - || cachedRef.Target is null)) - { - _cache.Remove(comPointer); - cachedRef.Free(); } } } diff --git a/src/runtime/src/libraries/System.Private.Xml.Linq/src/System/Xml/Linq/XContainer.cs b/src/runtime/src/libraries/System.Private.Xml.Linq/src/System/Xml/Linq/XContainer.cs index 8b21982599f0..e5a2b7e0fcbd 100644 --- a/src/runtime/src/libraries/System.Private.Xml.Linq/src/System/Xml/Linq/XContainer.cs +++ b/src/runtime/src/libraries/System.Private.Xml.Linq/src/System/Xml/Linq/XContainer.cs @@ -834,6 +834,10 @@ internal void ReadContentFrom(XmlReader r) ContentReader cr = new ContentReader(this); while (cr.ReadContentFrom(this, r) && r.Read()) ; + + // Materialize any text still buffered when the reader stops at end-of-input rather + // than a matching EndElement (e.g. document-level trailing whitespace on an XDocument). + cr.FlushBufferedText(); } internal void ReadContentFrom(XmlReader r, LoadOptions o) @@ -847,6 +851,10 @@ internal void ReadContentFrom(XmlReader r, LoadOptions o) ContentReader cr = new ContentReader(this, r, o); while (cr.ReadContentFromContainer(this, r) && r.Read()) ; + + // Materialize any text still buffered when the reader stops at end-of-input rather + // than a matching EndElement (e.g. document-level trailing whitespace on an XDocument). + cr.FlushBufferedText(); } internal async Task ReadContentFromAsync(XmlReader r, CancellationToken cancellationToken) @@ -859,6 +867,10 @@ internal async Task ReadContentFromAsync(XmlReader r, CancellationToken cancella cancellationToken.ThrowIfCancellationRequested(); } while (await cr.ReadContentFromAsync(this, r).ConfigureAwait(false) && await r.ReadAsync().ConfigureAwait(false)); + + // Materialize any text still buffered when the reader stops at end-of-input rather + // than a matching EndElement (e.g. document-level trailing whitespace on an XDocument). + cr.FlushBufferedText(); } internal async Task ReadContentFromAsync(XmlReader r, LoadOptions o, CancellationToken cancellationToken) @@ -876,6 +888,10 @@ internal async Task ReadContentFromAsync(XmlReader r, LoadOptions o, Cancellatio cancellationToken.ThrowIfCancellationRequested(); } while (await cr.ReadContentFromContainerAsync(this, r).ConfigureAwait(false) && await r.ReadAsync().ConfigureAwait(false)); + + // Materialize any text still buffered when the reader stops at end-of-input rather + // than a matching EndElement (e.g. document-level trailing whitespace on an XDocument). + cr.FlushBufferedText(); } private sealed class ContentReader @@ -885,6 +901,8 @@ private sealed class ContentReader private readonly IXmlLineInfo? _lineInfo; private XContainer _currentContainer; private string? _baseUri; + private string? _textValue; + private StringBuilder? _textBuffer; public ContentReader(XContainer rootContainer) { @@ -898,9 +916,64 @@ public ContentReader(XContainer rootContainer, XmlReader r, LoadOptions o) _lineInfo = (o & LoadOptions.SetLineInfo) != 0 ? r as IXmlLineInfo : null; } + private void BufferText(string value) + { + if (_textBuffer is not null) + { + _textBuffer.Append(value); + } + else if (_textValue is null) + { + _textValue = value; + } + else + { + _textBuffer = new StringBuilder(_textValue).Append(value); + _textValue = null; + } + } + + // A single text node is retained as its original string. Consecutive text nodes are + // promoted to a StringBuilder and materialized in one pass rather than being + // concatenated one chunk at a time. Some readers (notably the one used by + // DataContractSerializer over a stream) deliver a single logical text value as many + // small text nodes; appending each of them individually via AddStringSkipNotify + // concatenates immutable strings and degrades to O(n^2). Every read loop calls this + // once before handling any non-text node (so document order is preserved) and once + // more after the loop ends (so trailing buffered text is not lost when the reader + // stops at end-of-input rather than an EndElement). + internal void FlushBufferedText() + { + if (_textBuffer is StringBuilder buffer) + { + if (buffer.Length > 0) + { + _currentContainer.AddStringSkipNotify(buffer.ToString()); + } + + _textBuffer = null; + } + else if (!string.IsNullOrEmpty(_textValue)) + { + _currentContainer.AddStringSkipNotify(_textValue); + } + + _textValue = null; + } + public bool ReadContentFrom(XContainer rootContainer, XmlReader r) { - switch (r.NodeType) + XmlNodeType nodeType = r.NodeType; + if (nodeType is XmlNodeType.Text or XmlNodeType.SignificantWhitespace or XmlNodeType.Whitespace) + { + BufferText(r.Value); + return true; + } + + // Any non-text node ends the current run of text, so materialize it first. + FlushBufferedText(); + + switch (nodeType) { case XmlNodeType.Element: XElement e = new XElement(_eCache.Get(r.NamespaceURI).GetName(r.LocalName)); @@ -923,11 +996,6 @@ public bool ReadContentFrom(XContainer rootContainer, XmlReader r) if (_currentContainer == rootContainer) return false; _currentContainer = _currentContainer.parent!; break; - case XmlNodeType.Text: - case XmlNodeType.SignificantWhitespace: - case XmlNodeType.Whitespace: - _currentContainer.AddStringSkipNotify(r.Value); - break; case XmlNodeType.CDATA: _currentContainer.AddNodeSkipNotify(new XCData(r.Value)); break; @@ -947,14 +1015,24 @@ public bool ReadContentFrom(XContainer rootContainer, XmlReader r) case XmlNodeType.EndEntity: break; default: - throw new InvalidOperationException(SR.Format(SR.InvalidOperation_UnexpectedNodeType, r.NodeType)); + throw new InvalidOperationException(SR.Format(SR.InvalidOperation_UnexpectedNodeType, nodeType)); } return true; } public async ValueTask ReadContentFromAsync(XContainer rootContainer, XmlReader r) { - switch (r.NodeType) + XmlNodeType nodeType = r.NodeType; + if (nodeType is XmlNodeType.Text or XmlNodeType.SignificantWhitespace or XmlNodeType.Whitespace) + { + BufferText(await r.GetValueAsync().ConfigureAwait(false)); + return true; + } + + // Any non-text node ends the current run of text, so materialize it first. + FlushBufferedText(); + + switch (nodeType) { case XmlNodeType.Element: XElement e = new XElement(_eCache.Get(r.NamespaceURI).GetName(r.LocalName)); @@ -979,11 +1057,6 @@ public async ValueTask ReadContentFromAsync(XContainer rootContainer, XmlR if (_currentContainer == rootContainer) return false; _currentContainer = _currentContainer.parent!; break; - case XmlNodeType.Text: - case XmlNodeType.SignificantWhitespace: - case XmlNodeType.Whitespace: - _currentContainer.AddStringSkipNotify(await r.GetValueAsync().ConfigureAwait(false)); - break; case XmlNodeType.CDATA: _currentContainer.AddNodeSkipNotify(new XCData(await r.GetValueAsync().ConfigureAwait(false))); break; @@ -1003,7 +1076,7 @@ public async ValueTask ReadContentFromAsync(XContainer rootContainer, XmlR case XmlNodeType.EndEntity: break; default: - throw new InvalidOperationException(SR.Format(SR.InvalidOperation_UnexpectedNodeType, r.NodeType)); + throw new InvalidOperationException(SR.Format(SR.InvalidOperation_UnexpectedNodeType, nodeType)); } return true; } @@ -1012,8 +1085,22 @@ public bool ReadContentFromContainer(XContainer rootContainer, XmlReader r) { XNode? newNode = null; string baseUri = r.BaseURI; + XmlNodeType nodeType = r.NodeType; + + // Fast path: coalesce a run of adjacent text. Text that must carry its own + // baseUri or line info can't be coalesced, so it falls through to be created as a + // standalone XText node in the switch below. + if (nodeType is XmlNodeType.Text or XmlNodeType.SignificantWhitespace or XmlNodeType.Whitespace + && !((_baseUri != null && _baseUri != baseUri) || (_lineInfo != null && _lineInfo.HasLineInfo()))) + { + BufferText(r.Value); + return true; + } + + // Any other node ends the current run of text, so materialize it first. + FlushBufferedText(); - switch (r.NodeType) + switch (nodeType) { case XmlNodeType.Element: { @@ -1072,15 +1159,9 @@ public bool ReadContentFromContainer(XContainer rootContainer, XmlReader r) case XmlNodeType.Text: case XmlNodeType.SignificantWhitespace: case XmlNodeType.Whitespace: - if ((_baseUri != null && _baseUri != baseUri) || - (_lineInfo != null && _lineInfo.HasLineInfo())) - { - newNode = new XText(r.Value); - } - else - { - _currentContainer.AddStringSkipNotify(r.Value); - } + // Only reached for text that needs its own baseUri/line info; plain text + // runs are coalesced by the fast path above. + newNode = new XText(r.Value); break; case XmlNodeType.CDATA: newNode = new XCData(r.Value); @@ -1101,7 +1182,7 @@ public bool ReadContentFromContainer(XContainer rootContainer, XmlReader r) case XmlNodeType.EndEntity: break; default: - throw new InvalidOperationException(SR.Format(SR.InvalidOperation_UnexpectedNodeType, r.NodeType)); + throw new InvalidOperationException(SR.Format(SR.InvalidOperation_UnexpectedNodeType, nodeType)); } if (newNode != null) @@ -1126,8 +1207,22 @@ public async ValueTask ReadContentFromContainerAsync(XContainer rootContai { XNode? newNode = null; string baseUri = r.BaseURI!; + XmlNodeType nodeType = r.NodeType; + + // Fast path: coalesce a run of adjacent text. Text that must carry its own + // baseUri or line info can't be coalesced, so it falls through to be created as a + // standalone XText node in the switch below. + if (nodeType is XmlNodeType.Text or XmlNodeType.SignificantWhitespace or XmlNodeType.Whitespace + && !((_baseUri != null && _baseUri != baseUri) || (_lineInfo != null && _lineInfo.HasLineInfo()))) + { + BufferText(await r.GetValueAsync().ConfigureAwait(false)); + return true; + } + + // Any other node ends the current run of text, so materialize it first. + FlushBufferedText(); - switch (r.NodeType) + switch (nodeType) { case XmlNodeType.Element: { @@ -1188,15 +1283,9 @@ public async ValueTask ReadContentFromContainerAsync(XContainer rootContai case XmlNodeType.Text: case XmlNodeType.SignificantWhitespace: case XmlNodeType.Whitespace: - if ((_baseUri != null && _baseUri != baseUri) || - (_lineInfo != null && _lineInfo.HasLineInfo())) - { - newNode = new XText(await r.GetValueAsync().ConfigureAwait(false)); - } - else - { - _currentContainer.AddStringSkipNotify(await r.GetValueAsync().ConfigureAwait(false)); - } + // Only reached for text that needs its own baseUri/line info; plain text + // runs are coalesced by the fast path above. + newNode = new XText(await r.GetValueAsync().ConfigureAwait(false)); break; case XmlNodeType.CDATA: newNode = new XCData(await r.GetValueAsync().ConfigureAwait(false)); @@ -1217,7 +1306,7 @@ public async ValueTask ReadContentFromContainerAsync(XContainer rootContai case XmlNodeType.EndEntity: break; default: - throw new InvalidOperationException(SR.Format(SR.InvalidOperation_UnexpectedNodeType, r.NodeType)); + throw new InvalidOperationException(SR.Format(SR.InvalidOperation_UnexpectedNodeType, nodeType)); } if (newNode != null) diff --git a/src/runtime/src/libraries/System.Private.Xml.Linq/tests/misc/RegressionTests.cs b/src/runtime/src/libraries/System.Private.Xml.Linq/tests/misc/RegressionTests.cs index acb946bee68b..9c316582e396 100644 --- a/src/runtime/src/libraries/System.Private.Xml.Linq/tests/misc/RegressionTests.cs +++ b/src/runtime/src/libraries/System.Private.Xml.Linq/tests/misc/RegressionTests.cs @@ -1,10 +1,13 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics; using System.IO; using System.Linq; using System.Collections.Generic; using System.Text; +using System.Threading.Tasks; +using System.Xml; using Microsoft.Test.ModuleCore; using Xunit; @@ -229,5 +232,212 @@ public static IEnumerable GetObjects() yield return new object[] { new Guid(), typeof(Guid) }; yield return new object[] { d, typeof(Dictionary) }; } + + // When a reader delivers a single logical text value as many small text nodes (as the + // reader used by DataContractSerializer over a stream does), loading must remain linear + // and still coalesce the chunks into a single, correct text value rather than + // concatenating them one at a time. + [Theory] + [InlineData(1)] + [InlineData(7)] + public void LoadCoalescesChunkedTextIntoSingleNode(int chunkSize) + { + var original = new XElement("root", string.Join("\n", Enumerable.Repeat(new string('a', 40), 100))); + string xml = original.ToString(SaveOptions.DisableFormatting); + + XElement loaded = LoadChunked(xml, chunkSize, LoadOptions.None); + + Assert.Equal(original.Value, loaded.Value); + XText textNode = Assert.IsType(Assert.Single(loaded.Nodes())); + Assert.Equal(original.Value, textNode.Value); + } + + [Fact] + public void LoadSingleTextNodeReusesReaderValue() + { + const string xml = "single text value"; + using var reader = new ChunkingXmlReader(XmlReader.Create(new StringReader(xml)), int.MaxValue); + + XElement loaded = XElement.Load(reader, LoadOptions.None); + + XText textNode = Assert.IsType(Assert.Single(loaded.Nodes())); + Assert.Same(reader.LastTextValue, textNode.Value); + } + + [Theory] + [InlineData(1)] + [InlineData(3)] + public void LoadChunkedTextPreservesMixedContent(int chunkSize) + { + const string xml = "hello worldinner texttrailing text"; + + XElement loaded = LoadChunked(xml, chunkSize, LoadOptions.None); + + Assert.Equal(xml, loaded.ToString(SaveOptions.DisableFormatting)); + Assert.Equal("hello world", ((XText)loaded.FirstNode).Value); + Assert.Equal("inner text", loaded.Element("child").Value); + Assert.Equal("trailing text", ((XText)loaded.LastNode).Value); + } + + [Fact] + public void LoadChunkedTextWithBaseUriOptionCoalesces() + { + // LoadOptions.SetBaseUri routes through the ContentReader "container" code path. + var original = new XElement("root", string.Join("\n", Enumerable.Repeat(new string('b', 30), 80))); + string xml = original.ToString(SaveOptions.DisableFormatting); + + XElement loaded = LoadChunked(xml, chunkSize: 1, LoadOptions.SetBaseUri); + + Assert.Equal(original.Value, loaded.Value); + } + + [Theory] + [InlineData(1)] + [InlineData(7)] + public async Task LoadAsyncCoalescesChunkedText(int chunkSize) + { + var original = new XElement("root", string.Join("\n", Enumerable.Repeat(new string('c', 40), 100))); + string xml = original.ToString(SaveOptions.DisableFormatting); + + using var reader = new ChunkingXmlReader(XmlReader.Create(new StringReader(xml)), chunkSize); + XElement loaded = await XElement.LoadAsync(reader, LoadOptions.None, default); + + Assert.Equal(original.Value, loaded.Value); + Assert.Equal(original.Value, Assert.IsType(Assert.Single(loaded.Nodes())).Value); + } + + private static XElement LoadChunked(string xml, int chunkSize, LoadOptions options) + { + using var reader = new ChunkingXmlReader(XmlReader.Create(new StringReader(xml)), chunkSize); + return XElement.Load(reader, options); + } + + // With buffering, loading a heavily-chunked text value is O(n). Reverting to per-chunk + // string concatenation makes it O(n^2), which would take minutes for this input instead + // of well under a second, so the generous time bound only trips on an algorithmic + // regression, not on normal machine-speed variance. + [Fact] + public void LoadChunkedLargeTextRemainsLinear() + { + const int length = 750_000; + string xml = "" + new string('a', length) + ""; + + var stopwatch = Stopwatch.StartNew(); + XElement loaded = LoadChunked(xml, chunkSize: 1, LoadOptions.None); + stopwatch.Stop(); + + Assert.Equal(length, loaded.Value.Length); + Assert.True( + stopwatch.Elapsed < TimeSpan.FromSeconds(30), + $"Chunked load took {stopwatch.Elapsed.TotalSeconds:F1}s; expected linear-time completion."); + } + + // Wraps an XmlReader and reports each text node's value in fixed-size chunks, emulating + // readers that surface large text content as many small text nodes. + private sealed class ChunkingXmlReader : XmlReader + { + private readonly XmlReader _inner; + private readonly int _chunkSize; + private string? _pendingText; + private int _position; + + public string? LastTextValue { get; private set; } + + public ChunkingXmlReader(XmlReader inner, int chunkSize) + { + _inner = inner; + _chunkSize = chunkSize; + } + + public override bool Read() + { + if (_pendingText != null) + { + _position += _chunkSize; + if (_position < _pendingText.Length) + { + return true; + } + + _pendingText = null; + _position = 0; + } + + if (!_inner.Read()) + { + return false; + } + + if (_inner.NodeType == XmlNodeType.Text && _inner.Value.Length > _chunkSize) + { + _pendingText = _inner.Value; + _position = 0; + } + + return true; + } + + public override Task ReadAsync() => Task.FromResult(Read()); + + public override Task GetValueAsync() => Task.FromResult(Value); + + public override XmlNodeType NodeType => _pendingText != null ? XmlNodeType.Text : _inner.NodeType; + + public override string Value + { + get + { + string value; + if (_pendingText != null) + { + value = _pendingText.Substring(_position, Math.Min(_chunkSize, _pendingText.Length - _position)); + } + else + { + value = _inner.Value; + } + + if (NodeType == XmlNodeType.Text) + { + LastTextValue = value; + } + + return value; + } + } + + public override int AttributeCount => _inner.AttributeCount; + public override string BaseURI => _inner.BaseURI; + public override int Depth => _inner.Depth; + public override bool EOF => _inner.EOF; + public override bool IsEmptyElement => _inner.IsEmptyElement; + public override string LocalName => _inner.LocalName; + public override string NamespaceURI => _inner.NamespaceURI; + public override XmlNameTable NameTable => _inner.NameTable; + public override string Prefix => _inner.Prefix; + public override ReadState ReadState => _inner.ReadState; + + public override string GetAttribute(int i) => _inner.GetAttribute(i); + public override string? GetAttribute(string name) => _inner.GetAttribute(name); + public override string? GetAttribute(string name, string? namespaceURI) => _inner.GetAttribute(name, namespaceURI); + public override string? LookupNamespace(string prefix) => _inner.LookupNamespace(prefix); + public override bool MoveToAttribute(string name) => _inner.MoveToAttribute(name); + public override bool MoveToAttribute(string name, string? ns) => _inner.MoveToAttribute(name, ns); + public override bool MoveToElement() => _inner.MoveToElement(); + public override bool MoveToFirstAttribute() => _inner.MoveToFirstAttribute(); + public override bool MoveToNextAttribute() => _inner.MoveToNextAttribute(); + public override bool ReadAttributeValue() => _inner.ReadAttributeValue(); + public override void ResolveEntity() => _inner.ResolveEntity(); + + protected override void Dispose(bool disposing) + { + if (disposing) + { + _inner.Dispose(); + } + + base.Dispose(disposing); + } + } } } diff --git a/src/runtime/src/libraries/System.Private.Xml/src/System/Xml/Serialization/ReflectionXmlSerializationReader.cs b/src/runtime/src/libraries/System.Private.Xml/src/System/Xml/Serialization/ReflectionXmlSerializationReader.cs index f2fc2d330f4d..38aad4bea5a3 100644 --- a/src/runtime/src/libraries/System.Private.Xml/src/System/Xml/Serialization/ReflectionXmlSerializationReader.cs +++ b/src/runtime/src/libraries/System.Private.Xml/src/System/Xml/Serialization/ReflectionXmlSerializationReader.cs @@ -911,7 +911,6 @@ private void WriteMemberElementsIf(Member[] expectedMembers, Member? anyElementM } else if (!element.Mapping!.IsSoap && (element.Mapping is PrimitiveMapping)) { - HandleUnknownAttributes(); if (element.IsNullable && ReadNull()) { if (element.Mapping.TypeDesc!.IsValueType) @@ -923,51 +922,56 @@ private void WriteMemberElementsIf(Member[] expectedMembers, Member? anyElementM value = null; } } - else if ((element.Default != null && element.Default != DBNull.Value && element.Mapping.TypeDesc!.IsValueType) - && (Reader.IsEmptyElement)) - { - Reader.Skip(); - } - else if (element.Mapping.TypeDesc!.Type == typeof(TimeSpan) && Reader.IsEmptyElement) - { - Reader.Skip(); - value = default(TimeSpan); - } - else if (element.Mapping.TypeDesc!.Type == typeof(DateTimeOffset) && Reader.IsEmptyElement) - { - Reader.Skip(); - value = default(DateTimeOffset); - } - else if (element.Mapping.TypeDesc!.Type == typeof(DateOnly) && Reader.IsEmptyElement) - { - Reader.Skip(); - value = default(DateOnly); - } - else if (element.Mapping.TypeDesc!.Type == typeof(TimeOnly) && Reader.IsEmptyElement) - { - Reader.Skip(); - value = default(TimeOnly); - } else { - if (element.Mapping.TypeDesc == QnameTypeDesc) + HandleUnknownAttributes(); + + if ((element.Default != null && element.Default != DBNull.Value && element.Mapping.TypeDesc!.IsValueType) + && (Reader.IsEmptyElement)) + { + Reader.Skip(); + } + else if (element.Mapping.TypeDesc!.Type == typeof(TimeSpan) && Reader.IsEmptyElement) + { + Reader.Skip(); + value = default(TimeSpan); + } + else if (element.Mapping.TypeDesc!.Type == typeof(DateTimeOffset) && Reader.IsEmptyElement) + { + Reader.Skip(); + value = default(DateTimeOffset); + } + else if (element.Mapping.TypeDesc!.Type == typeof(DateOnly) && Reader.IsEmptyElement) { - value = ReadElementQualifiedName(); + Reader.Skip(); + value = default(DateOnly); + } + else if (element.Mapping.TypeDesc!.Type == typeof(TimeOnly) && Reader.IsEmptyElement) + { + Reader.Skip(); + value = default(TimeOnly); } else { - if (element.Mapping.TypeDesc.FormatterName == "ByteArrayBase64") - { - value = ToByteArrayBase64(false); - } - else if (element.Mapping.TypeDesc.FormatterName == "ByteArrayHex") + if (element.Mapping.TypeDesc == QnameTypeDesc) { - value = ToByteArrayHex(false); + value = ReadElementQualifiedName(); } else { - Func readFunc = (state) => ((XmlReader)state).ReadElementContentAsString(); - value = WritePrimitive(element.Mapping, readFunc, Reader); + if (element.Mapping.TypeDesc.FormatterName == "ByteArrayBase64") + { + value = ToByteArrayBase64(false); + } + else if (element.Mapping.TypeDesc.FormatterName == "ByteArrayHex") + { + value = ToByteArrayHex(false); + } + else + { + Func readFunc = (state) => ((XmlReader)state).ReadElementContentAsString(); + value = WritePrimitive(element.Mapping, readFunc, Reader); + } } } } @@ -1221,9 +1225,10 @@ private static bool IsWildcard(SpecialMapping mapping) } else { - HandleUnknownAttributes(); if (!ReadNull()) { + HandleUnknownAttributes(); + var memberMapping = new MemberMapping() { Elements = arrayMapping.Elements, @@ -1987,13 +1992,12 @@ private bool WriteDerivedTypes(out object? o, StructMapping mapping, XmlQualifie // on elements mapped to primitives, arrays, and collections are surfaced consistently. private void HandleUnknownAttributes() { - // When the element is marked xsi:nil, the nil marker (and the element itself) is consumed - // by the following ReadNull() call, so its attributes must not be surfaced as unknown. This - // also matches the struct path, where a nil element returns before its attributes are read. - if (GetNullAttr()) + if (!HasUnknownNodeOrAttributeEvents || + !Reader.HasAttributes) { return; } + while (Reader.MoveToNextAttribute()) { if (!IsXmlnsAttribute(Reader.Name)) diff --git a/src/runtime/src/libraries/System.Private.Xml/src/System/Xml/Serialization/ReflectionXmlSerializationWriter.cs b/src/runtime/src/libraries/System.Private.Xml/src/System/Xml/Serialization/ReflectionXmlSerializationWriter.cs index 045c94604210..c2920927d69e 100644 --- a/src/runtime/src/libraries/System.Private.Xml/src/System/Xml/Serialization/ReflectionXmlSerializationWriter.cs +++ b/src/runtime/src/libraries/System.Private.Xml/src/System/Xml/Serialization/ReflectionXmlSerializationWriter.cs @@ -7,6 +7,7 @@ using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Reflection; +using System.Runtime.CompilerServices; using System.Text; using System.Xml.Schema; @@ -156,13 +157,25 @@ private void WriteArrayItems(ElementAccessor[] elements, TextAccessor? text, Cho // its items are written as a single whitespace-separated list so that the value round-trips. bool isListText = text != null && text.IsList && elements.Length == 0; - var arr = o as IList; + IList? list = o as IList; + if (list is not null && list.Count == 0) + { + return; + } + + if (TryWritePrimitiveItems(elements, text, choice, o)) + { + return; + } - if (arr != null) + Array? choiceArray = choiceSources as Array; + if (list is not null) { - for (int i = 0; i < arr.Count; i++) + for (int i = 0; i < list.Count; i++) { - object? ai = arr[i]; + object? ai = list[i]; + object? choiceSource = choiceArray?.GetValue(i); + if (isListText && i > 0) { // Separate list items with a single space. The separator is written purely by @@ -173,7 +186,6 @@ private void WriteArrayItems(ElementAccessor[] elements, TextAccessor? text, Cho WriteValue(" "); } - var choiceSource = ((Array?)choiceSources)?.GetValue(i); WriteElements(ai, choiceSource, elements, text, choice, true, true); } } @@ -189,18 +201,145 @@ private void WriteArrayItems(ElementAccessor[] elements, TextAccessor? text, Cho while (e.MoveNext()) { object ai = e.Current; + object? choiceSource = choiceArray?.GetValue(c++); + if (isListText && c > 0) { WriteValue(" "); } - var choiceSource = ((Array?)choiceSources)?.GetValue(c++); WriteElements(ai, choiceSource, elements, text, choice, true, true); } } } } + private bool TryWritePrimitiveItems(ElementAccessor[] elements, TextAccessor? text, ChoiceIdentifierAccessor? choice, object o) + { + if (elements.Length != 1 || + text is not null || + choice is not null || + elements[0].Mapping is not PrimitiveMapping mapping || + mapping is EnumMapping) + { + return false; + } + + ElementAccessor element = elements[0]; + Type? elementType = mapping.TypeDesc!.Type; + + if (elementType == typeof(bool)) + return TryWritePrimitiveItems(o, element, mapping, static value => XmlConvert.ToString(value)); + if (elementType == typeof(byte)) + return TryWritePrimitiveItems(o, element, mapping, static value => XmlConvert.ToString(value)); + if (elementType == typeof(sbyte)) + return TryWritePrimitiveItems(o, element, mapping, static value => XmlConvert.ToString(value)); + if (elementType == typeof(short)) + return TryWritePrimitiveItems(o, element, mapping, static value => XmlConvert.ToString(value)); + if (elementType == typeof(ushort)) + return TryWritePrimitiveItems(o, element, mapping, static value => XmlConvert.ToString(value)); + if (elementType == typeof(int)) + return TryWritePrimitiveItems(o, element, mapping, static value => XmlConvert.ToString(value)); + if (elementType == typeof(uint)) + return TryWritePrimitiveItems(o, element, mapping, static value => XmlConvert.ToString(value)); + if (elementType == typeof(long)) + return TryWritePrimitiveItems(o, element, mapping, static value => XmlConvert.ToString(value)); + if (elementType == typeof(ulong)) + return TryWritePrimitiveItems(o, element, mapping, static value => XmlConvert.ToString(value)); + if (elementType == typeof(float)) + return TryWritePrimitiveItems(o, element, mapping, static value => XmlConvert.ToString(value)); + if (elementType == typeof(double)) + return TryWritePrimitiveItems(o, element, mapping, static value => XmlConvert.ToString(value)); + if (elementType == typeof(decimal)) + return TryWritePrimitiveItems(o, element, mapping, static value => XmlConvert.ToString(value)); + if (elementType == typeof(DateTime)) + { + return mapping.TypeDesc.FormatterName switch + { + "DateTime" => TryWritePrimitiveItems(o, element, mapping, static value => XmlCustomFormatter.FromDateTime(value)), + "Date" => TryWritePrimitiveItems(o, element, mapping, static value => XmlCustomFormatter.FromDate(value)), + "Time" => TryWritePrimitiveItems(o, element, mapping, static value => XmlCustomFormatter.FromTime(value)), + _ => false, + }; + } + if (elementType == typeof(Guid)) + return TryWritePrimitiveItems(o, element, mapping, static value => XmlConvert.ToString(value)); + if (elementType == typeof(char)) + return TryWritePrimitiveItems(o, element, mapping, static value => XmlCustomFormatter.FromChar(value)); + if (elementType == typeof(TimeSpan)) + return TryWritePrimitiveItems(o, element, mapping, static value => XmlConvert.ToString(value)); + if (elementType == typeof(DateTimeOffset)) + return TryWritePrimitiveItems(o, element, mapping, static value => XmlConvert.ToString(value)); + if (elementType == typeof(DateOnly)) + return TryWritePrimitiveItems(o, element, mapping, static value => XmlCustomFormatter.FromDateOnly(value)); + if (elementType == typeof(TimeOnly)) + return TryWritePrimitiveItems(o, element, mapping, static value => XmlCustomFormatter.FromTimeOnly(value)); + + return false; + } + + private bool TryWritePrimitiveItems(object o, ElementAccessor element, PrimitiveMapping mapping, Func formatter) + where T : struct + { + if (o is not IEnumerable items) + { + return false; + } + + string name = element.Name; + string? ns = element.Any && element.Name.Length == 0 ? null : (element.Form == XmlSchemaForm.Qualified ? element.Namespace : string.Empty); + WritePrimitiveMethodRequirement suffixNullable = mapping.IsSoap ? WritePrimitiveMethodRequirement.Encoded : WritePrimitiveMethodRequirement.None; + WritePrimitiveMethodRequirement suffixRaw = mapping.TypeDesc!.XmlEncodingNotRequired ? WritePrimitiveMethodRequirement.Raw : WritePrimitiveMethodRequirement.None; + WritePrimitiveMethodRequirement method = element.IsNullable + ? WritePrimitiveMethodRequirement.WriteNullableStringLiteral | suffixNullable | suffixRaw + : WritePrimitiveMethodRequirement.WriteElementString | suffixRaw; + XmlQualifiedName? xmlQualifiedName = mapping.IsSoap ? new XmlQualifiedName(mapping.TypeName, mapping.Namespace) : null; + bool hasDefault = mapping.TypeDesc.HasDefaultSupport && element.Default is T; + T defaultValue = hasDefault ? (T)element.Default! : default; + + if (items is T[] array) + { + for (int i = 0; i < array.Length; i++) + { + WritePrimitiveItem(method, name, ns, array[i], hasDefault, defaultValue, xmlQualifiedName, formatter); + } + } + else if (o is IList && items is IList list) + { + for (int i = 0; i < list.Count; i++) + { + WritePrimitiveItem(method, name, ns, list[i], hasDefault, defaultValue, xmlQualifiedName, formatter); + } + } + else + { + foreach (T item in items) + { + WritePrimitiveItem(method, name, ns, item, hasDefault, defaultValue, xmlQualifiedName, formatter); + } + } + + return true; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void WritePrimitiveItem( + WritePrimitiveMethodRequirement method, + string name, + string? ns, + T value, + bool hasDefault, + T defaultValue, + XmlQualifiedName? xmlQualifiedName, + Func formatter) + where T : struct + { + if (!hasDefault || !EqualityComparer.Default.Equals(value, defaultValue)) + { + WritePrimitiveString(method, name, ns, formatter(value), xmlQualifiedName); + } + } + private void WriteElements(object? o, object? choiceSource, ElementAccessor[] elements, TextAccessor? text, ChoiceIdentifierAccessor? choice, bool writeAccessors, bool isNullable) { if (elements.Length == 0 && text == null) @@ -1064,71 +1203,75 @@ private void WritePrimitive(WritePrimitiveMethodRequirement method, string name, if (hasValidStringValue) { - if (hasRequirement(method, WritePrimitiveMethodRequirement.WriteElementString)) + WritePrimitiveString(method, name, ns, stringValue, xmlQualifiedName); + } + else if (o is byte[] a) + { + if (hasRequirement(method, WritePrimitiveMethodRequirement.WriteElementString | WritePrimitiveMethodRequirement.Raw)) { - if (hasRequirement(method, WritePrimitiveMethodRequirement.Raw)) - { - WriteElementStringRaw(name, ns, stringValue, xmlQualifiedName); - } - else - { - WriteElementString(name, ns, stringValue, xmlQualifiedName); - } + WriteElementStringRaw(name, ns, FromByteArrayBase64(a)); } - - else if (hasRequirement(method, WritePrimitiveMethodRequirement.WriteNullableStringLiteral)) + else if (hasRequirement(method, WritePrimitiveMethodRequirement.WriteNullableStringLiteral | WritePrimitiveMethodRequirement.Raw)) { - if (hasRequirement(method, WritePrimitiveMethodRequirement.Encoded)) - { - if (hasRequirement(method, WritePrimitiveMethodRequirement.Raw)) - { - WriteNullableStringEncodedRaw(name, ns, stringValue, xmlQualifiedName); - } - else - { - WriteNullableStringEncoded(name, ns, stringValue, xmlQualifiedName); - } - } - else - { - if (hasRequirement(method, WritePrimitiveMethodRequirement.Raw)) - { - WriteNullableStringLiteralRaw(name, ns, stringValue); - } - else - { - WriteNullableStringLiteral(name, ns, stringValue); - } - } + WriteNullableStringLiteralRaw(name, ns, FromByteArrayBase64(a)); } else if (hasRequirement(method, WritePrimitiveMethodRequirement.WriteAttribute)) { - WriteAttribute(name, ns, stringValue); + WriteAttribute(name, ns!, a); } else { Debug.Fail("https://github.com/dotnet/runtime/issues/18037: Add More Tests for Serialization Code"); } } - else if (o is byte[] a) + else { - if (hasRequirement(method, WritePrimitiveMethodRequirement.WriteElementString | WritePrimitiveMethodRequirement.Raw)) + Debug.Fail("https://github.com/dotnet/runtime/issues/18037: Add More Tests for Serialization Code"); + } + } + + private void WritePrimitiveString(WritePrimitiveMethodRequirement method, string name, string? ns, string? value, XmlQualifiedName? xmlQualifiedName) + { + if (hasRequirement(method, WritePrimitiveMethodRequirement.WriteElementString)) + { + if (hasRequirement(method, WritePrimitiveMethodRequirement.Raw)) { - WriteElementStringRaw(name, ns, FromByteArrayBase64(a)); + WriteElementStringRaw(name, ns, value, xmlQualifiedName); } - else if (hasRequirement(method, WritePrimitiveMethodRequirement.WriteNullableStringLiteral | WritePrimitiveMethodRequirement.Raw)) + else { - WriteNullableStringLiteralRaw(name, ns, FromByteArrayBase64(a)); + WriteElementString(name, ns, value, xmlQualifiedName); } - else if (hasRequirement(method, WritePrimitiveMethodRequirement.WriteAttribute)) + } + else if (hasRequirement(method, WritePrimitiveMethodRequirement.WriteNullableStringLiteral)) + { + if (hasRequirement(method, WritePrimitiveMethodRequirement.Encoded)) { - WriteAttribute(name, ns!, a); + if (hasRequirement(method, WritePrimitiveMethodRequirement.Raw)) + { + WriteNullableStringEncodedRaw(name, ns, value, xmlQualifiedName); + } + else + { + WriteNullableStringEncoded(name, ns, value, xmlQualifiedName); + } } else { - Debug.Fail("https://github.com/dotnet/runtime/issues/18037: Add More Tests for Serialization Code"); + if (hasRequirement(method, WritePrimitiveMethodRequirement.Raw)) + { + WriteNullableStringLiteralRaw(name, ns, value); + } + else + { + WriteNullableStringLiteral(name, ns, value); + } } } + else if (hasRequirement(method, WritePrimitiveMethodRequirement.WriteAttribute)) + { + WriteAttribute(name, ns, value); + } else { Debug.Fail("https://github.com/dotnet/runtime/issues/18037: Add More Tests for Serialization Code"); diff --git a/src/runtime/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationReader.cs b/src/runtime/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationReader.cs index e8aefa82127f..5599c72dac04 100644 --- a/src/runtime/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationReader.cs +++ b/src/runtime/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationReader.cs @@ -163,6 +163,9 @@ protected XmlReader Reader } } + internal bool HasUnknownNodeOrAttributeEvents => + _events.OnUnknownNode is not null || _events.OnUnknownAttribute is not null; + protected int ReaderCount { get { return 0; } @@ -4612,10 +4615,7 @@ private void WriteSourceEnd(string source) // surfaced consistently. private void WriteHandleUnknownAttributes() { - // When the element is marked xsi:nil, the nil marker (and the element itself) is consumed - // by the following ReadNull() call, so its attributes must not be surfaced as unknown. This - // also matches the struct path, where a nil element returns before its attributes are read. - Writer.WriteLine("if (!GetNullAttr()) {"); + Writer.WriteLine("if (Reader.HasAttributes) {"); Writer.Indent++; Writer.WriteLine("while (Reader.MoveToNextAttribute()) {"); Writer.Indent++; @@ -4672,9 +4672,9 @@ private void WriteArray(string source, string? arrayName, ArrayMapping arrayMapp } else { - WriteHandleUnknownAttributes(); Writer.WriteLine("if (!ReadNull()) {"); Writer.Indent++; + WriteHandleUnknownAttributes(); MemberMapping memberMapping = new MemberMapping(); memberMapping.Elements = arrayMapping.Elements; @@ -4761,7 +4761,6 @@ private void WriteElement(string source, string? arrayName, string? choiceSource } else if (!element.Mapping!.IsSoap && (element.Mapping is PrimitiveMapping)) { - WriteHandleUnknownAttributes(); if (element.IsNullable) { Writer.WriteLine("if (ReadNull()) {"); @@ -4779,7 +4778,13 @@ private void WriteElement(string source, string? arrayName, string? choiceSource Writer.WriteLine(";"); Writer.Indent--; Writer.WriteLine("}"); - Writer.Write("else "); + Writer.WriteLine("else {"); + Writer.Indent++; + WriteHandleUnknownAttributes(); + } + else + { + WriteHandleUnknownAttributes(); } if (element.Default != null && element.Default != DBNull.Value && element.Mapping.TypeDesc!.IsValueType) { @@ -4858,6 +4863,11 @@ private void WriteElement(string source, string? arrayName, string? choiceSource } Writer.Indent--; Writer.WriteLine("}"); + if (element.IsNullable) + { + Writer.Indent--; + Writer.WriteLine("}"); + } } else if (element.Mapping is StructMapping || (element.Mapping.IsSoap && element.Mapping is PrimitiveMapping)) { diff --git a/src/runtime/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationReaderILGen.cs b/src/runtime/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationReaderILGen.cs index 4fa85b2227b8..5dbb439da549 100644 --- a/src/runtime/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationReaderILGen.cs +++ b/src/runtime/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationReaderILGen.cs @@ -2967,13 +2967,13 @@ private void WriteSourceEnd(string source, Type elementType, Type stackType) // surfaced consistently. private void WriteHandleUnknownAttributes() { - MethodInfo XmlSerializationReader_GetNullAttr = typeof(XmlSerializationReader).GetMethod( - "GetNullAttr", + MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod( + "get_Reader", CodeGenerator.InstanceBindingFlags, Type.EmptyTypes )!; - MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod( - "get_Reader", + MethodInfo XmlReader_get_HasAttributes = typeof(XmlReader).GetMethod( + "get_HasAttributes", CodeGenerator.InstanceBindingFlags, Type.EmptyTypes )!; @@ -3003,14 +3003,10 @@ private void WriteHandleUnknownAttributes() Type.EmptyTypes )!; - // When the element is marked xsi:nil, the nil marker (and the element itself) is consumed - // by the following ReadNull() call, so its attributes must not be surfaced as unknown. This - // also matches the struct path, where a nil element returns before its attributes are read. - // if (!GetNullAttr()) { ilg.Ldarg(0); - ilg.Call(XmlSerializationReader_GetNullAttr); - ilg.Ldc(false); - ilg.If(Cmp.EqualTo); + ilg.Call(XmlSerializationReader_get_Reader); + ilg.Call(XmlReader_get_HasAttributes); + ilg.If(); { // while (Reader.MoveToNextAttribute()) { // if (!IsXmlnsAttribute(Reader.Name)) { @@ -3051,11 +3047,6 @@ private void WriteHandleUnknownAttributes() private void WriteArray(string source, string? arrayName, ArrayMapping arrayMapping, bool readOnly, bool isNullable, int elementIndex) { - if (!arrayMapping.IsSoap) - { - WriteHandleUnknownAttributes(); - } - MethodInfo XmlSerializationReader_ReadNull = typeof(XmlSerializationReader).GetMethod( "ReadNull", CodeGenerator.InstanceBindingFlags, @@ -3066,6 +3057,11 @@ private void WriteArray(string source, string? arrayName, ArrayMapping arrayMapp ilg.IfNot(); // if (!ReadNull()) { // EnterScope ilg.EnterScope(); + if (!arrayMapping.IsSoap) + { + WriteHandleUnknownAttributes(); + } + MemberMapping memberMapping = new MemberMapping(); memberMapping.Elements = arrayMapping.Elements; memberMapping.TypeDesc = arrayMapping.TypeDesc; @@ -3203,10 +3199,6 @@ private void WriteElement(string source, string? arrayName, string? choiceSource } else if (element.Mapping is PrimitiveMapping) { - if (!element.Mapping.IsSoap) - { - WriteHandleUnknownAttributes(); - } bool doEndIf = false; if (element.IsNullable) { @@ -3231,6 +3223,10 @@ private void WriteElement(string source, string? arrayName, string? choiceSource ilg.Else(); doEndIf = true; } + if (!element.Mapping.IsSoap) + { + WriteHandleUnknownAttributes(); + } if (element.Default != null && element.Default != DBNull.Value && element.Mapping.TypeDesc!.IsValueType) { MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod( diff --git a/src/runtime/src/libraries/System.Private.Xml/tests/XmlSerializer/XmlSerializerTests.cs b/src/runtime/src/libraries/System.Private.Xml/tests/XmlSerializer/XmlSerializerTests.cs index 2c4d6ac5423e..e939a8a06de9 100644 --- a/src/runtime/src/libraries/System.Private.Xml/tests/XmlSerializer/XmlSerializerTests.cs +++ b/src/runtime/src/libraries/System.Private.Xml/tests/XmlSerializer/XmlSerializerTests.cs @@ -183,6 +183,88 @@ public static void Xml_ArrayAsGetSet() Assert.Null(y.P2); // Arrays stay null } + // These runtime-only test types are not included in the SerializableAssembly used by the pre-generated serializer tests. +#if !XMLSERIALIZERGENERATORTESTS + [Fact] + public static void Xml_PrimitiveArraysAndCollections() + { + var value = new PrimitiveCollections + { + Chars = new[] { 'A', '\u03A9' }, + Dates = new[] { new DateTime(2024, 1, 2, 0, 0, 0, DateTimeKind.Utc) }, + Times = new[] { new DateTime(1, 1, 1, 3, 4, 5, DateTimeKind.Utc) }, + DateOnlyValues = new[] { new DateOnly(2024, 1, 2) }, + TimeOnlyValues = new[] { new TimeOnly(3, 4, 5) }, + Integers = new List { -1, 0, 42 }, + EnumerableIntegers = new IntEnumerableCollection { 5, 6 }, + EmptyIntegers = Array.Empty(), + Enums = new[] { PrimitiveCollectionEnum.One, PrimitiveCollectionEnum.Two }, + NullableIntegers = new int?[] { 7, null, 9 }, + BoxedIntegers = new ArrayList { 10, 11 }, + }; + + PrimitiveCollections actual = SerializeAndDeserialize( + value, + """ + + + + 65 + 937 + + + 2024-01-02 + + + + + + 2024-01-02 + + + 03:04:05 + + + -1 + 0 + 42 + + + 5 + 6 + + + + One + Two + + + 7 + + 9 + + + 10 + 11 + + + """); + + Assert.Equal(value.Chars, actual.Chars); + Assert.Equal(value.Dates, actual.Dates); + Assert.Equal(value.Times, actual.Times); + Assert.Equal(value.DateOnlyValues, actual.DateOnlyValues); + Assert.Equal(value.TimeOnlyValues, actual.TimeOnlyValues); + Assert.Equal(value.Integers, actual.Integers); + Assert.Equal(value.EnumerableIntegers, actual.EnumerableIntegers); + Assert.Empty(actual.EmptyIntegers); + Assert.Equal(value.Enums, actual.Enums); + Assert.Equal(value.NullableIntegers, actual.NullableIntegers); + Assert.Equal(value.BoxedIntegers.Cast(), actual.BoxedIntegers.Cast()); + } + +#endif + [Fact] public static void Xml_ArrayAsGetOnly() { diff --git a/src/runtime/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ConvertToLibraryImportFixerTests.cs b/src/runtime/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ConvertToLibraryImportFixerTests.cs index ccff8deaedfb..77394fb396b1 100644 --- a/src/runtime/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ConvertToLibraryImportFixerTests.cs +++ b/src/runtime/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ConvertToLibraryImportFixerTests.cs @@ -1273,13 +1273,11 @@ partial class Test partial class Test { [LibraryImport("DoesNotExist")] - public static {|CS9388:safe|} partial void {|CS8795:Method|}(); + public static safe partial void {|CS8795:Method|}(); } """; - // The fixer test does not run the generator, so the `extern` implementing part that makes `safe` - // legal on this declaration is missing, the same way the implementation itself is (CS8795). await VerifyCodeFixAsync(source, fixedSource, updatedMemorySafetyRules: true); } diff --git a/src/runtime/src/libraries/System.Runtime.Numerics/src/System/Number.BigInteger.cs b/src/runtime/src/libraries/System.Runtime.Numerics/src/System/Number.BigInteger.cs index 2c7b1c115395..6cff3f3844ae 100644 --- a/src/runtime/src/libraries/System.Runtime.Numerics/src/System/Number.BigInteger.cs +++ b/src/runtime/src/libraries/System.Runtime.Numerics/src/System/Number.BigInteger.cs @@ -132,6 +132,11 @@ internal static unsafe ParsingStatus TryParseBigIntegerNumber(ReadOnlySpa else { ret = NumberToBigInteger(ref number, out result); + + if (ret != ParsingStatus.OK) + { + elementsConsumed = 0; + } } } diff --git a/src/runtime/src/libraries/System.Runtime.Numerics/tests/BigInteger/parse.cs b/src/runtime/src/libraries/System.Runtime.Numerics/tests/BigInteger/parse.cs index ceddb5ea929e..3a838fd66fd1 100644 --- a/src/runtime/src/libraries/System.Runtime.Numerics/tests/BigInteger/parse.cs +++ b/src/runtime/src/libraries/System.Runtime.Numerics/tests/BigInteger/parse.cs @@ -1482,6 +1482,11 @@ public static IEnumerable TryParsePartial_Invalid_TestData() // Only invalid characters (no valid number) yield return new object[] { "abc", NumberStyles.Integer, null }; yield return new object[] { "xyz", NumberStyles.Integer, null }; + + // Values that scan successfully but aren't representable as a BigInteger + yield return new object[] { "1.5", NumberStyles.Float, CultureInfo.InvariantCulture }; + yield return new object[] { "3.14159abc", NumberStyles.Float, CultureInfo.InvariantCulture }; + yield return new object[] { "1E1000000000", NumberStyles.Float, CultureInfo.InvariantCulture }; } [Theory] diff --git a/src/runtime/src/libraries/System.Runtime.Serialization.Xml/tests/SerializationTypes.RuntimeOnly.cs b/src/runtime/src/libraries/System.Runtime.Serialization.Xml/tests/SerializationTypes.RuntimeOnly.cs index 389b1721d5df..f841500c4ee3 100644 --- a/src/runtime/src/libraries/System.Runtime.Serialization.Xml/tests/SerializationTypes.RuntimeOnly.cs +++ b/src/runtime/src/libraries/System.Runtime.Serialization.Xml/tests/SerializationTypes.RuntimeOnly.cs @@ -46,6 +46,52 @@ public class MyTypeD : MyTypeB public int PropI { get; set; } } + [XmlRoot("PrimitiveCollections")] + public sealed class PrimitiveCollections + { + public char[] Chars { get; set; } + + [XmlArrayItem(DataType = "date")] + public DateTime[] Dates { get; set; } + + [XmlArrayItem(DataType = "time")] + public DateTime[] Times { get; set; } + + public DateOnly[] DateOnlyValues { get; set; } + + public TimeOnly[] TimeOnlyValues { get; set; } + + public List Integers { get; set; } + + public IntEnumerableCollection EnumerableIntegers { get; set; } + + public int[] EmptyIntegers { get; set; } + + public PrimitiveCollectionEnum[] Enums { get; set; } + + public int?[] NullableIntegers { get; set; } + + [XmlArrayItem(typeof(int))] + public ArrayList BoxedIntegers { get; set; } + } + + public sealed class IntEnumerableCollection : IEnumerable + { + private readonly List _items = new(); + + public void Add(int value) => _items.Add(value); + + public IEnumerator GetEnumerator() => _items.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + } + + public enum PrimitiveCollectionEnum + { + One, + Two, + } + public class TypeWithDictionaryGenericMembers { public Dictionary F1; diff --git a/src/runtime/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Numerics/BFloat16Tests.cs b/src/runtime/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Numerics/BFloat16Tests.cs index ef3a4c784354..a5ff7414edba 100644 --- a/src/runtime/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Numerics/BFloat16Tests.cs +++ b/src/runtime/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Numerics/BFloat16Tests.cs @@ -572,19 +572,6 @@ public static IEnumerable ExplicitConversion_FromSingle_TestData() foreach ((float original, BFloat16 expected) in data) { - // WASM on Mono lowers `float.Min` / `float.Max` through `f32.min` / `f32.max` - // (and `float.IsNaN(...)` branches through `f32.add`). The WebAssembly spec - // permits NaN-payload canonicalization on these ops but doesn't require it -- - // arch-native targets (Arm64, xArch) don't canonicalize, at most stripping - // the signaling bit per IEEE 754. The V8 engine used by the CI Helix queues - // does canonicalize, so the bit-strict NaN cases in this theory don't round- - // trip through the software conversion path in that environment. Gated on - // Mono specifically since other WASM runtimes don't share this lowering. - // Tracked in https://github.com/dotnet/runtime/issues/103347; this filter can - // be removed once the conversion path either avoids the canonicalizing ops - // or the host engines start preserving NaN payloads. - if (PlatformDetection.IsMonoRuntime && PlatformDetection.IsWasm && float.IsNaN(original)) - continue; yield return new object[] { original, expected }; } } @@ -594,6 +581,21 @@ public static IEnumerable ExplicitConversion_FromSingle_TestData() public static void ExplicitConversion_FromSingle(float f, BFloat16 expected) // Check the underlying bits for verifying NaNs { BFloat16 b16 = (BFloat16)f; + + // The software `float`->`BFloat16` conversion routes the value through `f32.abs`/`f32.min`/ + // `f32.max`/`f32.add`, and the WebAssembly spec permits (but doesn't require) host engines + // to canonicalize NaN payloads on those ops -- the V8 engine used on CI does. The sign is + // still carried through the integer ALU, so a canonicalized result is `sign | 0x7FC0`. + // Accept that as the expected value on WASM. See https://github.com/dotnet/runtime/issues/103347. + if (PlatformDetection.IsWasm && BFloat16.IsNaN(expected)) + { + ushort canonical = (ushort)((BitConverter.BFloat16ToUInt16Bits(expected) & 0x8000) | 0x7FC0); + if (BitConverter.BFloat16ToUInt16Bits(b16) == canonical) + { + expected = b16; + } + } + AssertEqual(expected, b16); } @@ -670,19 +672,6 @@ public static IEnumerable ExplicitConversion_FromDouble_TestData() foreach ((double original, BFloat16 expected) in data) { - // WASM on Mono lowers `double.Min` / `double.Max` through `f64.min` / `f64.max` - // (and `double.IsNaN(...)` branches through `f64.add`). The WebAssembly spec - // permits NaN-payload canonicalization on these ops but doesn't require it -- - // arch-native targets (Arm64, xArch) don't canonicalize, at most stripping - // the signaling bit per IEEE 754. The V8 engine used by the CI Helix queues - // does canonicalize, so the bit-strict NaN cases in this theory don't round- - // trip through the software conversion path in that environment. Gated on - // Mono specifically since other WASM runtimes don't share this lowering. - // Tracked in https://github.com/dotnet/runtime/issues/103347; this filter can - // be removed once the conversion path either avoids the canonicalizing ops - // or the host engines start preserving NaN payloads. - if (PlatformDetection.IsMonoRuntime && PlatformDetection.IsWasm && double.IsNaN(original)) - continue; yield return new object[] { original, expected }; } } @@ -692,6 +681,21 @@ public static IEnumerable ExplicitConversion_FromDouble_TestData() public static void ExplicitConversion_FromDouble(double d, BFloat16 expected) // Check the underlying bits for verifying NaNs { BFloat16 b16 = (BFloat16)d; + + // The software `double`->`BFloat16` conversion routes the value through `f64.abs`/`f64.min`/ + // `f64.max`/`f64.add`, and the WebAssembly spec permits (but doesn't require) host engines + // to canonicalize NaN payloads on those ops -- the V8 engine used on CI does. The sign is + // still carried through the integer ALU, so a canonicalized result is `sign | 0x7FC0`. + // Accept that as the expected value on WASM. See https://github.com/dotnet/runtime/issues/103347. + if (PlatformDetection.IsWasm && BFloat16.IsNaN(expected)) + { + ushort canonical = (ushort)((BitConverter.BFloat16ToUInt16Bits(expected) & 0x8000) | 0x7FC0); + if (BitConverter.BFloat16ToUInt16Bits(b16) == canonical) + { + expected = b16; + } + } + AssertEqual(expected, b16); } diff --git a/src/runtime/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs b/src/runtime/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs index 29b16440cd8e..3329d3dd1f6c 100644 --- a/src/runtime/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs +++ b/src/runtime/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs @@ -24,6 +24,13 @@ public sealed class SlidingWindowRateLimiter : ReplenishingRateLimiter private long _failedLeasesCount; private long _successfulLeasesCount; + /// + /// Function to calculate elapsed time from a given tick value. + /// Defaults to . + /// In tests, this field can be reassigned via reflection to inject custom time behavior without modifying the public API. + /// + private readonly Func _getElapsedTime = RateLimiterHelper.GetElapsedTime; + private readonly Timer? _renewTimer; private readonly SlidingWindowRateLimiterOptions _options; private readonly TimeSpan _replenishmentPeriod; @@ -124,8 +131,19 @@ protected override RateLimitLease AttemptAcquireCore(int permitCount) return SuccessfulLease; } - Interlocked.Increment(ref _failedLeasesCount); - return FailedLease; + lock (Lock) + { + // Edge case where the check before the lock showed 0 available permits but when we got the lock some permits were now available + if (_permitCount > 0) + { + Interlocked.Increment(ref _successfulLeasesCount); + return SuccessfulLease; + } + + Interlocked.Increment(ref _failedLeasesCount); + // Still holding Lock from the top of this block - required by CreateFailedSlidingWindowLease. + return CreateFailedSlidingWindowLease(0); + } } lock (Lock) @@ -135,9 +153,9 @@ protected override RateLimitLease AttemptAcquireCore(int permitCount) return lease; } - // TODO: Acquire additional metadata during a failed lease decision Interlocked.Increment(ref _failedLeasesCount); - return FailedLease; + // Still holding Lock from the top of this block - required by CreateFailedSlidingWindowLease. + return CreateFailedSlidingWindowLease(permitCount); } } @@ -204,8 +222,9 @@ protected override ValueTask AcquireAsyncCore(int permitCount, C else { Interlocked.Increment(ref _failedLeasesCount); - // Don't queue if queue limit reached and QueueProcessingOrder is OldestFirst - return new ValueTask(FailedLease); + // Don't queue if queue limit reached and QueueProcessingOrder is OldestFirst. + // Still holding Lock from the top of this block - required by CreateFailedSlidingWindowLease. + return new ValueTask(CreateFailedSlidingWindowLease(permitCount)); } } @@ -218,6 +237,50 @@ protected override ValueTask AcquireAsyncCore(int permitCount, C } } + // All callers of this method must hold Lock. _requestsPerSegment and _currentSegmentIndex are only otherwise + // mutated under Lock (in ReplenishInternal), so reading them here without it would risk a torn read (a mix of + // pre- and post-replenish state) rather than a clean snapshot. If a new call site is ever added, it must + // acquire Lock before calling this method. + // + // Note: like FixedWindowRateLimiter.CreateFailedWindowLease, this estimate ignores queue state. If permits are + // available (_permitCount >= permitCount) but the request still fails because it can't jump an OldestFirst + // queue, neededPermits floors at 1 and the estimate is based on segment replenishment timing even though the + // real blocker is queue draining, not permit scarcity. + private SlidingWindowLease CreateFailedSlidingWindowLease(int permitCount) + { + // How many permits still need to free up to satisfy this request. Math.Max(1, ...) covers the + // permitCount == 0 fast-path case, where we just need *any* permit to become available + // (i.e. _permitCount > 0). + int neededPermits = Math.Max(1, permitCount - _permitCount); + + // Walk forward from the oldest segment (the next to be freed) toward the newest, accumulating how many + // permits each segment will release, until we've accounted for enough to satisfy the request. + int cumulativeFreed = 0; + int periodsUntilEnough = _options.SegmentsPerWindow; + for (int i = 1; i <= _options.SegmentsPerWindow; i++) + { + int segmentIndex = (_currentSegmentIndex + i) % _options.SegmentsPerWindow; + cumulativeFreed += _requestsPerSegment[segmentIndex]; + if (cumulativeFreed >= neededPermits) + { + periodsUntilEnough = i; + break; + } + } + + TimeSpan? elapsedInCurrentPeriod = _getElapsedTime(_lastReplenishmentTick); + long remainingTicksInCurrentPeriod = _replenishmentPeriod.Ticks - (elapsedInCurrentPeriod?.Ticks ?? 0); + long remainingTicks = _replenishmentPeriod.Ticks * (periodsUntilEnough - 1) + remainingTicksInCurrentPeriod; + + // Clamp to zero if negative (segment(s) expired but not yet replenished) + if (remainingTicks < 0) + { + remainingTicks = 0; + } + + return new SlidingWindowLease(false, TimeSpan.FromTicks(remainingTicks)); + } + private bool TryLeaseUnsynchronized(int permitCount, [NotNullWhen(true)] out RateLimitLease? lease) { ThrowIfDisposed(); @@ -298,7 +361,7 @@ private void ReplenishInternal(long nowTicks) return; } - _lastReplenishmentTick = nowTicks; + Volatile.Write(ref _lastReplenishmentTick, nowTicks); // Increment the current segment index while move the window // We need to know the no. of requests that were acquired in a segment previously to ensure that we don't acquire more than the permit limit. diff --git a/src/runtime/src/libraries/System.Threading.RateLimiting/tests/SlidingWindowRateLimiterTests.cs b/src/runtime/src/libraries/System.Threading.RateLimiting/tests/SlidingWindowRateLimiterTests.cs index d2e92bd28fb2..1e03a43fb17a 100644 --- a/src/runtime/src/libraries/System.Threading.RateLimiting/tests/SlidingWindowRateLimiterTests.cs +++ b/src/runtime/src/libraries/System.Threading.RateLimiting/tests/SlidingWindowRateLimiterTests.cs @@ -253,7 +253,7 @@ public override async Task CanAcquireResourceAsync_QueuesAndGrabsNewest() [Fact] public override async Task FailsWhenQueuingMoreThanLimit_OldestFirst() { - var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + var options = new SlidingWindowRateLimiterOptions { PermitLimit = 1, QueueProcessingOrder = QueueProcessingOrder.OldestFirst, @@ -261,12 +261,18 @@ public override async Task FailsWhenQueuingMoreThanLimit_OldestFirst() Window = TimeSpan.FromMilliseconds(1), SegmentsPerWindow = 2, AutoReplenishment = false - }); + }; + var limiter = new SlidingWindowRateLimiter(options); + using var lease = limiter.AttemptAcquire(1); var wait = limiter.AcquireAsync(1); + SetElapsedTimeSinceLastReplenishment(limiter, TimeSpan.Zero); + var failedLease = await limiter.AcquireAsync(1); Assert.False(failedLease.IsAcquired); + Assert.True(failedLease.TryGetMetadata(MetadataName.RetryAfter, out var timeSpan)); + Assert.Equal(options.Window, timeSpan); } [Fact] @@ -1308,6 +1314,283 @@ public void AutoReplenishIgnoresTimerJitter() Assert.Equal(7, limiter.GetStatistics().CurrentAvailablePermits); } + [Fact] + public async Task RetryMetadataOnFailedAcquireAsync() + { + var options = new SlidingWindowRateLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + Window = TimeSpan.FromSeconds(20), + SegmentsPerWindow = 4, + AutoReplenishment = false + }; + var limiter = new SlidingWindowRateLimiter(options); + + using var lease = limiter.AttemptAcquire(2); + + SetElapsedTimeSinceLastReplenishment(limiter, TimeSpan.Zero); + + var failedLease = await limiter.AcquireAsync(2); + Assert.False(failedLease.IsAcquired); + Assert.True(failedLease.TryGetMetadata(MetadataName.RetryAfter.Name, out var metadata)); + var metaDataTime = Assert.IsType(metadata); + Assert.Equal(options.Window.Ticks, metaDataTime.Ticks); + + Assert.True(failedLease.TryGetMetadata(MetadataName.RetryAfter, out var typedMetadata)); + Assert.Equal(options.Window.Ticks, typedMetadata.Ticks); + Assert.Collection(failedLease.MetadataNames, item => Assert.Equal(MetadataName.RetryAfter.Name, item)); + } + + [Fact] + public async Task CorrectRetryMetadataWithQueuedItem() + { + var options = new SlidingWindowRateLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + Window = TimeSpan.FromSeconds(20), + SegmentsPerWindow = 4, + AutoReplenishment = false + }; + var limiter = new SlidingWindowRateLimiter(options); + + using var lease = limiter.AttemptAcquire(2); + // A queued item is present to confirm queue occupancy doesn't factor into the RetryAfter estimate + // (see CreateFailedSlidingWindowLease) - the failed request below is rejected immediately because 2 permits + // exceeds QueueLimit, not because of the queued item itself. + var wait = limiter.AcquireAsync(1); + Assert.False(wait.IsCompleted); + + SetElapsedTimeSinceLastReplenishment(limiter, TimeSpan.Zero); + + var failedLease = await limiter.AcquireAsync(2); + Assert.False(failedLease.IsAcquired); + Assert.True(failedLease.TryGetMetadata(MetadataName.RetryAfter, out var typedMetadata)); + Assert.Equal(options.Window.Ticks, typedMetadata.Ticks); + } + + [Fact] + public async Task CorrectRetryMetadataWithNonZeroAvailableItems() + { + var options = new SlidingWindowRateLimiterOptions + { + PermitLimit = 3, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + Window = TimeSpan.FromSeconds(20), + SegmentsPerWindow = 4, + AutoReplenishment = false + }; + var limiter = new SlidingWindowRateLimiter(options); + + // 2 of the 3 permits are consumed, leaving 1 available - but that 1 isn't enough to satisfy the 3-permit + // request below, so it should still fail and estimate against the segment holding the other 2. + using var lease = limiter.AttemptAcquire(2); + + SetElapsedTimeSinceLastReplenishment(limiter, TimeSpan.Zero); + + var failedLease = await limiter.AcquireAsync(3); + Assert.False(failedLease.IsAcquired); + Assert.True(failedLease.TryGetMetadata(MetadataName.RetryAfter, out var typedMetadata)); + Assert.Equal(options.Window.Ticks, typedMetadata.Ticks); + } + + [Fact] + public async Task RetryAfterWithPartiallyElapsedSegment() + { + var options = new SlidingWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0, + Window = TimeSpan.FromSeconds(20), + SegmentsPerWindow = 4, + AutoReplenishment = false + }; + var limiter = new SlidingWindowRateLimiter(options); + + using var lease = limiter.AttemptAcquire(1); + + // 2 seconds elapsed since the last replenishment tick. The single permit is in the current segment, so + // the deficit isn't resolved until the walk wraps all the way around: (SegmentsPerWindow - 1) full + // periods, plus the remainder of the current one. + SetElapsedTimeSinceLastReplenishment(limiter, TimeSpan.FromSeconds(2)); + + var failedLease = await limiter.AcquireAsync(1); + Assert.False(failedLease.IsAcquired); + Assert.True(failedLease.TryGetMetadata(MetadataName.RetryAfter, out var timeSpan)); + Assert.Equal(TimeSpan.FromSeconds(18), timeSpan); // 20 - 2 = 18 + } + + [Fact] + public async Task RetryAfterClampsToZeroWhenWindowExpired() + { + var options = new SlidingWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0, + Window = TimeSpan.FromSeconds(20), + SegmentsPerWindow = 4, + AutoReplenishment = false + }; + var limiter = new SlidingWindowRateLimiter(options); + + using var lease = limiter.AttemptAcquire(1); + + // 25 seconds elapsed - longer than the full window, so even after walking all the way around to the + // segment holding the permit, the estimate goes negative and should clamp to zero rather than report a + // negative TimeSpan. + SetElapsedTimeSinceLastReplenishment(limiter, TimeSpan.FromSeconds(25)); + + var failedLease = await limiter.AcquireAsync(1); + Assert.False(failedLease.IsAcquired); + Assert.True(failedLease.TryGetMetadata(MetadataName.RetryAfter, out var timeSpan)); + Assert.Equal(TimeSpan.Zero, timeSpan); // Clamped to zero, not negative + } + + [Fact] + public void RetryMetadataOnFailedAttemptAcquire() + { + var options = new SlidingWindowRateLimiterOptions + { + PermitLimit = 2, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + Window = TimeSpan.FromSeconds(20), + SegmentsPerWindow = 4, + AutoReplenishment = false + }; + var limiter = new SlidingWindowRateLimiter(options); + + using var lease = limiter.AttemptAcquire(2); + + SetElapsedTimeSinceLastReplenishment(limiter, TimeSpan.Zero); + + // Exercises the general locked branch in AttemptAcquireCore + var failedLease = limiter.AttemptAcquire(2); + Assert.False(failedLease.IsAcquired); + Assert.True(failedLease.TryGetMetadata(MetadataName.RetryAfter, out var timeSpan)); + Assert.Equal(options.Window, timeSpan); + } + + [Fact] + public void RetryMetadataOnFailedAttemptAcquireZeroPermitCount() + { + var options = new SlidingWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + Window = TimeSpan.FromSeconds(20), + SegmentsPerWindow = 4, + AutoReplenishment = false + }; + var limiter = new SlidingWindowRateLimiter(options); + + using var lease = limiter.AttemptAcquire(1); + + SetElapsedTimeSinceLastReplenishment(limiter, TimeSpan.Zero); + + // permitCount == 0 with no permits available hits the fast-path failure branch that was just moved inside + // the lock for the race condition fix. + var failedLease = limiter.AttemptAcquire(0); + Assert.False(failedLease.IsAcquired); + Assert.True(failedLease.TryGetMetadata(MetadataName.RetryAfter, out var timeSpan)); + Assert.Equal(options.Window, timeSpan); + } + + [Fact] + public async Task RetryAfterAccountsForPermitsAcrossMultipleSegments() + { + var options = new SlidingWindowRateLimiterOptions + { + PermitLimit = 4, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0, + Window = TimeSpan.FromSeconds(8), + SegmentsPerWindow = 4, + AutoReplenishment = false + }; + var limiter = new SlidingWindowRateLimiter(options); + + // Segment 0 holds 3 permits + using var lease1 = limiter.AttemptAcquire(3); + Assert.True(lease1.IsAcquired); + + // Advance one period (2s) so segment 0 becomes an older segment relative to the new current one + Replenish(limiter, 2000L); + + // Segment 1 (now current) holds the last permit - all 4 are now consumed + using var lease2 = limiter.AttemptAcquire(1); + Assert.True(lease2.IsAcquired); + Assert.Equal(0, limiter.GetStatistics().CurrentAvailablePermits); + + SetElapsedTimeSinceLastReplenishment(limiter, TimeSpan.Zero); + + // Only 2 permits are needed - segment 0's 3 permits alone satisfy that, one period before the walk would + // otherwise wrap all the way back to the current segment. + var failedLease = await limiter.AcquireAsync(2); + Assert.False(failedLease.IsAcquired); + Assert.True(failedLease.TryGetMetadata(MetadataName.RetryAfter, out var timeSpan)); + + // periodsUntilEnough = 3 (two empty segments walked, then segment 0 satisfies the deficit) + var periodTicks = options.Window.Ticks / options.SegmentsPerWindow; + Assert.Equal(TimeSpan.FromTicks(periodTicks * 3), timeSpan); + } + + [Fact] + public async Task AttemptAcquireZero_PermitBecomesAvailableWhileWaitingForLock() + { + var limiter = new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions + { + PermitLimit = 1, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 1, + Window = TimeSpan.FromMilliseconds(2), + SegmentsPerWindow = 2, + AutoReplenishment = false + }); + + using var lease = limiter.AttemptAcquire(1); + Assert.True(lease.IsAcquired); + Assert.Equal(0, limiter.GetStatistics().CurrentAvailablePermits); + + var lockProperty = typeof(SlidingWindowRateLimiter).GetProperty("Lock", Reflection.BindingFlags.NonPublic | Reflection.BindingFlags.Instance)!; + var lockObject = lockProperty.GetValue(limiter)!; + + Task acquireTask; + + // Hold the limiter's own lock on this thread, so a concurrent AttemptAcquire(0) can pass + // its outer, unlocked _permitCount check (which sees 0) but then has to block on the lock + // before it reaches the recheck. That's exactly the race window the fix is meant to close. + Monitor.Enter(lockObject); + try + { + acquireTask = Task.Run(() => limiter.AttemptAcquire(0)); + + // Two segments in this window - the first Replenish call advances to the (empty) + // second segment; the second call wraps back around and frees the permit that was + // recorded against the first segment. + Replenish(limiter, 1L); + Replenish(limiter, 1L); + Assert.True(limiter.GetStatistics().CurrentAvailablePermits > 0); + + // Do not await acquireTask here - see comment above about why. + } + finally + { + Monitor.Exit(lockObject); + } + + var result = await acquireTask; + Assert.True(result.IsAcquired); + Assert.Equal(0, limiter.GetStatistics().TotalFailedLeases); // the bug would have incremented this + } + private static readonly double TickFrequency = (double)TimeSpan.TicksPerSecond / Stopwatch.Frequency; static internal void Replenish(SlidingWindowRateLimiter limiter, long addMilliseconds) @@ -1317,5 +1600,14 @@ static internal void Replenish(SlidingWindowRateLimiter limiter, long addMillise var currentTick = (long)internalTick.GetValue(limiter); replenishInternalMethod.Invoke(limiter, new object[] { currentTick + addMilliseconds * (long)(TimeSpan.TicksPerMillisecond / TickFrequency) }); } + + // Function that replaces the _getElapsedTime function in SlidingWindowRateLimiter to return a specified + // TimeSpan. Used for testing the RetryAfter metadata on failed leases. + static internal void SetElapsedTimeSinceLastReplenishment(SlidingWindowRateLimiter limiter, TimeSpan elapsedTimeSinceLastReplenishment) + { + var _getElapsedTimeField = typeof(SlidingWindowRateLimiter).GetField("_getElapsedTime", Reflection.BindingFlags.NonPublic | Reflection.BindingFlags.Instance)!; + Func overrideFunc = (_) => elapsedTimeSinceLastReplenishment; + _getElapsedTimeField.SetValue(limiter, overrideFunc); + } } } diff --git a/src/runtime/src/mono/mono/eglib/glib.h b/src/runtime/src/mono/mono/eglib/glib.h index 6d14a1721b21..0c7f5f4dc7f2 100644 --- a/src/runtime/src/mono/mono/eglib/glib.h +++ b/src/runtime/src/mono/mono/eglib/glib.h @@ -346,8 +346,8 @@ typedef struct { void g_clear_error (GError **gerror); void g_error_free (GError *gerror); -GError *g_error_new (gpointer domain, gint code, const char *format, ...); -void g_set_error (GError **err, gpointer domain, gint code, const gchar *format, ...); +GError *g_error_new (gpointer domain, gint code, const char *format, ...) G_ATTR_FORMAT_PRINTF(3, 4); +void g_set_error (GError **err, gpointer domain, gint code, const gchar *format, ...) G_ATTR_FORMAT_PRINTF(4, 5); void g_propagate_error (GError **dest, GError *src); /* @@ -724,17 +724,17 @@ typedef enum { G_ENUM_FUNCTIONS (GLogLevelFlags) gint g_printv (const gchar *format, va_list args); -void g_print (const gchar *format, ...); -void g_printerr (const gchar *format, ...); +void g_print (const gchar *format, ...) G_ATTR_FORMAT_PRINTF(1, 2); +void g_printerr (const gchar *format, ...) G_ATTR_FORMAT_PRINTF(1, 2); GLogLevelFlags g_log_set_always_fatal (GLogLevelFlags fatal_mask); GLogLevelFlags g_log_set_fatal_mask (const gchar *log_domain, GLogLevelFlags fatal_mask); void g_logv (const gchar *log_domain, GLogLevelFlags log_level, const gchar *format, va_list args); G_EXTERN_C // Used by MonoPosixHelper or MonoSupportW, at least. -void g_log (const gchar *log_domain, GLogLevelFlags log_level, const gchar *format, ...); +void g_log (const gchar *log_domain, GLogLevelFlags log_level, const gchar *format, ...) G_ATTR_FORMAT_PRINTF(3, 4); void g_log_disabled (const gchar *log_domain, GLogLevelFlags log_level, const char *file, int line); G_EXTERN_C // Used by MonoPosixHelper or MonoSupportW, at least. G_ATTR_NORETURN void - g_assertion_message (const gchar *format, ...); + g_assertion_message (const gchar *format, ...) G_ATTR_FORMAT_PRINTF(1, 2); G_ATTR_NORETURN void mono_assertion_message_disabled (const char *file, int line); G_ATTR_NORETURN void @@ -1031,7 +1031,7 @@ g_async_safe_vfprintf (int handle, gchar const *format, va_list args) return ret; } -static inline gint +static inline gint G_ATTR_FORMAT_PRINTF(2, 3) g_async_safe_fprintf (int handle, gchar const *format, ...) { va_list args; @@ -1047,7 +1047,7 @@ g_async_safe_vprintf (gchar const *format, va_list args) return g_async_safe_vfprintf (1, format, args); } -static inline gint +static inline gint G_ATTR_FORMAT_PRINTF(1, 2) g_async_safe_printf (gchar const *format, ...) { va_list args; diff --git a/src/runtime/src/mono/mono/eglib/gmem.c b/src/runtime/src/mono/mono/eglib/gmem.c index b50a24157150..29055e83b0fb 100644 --- a/src/runtime/src/mono/mono/eglib/gmem.c +++ b/src/runtime/src/mono/mono/eglib/gmem.c @@ -108,7 +108,7 @@ gpointer g_realloc (gpointer obj, gsize size) ptr = G_REALLOC_INTERNAL (obj, size); if (ptr) return ptr; - g_error ("Could not allocate %i bytes", size); + g_error ("Could not allocate %zu bytes", size); } gpointer @@ -120,7 +120,7 @@ g_malloc (gsize x) ptr = G_MALLOC_INTERNAL (x); if (ptr) return ptr; - g_error ("Could not allocate %i bytes", x); + g_error ("Could not allocate %zu bytes", x); } gpointer g_calloc (gsize n, gsize x) @@ -131,7 +131,7 @@ gpointer g_calloc (gsize n, gsize x) ptr = G_CALLOC_INTERNAL (n, x); if (ptr) return ptr; - g_error ("Could not allocate %i (%i * %i) bytes", x*n, n, x); + g_error ("Could not allocate %zu (%zu * %zu) bytes", x*n, n, x); } gpointer g_malloc0 (gsize x) { diff --git a/src/runtime/src/mono/mono/metadata/class.c b/src/runtime/src/mono/mono/metadata/class.c index 5600f3dc75dd..b7c5de0a8143 100644 --- a/src/runtime/src/mono/mono/metadata/class.c +++ b/src/runtime/src/mono/mono/metadata/class.c @@ -7099,8 +7099,10 @@ mono_class_set_deferred_type_load_failure (MonoClass *klass, const char * fmt, . va_list args; va_start (args, fmt); - g_warning ("Warning: %s", fmt, args); + gchar *message = g_strdup_vprintf (fmt, args); va_end (args); + g_warning ("Warning: %s", message); + g_free (message); mono_class_set_deferred_failure (klass); } diff --git a/src/runtime/src/mono/mono/metadata/debug-helpers.c b/src/runtime/src/mono/mono/metadata/debug-helpers.c index 90da50428276..1c74ccdcbd1c 100644 --- a/src/runtime/src/mono/mono/metadata/debug-helpers.c +++ b/src/runtime/src/mono/mono/metadata/debug-helpers.c @@ -1076,7 +1076,7 @@ static void print_field_value (const char *field_ptr, MonoClassField *field, gssize type_offset) { MonoType *type; - g_print ("At %p (ofs: %2d) %s: ", field_ptr, m_field_is_from_update (field) ? -1 : (field->offset + type_offset), mono_field_get_name (field)); + g_print ("At %p (ofs: %2td) %s: ", field_ptr, m_field_is_from_update (field) ? -1 : (field->offset + type_offset), mono_field_get_name (field)); type = mono_type_get_underlying_type (field->type); switch (type->type) { diff --git a/src/runtime/src/mono/mono/metadata/icall.c b/src/runtime/src/mono/mono/metadata/icall.c index 37c5d1a5a1c9..097e4e26d1d2 100644 --- a/src/runtime/src/mono/mono/metadata/icall.c +++ b/src/runtime/src/mono/mono/metadata/icall.c @@ -6230,7 +6230,7 @@ ves_icall_System_Environment_FailFast (MonoStringHandle message, MonoExceptionHa if (!MONO_HANDLE_IS_NULL (message)) { char *msg = mono_string_handle_to_utf8 (message, error); - g_warning_dont_trim (msg); + g_warning_dont_trim ("%s", msg); g_free (msg); } diff --git a/src/runtime/src/mono/mono/metadata/jit-icall-reg.h b/src/runtime/src/mono/mono/metadata/jit-icall-reg.h index c58a320f89ab..1d159485bc63 100644 --- a/src/runtime/src/mono/mono/metadata/jit-icall-reg.h +++ b/src/runtime/src/mono/mono/metadata/jit-icall-reg.h @@ -203,6 +203,7 @@ MONO_JIT_ICALL (mono_get_native_calli_wrapper) \ MONO_JIT_ICALL (mono_get_special_static_data) \ MONO_JIT_ICALL (mono_gsharedvt_constrained_call) \ MONO_JIT_ICALL (mono_gsharedvt_value_copy) \ +MONO_JIT_ICALL (mono_helper_box_nullable) \ MONO_JIT_ICALL (mono_helper_compile_generic_method) \ MONO_JIT_ICALL (mono_helper_ldstr) \ MONO_JIT_ICALL (mono_helper_ldstr_mscorlib) \ diff --git a/src/runtime/src/mono/mono/metadata/threads.c b/src/runtime/src/mono/mono/metadata/threads.c index 8641175cfee2..0fcf0cded31a 100644 --- a/src/runtime/src/mono/mono/metadata/threads.c +++ b/src/runtime/src/mono/mono/metadata/threads.c @@ -995,12 +995,12 @@ mono_thread_detach_internal (MonoInternalThread *thread) g_assert (threads); if (!mono_g_hash_table_lookup_extended (threads, GUINT_TO_POINTER (thread->tid), NULL, (gpointer*) &value)) { - g_error ("%s: thread %p (tid: %p) should not have been removed yet from threads", __func__, thread, thread->tid); + g_error ("%s: thread %p (tid: %" G_GSIZE_FORMAT ") should not have been removed yet from threads", __func__, thread, (gsize)thread->tid); } else if (thread != value) { /* We have to check whether the thread object for the tid is still the same in the table because the * thread might have been destroyed and the tid reused in the meantime, in which case the tid would be in * the table, but with another thread object. */ - g_error ("%s: thread %p (tid: %p) do not match with value %p (tid: %p)", __func__, thread, thread->tid, value, value->tid); + g_error ("%s: thread %p (tid: %" G_GSIZE_FORMAT ") do not match with value %p (tid: %" G_GSIZE_FORMAT ")", __func__, thread, (gsize)thread->tid, value, (gsize)value->tid); } removed = mono_g_hash_table_remove (threads, GUINT_TO_POINTER (thread->tid)); @@ -2773,7 +2773,7 @@ wait_for_tids (struct wait_data *wait, guint32 timeout, gboolean check_state_cha mono_threads_lock (); if (mono_g_hash_table_lookup (threads, GUINT_TO_POINTER (internal->tid)) == internal) - g_error ("%s: failed to call mono_thread_detach_internal on thread %p, InternalThread: %p", __func__, internal->tid, internal); + g_error ("%s: failed to call mono_thread_detach_internal on thread %" G_GSIZE_FORMAT ", InternalThread: %p", __func__, (gsize)internal->tid, internal); mono_threads_unlock (); } } diff --git a/src/runtime/src/mono/mono/mini/driver.c b/src/runtime/src/mono/mono/mini/driver.c index 05e8a0a05fe5..426027a3cb7d 100644 --- a/src/runtime/src/mono/mono/mini/driver.c +++ b/src/runtime/src/mono/mono/mini/driver.c @@ -2048,7 +2048,7 @@ mono_main (int argc, char* argv[]) g_print ("Mono JIT compiler version %s\nCopyright (C) Novell, Inc, Xamarin Inc and Contributors. www.mono-project.com\n", build); g_free (build); char *info = mono_get_version_info (); - g_print (info); + g_print ("%s", info); g_free (info); gc_descr = mono_gc_get_description (); diff --git a/src/runtime/src/mono/mono/mini/interp/interp-pgo.c b/src/runtime/src/mono/mono/mini/interp/interp-pgo.c index e9df819df16f..02c4feaaba05 100644 --- a/src/runtime/src/mono/mono/mini/interp/interp-pgo.c +++ b/src/runtime/src/mono/mono/mini/interp/interp-pgo.c @@ -321,7 +321,7 @@ mono_interp_pgo_load_table (uint8_t * data, int data_size) { uint32_t size = *(uint32_t *)data; if (mono_opt_interp_pgo_logging) - g_print ("Loading %d bytes of interp_pgo data (table size == %zu)\n", data_size, size); + g_print ("Loading %d bytes of interp_pgo data (table size == %u)\n", data_size, size); result->data = g_malloc0 (data_size); g_assert ((int64_t)size < (int64_t)data_size); diff --git a/src/runtime/src/mono/mono/mini/interp/jiterpreter.c b/src/runtime/src/mono/mono/mini/interp/jiterpreter.c index 887038ca47fa..919f0b5c9b5e 100644 --- a/src/runtime/src/mono/mono/mini/interp/jiterpreter.c +++ b/src/runtime/src/mono/mono/mini/interp/jiterpreter.c @@ -1379,7 +1379,7 @@ mono_jiterp_monitor_trace (const guint16 *ip, void *_frame, void *locals) #endif if (mono_opt_jiterpreter_trace_monitoring_log > 2) - g_print ("trace #%d @%d '%s' bailout recorded at opcode #%d, penalty=%d\n", opcode->trace_index, ip, frame->imethod->method->name, cinfo.bailout_opcode_count, penalty); + g_print ("trace #%d @%p '%s' bailout recorded at opcode #%d, penalty=%d\n", opcode->trace_index, (void*)ip, frame->imethod->method->name, cinfo.bailout_opcode_count, penalty); } #ifdef DISABLE_THREADS @@ -1400,7 +1400,7 @@ mono_jiterp_monitor_trace (const guint16 *ip, void *_frame, void *locals) if (average_penalty <= threshold) { if ((int)thunk < mono_jiterp_first_trace_fn_ptr) - g_error ("thunk ptr %d below start of trace table %d\n", thunk, mono_jiterp_first_trace_fn_ptr); + g_error ("thunk ptr %d below start of trace table %d\n", (int)(gsize)thunk, mono_jiterp_first_trace_fn_ptr); guint16 new_relative_fn_ptr = (int)thunk - mono_jiterp_first_trace_fn_ptr; #ifdef DISABLE_THREADS @@ -1415,13 +1415,13 @@ mono_jiterp_monitor_trace (const guint16 *ip, void *_frame, void *locals) g_assert (mono_jiterp_patch_opcode (opcode, MINT_TIER_NOP_JITERPRETER, MINT_TIER_ENTER_JITERPRETER)); if (mono_opt_jiterpreter_trace_monitoring_log > 1) - g_print ("trace #%d @%d '%s' accepted; average_penalty %f <= %f\n", opcode->trace_index, ip, frame->imethod->method->name, average_penalty, threshold); + g_print ("trace #%d @%p '%s' accepted; average_penalty %f <= %f\n", opcode->trace_index, (void*)ip, frame->imethod->method->name, average_penalty, threshold); } else { // FIXME: Harmless race condition if threads are in use traces_rejected++; if (mono_opt_jiterpreter_trace_monitoring_log > 0) { char * full_name = mono_method_get_full_name (frame->imethod->method); - g_print ("trace #%d @%d '%s' rejected; average_penalty %f > %f\n", opcode->trace_index, ip, full_name, average_penalty, threshold); + g_print ("trace #%d @%p '%s' rejected; average_penalty %f > %f\n", opcode->trace_index, (void*)ip, full_name, average_penalty, threshold); g_free (full_name); } } diff --git a/src/runtime/src/mono/mono/mini/interp/transform-opt.c b/src/runtime/src/mono/mono/mini/interp/transform-opt.c index 1bf529f313e0..357e5ef89ed4 100644 --- a/src/runtime/src/mono/mono/mini/interp/transform-opt.c +++ b/src/runtime/src/mono/mono/mini/interp/transform-opt.c @@ -1061,7 +1061,7 @@ interp_compute_pruned_ssa_liveness (TransformData *td) mono_bitset_foreach_bit (bb->live_in_set, i, td->renamable_vars_size) { g_print (" %d", td->renamable_vars [i].var_index); } - g_print (" }\n\tLIVE_OUT = {", bb->index); + g_print (" }\n\tLIVE_OUT = {"); mono_bitset_foreach_bit (bb->live_out_set, i, td->renamable_vars_size) { g_print (" %d", td->renamable_vars [i].var_index); } diff --git a/src/runtime/src/mono/mono/mini/interp/transform.c b/src/runtime/src/mono/mono/mini/interp/transform.c index 534acb4ad72a..7a79605dbdac 100644 --- a/src/runtime/src/mono/mono/mini/interp/transform.c +++ b/src/runtime/src/mono/mono/mini/interp/transform.c @@ -961,7 +961,7 @@ binary_arith_op(TransformData *td, int mint_op) if (type1 != type2) { g_warning("%s.%s: %04x arith type mismatch %s %d %d", m_class_get_name (td->method->klass), td->method->name, - td->ip - td->il_code, mono_interp_opname (mint_op), type1, type2); + (guint32)(td->ip - td->il_code), mono_interp_opname (mint_op), type1, type2); } op = mint_op + type1 - STACK_TYPE_I4; td->sp -= 2; @@ -5574,7 +5574,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, InterpBasicBlock *new_bb = td->offset_to_bb [in_offset]; if (new_bb != NULL && td->cbb != new_bb) { if (td->verbose_level) - g_print ("BB%d (IL_%04lx):\n", new_bb->index, new_bb->il_offset); + g_print ("BB%d (IL_%04x):\n", new_bb->index, new_bb->il_offset); // If we were emitting into previous bblock, we are finished now if (td->cbb->emit_state == BB_STATE_EMITTING) td->cbb->emit_state = BB_STATE_EMITTED; @@ -5683,7 +5683,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, if (bb->dead || td->cbb->dead) { g_assert (op_size > 0); /* The BB formation pass must catch all bad ops */ if (td->verbose_level > 1) - g_print ("SKIPPING DEAD OP at %x\n", in_offset); + g_print ("SKIPPING DEAD OP at %x\n", (guint32)in_offset); link_bblocks = FALSE; td->ip += op_size; continue; @@ -5693,8 +5693,8 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, if (td->verbose_level > 1) { g_print ("IL_%04lx %-10s, sp %ld, %s %-12s\n", - td->ip - td->il_code, - mono_opcode_name (*td->ip), td->sp - td->stack, + (gulong)(td->ip - td->il_code), + mono_opcode_name (*td->ip), (glong)(td->sp - td->stack), td->sp > td->stack ? stack_type_string [td->sp [-1].type] : " ", (td->sp > td->stack && (td->sp [-1].type == STACK_TYPE_O || td->sp [-1].type == STACK_TYPE_VT)) ? (td->sp [-1].klass == NULL ? "?" : m_class_get_name (td->sp [-1].klass)) : ""); } @@ -8384,7 +8384,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, /*stackval_from_data (signature->ret, frame->retval, sp->data.vt, signature->pinvoke);*/ if (td->sp > td->stack) - g_warning ("CEE_MONO_RETOBJ: more values on stack: %d", td->sp-td->stack); + g_warning ("CEE_MONO_RETOBJ: more values on stack: %d", (int)(td->sp-td->stack)); break; case CEE_MONO_LDNATIVEOBJ: { token = read32 (td->ip + 1); @@ -8461,7 +8461,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, break; } default: - g_error ("transform.c: Unimplemented opcode: 0xF0 %02x at 0x%x\n", *td->ip, td->ip-header->code); + g_error ("transform.c: Unimplemented opcode: 0xF0 %02x at 0x%x\n", *td->ip, (int)(td->ip-header->code)); } break; #if 0 @@ -8863,7 +8863,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, ++td->ip; break; default: - g_error ("transform.c: Unimplemented opcode: 0xFE %02x (%s) at 0x%x\n", *td->ip, mono_opcode_name (256 + *td->ip), td->ip-header->code); + g_error ("transform.c: Unimplemented opcode: 0xFE %02x (%s) at 0x%x\n", *td->ip, mono_opcode_name (256 + *td->ip), (int)(td->ip-header->code)); } break; default: { @@ -9215,7 +9215,7 @@ interp_mark_ref_slots_for_var (TransformData *td, int var) int index = td->vars [var].offset / sizeof (gpointer); mono_bitset_set (td->ref_slots, index); if (td->verbose_level) - g_print ("Stack ref slot at off %d for var %d\n", index * sizeof (gpointer), var); + g_print ("Stack ref slot at off %d for var %d\n", (int)(index * sizeof (gpointer)), var); } } } @@ -9852,7 +9852,7 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, MonoG /* Check if we use excessive stack space */ if (td->max_stack_height > header->max_stack * 3u && header->max_stack > 16) - g_warning ("Excessive stack space usage for method %s, %d/%d", method->name, td->max_stack_height, header->max_stack); + g_warning ("Excessive stack space usage for method %s, %u/%d", method->name, td->max_stack_height, header->max_stack); guint32 code_len_u8, code_len_u16; code_len_u8 = GPTRDIFF_TO_UINT32 ((guint8 *) td->new_code_end - (guint8 *) td->new_code); diff --git a/src/runtime/src/mono/mono/mini/jit-icalls.c b/src/runtime/src/mono/mono/mini/jit-icalls.c index fba533310bd2..4d9a95b81812 100644 --- a/src/runtime/src/mono/mono/mini/jit-icalls.c +++ b/src/runtime/src/mono/mono/mini/jit-icalls.c @@ -1169,6 +1169,15 @@ mono_helper_newobj_mscorlib (guint32 idx) return obj; } +MonoObject* +mono_helper_box_nullable (gpointer vbuf, MonoClass *klass) +{ + ERROR_DECL (error); + MonoObject *result = mono_nullable_box (vbuf, klass, error); + mono_error_set_pending_exception (error); + return result; +} + /* * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions * in generated code. So instead we emit a call to this function and place a gdb diff --git a/src/runtime/src/mono/mono/mini/jit-icalls.h b/src/runtime/src/mono/mono/mini/jit-icalls.h index 6e9ea58124e1..42b394b06b28 100644 --- a/src/runtime/src/mono/mono/mini/jit-icalls.h +++ b/src/runtime/src/mono/mono/mini/jit-icalls.h @@ -116,6 +116,8 @@ ICALL_EXPORT MonoString *mono_helper_ldstr_mscorlib (guint32 idx); ICALL_EXPORT MonoObject *mono_helper_newobj_mscorlib (guint32 idx); +ICALL_EXPORT MonoObject *mono_helper_box_nullable (gpointer vbuf, MonoClass *klass); + ICALL_EXPORT double mono_fsub (double a, double b); ICALL_EXPORT double mono_fadd (double a, double b); diff --git a/src/runtime/src/mono/mono/mini/method-to-ir.c b/src/runtime/src/mono/mono/mini/method-to-ir.c index 4545e6e0a211..b7faaa15cf79 100644 --- a/src/runtime/src/mono/mono/mini/method-to-ir.c +++ b/src/runtime/src/mono/mono/mini/method-to-ir.c @@ -3403,6 +3403,26 @@ handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_ return mono_emit_jit_icall_id (cfg, alloc_ftn, iargs); } +/* + * Box a gsharedvt Nullable via a non-generic runtime helper, passing the value by + * address and the concrete class from the rgctx. This avoids a per-T box wrapper that + * cannot be emitted at AOT time when the consuming assembly runs interpreted. + */ +static MonoInst* +mini_emit_nullable_box_helper (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used) +{ + MonoInst *iargs [2], *addr, *var; + + var = get_vreg_to_inst (cfg, val->dreg); + if (!var) + var = mono_compile_create_var_for_vreg (cfg, m_class_get_byval_arg (klass), OP_LOCAL, val->dreg); + EMIT_NEW_VARLOADA (cfg, addr, var, var->inst_vtype); + + iargs [0] = addr; + iargs [1] = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS); + return mono_emit_jit_icall (cfg, mono_helper_box_nullable, iargs); +} + /* * Returns NULL and set the cfg exception on error. */ @@ -3425,11 +3445,9 @@ mini_emit_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_us MonoInst *addr; MonoMethodSignature *sig = mono_method_signature_internal (method); if (mini_is_gsharedvt_klass (klass)) - addr = mini_emit_get_gsharedvt_info_klass (cfg, klass, - MONO_RGCTX_INFO_NULLABLE_CLASS_BOX); - else - addr = emit_get_rgctx_method (cfg, context_used, method, - MONO_RGCTX_INFO_METHOD_FTNDESC); + return mini_emit_nullable_box_helper (cfg, val, klass, context_used); + addr = emit_get_rgctx_method (cfg, context_used, method, + MONO_RGCTX_INFO_METHOD_FTNDESC); cfg->interp_in_signatures = g_slist_prepend_mempool (cfg->mempool, cfg->interp_in_signatures, sig); return mini_emit_llvmonly_calli (cfg, sig, &val, addr); } else { @@ -3495,9 +3513,14 @@ mini_emit_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_us /* Nullable case */ MONO_START_BB (cfg, is_nullable_bb); - { + if (cfg->llvm_only) { + MonoInst *box_call = mini_emit_nullable_box_helper (cfg, val, klass, context_used); + EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg); + res->type = STACK_OBJ; + res->klass = klass; + } else { MonoInst *box_addr = mini_emit_get_gsharedvt_info_klass (cfg, klass, - MONO_RGCTX_INFO_NULLABLE_CLASS_BOX); + MONO_RGCTX_INFO_NULLABLE_CLASS_BOX); MonoInst *box_call; MonoMethodSignature *box_sig; @@ -3510,10 +3533,7 @@ mini_emit_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_us box_sig->param_count = 1; box_sig->params [0] = m_class_get_byval_arg (klass); - if (cfg->llvm_only) - box_call = mini_emit_llvmonly_calli (cfg, box_sig, &val, box_addr); - else - box_call = mini_emit_calli (cfg, box_sig, &val, box_addr, NULL, NULL); + box_call = mini_emit_calli (cfg, box_sig, &val, box_addr, NULL, NULL); EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg); res->type = STACK_OBJ; res->klass = klass; diff --git a/src/runtime/src/mono/mono/mini/mini-arm64.c b/src/runtime/src/mono/mono/mini/mini-arm64.c index c3a439b0f0d2..8295f4bbdd38 100644 --- a/src/runtime/src/mono/mono/mini/mini-arm64.c +++ b/src/runtime/src/mono/mono/mini/mini-arm64.c @@ -6035,7 +6035,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) after_instruction_emit: if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) { g_warning ("wrong maximal instruction length of instruction " M_PRI_INST " (expected %d, got %d)", - mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset); + mono_inst_name (ins->opcode), max_len, (int)(code - cfg->native_code - offset)); g_assert_not_reached (); } diff --git a/src/runtime/src/mono/mono/mini/mini-runtime.c b/src/runtime/src/mono/mono/mini/mini-runtime.c index 46e28a680b3c..6a2099535cbd 100644 --- a/src/runtime/src/mono/mono/mini/mini-runtime.c +++ b/src/runtime/src/mono/mono/mini/mini-runtime.c @@ -5114,6 +5114,7 @@ register_icalls (void) register_icall (mono_helper_ldstr, mono_icall_sig_object_ptr_int, FALSE); register_icall (mono_helper_ldstr_mscorlib, mono_icall_sig_object_int, FALSE); register_icall (mono_helper_newobj_mscorlib, mono_icall_sig_object_int, FALSE); + register_icall (mono_helper_box_nullable, mono_icall_sig_object_ptr_ptr, FALSE); register_icall (mono_value_copy_internal, mono_icall_sig_void_ptr_ptr_ptr, FALSE); register_icall (mono_object_castclass_unbox, mono_icall_sig_object_object_ptr, FALSE); register_icall (mono_break, mono_icall_sig_void, TRUE); diff --git a/src/runtime/src/mono/mono/mini/tramp-amd64.c b/src/runtime/src/mono/mono/mini/tramp-amd64.c index 9e61ba12c49d..a1b725e0cb2c 100644 --- a/src/runtime/src/mono/mono/mini/tramp-amd64.c +++ b/src/runtime/src/mono/mono/mini/tramp-amd64.c @@ -599,7 +599,7 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf amd64_jump_membase (code, AMD64_RSP, rax_offset - sizeof (target_mgreg_t)); } - g_assertf ((code - buf) <= kMaxCodeSize, "%d %d", code, buf, (int)(code - buf), kMaxCodeSize); + g_assertf ((code - buf) <= kMaxCodeSize, "code=%p buf=%p size=%d max=%d", code, buf, (int)(code - buf), kMaxCodeSize); g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_MAX_TRAMPOLINE_UNWINDINFO_SIZE)); mono_arch_flush_icache (buf, GPTRDIFF_TO_INT (code - buf)); diff --git a/src/runtime/src/mono/mono/utils/mono-os-mutex.c b/src/runtime/src/mono/mono/utils/mono-os-mutex.c index b306c91e2354..5ec384112a44 100644 --- a/src/runtime/src/mono/mono/utils/mono-os-mutex.c +++ b/src/runtime/src/mono/mono/utils/mono-os-mutex.c @@ -44,7 +44,7 @@ mono_os_cond_timedwait (mono_cond_t *cond, mono_mutex_t *mutex, guint32 timeout_ res = pthread_cond_timedwait_relative_np (cond, mutex, &ts); if (G_UNLIKELY (res != 0 && res != ETIMEDOUT)) { g_print ("cond: %p mutex: %p\n", *(gpointer*)cond, *(gpointer*)mutex); - g_error ("%s: pthread_cond_timedwait_relative_np failed with \"%s\" (%d) %ld %ld %d", __func__, g_strerror (res), res, ts.tv_sec, ts.tv_nsec, timeout_ms); + g_error ("%s: pthread_cond_timedwait_relative_np failed with \"%s\" (%d) %lld %ld %d", __func__, g_strerror (res), res, (long long)ts.tv_sec, (long)ts.tv_nsec, timeout_ms); } return res != 0 ? -1 : 0; #else @@ -75,7 +75,7 @@ mono_os_cond_timedwait (mono_cond_t *cond, mono_mutex_t *mutex, guint32 timeout_ res = pthread_cond_timedwait (cond, mutex, &ts); if (G_UNLIKELY (res != 0 && res != ETIMEDOUT)) { g_print ("cond: %p mutex: %p\n", *(gpointer*)cond, *(gpointer*)mutex); - g_error ("%s: pthread_cond_timedwait failed with \"%s\" (%d) %ld %ld %d", __func__, g_strerror (res), res, ts.tv_sec, ts.tv_nsec, timeout_ms); + g_error ("%s: pthread_cond_timedwait failed with \"%s\" (%d) %lld %ld %d", __func__, g_strerror (res), res, (long long)ts.tv_sec, (long)ts.tv_nsec, timeout_ms); } return res != 0 ? -1 : 0; #endif /* !HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP */ diff --git a/src/runtime/src/mono/mono/utils/mono-threads-state-machine.c b/src/runtime/src/mono/mono/utils/mono-threads-state-machine.c index 3550cc66837f..49a7b2c2d168 100644 --- a/src/runtime/src/mono/mono/utils/mono-threads-state-machine.c +++ b/src/runtime/src/mono/mono/utils/mono-threads-state-machine.c @@ -286,7 +286,7 @@ mono_threads_transition_request_suspension (MonoThreadInfo *info) if (no_safepoints) mono_fatal_with_history ("no_safepoints = TRUE, but should be FALSE"); if (!(suspend_count > 0 && suspend_count < THREAD_SUSPEND_COUNT_MAX)) - mono_fatal_with_history ("suspend_count = %d, but should be > 0 and < THREAD_SUSPEND_COUNT_MAX, for thread %d", suspend_count, mono_thread_info_get_tid (info)); + mono_fatal_with_history ("suspend_count = %d, but should be > 0 and < THREAD_SUSPEND_COUNT_MAX, for thread 0x%" G_GSIZE_FORMAT "x", suspend_count, (gsize)mono_thread_info_get_tid (info)); if (thread_state_cas (&info->thread_state, build_thread_state (cur_state, suspend_count + 1, no_safepoints), raw_state) != raw_state) goto retry_state_change; trace_state_change ("SUSPEND_INIT_REQUESTED", info, raw_state, cur_state, no_safepoints, 1); diff --git a/src/runtime/src/mono/mono/utils/mono-threads.c b/src/runtime/src/mono/mono/utils/mono-threads.c index 144feb388787..9e68886f21d1 100644 --- a/src/runtime/src/mono/mono/utils/mono-threads.c +++ b/src/runtime/src/mono/mono/utils/mono-threads.c @@ -259,7 +259,7 @@ mono_threads_begin_global_suspend (void) { size_t ps = pending_suspends; if (G_UNLIKELY (ps != 0)) - g_error ("pending_suspends = %d, but must be 0", ps); + g_error ("pending_suspends = %zu, but must be 0", ps); THREADS_SUSPEND_DEBUG ("------ BEGIN GLOBAL OP sp %d rp %d ap %d wd %d po %d (sp + rp + ap == wd) (wd == po)\n", suspend_posts, resume_posts, abort_posts, waits_done, pending_ops); g_assert ((suspend_posts + resume_posts + abort_posts) == waits_done); @@ -271,7 +271,7 @@ mono_threads_end_global_suspend (void) { size_t ps = pending_suspends; if (G_UNLIKELY (ps != 0)) - g_error ("pending_suspends = %d, but must be 0", ps); + g_error ("pending_suspends = %zu, but must be 0", ps); THREADS_SUSPEND_DEBUG ("------ END GLOBAL OP sp %d rp %d ap %d wd %d po %d\n", suspend_posts, resume_posts, abort_posts, waits_done, pending_ops); g_assert ((suspend_posts + resume_posts + abort_posts) == waits_done); diff --git a/src/runtime/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets b/src/runtime/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets index 4ec8ade0ed5c..e9685629edc7 100644 --- a/src/runtime/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets +++ b/src/runtime/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets @@ -1292,7 +1292,6 @@ Copyright (c) .NET Foundation. All rights reserved. - diff --git a/src/runtime/src/native/corehost/bundle/reader.h b/src/runtime/src/native/corehost/bundle/reader.h index 2aee7a90b97b..54d751f521f6 100644 --- a/src/runtime/src/native/corehost/bundle/reader.h +++ b/src/runtime/src/native/corehost/bundle/reader.h @@ -64,12 +64,12 @@ namespace bundle if (magic == FAT_MAGIC) { m_offset_in_file = OSSwapBigToHostInt32(*(uint32_t*)offset_in_FAT_universal_binary(base_ptr)); - trace::info(_X("FAT container detected. Offset in file:[%lx]"), m_offset_in_file); + trace::info(_X("FAT container detected. Offset in file:[%llx]"), (unsigned long long)m_offset_in_file); } else if (magic == FAT_MAGIC_64) { m_offset_in_file = OSSwapBigToHostInt64(*(uint64_t*)offset_in_FAT_universal_binary(base_ptr)); - trace::info(_X("FAT64 container detected. Offset in file:[%lx]"), m_offset_in_file); + trace::info(_X("FAT64 container detected. Offset in file:[%llx]"), (unsigned long long)m_offset_in_file); } #endif diff --git a/src/runtime/src/native/corehost/fxr/sdk_resolver.cpp b/src/runtime/src/native/corehost/fxr/sdk_resolver.cpp index 39a93d4272cf..b1cbf949b55c 100644 --- a/src/runtime/src/native/corehost/fxr/sdk_resolver.cpp +++ b/src/runtime/src/native/corehost/fxr/sdk_resolver.cpp @@ -179,9 +179,9 @@ void sdk_resolver::print_resolution_error(const pal::string_t& dotnet_root, cons trace::error(_X("\nInstalled SDKs:")); sdk_exists = sdk_info::print_all_sdks(dotnet_root, _X("")); if (!sdk_exists) - trace::error(no_sdk_message); + trace::error(_X("%s"), no_sdk_message); - trace::error(_X("")); + trace::error(_X("%s"), _X("")); if (has_global_file) { trace::error(_X("Install the [%s] .NET SDK or update [%s] to match an installed SDK."), requested.c_str(), global_json.path.c_str()); diff --git a/src/runtime/src/native/corehost/hostmisc/trace.c b/src/runtime/src/native/corehost/hostmisc/trace.c index 25c2599704b1..f185a7b55cd8 100644 --- a/src/runtime/src/native/corehost/hostmisc/trace.c +++ b/src/runtime/src/native/corehost/hostmisc/trace.c @@ -349,7 +349,7 @@ void trace_println(const pal_char_t* format, ...) void trace_println_empty(void) { - trace_println(_X("")); + trace_println(_X("%s"), _X("")); } void trace_warning_v(const pal_char_t* format, va_list args) diff --git a/src/runtime/src/native/corehost/hostmisc/trace.h b/src/runtime/src/native/corehost/hostmisc/trace.h index fb4ce6779c2b..a00f84237b21 100644 --- a/src/runtime/src/native/corehost/hostmisc/trace.h +++ b/src/runtime/src/native/corehost/hostmisc/trace.h @@ -8,6 +8,13 @@ #include #include "pal.h" // for pal_char_t, _X +#include + +#if defined(_WIN32) +#define TRACE_ATTR_FORMAT_PRINTF(fmt_pos, arg_pos) +#else +#define TRACE_ATTR_FORMAT_PRINTF(fmt_pos, arg_pos) MINIPAL_ATTR_FORMAT_PRINTF(fmt_pos, arg_pos) +#endif #ifdef __cplusplus extern "C" { @@ -18,11 +25,11 @@ typedef void (__cdecl *trace_error_writer_fn)(const pal_char_t* message); void trace_setup(void); bool trace_enable(void); bool trace_is_enabled(void); -void trace_verbose(const pal_char_t* format, ...); -void trace_info(const pal_char_t* format, ...); -void trace_warning(const pal_char_t* format, ...); -void trace_error(const pal_char_t* format, ...); -void trace_println(const pal_char_t* format, ...); +void trace_verbose(const pal_char_t* format, ...) TRACE_ATTR_FORMAT_PRINTF(1, 2); +void trace_info(const pal_char_t* format, ...) TRACE_ATTR_FORMAT_PRINTF(1, 2); +void trace_warning(const pal_char_t* format, ...) TRACE_ATTR_FORMAT_PRINTF(1, 2); +void trace_error(const pal_char_t* format, ...) TRACE_ATTR_FORMAT_PRINTF(1, 2); +void trace_println(const pal_char_t* format, ...) TRACE_ATTR_FORMAT_PRINTF(1, 2); void trace_println_empty(void); void trace_flush(void); @@ -66,7 +73,7 @@ namespace trace inline bool enable() { return trace_enable(); } inline bool is_enabled() { return trace_is_enabled(); } - inline void verbose(const pal::char_t* format, ...) + inline void TRACE_ATTR_FORMAT_PRINTF(1, 2) verbose(const pal::char_t* format, ...) { va_list args; va_start(args, format); @@ -74,7 +81,7 @@ namespace trace va_end(args); } - inline void info(const pal::char_t* format, ...) + inline void TRACE_ATTR_FORMAT_PRINTF(1, 2) info(const pal::char_t* format, ...) { va_list args; va_start(args, format); @@ -82,7 +89,7 @@ namespace trace va_end(args); } - inline void warning(const pal::char_t* format, ...) + inline void TRACE_ATTR_FORMAT_PRINTF(1, 2) warning(const pal::char_t* format, ...) { va_list args; va_start(args, format); @@ -90,7 +97,7 @@ namespace trace va_end(args); } - inline void error(const pal::char_t* format, ...) + inline void TRACE_ATTR_FORMAT_PRINTF(1, 2) error(const pal::char_t* format, ...) { va_list args; va_start(args, format); @@ -98,7 +105,7 @@ namespace trace va_end(args); } - inline void println(const pal::char_t* format, ...) + inline void TRACE_ATTR_FORMAT_PRINTF(1, 2) println(const pal::char_t* format, ...) { va_list args; va_start(args, format); diff --git a/src/runtime/src/native/corehost/hostpolicy/deps_format.cpp b/src/runtime/src/native/corehost/hostpolicy/deps_format.cpp index db0417db6e06..d99f0805360b 100644 --- a/src/runtime/src/native/corehost/hostpolicy/deps_format.cpp +++ b/src/runtime/src/native/corehost/hostpolicy/deps_format.cpp @@ -364,7 +364,7 @@ void deps_json_t::perform_rid_fallback(rid_specific_assets_t* portable_assets) { if (iter->first != matched_rid) { - trace::verbose(_X(" Removing %s assets"),iter->first.c_str(), package.first.c_str()); + trace::verbose(_X(" Removing %s assets from %s"), iter->first.c_str(), package.first.c_str()); iter = rid_assets.erase(iter); } else diff --git a/src/runtime/src/native/corehost/hostpolicy/hostpolicy.cpp b/src/runtime/src/native/corehost/hostpolicy/hostpolicy.cpp index 9d4761803b97..7d1befbca168 100644 --- a/src/runtime/src/native/corehost/hostpolicy/hostpolicy.cpp +++ b/src/runtime/src/native/corehost/hostpolicy/hostpolicy.cpp @@ -447,7 +447,7 @@ SHARED_API int HOSTPOLICY_CALLTYPE corehost_main_with_output_buffer(const int ar { rc = StatusCode::HostApiBufferTooSmall; *required_buffer_size = len + 1; - trace::info(_X("get-native-search-directories failed with buffer too small"), output_string.c_str()); + trace::info(_X("get-native-search-directories failed with buffer too small. Required: %d, available: %d"), len + 1, buffer_size); } else { diff --git a/src/runtime/src/native/corehost/hostpolicy/hostpolicy_context.cpp b/src/runtime/src/native/corehost/hostpolicy/hostpolicy_context.cpp index 3bf16e9bf9c3..010ea0de65a4 100644 --- a/src/runtime/src/native/corehost/hostpolicy/hostpolicy_context.cpp +++ b/src/runtime/src/native/corehost/hostpolicy/hostpolicy_context.cpp @@ -38,7 +38,11 @@ namespace if (!pal::clr_palstring(path, &file_path)) { trace::warning(_X("Failure probing contents of the application bundle.")); +#ifdef TARGET_UNIX + trace::warning(_X("Failed to convert path [%s] to UTF8"), path); +#else trace::warning(_X("Failed to convert path [%hs] to UTF8"), path); +#endif return false; } diff --git a/src/runtime/src/native/corehost/hostpolicy/hostpolicy_init.cpp b/src/runtime/src/native/corehost/hostpolicy/hostpolicy_init.cpp index c6848def713e..202d6fc9f992 100644 --- a/src/runtime/src/native/corehost/hostpolicy/hostpolicy_init.cpp +++ b/src/runtime/src/native/corehost/hostpolicy/hostpolicy_init.cpp @@ -23,7 +23,7 @@ bool hostpolicy_init_t::init(const host_interface_t* input, hostpolicy_init_t* i return false; } - trace::verbose(_X("Reading from host interface version: [0x%04zx:%zd] to initialize policy version: [0x%04x:%d]"), input->version_hi, input->version_lo, HOST_INTERFACE_LAYOUT_VERSION_HI, HOST_INTERFACE_LAYOUT_VERSION_LO); + trace::verbose(_X("Reading from host interface version: [0x%04zx:%zu] to initialize policy version: [0x%04x:%zu]"), input->version_hi, input->version_lo, HOST_INTERFACE_LAYOUT_VERSION_HI, (size_t)HOST_INTERFACE_LAYOUT_VERSION_LO); // This check is to ensure is an old hostfxr can still load new hostpolicy. // We should not read garbage due to potentially shorter struct size @@ -46,8 +46,8 @@ bool hostpolicy_init_t::init(const host_interface_t* input, hostpolicy_init_t* i } else { - trace::error(_X("The size of the data layout used to initialize %s is %zd; expected at least %d"), LIBHOSTPOLICY_NAME, input->version_lo, - offsetof(host_interface_t, host_mode) + sizeof(input->host_mode)); + trace::error(_X("The size of the data layout used to initialize %s is %zu; expected at least %zu"), LIBHOSTPOLICY_NAME, input->version_lo, + (size_t)(offsetof(host_interface_t, host_mode) + sizeof(input->host_mode))); } // An old hostfxr may not provide these fields. diff --git a/src/runtime/src/native/libs/Common/pal_compiler.h b/src/runtime/src/native/libs/Common/pal_compiler.h index 31d45a0c385b..f71b1df5ae59 100644 --- a/src/runtime/src/native/libs/Common/pal_compiler.h +++ b/src/runtime/src/native/libs/Common/pal_compiler.h @@ -3,6 +3,8 @@ #pragma once +#include + #ifndef __cplusplus #include #endif @@ -28,7 +30,7 @@ #endif #if defined(TARGET_ANDROID) -static inline void +static inline void MINIPAL_ATTR_FORMAT_PRINTF(2, 3) do_abort_unless (bool condition, const char* fmt, ...) { if (condition) { diff --git a/src/runtime/src/native/libs/System.Native/pal_string.h b/src/runtime/src/native/libs/System.Native/pal_string.h index ff69055fec09..996a81e6c8e9 100644 --- a/src/runtime/src/native/libs/System.Native/pal_string.h +++ b/src/runtime/src/native/libs/System.Native/pal_string.h @@ -14,7 +14,7 @@ * success; if the return value is equal to the size then the result may have been truncated. * On failure, returns a negative value. */ -PALEXPORT int32_t SystemNative_SNPrintF(char* string, int32_t size, const char* format, ...); +PALEXPORT int32_t SystemNative_SNPrintF(char* string, int32_t size, const char* format, ...) MINIPAL_ATTR_FORMAT_PRINTF(3, 4); /** * Two specialized overloads for use from Interop.Sys, because these two signatures are not equivalent diff --git a/src/runtime/src/native/libs/System.Security.Cryptography.Native/osslcompat_30.h b/src/runtime/src/native/libs/System.Security.Cryptography.Native/osslcompat_30.h index 6da9eb3c1b6a..7384bbaf615d 100644 --- a/src/runtime/src/native/libs/System.Security.Cryptography.Native/osslcompat_30.h +++ b/src/runtime/src/native/libs/System.Security.Cryptography.Native/osslcompat_30.h @@ -5,6 +5,7 @@ #pragma once #include "pal_types.h" +#include #undef EVP_PKEY_CTX_set_rsa_keygen_bits #undef EVP_PKEY_CTX_set_rsa_oaep_md @@ -76,7 +77,7 @@ struct ossl_param_st void ERR_new(void); void ERR_set_debug(const char *file, int line, const char *func); -void ERR_set_error(int lib, int reason, const char *fmt, ...); +void ERR_set_error(int lib, int reason, const char *fmt, ...) MINIPAL_ATTR_FORMAT_PRINTF(3, 4); int EVP_CIPHER_get_nid(const EVP_CIPHER *e); EVP_KDF* EVP_KDF_fetch(OSSL_LIB_CTX *libctx, const char *algorithm, const char *properties); diff --git a/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/CoreCLRContracts.cs b/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/CoreCLRContracts.cs index 5a0276bd38a2..e9b8312f726e 100644 --- a/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/CoreCLRContracts.cs +++ b/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/CoreCLRContracts.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.Threading; using Microsoft.Diagnostics.DataContractReader.Contracts.GCInfoHelpers; namespace Microsoft.Diagnostics.DataContractReader.Contracts; @@ -98,8 +99,9 @@ public static void Register(ContractRegistry registry) /// / /// if the advertised version is recognized but intentionally unimplemented. /// - public static void ValidateForDataAccess(Target target) + public static void ValidateForDataAccess(Target target, Lock? apiLock = null) { + using Lock.Scope scope = apiLock is null ? default : apiLock.EnterScope(); ContractRegistry registry = target.Contracts; // In-box (main-descriptor) contract accesses across the ISOSDac* and IXCLRData* surface that diff --git a/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataAppDomain.cs b/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataAppDomain.cs index ed02d4c6fad2..98e97692467b 100644 --- a/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataAppDomain.cs +++ b/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataAppDomain.cs @@ -5,6 +5,7 @@ using System.Diagnostics; using System.Runtime.InteropServices; using System.Runtime.InteropServices.Marshalling; +using System.Threading; using Microsoft.Diagnostics.DataContractReader.Contracts; namespace Microsoft.Diagnostics.DataContractReader.Legacy; @@ -14,6 +15,7 @@ public sealed unsafe partial class ClrDataAppDomain : IXCLRDataAppDomain { internal const uint DefaultAppDomainId = 1; + private readonly Lock _apiLock; private readonly Target _target; private readonly TargetPointer _appDomain; private readonly IXCLRDataAppDomain? _legacyImpl; @@ -21,18 +23,24 @@ public sealed unsafe partial class ClrDataAppDomain : IXCLRDataAppDomain public TargetPointer Address => _appDomain; internal IXCLRDataAppDomain? LegacyImpl => _legacyImpl; - public ClrDataAppDomain(Target target, TargetPointer appDomain, IXCLRDataAppDomain? legacyImpl) + public ClrDataAppDomain(Target target, TargetPointer appDomain, IXCLRDataAppDomain? legacyImpl, Lock apiLock) { + _apiLock = apiLock; _target = target; _appDomain = appDomain; _legacyImpl = legacyImpl; } int IXCLRDataAppDomain.GetProcess(DacComNullableByRef process) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataAppDomain.GetName(uint bufLen, uint* nameLen, char* name) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; string friendlyName; try @@ -100,6 +108,7 @@ int IXCLRDataAppDomain.GetName(uint bufLen, uint* nameLen, char* name) int IXCLRDataAppDomain.GetUniqueID(ulong* id) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -128,6 +137,7 @@ int IXCLRDataAppDomain.GetUniqueID(ulong* id) int IXCLRDataAppDomain.GetFlags(uint* flags) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -157,6 +167,7 @@ int IXCLRDataAppDomain.GetFlags(uint* flags) int IXCLRDataAppDomain.IsSameObject(IXCLRDataAppDomain* appDomain) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_FALSE; try { @@ -183,8 +194,16 @@ int IXCLRDataAppDomain.IsSameObject(IXCLRDataAppDomain* appDomain) } int IXCLRDataAppDomain.GetManagedObject(DacComNullableByRef value) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataAppDomain.Request(uint reqCode, uint inBufferSize, byte* inBuffer, uint outBufferSize, byte* outBuffer) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } } diff --git a/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataExceptionState.cs b/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataExceptionState.cs index f667d88c36c2..6717a9ddaa6f 100644 --- a/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataExceptionState.cs +++ b/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataExceptionState.cs @@ -4,6 +4,7 @@ using System; using System.Diagnostics; using System.Runtime.InteropServices.Marshalling; +using System.Threading; using Microsoft.Diagnostics.DataContractReader.Contracts; namespace Microsoft.Diagnostics.DataContractReader.Legacy; @@ -11,6 +12,7 @@ namespace Microsoft.Diagnostics.DataContractReader.Legacy; [GeneratedComClass] public sealed unsafe partial class ClrDataExceptionState : IXCLRDataExceptionState { + private readonly Lock _apiLock; private readonly Target _target; private readonly TargetPointer _threadAddress; private readonly uint _flags; @@ -26,8 +28,10 @@ public ClrDataExceptionState( TargetPointer exceptionInfoAddress, TargetPointer thrownObjectHandle, TargetPointer previousExInfoAddress, - IXCLRDataExceptionState? legacyImpl) + IXCLRDataExceptionState? legacyImpl, + Lock apiLock) { + _apiLock = apiLock; _target = target; _threadAddress = threadAddress; _flags = flags; @@ -39,6 +43,7 @@ public ClrDataExceptionState( int IXCLRDataExceptionState.GetFlags(uint* flags) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -69,6 +74,7 @@ int IXCLRDataExceptionState.GetFlags(uint* flags) int IXCLRDataExceptionState.GetPrevious(DacComNullableByRef exState) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK, hrLocal = HResults.S_OK; IXCLRDataExceptionState? legacyPrevious = null; @@ -97,7 +103,8 @@ int IXCLRDataExceptionState.GetPrevious(DacComNullableByRef value) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK, hrLocal = HResults.S_OK; IXCLRDataValue? legacyValue = null; @@ -160,7 +168,8 @@ int IXCLRDataExceptionState.GetManagedObject(DacComNullableByRef IsRegisterValue = false, }, ], - legacyValue); + legacyValue, + _apiLock); } catch (System.Exception ex) { @@ -176,12 +185,23 @@ int IXCLRDataExceptionState.GetManagedObject(DacComNullableByRef return hr; } - int IXCLRDataExceptionState.GetBaseType(/*CLRDataBaseExceptionType*/ uint* type) => HResults.E_NOTIMPL; + int IXCLRDataExceptionState.GetBaseType(/*CLRDataBaseExceptionType*/ uint* type) + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } - int IXCLRDataExceptionState.GetCode(uint* code) => HResults.E_NOTIMPL; + int IXCLRDataExceptionState.GetCode(uint* code) + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataExceptionState.GetString(uint bufLen, uint* strLen, char* str) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -243,6 +263,7 @@ int IXCLRDataExceptionState.GetString(uint bufLen, uint* strLen, char* str) int IXCLRDataExceptionState.Request(uint reqCode, uint inBufferSize, byte* inBuffer, uint outBufferSize, byte* outBuffer) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.E_INVALIDARG; if (reqCode == (uint)CLRDataGeneralRequest.CLRDATA_REQUEST_REVISION) @@ -276,6 +297,7 @@ int IXCLRDataExceptionState.Request(uint reqCode, uint inBufferSize, byte* inBuf int IXCLRDataExceptionState.IsSameState(EXCEPTION_RECORD64* exRecord, uint contextSize, byte* cxRecord) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = IsSameState2((uint)CLRDataExceptionSameFlag.CLRDATA_EXSAME_SECOND_CHANCE, exRecord); #if DEBUG if (_legacyImpl is not null) @@ -289,6 +311,7 @@ int IXCLRDataExceptionState.IsSameState(EXCEPTION_RECORD64* exRecord, uint conte int IXCLRDataExceptionState.IsSameState2(uint flags, EXCEPTION_RECORD64* exRecord, uint contextSize, byte* cxRecord) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = IsSameState2(flags, exRecord); #if DEBUG if (_legacyImpl is not null) @@ -352,6 +375,7 @@ private int IsSameState2(uint flags, EXCEPTION_RECORD64* exRecord) int IXCLRDataExceptionState.GetTask(DacComNullableByRef task) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK, hrLocal = HResults.S_OK; IXCLRDataTask? legacyTask = null; @@ -363,7 +387,7 @@ int IXCLRDataExceptionState.GetTask(DacComNullableByRef task) } try { - task.Interface = new ClrDataTask(_threadAddress, _target, legacyTask); + task.Interface = new ClrDataTask(_threadAddress, _target, legacyTask, _apiLock); } catch (System.Exception ex) { diff --git a/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataFrame.cs b/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataFrame.cs index 5088c9f32911..31e287041c1f 100644 --- a/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataFrame.cs +++ b/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataFrame.cs @@ -9,6 +9,7 @@ using System.Reflection.Metadata.Ecma335; using System.Runtime.InteropServices; using System.Runtime.InteropServices.Marshalling; +using System.Threading; using Microsoft.Diagnostics.DataContractReader.Contracts; using Microsoft.Diagnostics.DataContractReader.Contracts.StackWalkHelpers; using Microsoft.Diagnostics.DataContractReader.SignatureHelpers; @@ -18,14 +19,16 @@ namespace Microsoft.Diagnostics.DataContractReader.Legacy; [GeneratedComClass] public sealed unsafe partial class ClrDataFrame : IXCLRDataFrame, IXCLRDataFrame2 { + private readonly Lock _apiLock; private readonly Target _target; private readonly TargetPointer _threadAddress; private readonly IXCLRDataFrame? _legacyImpl; private readonly IStackDataFrameHandle _dataFrame; - public ClrDataFrame(Target target, TargetPointer threadAddress, IStackDataFrameHandle dataFrame, IXCLRDataFrame? legacyImpl) + public ClrDataFrame(Target target, TargetPointer threadAddress, IStackDataFrameHandle dataFrame, IXCLRDataFrame? legacyImpl, Lock apiLock) { + _apiLock = apiLock; _target = target; _threadAddress = threadAddress; _legacyImpl = legacyImpl; @@ -35,7 +38,11 @@ public ClrDataFrame(Target target, TargetPointer threadAddress, IStackDataFrameH // IXCLRDataFrame implementation int IXCLRDataFrame.GetFrameType(uint* simpleType, uint* detailedType) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataFrame.GetContext( uint contextFlags, @@ -43,6 +50,7 @@ int IXCLRDataFrame.GetContext( uint* contextSize, [Out, MarshalUsing(CountElementName = nameof(contextBufSize))] byte[] contextBuf) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -93,6 +101,7 @@ int IXCLRDataFrame.GetContext( int IXCLRDataFrame.GetAppDomain(DacComNullableByRef appDomain) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; int hrLegacy = HResults.S_OK; @@ -113,7 +122,7 @@ int IXCLRDataFrame.GetAppDomain(DacComNullableByRef appDomai if (appDomainAddr != TargetPointer.Null) { - appDomain.Interface = new ClrDataAppDomain(_target, appDomainAddr, legacyAppDomain); + appDomain.Interface = new ClrDataAppDomain(_target, appDomainAddr, legacyAppDomain, _apiLock); } else { @@ -137,6 +146,7 @@ int IXCLRDataFrame.GetAppDomain(DacComNullableByRef appDomai int IXCLRDataFrame.GetNumArguments(uint* numArgs) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -175,6 +185,7 @@ int IXCLRDataFrame.GetArgumentByIndex( uint* nameLen, char* name) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; int hrLegacy = HResults.S_OK; @@ -266,6 +277,7 @@ int IXCLRDataFrame.GetArgumentByIndex( int IXCLRDataFrame.GetNumLocalVariables(uint* numLocals) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -297,6 +309,7 @@ int IXCLRDataFrame.GetLocalVariableByIndex( uint* nameLen, char* name) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; int hrLegacy = HResults.S_OK; @@ -360,10 +373,15 @@ int IXCLRDataFrame.GetCodeName( uint bufLen, uint* nameLen, char* nameBuf) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetCodeName(flags, bufLen, nameLen, nameBuf) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetCodeName(flags, bufLen, nameLen, nameBuf) : HResults.E_NOTIMPL; + } int IXCLRDataFrame.GetMethodInstance(DacComNullableByRef method) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; int hrLocal = HResults.S_OK; @@ -381,7 +399,7 @@ int IXCLRDataFrame.GetMethodInstance(DacComNullableByRef LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.Request(reqCode, inBufferSize, inBuffer, outBufferSize, outBuffer) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.Request(reqCode, inBufferSize, inBuffer, outBufferSize, outBuffer) : HResults.E_NOTIMPL; + } int IXCLRDataFrame.GetNumTypeArguments(uint* numTypeArgs) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataFrame.GetTypeArgumentByIndex(uint index, DacComNullableByRef typeArg) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } // IXCLRDataFrame2 implementation int IXCLRDataFrame2.GetExactGenericArgsToken(DacComNullableByRef genericToken) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } // ========== Metadata resolution helpers ========== @@ -513,7 +547,7 @@ private ClrDataValue CreateValueFromDebugInfo( ulong baseAddress = locations.Length == 1 && !locations[0].IsRegisterValue ? locations[0].AddressOrValue : 0; - return new ClrDataValue(_target, _threadAddress, valueFlags, typeHandle, baseAddress, locations, legacyImpl); + return new ClrDataValue(_target, _threadAddress, valueFlags, typeHandle, baseAddress, locations, legacyImpl, _apiLock); } // ========== Signature-based flag computation ========== diff --git a/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataMethodDefinition.cs b/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataMethodDefinition.cs index 15d701c9077f..93bfd8cc4a2a 100644 --- a/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataMethodDefinition.cs +++ b/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataMethodDefinition.cs @@ -10,6 +10,7 @@ using System.Runtime.InteropServices; using System.Runtime.InteropServices.Marshalling; using System.Text; +using System.Threading; using Microsoft.Diagnostics.DataContractReader.Contracts; namespace Microsoft.Diagnostics.DataContractReader.Legacy; @@ -28,6 +29,7 @@ public EnumMethodDefinitionExtents(ClrDataMethodDefinitionExtent extent) } } + private readonly Lock _apiLock; private readonly Target _target; private readonly TargetPointer _module; private readonly uint _token; @@ -36,8 +38,10 @@ public ClrDataMethodDefinition( Target target, TargetPointer module, uint token, - IXCLRDataMethodDefinition? legacyImpl) + IXCLRDataMethodDefinition? legacyImpl, + Lock apiLock) { + _apiLock = apiLock; _target = target; _module = module; _token = token; @@ -144,10 +148,15 @@ private string GetFullMethodNameFromMetadata() } int IXCLRDataMethodDefinition.GetTypeDefinition(DacComNullableByRef typeDefinition) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataMethodDefinition.StartEnumInstances(IXCLRDataAppDomain? appDomain, ulong* handle) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_FALSE; *handle = 0; @@ -207,6 +216,7 @@ int IXCLRDataMethodDefinition.StartEnumInstances(IXCLRDataAppDomain? appDomain, int IXCLRDataMethodDefinition.EnumInstance(ulong* handle, DacComNullableByRef instance) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; if (*handle == 0) @@ -234,7 +244,7 @@ int IXCLRDataMethodDefinition.EnumInstance(ulong* handle, DacComNullableByRef mod) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -389,7 +402,7 @@ int IXCLRDataMethodDefinition.GetTokenAndScope(uint* token, DacComNullableByRef< legacyMod = legacyModOut.Interface; } - mod.Interface = new ClrDataModule(_module, _target, legacyMod); + mod.Interface = new ClrDataModule(_module, _target, legacyMod, _apiLock); } } catch (System.Exception ex) @@ -420,16 +433,29 @@ int IXCLRDataMethodDefinition.GetTokenAndScope(uint* token, DacComNullableByRef< } int IXCLRDataMethodDefinition.GetFlags(uint* flags) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataMethodDefinition.IsSameObject(IXCLRDataMethodDefinition? method) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataMethodDefinition.GetLatestEnCVersion(uint* version) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataMethodDefinition.StartEnumExtents(ulong* handle) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -482,6 +508,7 @@ int IXCLRDataMethodDefinition.StartEnumExtents(ulong* handle) int IXCLRDataMethodDefinition.EnumExtent(ulong* handle, ClrDataMethodDefinitionExtent* extent) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; EnumMethodDefinitionExtents? extents = null; try @@ -535,6 +562,7 @@ int IXCLRDataMethodDefinition.EnumExtent(ulong* handle, ClrDataMethodDefinitionE int IXCLRDataMethodDefinition.EndEnumExtents(ulong handle) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; nuint legacyHandle = 0; try @@ -568,6 +596,7 @@ int IXCLRDataMethodDefinition.EndEnumExtents(ulong handle) int IXCLRDataMethodDefinition.GetCodeNotification(uint* flags) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; ICodeNotifications codeNotif = _target.Contracts.CodeNotifications; @@ -592,6 +621,7 @@ int IXCLRDataMethodDefinition.GetCodeNotification(uint* flags) int IXCLRDataMethodDefinition.SetCodeNotification(uint flags) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; ICodeNotifications codeNotif = _target.Contracts.CodeNotifications; @@ -616,6 +646,7 @@ int IXCLRDataMethodDefinition.SetCodeNotification(uint flags) int IXCLRDataMethodDefinition.Request(uint reqCode, uint inBufferSize, byte* inBuffer, uint outBufferSize, byte* outBuffer) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try @@ -659,6 +690,7 @@ int IXCLRDataMethodDefinition.Request(uint reqCode, uint inBufferSize, byte* inB int IXCLRDataMethodDefinition.GetRepresentativeEntryAddress(ClrDataAddress* addr) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -694,6 +726,7 @@ int IXCLRDataMethodDefinition.GetRepresentativeEntryAddress(ClrDataAddress* addr int IXCLRDataMethodDefinition.HasClassOrMethodInstantiation(int* bGeneric) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try diff --git a/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataMethodInstance.cs b/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataMethodInstance.cs index eca82fe2685b..9cbebb9ec82e 100644 --- a/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataMethodInstance.cs +++ b/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataMethodInstance.cs @@ -9,6 +9,7 @@ using System.Runtime.InteropServices; using System.Runtime.InteropServices.Marshalling; using System.Text; +using System.Threading; using Microsoft.Diagnostics.DataContractReader.Contracts; namespace Microsoft.Diagnostics.DataContractReader.Legacy; @@ -27,6 +28,7 @@ public EnumMethodExtents(ClrDataAddressRange extent) } } + private readonly Lock _apiLock; private readonly Target _target; private readonly MethodDescHandle _methodDesc; private readonly TargetPointer _appDomain; @@ -35,8 +37,10 @@ public ClrDataMethodInstance( Target target, MethodDescHandle methodDesc, TargetPointer appDomain, - IXCLRDataMethodInstance? legacyImpl) + IXCLRDataMethodInstance? legacyImpl, + Lock apiLock) { + _apiLock = apiLock; _target = target; _methodDesc = methodDesc; _appDomain = appDomain; @@ -44,10 +48,15 @@ public ClrDataMethodInstance( } int IXCLRDataMethodInstance.GetTypeInstance(DacComNullableByRef typeInstance) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataMethodInstance.GetDefinition(DacComNullableByRef methodDefinition) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; int hrLocal = HResults.S_OK; IXCLRDataMethodDefinition? legacyMethodDefinition = null; @@ -65,7 +74,7 @@ int IXCLRDataMethodInstance.GetDefinition(DacComNullableByRef mod) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try @@ -108,7 +118,7 @@ int IXCLRDataMethodInstance.GetTokenAndScope(uint* token, DacComNullableByRef HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataMethodInstance.IsSameObject(IXCLRDataMethodInstance* method) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataMethodInstance.GetEnCVersion(uint* version) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataMethodInstance.GetNumTypeArguments(uint* numTypeArgs) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataMethodInstance.GetTypeArgumentByIndex(uint index, DacComNullableByRef typeArg) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataMethodInstance.GetILOffsetsByAddress(ClrDataAddress address, uint offsetsLen, uint* offsetsNeeded, uint* ilOffsets) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try @@ -328,6 +360,7 @@ int IXCLRDataMethodInstance.GetAddressRangesByILOffset( uint* rangesNeeded, [In, Out, MarshalUsing(CountElementName = nameof(rangesLen))] ClrDataAddressRange[]? addressRanges) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try @@ -422,6 +455,7 @@ int IXCLRDataMethodInstance.GetAddressRangesByILOffset( int IXCLRDataMethodInstance.GetILAddressMap(uint mapLen, uint* mapNeeded, [In, Out, MarshalUsing(CountElementName = "mapLen")] ClrDataILAddressMap[]? maps) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try @@ -551,6 +585,7 @@ private ClrDataAddressRange GetMethodExtent() int IXCLRDataMethodInstance.StartEnumExtents(ulong* handle) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -589,6 +624,7 @@ int IXCLRDataMethodInstance.StartEnumExtents(ulong* handle) int IXCLRDataMethodInstance.EnumExtent(ulong* handle, ClrDataAddressRange* extent) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; EnumMethodExtents? extents = null; try @@ -640,6 +676,7 @@ int IXCLRDataMethodInstance.EnumExtent(ulong* handle, ClrDataAddressRange* exten int IXCLRDataMethodInstance.EndEnumExtents(ulong handle) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; nuint legacyHandle = 0; try @@ -673,6 +710,7 @@ int IXCLRDataMethodInstance.EndEnumExtents(ulong handle) int IXCLRDataMethodInstance.Request(uint reqCode, uint inBufferSize, byte* inBuffer, uint outBufferSize, byte* outBuffer) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try @@ -716,6 +754,7 @@ int IXCLRDataMethodInstance.Request(uint reqCode, uint inBufferSize, byte* inBuf int IXCLRDataMethodInstance.GetRepresentativeEntryAddress(ClrDataAddress* addr) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try diff --git a/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataModule.cs b/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataModule.cs index 81df7f659d90..fb955bac31ce 100644 --- a/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataModule.cs +++ b/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataModule.cs @@ -10,6 +10,7 @@ using System.Reflection.Metadata.Ecma335; using System.Reflection.Metadata; using System.Collections.Generic; +using System.Threading; using Microsoft.Diagnostics.DataContractReader.Contracts; namespace Microsoft.Diagnostics.DataContractReader.Legacy; @@ -17,6 +18,7 @@ namespace Microsoft.Diagnostics.DataContractReader.Legacy; [GeneratedComClass] public sealed unsafe partial class ClrDataModule : ICustomQueryInterface, IXCLRDataModule, IXCLRDataModule2 { + private readonly Lock _apiLock; private readonly TargetPointer _address; private readonly Target _target; @@ -38,8 +40,9 @@ public sealed unsafe partial class ClrDataModule : ICustomQueryInterface, IXCLRD private MetaDataImportImpl? _metaDataImportImpl; - public ClrDataModule(TargetPointer address, Target target, IXCLRDataModule? legacyImpl) + public ClrDataModule(TargetPointer address, Target target, IXCLRDataModule? legacyImpl, Lock apiLock) { + _apiLock = apiLock; _address = address; _target = target; _legacyModule = legacyImpl; @@ -56,6 +59,7 @@ public ClrDataModule(TargetPointer address, Target target, IXCLRDataModule? lega CustomQueryInterfaceResult ICustomQueryInterface.GetInterface(ref Guid iid, out nint ppv) { + using Lock.Scope scope = _apiLock.EnterScope(); ppv = default; // Legacy DAC implementation of IXCLRDataModule handles QIs for IMetaDataImport by creating and @@ -104,7 +108,7 @@ CustomQueryInterfaceResult ICustomQueryInterface.GetInterface(ref Guid iid, out if (reader is null) return CustomQueryInterfaceResult.NotHandled; - wrapper = new MetaDataImportImpl(reader, legacyImport); + wrapper = new MetaDataImportImpl(reader, legacyImport, _apiLock); _metaDataImportImpl ??= wrapper; wrapper = _metaDataImportImpl; } @@ -238,45 +242,110 @@ private IEnumerable IterateMethodDefinitions() } int IXCLRDataModule.StartEnumAssemblies(ulong* handle) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataModule.EnumAssembly(ulong* handle, DacComNullableByRef assembly) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataModule.EndEnumAssemblies(ulong handle) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataModule.StartEnumTypeDefinitions(ulong* handle) - => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.StartEnumTypeDefinitions(handle) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.StartEnumTypeDefinitions(handle) : HResults.E_NOTIMPL; + } int IXCLRDataModule.EnumTypeDefinition(ulong* handle, DacComNullableByRef typeDefinition) - => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.EnumTypeDefinition(handle, typeDefinition) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.EnumTypeDefinition(handle, typeDefinition) : HResults.E_NOTIMPL; + } int IXCLRDataModule.EndEnumTypeDefinitions(ulong handle) - => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.EndEnumTypeDefinitions(handle) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.EndEnumTypeDefinitions(handle) : HResults.E_NOTIMPL; + } int IXCLRDataModule.StartEnumTypeInstances(IXCLRDataAppDomain? appDomain, ulong* handle) - => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.StartEnumTypeInstances(appDomain, handle) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.StartEnumTypeInstances(appDomain, handle) : HResults.E_NOTIMPL; + } int IXCLRDataModule.EnumTypeInstance(ulong* handle, DacComNullableByRef typeInstance) - => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.EnumTypeInstance(handle, typeInstance) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.EnumTypeInstance(handle, typeInstance) : HResults.E_NOTIMPL; + } int IXCLRDataModule.EndEnumTypeInstances(ulong handle) - => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.EndEnumTypeInstances(handle) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.EndEnumTypeInstances(handle) : HResults.E_NOTIMPL; + } int IXCLRDataModule.StartEnumTypeDefinitionsByName(char* name, uint flags, ulong* handle) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataModule.EnumTypeDefinitionByName(ulong* handle, DacComNullableByRef type) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataModule.EndEnumTypeDefinitionsByName(ulong handle) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataModule.StartEnumTypeInstancesByName(char* name, uint flags, IXCLRDataAppDomain? appDomain, ulong* handle) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataModule.EnumTypeInstanceByName(ulong* handle, DacComNullableByRef type) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataModule.EndEnumTypeInstancesByName(ulong handle) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataModule.GetTypeDefinitionByToken(/*mdTypeDef*/ uint token, DacComNullableByRef typeDefinition) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataModule.StartEnumMethodDefinitionsByName(char* name, uint flags, ulong* handle) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; *handle = 0; @@ -320,6 +389,7 @@ int IXCLRDataModule.StartEnumMethodDefinitionsByName(char* name, uint flags, ulo int IXCLRDataModule.EnumMethodDefinitionByName(ulong* handle, DacComNullableByRef method) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; EnumMethodDefinitions emd; try @@ -354,7 +424,7 @@ int IXCLRDataModule.EnumMethodDefinitionByName(ulong* handle, DacComNullableByRe if (emd.Enumerator.MoveNext()) { uint token = emd.Enumerator.Current; - method.Interface = new ClrDataMethodDefinition(_target, _address, token, legacyMethod); + method.Interface = new ClrDataMethodDefinition(_target, _address, token, legacyMethod, _apiLock); } else { @@ -377,6 +447,7 @@ int IXCLRDataModule.EnumMethodDefinitionByName(ulong* handle, DacComNullableByRe } int IXCLRDataModule.EndEnumMethodDefinitionsByName(ulong handle) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; EnumMethodDefinitions emd; try @@ -403,14 +474,27 @@ int IXCLRDataModule.EndEnumMethodDefinitionsByName(ulong handle) return hr; } int IXCLRDataModule.StartEnumMethodInstancesByName(char* name, uint flags, IXCLRDataAppDomain? appDomain, ulong* handle) - => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.StartEnumMethodInstancesByName(name, flags, appDomain, handle) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.StartEnumMethodInstancesByName(name, flags, appDomain, handle) : HResults.E_NOTIMPL; + } int IXCLRDataModule.EnumMethodInstanceByName(ulong* handle, DacComNullableByRef method) - => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.EnumMethodInstanceByName(handle, method) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.EnumMethodInstanceByName(handle, method) : HResults.E_NOTIMPL; + } int IXCLRDataModule.EndEnumMethodInstancesByName(ulong handle) - => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.EndEnumMethodInstancesByName(handle) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.EndEnumMethodInstancesByName(handle) : HResults.E_NOTIMPL; + } int IXCLRDataModule.GetMethodDefinitionByToken(/*mdMethodDef*/ uint token, DacComNullableByRef methodDefinition) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; int hrLocal = HResults.S_OK; IXCLRDataMethodDefinition? legacyMethod = null; @@ -426,7 +510,7 @@ int IXCLRDataModule.GetMethodDefinitionByToken(/*mdMethodDef*/ uint token, DacCo if ((EcmaMetadataUtils.TokenType)(token & EcmaMetadataUtils.TokenTypeMask) != EcmaMetadataUtils.TokenType.mdtMethodDef) throw new ArgumentException(); - methodDefinition.Interface = new ClrDataMethodDefinition(_target, _address, token, legacyMethod); + methodDefinition.Interface = new ClrDataMethodDefinition(_target, _address, token, legacyMethod, _apiLock); } catch (System.Exception ex) { @@ -444,14 +528,27 @@ int IXCLRDataModule.GetMethodDefinitionByToken(/*mdMethodDef*/ uint token, DacCo } int IXCLRDataModule.StartEnumDataByName(char* name, uint flags, IXCLRDataAppDomain? appDomain, IXCLRDataTask? tlsTask, ulong* handle) - => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.StartEnumDataByName(name, flags, appDomain, tlsTask, handle) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.StartEnumDataByName(name, flags, appDomain, tlsTask, handle) : HResults.E_NOTIMPL; + } int IXCLRDataModule.EnumDataByName(ulong* handle, DacComNullableByRef value) - => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.EnumDataByName(handle, value) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.EnumDataByName(handle, value) : HResults.E_NOTIMPL; + } int IXCLRDataModule.EndEnumDataByName(ulong handle) - => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.EndEnumDataByName(handle) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.EndEnumDataByName(handle) : HResults.E_NOTIMPL; + } int IXCLRDataModule.GetName(uint bufLen, uint* nameLen, char* name) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -496,6 +593,7 @@ int IXCLRDataModule.GetName(uint bufLen, uint* nameLen, char* name) } int IXCLRDataModule.GetFileName(uint bufLen, uint* nameLen, char* name) { + using Lock.Scope scope = _apiLock.EnterScope(); try { Contracts.ILoader contract = _target.Contracts.Loader; @@ -545,6 +643,7 @@ int IXCLRDataModule.GetFileName(uint bufLen, uint* nameLen, char* name) int IXCLRDataModule.GetFlags(uint* flags) { + using Lock.Scope scope = _apiLock.EnterScope(); *flags = 0; try { @@ -581,10 +680,15 @@ int IXCLRDataModule.GetFlags(uint* flags) } int IXCLRDataModule.IsSameObject(IXCLRDataModule* mod) - => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.IsSameObject(mod) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.IsSameObject(mod) : HResults.E_NOTIMPL; + } int IXCLRDataModule.StartEnumExtents(ulong* handle) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -633,6 +737,7 @@ int IXCLRDataModule.StartEnumExtents(ulong* handle) } int IXCLRDataModule.EnumExtent(ulong* handle, /*CLRDATA_MODULE_EXTENT*/ void* extent) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -683,6 +788,7 @@ int IXCLRDataModule.EnumExtent(ulong* handle, /*CLRDATA_MODULE_EXTENT*/ void* ex } int IXCLRDataModule.EndEnumExtents(ulong handle) { + using Lock.Scope scope = _apiLock.EnterScope(); #if DEBUG if (_legacyModule is not null) { @@ -696,6 +802,7 @@ int IXCLRDataModule.EndEnumExtents(ulong handle) int IXCLRDataModule.Request(uint reqCode, uint inBufferSize, byte* inBuffer, uint outBufferSize, byte* outBuffer) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -792,17 +899,34 @@ private void PopulateModuleData(DacpGetModuleData* getModuleData) } int IXCLRDataModule.StartEnumAppDomains(ulong* handle) - => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.StartEnumAppDomains(handle) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.StartEnumAppDomains(handle) : HResults.E_NOTIMPL; + } int IXCLRDataModule.EnumAppDomain(ulong* handle, /*IXCLRDataAppDomain*/ void** appDomain) - => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.EnumAppDomain(handle, appDomain) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.EnumAppDomain(handle, appDomain) : HResults.E_NOTIMPL; + } int IXCLRDataModule.EndEnumAppDomains(ulong handle) - => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.EndEnumAppDomains(handle) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.EndEnumAppDomains(handle) : HResults.E_NOTIMPL; + } int IXCLRDataModule.GetVersionId(Guid* vid) - => LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.GetVersionId(vid) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyModule is not null ? _legacyModule.GetVersionId(vid) : HResults.E_NOTIMPL; + } int IXCLRDataModule2.SetJITCompilerFlags(uint flags) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { diff --git a/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataStackWalk.cs b/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataStackWalk.cs index 1baa8081f544..9daa22fae046 100644 --- a/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataStackWalk.cs +++ b/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataStackWalk.cs @@ -6,6 +6,7 @@ using System.Diagnostics; using System.Runtime.InteropServices; using System.Runtime.InteropServices.Marshalling; +using System.Threading; using Microsoft.Diagnostics.DataContractReader.Contracts; using Microsoft.Diagnostics.DataContractReader.Contracts.StackWalkHelpers; @@ -14,6 +15,7 @@ namespace Microsoft.Diagnostics.DataContractReader.Legacy; [GeneratedComClass] public sealed unsafe partial class ClrDataStackWalk : IXCLRDataStackWalk { + private readonly Lock _apiLock; private readonly TargetPointer _threadAddr; private readonly CLRDataStackWalkFlag _flags; private readonly Target _target; @@ -25,8 +27,9 @@ public sealed unsafe partial class ClrDataStackWalk : IXCLRDataStackWalk private ulong _stackPointerBeforeFiltering; private ulong _stackSizeSkipped; - public ClrDataStackWalk(TargetPointer threadAddr, CLRDataStackWalkFlag flags, Target target, IXCLRDataStackWalk? legacyImpl) + public ClrDataStackWalk(TargetPointer threadAddr, CLRDataStackWalkFlag flags, Target target, IXCLRDataStackWalk? legacyImpl, Lock apiLock) { + _apiLock = apiLock; _threadAddr = threadAddr; _flags = flags; _target = target; @@ -81,6 +84,7 @@ private void Reseed(byte[] context, bool isFirst) int IXCLRDataStackWalk.GetContext(uint contextFlags, uint contextBufSize, uint* contextSize, [MarshalUsing(CountElementName = "contextBufSize"), Out] byte[] contextBuf) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; if (_currentFrameIsValid) @@ -128,6 +132,7 @@ int IXCLRDataStackWalk.GetContext(uint contextFlags, uint contextBufSize, uint* int IXCLRDataStackWalk.GetFrame(DacComNullableByRef frame) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; IXCLRDataFrame? legacyFrame = null; @@ -145,7 +150,7 @@ int IXCLRDataStackWalk.GetFrame(DacComNullableByRef frame) if (!_currentFrameIsValid) throw new ArgumentException(); - frame.Interface = new ClrDataFrame(_target, _threadAddr, _dataFrames.Current, legacyFrame); + frame.Interface = new ClrDataFrame(_target, _threadAddr, _dataFrames.Current, legacyFrame, _apiLock); } catch (System.Exception ex) { @@ -156,6 +161,7 @@ int IXCLRDataStackWalk.GetFrame(DacComNullableByRef frame) } int IXCLRDataStackWalk.GetFrameType(CLRDataSimpleFrameType* simpleType, CLRDataDetailedFrameType* detailedType) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -210,6 +216,7 @@ int IXCLRDataStackWalk.GetFrameType(CLRDataSimpleFrameType* simpleType, CLRDataD } int IXCLRDataStackWalk.GetStackSizeSkipped(ulong* stackSizeSkipped) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -237,6 +244,7 @@ int IXCLRDataStackWalk.GetStackSizeSkipped(ulong* stackSizeSkipped) } int IXCLRDataStackWalk.Next() { + using Lock.Scope scope = _apiLock.EnterScope(); int hr; try { @@ -264,6 +272,7 @@ int IXCLRDataStackWalk.Next() } int IXCLRDataStackWalk.Request(uint reqCode, uint inBufferSize, byte* inBuffer, uint outBufferSize, byte* outBuffer) { + using Lock.Scope scope = _apiLock.EnterScope(); const uint DACSTACKPRIV_REQUEST_FRAME_DATA = 0xf0000000; int hr = HResults.S_OK; @@ -320,6 +329,7 @@ int IXCLRDataStackWalk.Request(uint reqCode, uint inBufferSize, byte* inBuffer, } int IXCLRDataStackWalk.SetContext(uint contextSize, [In, MarshalUsing(CountElementName = "contextSize")] byte[] context) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -347,5 +357,9 @@ int IXCLRDataStackWalk.SetContext(uint contextSize, [In, MarshalUsing(CountEleme } int IXCLRDataStackWalk.SetContext2(uint flags, uint contextSize, [In, MarshalUsing(CountElementName = "contextSize")] byte[] context) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } } diff --git a/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataTask.cs b/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataTask.cs index d774e44e582a..42abe9909e00 100644 --- a/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataTask.cs +++ b/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataTask.cs @@ -5,6 +5,7 @@ using System.Diagnostics; using System.Runtime.InteropServices; using System.Runtime.InteropServices.Marshalling; +using System.Threading; using Microsoft.Diagnostics.DataContractReader.Contracts; namespace Microsoft.Diagnostics.DataContractReader.Legacy; @@ -12,21 +13,28 @@ namespace Microsoft.Diagnostics.DataContractReader.Legacy; [GeneratedComClass] public sealed unsafe partial class ClrDataTask : IXCLRDataTask { + private readonly Lock _apiLock; private readonly TargetPointer _address; private readonly Target _target; private readonly IXCLRDataTask? _legacyImpl; - public ClrDataTask(TargetPointer address, Target target, IXCLRDataTask? legacyImpl) + public ClrDataTask(TargetPointer address, Target target, IXCLRDataTask? legacyImpl, Lock apiLock) { + _apiLock = apiLock; _address = address; _target = target; _legacyImpl = legacyImpl; } int IXCLRDataTask.GetProcess(/*IXCLRDataProcess*/ void** process) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataTask.GetCurrentAppDomain(DacComNullableByRef appDomain) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK, hrLocal = HResults.S_OK; IXCLRDataAppDomain? legacyAppDomain = null; @@ -39,7 +47,7 @@ int IXCLRDataTask.GetCurrentAppDomain(DacComNullableByRef ap try { TargetPointer currentAppDomain = _target.Contracts.Loader.GetAppDomain(); - appDomain.Interface = new ClrDataAppDomain(_target, currentAppDomain, legacyAppDomain); + appDomain.Interface = new ClrDataAppDomain(_target, currentAppDomain, legacyAppDomain, _apiLock); } catch (System.Exception ex) { @@ -54,20 +62,45 @@ int IXCLRDataTask.GetCurrentAppDomain(DacComNullableByRef ap return hr; } int IXCLRDataTask.GetUniqueID(ulong* id) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataTask.GetFlags(uint* flags) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataTask.IsSameObject(IXCLRDataTask* task) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataTask.GetManagedObject(DacComNullableByRef value) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataTask.GetDesiredExecutionState(uint* state) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataTask.SetDesiredExecutionState(uint state) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataTask.CreateStackWalk(CLRDataStackWalkFlag flags, DacComNullableByRef stackWalk) { + using Lock.Scope scope = _apiLock.EnterScope(); Contracts.ThreadData threadData = _target.Contracts.Thread.GetThreadData(_address); if (threadData.State.HasFlag(Contracts.ThreadState.Unstarted)) return HResults.E_FAIL; @@ -82,19 +115,32 @@ int IXCLRDataTask.CreateStackWalk(CLRDataStackWalkFlag flags, DacComNullableByRe legacyStackWalk = legacyStackWalkOut.Interface; } - stackWalk.Interface = new ClrDataStackWalk(_address, flags, _target, legacyStackWalk); + stackWalk.Interface = new ClrDataStackWalk(_address, flags, _target, legacyStackWalk, _apiLock); return HResults.S_OK; } int IXCLRDataTask.GetOSThreadID(uint* id) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataTask.GetContext(uint contextFlags, uint contextBufSize, uint* contextSize, byte* contextBuffer) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataTask.SetContext(uint contextSize, byte* context) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataTask.GetCurrentExceptionState(DacComNullableByRef exception) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK, hrLocal = HResults.S_OK; IXCLRDataExceptionState? legacyExceptionState = null; @@ -114,7 +160,7 @@ int IXCLRDataTask.GetCurrentExceptionState(DacComNullableByRef HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataTask.GetLastExceptionState(DacComNullableByRef exception) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK, hrLocal = HResults.S_OK; IXCLRDataExceptionState? legacyExceptionState = null; @@ -195,7 +247,7 @@ int IXCLRDataTask.GetLastExceptionState(DacComNullableByRef mod) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetModule(mod) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetModule(mod) : HResults.E_NOTIMPL; + } int IXCLRDataTypeDefinition.StartEnumMethodDefinitions(ulong* handle) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.StartEnumMethodDefinitions(handle) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.StartEnumMethodDefinitions(handle) : HResults.E_NOTIMPL; + } int IXCLRDataTypeDefinition.EnumMethodDefinition(ulong* handle, DacComNullableByRef methodDefinition) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EnumMethodDefinition(handle, methodDefinition) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EnumMethodDefinition(handle, methodDefinition) : HResults.E_NOTIMPL; + } int IXCLRDataTypeDefinition.EndEnumMethodDefinitions(ulong handle) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EndEnumMethodDefinitions(handle) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EndEnumMethodDefinitions(handle) : HResults.E_NOTIMPL; + } int IXCLRDataTypeDefinition.StartEnumMethodDefinitionsByName(char* name, uint flags, ulong* handle) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.StartEnumMethodDefinitionsByName(name, flags, handle) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.StartEnumMethodDefinitionsByName(name, flags, handle) : HResults.E_NOTIMPL; + } int IXCLRDataTypeDefinition.EnumMethodDefinitionByName(ulong* handle, DacComNullableByRef method) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EnumMethodDefinitionByName(handle, method) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EnumMethodDefinitionByName(handle, method) : HResults.E_NOTIMPL; + } int IXCLRDataTypeDefinition.EndEnumMethodDefinitionsByName(ulong handle) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EndEnumMethodDefinitionsByName(handle) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EndEnumMethodDefinitionsByName(handle) : HResults.E_NOTIMPL; + } int IXCLRDataTypeDefinition.GetMethodDefinitionByToken(uint token, DacComNullableByRef methodDefinition) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetMethodDefinitionByToken(token, methodDefinition) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetMethodDefinitionByToken(token, methodDefinition) : HResults.E_NOTIMPL; + } int IXCLRDataTypeDefinition.StartEnumInstances(IXCLRDataAppDomain? appDomain, ulong* handle) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.StartEnumInstances(appDomain, handle) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.StartEnumInstances(appDomain, handle) : HResults.E_NOTIMPL; + } int IXCLRDataTypeDefinition.EnumInstance(ulong* handle, DacComNullableByRef instance) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EnumInstance(handle, instance) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EnumInstance(handle, instance) : HResults.E_NOTIMPL; + } int IXCLRDataTypeDefinition.EndEnumInstances(ulong handle) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EndEnumInstances(handle) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EndEnumInstances(handle) : HResults.E_NOTIMPL; + } int IXCLRDataTypeDefinition.GetName(uint flags, uint bufLen, uint* nameLen, char* nameBuf) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -132,6 +181,7 @@ int IXCLRDataTypeDefinition.GetName(uint flags, uint bufLen, uint* nameLen, char int IXCLRDataTypeDefinition.GetTokenAndScope(uint* token, DacComNullableByRef mod) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -149,7 +199,7 @@ int IXCLRDataTypeDefinition.GetTokenAndScope(uint* token, DacComNullableByRef LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetFlags(flags) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetFlags(flags) : HResults.E_NOTIMPL; + } int IXCLRDataTypeDefinition.IsSameObject(IXCLRDataTypeDefinition? type) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.IsSameObject(type) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.IsSameObject(type) : HResults.E_NOTIMPL; + } int IXCLRDataTypeDefinition.Request(uint reqCode, uint inBufferSize, byte* inBuffer, uint outBufferSize, byte* outBuffer) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.Request(reqCode, inBufferSize, inBuffer, outBufferSize, outBuffer) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.Request(reqCode, inBufferSize, inBuffer, outBufferSize, outBuffer) : HResults.E_NOTIMPL; + } int IXCLRDataTypeDefinition.GetArrayRank(uint* rank) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetArrayRank(rank) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetArrayRank(rank) : HResults.E_NOTIMPL; + } int IXCLRDataTypeDefinition.GetBase(DacComNullableByRef @base) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetBase(@base) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetBase(@base) : HResults.E_NOTIMPL; + } int IXCLRDataTypeDefinition.GetNumFields(uint flags, uint* numFields) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetNumFields(flags, numFields) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetNumFields(flags, numFields) : HResults.E_NOTIMPL; + } int IXCLRDataTypeDefinition.StartEnumFields(uint flags, ulong* handle) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.StartEnumFields(flags, handle) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.StartEnumFields(flags, handle) : HResults.E_NOTIMPL; + } int IXCLRDataTypeDefinition.EnumField(ulong* handle, uint nameBufLen, uint* nameLen, char* nameBuf, DacComNullableByRef type, uint* flags, uint* token) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EnumField(handle, nameBufLen, nameLen, nameBuf, type, flags, token) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EnumField(handle, nameBufLen, nameLen, nameBuf, type, flags, token) : HResults.E_NOTIMPL; + } int IXCLRDataTypeDefinition.EndEnumFields(ulong handle) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EndEnumFields(handle) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EndEnumFields(handle) : HResults.E_NOTIMPL; + } int IXCLRDataTypeDefinition.StartEnumFieldsByName(char* name, uint nameFlags, uint fieldFlags, ulong* handle) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.StartEnumFieldsByName(name, nameFlags, fieldFlags, handle) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.StartEnumFieldsByName(name, nameFlags, fieldFlags, handle) : HResults.E_NOTIMPL; + } int IXCLRDataTypeDefinition.EnumFieldByName(ulong* handle, DacComNullableByRef type, uint* flags, uint* token) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EnumFieldByName(handle, type, flags, token) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EnumFieldByName(handle, type, flags, token) : HResults.E_NOTIMPL; + } int IXCLRDataTypeDefinition.EndEnumFieldsByName(ulong handle) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EndEnumFieldsByName(handle) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EndEnumFieldsByName(handle) : HResults.E_NOTIMPL; + } int IXCLRDataTypeDefinition.GetFieldByToken(uint token, uint nameBufLen, uint* nameLen, char* nameBuf, DacComNullableByRef type, uint* flags) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetFieldByToken(token, nameBufLen, nameLen, nameBuf, type, flags) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetFieldByToken(token, nameBufLen, nameLen, nameBuf, type, flags) : HResults.E_NOTIMPL; + } int IXCLRDataTypeDefinition.GetTypeNotification(uint* flags) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetTypeNotification(flags) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetTypeNotification(flags) : HResults.E_NOTIMPL; + } int IXCLRDataTypeDefinition.SetTypeNotification(uint flags) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.SetTypeNotification(flags) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.SetTypeNotification(flags) : HResults.E_NOTIMPL; + } int IXCLRDataTypeDefinition.EnumField2(ulong* handle, uint nameBufLen, uint* nameLen, char* nameBuf, DacComNullableByRef type, uint* flags, DacComNullableByRef tokenScope, uint* token) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EnumField2(handle, nameBufLen, nameLen, nameBuf, type, flags, tokenScope, token) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EnumField2(handle, nameBufLen, nameLen, nameBuf, type, flags, tokenScope, token) : HResults.E_NOTIMPL; + } int IXCLRDataTypeDefinition.EnumFieldByName2(ulong* handle, DacComNullableByRef type, uint* flags, DacComNullableByRef tokenScope, uint* token) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EnumFieldByName2(handle, type, flags, tokenScope, token) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EnumFieldByName2(handle, type, flags, tokenScope, token) : HResults.E_NOTIMPL; + } int IXCLRDataTypeDefinition.GetFieldByToken2(IXCLRDataModule? tokenScope, uint token, uint nameBufLen, uint* nameLen, char* nameBuf, DacComNullableByRef type, uint* flags) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetFieldByToken2(tokenScope, token, nameBufLen, nameLen, nameBuf, type, flags) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetFieldByToken2(tokenScope, token, nameBufLen, nameLen, nameBuf, type, flags) : HResults.E_NOTIMPL; + } } diff --git a/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataTypeInstance.cs b/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataTypeInstance.cs index 113e4e823375..3aebe72544d6 100644 --- a/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataTypeInstance.cs +++ b/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataTypeInstance.cs @@ -4,6 +4,7 @@ using System; using System.Diagnostics; using System.Runtime.InteropServices.Marshalling; +using System.Threading; using Microsoft.Diagnostics.DataContractReader.Contracts; namespace Microsoft.Diagnostics.DataContractReader.Legacy; @@ -11,6 +12,7 @@ namespace Microsoft.Diagnostics.DataContractReader.Legacy; [GeneratedComClass] public sealed unsafe partial class ClrDataTypeInstance : IXCLRDataTypeInstance { + private readonly Lock _apiLock; private readonly Target _target; private readonly ITypeHandle _typeHandle; private readonly IXCLRDataTypeInstance? _legacyImpl; @@ -18,54 +20,108 @@ public sealed unsafe partial class ClrDataTypeInstance : IXCLRDataTypeInstance internal ITypeHandle TypeHandle => _typeHandle; internal IXCLRDataTypeInstance? LegacyImpl => _legacyImpl; - public ClrDataTypeInstance(Target target, ITypeHandle typeHandle, IXCLRDataTypeInstance? legacyImpl) + public ClrDataTypeInstance(Target target, ITypeHandle typeHandle, IXCLRDataTypeInstance? legacyImpl, Lock apiLock) { + _apiLock = apiLock; _target = target; _typeHandle = typeHandle; _legacyImpl = legacyImpl; } int IXCLRDataTypeInstance.StartEnumMethodInstances(ulong* handle) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.StartEnumMethodInstances(handle) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.StartEnumMethodInstances(handle) : HResults.E_NOTIMPL; + } int IXCLRDataTypeInstance.EnumMethodInstance(ulong* handle, DacComNullableByRef methodInstance) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EnumMethodInstance(handle, methodInstance) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EnumMethodInstance(handle, methodInstance) : HResults.E_NOTIMPL; + } int IXCLRDataTypeInstance.EndEnumMethodInstances(ulong handle) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EndEnumMethodInstances(handle) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EndEnumMethodInstances(handle) : HResults.E_NOTIMPL; + } int IXCLRDataTypeInstance.StartEnumMethodInstancesByName(char* name, uint flags, ulong* handle) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.StartEnumMethodInstancesByName(name, flags, handle) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.StartEnumMethodInstancesByName(name, flags, handle) : HResults.E_NOTIMPL; + } int IXCLRDataTypeInstance.EnumMethodInstanceByName(ulong* handle, DacComNullableByRef method) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EnumMethodInstanceByName(handle, method) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EnumMethodInstanceByName(handle, method) : HResults.E_NOTIMPL; + } int IXCLRDataTypeInstance.EndEnumMethodInstancesByName(ulong handle) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EndEnumMethodInstancesByName(handle) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EndEnumMethodInstancesByName(handle) : HResults.E_NOTIMPL; + } int IXCLRDataTypeInstance.GetNumStaticFields(uint* numFields) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetNumStaticFields(numFields) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetNumStaticFields(numFields) : HResults.E_NOTIMPL; + } int IXCLRDataTypeInstance.GetStaticFieldByIndex(uint index, IXCLRDataTask? tlsTask, DacComNullableByRef field, uint bufLen, uint* nameLen, char* nameBuf, uint* token) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetStaticFieldByIndex(index, tlsTask, field, bufLen, nameLen, nameBuf, token) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetStaticFieldByIndex(index, tlsTask, field, bufLen, nameLen, nameBuf, token) : HResults.E_NOTIMPL; + } int IXCLRDataTypeInstance.StartEnumStaticFieldsByName(char* name, uint flags, IXCLRDataTask? tlsTask, ulong* handle) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.StartEnumStaticFieldsByName(name, flags, tlsTask, handle) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.StartEnumStaticFieldsByName(name, flags, tlsTask, handle) : HResults.E_NOTIMPL; + } int IXCLRDataTypeInstance.EnumStaticFieldByName(ulong* handle, DacComNullableByRef value) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EnumStaticFieldByName(handle, value) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EnumStaticFieldByName(handle, value) : HResults.E_NOTIMPL; + } int IXCLRDataTypeInstance.EndEnumStaticFieldsByName(ulong handle) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EndEnumStaticFieldsByName(handle) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EndEnumStaticFieldsByName(handle) : HResults.E_NOTIMPL; + } int IXCLRDataTypeInstance.GetNumTypeArguments(uint* numTypeArgs) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetNumTypeArguments(numTypeArgs) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetNumTypeArguments(numTypeArgs) : HResults.E_NOTIMPL; + } int IXCLRDataTypeInstance.GetTypeArgumentByIndex(uint index, DacComNullableByRef typeArg) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetTypeArgumentByIndex(index, typeArg) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetTypeArgumentByIndex(index, typeArg) : HResults.E_NOTIMPL; + } int IXCLRDataTypeInstance.GetName(uint flags, uint bufLen, uint* nameLen, char* nameBuf) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try @@ -118,10 +174,15 @@ int IXCLRDataTypeInstance.GetName(uint flags, uint bufLen, uint* nameLen, char* } int IXCLRDataTypeInstance.GetModule(DacComNullableByRef mod) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetModule(mod) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetModule(mod) : HResults.E_NOTIMPL; + } int IXCLRDataTypeInstance.GetDefinition(DacComNullableByRef typeDefinition) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; int hrLocal = HResults.S_OK; IXCLRDataTypeDefinition? legacyDefinition = null; @@ -170,7 +231,8 @@ int IXCLRDataTypeInstance.GetDefinition(DacComNullableByRef LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetFlags(flags) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetFlags(flags) : HResults.E_NOTIMPL; + } int IXCLRDataTypeInstance.IsSameObject(IXCLRDataTypeInstance? type) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.IsSameObject(type) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.IsSameObject(type) : HResults.E_NOTIMPL; + } int IXCLRDataTypeInstance.Request(uint reqCode, uint inBufferSize, byte* inBuffer, uint outBufferSize, byte* outBuffer) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.Request(reqCode, inBufferSize, inBuffer, outBufferSize, outBuffer) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.Request(reqCode, inBufferSize, inBuffer, outBufferSize, outBuffer) : HResults.E_NOTIMPL; + } int IXCLRDataTypeInstance.GetNumStaticFields2(uint flags, uint* numFields) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetNumStaticFields2(flags, numFields) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetNumStaticFields2(flags, numFields) : HResults.E_NOTIMPL; + } int IXCLRDataTypeInstance.StartEnumStaticFields(uint flags, IXCLRDataTask? tlsTask, ulong* handle) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.StartEnumStaticFields(flags, tlsTask, handle) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.StartEnumStaticFields(flags, tlsTask, handle) : HResults.E_NOTIMPL; + } int IXCLRDataTypeInstance.EnumStaticField(ulong* handle, DacComNullableByRef value) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EnumStaticField(handle, value) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EnumStaticField(handle, value) : HResults.E_NOTIMPL; + } int IXCLRDataTypeInstance.EndEnumStaticFields(ulong handle) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EndEnumStaticFields(handle) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EndEnumStaticFields(handle) : HResults.E_NOTIMPL; + } int IXCLRDataTypeInstance.StartEnumStaticFieldsByName2(char* name, uint nameFlags, uint fieldFlags, IXCLRDataTask? tlsTask, ulong* handle) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.StartEnumStaticFieldsByName2(name, nameFlags, fieldFlags, tlsTask, handle) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.StartEnumStaticFieldsByName2(name, nameFlags, fieldFlags, tlsTask, handle) : HResults.E_NOTIMPL; + } int IXCLRDataTypeInstance.EnumStaticFieldByName2(ulong* handle, DacComNullableByRef value) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EnumStaticFieldByName2(handle, value) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EnumStaticFieldByName2(handle, value) : HResults.E_NOTIMPL; + } int IXCLRDataTypeInstance.EndEnumStaticFieldsByName2(ulong handle) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EndEnumStaticFieldsByName2(handle) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EndEnumStaticFieldsByName2(handle) : HResults.E_NOTIMPL; + } int IXCLRDataTypeInstance.GetStaticFieldByToken(uint token, IXCLRDataTask? tlsTask, DacComNullableByRef field, uint bufLen, uint* nameLen, char* nameBuf) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetStaticFieldByToken(token, tlsTask, field, bufLen, nameLen, nameBuf) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetStaticFieldByToken(token, tlsTask, field, bufLen, nameLen, nameBuf) : HResults.E_NOTIMPL; + } int IXCLRDataTypeInstance.GetBase(DacComNullableByRef @base) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetBase(@base) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetBase(@base) : HResults.E_NOTIMPL; + } int IXCLRDataTypeInstance.EnumStaticField2(ulong* handle, DacComNullableByRef value, uint bufLen, uint* nameLen, char* nameBuf, DacComNullableByRef tokenScope, uint* token) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EnumStaticField2(handle, value, bufLen, nameLen, nameBuf, tokenScope, token) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EnumStaticField2(handle, value, bufLen, nameLen, nameBuf, tokenScope, token) : HResults.E_NOTIMPL; + } int IXCLRDataTypeInstance.EnumStaticFieldByName3(ulong* handle, DacComNullableByRef value, DacComNullableByRef tokenScope, uint* token) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EnumStaticFieldByName3(handle, value, tokenScope, token) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.EnumStaticFieldByName3(handle, value, tokenScope, token) : HResults.E_NOTIMPL; + } int IXCLRDataTypeInstance.GetStaticFieldByToken2(IXCLRDataModule? tokenScope, uint token, IXCLRDataTask? tlsTask, DacComNullableByRef field, uint bufLen, uint* nameLen, char* nameBuf) - => LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetStaticFieldByToken2(tokenScope, token, tlsTask, field, bufLen, nameLen, nameBuf) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyImpl is not null ? _legacyImpl.GetStaticFieldByToken2(tokenScope, token, tlsTask, field, bufLen, nameLen, nameBuf) : HResults.E_NOTIMPL; + } } diff --git a/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataValue.cs b/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataValue.cs index 090936f520fe..ac8bd2f40fbb 100644 --- a/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataValue.cs +++ b/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataValue.cs @@ -11,6 +11,7 @@ using System.Reflection.Metadata.Ecma335; using System.Runtime.InteropServices; using System.Runtime.InteropServices.Marshalling; +using System.Threading; using Microsoft.Diagnostics.DataContractReader.Contracts; namespace Microsoft.Diagnostics.DataContractReader.Legacy; @@ -29,6 +30,7 @@ public readonly struct NativeVarLocation [GeneratedComClass] public sealed unsafe partial class ClrDataValue : IXCLRDataValue { + private readonly Lock _apiLock; private readonly Target _target; private readonly TargetPointer _threadAddress; private readonly IXCLRDataValue? _legacyImpl; @@ -45,8 +47,10 @@ public ClrDataValue( ITypeHandle? typeHandle, TargetPointer baseAddress, NativeVarLocation[] locations, - IXCLRDataValue? legacyImpl) + IXCLRDataValue? legacyImpl, + Lock apiLock) { + _apiLock = apiLock; _target = target; _threadAddress = threadAddress; _legacyImpl = legacyImpl; @@ -71,6 +75,7 @@ public ClrDataValue( int IXCLRDataValue.GetFlags(uint* flags) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -97,6 +102,7 @@ int IXCLRDataValue.GetFlags(uint* flags) int IXCLRDataValue.GetAddress(ClrDataAddress* address) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -129,6 +135,7 @@ int IXCLRDataValue.GetAddress(ClrDataAddress* address) int IXCLRDataValue.GetSize(ulong* size) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -161,6 +168,7 @@ int IXCLRDataValue.GetSize(ulong* size) int IXCLRDataValue.GetBytes(uint bufLen, uint* dataSize, byte* buffer) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -226,10 +234,16 @@ int IXCLRDataValue.GetBytes(uint bufLen, uint* dataSize, byte* buffer) return hr; } - int IXCLRDataValue.SetBytes(uint bufLen, uint* dataSize, byte* buffer) => HResults.E_NOTIMPL; + int IXCLRDataValue.SetBytes(uint bufLen, uint* dataSize, byte* buffer) + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataValue.GetType(DacComNullableByRef typeInstance) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; IXCLRDataTypeInstance? legacyType = null; int hrLocal = HResults.S_OK; @@ -254,7 +268,7 @@ int IXCLRDataValue.GetType(DacComNullableByRef typeInstan } else { - typeInstance.Interface = new ClrDataTypeInstance(_target, _typeHandle, legacyType); + typeInstance.Interface = new ClrDataTypeInstance(_target, _typeHandle, legacyType, _apiLock); } } catch (System.Exception ex) @@ -270,7 +284,12 @@ int IXCLRDataValue.GetType(DacComNullableByRef typeInstan return hr; } - int IXCLRDataValue.GetNumFields(uint* numFields) => HResults.E_NOTIMPL; + int IXCLRDataValue.GetNumFields(uint* numFields) + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataValue.GetFieldByIndex( uint index, @@ -279,10 +298,15 @@ int IXCLRDataValue.GetFieldByIndex( uint* nameLen, char* nameBuf, uint* token) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataValue.Request(uint reqCode, uint inBufferSize, byte* inBuffer, uint outBufferSize, byte* outBuffer) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try @@ -326,6 +350,7 @@ int IXCLRDataValue.Request(uint reqCode, uint inBufferSize, byte* inBuffer, uint int IXCLRDataValue.GetNumFields2(uint flags, IXCLRDataTypeInstance? fromType, uint* numFields) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -355,7 +380,11 @@ int IXCLRDataValue.GetNumFields2(uint flags, IXCLRDataTypeInstance? fromType, ui } int IXCLRDataValue.StartEnumFields(uint flags, IXCLRDataTypeInstance? fromType, ulong* handle) - => StartEnumFields(null, (uint)CLRDataByNameFlag.CLRDATA_BYNAME_CASE_SENSITIVE, flags, fromType, handle); + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return StartEnumFields(null, (uint)CLRDataByNameFlag.CLRDATA_BYNAME_CASE_SENSITIVE, flags, fromType, handle); + } int IXCLRDataValue.EnumField( ulong* handle, @@ -364,17 +393,39 @@ int IXCLRDataValue.EnumField( uint* nameLen, char* nameBuf, uint* token) - => EnumField(handle, field, nameBufLen, nameLen, nameBuf, token, byName: false); + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return EnumField(handle, field, nameBufLen, nameLen, nameBuf, token, byName: false); + } - int IXCLRDataValue.EndEnumFields(ulong handle) => EndEnumFields(handle, byName: false); + int IXCLRDataValue.EndEnumFields(ulong handle) + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return EndEnumFields(handle, byName: false); + } int IXCLRDataValue.StartEnumFieldsByName(char* name, uint nameFlags, uint fieldFlags, IXCLRDataTypeInstance? fromType, ulong* handle) - => StartEnumFields(name is null ? null : new string(name), nameFlags, fieldFlags, fromType, handle); + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return StartEnumFields(name is null ? null : new string(name), nameFlags, fieldFlags, fromType, handle); + } int IXCLRDataValue.EnumFieldByName(ulong* handle, DacComNullableByRef field, uint* token) - => EnumField(handle, field, 0, null, null, token, byName: true); + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return EnumField(handle, field, 0, null, null, token, byName: true); + } + + int IXCLRDataValue.EndEnumFieldsByName(ulong handle) + { + using Lock.Scope scope = _apiLock.EnterScope(); - int IXCLRDataValue.EndEnumFieldsByName(ulong handle) => EndEnumFields(handle, byName: true); + return EndEnumFields(handle, byName: true); + } int IXCLRDataValue.GetFieldByToken( uint token, @@ -382,10 +433,15 @@ int IXCLRDataValue.GetFieldByToken( uint bufLen, uint* nameLen, char* nameBuf) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataValue.GetAssociatedValue(DacComNullableByRef assocValue) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; IXCLRDataValue? legacyValue = null; int hrLocal = HResults.S_OK; @@ -418,7 +474,7 @@ int IXCLRDataValue.GetAssociatedValue(DacComNullableByRef assocV IsRegisterValue = false, }; - assocValue.Interface = new ClrDataValue(_target, _threadAddress, flags, _typeHandle, address, [location], legacyValue); + assocValue.Interface = new ClrDataValue(_target, _threadAddress, flags, _typeHandle, address, [location], legacyValue, _apiLock); } catch (System.Exception ex) { @@ -435,6 +491,7 @@ int IXCLRDataValue.GetAssociatedValue(DacComNullableByRef assocV int IXCLRDataValue.GetAssociatedType(DacComNullableByRef assocType) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; IXCLRDataTypeInstance? legacyType = null; int hrLocal = HResults.S_OK; @@ -463,7 +520,7 @@ int IXCLRDataValue.GetAssociatedType(DacComNullableByRef if (typeHandle is null) throw new InvalidCastException(); - assocType.Interface = new ClrDataTypeInstance(_target, typeHandle, legacyType); + assocType.Interface = new ClrDataTypeInstance(_target, typeHandle, legacyType, _apiLock); } catch (System.Exception ex) { @@ -480,6 +537,7 @@ int IXCLRDataValue.GetAssociatedType(DacComNullableByRef int IXCLRDataValue.GetString(uint bufLen, uint* strLen, char* str) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -520,6 +578,7 @@ int IXCLRDataValue.GetString(uint bufLen, uint* strLen, char* str) int IXCLRDataValue.GetArrayProperties(uint* rank, uint* totalElements, uint numDim, [Out, MarshalUsing(CountElementName = nameof(numDim))] uint[] dims, uint numBases, [Out, MarshalUsing(CountElementName = nameof(numBases))] int[] bases) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -569,6 +628,7 @@ int IXCLRDataValue.GetArrayProperties(uint* rank, uint* totalElements, uint numD int IXCLRDataValue.GetArrayElement(uint numInd, [In, MarshalUsing(CountElementName = nameof(numInd))] int[] indices, DacComNullableByRef value) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; IXCLRDataValue? legacyValue = null; int hrLocal = HResults.S_OK; @@ -617,7 +677,7 @@ int IXCLRDataValue.GetArrayElement(uint numInd, [In, MarshalUsing(CountElementNa IsRegisterValue = false, }; uint flags = GetTypeFieldValueFlags(elementType, null, 0, isDeref: false); - value.Interface = new ClrDataValue(_target, _threadAddress, flags, elementType, offset, [location], legacyValue); + value.Interface = new ClrDataValue(_target, _threadAddress, flags, elementType, offset, [location], legacyValue, _apiLock); } catch (System.Exception ex) { @@ -945,7 +1005,7 @@ private ClrDataValue CreateFieldValue( uint flags = entry.IsInherited ? (uint)ClrDataValueFlag.IS_INHERITED : 0; flags = GetTypeFieldValueFlags(fieldType, fieldDesc, flags, isDeref: false, fieldDefinition); - return new ClrDataValue(_target, _threadAddress, flags, fieldType, baseAddress, locations, legacyValue); + return new ClrDataValue(_target, _threadAddress, flags, fieldType, baseAddress, locations, legacyValue, _apiLock); } private uint GetTypeFieldValueFlags( @@ -1036,14 +1096,22 @@ int IXCLRDataValue.EnumField2( char* nameBuf, DacComNullableByRef tokenScope, uint* token) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataValue.EnumFieldByName2( ulong* handle, DacComNullableByRef field, DacComNullableByRef tokenScope, uint* token) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataValue.GetFieldByToken2( IXCLRDataModule? tokenScope, @@ -1052,10 +1120,15 @@ int IXCLRDataValue.GetFieldByToken2( uint bufLen, uint* nameLen, char* nameBuf) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataValue.GetNumLocations(uint* numLocs) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -1082,6 +1155,7 @@ int IXCLRDataValue.GetNumLocations(uint* numLocs) int IXCLRDataValue.GetLocationByIndex(uint loc, uint* flags, ClrDataAddress* arg) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { diff --git a/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs b/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs index a00a515ef2ee..6db40172c4ed 100644 --- a/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs +++ b/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs @@ -13,6 +13,7 @@ using System.Numerics; using System.Runtime.InteropServices; using System.Runtime.InteropServices.Marshalling; +using System.Threading; using Microsoft.Diagnostics.DataContractReader.Contracts; using Microsoft.Diagnostics.DataContractReader.Contracts.StackWalkHelpers; using Microsoft.Diagnostics.DataContractReader.RuntimeTypeSystemHelpers; @@ -25,6 +26,7 @@ public sealed unsafe partial class DacDbiImpl : IDacDbiInterface { private const uint DefaultAppDomainId = 1; + private readonly Lock _apiLock; private readonly Target _target; private IDacDbiInterface? _legacy; private ComObject? _dataTargetComObject; @@ -64,8 +66,10 @@ private bool CORProfilerPresent() public DacDbiImpl( Target target, object? legacyObj, + Lock apiLock, ComObject? dataTargetComObject = null) { + _apiLock = apiLock; _target = target; _legacy = legacyObj as IDacDbiInterface; _dataTargetComObject = dataTargetComObject; @@ -73,12 +77,14 @@ public DacDbiImpl( public int FlushCache() { + using Lock.Scope scope = _apiLock.EnterScope(); _target.Flush(FlushScope.All); return _legacy is not null ? _legacy.FlushCache() : HResults.S_OK; } public int Destroy() { + using Lock.Scope scope = _apiLock.EnterScope(); try { ComObject? legacyComObject = (object?)_legacy as ComObject; @@ -96,12 +102,17 @@ public int Destroy() } public int DacSetTargetConsistencyChecks(Interop.BOOL fEnableAsserts) - => LegacyFallbackHelper.CanFallback() && _legacy is not null + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.DacSetTargetConsistencyChecks(fEnableAsserts) : HResults.S_OK; + } public int IsLeftSideInitialized(Interop.BOOL* pResult) { + using Lock.Scope scope = _apiLock.EnterScope(); *pResult = Interop.BOOL.FALSE; int hr = HResults.S_OK; try @@ -129,6 +140,7 @@ public int IsLeftSideInitialized(Interop.BOOL* pResult) public int GetAppDomainId(ulong vmAppDomain, uint* pRetVal) { + using Lock.Scope scope = _apiLock.EnterScope(); *pRetVal = 0; int hr = HResults.S_OK; try @@ -154,6 +166,7 @@ public int GetAppDomainId(ulong vmAppDomain, uint* pRetVal) public int GetAppDomainFullName(ulong vmAppDomain, nint pStrName) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -176,6 +189,7 @@ public int GetAppDomainFullName(ulong vmAppDomain, nint pStrName) public int GetModuleSimpleName(ulong vmModule, nint pStrFilename) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; string? cdacSimpleName = null; try @@ -208,6 +222,7 @@ public int GetModuleSimpleName(ulong vmModule, nint pStrFilename) public int GetAssemblyPath(ulong vmAssembly, nint pStrFilename, Interop.BOOL* pResult) { + using Lock.Scope scope = _apiLock.EnterScope(); *pResult = Interop.BOOL.FALSE; int hr = HResults.S_OK; try @@ -244,6 +259,7 @@ public int GetAssemblyPath(ulong vmAssembly, nint pStrFilename, Interop.BOOL* pR public int ResolveTypeReference(DacDbiTypeRefData* pTypeRefInfo, DacDbiTypeRefData* pTargetRefInfo) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; bool resolved = false; TargetPointer targetAssembly = TargetPointer.Null; @@ -327,6 +343,7 @@ public int ResolveTypeReference(DacDbiTypeRefData* pTypeRefInfo, DacDbiTypeRefDa public int GetModulePath(ulong vmModule, nint pStrFilename, Interop.BOOL* pResult) { + using Lock.Scope scope = _apiLock.EnterScope(); *pResult = Interop.BOOL.FALSE; int hr = HResults.S_OK; try @@ -374,6 +391,7 @@ public int GetModulePath(ulong vmModule, nint pStrFilename, Interop.BOOL* pResul public int GetMetadata(ulong vmModule, DacDbiTargetBuffer* pTargetBuffer) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -418,6 +436,7 @@ public int GetMetadata(ulong vmModule, DacDbiTargetBuffer* pTargetBuffer) public int GetReadWriteMetadataSize(ulong vmModule, uint* pSize) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -454,6 +473,7 @@ public int GetReadWriteMetadataSize(ulong vmModule, uint* pSize) public int FillReadWriteMetadata(ulong vmModule, byte* pBuffer, uint cbBuffer) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; int blobLength = 0; try @@ -498,6 +518,7 @@ public int FillReadWriteMetadata(ulong vmModule, byte* pBuffer, uint cbBuffer) public int GetSymbolsBuffer(ulong vmModule, DacDbiTargetBuffer* pTargetBuffer, SymbolFormat* pSymbolFormat) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -547,6 +568,7 @@ public int GetSymbolsBuffer(ulong vmModule, DacDbiTargetBuffer* pTargetBuffer, S public int GetModuleData(ulong vmModule, DacDbiModuleInfo* pData) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -597,6 +619,7 @@ public int GetModuleData(ulong vmModule, DacDbiModuleInfo* pData) } public int GetModuleForAssembly(ulong vmAssembly, ulong* pModule, Interop.BOOL* pIsModuleLoaded) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -639,6 +662,7 @@ public int GetModuleForAssembly(ulong vmAssembly, ulong* pModule, Interop.BOOL* public int IsManagedCode(ulong address, Interop.BOOL* pIsManaged) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -672,6 +696,7 @@ public int IsManagedCode(ulong address, Interop.BOOL* pIsManaged) public int GetCompilerFlags(ulong vmAssembly, Interop.BOOL* pfAllowJITOpts, Interop.BOOL* pfEnableEnC) { + using Lock.Scope scope = _apiLock.EnterScope(); *pfAllowJITOpts = Interop.BOOL.FALSE; *pfEnableEnC = Interop.BOOL.FALSE; int hr = HResults.S_OK; @@ -710,6 +735,7 @@ public int GetCompilerFlags(ulong vmAssembly, Interop.BOOL* pfAllowJITOpts, Inte public int SetCompilerFlags(ulong vmAssembly, Interop.BOOL fAllowJitOpts, Interop.BOOL fEnableEnC) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -757,6 +783,7 @@ public int SetCompilerFlags(ulong vmAssembly, Interop.BOOL fAllowJitOpts, Intero public int EnumerateAssembliesInAppDomain(ulong vmAppDomain, delegate* unmanaged fpCallback, nint pUserData) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; #if DEBUG List? cdacAssemblies = _legacy is not null ? new() : null; @@ -818,6 +845,7 @@ public int EnumerateAssembliesInAppDomain(ulong vmAppDomain, delegate* unmanaged public int RequestSyncAtEvent() { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -839,6 +867,7 @@ public int RequestSyncAtEvent() public int SetSendExceptionsOutsideOfJMC(Interop.BOOL sendExceptionsOutsideOfJMC) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -860,6 +889,7 @@ public int SetSendExceptionsOutsideOfJMC(Interop.BOOL sendExceptionsOutsideOfJMC public int MarkDebuggerAttachPending() { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -891,6 +921,7 @@ public int MarkDebuggerAttachPending() public int MarkDebuggerAttached(Interop.BOOL fAttached) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -935,6 +966,7 @@ private static int ExceptionRecordFullSize(int ptrSize) public int Hijack(ulong vmThread, uint dwThreadId, nint pRecord, nint pOriginalContext, uint cbSizeContext, int reason, nint pUserData, ulong* pRemoteContextAddr) { + using Lock.Scope scope = _apiLock.EnterScope(); // Hijack mutates live target state (it writes to the thread's stack and sets the thread context). // It therefore cannot be cross-checked against the legacy implementation in DEBUG builds. // See https://github.com/dotnet/runtime/blob/0d1a20fb14109f277df06ebee3f83c964f9dcc61/src/coreclr/debug/daccess/dacdbiimpl.cpp#L4907 for more algorithm detail. @@ -986,6 +1018,7 @@ public int Hijack(ulong vmThread, uint dwThreadId, nint pRecord, nint pOriginalC public int EnumerateThreads(delegate* unmanaged fpCallback, nint pUserData) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; #if DEBUG List? cdacThreads = _legacy is not null ? new() : null; @@ -1045,6 +1078,7 @@ private static void CollectEnumerationCallback(ulong value, nint pUserData) public int IsThreadMarkedDead(ulong vmThread, Interop.BOOL* pResult) { + using Lock.Scope scope = _apiLock.EnterScope(); *pResult = Interop.BOOL.FALSE; int hr = HResults.S_OK; try @@ -1071,6 +1105,7 @@ public int IsThreadMarkedDead(ulong vmThread, Interop.BOOL* pResult) public int GetThreadHandle(ulong vmThread, void** pRetVal) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -1096,6 +1131,7 @@ public int GetThreadHandle(ulong vmThread, void** pRetVal) public int GetThreadObject(ulong vmThread, ulong* pRetVal) { + using Lock.Scope scope = _apiLock.EnterScope(); *pRetVal = 0; int hr = HResults.S_OK; try @@ -1125,6 +1161,7 @@ public int GetThreadObject(ulong vmThread, ulong* pRetVal) public int GetThreadAllocInfo(ulong vmThread, DacDbiThreadAllocInfo* pThreadAllocInfo) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -1159,6 +1196,7 @@ public int GetThreadAllocInfo(ulong vmThread, DacDbiThreadAllocInfo* pThreadAllo public int SetDebugState(ulong vmThread, int debugState) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -1193,6 +1231,7 @@ public int SetDebugState(ulong vmThread, int debugState) public int HasUnhandledException(ulong vmThread, Interop.BOOL* pResult) { + using Lock.Scope scope = _apiLock.EnterScope(); *pResult = Interop.BOOL.FALSE; int hr = HResults.S_OK; try @@ -1219,6 +1258,7 @@ public int HasUnhandledException(ulong vmThread, Interop.BOOL* pResult) public int GetUserState(ulong vmThread, int* pRetVal) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -1260,6 +1300,7 @@ public int GetUserState(ulong vmThread, int* pRetVal) public int GetPartialUserState(ulong vmThread, CorDebugUserState* pRetVal) { + using Lock.Scope scope = _apiLock.EnterScope(); *pRetVal = default; int hr = HResults.S_OK; try @@ -1305,6 +1346,7 @@ public int GetPartialUserState(ulong vmThread, CorDebugUserState* pRetVal) public int GetConnectionID(ulong vmThread, uint* pRetVal) { + using Lock.Scope scope = _apiLock.EnterScope(); *pRetVal = 0; int hr = HResults.S_OK; #if DEBUG @@ -1322,6 +1364,7 @@ public int GetConnectionID(ulong vmThread, uint* pRetVal) public int GetTaskID(ulong vmThread, ulong* pRetVal) { + using Lock.Scope scope = _apiLock.EnterScope(); *pRetVal = 0; int hr = HResults.S_OK; #if DEBUG @@ -1339,6 +1382,7 @@ public int GetTaskID(ulong vmThread, ulong* pRetVal) public int TryGetVolatileOSThreadID(ulong vmThread, uint* pRetVal) { + using Lock.Scope scope = _apiLock.EnterScope(); *pRetVal = 0; int hr = HResults.S_OK; try @@ -1368,6 +1412,7 @@ public int TryGetVolatileOSThreadID(ulong vmThread, uint* pRetVal) public int GetUniqueThreadID(ulong vmThread, uint* pRetVal) { + using Lock.Scope scope = _apiLock.EnterScope(); *pRetVal = 0; int hr = HResults.S_OK; try @@ -1394,6 +1439,7 @@ public int GetUniqueThreadID(ulong vmThread, uint* pRetVal) public int GetCurrentException(ulong vmThread, ulong* pRetVal) { + using Lock.Scope scope = _apiLock.EnterScope(); *pRetVal = 0; int hr = HResults.S_OK; try @@ -1427,6 +1473,7 @@ public int GetCurrentException(ulong vmThread, ulong* pRetVal) public int GetObjectForCCW(ulong ccwPtr, ulong* pRetVal) { + using Lock.Scope scope = _apiLock.EnterScope(); *pRetVal = 0; int hr = HResults.S_OK; try @@ -1476,6 +1523,7 @@ public int GetObjectForCCW(ulong ccwPtr, ulong* pRetVal) public int GetCurrentCustomDebuggerNotification(ulong vmThread, ulong* pRetVal) { + using Lock.Scope scope = _apiLock.EnterScope(); *pRetVal = 0; int hr = HResults.S_OK; try @@ -1502,6 +1550,7 @@ public int GetCurrentCustomDebuggerNotification(ulong vmThread, ulong* pRetVal) public int GetCurrentAppDomain(ulong* pRetVal) { + using Lock.Scope scope = _apiLock.EnterScope(); *pRetVal = 0; int hr = HResults.S_OK; try @@ -1528,6 +1577,7 @@ public int GetCurrentAppDomain(ulong* pRetVal) public int ResolveAssembly(ulong vmScope, uint tkAssemblyRef, ulong* pRetVal) { + using Lock.Scope scope = _apiLock.EnterScope(); *pRetVal = 0; int hr = HResults.S_OK; try @@ -1571,6 +1621,7 @@ public int GetNativeCodeSequencePointsAndVarInfo( delegate* unmanaged fpSeqPointCallback, nint pUserData) { + using Lock.Scope scope = _apiLock.EnterScope(); // Fully materialize both arrays before invoking any callback to avoid delivering partial results on failure. List cdacVarInfos = new(); List cdacSeqPoints = new(); @@ -1643,6 +1694,7 @@ public int GetNativeCodeSequencePointsAndVarInfo( public int GetManagedStoppedContext(ulong vmThread, ulong* pRetVal) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -1729,6 +1781,7 @@ private string DescribeContextDiff(ReadOnlySpan cdac, ReadOnlySpan l public int CreateStackWalk(ulong vmThread, byte* pInternalContextBuffer, nuint* ppSFIHandle) { + using Lock.Scope scope = _apiLock.EnterScope(); if (ppSFIHandle is null) return HResults.E_POINTER; if (pInternalContextBuffer == null) @@ -1791,6 +1844,7 @@ public int CreateStackWalk(ulong vmThread, byte* pInternalContextBuffer, nuint* public int DeleteStackWalk(nuint ppSFIHandle) { + using Lock.Scope scope = _apiLock.EnterScope(); if (ppSFIHandle == 0) return HResults.S_OK; @@ -1819,6 +1873,7 @@ public int DeleteStackWalk(nuint ppSFIHandle) public int GetStackWalkCurrentContext(nuint pSFIHandle, byte* pContext) { + using Lock.Scope scope = _apiLock.EnterScope(); if (pSFIHandle == 0) return HResults.E_INVALIDARG; if (pContext == null) @@ -1876,6 +1931,7 @@ public int GetStackWalkCurrentContext(nuint pSFIHandle, byte* pContext) public int SetStackWalkCurrentContext(ulong vmThread, nuint pSFIHandle, int flag, byte* pContext) { + using Lock.Scope scope = _apiLock.EnterScope(); if (pSFIHandle == 0) return HResults.E_INVALIDARG; if (pContext == null) @@ -1907,6 +1963,7 @@ public int SetStackWalkCurrentContext(ulong vmThread, nuint pSFIHandle, int flag public int UnwindStackWalkFrame(nuint pSFIHandle, Interop.BOOL* pResult) { + using Lock.Scope scope = _apiLock.EnterScope(); if (pSFIHandle == 0) return HResults.E_INVALIDARG; if (pResult == null) @@ -1959,6 +2016,7 @@ public int UnwindStackWalkFrame(nuint pSFIHandle, Interop.BOOL* pResult) public int CheckContext(ulong vmThread, byte* pContext) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -1991,6 +2049,7 @@ public int CheckContext(ulong vmThread, byte* pContext) public int GetStackWalkCurrentFrameInfo(nuint pSFIHandle, nint pFrameData, FrameType* pRetVal) { + using Lock.Scope scope = _apiLock.EnterScope(); if (pSFIHandle == 0) return HResults.E_INVALIDARG; @@ -2279,6 +2338,7 @@ private static bool IsReportedInternalFrame(IStackWalk stackwalk, Contracts.Stac public int GetCountOfInternalFrames(ulong vmThread, uint* pRetVal) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -2313,6 +2373,7 @@ public int GetCountOfInternalFrames(ulong vmThread, uint* pRetVal) public int EnumerateInternalFrames(ulong vmThread, delegate* unmanaged fpCallback, nint pUserData) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; #if DEBUG List? cdacFrames = _legacy is not null ? new() : null; @@ -2454,6 +2515,7 @@ private static CorDebugInternalFrameType ToCorDebugInternalFrameType(Contracts.I public int GetStackParameterSize(ulong controlPC, uint* pRetVal) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -2499,6 +2561,7 @@ private static nuint TryGetLegacyHandle(nuint pSFIHandle) public int IsLeafFrame(ulong vmThread, byte* pContext, Interop.BOOL* pResult) { + using Lock.Scope scope = _apiLock.EnterScope(); *pResult = Interop.BOOL.FALSE; int hr = HResults.S_OK; try @@ -2536,6 +2599,7 @@ public int IsLeafFrame(ulong vmThread, byte* pContext, Interop.BOOL* pResult) public int GetContext(ulong vmThread, byte* pContextBuffer) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -2576,6 +2640,7 @@ public int GetContext(ulong vmThread, byte* pContextBuffer) public int IsDiagnosticsHiddenOrLCGMethod(ulong vmMethodDesc, int* pRetVal) { + using Lock.Scope scope = _apiLock.EnterScope(); *pRetVal = (int)DynamicMethodType.kNone; int hr = HResults.S_OK; try @@ -2610,6 +2675,7 @@ public int IsDiagnosticsHiddenOrLCGMethod(ulong vmMethodDesc, int* pRetVal) public int GetVarArgSig(ulong VASigCookieAddr, ulong* pArgBase, DacDbiTargetBuffer* pRetVal) { + using Lock.Scope scope = _apiLock.EnterScope(); *pArgBase = 0; *pRetVal = default; int hr = HResults.S_OK; @@ -2646,6 +2712,7 @@ public int GetVarArgSig(ulong VASigCookieAddr, ulong* pArgBase, DacDbiTargetBuff public int RequiresAlign8(ulong thExact, Interop.BOOL* pResult) { + using Lock.Scope scope = _apiLock.EnterScope(); *pResult = Interop.BOOL.FALSE; int hr = HResults.S_OK; RuntimeInfoArchitecture arch = _target.Contracts.RuntimeInfo.GetTargetArchitecture(); @@ -2682,6 +2749,7 @@ public int RequiresAlign8(ulong thExact, Interop.BOOL* pResult) public int ResolveExactGenericArgsToken(uint dwExactGenericArgsTokenIndex, ulong rawToken, ulong* pRetVal) { + using Lock.Scope scope = _apiLock.EnterScope(); *pRetVal = 0; int hr = HResults.S_OK; try @@ -2734,6 +2802,7 @@ public int ResolveExactGenericArgsToken(uint dwExactGenericArgsTokenIndex, ulong public int GetILCodeAndSig(ulong vmAssembly, uint functionToken, DacDbiTargetBuffer* pTargetBuffer, uint* pLocalSigToken) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -2806,6 +2875,7 @@ public int GetILCodeAndSig(ulong vmAssembly, uint functionToken, DacDbiTargetBuf public int GetNativeCodeInfo(ulong vmAssembly, uint functionToken, NativeCodeFunctionData* pCodeInfo) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -2871,6 +2941,7 @@ public int GetNativeCodeInfo(ulong vmAssembly, uint functionToken, NativeCodeFun public int GetNativeCodeInfoForAddr(ulong codeAddress, NativeCodeFunctionData* pCodeInfo, ulong* pVmModule, uint* pFunctionToken) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -2991,6 +3062,7 @@ private static void ValidateNativeCodeFunctionData(NativeCodeFunctionData codeIn public int IsValueType(ulong vmTypeHandle, Interop.BOOL* pResult) { + using Lock.Scope scope = _apiLock.EnterScope(); *pResult = Interop.BOOL.FALSE; int hr = HResults.S_OK; try @@ -3018,6 +3090,7 @@ public int IsValueType(ulong vmTypeHandle, Interop.BOOL* pResult) public int HasTypeParams(ulong vmTypeHandle, Interop.BOOL* pResult) { + using Lock.Scope scope = _apiLock.EnterScope(); *pResult = Interop.BOOL.FALSE; int hr = HResults.S_OK; try @@ -3045,6 +3118,7 @@ public int HasTypeParams(ulong vmTypeHandle, Interop.BOOL* pResult) public int EnumerateClassFields(ulong thExact, nuint* pObjectSize, delegate* unmanaged fpCallback, nint pUserData) { + using Lock.Scope scope = _apiLock.EnterScope(); if (pObjectSize != null) *pObjectSize = 0; @@ -3098,6 +3172,7 @@ public int EnumerateClassFields(ulong thExact, nuint* pObjectSize, delegate* unm public int EnumerateInstantiationFields(ulong vmAssembly, ulong vmThExact, ulong vmThApprox, nuint* pObjectSize, delegate* unmanaged fpCallback, nint pUserData) { + using Lock.Scope scope = _apiLock.EnterScope(); if (pObjectSize != null) *pObjectSize = 0; @@ -3318,6 +3393,7 @@ private static void AssertFieldListsEqual(List? cdacFields, List fpCallback, nint pUserData) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; #if DEBUG List entries = new(); @@ -3798,6 +3879,7 @@ public int EnumerateMethodDescParams(ulong vmMethodDesc, ulong genericsToken, ui public int GetThreadStaticAddress(ulong vmField, ulong vmRuntimeThread, ulong* pRetVal) { + using Lock.Scope scope = _apiLock.EnterScope(); *pRetVal = 0; int hr = HResults.S_OK; try @@ -3831,6 +3913,7 @@ public int GetThreadStaticAddress(ulong vmField, ulong vmRuntimeThread, ulong* p public int GetCollectibleTypeStaticAddress(ulong vmField, ulong* pRetVal) { + using Lock.Scope scope = _apiLock.EnterScope(); *pRetVal = 0; int hr = HResults.S_OK; try @@ -3858,6 +3941,7 @@ public int GetCollectibleTypeStaticAddress(ulong vmField, ulong* pRetVal) public int GetEnCHangingFieldInfo(EnCHangingFieldInfo* pEnCFieldInfo, FieldData* pFieldData) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -3988,6 +4072,7 @@ internal ITypeHandle LookupTypeDefOrRefInAssembly(ulong vmAssembly, uint metadat public int EnumerateTypeHandleParams(ulong vmTypeHandle, delegate* unmanaged fpCallback, nint pUserData) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; #if DEBUG List entries = new(); @@ -4069,6 +4154,7 @@ private static string FormatExpandedTypeData(DebuggerIPCE_ExpandedTypeData e) => public int GetSimpleType(int simpleType, uint* pMetadataToken, ulong* pVmModule) { + using Lock.Scope scope = _apiLock.EnterScope(); Debug.Assert(pVmModule != null); *pVmModule = 0; int hr = HResults.S_OK; @@ -4109,6 +4195,7 @@ public int GetSimpleType(int simpleType, uint* pMetadataToken, ulong* pVmModule) public int IsExceptionObject(ulong vmObject, Interop.BOOL* pResult) { + using Lock.Scope scope = _apiLock.EnterScope(); *pResult = Interop.BOOL.FALSE; int hr = HResults.S_OK; try @@ -4163,6 +4250,7 @@ private static void EnumerateStackFramesFromExceptionDebugCallback(ulong vmAppDo public int EnumerateStackFramesFromException(ulong vmObject, delegate* unmanaged fpCallback, nint pUserData) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; #if DEBUG List<(ulong VmAppDomain, ulong VmAssembly, ulong Ip, uint MethodDef, Interop.BOOL IsLastForeignExceptionFrame)> frames = new(); @@ -4215,6 +4303,7 @@ static string FormatFrame((ulong VmAppDomain, ulong VmAssembly, ulong Ip, uint M public int IsRcw(ulong vmObject, Interop.BOOL* pResult) { + using Lock.Scope scope = _apiLock.EnterScope(); *pResult = Interop.BOOL.FALSE; int hr = HResults.S_OK; try @@ -4256,6 +4345,7 @@ private static void EnumerateRcwCachedInterfacePointersDebugCallback(ulong itfPt public int EnumerateRcwCachedInterfacePointers(ulong vmObject, delegate* unmanaged fpCallback, nint pUserData) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; List itfPtrs = new(); try @@ -4305,6 +4395,7 @@ public int EnumerateRcwCachedInterfacePointers(ulong vmObject, delegate* unmanag public int GetTypedByRefInfo(ulong pTypedByRef, ulong* pObjRef, DebuggerIPCE_BasicTypeData* pTypedByRefType) { + using Lock.Scope scope = _apiLock.EnterScope(); *pObjRef = 0; *pTypedByRefType = default; int hr = HResults.S_OK; @@ -4345,6 +4436,7 @@ public int GetTypedByRefInfo(ulong pTypedByRef, ulong* pObjRef, DebuggerIPCE_Bas public int GetStringData(ulong objectAddress, uint* pLength, uint* pOffsetToStringBase) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -4381,6 +4473,7 @@ public int GetStringData(ulong objectAddress, uint* pLength, uint* pOffsetToStri public int GetArrayData(ulong objectAddress, Interop.BOOL* pIsValidArray, DacDbiArrayInfo* pArrayInfo) { + using Lock.Scope scope = _apiLock.EnterScope(); *pIsValidArray = Interop.BOOL.FALSE; *pArrayInfo = default; int hr = HResults.S_OK; @@ -4443,6 +4536,7 @@ public int GetArrayData(ulong objectAddress, Interop.BOOL* pIsValidArray, DacDbi public int GetBasicObjectInfo(ulong objectAddress, Interop.BOOL* pIsValidRef, uint* pObjSize, uint* pObjOffsetToVars, DebuggerIPCE_ExpandedTypeData* pObjTypeData) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -4506,6 +4600,7 @@ public int GetBasicObjectInfo(ulong objectAddress, Interop.BOOL* pIsValidRef, ui public int GetDebuggerControlBlockAddress(ulong* pRetVal) { + using Lock.Scope scope = _apiLock.EnterScope(); *pRetVal = 0; int hr = HResults.S_OK; try @@ -4531,6 +4626,7 @@ public int GetDebuggerControlBlockAddress(ulong* pRetVal) public int GetObjectFromRefPtr(ulong ptr, ulong* pRetVal) { + using Lock.Scope scope = _apiLock.EnterScope(); *pRetVal = 0; int hr = HResults.S_OK; try @@ -4556,6 +4652,7 @@ public int GetObjectFromRefPtr(ulong ptr, ulong* pRetVal) public int GetObject(ulong ptr, ulong* pRetVal) { + using Lock.Scope scope = _apiLock.EnterScope(); // Native GetObject wraps the address directly in a VMPTR_Object without dereferencing. *pRetVal = ptr; int hr = HResults.S_OK; @@ -4574,6 +4671,7 @@ public int GetObject(ulong ptr, ulong* pRetVal) public int GetVmObjectHandle(ulong handleAddress, ulong* pRetVal) { + using Lock.Scope scope = _apiLock.EnterScope(); *pRetVal = handleAddress; int hr = HResults.S_OK; #if DEBUG @@ -4591,6 +4689,7 @@ public int GetVmObjectHandle(ulong handleAddress, ulong* pRetVal) public int IsVmObjectHandleValid(ulong vmHandle, Interop.BOOL* pResult) { + using Lock.Scope scope = _apiLock.EnterScope(); *pResult = Interop.BOOL.FALSE; int hr = HResults.S_OK; try @@ -4617,6 +4716,7 @@ public int IsVmObjectHandleValid(ulong vmHandle, Interop.BOOL* pResult) public int GetHandleAddressFromVmHandle(ulong vmHandle, ulong* pRetVal) { + using Lock.Scope scope = _apiLock.EnterScope(); *pRetVal = vmHandle; int hr = HResults.S_OK; #if DEBUG @@ -4634,6 +4734,7 @@ public int GetHandleAddressFromVmHandle(ulong vmHandle, ulong* pRetVal) public int GetThreadOwningMonitorLock(ulong vmObject, DacDbiMonitorLockInfo* pRetVal) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; *pRetVal = default; try @@ -4681,10 +4782,16 @@ public int GetThreadOwningMonitorLock(ulong vmObject, DacDbiMonitorLockInfo* pRe return hr; } - public int EnumerateMonitorEventWaitList(ulong vmObject, nint fpCallback, nint pUserData) => HResults.E_NOTIMPL; + public int EnumerateMonitorEventWaitList(ulong vmObject, nint fpCallback, nint pUserData) + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } public int GetAttachStateFlags(int* pRetVal) { + using Lock.Scope scope = _apiLock.EnterScope(); *pRetVal = 0; int hr = HResults.S_OK; try @@ -4712,6 +4819,7 @@ public int GetAttachStateFlags(int* pRetVal) public int GetModuleMetaDataFileInfo(ulong vmModule, uint* dwTimeStamp, uint* dwImageSize, nint pStrFilename, Interop.BOOL* pResult) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; string path = string.Empty; try @@ -4778,6 +4886,7 @@ public int GetModuleMetaDataFileInfo(ulong vmModule, uint* dwTimeStamp, uint* dw public int IsThreadSuspendedOrHijacked(ulong vmThread, Interop.BOOL* pResult) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -4809,6 +4918,7 @@ public int IsThreadSuspendedOrHijacked(ulong vmThread, Interop.BOOL* pResult) public int CreateHeapWalk(nuint* pHandle) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; if (pHandle is null) return HResults.E_POINTER; @@ -4842,6 +4952,7 @@ public int CreateHeapWalk(nuint* pHandle) public int DeleteHeapWalk(nuint handle) { + using Lock.Scope scope = _apiLock.EnterScope(); if (handle == 0) return HResults.S_OK; @@ -4873,6 +4984,7 @@ public int DeleteHeapWalk(nuint handle) // Should be called repeatedly until it returns S_FALSE. E_FAIL is not fatal, just indicates partial heap corruption. public int WalkHeap(nuint handle, uint count, COR_HEAPOBJECT* objects, uint* fetched) { + using Lock.Scope scope = _apiLock.EnterScope(); if (fetched is null) return HResults.E_INVALIDARG; *fetched = 0; @@ -4966,6 +5078,7 @@ private static void EnumerateHeapSegmentsDebugCallback(ulong start, ulong end, i public int EnumerateHeapSegments(delegate* unmanaged fpCallback, nint pUserData) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; List<(ulong Start, ulong End, int Generation, uint Heap)> segments = new(); try @@ -5075,6 +5188,7 @@ private static IEnumerable EnumerateHeaps(IGC gc, bool isWorkstation public int IsValidObject(ulong obj, Interop.BOOL* pResult) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; Interop.BOOL isValid = Interop.BOOL.FALSE; @@ -5116,6 +5230,7 @@ public int IsValidObject(ulong obj, Interop.BOOL* pResult) public int CreateRefWalk(nuint* pHandle, Interop.BOOL walkStacks, CorGCReferenceType handleWalkMask) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; RefWalk? walk = null; try @@ -5148,6 +5263,7 @@ public int CreateRefWalk(nuint* pHandle, Interop.BOOL walkStacks, CorGCReference public int DeleteRefWalk(nuint handle) { + using Lock.Scope scope = _apiLock.EnterScope(); if (handle == 0) return HResults.S_OK; @@ -5179,6 +5295,7 @@ public int DeleteRefWalk(nuint handle) // Should be called repeatedly until it returns S_FALSE. public int WalkRefs(nuint handle, uint count, [In, MarshalUsing(CountElementName = "count"), Out] DacGcReference[] refs, uint* pFetched) { + using Lock.Scope scope = _apiLock.EnterScope(); RefWalk walk; try { @@ -5265,6 +5382,7 @@ static uint CountHandlePrefix(DacGcReference[] buffer, uint length) public int GetTypeID(ulong obj, COR_TYPEID* pType) { + using Lock.Scope scope = _apiLock.EnterScope(); *pType = default; int hr = HResults.S_OK; try @@ -5297,6 +5415,7 @@ public int GetTypeID(ulong obj, COR_TYPEID* pType) public int GetTypeIDForType(ulong vmTypeHandle, COR_TYPEID* pId) { + using Lock.Scope scope = _apiLock.EnterScope(); *pId = default; int hr = HResults.S_OK; try @@ -5328,6 +5447,7 @@ public int GetTypeIDForType(ulong vmTypeHandle, COR_TYPEID* pId) public int GetObjectFields(ulong id, uint celt, COR_FIELD* layout, uint* pceltFetched) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; uint cFields = 0; try @@ -5480,6 +5600,7 @@ public int GetObjectFields(ulong id, uint celt, COR_FIELD* layout, uint* pceltFe public int GetTypeLayout(ulong id, COR_TYPE_LAYOUT* pLayout) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -5537,6 +5658,7 @@ public int GetTypeLayout(ulong id, COR_TYPE_LAYOUT* pLayout) public int GetArrayLayout(ulong id, COR_ARRAY_LAYOUT* pLayout) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -5613,6 +5735,7 @@ public int GetArrayLayout(ulong id, COR_ARRAY_LAYOUT* pLayout) public int GetGCHeapInformation(COR_HEAPINFO* pHeapInfo) { + using Lock.Scope scope = _apiLock.EnterScope(); *pHeapInfo = default; int hr = HResults.S_OK; try @@ -5654,6 +5777,7 @@ public int GetGCHeapInformation(COR_HEAPINFO* pHeapInfo) public int HasReadWriteMetadata(ulong vmPEAssembly, Interop.BOOL* pHasReadWriteMetadata) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -5683,6 +5807,7 @@ public int HasReadWriteMetadata(ulong vmPEAssembly, Interop.BOOL* pHasReadWriteM public int AreOptimizationsDisabled(ulong vmModule, uint methodTk, Interop.BOOL* pOptimizationsDisabled) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -5738,6 +5863,7 @@ public int AreOptimizationsDisabled(ulong vmModule, uint methodTk, Interop.BOOL* public int GetActiveRejitILCodeVersionNode(ulong vmModule, uint methodTk, ulong* pVmILCodeVersionNode) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -5795,6 +5921,7 @@ public int GetActiveRejitILCodeVersionNode(ulong vmModule, uint methodTk, ulong* public int GetEnCILCodeAndSig(ulong vmModule, uint methodTk, nuint enCVersion, DacDbiTargetBuffer* pCodeInfo, uint* pLocalSigToken) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -5866,6 +5993,7 @@ public int GetEnCILCodeAndSig(ulong vmModule, uint methodTk, nuint enCVersion, D public int GetNativeCodeVersionNode(ulong vmMethod, ulong codeStartAddress, ulong* pVmNativeCodeVersionNode) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -5904,6 +6032,7 @@ public int GetNativeCodeVersionNode(ulong vmMethod, ulong codeStartAddress, ulon public int GetILCodeVersionNode(ulong vmNativeCodeVersionNode, ulong* pVmILCodeVersionNode) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -5941,6 +6070,7 @@ public int GetILCodeVersionNode(ulong vmNativeCodeVersionNode, ulong* pVmILCodeV public int GetILCodeVersionNodeData(ulong ilCodeVersionNode, DacDbiSharedReJitInfo* pData) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -5990,6 +6120,7 @@ public int GetILCodeVersionNodeData(ulong ilCodeVersionNode, DacDbiSharedReJitIn public int EnableGCNotificationEvents(Interop.BOOL fEnable) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -6011,6 +6142,7 @@ public int EnableGCNotificationEvents(Interop.BOOL fEnable) public int IsDelegate(ulong vmObject, Interop.BOOL* pResult) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -6042,6 +6174,7 @@ public int IsDelegate(ulong vmObject, Interop.BOOL* pResult) public int GetDelegateFunctionData(ulong delegateObject, ulong* ppFunctionAssembly, uint* pMethodDef) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -6102,6 +6235,7 @@ public int GetDelegateFunctionData(ulong delegateObject, ulong* ppFunctionAssemb public int GetDelegateTargetObject(ulong delegateObject, ulong* ppTargetObj) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -6145,6 +6279,7 @@ private bool IsDelegateHelper(ulong vmObject) public int IsModuleMapped(ulong pModule, Interop.BOOL* isModuleMapped) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_FALSE; try { @@ -6182,6 +6317,7 @@ public int IsModuleMapped(ulong pModule, Interop.BOOL* isModuleMapped) public int MetadataUpdatesApplied(Interop.BOOL* pResult) { + using Lock.Scope scope = _apiLock.EnterScope(); *pResult = Interop.BOOL.FALSE; int hr = HResults.S_OK; try @@ -6209,6 +6345,7 @@ public int MetadataUpdatesApplied(Interop.BOOL* pResult) public int GetAssemblyFromModule(ulong vmModule, ulong* pVmAssembly) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -6244,6 +6381,7 @@ public int GetAssemblyFromModule(ulong vmModule, ulong* pVmAssembly) public int ParseContinuation(ulong continuationAddress, ulong* pDiagnosticIP, ulong* pNextContinuation, uint* pState) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -6295,6 +6433,7 @@ private static void EnumerateAsyncLocalsDebugCallback(AsyncLocalData* pLocal, ni public int EnumerateAsyncLocals(ulong vmMethod, ulong codeAddr, uint state, delegate* unmanaged fpCallback, nint pUserData) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; #if DEBUG List locals = new(); @@ -6380,6 +6519,7 @@ public int EnumerateAsyncLocals(ulong vmMethod, ulong codeAddr, uint state, public int GetGenericArgTokenIndex(ulong vmMethod, uint* pIndex) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { diff --git a/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/MetaDataImportImpl.cs b/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/MetaDataImportImpl.cs index 214bdc569959..a062ed7aa881 100644 --- a/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/MetaDataImportImpl.cs +++ b/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/MetaDataImportImpl.cs @@ -9,6 +9,7 @@ using System.Reflection.Metadata.Ecma335; using System.Runtime.InteropServices; using System.Runtime.InteropServices.Marshalling; +using System.Threading; using Microsoft.Diagnostics.DataContractReader.Contracts; namespace Microsoft.Diagnostics.DataContractReader.Legacy; @@ -16,6 +17,7 @@ namespace Microsoft.Diagnostics.DataContractReader.Legacy; [GeneratedComClass] internal sealed unsafe partial class MetaDataImportImpl : ICustomQueryInterface, IMetaDataImport2, IMetaDataAssemblyImport { + private readonly Lock _apiLock; private readonly MetadataReader _reader; private readonly IMetaDataImport? _legacyImport; private readonly IMetaDataImport2? _legacyImport2; @@ -30,8 +32,9 @@ internal sealed unsafe partial class MetaDataImportImpl : ICustomQueryInterface, // ConcurrentDictionary is used because COM objects may be called from multiple threads. private readonly ConcurrentDictionary _cdacEnumHandles = new(); - public MetaDataImportImpl(MetadataReader reader, IMetaDataImport? legacyImport = null) + public MetaDataImportImpl(MetadataReader reader, IMetaDataImport? legacyImport, Lock apiLock) { + _apiLock = apiLock; _reader = reader; _legacyImport = legacyImport; _legacyImport2 = legacyImport as IMetaDataImport2; @@ -40,6 +43,7 @@ public MetaDataImportImpl(MetadataReader reader, IMetaDataImport? legacyImport = CustomQueryInterfaceResult ICustomQueryInterface.GetInterface(ref Guid iid, out nint ppv) { + using Lock.Scope scope = _apiLock.EnterScope(); ppv = default; if (iid == typeof(IMetaDataImport).GUID) @@ -108,6 +112,7 @@ private int FillEnum(nint* phEnum, List tokens, uint* rTokens, uint cMax, void IMetaDataImport.CloseEnum(nint hEnum) { + using Lock.Scope scope = _apiLock.EnterScope(); if (hEnum == 0) return; @@ -124,6 +129,7 @@ void IMetaDataImport.CloseEnum(nint hEnum) int IMetaDataImport.CountEnum(nint hEnum, uint* pulCount) { + using Lock.Scope scope = _apiLock.EnterScope(); if (hEnum == 0) { if (pulCount is not null) @@ -144,6 +150,7 @@ int IMetaDataImport.CountEnum(nint hEnum, uint* pulCount) int IMetaDataImport.ResetEnum(nint hEnum, uint ulPos) { + using Lock.Scope scope = _apiLock.EnterScope(); if (hEnum == 0) return HResults.S_OK; @@ -159,6 +166,7 @@ int IMetaDataImport.ResetEnum(nint hEnum, uint ulPos) int IMetaDataImport.EnumTypeDefs(nint* phEnum, uint* rTypeDefs, uint cMax, uint* pcTypeDefs) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; List? tokens = null; try @@ -205,6 +213,7 @@ int IMetaDataImport.EnumTypeDefs(nint* phEnum, uint* rTypeDefs, uint cMax, uint* int IMetaDataImport.EnumInterfaceImpls(nint* phEnum, uint td, uint* rImpls, uint cMax, uint* pcImpls) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; List? tokens = null; try @@ -252,13 +261,22 @@ int IMetaDataImport.EnumInterfaceImpls(nint* phEnum, uint td, uint* rImpls, uint } int IMetaDataImport.EnumTypeRefs(nint* phEnum, uint* rTypeRefs, uint cMax, uint* pcTypeRefs) - => _legacyImport is not null ? _legacyImport.EnumTypeRefs(phEnum, rTypeRefs, cMax, pcTypeRefs) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport is not null ? _legacyImport.EnumTypeRefs(phEnum, rTypeRefs, cMax, pcTypeRefs) : HResults.E_NOTIMPL; + } int IMetaDataImport.EnumMembers(nint* phEnum, uint cl, uint* rMembers, uint cMax, uint* pcTokens) - => _legacyImport is not null ? _legacyImport.EnumMembers(phEnum, cl, rMembers, cMax, pcTokens) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport is not null ? _legacyImport.EnumMembers(phEnum, cl, rMembers, cMax, pcTokens) : HResults.E_NOTIMPL; + } int IMetaDataImport.EnumMethods(nint* phEnum, uint cl, uint* rMethods, uint cMax, uint* pcTokens) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; List? tokens = null; try @@ -307,6 +325,7 @@ int IMetaDataImport.EnumMethods(nint* phEnum, uint cl, uint* rMethods, uint cMax int IMetaDataImport.EnumFields(nint* phEnum, uint cl, uint* rFields, uint cMax, uint* pcTokens) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; List? tokens = null; try @@ -354,10 +373,15 @@ int IMetaDataImport.EnumFields(nint* phEnum, uint cl, uint* rFields, uint cMax, } int IMetaDataImport.EnumCustomAttributes(nint* phEnum, uint tk, uint tkType, uint* rCustomAttributes, uint cMax, uint* pcCustomAttributes) - => _legacyImport is not null ? _legacyImport.EnumCustomAttributes(phEnum, tk, tkType, rCustomAttributes, cMax, pcCustomAttributes) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport is not null ? _legacyImport.EnumCustomAttributes(phEnum, tk, tkType, rCustomAttributes, cMax, pcCustomAttributes) : HResults.E_NOTIMPL; + } int IMetaDataImport2.EnumGenericParams(nint* phEnum, uint tk, uint* rGenericParams, uint cMax, uint* pcGenericParams) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; List? tokens = null; try @@ -416,6 +440,7 @@ int IMetaDataImport2.EnumGenericParams(nint* phEnum, uint tk, uint* rGenericPara int IMetaDataImport.GetTypeDefProps(uint td, char* szTypeDef, uint cchTypeDef, uint* pchTypeDef, uint* pdwTypeDefFlags, uint* ptkExtends) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -470,6 +495,7 @@ int IMetaDataImport.GetTypeDefProps(uint td, char* szTypeDef, uint cchTypeDef, u int IMetaDataImport.GetTypeRefProps(uint tr, uint* ptkResolutionScope, char* szName, uint cchName, uint* pchName) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -481,8 +507,8 @@ int IMetaDataImport.GetTypeRefProps(uint tr, uint* ptkResolutionScope, char* szN if (ptkResolutionScope is not null) { - EntityHandle scope = typeRef.ResolutionScope; - *ptkResolutionScope = scope.IsNil ? 0 : (uint)MetadataTokens.GetToken(scope); + EntityHandle resolutionScope = typeRef.ResolutionScope; + *ptkResolutionScope = resolutionScope.IsNil ? 0 : (uint)MetadataTokens.GetToken(resolutionScope); } hr = truncated ? CldbHResults.CLDB_S_TRUNCATION : HResults.S_OK; @@ -520,6 +546,7 @@ int IMetaDataImport.GetTypeRefProps(uint tr, uint* ptkResolutionScope, char* szN int IMetaDataImport.GetMethodProps(uint mb, uint* pClass, char* szMethod, uint cchMethod, uint* pchMethod, uint* pdwAttr, byte** ppvSigBlob, uint* pcbSigBlob, uint* pulCodeRVA, uint* pdwImplFlags) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -598,6 +625,7 @@ int IMetaDataImport.GetFieldProps(uint mb, uint* pClass, char* szField, uint cch uint* pdwAttr, byte** ppvSigBlob, uint* pcbSigBlob, uint* pdwCPlusTypeFlag, void** ppValue, uint* pcchValue) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -696,6 +724,7 @@ int IMetaDataImport.GetMemberProps(uint mb, uint* pClass, char* szMember, uint c uint* pdwAttr, byte** ppvSigBlob, uint* pcbSigBlob, uint* pulCodeRVA, uint* pdwImplFlags, uint* pdwCPlusTypeFlag, void** ppValue, uint* pcchValue) { + using Lock.Scope scope = _apiLock.EnterScope(); uint tableIndex = mb >> 24; if (tableIndex == 0x06) // MethodDef { @@ -724,6 +753,7 @@ int IMetaDataImport.GetMemberProps(uint mb, uint* pClass, char* szMember, uint c int IMetaDataImport.GetInterfaceImplProps(uint iiImpl, uint* pClass, uint* ptkIface) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -767,6 +797,7 @@ int IMetaDataImport.GetInterfaceImplProps(uint iiImpl, uint* pClass, uint* ptkIf int IMetaDataImport.GetNestedClassProps(uint tdNestedClass, uint* ptdEnclosingClass) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -800,6 +831,7 @@ int IMetaDataImport.GetNestedClassProps(uint tdNestedClass, uint* ptdEnclosingCl int IMetaDataImport2.GetGenericParamProps(uint gp, uint* pulParamSeq, uint* pdwParamFlags, uint* ptOwner, uint* reserved, char* wzname, uint cchName, uint* pchName) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -859,6 +891,7 @@ int IMetaDataImport2.GetGenericParamProps(uint gp, uint* pulParamSeq, uint* pdwP int IMetaDataImport.GetRVA(uint tk, uint* pulCodeRVA, uint* pdwImplFlags) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -911,6 +944,7 @@ int IMetaDataImport.GetRVA(uint tk, uint* pulCodeRVA, uint* pdwImplFlags) int IMetaDataImport.GetSigFromToken(uint mdSig, byte** ppvSig, uint* pcbSig) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -951,6 +985,7 @@ int IMetaDataImport.GetSigFromToken(uint mdSig, byte** ppvSig, uint* pcbSig) int IMetaDataImport.GetCustomAttributeByName(uint tkObj, char* szName, void** ppData, uint* pcbData) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -1008,6 +1043,7 @@ int IMetaDataImport.GetCustomAttributeByName(uint tkObj, char* szName, void** pp int IMetaDataImport.IsValidToken(uint tk) { + using Lock.Scope scope = _apiLock.EnterScope(); int rid = GetRID(tk); int tokenType = (int)(tk >> 24); @@ -1056,6 +1092,7 @@ private string GetCustomAttributeTypeName(EntityHandle constructor) int IMetaDataImport.FindTypeDefByName(char* szTypeDef, uint tkEnclosingClass, uint* ptd) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -1109,50 +1146,107 @@ int IMetaDataImport.FindTypeDefByName(char* szTypeDef, uint tkEnclosingClass, ui } int IMetaDataImport.GetScopeProps(char* szName, uint cchName, uint* pchName, Guid* pmvid) - => _legacyImport is not null ? _legacyImport.GetScopeProps(szName, cchName, pchName, pmvid) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport is not null ? _legacyImport.GetScopeProps(szName, cchName, pchName, pmvid) : HResults.E_NOTIMPL; + } int IMetaDataImport.GetModuleFromScope(uint* pmd) - => _legacyImport is not null ? _legacyImport.GetModuleFromScope(pmd) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport is not null ? _legacyImport.GetModuleFromScope(pmd) : HResults.E_NOTIMPL; + } int IMetaDataImport.ResolveTypeRef(uint tr, Guid* riid, void** ppIScope, uint* ptd) - => _legacyImport is not null ? _legacyImport.ResolveTypeRef(tr, riid, ppIScope, ptd) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport is not null ? _legacyImport.ResolveTypeRef(tr, riid, ppIScope, ptd) : HResults.E_NOTIMPL; + } int IMetaDataImport.EnumMembersWithName(nint* phEnum, uint cl, char* szName, uint* rMembers, uint cMax, uint* pcTokens) - => _legacyImport is not null ? _legacyImport.EnumMembersWithName(phEnum, cl, szName, rMembers, cMax, pcTokens) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport is not null ? _legacyImport.EnumMembersWithName(phEnum, cl, szName, rMembers, cMax, pcTokens) : HResults.E_NOTIMPL; + } int IMetaDataImport.EnumMethodsWithName(nint* phEnum, uint cl, char* szName, uint* rMethods, uint cMax, uint* pcTokens) - => _legacyImport is not null ? _legacyImport.EnumMethodsWithName(phEnum, cl, szName, rMethods, cMax, pcTokens) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport is not null ? _legacyImport.EnumMethodsWithName(phEnum, cl, szName, rMethods, cMax, pcTokens) : HResults.E_NOTIMPL; + } int IMetaDataImport.EnumFieldsWithName(nint* phEnum, uint cl, char* szName, uint* rFields, uint cMax, uint* pcTokens) - => _legacyImport is not null ? _legacyImport.EnumFieldsWithName(phEnum, cl, szName, rFields, cMax, pcTokens) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport is not null ? _legacyImport.EnumFieldsWithName(phEnum, cl, szName, rFields, cMax, pcTokens) : HResults.E_NOTIMPL; + } int IMetaDataImport.EnumParams(nint* phEnum, uint mb, uint* rParams, uint cMax, uint* pcTokens) - => _legacyImport is not null ? _legacyImport.EnumParams(phEnum, mb, rParams, cMax, pcTokens) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport is not null ? _legacyImport.EnumParams(phEnum, mb, rParams, cMax, pcTokens) : HResults.E_NOTIMPL; + } int IMetaDataImport.EnumMemberRefs(nint* phEnum, uint tkParent, uint* rMemberRefs, uint cMax, uint* pcTokens) - => _legacyImport is not null ? _legacyImport.EnumMemberRefs(phEnum, tkParent, rMemberRefs, cMax, pcTokens) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport is not null ? _legacyImport.EnumMemberRefs(phEnum, tkParent, rMemberRefs, cMax, pcTokens) : HResults.E_NOTIMPL; + } int IMetaDataImport.EnumMethodImpls(nint* phEnum, uint td, uint* rMethodBody, uint* rMethodDecl, uint cMax, uint* pcTokens) - => _legacyImport is not null ? _legacyImport.EnumMethodImpls(phEnum, td, rMethodBody, rMethodDecl, cMax, pcTokens) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport is not null ? _legacyImport.EnumMethodImpls(phEnum, td, rMethodBody, rMethodDecl, cMax, pcTokens) : HResults.E_NOTIMPL; + } int IMetaDataImport.EnumPermissionSets(nint* phEnum, uint tk, uint dwActions, uint* rPermission, uint cMax, uint* pcTokens) - => _legacyImport is not null ? _legacyImport.EnumPermissionSets(phEnum, tk, dwActions, rPermission, cMax, pcTokens) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport is not null ? _legacyImport.EnumPermissionSets(phEnum, tk, dwActions, rPermission, cMax, pcTokens) : HResults.E_NOTIMPL; + } int IMetaDataImport.FindMember(uint td, char* szName, byte* pvSigBlob, uint cbSigBlob, uint* pmb) - => _legacyImport is not null ? _legacyImport.FindMember(td, szName, pvSigBlob, cbSigBlob, pmb) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport is not null ? _legacyImport.FindMember(td, szName, pvSigBlob, cbSigBlob, pmb) : HResults.E_NOTIMPL; + } int IMetaDataImport.FindMethod(uint td, char* szName, byte* pvSigBlob, uint cbSigBlob, uint* pmb) - => _legacyImport is not null ? _legacyImport.FindMethod(td, szName, pvSigBlob, cbSigBlob, pmb) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport is not null ? _legacyImport.FindMethod(td, szName, pvSigBlob, cbSigBlob, pmb) : HResults.E_NOTIMPL; + } int IMetaDataImport.FindField(uint td, char* szName, byte* pvSigBlob, uint cbSigBlob, uint* pmb) - => _legacyImport is not null ? _legacyImport.FindField(td, szName, pvSigBlob, cbSigBlob, pmb) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport is not null ? _legacyImport.FindField(td, szName, pvSigBlob, cbSigBlob, pmb) : HResults.E_NOTIMPL; + } int IMetaDataImport.FindMemberRef(uint td, char* szName, byte* pvSigBlob, uint cbSigBlob, uint* pmr) - => _legacyImport is not null ? _legacyImport.FindMemberRef(td, szName, pvSigBlob, cbSigBlob, pmr) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport is not null ? _legacyImport.FindMemberRef(td, szName, pvSigBlob, cbSigBlob, pmr) : HResults.E_NOTIMPL; + } int IMetaDataImport.GetMemberRefProps(uint mr, uint* ptk, char* szMember, uint cchMember, uint* pchMember, byte** ppvSigBlob, uint* pbSig) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -1212,24 +1306,45 @@ int IMetaDataImport.GetMemberRefProps(uint mr, uint* ptk, char* szMember, uint c } int IMetaDataImport.EnumProperties(nint* phEnum, uint td, uint* rProperties, uint cMax, uint* pcProperties) - => _legacyImport is not null ? _legacyImport.EnumProperties(phEnum, td, rProperties, cMax, pcProperties) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport is not null ? _legacyImport.EnumProperties(phEnum, td, rProperties, cMax, pcProperties) : HResults.E_NOTIMPL; + } int IMetaDataImport.EnumEvents(nint* phEnum, uint td, uint* rEvents, uint cMax, uint* pcEvents) - => _legacyImport is not null ? _legacyImport.EnumEvents(phEnum, td, rEvents, cMax, pcEvents) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport is not null ? _legacyImport.EnumEvents(phEnum, td, rEvents, cMax, pcEvents) : HResults.E_NOTIMPL; + } int IMetaDataImport.GetEventProps(uint ev, uint* pClass, char* szEvent, uint cchEvent, uint* pchEvent, uint* pdwEventFlags, uint* ptkEventType, uint* pmdAddOn, uint* pmdRemoveOn, uint* pmdFire, uint* rmdOtherMethod, uint cMax, uint* pcOtherMethod) - => _legacyImport is not null ? _legacyImport.GetEventProps(ev, pClass, szEvent, cchEvent, pchEvent, pdwEventFlags, ptkEventType, pmdAddOn, pmdRemoveOn, pmdFire, rmdOtherMethod, cMax, pcOtherMethod) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport is not null ? _legacyImport.GetEventProps(ev, pClass, szEvent, cchEvent, pchEvent, pdwEventFlags, ptkEventType, pmdAddOn, pmdRemoveOn, pmdFire, rmdOtherMethod, cMax, pcOtherMethod) : HResults.E_NOTIMPL; + } int IMetaDataImport.EnumMethodSemantics(nint* phEnum, uint mb, uint* rEventProp, uint cMax, uint* pcEventProp) - => _legacyImport is not null ? _legacyImport.EnumMethodSemantics(phEnum, mb, rEventProp, cMax, pcEventProp) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport is not null ? _legacyImport.EnumMethodSemantics(phEnum, mb, rEventProp, cMax, pcEventProp) : HResults.E_NOTIMPL; + } int IMetaDataImport.GetMethodSemantics(uint mb, uint tkEventProp, uint* pdwSemanticsFlags) - => _legacyImport is not null ? _legacyImport.GetMethodSemantics(mb, tkEventProp, pdwSemanticsFlags) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport is not null ? _legacyImport.GetMethodSemantics(mb, tkEventProp, pdwSemanticsFlags) : HResults.E_NOTIMPL; + } int IMetaDataImport.GetClassLayout(uint td, uint* pdwPackSize, void* rFieldOffset, uint cMax, uint* pcFieldOffset, uint* pulClassSize) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -1297,13 +1412,22 @@ int IMetaDataImport.GetClassLayout(uint td, uint* pdwPackSize, void* rFieldOffse } int IMetaDataImport.GetFieldMarshal(uint tk, byte** ppvNativeType, uint* pcbNativeType) - => _legacyImport is not null ? _legacyImport.GetFieldMarshal(tk, ppvNativeType, pcbNativeType) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport is not null ? _legacyImport.GetFieldMarshal(tk, ppvNativeType, pcbNativeType) : HResults.E_NOTIMPL; + } int IMetaDataImport.GetPermissionSetProps(uint pm, uint* pdwAction, void** ppvPermission, uint* pcbPermission) - => _legacyImport is not null ? _legacyImport.GetPermissionSetProps(pm, pdwAction, ppvPermission, pcbPermission) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport is not null ? _legacyImport.GetPermissionSetProps(pm, pdwAction, ppvPermission, pcbPermission) : HResults.E_NOTIMPL; + } int IMetaDataImport.GetModuleRefProps(uint mur, char* szName, uint cchName, uint* pchName) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -1344,10 +1468,15 @@ int IMetaDataImport.GetModuleRefProps(uint mur, char* szName, uint cchName, uint } int IMetaDataImport.EnumModuleRefs(nint* phEnum, uint* rModuleRefs, uint cmax, uint* pcModuleRefs) - => _legacyImport is not null ? _legacyImport.EnumModuleRefs(phEnum, rModuleRefs, cmax, pcModuleRefs) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport is not null ? _legacyImport.EnumModuleRefs(phEnum, rModuleRefs, cmax, pcModuleRefs) : HResults.E_NOTIMPL; + } int IMetaDataImport.GetTypeSpecFromToken(uint typespec, byte** ppvSig, uint* pcbSig) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -1387,13 +1516,22 @@ int IMetaDataImport.GetTypeSpecFromToken(uint typespec, byte** ppvSig, uint* pcb } int IMetaDataImport.GetNameFromToken(uint tk, byte** pszUtf8NamePtr) - => _legacyImport is not null ? _legacyImport.GetNameFromToken(tk, pszUtf8NamePtr) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport is not null ? _legacyImport.GetNameFromToken(tk, pszUtf8NamePtr) : HResults.E_NOTIMPL; + } int IMetaDataImport.EnumUnresolvedMethods(nint* phEnum, uint* rMethods, uint cMax, uint* pcTokens) - => _legacyImport is not null ? _legacyImport.EnumUnresolvedMethods(phEnum, rMethods, cMax, pcTokens) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport is not null ? _legacyImport.EnumUnresolvedMethods(phEnum, rMethods, cMax, pcTokens) : HResults.E_NOTIMPL; + } int IMetaDataImport.GetUserString(uint stk, char* szString, uint cchString, uint* pchString) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -1471,19 +1609,36 @@ int IMetaDataImport.GetUserString(uint stk, char* szString, uint cchString, uint int IMetaDataImport.GetPinvokeMap(uint tk, uint* pdwMappingFlags, char* szImportName, uint cchImportName, uint* pchImportName, uint* pmrImportDLL) - => _legacyImport is not null ? _legacyImport.GetPinvokeMap(tk, pdwMappingFlags, szImportName, cchImportName, pchImportName, pmrImportDLL) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport is not null ? _legacyImport.GetPinvokeMap(tk, pdwMappingFlags, szImportName, cchImportName, pchImportName, pmrImportDLL) : HResults.E_NOTIMPL; + } int IMetaDataImport.EnumSignatures(nint* phEnum, uint* rSignatures, uint cmax, uint* pcSignatures) - => _legacyImport is not null ? _legacyImport.EnumSignatures(phEnum, rSignatures, cmax, pcSignatures) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport is not null ? _legacyImport.EnumSignatures(phEnum, rSignatures, cmax, pcSignatures) : HResults.E_NOTIMPL; + } int IMetaDataImport.EnumTypeSpecs(nint* phEnum, uint* rTypeSpecs, uint cmax, uint* pcTypeSpecs) - => _legacyImport is not null ? _legacyImport.EnumTypeSpecs(phEnum, rTypeSpecs, cmax, pcTypeSpecs) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport is not null ? _legacyImport.EnumTypeSpecs(phEnum, rTypeSpecs, cmax, pcTypeSpecs) : HResults.E_NOTIMPL; + } int IMetaDataImport.EnumUserStrings(nint* phEnum, uint* rStrings, uint cmax, uint* pcStrings) - => _legacyImport is not null ? _legacyImport.EnumUserStrings(phEnum, rStrings, cmax, pcStrings) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport is not null ? _legacyImport.EnumUserStrings(phEnum, rStrings, cmax, pcStrings) : HResults.E_NOTIMPL; + } int IMetaDataImport.GetParamForMethodIndex(uint md, uint ulParamSeq, uint* ppd) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -1528,20 +1683,33 @@ int IMetaDataImport.GetParamForMethodIndex(uint md, uint ulParamSeq, uint* ppd) } int IMetaDataImport.GetCustomAttributeProps(uint cv, uint* ptkObj, uint* ptkType, void** ppBlob, uint* pcbSize) - => _legacyImport is not null ? _legacyImport.GetCustomAttributeProps(cv, ptkObj, ptkType, ppBlob, pcbSize) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport is not null ? _legacyImport.GetCustomAttributeProps(cv, ptkObj, ptkType, ppBlob, pcbSize) : HResults.E_NOTIMPL; + } int IMetaDataImport.FindTypeRef(uint tkResolutionScope, char* szName, uint* ptr) - => _legacyImport is not null ? _legacyImport.FindTypeRef(tkResolutionScope, szName, ptr) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport is not null ? _legacyImport.FindTypeRef(tkResolutionScope, szName, ptr) : HResults.E_NOTIMPL; + } int IMetaDataImport.GetPropertyProps(uint prop, uint* pClass, char* szProperty, uint cchProperty, uint* pchProperty, uint* pdwPropFlags, byte** ppvSig, uint* pbSig, uint* pdwCPlusTypeFlag, void** ppDefaultValue, uint* pcchDefaultValue, uint* pmdSetter, uint* pmdGetter, uint* rmdOtherMethod, uint cMax, uint* pcOtherMethod) - => _legacyImport is not null ? _legacyImport.GetPropertyProps(prop, pClass, szProperty, cchProperty, pchProperty, pdwPropFlags, ppvSig, pbSig, pdwCPlusTypeFlag, ppDefaultValue, pcchDefaultValue, pmdSetter, pmdGetter, rmdOtherMethod, cMax, pcOtherMethod) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport is not null ? _legacyImport.GetPropertyProps(prop, pClass, szProperty, cchProperty, pchProperty, pdwPropFlags, ppvSig, pbSig, pdwCPlusTypeFlag, ppDefaultValue, pcchDefaultValue, pmdSetter, pmdGetter, rmdOtherMethod, cMax, pcOtherMethod) : HResults.E_NOTIMPL; + } int IMetaDataImport.GetParamProps(uint tk, uint* pmd, uint* pulSequence, char* szName, uint cchName, uint* pchName, uint* pdwAttr, uint* pdwCPlusTypeFlag, void** ppValue, uint* pcchValue) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -1623,29 +1791,61 @@ int IMetaDataImport.GetParamProps(uint tk, uint* pmd, uint* pulSequence, char* s } int IMetaDataImport.GetNativeCallConvFromSig(void* pvSig, uint cbSig, uint* pCallConv) - => _legacyImport is not null ? _legacyImport.GetNativeCallConvFromSig(pvSig, cbSig, pCallConv) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport is not null ? _legacyImport.GetNativeCallConvFromSig(pvSig, cbSig, pCallConv) : HResults.E_NOTIMPL; + } int IMetaDataImport.IsGlobal(uint pd, int* pbGlobal) - => _legacyImport is not null ? _legacyImport.IsGlobal(pd, pbGlobal) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport is not null ? _legacyImport.IsGlobal(pd, pbGlobal) : HResults.E_NOTIMPL; + } // IMetaDataImport2 methods — delegate to legacy via _legacyImport2 int IMetaDataImport2.GetMethodSpecProps(uint mi, uint* tkParent, byte** ppvSigBlob, uint* pcbSigBlob) - => _legacyImport2 is not null ? _legacyImport2.GetMethodSpecProps(mi, tkParent, ppvSigBlob, pcbSigBlob) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport2 is not null ? _legacyImport2.GetMethodSpecProps(mi, tkParent, ppvSigBlob, pcbSigBlob) : HResults.E_NOTIMPL; + } int IMetaDataImport2.EnumGenericParamConstraints(nint* phEnum, uint tk, uint* rGenericParamConstraints, uint cMax, uint* pcGenericParamConstraints) - => _legacyImport2 is not null ? _legacyImport2.EnumGenericParamConstraints(phEnum, tk, rGenericParamConstraints, cMax, pcGenericParamConstraints) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport2 is not null ? _legacyImport2.EnumGenericParamConstraints(phEnum, tk, rGenericParamConstraints, cMax, pcGenericParamConstraints) : HResults.E_NOTIMPL; + } int IMetaDataImport2.GetGenericParamConstraintProps(uint gpc, uint* ptGenericParam, uint* ptkConstraintType) - => _legacyImport2 is not null ? _legacyImport2.GetGenericParamConstraintProps(gpc, ptGenericParam, ptkConstraintType) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport2 is not null ? _legacyImport2.GetGenericParamConstraintProps(gpc, ptGenericParam, ptkConstraintType) : HResults.E_NOTIMPL; + } int IMetaDataImport2.GetPEKind(uint* pdwPEKind, uint* pdwMachine) - => _legacyImport2 is not null ? _legacyImport2.GetPEKind(pdwPEKind, pdwMachine) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport2 is not null ? _legacyImport2.GetPEKind(pdwPEKind, pdwMachine) : HResults.E_NOTIMPL; + } int IMetaDataImport2.GetVersionString(char* pwzBuf, uint ccBufSize, uint* pccBufSize) - => _legacyImport2 is not null ? _legacyImport2.GetVersionString(pwzBuf, ccBufSize, pccBufSize) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport2 is not null ? _legacyImport2.GetVersionString(pwzBuf, ccBufSize, pccBufSize) : HResults.E_NOTIMPL; + } int IMetaDataImport2.EnumMethodSpecs(nint* phEnum, uint tk, uint* rMethodSpecs, uint cMax, uint* pcMethodSpecs) - => _legacyImport2 is not null ? _legacyImport2.EnumMethodSpecs(phEnum, tk, rMethodSpecs, cMax, pcMethodSpecs) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyImport2 is not null ? _legacyImport2.EnumMethodSpecs(phEnum, tk, rMethodSpecs, cMax, pcMethodSpecs) : HResults.E_NOTIMPL; + } // ============================================= // IMetaDataAssemblyImport @@ -1655,6 +1855,7 @@ int IMetaDataAssemblyImport.GetAssemblyProps(uint mda, byte** ppbPublicKey, uint uint* pulHashAlgId, char* szName, uint cchName, uint* pchName, ASSEMBLYMETADATA* pMetaData, uint* pdwAssemblyFlags) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -1761,6 +1962,7 @@ int IMetaDataAssemblyImport.GetAssemblyRefProps(uint mdar, byte** ppbPublicKeyOr char* szName, uint cchName, uint* pchName, ASSEMBLYMETADATA* pMetaData, byte** ppbHashValue, uint* pcbHashValue, uint* pdwAssemblyRefFlags) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -1872,11 +2074,16 @@ int IMetaDataAssemblyImport.GetAssemblyRefProps(uint mdar, byte** ppbPublicKeyOr int IMetaDataAssemblyImport.GetFileProps(uint mdf, char* szName, uint cchName, uint* pchName, byte** ppbHashValue, uint* pcbHashValue, uint* pdwFileFlags) - => _legacyAssemblyImport is not null ? _legacyAssemblyImport.GetFileProps(mdf, szName, cchName, pchName, ppbHashValue, pcbHashValue, pdwFileFlags) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyAssemblyImport is not null ? _legacyAssemblyImport.GetFileProps(mdf, szName, cchName, pchName, ppbHashValue, pcbHashValue, pdwFileFlags) : HResults.E_NOTIMPL; + } int IMetaDataAssemblyImport.GetExportedTypeProps(uint mdct, char* szName, uint cchName, uint* pchName, uint* ptkImplementation, uint* ptkTypeDef, uint* pdwExportedTypeFlags) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -1942,22 +2149,43 @@ int IMetaDataAssemblyImport.GetExportedTypeProps(uint mdct, char* szName, uint c int IMetaDataAssemblyImport.GetManifestResourceProps(uint mdmr, char* szName, uint cchName, uint* pchName, uint* ptkImplementation, uint* pdwOffset, uint* pdwResourceFlags) - => _legacyAssemblyImport is not null ? _legacyAssemblyImport.GetManifestResourceProps(mdmr, szName, cchName, pchName, ptkImplementation, pdwOffset, pdwResourceFlags) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyAssemblyImport is not null ? _legacyAssemblyImport.GetManifestResourceProps(mdmr, szName, cchName, pchName, ptkImplementation, pdwOffset, pdwResourceFlags) : HResults.E_NOTIMPL; + } int IMetaDataAssemblyImport.EnumAssemblyRefs(nint* phEnum, uint* rAssemblyRefs, uint cMax, uint* pcTokens) - => _legacyAssemblyImport is not null ? _legacyAssemblyImport.EnumAssemblyRefs(phEnum, rAssemblyRefs, cMax, pcTokens) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyAssemblyImport is not null ? _legacyAssemblyImport.EnumAssemblyRefs(phEnum, rAssemblyRefs, cMax, pcTokens) : HResults.E_NOTIMPL; + } int IMetaDataAssemblyImport.EnumFiles(nint* phEnum, uint* rFiles, uint cMax, uint* pcTokens) - => _legacyAssemblyImport is not null ? _legacyAssemblyImport.EnumFiles(phEnum, rFiles, cMax, pcTokens) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyAssemblyImport is not null ? _legacyAssemblyImport.EnumFiles(phEnum, rFiles, cMax, pcTokens) : HResults.E_NOTIMPL; + } int IMetaDataAssemblyImport.EnumExportedTypes(nint* phEnum, uint* rExportedTypes, uint cMax, uint* pcTokens) - => _legacyAssemblyImport is not null ? _legacyAssemblyImport.EnumExportedTypes(phEnum, rExportedTypes, cMax, pcTokens) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyAssemblyImport is not null ? _legacyAssemblyImport.EnumExportedTypes(phEnum, rExportedTypes, cMax, pcTokens) : HResults.E_NOTIMPL; + } int IMetaDataAssemblyImport.EnumManifestResources(nint* phEnum, uint* rManifestResources, uint cMax, uint* pcTokens) - => _legacyAssemblyImport is not null ? _legacyAssemblyImport.EnumManifestResources(phEnum, rManifestResources, cMax, pcTokens) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyAssemblyImport is not null ? _legacyAssemblyImport.EnumManifestResources(phEnum, rManifestResources, cMax, pcTokens) : HResults.E_NOTIMPL; + } int IMetaDataAssemblyImport.GetAssemblyFromScope(uint* ptkAssembly) { + using Lock.Scope scope = _apiLock.EnterScope(); if (ptkAssembly is not null) *ptkAssembly = 0x20000001; // TokenFromRid(1, mdtAssembly) @@ -1977,6 +2205,7 @@ int IMetaDataAssemblyImport.GetAssemblyFromScope(uint* ptkAssembly) int IMetaDataAssemblyImport.FindExportedTypeByName(char* szName, uint mdtExportedType, uint* ptkExportedType) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -2032,14 +2261,26 @@ int IMetaDataAssemblyImport.FindExportedTypeByName(char* szName, uint mdtExporte } int IMetaDataAssemblyImport.FindManifestResourceByName(char* szName, uint* ptkManifestResource) - => _legacyAssemblyImport is not null ? _legacyAssemblyImport.FindManifestResourceByName(szName, ptkManifestResource) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyAssemblyImport is not null ? _legacyAssemblyImport.FindManifestResourceByName(szName, ptkManifestResource) : HResults.E_NOTIMPL; + } void IMetaDataAssemblyImport.CloseEnum(nint hEnum) - => ((IMetaDataImport)this).CloseEnum(hEnum); + { + using Lock.Scope scope = _apiLock.EnterScope(); + + ((IMetaDataImport)this).CloseEnum(hEnum); + } int IMetaDataAssemblyImport.FindAssembliesByName(char* szAppBase, char* szPrivateBin, char* szAssemblyName, nint* ppIUnk, uint cMax, uint* pcAssemblies) - => _legacyAssemblyImport is not null ? _legacyAssemblyImport.FindAssembliesByName(szAppBase, szPrivateBin, szAssemblyName, ppIUnk, cMax, pcAssemblies) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return _legacyAssemblyImport is not null ? _legacyAssemblyImport.FindAssembliesByName(szAppBase, szPrivateBin, szAssemblyName, ppIUnk, cMax, pcAssemblies) : HResults.E_NOTIMPL; + } // Helpers and lookup builders diff --git a/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.ICLRDataEnumMemoryRegions.cs b/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.ICLRDataEnumMemoryRegions.cs index 7e30e2ad47f8..69fe49a73fa4 100644 --- a/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.ICLRDataEnumMemoryRegions.cs +++ b/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.ICLRDataEnumMemoryRegions.cs @@ -3,6 +3,7 @@ using System; +using System.Threading; namespace Microsoft.Diagnostics.DataContractReader.Legacy; /// @@ -12,5 +13,9 @@ namespace Microsoft.Diagnostics.DataContractReader.Legacy; public sealed unsafe partial class SOSDacImpl : ICLRDataEnumMemoryRegions { int ICLRDataEnumMemoryRegions.EnumMemoryRegions(void* callback, uint miniDumpFlags, int clrFlags) - => LegacyFallbackHelper.CanFallback() && _legacyEnumMemory is not null ? _legacyEnumMemory.EnumMemoryRegions(callback, miniDumpFlags, clrFlags) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyEnumMemory is not null ? _legacyEnumMemory.EnumMemoryRegions(callback, miniDumpFlags, clrFlags) : HResults.E_NOTIMPL; + } } diff --git a/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.IXCLRDataProcess.cs b/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.IXCLRDataProcess.cs index 6c8d60c9d854..dfec74b4066b 100644 --- a/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.IXCLRDataProcess.cs +++ b/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.IXCLRDataProcess.cs @@ -10,6 +10,7 @@ using System.Runtime.InteropServices; using System.Runtime.InteropServices.Marshalling; using System.Text; +using System.Threading; using Microsoft.Diagnostics.DataContractReader.Contracts; using Microsoft.Diagnostics.DataContractReader.Contracts.Extensions; @@ -28,6 +29,7 @@ int IXCLRDataProcess3.GetFunctionTable( uint* bytesNeeded, uint* entries) { + using Lock.Scope scope = _apiLock.EnterScope(); if (bytesNeeded is null || entries is null) { if (bytesNeeded is not null) @@ -82,6 +84,7 @@ int IXCLRDataProcess3.GetFunctionTable( int IXCLRDataProcess.Flush() { + using Lock.Scope scope = _apiLock.EnterScope(); _target.Flush(FlushScope.All); // Flush is always propagated — it's cache management, not data retrieval. @@ -92,16 +95,29 @@ int IXCLRDataProcess.Flush() } int IXCLRDataProcess.StartEnumTasks(ulong* handle) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataProcess.EnumTask(ulong* handle, DacComNullableByRef task) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataProcess.EndEnumTasks(ulong handle) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataProcess.GetTaskByOSThreadID(uint osThreadID, DacComNullableByRef task) { + using Lock.Scope scope = _apiLock.EnterScope(); // Find the thread corresponding to the OS thread ID Contracts.IThread contract = _target.Contracts.Thread; TargetPointer thread = contract.GetThreadStoreData().FirstThread; @@ -131,12 +147,13 @@ int IXCLRDataProcess.GetTaskByOSThreadID(uint osThreadID, DacComNullableByRef task) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; int hrLocal = HResults.S_OK; IXCLRDataTask? legacyTask = null; @@ -154,7 +171,7 @@ int IXCLRDataProcess.GetTaskByUniqueID(ulong taskID, DacComNullableByRef HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataProcess.IsSameObject(IXCLRDataProcess* process) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataProcess.GetManagedObject(DacComNullableByRef value) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataProcess.GetDesiredExecutionState(uint* state) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataProcess.SetDesiredExecutionState(uint state) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataProcess.GetAddressType(ClrDataAddress address, CLRDataAddressType* type) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -235,6 +273,7 @@ int IXCLRDataProcess.GetRuntimeNameByAddress( char* nameBuf, ClrDataAddress* displacement) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -384,6 +423,7 @@ public ProcessEnum(IEnumerable values, nuint legacyHandle) int IXCLRDataProcess.StartEnumAppDomains(ulong* handle) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; int hrLocal = HResults.S_OK; ulong legacyHandle = 0; @@ -428,6 +468,7 @@ int IXCLRDataProcess.StartEnumAppDomains(ulong* handle) int IXCLRDataProcess.EnumAppDomain(ulong* handle, DacComNullableByRef appDomain) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; int hrLocal = HResults.S_OK; try @@ -455,7 +496,7 @@ int IXCLRDataProcess.EnumAppDomain(ulong* handle, DacComNullableByRef appDomain) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; int hrLocal = HResults.S_OK; IXCLRDataAppDomain? legacyAppDomain = null; @@ -526,7 +569,7 @@ int IXCLRDataProcess.GetAppDomainByUniqueID(ulong id, DacComNullableByRef HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataProcess.EnumAssembly(ulong* handle, DacComNullableByRef assembly) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataProcess.EndEnumAssemblies(ulong handle) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataProcess.StartEnumModules(ulong* handle) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; int hrLocal = HResults.S_OK; ulong legacyHandle = 0; @@ -601,6 +657,7 @@ int IXCLRDataProcess.StartEnumModules(ulong* handle) int IXCLRDataProcess.EnumModule(ulong* handle, DacComNullableByRef mod) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; int hrLocal = HResults.S_OK; try @@ -627,7 +684,7 @@ int IXCLRDataProcess.EnumModule(ulong* handle, DacComNullableByRef mod) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_FALSE; int hrLocal = HResults.S_OK; IXCLRDataModule? legacyModule = null; @@ -709,7 +768,7 @@ int IXCLRDataProcess.GetModuleByAddress(ClrDataAddress address, DacComNullableBy ClrDataAddress imageBase = baseAddress.ToClrDataAddress(_target); if (imageBase <= address && address - imageBase < size) { - mod.Interface = new ClrDataModule(module.Address, _target, legacyModule); + mod.Interface = new ClrDataModule(module.Address, _target, legacyModule, _apiLock); hr = HResults.S_OK; break; } @@ -924,6 +983,7 @@ private bool HasMethodInstantiation(MethodDescHandle md) int IXCLRDataProcess.StartEnumMethodInstancesByAddress(ClrDataAddress address, IXCLRDataAppDomain? appDomain, ulong* handle) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_FALSE; *handle = 0; @@ -997,6 +1057,7 @@ int IXCLRDataProcess.StartEnumMethodInstancesByAddress(ClrDataAddress address, I int IXCLRDataProcess.EnumMethodInstanceByAddress(ulong* handle, DacComNullableByRef method) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; GCHandle gcHandle = GCHandle.FromIntPtr((IntPtr)(*handle)); @@ -1020,7 +1081,7 @@ int IXCLRDataProcess.EnumMethodInstanceByAddress(ulong* handle, DacComNullableBy if (emi.Enumerator.MoveNext()) { MethodDescHandle methodDesc = emi.Enumerator.Current; - method.Interface = new ClrDataMethodInstance(_target, methodDesc, emi._appDomain, legacyMethod); + method.Interface = new ClrDataMethodInstance(_target, methodDesc, emi._appDomain, legacyMethod, _apiLock); } else { @@ -1044,6 +1105,7 @@ int IXCLRDataProcess.EnumMethodInstanceByAddress(ulong* handle, DacComNullableBy int IXCLRDataProcess.EndEnumMethodInstancesByAddress(ulong handle) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; GCHandle gcHandle = GCHandle.FromIntPtr((IntPtr)handle); @@ -1071,6 +1133,7 @@ int IXCLRDataProcess.GetDataByAddress( DacComNullableByRef value, ClrDataAddress* displacement) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = flags == 0 ? HResults.E_NOTIMPL : HResults.E_INVALIDARG; #if DEBUG @@ -1085,7 +1148,11 @@ int IXCLRDataProcess.GetDataByAddress( } int IXCLRDataProcess.GetExceptionStateByExceptionRecord(EXCEPTION_RECORD64* record, DacComNullableByRef exState) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataProcess.TranslateExceptionRecordToNotification(EXCEPTION_RECORD64* record, [MarshalUsing(typeof(UniqueComInterfaceMarshaller))] IXCLRDataExceptionNotification notify) { @@ -1097,116 +1164,142 @@ int IXCLRDataProcess.TranslateExceptionRecordToNotification(EXCEPTION_RECORD64* int hr = HResults.S_OK; try { - Span exInfo = stackalloc TargetPointer[EXCEPTION_RECORD64.ExceptionMaximumParameters]; - for (int i = 0; i < EXCEPTION_RECORD64.ExceptionMaximumParameters; i++) - exInfo[i] = new TargetPointer(record->ExceptionInformation[i]); + Action? callback = null; + { + using Lock.Scope scope = _apiLock.EnterScope(); - INotifications notifications = _target.Contracts.Notifications; - if (!notifications.TryParseNotification(exInfo, out NotificationData? notification)) - return HResults.E_INVALIDARG; + // External notification code can call back into the DAC, so prepare everything + // needed for the callback while locked and invoke it after releasing the lock. + Span exInfo = stackalloc TargetPointer[EXCEPTION_RECORD64.ExceptionMaximumParameters]; + for (int i = 0; i < EXCEPTION_RECORD64.ExceptionMaximumParameters; i++) + exInfo[i] = new TargetPointer(record->ExceptionInformation[i]); - switch (notification) - { - case ModuleLoadNotificationData moduleLoad: + INotifications notifications = _target.Contracts.Notifications; + if (!notifications.TryParseNotification(exInfo, out NotificationData? notification)) + return HResults.E_INVALIDARG; + + switch (notification) { - IXCLRDataModule? legacyModule = null; - if (_legacyImpl is not null) + case ModuleLoadNotificationData moduleLoad: { - DacComNullableByRef legacyModuleOut = new(isNullRef: false); - _legacyImpl.GetModule(moduleLoad.ModuleAddress.ToClrDataAddress(_target), legacyModuleOut); - legacyModule = legacyModuleOut.Interface; - } + IXCLRDataModule? legacyModule = null; + if (_legacyImpl is not null) + { + DacComNullableByRef legacyModuleOut = new(isNullRef: false); + _legacyImpl.GetModule(moduleLoad.ModuleAddress.ToClrDataAddress(_target), legacyModuleOut); + legacyModule = legacyModuleOut.Interface; + } - notify.OnModuleLoaded(new ClrDataModule(moduleLoad.ModuleAddress, _target, legacyModule)); - break; - } + ClrDataModule module = new(moduleLoad.ModuleAddress, _target, legacyModule, _apiLock); + callback = () => notify.OnModuleLoaded(module); + break; + } - case ModuleUnloadNotificationData moduleUnload: - { - IXCLRDataModule? legacyModule = null; - if (_legacyImpl is not null) + case ModuleUnloadNotificationData moduleUnload: { - DacComNullableByRef legacyModuleOut = new(isNullRef: false); - _legacyImpl.GetModule(moduleUnload.ModuleAddress.ToClrDataAddress(_target), legacyModuleOut); - legacyModule = legacyModuleOut.Interface; - } + IXCLRDataModule? legacyModule = null; + if (_legacyImpl is not null) + { + DacComNullableByRef legacyModuleOut = new(isNullRef: false); + _legacyImpl.GetModule(moduleUnload.ModuleAddress.ToClrDataAddress(_target), legacyModuleOut); + legacyModule = legacyModuleOut.Interface; + } - notify.OnModuleUnloaded(new ClrDataModule(moduleUnload.ModuleAddress, _target, legacyModule)); - break; - } + ClrDataModule module = new(moduleUnload.ModuleAddress, _target, legacyModule, _apiLock); + callback = () => notify.OnModuleUnloaded(module); + break; + } - case JitNotificationData jit: - { - TargetPointer appDomain = _target.Contracts.Loader.GetAppDomain(); + case JitNotificationData jit: + { + TargetPointer appDomain = _target.Contracts.Loader.GetAppDomain(); - IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; - MethodDescHandle methodDesc = rts.GetMethodDescHandle(jit.MethodDescAddress); + IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; + MethodDescHandle methodDesc = rts.GetMethodDescHandle(jit.MethodDescAddress); - ClrDataMethodInstance methodInst = new(_target, methodDesc, appDomain, null); - notify.OnCodeGenerated(methodInst); - if (notify is IXCLRDataExceptionNotification5 notify5) - { - notify5.OnCodeGenerated2(methodInst, jit.NativeCodeAddress.ToClrDataAddress(_target)); + ClrDataMethodInstance methodInst = new(_target, methodDesc, appDomain, null, _apiLock); + ClrDataAddress nativeCodeAddress = jit.NativeCodeAddress.ToClrDataAddress(_target); + if (notify is IXCLRDataExceptionNotification5 notify5) + { + callback = () => + { + notify.OnCodeGenerated(methodInst); + notify5.OnCodeGenerated2(methodInst, nativeCodeAddress); + }; + } + else + { + callback = () => notify.OnCodeGenerated(methodInst); + } + break; } - break; - } - case ExceptionNotificationData exception: - { - if (notify is IXCLRDataExceptionNotification2 notify2) + case ExceptionNotificationData exception: { - IThread thread = _target.Contracts.Thread; - Contracts.ThreadData threadData = thread.GetThreadData(exception.ThreadAddress); - TargetPointer thrownObjectHandle = thread.GetCurrentExceptionHandle(exception.ThreadAddress); - notify2.OnException(new ClrDataExceptionState( - _target, - exception.ThreadAddress, - (uint)CLRDataExceptionStateFlag.CLRDATA_EXCEPTION_DEFAULT, - TargetPointer.Null, - thrownObjectHandle, - threadData.FirstNestedException, - null)); + if (notify is IXCLRDataExceptionNotification2 notify2) + { + IThread thread = _target.Contracts.Thread; + Contracts.ThreadData threadData = thread.GetThreadData(exception.ThreadAddress); + TargetPointer thrownObjectHandle = thread.GetCurrentExceptionHandle(exception.ThreadAddress); + ClrDataExceptionState exceptionState = new( + _target, + exception.ThreadAddress, + (uint)CLRDataExceptionStateFlag.CLRDATA_EXCEPTION_DEFAULT, + TargetPointer.Null, + thrownObjectHandle, + threadData.FirstNestedException, + null, + _apiLock); + callback = () => notify2.OnException(exceptionState); + } + else + return HResults.E_INVALIDARG; + break; } - else - return HResults.E_INVALIDARG; - break; - } - case GcNotificationData gc: - { - if (gc.IsSupportedEvent) + case GcNotificationData gc: { - if (notify is IXCLRDataExceptionNotification3 notify3) + if (gc.IsSupportedEvent) { - notify3.OnGcEvent(new GcEvtArgs + if (notify is IXCLRDataExceptionNotification3 notify3) { - type = gc.EventData.EventType switch + GcEvtArgs args = new() { - GcEventType.MarkEnd => GcEvtArgs.GcEvt_t.GC_MARK_END, - _ => GcEvtArgs.GcEvt_t.GC_EVENT_TYPE_MAX, - }, - condemnedGeneration = gc.EventData.CondemnedGeneration, - }); + type = gc.EventData.EventType switch + { + GcEventType.MarkEnd => GcEvtArgs.GcEvt_t.GC_MARK_END, + _ => GcEvtArgs.GcEvt_t.GC_EVENT_TYPE_MAX, + }, + condemnedGeneration = gc.EventData.CondemnedGeneration, + }; + callback = () => notify3.OnGcEvent(args); + } + hr = HResults.S_OK; } - hr = HResults.S_OK; + else + { + hr = HResults.E_FAIL; + } + break; } - else - hr = HResults.E_FAIL; - break; - } - case ExceptionCatcherEnterNotificationData exceptionCatcherEnter: - { - if (notify is IXCLRDataExceptionNotification4 notify4) + case ExceptionCatcherEnterNotificationData exceptionCatcherEnter: { - TargetPointer appDomain = _target.Contracts.Loader.GetAppDomain(); - IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; - MethodDescHandle methodDesc = rts.GetMethodDescHandle(exceptionCatcherEnter.MethodDescAddress); - notify4.ExceptionCatcherEnter(new ClrDataMethodInstance(_target, methodDesc, appDomain, null), exceptionCatcherEnter.NativeOffset); + if (notify is IXCLRDataExceptionNotification4 notify4) + { + TargetPointer appDomain = _target.Contracts.Loader.GetAppDomain(); + IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; + MethodDescHandle methodDesc = rts.GetMethodDescHandle(exceptionCatcherEnter.MethodDescAddress); + ClrDataMethodInstance methodInst = new(_target, methodDesc, appDomain, null, _apiLock); + uint nativeOffset = exceptionCatcherEnter.NativeOffset; + callback = () => notify4.ExceptionCatcherEnter(methodInst, nativeOffset); + } + break; } - break; } } + + callback?.Invoke(); } catch (System.Exception ex) { @@ -1221,6 +1314,7 @@ int IXCLRDataProcess.TranslateExceptionRecordToNotification(EXCEPTION_RECORD64* int IXCLRDataProcess.Request(uint reqCode, uint inBufferSize, byte* inBuffer, uint outBufferSize, byte* outBuffer) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.E_INVALIDARG; if (reqCode == (uint)CLRDataGeneralRequest.CLRDATA_REQUEST_REVISION) @@ -1271,13 +1365,22 @@ int IXCLRDataProcess.CreateMemoryValue( IXCLRDataTypeInstance? type, ClrDataAddress addr, DacComNullableByRef value) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataProcess.SetAllTypeNotifications(IXCLRDataModule? mod, uint flags) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataProcess.SetAllCodeNotifications(IXCLRDataModule? mod, uint flags) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -1311,7 +1414,11 @@ int IXCLRDataProcess.GetTypeNotifications( IXCLRDataModule? singleMod, [In, MarshalUsing(CountElementName = nameof(numTokens))] /*mdTypeDef*/ uint[]? tokens, [In, Out, MarshalUsing(CountElementName = nameof(numTokens))] uint[]? flags) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataProcess.SetTypeNotifications( uint numTokens, @@ -1320,7 +1427,11 @@ int IXCLRDataProcess.SetTypeNotifications( [In, MarshalUsing(CountElementName = nameof(numTokens))] /*mdTypeDef*/ uint[]? tokens, [In, MarshalUsing(CountElementName = nameof(numTokens))] uint[]? flags, uint singleFlags) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataProcess.GetCodeNotifications( uint numTokens, @@ -1329,6 +1440,7 @@ int IXCLRDataProcess.GetCodeNotifications( [In, MarshalUsing(CountElementName = nameof(numTokens))] /*mdMethodDef*/ uint[]? tokens, [In, Out, MarshalUsing(CountElementName = nameof(numTokens))] uint[]? flags) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; ICodeNotifications codeNotif = _target.Contracts.CodeNotifications; @@ -1377,6 +1489,7 @@ int IXCLRDataProcess.SetCodeNotifications( [In, MarshalUsing(CountElementName = nameof(numTokens))] uint[]? flags, uint singleFlags) { + using Lock.Scope scope = _apiLock.EnterScope(); // Behavior difference from the legacy DAC: the legacy DAC performs an upfront // capacity check (numTokens > table size returns E_OUTOFMEMORY with no writes // performed). The cDAC's CodeNotifications contract does not expose a capacity @@ -1438,6 +1551,7 @@ int IXCLRDataProcess.SetCodeNotifications( int IXCLRDataProcess.GetOtherNotificationFlags(uint* flags) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -1460,6 +1574,7 @@ int IXCLRDataProcess.GetOtherNotificationFlags(uint* flags) } int IXCLRDataProcess.SetOtherNotificationFlags(uint flags) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -1511,6 +1626,7 @@ int IXCLRDataProcess.SetOtherNotificationFlags(uint flags) int IXCLRDataProcess.StartEnumMethodDefinitionsByAddress(ClrDataAddress address, ulong* handle) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_FALSE; int hrLocal = HResults.S_OK; ulong legacyHandle = 0; @@ -1573,6 +1689,7 @@ int IXCLRDataProcess.StartEnumMethodDefinitionsByAddress(ClrDataAddress address, int IXCLRDataProcess.EnumMethodDefinitionByAddress(ulong* handle, DacComNullableByRef method) { + using Lock.Scope scope = _apiLock.EnterScope(); ProcessEnum methodDefinitions; try { @@ -1615,7 +1732,8 @@ int IXCLRDataProcess.EnumMethodDefinitionByAddress(ulong* handle, DacComNullable _target, methodDefinition.Module, methodDefinition.Token, - legacyMethod); + legacyMethod, + _apiLock); } else { @@ -1639,6 +1757,7 @@ int IXCLRDataProcess.EnumMethodDefinitionByAddress(ulong* handle, DacComNullable int IXCLRDataProcess.EndEnumMethodDefinitionsByAddress(ulong handle) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; ProcessEnum methodDefinitions; try @@ -1705,7 +1824,11 @@ int IXCLRDataProcess.FollowStub( ClrDataAddress* outAddr, /*struct CLRDATA_FOLLOW_STUB_BUFFER*/ void* outBuffer, uint* outFlags) - => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.FollowStub(inFlags, inAddr, inBuffer, outAddr, outBuffer, outFlags) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.FollowStub(inFlags, inAddr, inBuffer, outAddr, outBuffer, outFlags) : HResults.E_NOTIMPL; + } int IXCLRDataProcess.FollowStub2( IXCLRDataTask? task, @@ -1715,7 +1838,11 @@ int IXCLRDataProcess.FollowStub2( ClrDataAddress* outAddr, /*struct CLRDATA_FOLLOW_STUB_BUFFER*/ void* outBuffer, uint* outFlags) - => LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.FollowStub2(task, inFlags, inAddr, inBuffer, outAddr, outBuffer, outFlags) : HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return LegacyFallbackHelper.CanFallback() && _legacyProcess is not null ? _legacyProcess.FollowStub2(task, inFlags, inAddr, inBuffer, outAddr, outBuffer, outFlags) : HResults.E_NOTIMPL; + } int IXCLRDataProcess.DumpNativeImage( ClrDataAddress loadedBase, @@ -1723,10 +1850,15 @@ int IXCLRDataProcess.DumpNativeImage( /*IXCLRDataDisplay*/ void* display, /*IXCLRLibrarySupport*/ void* libSupport, /*IXCLRDisassemblySupport*/ void* dis) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int IXCLRDataProcess2.GetGcNotification(GcEvtArgs* gcEvtArgs) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.E_NOTIMPL; #if DEBUG if (_legacyProcess2 is not null) @@ -1740,6 +1872,7 @@ int IXCLRDataProcess2.GetGcNotification(GcEvtArgs* gcEvtArgs) int IXCLRDataProcess2.SetGcNotification(GcEvtArgs gcEvtArgs) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { diff --git a/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs b/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs index bb0ab68fe89e..c045d545c443 100644 --- a/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs +++ b/src/runtime/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs @@ -16,6 +16,7 @@ using Microsoft.Diagnostics.DataContractReader.Contracts.StackWalkHelpers; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; +using System.Threading; namespace Microsoft.Diagnostics.DataContractReader.Legacy; @@ -37,6 +38,7 @@ public sealed unsafe partial class SOSDacImpl { private const uint DefaultAppDomainId = 1; + private readonly Lock _apiLock; private readonly Target _target; private readonly ulong _rcwMask = 1UL; @@ -61,8 +63,9 @@ public sealed unsafe partial class SOSDacImpl private readonly IXCLRDataProcess2? _legacyProcess2; private readonly ICLRDataEnumMemoryRegions? _legacyEnumMemory; - public SOSDacImpl(Target target, object? legacyObj) + public SOSDacImpl(Target target, object? legacyObj, Lock apiLock) { + _apiLock = apiLock; _target = target; // Get all the interfaces for delegating to the legacy DAC @@ -95,6 +98,7 @@ public SOSDacImpl(Target target, object? legacyObj) #region ISOSDacInterface int ISOSDacInterface.GetAppDomainConfigFile(ClrDataAddress appDomain, int count, char* configFile, uint* pNeeded) { + using Lock.Scope scope = _apiLock.EnterScope(); // Method is not supported on CoreCLR int hr = HResults.E_FAIL; @@ -112,6 +116,7 @@ int ISOSDacInterface.GetAppDomainConfigFile(ClrDataAddress appDomain, int count, // addr is ignored, only one AppDomain exists in CoreCLR. int ISOSDacInterface.GetAppDomainData(ClrDataAddress addr, DacpAppDomainData* data) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -178,6 +183,7 @@ int ISOSDacInterface.GetAppDomainData(ClrDataAddress addr, DacpAppDomainData* da } int ISOSDacInterface.GetAppDomainList(uint count, [In, MarshalUsing(CountElementName = "count"), Out] ClrDataAddress[] values, uint* pNeeded) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -218,6 +224,7 @@ int ISOSDacInterface.GetAppDomainList(uint count, [In, MarshalUsing(CountElement // addr is ignored -- only one AppDomain exists in CoreCLR. int ISOSDacInterface.GetAppDomainName(ClrDataAddress addr, uint count, char* name, uint* pNeeded) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -287,6 +294,7 @@ int ISOSDacInterface.GetAppDomainName(ClrDataAddress addr, uint count, char* nam } int ISOSDacInterface.GetAppDomainStoreData(void* data) { + using Lock.Scope scope = _apiLock.EnterScope(); DacpAppDomainStoreData* appDomainStoreData = (DacpAppDomainStoreData*)data; int hr = HResults.S_OK; try @@ -317,6 +325,7 @@ int ISOSDacInterface.GetAppDomainStoreData(void* data) } int ISOSDacInterface.GetApplicationBase(ClrDataAddress appDomain, int count, char* appBase, uint* pNeeded) { + using Lock.Scope scope = _apiLock.EnterScope(); // Method is not supported on CoreCLR int hr = HResults.E_FAIL; @@ -333,6 +342,7 @@ int ISOSDacInterface.GetApplicationBase(ClrDataAddress appDomain, int count, cha int ISOSDacInterface.GetAssemblyData(ClrDataAddress domain, ClrDataAddress assembly, DacpAssemblyData* data) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try @@ -391,6 +401,7 @@ int ISOSDacInterface.GetAssemblyData(ClrDataAddress domain, ClrDataAddress assem // addr is ignored, only one AppDomain exists in CoreCLR. int ISOSDacInterface.GetAssemblyList(ClrDataAddress addr, int count, [In, MarshalUsing(CountElementName = "count"), Out] ClrDataAddress[]? values, int* pNeeded) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try @@ -466,9 +477,14 @@ int ISOSDacInterface.GetAssemblyList(ClrDataAddress addr, int count, [In, Marsha return hr; } int ISOSDacInterface.GetAssemblyLocation(ClrDataAddress assembly, int count, char* location, uint* pNeeded) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int ISOSDacInterface.GetAssemblyModuleList(ClrDataAddress assembly, uint count, [In, MarshalUsing(CountElementName = "count"), Out] ClrDataAddress[]? modules, uint* pNeeded) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -515,6 +531,7 @@ int ISOSDacInterface.GetAssemblyModuleList(ClrDataAddress assembly, uint count, } int ISOSDacInterface.GetAssemblyName(ClrDataAddress assembly, uint count, char* name, uint* pNeeded) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -563,6 +580,7 @@ int ISOSDacInterface.GetAssemblyName(ClrDataAddress assembly, uint count, char* } int ISOSDacInterface.GetCCWData(ClrDataAddress ccw, DacpCCWData* data) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -632,6 +650,7 @@ int ISOSDacInterface.GetCCWData(ClrDataAddress ccw, DacpCCWData* data) } int ISOSDacInterface.GetCCWInterfaces(ClrDataAddress ccw, uint count, [In, MarshalUsing(CountElementName = nameof(count)), Out] DacpCOMInterfacePointerData[]? interfaces, uint* pNeeded) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; #if DEBUG int numWritten = 0; @@ -715,6 +734,7 @@ int ISOSDacInterface.GetCCWInterfaces(ClrDataAddress ccw, uint count, [In, Marsh } int ISOSDacInterface.GetClrWatsonBuckets(ClrDataAddress thread, void* pGenericModeBlock) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; byte[] buckets = Array.Empty(); try @@ -762,6 +782,7 @@ int ISOSDacInterface.GetClrWatsonBuckets(ClrDataAddress thread, void* pGenericMo } int ISOSDacInterface.GetCodeHeaderData(ClrDataAddress ip, DacpCodeHeaderData* data) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -846,6 +867,7 @@ int ISOSDacInterface.GetCodeHeaderData(ClrDataAddress ip, DacpCodeHeaderData* da } int ISOSDacInterface.GetCodeHeapList(ClrDataAddress jitManager, uint count, [In, MarshalUsing(CountElementName = nameof(count)), Out] DacpJitCodeHeapInfo[]? codeHeaps, uint* pNeeded) { + using Lock.Scope scope = _apiLock.EnterScope(); // returns the code heap list from the single global EEJitManager. int hr = HResults.S_OK; try @@ -928,9 +950,14 @@ int ISOSDacInterface.GetCodeHeapList(ClrDataAddress jitManager, uint count, [In, return hr; } int ISOSDacInterface.GetDacModuleHandle(void* phModule) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int ISOSDacInterface.GetDomainFromContext(ClrDataAddress context, ClrDataAddress* domain) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -958,6 +985,7 @@ int ISOSDacInterface.GetDomainFromContext(ClrDataAddress context, ClrDataAddress } int ISOSDacInterface.GetDomainLocalModuleData(ClrDataAddress addr, void* data) { + using Lock.Scope scope = _apiLock.EnterScope(); // CoreCLR does not use domain local modules anymore int hr = HResults.E_NOTIMPL; @@ -974,6 +1002,7 @@ int ISOSDacInterface.GetDomainLocalModuleData(ClrDataAddress addr, void* data) int ISOSDacInterface.GetDomainLocalModuleDataFromAppDomain(ClrDataAddress appDomainAddr, int moduleID, void* data) { + using Lock.Scope scope = _apiLock.EnterScope(); // CoreCLR does not support multi-appdomain shared assembly loading. Thus, a non-pointer sized moduleID cannot exist. int hr = HResults.E_INVALIDARG; @@ -989,6 +1018,7 @@ int ISOSDacInterface.GetDomainLocalModuleDataFromAppDomain(ClrDataAddress appDom } int ISOSDacInterface.GetDomainLocalModuleDataFromModule(ClrDataAddress moduleAddr, void* data) { + using Lock.Scope scope = _apiLock.EnterScope(); // CoreCLR does not use domain local modules anymore int hr = HResults.E_NOTIMPL; @@ -1003,13 +1033,26 @@ int ISOSDacInterface.GetDomainLocalModuleDataFromModule(ClrDataAddress moduleAdd return hr; } int ISOSDacInterface.GetFailedAssemblyData(ClrDataAddress assembly, uint* pContext, int* pResult) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int ISOSDacInterface.GetFailedAssemblyDisplayName(ClrDataAddress assembly, uint count, char* name, uint* pNeeded) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int ISOSDacInterface.GetFailedAssemblyList(ClrDataAddress appDomain, int count, [In, MarshalUsing(CountElementName = "count"), Out] ClrDataAddress[] values, uint* pNeeded) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int ISOSDacInterface.GetFailedAssemblyLocation(ClrDataAddress assembly, uint count, char* location, uint* pNeeded) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -1048,6 +1091,7 @@ int ISOSDacInterface.GetFailedAssemblyLocation(ClrDataAddress assembly, uint cou } int ISOSDacInterface.GetFieldDescData(ClrDataAddress fieldDesc, DacpFieldDescData* data) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -1178,6 +1222,7 @@ int ISOSDacInterface.GetFieldDescData(ClrDataAddress fieldDesc, DacpFieldDescDat int ISOSDacInterface.GetFrameName(ClrDataAddress vtable, uint count, char* frameName, uint* pNeeded) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -1227,6 +1272,7 @@ int ISOSDacInterface.GetFrameName(ClrDataAddress vtable, uint count, char* frame } int ISOSDacInterface.GetGCHeapData(DacpGcHeapData* data) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try @@ -1273,6 +1319,7 @@ int ISOSDacInterface.GetGCHeapData(DacpGcHeapData* data) } int ISOSDacInterface.GetGCHeapList(uint count, [In, MarshalUsing(CountElementName = "count"), Out] ClrDataAddress[] heaps, uint* pNeeded) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try @@ -1335,6 +1382,7 @@ int ISOSDacInterface.GetGCHeapList(uint count, [In, MarshalUsing(CountElementNam } int ISOSDacInterface.GetGCHeapDetails(ClrDataAddress heap, DacpGcHeapDetails* details) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try @@ -1468,6 +1516,7 @@ int ISOSDacInterface.GetGCHeapDetails(ClrDataAddress heap, DacpGcHeapDetails* de int ISOSDacInterface.GetGCHeapStaticData(DacpGcHeapDetails* details) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try @@ -1602,13 +1651,15 @@ int ISOSDacInterface.GetGCHeapStaticData(DacpGcHeapDetails* details) [GeneratedComClass] internal sealed unsafe partial class SOSHandleEnum : ISOSHandleEnum { + private readonly Lock _apiLock; private readonly Target _target; private readonly SOSHandleData[] _handles; private readonly ISOSHandleEnum? _legacyHandleEnum; private uint _index; - public SOSHandleEnum(Target target, HandleType[] types, ISOSHandleEnum? legacyHandleEnum) + public SOSHandleEnum(Target target, HandleType[] types, ISOSHandleEnum? legacyHandleEnum, Lock apiLock) { + _apiLock = apiLock; _target = target; _legacyHandleEnum = legacyHandleEnum; _handles = GetHandles(types); @@ -1644,6 +1695,7 @@ private SOSHandleData[] GetHandles(HandleType[] types) int ISOSHandleEnum.Next(uint count, SOSHandleData[] handles, uint* pNeeded) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -1690,6 +1742,7 @@ int ISOSHandleEnum.Next(uint count, SOSHandleData[] handles, uint* pNeeded) int ISOSEnum.Skip(uint count) { + using Lock.Scope scope = _apiLock.EnterScope(); _index += count; #if DEBUG _legacyHandleEnum?.Skip(count); @@ -1698,6 +1751,7 @@ int ISOSEnum.Skip(uint count) } int ISOSEnum.Reset() { + using Lock.Scope scope = _apiLock.EnterScope(); _index = 0; #if DEBUG _legacyHandleEnum?.Reset(); @@ -1706,6 +1760,7 @@ int ISOSEnum.Reset() } int ISOSEnum.GetCount(uint* pCount) { + using Lock.Scope scope = _apiLock.EnterScope(); if (pCount is null) return HResults.E_POINTER; *pCount = (uint)_handles.Length; #if DEBUG @@ -1723,12 +1778,14 @@ int ISOSEnum.GetCount(uint* pCount) [GeneratedComClass] internal sealed unsafe partial class SOSMemoryEnum : ISOSMemoryEnum { + private readonly Lock _apiLock; private readonly SOSMemoryRegion[] _regions; private readonly ISOSMemoryEnum? _legacyMemoryEnum; private uint _index; - public SOSMemoryEnum(Target target, IReadOnlyList regions, ISOSMemoryEnum? legacyMemoryEnum = null) + public SOSMemoryEnum(Target target, IReadOnlyList regions, ISOSMemoryEnum? legacyMemoryEnum, Lock apiLock) { + _apiLock = apiLock; _legacyMemoryEnum = legacyMemoryEnum; _regions = new SOSMemoryRegion[regions.Count]; for (int i = 0; i < regions.Count; i++) @@ -1743,14 +1800,16 @@ public SOSMemoryEnum(Target target, IReadOnlyList regions, I } } - public SOSMemoryEnum(SOSMemoryRegion[] regions, ISOSMemoryEnum? legacyMemoryEnum = null) + public SOSMemoryEnum(SOSMemoryRegion[] regions, ISOSMemoryEnum? legacyMemoryEnum, Lock apiLock) { + _apiLock = apiLock; _regions = regions; _legacyMemoryEnum = legacyMemoryEnum; } int ISOSMemoryEnum.Next(uint count, SOSMemoryRegion[] memRegions, uint* pNeeded) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -1793,6 +1852,7 @@ int ISOSMemoryEnum.Next(uint count, SOSMemoryRegion[] memRegions, uint* pNeeded) int ISOSEnum.Skip(uint count) { + using Lock.Scope scope = _apiLock.EnterScope(); _index += count; #if DEBUG _legacyMemoryEnum?.Skip(count); @@ -1802,6 +1862,7 @@ int ISOSEnum.Skip(uint count) int ISOSEnum.Reset() { + using Lock.Scope scope = _apiLock.EnterScope(); _index = 0; #if DEBUG _legacyMemoryEnum?.Reset(); @@ -1811,6 +1872,7 @@ int ISOSEnum.Reset() int ISOSEnum.GetCount(uint* pCount) { + using Lock.Scope scope = _apiLock.EnterScope(); if (pCount is null) return HResults.E_POINTER; *pCount = (uint)_regions.Length; @@ -1828,6 +1890,7 @@ int ISOSEnum.GetCount(uint* pCount) int ISOSDacInterface.GetHandleEnum(DacComNullableByRef ppHandleEnum) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -1843,7 +1906,7 @@ int ISOSDacInterface.GetHandleEnum(DacComNullableByRef ppHandleE legacyHandleEnum = legacyOut.Interface; } #endif - ppHandleEnum.Interface = new SOSHandleEnum(_target, supportedHandleTypes, legacyHandleEnum); + ppHandleEnum.Interface = new SOSHandleEnum(_target, supportedHandleTypes, legacyHandleEnum, _apiLock); } catch (System.Exception ex) { @@ -1852,9 +1915,14 @@ int ISOSDacInterface.GetHandleEnum(DacComNullableByRef ppHandleE return hr; } int ISOSDacInterface.GetHandleEnumForGC(uint gen, DacComNullableByRef ppHandleEnum) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int ISOSDacInterface.GetHandleEnumForTypes([In, MarshalUsing(CountElementName = "count")] uint[] types, uint count, DacComNullableByRef ppHandleEnum) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -1870,7 +1938,7 @@ int ISOSDacInterface.GetHandleEnumForTypes([In, MarshalUsing(CountElementName = #endif IGC gc = _target.Contracts.GC; HandleType[] handleTypes = gc.GetHandleTypes(types); - ppHandleEnum.Interface = new SOSHandleEnum(_target, handleTypes, legacyHandleEnum); + ppHandleEnum.Interface = new SOSHandleEnum(_target, handleTypes, legacyHandleEnum, _apiLock); } catch (System.Exception ex) { @@ -1879,9 +1947,14 @@ int ISOSDacInterface.GetHandleEnumForTypes([In, MarshalUsing(CountElementName = return hr; } int ISOSDacInterface.GetHeapAllocData(uint count, void* data, uint* pNeeded) - => HResults.E_NOTIMPL; + { + using Lock.Scope scope = _apiLock.EnterScope(); + + return HResults.E_NOTIMPL; + } int ISOSDacInterface.GetHeapAnalyzeData(ClrDataAddress addr, DacpGcHeapAnalyzeData* data) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -1927,6 +2000,7 @@ int ISOSDacInterface.GetHeapAnalyzeData(ClrDataAddress addr, DacpGcHeapAnalyzeDa } int ISOSDacInterface.GetHeapAnalyzeStaticData(DacpGcHeapAnalyzeData* data) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -1973,6 +2047,7 @@ int ISOSDacInterface.GetHeapAnalyzeStaticData(DacpGcHeapAnalyzeData* data) } int ISOSDacInterface.GetHeapSegmentData(ClrDataAddress seg, DacpHeapSegmentData* data) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -2042,6 +2117,7 @@ int ISOSDacInterface.GetHeapSegmentData(ClrDataAddress seg, DacpHeapSegmentData* int ISOSDacInterface.GetHillClimbingLogEntry(ClrDataAddress addr, void* data) { + using Lock.Scope scope = _apiLock.EnterScope(); // This API is not implemented by the legacy DAC int hr = HResults.E_NOTIMPL; @@ -2057,6 +2133,7 @@ int ISOSDacInterface.GetHillClimbingLogEntry(ClrDataAddress addr, void* data) } int ISOSDacInterface.GetILForModule(ClrDataAddress moduleAddr, int rva, ClrDataAddress* il) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -2089,6 +2166,7 @@ int ISOSDacInterface.GetILForModule(ClrDataAddress moduleAddr, int rva, ClrDataA } int ISOSDacInterface.GetJitHelperFunctionName(ClrDataAddress ip, uint count, byte* name, uint* pNeeded) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -2129,6 +2207,7 @@ int ISOSDacInterface.GetJitHelperFunctionName(ClrDataAddress ip, uint count, byt } int ISOSDacInterface.GetJitManagerList(uint count, DacpJitManagerInfo* managers, uint* pNeeded) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -2197,6 +2276,7 @@ private TargetPointer DecodeJump64(TargetPointer pThunk) int ISOSDacInterface.GetJumpThunkTarget(void* ctx, ClrDataAddress* targetIP, ClrDataAddress* targetMD) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -2247,6 +2327,7 @@ int ISOSDacInterface.GetJumpThunkTarget(void* ctx, ClrDataAddress* targetIP, Clr } int ISOSDacInterface.GetMethodDescData(ClrDataAddress addr, ClrDataAddress ip, DacpMethodDescData* data, uint cRevertedRejitVersions, DacpReJitData* rgRevertedRejitData, uint* pcNeededRevertedRejitData) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -2547,6 +2628,7 @@ private void CopyNativeCodeVersionToReJitData( int ISOSDacInterface.GetMethodDescFromToken(ClrDataAddress moduleAddr, uint token, ClrDataAddress* methodDesc) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -2594,6 +2676,7 @@ int ISOSDacInterface.GetMethodDescFromToken(ClrDataAddress moduleAddr, uint toke } int ISOSDacInterface.GetMethodDescName(ClrDataAddress addr, uint count, char* name, uint* pNeeded) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; if (pNeeded != null) *pNeeded = 0; @@ -2683,6 +2766,7 @@ int ISOSDacInterface.GetMethodDescName(ClrDataAddress addr, uint count, char* na int ISOSDacInterface.GetMethodDescPtrFromFrame(ClrDataAddress frameAddr, ClrDataAddress* ppMD) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -2718,6 +2802,7 @@ int ISOSDacInterface.GetMethodDescPtrFromFrame(ClrDataAddress frameAddr, ClrData } int ISOSDacInterface.GetMethodDescPtrFromIP(ClrDataAddress ip, ClrDataAddress* ppMD) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.E_NOTIMPL; try @@ -2770,6 +2855,7 @@ int ISOSDacInterface.GetMethodDescPtrFromIP(ClrDataAddress ip, ClrDataAddress* p int ISOSDacInterface.GetMethodDescTransparencyData(ClrDataAddress methodDesc, DacpMethodDescTransparencyData* data) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -2792,6 +2878,7 @@ int ISOSDacInterface.GetMethodDescTransparencyData(ClrDataAddress methodDesc, Da int ISOSDacInterface.GetMethodTableData(ClrDataAddress mt, DacpMethodTableData* data) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -2863,6 +2950,7 @@ int ISOSDacInterface.GetMethodTableData(ClrDataAddress mt, DacpMethodTableData* } int ISOSDacInterface.GetMethodTableFieldData(ClrDataAddress mt, DacpMethodTableFieldData* data) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -2905,6 +2993,7 @@ int ISOSDacInterface.GetMethodTableFieldData(ClrDataAddress mt, DacpMethodTableF } int ISOSDacInterface.GetMethodTableForEEClass(ClrDataAddress eeClassReallyCanonMT, ClrDataAddress* value) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -2934,6 +3023,7 @@ int ISOSDacInterface.GetMethodTableForEEClass(ClrDataAddress eeClassReallyCanonM int ISOSDacInterface.GetMethodTableName(ClrDataAddress mt, uint count, char* mtName, uint* pNeeded) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -3003,6 +3093,7 @@ int ISOSDacInterface.GetMethodTableName(ClrDataAddress mt, uint count, char* mtN int ISOSDacInterface.GetMethodTableSlot(ClrDataAddress mt, uint slot, ClrDataAddress* value) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; @@ -3073,6 +3164,7 @@ int ISOSDacInterface.GetMethodTableSlot(ClrDataAddress mt, uint slot, ClrDataAdd int ISOSDacInterface.GetMethodTableTransparencyData(ClrDataAddress mt, DacpMethodTableTransparencyData* data) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -3095,6 +3187,7 @@ int ISOSDacInterface.GetMethodTableTransparencyData(ClrDataAddress mt, DacpMetho int ISOSDacInterface.GetModule(ClrDataAddress addr, DacComNullableByRef mod) { + using Lock.Scope scope = _apiLock.EnterScope(); IXCLRDataModule? legacyModule = null; if (_legacyImpl is not null) { @@ -3105,13 +3198,14 @@ int ISOSDacInterface.GetModule(ClrDataAddress addr, DacComNullableByRef ppEnum) { + using Lock.Scope scope = _apiLock.EnterScope(); return HResults.E_NOTIMPL; } int ISOSEnum.Skip(uint count) { + using Lock.Scope scope = _apiLock.EnterScope(); _index = Math.Min(_index + count, (uint)_refs.Length); return HResults.S_OK; } int ISOSEnum.Reset() { + using Lock.Scope scope = _apiLock.EnterScope(); _index = 0; return HResults.S_OK; } int ISOSEnum.GetCount(uint* pCount) { + using Lock.Scope scope = _apiLock.EnterScope(); if (pCount is null) return HResults.E_POINTER; *pCount = (uint)_refs.Length; return HResults.S_OK; @@ -4036,6 +4150,7 @@ int ISOSEnum.GetCount(uint* pCount) int ISOSDacInterface.GetStackReferences(int osThreadID, DacComNullableByRef ppEnum) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -4086,7 +4201,7 @@ int ISOSDacInterface.GetStackReferences(int osThreadID, DacComNullableByRef pCallback, void* token) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; #if DEBUG List clausesLocal = new(); @@ -4772,6 +4900,7 @@ private int TraverseLoaderHeapCore(TargetPointer loaderHeapAddr, delegate* unman int ISOSDacInterface.TraverseLoaderHeap(ClrDataAddress loaderHeapAddr, delegate* unmanaged pCallback) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = TraverseLoaderHeapCore(loaderHeapAddr.ToTargetPointer(_target), pCallback); #if DEBUG if (_legacyImpl is not null) @@ -4809,6 +4938,7 @@ private static void TraverseModuleMapCallback(uint index, ulong moduleAddr, void #endif int ISOSDacInterface.TraverseModuleMap(ModuleMapType mmt, ClrDataAddress moduleAddr, delegate* unmanaged pCallback, void* token) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; IEnumerable<(TargetPointer Address, uint Index)> elements = Enumerable.Empty<(TargetPointer, uint)>(); try @@ -4874,6 +5004,7 @@ private static Interop.BOOL TraverseRCWCleanupListCallback(ulong rcwAddr, ulong #endif int ISOSDacInterface.TraverseRCWCleanupList(ClrDataAddress cleanupListPtr, delegate* unmanaged pCallback, void* token) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; IEnumerable cleanupInfos = Enumerable.Empty(); try @@ -4918,6 +5049,7 @@ int ISOSDacInterface.TraverseRCWCleanupList(ClrDataAddress cleanupListPtr, deleg } int ISOSDacInterface.TraverseVirtCallStubHeap(ClrDataAddress pAppDomain, VCSHeapType heaptype, delegate* unmanaged pCallback) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -4972,6 +5104,7 @@ int ISOSDacInterface.TraverseVirtCallStubHeap(ClrDataAddress pAppDomain, VCSHeap #region ISOSDacInterface2 int ISOSDacInterface2.GetObjectExceptionData(ClrDataAddress objectAddress, DacpExceptionObjectData* data) { + using Lock.Scope scope = _apiLock.EnterScope(); try { Contracts.IException contract = _target.Contracts.Exception; @@ -4995,6 +5128,7 @@ int ISOSDacInterface2.GetObjectExceptionData(ClrDataAddress objectAddress, DacpE int ISOSDacInterface2.IsRCWDCOMProxy(ClrDataAddress rcwAddress, int* inDCOMProxy) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -5032,6 +5166,7 @@ int ISOSDacInterface2.IsRCWDCOMProxy(ClrDataAddress rcwAddress, int* inDCOMProxy #region ISOSDacInterface3 int ISOSDacInterface3.GetGCInterestingInfoData(ClrDataAddress interestingInfoAddr, DacpGCInterestingInfoData* data) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try @@ -5074,6 +5209,7 @@ int ISOSDacInterface3.GetGCInterestingInfoData(ClrDataAddress interestingInfoAdd int ISOSDacInterface3.GetGCInterestingInfoStaticData(DacpGCInterestingInfoData* data) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try @@ -5181,6 +5317,7 @@ private static void VerifyGCInterestingInfoData(DacpGCInterestingInfoData* cdacD int ISOSDacInterface3.GetGCGlobalMechanisms(nuint* globalMechanisms) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -5235,6 +5372,7 @@ int ISOSDacInterface3.GetGCGlobalMechanisms(nuint* globalMechanisms) #region ISOSDacInterface4 int ISOSDacInterface4.GetClrNotification(ClrDataAddress[] arguments, int count, int* pNeeded) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; _target.TryReadGlobal(Constants.Globals.MaxClrNotificationArgs, out uint? maxArgs); uint MaxClrNotificationArgs = maxArgs ?? 0; @@ -5283,6 +5421,7 @@ int ISOSDacInterface5.GetTieredVersions( int cNativeCodeAddrs, int* pcNativeCodeAddrs) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -5414,6 +5553,7 @@ int ISOSDacInterface5.GetTieredVersions( #region ISOSDacInterface6 int ISOSDacInterface6.GetMethodTableCollectibleData(ClrDataAddress mt, DacpMethodTableCollectibleData* data) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -5459,6 +5599,7 @@ int ISOSDacInterface6.GetMethodTableCollectibleData(ClrDataAddress mt, DacpMetho #region ISOSDacInterface7 int ISOSDacInterface7.GetPendingReJITID(ClrDataAddress methodDesc, int* pRejitId) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -5503,6 +5644,7 @@ int ISOSDacInterface7.GetPendingReJITID(ClrDataAddress methodDesc, int* pRejitId } int ISOSDacInterface7.GetReJITInformation(ClrDataAddress methodDesc, int rejitId, DacpReJitData2* pRejitData) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -5563,6 +5705,7 @@ int ISOSDacInterface7.GetReJITInformation(ClrDataAddress methodDesc, int rejitId } int ISOSDacInterface7.GetProfilerModifiedILInformation(ClrDataAddress methodDesc, DacpProfilerILData* pILData) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -5623,6 +5766,7 @@ int ISOSDacInterface7.GetProfilerModifiedILInformation(ClrDataAddress methodDesc } int ISOSDacInterface7.GetMethodsWithProfilerModifiedIL(ClrDataAddress mod, ClrDataAddress* methodDescs, int cMethodDescs, int* pcMethodDescs) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -5696,6 +5840,7 @@ int ISOSDacInterface7.GetMethodsWithProfilerModifiedIL(ClrDataAddress mod, ClrDa #region ISOSDacInterface8 int ISOSDacInterface8.GetNumberGenerations(uint* pGenerations) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -5731,6 +5876,7 @@ int ISOSDacInterface8.GetNumberGenerations(uint* pGenerations) int ISOSDacInterface8.GetGenerationTable(uint cGenerations, DacpGenerationData* pGenerationData, uint* pNeeded) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -5800,6 +5946,7 @@ int ISOSDacInterface8.GetGenerationTable(uint cGenerations, DacpGenerationData* int ISOSDacInterface8.GetFinalizationFillPointers(uint cFillPointers, ClrDataAddress* pFinalizationFillPointers, uint* pNeeded) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -5862,6 +6009,7 @@ int ISOSDacInterface8.GetFinalizationFillPointers(uint cFillPointers, ClrDataAdd int ISOSDacInterface8.GetGenerationTableSvr(ClrDataAddress heapAddr, uint cGenerations, DacpGenerationData* pGenerationData, uint* pNeeded) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -5931,6 +6079,7 @@ int ISOSDacInterface8.GetGenerationTableSvr(ClrDataAddress heapAddr, uint cGener int ISOSDacInterface8.GetFinalizationFillPointersSvr(ClrDataAddress heapAddr, uint cFillPointers, ClrDataAddress* pFinalizationFillPointers, uint* pNeeded) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -5994,6 +6143,7 @@ int ISOSDacInterface8.GetFinalizationFillPointersSvr(ClrDataAddress heapAddr, ui int ISOSDacInterface8.GetAssemblyLoadContext(ClrDataAddress methodTable, ClrDataAddress* assemblyLoadContext) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -6030,6 +6180,7 @@ int ISOSDacInterface8.GetAssemblyLoadContext(ClrDataAddress methodTable, ClrData #region ISOSDacInterface9 int ISOSDacInterface9.GetBreakingChangeVersion() { + using Lock.Scope scope = _apiLock.EnterScope(); int version = _target.ReadGlobal(Constants.Globals.SOSBreakingChangeVersion); #if DEBUG @@ -6045,6 +6196,7 @@ int ISOSDacInterface9.GetBreakingChangeVersion() #region ISOSDacInterface10 int ISOSDacInterface10.GetObjectComWrappersData(ClrDataAddress objAddr, ClrDataAddress* rcw, uint count, [In, MarshalUsing(CountElementName = "count"), Out] ClrDataAddress[]? mowList, uint* pNeeded) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_FALSE; try { @@ -6118,6 +6270,7 @@ int ISOSDacInterface10.GetObjectComWrappersData(ClrDataAddress objAddr, ClrDataA } int ISOSDacInterface10.IsComWrappersCCW(ClrDataAddress ccw, Interop.BOOL* isComWrappersCCW) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -6152,6 +6305,7 @@ int ISOSDacInterface10.IsComWrappersCCW(ClrDataAddress ccw, Interop.BOOL* isComW } int ISOSDacInterface10.GetComWrappersCCWData(ClrDataAddress ccw, ClrDataAddress* managedObject, int* refCount) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -6196,6 +6350,7 @@ int ISOSDacInterface10.GetComWrappersCCWData(ClrDataAddress ccw, ClrDataAddress* } int ISOSDacInterface10.IsComWrappersRCW(ClrDataAddress rcw, Interop.BOOL* isComWrappersRCW) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -6234,6 +6389,7 @@ int ISOSDacInterface10.IsComWrappersRCW(ClrDataAddress rcw, Interop.BOOL* isComW } int ISOSDacInterface10.GetComWrappersRCWData(ClrDataAddress rcw, ClrDataAddress* identity) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -6271,6 +6427,7 @@ int ISOSDacInterface10.GetComWrappersRCWData(ClrDataAddress rcw, ClrDataAddress* #region ISOSDacInterface11 int ISOSDacInterface11.IsTrackedType(ClrDataAddress objAddr, Interop.BOOL* isTrackedType, Interop.BOOL* hasTaggedMemory) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -6324,6 +6481,7 @@ int ISOSDacInterface11.IsTrackedType(ClrDataAddress objAddr, Interop.BOOL* isTra int ISOSDacInterface11.GetTaggedMemory(ClrDataAddress objAddr, ClrDataAddress* taggedMemory, nuint* taggedMemorySizeInBytes) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_FALSE; try { @@ -6370,6 +6528,7 @@ int ISOSDacInterface11.GetTaggedMemory(ClrDataAddress objAddr, ClrDataAddress* t #region ISOSDacInterface12 int ISOSDacInterface12.GetGlobalAllocationContext(ClrDataAddress* allocPtr, ClrDataAddress* allocLimit) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -6408,6 +6567,7 @@ int ISOSDacInterface12.GetGlobalAllocationContext(ClrDataAddress* allocPtr, ClrD int ISOSDacInterface13.TraverseLoaderHeap(ClrDataAddress loaderHeapAddr, /*LoaderHeapKind*/ int kind, /*VISITHEAP*/ delegate* unmanaged pCallback) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = TraverseLoaderHeapCore(loaderHeapAddr.ToTargetPointer(_target), pCallback); #if DEBUG if (_legacyImpl13 is not null) @@ -6429,6 +6589,7 @@ int ISOSDacInterface13.TraverseLoaderHeap(ClrDataAddress loaderHeapAddr, /*Loade } int ISOSDacInterface13.GetDomainLoaderAllocator(ClrDataAddress domainAddress, ClrDataAddress* pLoaderAllocator) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -6523,6 +6684,7 @@ private static (LoaderAllocatorHeapType heapType, nint AnsiPtr)[] InitializeHeap int ISOSDacInterface13.GetLoaderAllocatorHeapNames(int count, char** ppNames, int* pNeeded) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -6571,6 +6733,7 @@ int ISOSDacInterface13.GetLoaderAllocatorHeapNames(int count, char** ppNames, in } int ISOSDacInterface13.GetLoaderAllocatorHeaps(ClrDataAddress loaderAllocator, int count, ClrDataAddress* pLoaderHeaps, /*LoaderHeapKind*/ int* pKinds, int* pNeeded) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -6632,6 +6795,7 @@ int ISOSDacInterface13.GetLoaderAllocatorHeaps(ClrDataAddress loaderAllocator, i int ISOSDacInterface13.GetHandleTableMemoryRegions(DacComNullableByRef ppEnum) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -6646,7 +6810,7 @@ int ISOSDacInterface13.GetHandleTableMemoryRegions(DacComNullableByRef ppEnum) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -6671,7 +6836,7 @@ int ISOSDacInterface13.GetGCBookkeepingMemoryRegions(DacComNullableByRef ppEnum) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -6696,7 +6862,7 @@ int ISOSDacInterface13.GetGCFreeRegions(DacComNullableByRef ppEn legacyMemoryEnum = legacyOut.Interface; } #endif - ppEnum.Interface = new SOSMemoryEnum(_target, regions, legacyMemoryEnum); + ppEnum.Interface = new SOSMemoryEnum(_target, regions, legacyMemoryEnum, _apiLock); } catch (System.Exception e) { @@ -6707,6 +6873,7 @@ int ISOSDacInterface13.GetGCFreeRegions(DacComNullableByRef ppEn } int ISOSDacInterface13.LockedFlush() { + using Lock.Scope scope = _apiLock.EnterScope(); _target.Flush(FlushScope.All); // As long as any part of cDAC falls back to the legacy DAC, we need to propagate the Flush call @@ -6720,6 +6887,7 @@ int ISOSDacInterface13.LockedFlush() #region ISOSDacInterface14 int ISOSDacInterface14.GetStaticBaseAddress(ClrDataAddress methodTable, ClrDataAddress* nonGCStaticsAddress, ClrDataAddress* GCStaticsAddress) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -6759,6 +6927,7 @@ int ISOSDacInterface14.GetStaticBaseAddress(ClrDataAddress methodTable, ClrDataA } int ISOSDacInterface14.GetThreadStaticBaseAddress(ClrDataAddress methodTable, ClrDataAddress thread, ClrDataAddress* nonGCStaticsAddress, ClrDataAddress* GCStaticsAddress) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -6814,6 +6983,7 @@ int ISOSDacInterface14.GetThreadStaticBaseAddress(ClrDataAddress methodTable, Cl int ISOSDacInterface14.GetMethodTableInitializationFlags(ClrDataAddress methodTable, MethodTableInitializationFlags* initializationStatus) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -6855,6 +7025,7 @@ int ISOSDacInterface14.GetMethodTableInitializationFlags(ClrDataAddress methodTa [GeneratedComClass] internal sealed unsafe partial class SOSMethodEnum : ISOSMethodEnum { + private readonly Lock _apiLock; private readonly Target _target; private readonly IRuntimeTypeSystem _rts; private readonly ITypeHandle _methodTable; @@ -6864,8 +7035,9 @@ internal sealed unsafe partial class SOSMethodEnum : ISOSMethodEnum private uint _iteratorIndex; private List _methods = []; - public SOSMethodEnum(Target target, ITypeHandle methodTable, ISOSMethodEnum? legacyMethodEnum) + public SOSMethodEnum(Target target, ITypeHandle methodTable, ISOSMethodEnum? legacyMethodEnum, Lock apiLock) { + _apiLock = apiLock; _target = target; _rts = _target.Contracts.RuntimeTypeSystem; _methodTable = methodTable; @@ -6940,6 +7112,7 @@ private void PopulateMethods() int ISOSMethodEnum.Next(uint count, [In, Out, MarshalUsing(CountElementName = nameof(count))] SOSMethodData[] values, uint* pNeeded) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -6992,6 +7165,7 @@ int ISOSMethodEnum.Next(uint count, [In, Out, MarshalUsing(CountElementName = na int ISOSEnum.Skip(uint count) { + using Lock.Scope scope = _apiLock.EnterScope(); _iteratorIndex += count; #if DEBUG _legacyMethodEnum?.Skip(count); @@ -7001,6 +7175,7 @@ int ISOSEnum.Skip(uint count) int ISOSEnum.Reset() { + using Lock.Scope scope = _apiLock.EnterScope(); _iteratorIndex = 0; #if DEBUG _legacyMethodEnum?.Reset(); @@ -7010,6 +7185,7 @@ int ISOSEnum.Reset() int ISOSEnum.GetCount(uint* pCount) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -7035,6 +7211,7 @@ int ISOSEnum.GetCount(uint* pCount) int ISOSDacInterface15.GetMethodTableSlotEnumerator(ClrDataAddress mt, DacComNullableByRef enumerator) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try @@ -7056,7 +7233,7 @@ int ISOSDacInterface15.GetMethodTableSlotEnumerator(ClrDataAddress mt, DacComNul } #endif - enumerator.Interface = new SOSMethodEnum(_target, methodTableHandle, legacyMethodEnum); + enumerator.Interface = new SOSMethodEnum(_target, methodTableHandle, legacyMethodEnum, _apiLock); } catch (System.Exception ex) { @@ -7070,6 +7247,7 @@ int ISOSDacInterface15.GetMethodTableSlotEnumerator(ClrDataAddress mt, DacComNul #region ISOSDacInterface16 int ISOSDacInterface16.GetGCDynamicAdaptationMode(int* pDynamicAdaptationMode) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try @@ -7114,16 +7292,19 @@ int ISOSDacInterface16.GetGCDynamicAdaptationMode(int* pDynamicAdaptationMode) [GeneratedComClass] internal sealed unsafe partial class SOSStressLogThreadEnum : ISOSStressLogThreadEnum { + private readonly Lock _apiLock; private readonly SOSThreadStressLogData[] _threads; private uint _index; - public SOSStressLogThreadEnum(SOSThreadStressLogData[] threads) + public SOSStressLogThreadEnum(SOSThreadStressLogData[] threads, Lock apiLock) { + _apiLock = apiLock; _threads = threads; } int ISOSStressLogThreadEnum.Next(uint count, SOSThreadStressLogData[] values, uint* pFetched) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -7149,18 +7330,21 @@ int ISOSStressLogThreadEnum.Next(uint count, SOSThreadStressLogData[] values, ui int ISOSEnum.Skip(uint count) { + using Lock.Scope scope = _apiLock.EnterScope(); _index = Math.Min(_index + count, (uint)_threads.Length); return HResults.S_OK; } int ISOSEnum.Reset() { + using Lock.Scope scope = _apiLock.EnterScope(); _index = 0; return HResults.S_OK; } int ISOSEnum.GetCount(uint* pCount) { + using Lock.Scope scope = _apiLock.EnterScope(); if (pCount is null) return HResults.E_POINTER; *pCount = (uint)_threads.Length; return HResults.S_OK; @@ -7170,20 +7354,23 @@ int ISOSEnum.GetCount(uint* pCount) [GeneratedComClass] internal sealed unsafe partial class SOSStressLogMsgEnum : ISOSStressLogMsgEnum { + private readonly Lock _apiLock; private readonly Target _target; private readonly Contracts.StressMsgData[] _messages; private uint _index; private uint _lastBatchStart; private uint _lastBatchCount; - public SOSStressLogMsgEnum(Target target, IEnumerable messages) + public SOSStressLogMsgEnum(Target target, IEnumerable messages, Lock apiLock) { + _apiLock = apiLock; _target = target; _messages = messages.ToArray(); } int ISOSStressLogMsgEnum.Next(uint count, SOSStressMsgData[] values, uint* pFetched) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -7222,6 +7409,7 @@ int ISOSStressLogMsgEnum.Next(uint count, SOSStressMsgData[] values, uint* pFetc int ISOSStressLogMsgEnum.GetArguments(uint messageIndex, uint argCount, ClrDataAddress[] args, uint* pFetched) { + using Lock.Scope scope = _apiLock.EnterScope(); if (pFetched is null || args is null) return HResults.E_POINTER; @@ -7243,12 +7431,14 @@ int ISOSStressLogMsgEnum.GetArguments(uint messageIndex, uint argCount, ClrDataA int ISOSEnum.Skip(uint count) { + using Lock.Scope scope = _apiLock.EnterScope(); _index = Math.Min(_index + count, (uint)_messages.Length); return HResults.S_OK; } int ISOSEnum.Reset() { + using Lock.Scope scope = _apiLock.EnterScope(); _index = 0; _lastBatchStart = 0; _lastBatchCount = 0; @@ -7257,6 +7447,7 @@ int ISOSEnum.Reset() int ISOSEnum.GetCount(uint* pCount) { + using Lock.Scope scope = _apiLock.EnterScope(); if (pCount is null) return HResults.E_POINTER; *pCount = (uint)_messages.Length; return HResults.S_OK; @@ -7265,6 +7456,7 @@ int ISOSEnum.GetCount(uint* pCount) int ISOSDacInterface17.GetStressLogData(SOSStressLogData* data) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -7297,6 +7489,7 @@ int ISOSDacInterface17.GetStressLogData(SOSStressLogData* data) int ISOSDacInterface17.GetStressLogThreadEnumerator(DacComNullableByRef ppEnum) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -7313,7 +7506,7 @@ int ISOSDacInterface17.GetStressLogThreadEnumerator(DacComNullableByRef ppEnum) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -7336,7 +7530,7 @@ int ISOSDacInterface17.GetStressLogMessageEnumerator( TargetPointer address = threadStressLogAddress.ToTargetPointer(_target); IEnumerable messages = stressLogContract.GetStressMessages(address); - ppEnum.Interface = new SOSStressLogMsgEnum(_target, messages); + ppEnum.Interface = new SOSStressLogMsgEnum(_target, messages, _apiLock); } catch (System.Exception ex) { @@ -7348,6 +7542,7 @@ int ISOSDacInterface17.GetStressLogMessageEnumerator( int ISOSDacInterface17.GetStressLogMemoryRanges(DacComNullableByRef ppEnum) { + using Lock.Scope scope = _apiLock.EnterScope(); int hr = HResults.S_OK; try { @@ -7366,7 +7561,7 @@ int ISOSDacInterface17.GetStressLogMemoryRanges(DacComNullableByRef.ConvertToUnmanaged(impl); *obj = ptr; return 0; @@ -221,8 +234,8 @@ private static unsafe int CreateDacDbiInterface(IntPtr handle, IntPtr legacyImpl return HResults.E_NOTIMPL; } - Target? target = GCHandle.FromIntPtr(handle).Target as Target; - if (target is null) + CdacHandle? cdacHandle = GCHandle.FromIntPtr(handle).Target as CdacHandle; + if (cdacHandle is null) { *obj = IntPtr.Zero; return HResults.E_INVALIDARG; @@ -233,7 +246,7 @@ private static unsafe int CreateDacDbiInterface(IntPtr handle, IntPtr legacyImpl legacyObj = UniqueComInterfaceMarshaller.ConvertToManaged((void*)legacyImplPtr); } - Legacy.DacDbiImpl impl = new(target, legacyObj); + Legacy.DacDbiImpl impl = new(cdacHandle.Target, legacyObj, cdacHandle.ApiLock); *obj = (nint)ComInterfaceMarshaller.ConvertToUnmanaged(impl); legacyObj = null; return HResults.S_OK; @@ -288,7 +301,7 @@ private static unsafe int DacDbiInterfaceInstance( UniqueComInterfaceMarshaller.ConvertToManaged((void*)pTarget)!; dataTargetComObject = (ComObject)(object)dataTarget; ContractDescriptorTarget target = CreateTargetFromCorDebugDataTarget(dataTarget, contractDescriptorAddress); - Legacy.DacDbiImpl impl = new(target, legacyObj: null, dataTargetComObject: dataTargetComObject); + Legacy.DacDbiImpl impl = new(target, legacyObj: null, apiLock: new Lock(), dataTargetComObject: dataTargetComObject); *iface = ComInterfaceMarshaller.ConvertToUnmanaged(impl); dataTargetComObject = null; return HResults.S_OK; @@ -327,7 +340,7 @@ private static unsafe int DbgShimCreateInstanceFromContractDescriptor(Guid* pIID try { object legacyTarget = ComInterfaceMarshaller.ConvertToManaged((void*)pLegacyTarget)!; - return CreateInstanceFromContractDescriptorCore(pIID, legacyTarget, contractDescriptorAddr, legacyImpl: null, iface); + return CreateInstanceFromContractDescriptorCore(pIID, legacyTarget, contractDescriptorAddr, legacyImpl: null, new Lock(), iface); } catch (Exception ex) { @@ -344,7 +357,7 @@ private static unsafe int CLRDataCreateInstanceImpl(Guid* pIID, IntPtr /*ICLRDat try { - return CLRDataCreateInstanceCore(pIID, pLegacyTarget, pLegacyImpl, iface); + return CLRDataCreateInstanceCore(pIID, pLegacyTarget, pLegacyImpl, new Lock(), iface); } catch (Exception ex) { @@ -353,7 +366,7 @@ private static unsafe int CLRDataCreateInstanceImpl(Guid* pIID, IntPtr /*ICLRDat } } - private static unsafe int CLRDataCreateInstanceCore(Guid* pIID, IntPtr /*ICLRDataTarget*/ pLegacyTarget, IntPtr pLegacyImpl, void** iface) + private static unsafe int CLRDataCreateInstanceCore(Guid* pIID, IntPtr /*ICLRDataTarget*/ pLegacyTarget, IntPtr pLegacyImpl, Lock apiLock, void** iface) { object legacyTarget = ComInterfaceMarshaller.ConvertToManaged((void*)pLegacyTarget)!; object? legacyImpl = pLegacyImpl != IntPtr.Zero ? @@ -373,10 +386,10 @@ private static unsafe int CLRDataCreateInstanceCore(Guid* pIID, IntPtr /*ICLRDat }; } - return CreateInstanceFromContractDescriptorCore(pIID, legacyTarget, contractAddress, legacyImpl, iface); + return CreateInstanceFromContractDescriptorCore(pIID, legacyTarget, contractAddress, legacyImpl, apiLock, iface); } - private static unsafe int CreateInstanceFromContractDescriptorCore(Guid* pIID, object legacyTarget, ulong contractAddress, object? legacyImpl, void** iface) + private static unsafe int CreateInstanceFromContractDescriptorCore(Guid* pIID, object legacyTarget, ulong contractAddress, object? legacyImpl, Lock apiLock, void** iface) { ICLRDataTarget dataTarget = legacyTarget as ICLRDataTarget ?? throw new ArgumentException( $"Data target does not implement {nameof(ICLRDataTarget)}", nameof(legacyTarget)); @@ -460,7 +473,7 @@ private static unsafe int CreateInstanceFromContractDescriptorCore(Guid* pIID, o if (legacyImpl is null) Contracts.CoreCLRContracts.ValidateForDataAccess(target); - Legacy.SOSDacImpl impl = new(target, legacyImpl); + Legacy.SOSDacImpl impl = new(target, legacyImpl, apiLock); void* ccw = ComInterfaceMarshaller.ConvertToUnmanaged(impl); int hrQI = Marshal.QueryInterface((nint)ccw, *pIID, out nint ptrToIface); diff --git a/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiAppDomainDumpTests.cs b/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiAppDomainDumpTests.cs index 376c60525c10..a21b0daecc74 100644 --- a/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiAppDomainDumpTests.cs +++ b/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiAppDomainDumpTests.cs @@ -17,7 +17,7 @@ public class DacDbiAppDomainDumpTests : DumpTestBase protected override string DebuggeeName => "BasicThreads"; protected override string DumpType => "full"; - private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null); + private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null, new()); [ConditionalTheory] [MemberData(nameof(TestConfigurations))] diff --git a/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiApproxTypeHandleDumpTests.cs b/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiApproxTypeHandleDumpTests.cs index a2aa905e690a..8a60d575c42b 100644 --- a/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiApproxTypeHandleDumpTests.cs +++ b/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiApproxTypeHandleDumpTests.cs @@ -34,7 +34,7 @@ public class DacDbiApproxTypeHandleDumpTests : DumpTestBase { protected override string DebuggeeName => "ExactTypeHandle"; - private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null); + private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null, new()); /// /// All non-null heap objects reachable from Strong / Pinned / WeakLong / Dependent handles diff --git a/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiCCWDumpTests.cs b/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiCCWDumpTests.cs index af14669cd4e5..8486fa57ec87 100644 --- a/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiCCWDumpTests.cs +++ b/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiCCWDumpTests.cs @@ -19,7 +19,7 @@ public class DacDbiCCWDumpTests : DumpTestBase { protected override string DebuggeeName => "CCW"; protected override string DumpType => "full"; - private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null); + private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null, new()); private (TargetPointer Ccw, TargetPointer InterfacePointer) FindBuiltInComCcwWithInterface() { diff --git a/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiComWrappersDumpTests.cs b/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiComWrappersDumpTests.cs index 18ca20946ff6..3262d6a17448 100644 --- a/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiComWrappersDumpTests.cs +++ b/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiComWrappersDumpTests.cs @@ -17,7 +17,7 @@ namespace Microsoft.Diagnostics.DataContractReader.DumpTests; public class DacDbiComWrappersDumpTests : DumpTestBase { protected override string DebuggeeName => "ComWrappers"; - private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null); + private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null, new()); [ConditionalTheory] [MemberData(nameof(TestConfigurations))] diff --git a/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiDebuggerDumpTests.cs b/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiDebuggerDumpTests.cs index ce5adeb61cf4..a91f2d7a2586 100644 --- a/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiDebuggerDumpTests.cs +++ b/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiDebuggerDumpTests.cs @@ -17,7 +17,7 @@ public class DacDbiDebuggerDumpTests : DumpTestBase protected override string DebuggeeName => "BasicThreads"; protected override string DumpType => "full"; - private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null); + private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null, new()); [ConditionalTheory] [MemberData(nameof(TestConfigurations))] diff --git a/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiExactTypeHandleDumpTests.cs b/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiExactTypeHandleDumpTests.cs index 83f0996a2d50..59fc43f82294 100644 --- a/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiExactTypeHandleDumpTests.cs +++ b/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiExactTypeHandleDumpTests.cs @@ -27,7 +27,7 @@ public class DacDbiExactTypeHandleDumpTests : DumpTestBase { protected override string DebuggeeName => "ExactTypeHandle"; - private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null); + private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null, new()); /// /// All non-null heap objects reachable from Strong / Pinned / WeakLong / Dependent handles diff --git a/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiGCDumpTests.cs b/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiGCDumpTests.cs index 5665d0c4cd22..b1d277d3072f 100644 --- a/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiGCDumpTests.cs +++ b/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiGCDumpTests.cs @@ -17,7 +17,7 @@ public class DacDbiGCDumpTests : DumpTestBase protected override string DebuggeeName => "BasicThreads"; protected override string DumpType => "full"; - private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null); + private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null, new()); [ConditionalTheory] [MemberData(nameof(TestConfigurations))] diff --git a/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiHeapWalkDumpTests.cs b/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiHeapWalkDumpTests.cs index ae010f8b8f55..b334d4525f05 100644 --- a/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiHeapWalkDumpTests.cs +++ b/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiHeapWalkDumpTests.cs @@ -19,7 +19,7 @@ public class DacDbiHeapWalkDumpTests : DumpTestBase { protected override string DebuggeeName => "GCRoots"; - private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null); + private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null, new()); /// /// Drives to completion and returns every diff --git a/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiLoaderDumpTests.cs b/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiLoaderDumpTests.cs index 1dfce0799bb9..4b9ddf9d7128 100644 --- a/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiLoaderDumpTests.cs +++ b/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiLoaderDumpTests.cs @@ -16,7 +16,7 @@ namespace Microsoft.Diagnostics.DataContractReader.DumpTests; public class DacDbiLoaderDumpTests : DumpTestBase { protected override string DebuggeeName => "StackRefs"; - private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null); + private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null, new()); private IEnumerable GetAllModules() { diff --git a/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiMultiModuleDumpTests.cs b/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiMultiModuleDumpTests.cs index 6067e6bd6060..3e0087a4e3ed 100644 --- a/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiMultiModuleDumpTests.cs +++ b/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiMultiModuleDumpTests.cs @@ -20,7 +20,7 @@ public class DacDbiMultiModuleDumpTests : DumpTestBase { protected override string DebuggeeName => "MultiModule"; - private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null); + private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null, new()); private IEnumerable GetAllModules() { diff --git a/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiObjectDumpTests.cs b/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiObjectDumpTests.cs index 6145d1b2aaf0..9955f5080af6 100644 --- a/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiObjectDumpTests.cs +++ b/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiObjectDumpTests.cs @@ -19,7 +19,7 @@ public class DacDbiObjectDumpTests : DumpTestBase protected override string DebuggeeName => "BasicThreads"; protected override string DumpType => "full"; - private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null); + private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null, new()); [ConditionalTheory] [MemberData(nameof(TestConfigurations))] diff --git a/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiRCWDumpTests.cs b/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiRCWDumpTests.cs index 8b553d971d8c..4d4f88a4c690 100644 --- a/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiRCWDumpTests.cs +++ b/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiRCWDumpTests.cs @@ -17,7 +17,7 @@ public class DacDbiRCWDumpTests : DumpTestBase { protected override string DebuggeeName => "RCW"; protected override string DumpType => "full"; - private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null); + private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null, new()); [ConditionalTheory] [MemberData(nameof(TestConfigurations))] diff --git a/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiRefWalkDumpTests.cs b/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiRefWalkDumpTests.cs index c05efc91fe18..d013c487b017 100644 --- a/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiRefWalkDumpTests.cs +++ b/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiRefWalkDumpTests.cs @@ -20,7 +20,7 @@ public class DacDbiRefWalkDumpTests : DumpTestBase { protected override string DebuggeeName => "GCRoots"; - private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null); + private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null, new()); /// /// Drives to completion and returns every reference reported. diff --git a/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiStackWalkDumpTests.cs b/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiStackWalkDumpTests.cs index 4e2d160be0ec..bec70f3d9437 100644 --- a/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiStackWalkDumpTests.cs +++ b/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiStackWalkDumpTests.cs @@ -21,7 +21,7 @@ public class DacDbiStackWalkDumpTests : DumpTestBase protected override string DebuggeeName => "StackWalk"; protected override string DumpType => "full"; - private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null); + private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null, new()); [ConditionalTheory] [MemberData(nameof(TestConfigurations))] diff --git a/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiThreadDumpTests.cs b/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiThreadDumpTests.cs index f641c93755cb..accc7a411673 100644 --- a/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiThreadDumpTests.cs +++ b/src/runtime/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiThreadDumpTests.cs @@ -21,7 +21,7 @@ public class DacDbiThreadDumpTests : DumpTestBase protected override string DebuggeeName => "BasicThreads"; protected override string DumpType => "full"; - private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null); + private DacDbiImpl CreateDacDbi() => new DacDbiImpl(Target, legacyObj: null, new()); [ConditionalTheory] [MemberData(nameof(TestConfigurations))] diff --git a/src/runtime/src/native/managed/cdac/tests/DumpTests/ISOSDacInterface13Tests.cs b/src/runtime/src/native/managed/cdac/tests/DumpTests/ISOSDacInterface13Tests.cs index 9715eb1da1aa..66dc9a0f44de 100644 --- a/src/runtime/src/native/managed/cdac/tests/DumpTests/ISOSDacInterface13Tests.cs +++ b/src/runtime/src/native/managed/cdac/tests/DumpTests/ISOSDacInterface13Tests.cs @@ -22,7 +22,7 @@ public class ISOSDacInterface13Tests : DumpTestBase public unsafe void GetLoaderAllocatorHeapNames_MatchExpectedOrder(TestConfiguration config) { InitializeDumpTest(config); - ISOSDacInterface13 sosDac = (ISOSDacInterface13)new SOSDacImpl(Target, legacyObj: null); + ISOSDacInterface13 sosDac = (ISOSDacInterface13)new SOSDacImpl(Target, legacyObj: null, new()); int heapCount; int hr = sosDac.GetLoaderAllocatorHeapNames(0, null, &heapCount); diff --git a/src/runtime/src/native/managed/cdac/tests/DumpTests/ISOSDacInterfaceTests.cs b/src/runtime/src/native/managed/cdac/tests/DumpTests/ISOSDacInterfaceTests.cs index 832bf838f99f..b51c1f79cf67 100644 --- a/src/runtime/src/native/managed/cdac/tests/DumpTests/ISOSDacInterfaceTests.cs +++ b/src/runtime/src/native/managed/cdac/tests/DumpTests/ISOSDacInterfaceTests.cs @@ -35,7 +35,7 @@ public unsafe void GetCodeHeaderData_InterpreterMethod_ReturnsTypeInterpreter(Te IRuntimeTypeSystem rts = Target.Contracts.RuntimeTypeSystem; IPrecodeStubs precodeStubs = Target.Contracts.PrecodeStubs; - ISOSDacInterface sosDac = new SOSDacImpl(Target, legacyObj: null); + ISOSDacInterface sosDac = new SOSDacImpl(Target, legacyObj: null, new()); ThreadData crashingThread = DumpTestHelpers.FindFailFastThread(Target); DumpTestStackWalker walker = DumpTestStackWalker.Walk(Target, crashingThread); diff --git a/src/runtime/src/native/managed/cdac/tests/DumpTests/IXCLRDataAppDomainDumpTests.cs b/src/runtime/src/native/managed/cdac/tests/DumpTests/IXCLRDataAppDomainDumpTests.cs index d17cde130926..86d35c400fc4 100644 --- a/src/runtime/src/native/managed/cdac/tests/DumpTests/IXCLRDataAppDomainDumpTests.cs +++ b/src/runtime/src/native/managed/cdac/tests/DumpTests/IXCLRDataAppDomainDumpTests.cs @@ -207,7 +207,7 @@ private IXCLRDataAppDomain GetAppDomain() Assert.NotNull(managedFrame); - ClrDataFrame frame = new ClrDataFrame(Target, crashingThread.ThreadAddress, managedFrame, legacyImpl: null); + ClrDataFrame frame = new ClrDataFrame(Target, crashingThread.ThreadAddress, managedFrame, legacyImpl: null, new()); IXCLRDataFrame xclrFrame = frame; DacComNullableByRef appDomainOut = new(isNullRef: false); diff --git a/src/runtime/src/native/managed/cdac/tests/DumpTests/IXCLRDataFrameDumpTests.cs b/src/runtime/src/native/managed/cdac/tests/DumpTests/IXCLRDataFrameDumpTests.cs index cc4455b79f38..8fae2f45d415 100644 --- a/src/runtime/src/native/managed/cdac/tests/DumpTests/IXCLRDataFrameDumpTests.cs +++ b/src/runtime/src/native/managed/cdac/tests/DumpTests/IXCLRDataFrameDumpTests.cs @@ -530,6 +530,6 @@ private IXCLRDataFrame CreateFrameForFirstManagedFrame() private ClrDataFrame CreateFrame(IStackDataFrameHandle dataFrame) { ThreadData crashingThread = DumpTestHelpers.FindFailFastThread(Target); - return new ClrDataFrame(Target, crashingThread.ThreadAddress, dataFrame, legacyImpl: null); + return new ClrDataFrame(Target, crashingThread.ThreadAddress, dataFrame, legacyImpl: null, new()); } } diff --git a/src/runtime/src/native/managed/cdac/tests/DumpTests/IXCLRDataMethodDefinitionDumpTests.cs b/src/runtime/src/native/managed/cdac/tests/DumpTests/IXCLRDataMethodDefinitionDumpTests.cs index 874f79a2f6ce..21a10a8544a9 100644 --- a/src/runtime/src/native/managed/cdac/tests/DumpTests/IXCLRDataMethodDefinitionDumpTests.cs +++ b/src/runtime/src/native/managed/cdac/tests/DumpTests/IXCLRDataMethodDefinitionDumpTests.cs @@ -214,7 +214,7 @@ private IXCLRDataMethodDefinition GetMethodDefinitionFromStack(string methodName TargetPointer mt = rts.GetMethodTable(mdHandle); TargetPointer modulePtr = rts.GetModule(rts.GetTypeHandle(mt)); - return new ClrDataMethodDefinition(Target, modulePtr, token, legacyImpl: null); + return new ClrDataMethodDefinition(Target, modulePtr, token, legacyImpl: null, new()); } Assert.Fail($"Could not find method '{methodName}' on the crashing thread's stack"); @@ -258,7 +258,7 @@ private IXCLRDataMethodDefinition GetGenericMethodDefinition() if (mdAddr == TargetPointer.Null) continue; - return new ClrDataMethodDefinition(Target, modulePtr, token, legacyImpl: null); + return new ClrDataMethodDefinition(Target, modulePtr, token, legacyImpl: null, new()); } Assert.Fail("Could not find a loaded method on List<> in CoreLib"); diff --git a/src/runtime/src/native/managed/cdac/tests/DumpTests/IXCLRDataValueDumpTests.cs b/src/runtime/src/native/managed/cdac/tests/DumpTests/IXCLRDataValueDumpTests.cs index ef067f9e8624..aac8422e4610 100644 --- a/src/runtime/src/native/managed/cdac/tests/DumpTests/IXCLRDataValueDumpTests.cs +++ b/src/runtime/src/native/managed/cdac/tests/DumpTests/IXCLRDataValueDumpTests.cs @@ -697,7 +697,7 @@ public void GetSize_GetFlags_AllFrames_Succeeds(TestConfiguration config) if (md == TargetPointer.Null) continue; - ClrDataFrame frame = new ClrDataFrame(Target, crashingThread.ThreadAddress, dataFrame, legacyImpl: null); + ClrDataFrame frame = new ClrDataFrame(Target, crashingThread.ThreadAddress, dataFrame, legacyImpl: null, new()); IXCLRDataFrame xclrFrame = frame; uint numArgs; @@ -900,7 +900,7 @@ private static void AssertEach(Dictionary values, Di string? name = DumpTestHelpers.GetMethodName(Target, md); if (name == methodName) { - ClrDataFrame frame = new ClrDataFrame(Target, crashingThread.ThreadAddress, dataFrame, legacyImpl: null); + ClrDataFrame frame = new ClrDataFrame(Target, crashingThread.ThreadAddress, dataFrame, legacyImpl: null, new()); return (frame, dataFrame); } diff --git a/src/runtime/src/native/managed/cdac/tests/DumpTests/MetaDataImportDumpTests.cs b/src/runtime/src/native/managed/cdac/tests/DumpTests/MetaDataImportDumpTests.cs index e9300fc67710..cf41c4cf0dcd 100644 --- a/src/runtime/src/native/managed/cdac/tests/DumpTests/MetaDataImportDumpTests.cs +++ b/src/runtime/src/native/managed/cdac/tests/DumpTests/MetaDataImportDumpTests.cs @@ -34,7 +34,7 @@ public class MetaDataImportDumpTests : DumpTestBase MetadataReader? reader = ecmaMetadata.GetMetadata(moduleHandle); Assert.NotNull(reader); - return (reader, new MetaDataImportImpl(reader)); + return (reader, new MetaDataImportImpl(reader, legacyImport: null, new())); } [ConditionalTheory] diff --git a/src/runtime/src/native/managed/cdac/tests/DumpTests/StackWalkDumpTests.cs b/src/runtime/src/native/managed/cdac/tests/DumpTests/StackWalkDumpTests.cs index 87b116fdc38f..499e7c7a6680 100644 --- a/src/runtime/src/native/managed/cdac/tests/DumpTests/StackWalkDumpTests.cs +++ b/src/runtime/src/native/managed/cdac/tests/DumpTests/StackWalkDumpTests.cs @@ -159,7 +159,7 @@ public unsafe void MethodInstance_EnumExtents_ReturnsSingleRangeContainingInstru continue; IXCLRDataMethodInstance methodInstance = new ClrDataMethodInstance( - Target, methodDesc, TargetPointer.Null, legacyImpl: null); + Target, methodDesc, TargetPointer.Null, legacyImpl: null, new()); ulong handle = 0; int hr = methodInstance.StartEnumExtents(&handle); @@ -385,7 +385,7 @@ public unsafe void VarargPInvoke_GetMethodTableDataForILStubFrame(TestConfigurat InitializeDumpTest(config, "VarargPInvoke", "full"); IStackWalk stackWalk = Target.Contracts.StackWalk; IRuntimeTypeSystem rts = Target.Contracts.RuntimeTypeSystem; - ISOSDacInterface sosDac = new SOSDacImpl(Target, legacyObj: null); + ISOSDacInterface sosDac = new SOSDacImpl(Target, legacyObj: null, new()); ThreadData crashingThread = DumpTestHelpers.FindThreadWithMethod(Target, "Main"); IEnumerable frames = DumpTestStackWalker.LegacyVisibleFrames(stackWalk, crashingThread); @@ -435,7 +435,7 @@ public unsafe void VarargPInvoke_GetILAddressMapForILStub_ReturnsFailure(TestCon continue; IXCLRDataMethodInstance methodInstance = new ClrDataMethodInstance( - Target, mdHandle, TargetPointer.Null, legacyImpl: null); + Target, mdHandle, TargetPointer.Null, legacyImpl: null, new()); uint mapNeeded; int hr = methodInstance.GetILAddressMap(0, &mapNeeded, null); Assert.True(hr < 0, $"Expected failure HRESULT for ILStub GetILAddressMap, got 0x{hr:X8}"); @@ -455,7 +455,7 @@ public unsafe void VarargPInvoke_GetCodeHeaderDataWithInvalidPrecodeAddress(Test InitializeDumpTest(config, "VarargPInvoke", "full"); IStackWalk stackWalk = Target.Contracts.StackWalk; IRuntimeTypeSystem rts = Target.Contracts.RuntimeTypeSystem; - ISOSDacInterface sosDac = new SOSDacImpl(Target, legacyObj: null); + ISOSDacInterface sosDac = new SOSDacImpl(Target, legacyObj: null, new()); ThreadData crashingThread = DumpTestHelpers.FindThreadWithMethod(Target, "Main"); IEnumerable frames = DumpTestStackWalker.LegacyVisibleFrames(stackWalk, crashingThread); @@ -504,7 +504,7 @@ public unsafe void VarargPInvoke_GetCodeHeaderDataForILStub_ReturnsMethodSize(Te InitializeDumpTest(config, "VarargPInvoke", "full"); IStackWalk stackWalk = Target.Contracts.StackWalk; IRuntimeTypeSystem rts = Target.Contracts.RuntimeTypeSystem; - ISOSDacInterface sosDac = new SOSDacImpl(Target, legacyObj: null); + ISOSDacInterface sosDac = new SOSDacImpl(Target, legacyObj: null, new()); ThreadData crashingThread = DumpTestHelpers.FindThreadWithMethod(Target, "Main"); IEnumerable frames = DumpTestStackWalker.LegacyVisibleFrames(stackWalk, crashingThread); @@ -578,7 +578,7 @@ private IXCLRDataMethodInstance GetMethodInstanceFromStack(string methodName) MethodDescHandle methodDesc = rts.GetMethodDescHandle(methodDescPtr); if (DumpTestHelpers.GetMethodName(Target, methodDesc) == methodName) - return new ClrDataMethodInstance(Target, methodDesc, TargetPointer.Null, legacyImpl: null); + return new ClrDataMethodInstance(Target, methodDesc, TargetPointer.Null, legacyImpl: null, new()); } Assert.Fail($"{methodName} not found on the crashing thread's stack"); diff --git a/src/runtime/src/native/managed/cdac/tests/DumpTests/StressLogDumpTests.cs b/src/runtime/src/native/managed/cdac/tests/DumpTests/StressLogDumpTests.cs index 7d30d45afb98..89e74f6079b6 100644 --- a/src/runtime/src/native/managed/cdac/tests/DumpTests/StressLogDumpTests.cs +++ b/src/runtime/src/native/managed/cdac/tests/DumpTests/StressLogDumpTests.cs @@ -72,7 +72,7 @@ public void CanEnumerateThreadsAndMessages(TestConfiguration config) public unsafe void ISOSDacInterface17_GetStressLogData(TestConfiguration config) { InitializeDumpTest(config); - ISOSDacInterface17 sosDac = (ISOSDacInterface17)new SOSDacImpl(Target, legacyObj: null); + ISOSDacInterface17 sosDac = (ISOSDacInterface17)new SOSDacImpl(Target, legacyObj: null, new()); SOSStressLogData data; int hr = sosDac.GetStressLogData(&data); @@ -87,7 +87,7 @@ public unsafe void ISOSDacInterface17_GetStressLogData(TestConfiguration config) public unsafe void ISOSDacInterface17_GetStressLogThreadEnumerator(TestConfiguration config) { InitializeDumpTest(config); - ISOSDacInterface17 sosDac = (ISOSDacInterface17)new SOSDacImpl(Target, legacyObj: null); + ISOSDacInterface17 sosDac = (ISOSDacInterface17)new SOSDacImpl(Target, legacyObj: null, new()); DacComNullableByRef ppEnum = new(isNullRef: false); int hr = sosDac.GetStressLogThreadEnumerator(ppEnum); @@ -114,7 +114,7 @@ public unsafe void ISOSDacInterface17_GetStressLogThreadEnumerator(TestConfigura public unsafe void ISOSDacInterface17_GetStressLogMessageEnumerator(TestConfiguration config) { InitializeDumpTest(config); - ISOSDacInterface17 sosDac = (ISOSDacInterface17)new SOSDacImpl(Target, legacyObj: null); + ISOSDacInterface17 sosDac = (ISOSDacInterface17)new SOSDacImpl(Target, legacyObj: null, new()); DacComNullableByRef ppThreadEnum = new(isNullRef: false); int hr = sosDac.GetStressLogThreadEnumerator(ppThreadEnum); diff --git a/src/runtime/src/native/managed/cdac/tests/UnitTests/ClrDataExceptionStateTests.cs b/src/runtime/src/native/managed/cdac/tests/UnitTests/ClrDataExceptionStateTests.cs index f5b1cc5023d7..9dc0a05829d6 100644 --- a/src/runtime/src/native/managed/cdac/tests/UnitTests/ClrDataExceptionStateTests.cs +++ b/src/runtime/src/native/managed/cdac/tests/UnitTests/ClrDataExceptionStateTests.cs @@ -116,7 +116,7 @@ private static (TestPlaceholderTarget Target, IXCLRDataTask Task) CreateTargetWi .AddMockContract(mockThread) .Build(); - IXCLRDataTask task = new ClrDataTask(threadAddr, target, null); + IXCLRDataTask task = new ClrDataTask(threadAddr, target, null, new()); return (target, task); } @@ -217,7 +217,8 @@ private static IXCLRDataExceptionState CreateExceptionStateWithRecord( TargetPointer.Null, TargetPointer.Null, previousExInfoAddress, - null); + null, + new()); } [Theory] @@ -234,7 +235,8 @@ public void GetFlags(uint inputFlags, bool hasNestedException, uint expectedFlag TargetPointer.Null, new TargetPointer(0x2000), previousExInfo, - null); + null, + new()); AssertFlags(exceptionState, expectedFlags); } @@ -252,7 +254,8 @@ public void GetManagedObject(MockTarget.Architecture arch) TargetPointer.Null, thrownObjectHandle, TargetPointer.Null, - null); + null, + new()); DacComNullableByRef value = new(isNullRef: false); int hr = exceptionState.GetManagedObject(value); @@ -297,7 +300,8 @@ public void GetManagedObject_InvalidHandle(MockTarget.Architecture arch) TargetPointer.Null, new TargetPointer(0x2000), TargetPointer.Null, - null); + null, + new()); DacComNullableByRef value = new(isNullRef: false); int hr = exceptionState.GetManagedObject(value); @@ -316,7 +320,8 @@ public void GetManagedObject_NullHandle() TargetPointer.Null, TargetPointer.Null, TargetPointer.Null, - null); + null, + new()); DacComNullableByRef value = new(isNullRef: false); int hr = exceptionState.GetManagedObject(value); @@ -338,7 +343,8 @@ public void GetManagedObject_NullOutput(MockTarget.Architecture arch) TargetPointer.Null, thrownObjectHandle, TargetPointer.Null, - null); + null, + new()); DacComNullableByRef value = new(isNullRef: true); int hr = exceptionState.GetManagedObject(value); @@ -356,7 +362,7 @@ public void GetString_WithMessage(MockTarget.Architecture arch) (TestPlaceholderTarget target, TargetPointer thrownObjectHandle) = CreateTargetWithException(arch, messageAddr, expectedMessage); IXCLRDataExceptionState exceptionState = new ClrDataExceptionState( target, new TargetPointer(0x1000), (uint)CLRDataExceptionStateFlag.CLRDATA_EXCEPTION_DEFAULT, - TargetPointer.Null, thrownObjectHandle, TargetPointer.Null, null); + TargetPointer.Null, thrownObjectHandle, TargetPointer.Null, null, new()); (int hr, uint strLen, char[] buffer) = CallGetString(exceptionState, bufLen: 256); Assert.Equal(HResults.S_OK, hr); @@ -371,7 +377,7 @@ public void GetString_NullMessage(MockTarget.Architecture arch) (TestPlaceholderTarget target, TargetPointer thrownObjectHandle) = CreateTargetWithException(arch, TargetPointer.Null, null); IXCLRDataExceptionState exceptionState = new ClrDataExceptionState( target, new TargetPointer(0x1000), (uint)CLRDataExceptionStateFlag.CLRDATA_EXCEPTION_DEFAULT, - TargetPointer.Null, thrownObjectHandle, TargetPointer.Null, null); + TargetPointer.Null, thrownObjectHandle, TargetPointer.Null, null, new()); (int hr, uint strLen, char[] buffer) = CallGetString(exceptionState, bufLen: 256); Assert.Equal(HResults.S_OK, hr); @@ -386,7 +392,7 @@ public void GetString_NullMessageNonEmptyBuffer(MockTarget.Architecture arch) (TestPlaceholderTarget target, TargetPointer thrownObjectHandle) = CreateTargetWithException(arch, TargetPointer.Null, null); IXCLRDataExceptionState exceptionState = new ClrDataExceptionState( target, new TargetPointer(0x1000), (uint)CLRDataExceptionStateFlag.CLRDATA_EXCEPTION_DEFAULT, - TargetPointer.Null, thrownObjectHandle, TargetPointer.Null, null); + TargetPointer.Null, thrownObjectHandle, TargetPointer.Null, null, new()); uint bufferSize = 256; char* str = null; @@ -405,7 +411,7 @@ public void GetString_BufferOverflow(MockTarget.Architecture arch) (TestPlaceholderTarget target, TargetPointer thrownObjectHandle) = CreateTargetWithException(arch, messageAddr, expectedMessage); IXCLRDataExceptionState exceptionState = new ClrDataExceptionState( target, new TargetPointer(0x1000), (uint)CLRDataExceptionStateFlag.CLRDATA_EXCEPTION_DEFAULT, - TargetPointer.Null, thrownObjectHandle, TargetPointer.Null, null); + TargetPointer.Null, thrownObjectHandle, TargetPointer.Null, null, new()); (int hr, uint strLen, _) = CallGetString(exceptionState, bufLen: 5); Assert.Equal(HResults.S_FALSE, hr); @@ -426,7 +432,8 @@ public void Request_NullInBuffer_InvalidArgs(uint reqCode, uint inBufferSize, ui default, default, default, - null); + null, + new()); byte[] outBuffer = new byte[8]; fixed (byte* outPtr = outBuffer) @@ -446,7 +453,8 @@ public void Request_NonNullInBuffer_InvalidArgs() default, default, default, - null); + null, + new()); byte inByte = 0; uint outBufferSize = sizeof(uint); @@ -468,7 +476,8 @@ public void Request_Success() default, default, default, - null); + null, + new()); uint outBufferSize = sizeof(uint); byte[] outBuffer = new byte[outBufferSize]; @@ -490,7 +499,8 @@ public void GetTask() TargetPointer.Null, new TargetPointer(0x2000), TargetPointer.Null, - null); + null, + new()); DacComNullableByRef task = new(isNullRef: false); int hr = exceptionState.GetTask(task); @@ -552,7 +562,8 @@ public void IsSameState2_PartialState(uint flags) TargetPointer.Null, TargetPointer.Null, TargetPointer.Null, - null); + null, + new()); int hr = exceptionState.IsSameState2(flags, null, 0, null); @@ -571,7 +582,8 @@ public void IsSameState2_InvalidFlags(uint flags) TargetPointer.Null, TargetPointer.Null, TargetPointer.Null, - null); + null, + new()); int hr = exceptionState.IsSameState2(flags, null, 0, null); @@ -643,7 +655,8 @@ public void GetPrevious_NoPrevious() TargetPointer.Null, new TargetPointer(0x2000), TargetPointer.Null, - null); + null, + new()); DacComNullableByRef previous = new(isNullRef: false); int hr = exceptionState.GetPrevious(previous); @@ -674,7 +687,8 @@ public void GetPrevious_HasPrevious_ReturnsState(MockTarget.Architecture arch) TargetPointer.Null, new TargetPointer(0x2000), previousExInfoAddr, - null); + null, + new()); DacComNullableByRef previous = new(isNullRef: false); int hr = exceptionState.GetPrevious(previous); @@ -710,7 +724,8 @@ public void GetPrevious_NestedExceptionsChain(MockTarget.Architecture arch) TargetPointer.Null, new TargetPointer(0x2000), firstNestedAddr, - null); + null, + new()); DacComNullableByRef first = new(isNullRef: false); int hr1 = exceptionState.GetPrevious(first); @@ -794,7 +809,7 @@ private static (IXCLRDataTask Task, string ExpectedMessage) CreateTargetWithLast .AddMockContract(mockObject) .Build(); - IXCLRDataTask task = new ClrDataTask(threadAddr, target, null); + IXCLRDataTask task = new ClrDataTask(threadAddr, target, null, new()); return (task, expectedMessage); } diff --git a/src/runtime/src/native/managed/cdac/tests/UnitTests/ClrDataRequestTests.cs b/src/runtime/src/native/managed/cdac/tests/UnitTests/ClrDataRequestTests.cs index 9b2138db990b..54ddbaa6edb3 100644 --- a/src/runtime/src/native/managed/cdac/tests/UnitTests/ClrDataRequestTests.cs +++ b/src/runtime/src/native/managed/cdac/tests/UnitTests/ClrDataRequestTests.cs @@ -82,10 +82,10 @@ public void Request_NullOutputBuffer_ReturnsPointerError(RequestType type) private static object CreateInstance(RequestType type) => type switch { - RequestType.Task => new ClrDataTask(default, null!, null), - RequestType.MethodDefinition => new ClrDataMethodDefinition(null!, default, 0, null), - RequestType.MethodInstance => new ClrDataMethodInstance(null!, default, default, null), - RequestType.Value => new ClrDataValue(null!, TargetPointer.Null, 0, null, TargetPointer.Null, [], null), + RequestType.Task => new ClrDataTask(default, null!, null, new()), + RequestType.MethodDefinition => new ClrDataMethodDefinition(null!, default, 0, null, new()), + RequestType.MethodInstance => new ClrDataMethodInstance(null!, default, default, null, new()), + RequestType.Value => new ClrDataValue(null!, TargetPointer.Null, 0, null, TargetPointer.Null, [], null, new()), _ => throw new ArgumentOutOfRangeException(nameof(type)), }; diff --git a/src/runtime/src/native/managed/cdac/tests/UnitTests/ClrDataTaskTests.cs b/src/runtime/src/native/managed/cdac/tests/UnitTests/ClrDataTaskTests.cs index 91e535fc61b2..c6dc4b2cd30f 100644 --- a/src/runtime/src/native/managed/cdac/tests/UnitTests/ClrDataTaskTests.cs +++ b/src/runtime/src/native/managed/cdac/tests/UnitTests/ClrDataTaskTests.cs @@ -36,7 +36,7 @@ public void GetCurrentAppDomain(MockTarget.Architecture arch) .Build(); TargetPointer taskAddress = new TargetPointer(0x5000); - IXCLRDataTask task = new ClrDataTask(taskAddress, target, legacyImpl: null); + IXCLRDataTask task = new ClrDataTask(taskAddress, target, legacyImpl: null, new()); DacComNullableByRef appDomain = new(isNullRef: false); int hr = task.GetCurrentAppDomain(appDomain); diff --git a/src/runtime/src/native/managed/cdac/tests/UnitTests/DacDbiImplTests.cs b/src/runtime/src/native/managed/cdac/tests/UnitTests/DacDbiImplTests.cs index 6e7e7a2b50c9..f107f1654f23 100644 --- a/src/runtime/src/native/managed/cdac/tests/UnitTests/DacDbiImplTests.cs +++ b/src/runtime/src/native/managed/cdac/tests/UnitTests/DacDbiImplTests.cs @@ -38,7 +38,7 @@ private static (DacDbiImpl DacDbi, TestPlaceholderTarget Target) CreateDacDbiWit builder.AddGlobals((Constants.Globals.CorDBDefaultEnCFunctionVersion, CorDBDefaultEnCFunctionVersion)); configure(loader, builder); }); - var dacDbi = new DacDbiImpl(target, legacyObj: null); + var dacDbi = new DacDbiImpl(target, legacyObj: null, new()); return (dacDbi, target); } @@ -50,7 +50,7 @@ public void IsThreadSuspendedOrHijacked_NullOutput_ReturnsEPointer(MockTarget.Ar TestPlaceholderTarget target = new TestPlaceholderTarget.Builder(arch) .AddMockContract(mockThread) .Build(); - DacDbiImpl dacDbi = new(target, legacyObj: null); + DacDbiImpl dacDbi = new(target, legacyObj: null, new()); int hr = dacDbi.IsThreadSuspendedOrHijacked(0, null); @@ -70,7 +70,7 @@ public void IsThreadSuspendedOrHijacked_ContractFailure_InitializesOutput(MockTa TestPlaceholderTarget target = new TestPlaceholderTarget.Builder(arch) .AddMockContract(mockThread) .Build(); - DacDbiImpl dacDbi = new(target, legacyObj: null); + DacDbiImpl dacDbi = new(target, legacyObj: null, new()); Interop.BOOL result = Interop.BOOL.TRUE; int hr = dacDbi.IsThreadSuspendedOrHijacked(ThreadAddress, &result); @@ -84,7 +84,7 @@ public void DacSetTargetConsistencyChecks_Standalone_ReturnsSuccess() { MockTarget.Architecture architecture = new() { IsLittleEndian = true, Is64Bit = true }; TestPlaceholderTarget target = new TestPlaceholderTarget.Builder(architecture).Build(); - DacDbiImpl dacDbi = new(target, legacyObj: null); + DacDbiImpl dacDbi = new(target, legacyObj: null, new()); Assert.Equal(System.HResults.S_OK, dacDbi.DacSetTargetConsistencyChecks(Interop.BOOL.TRUE)); Assert.Equal(System.HResults.S_OK, dacDbi.DacSetTargetConsistencyChecks(Interop.BOOL.FALSE)); @@ -327,7 +327,7 @@ private static DacDbiImpl CreateDacDbiWithMockLoader( .AddGlobals((Constants.Globals.CorDBDefaultEnCFunctionVersion, CorDBDefaultEnCFunctionVersion)) .AddMockContract(mockLoader) .Build(); - return new DacDbiImpl(target, legacyObj: null); + return new DacDbiImpl(target, legacyObj: null, new()); } private static (DacDbiImpl DacDbi, TestPlaceholderTarget Target) CreateDacDbiWithExceptionMT( @@ -340,7 +340,7 @@ private static (DacDbiImpl DacDbi, TestPlaceholderTarget Target) CreateDacDbiWit builder.AddMockContract(mockObject); builder.AddMockContract(mockRts); var target = builder.Build(); - var dacDbi = new DacDbiImpl(target, legacyObj: null); + var dacDbi = new DacDbiImpl(target, legacyObj: null, new()); return (dacDbi, target); } @@ -706,7 +706,7 @@ private static DacDbiImpl CreateDacDbiWithMockContracts(MockTarget.Architecture .AddMockContract(loader) .AddMockContract(ecma) .Build(); - return new DacDbiImpl(target, legacyObj: null); + return new DacDbiImpl(target, legacyObj: null, new()); } [Theory] @@ -912,7 +912,7 @@ public void CheckContext_NoControlFlag_SkipsSpCheck(MockTarget.Architecture arch .AddContract(version: "c1") .AddMockContract(mockThread) .Build(); - var dacDbi = new DacDbiImpl(target, legacyObj: null); + var dacDbi = new DacDbiImpl(target, legacyObj: null, new()); IPlatformAgnosticContext ctx = IPlatformAgnosticContext.GetContextForPlatform(target); ctx.RawContextFlags = 0; @@ -949,7 +949,7 @@ private static (DacDbiImpl DacDbi, Target Target) CreateCheckContextDacDbi(MockT .AddMockContract(mockThread) .Build(); - return (new DacDbiImpl(target, legacyObj: null), target); + return (new DacDbiImpl(target, legacyObj: null, new()), target); } private delegate void GetStackLimitDataCallback(TargetPointer threadPointer, out TargetPointer stackBase, out TargetPointer stackLimit, out TargetPointer frameAddress); @@ -980,7 +980,7 @@ private static DacDbiImpl CreateNativeCodeDacDbi( .AddMockContract(codeVersions) .AddMockContract(new Mock()) .Build(); - return new DacDbiImpl(target, legacyObj: null); + return new DacDbiImpl(target, legacyObj: null, new()); } [Theory] @@ -1234,7 +1234,7 @@ private static DacDbiImpl CreateDacDbiWithMockContracts( .AddMockContract(mockCodeVersions) .AddMockContract(mockReJIT) .Build(); - return new DacDbiImpl(target, legacyObj: null); + return new DacDbiImpl(target, legacyObj: null, new()); } private static Mock SetupMockLoader(TargetPointer modulePtr, uint methodTk, TargetPointer methodDesc) @@ -1405,7 +1405,7 @@ public void GetThreadOwningMonitorLock(MockTarget.Architecture arch, bool hasSyn builder.AddMockContract(mockThread); } - var dacDbi = new DacDbiImpl(builder.Build(), legacyObj: null); + var dacDbi = new DacDbiImpl(builder.Build(), legacyObj: null, new()); DacDbiMonitorLockInfo result; int hr = dacDbi.GetThreadOwningMonitorLock(ObjectAddr, &result); @@ -1466,7 +1466,7 @@ private static (DacDbiImpl DacDbi, MockThread Thread, MockFrameBuilder FrameBuil .AddContract(version: "c1") .AddContract(version: "c1"); TestPlaceholderTarget target = targetBuilder.Build(); - DacDbiImpl dacDbi = new(target, legacyObj: null); + DacDbiImpl dacDbi = new(target, legacyObj: null, new()); return (dacDbi, thread, frameBuilder); } @@ -1590,7 +1590,7 @@ public void GetStackWalkCurrentFrameInfo_MissingOptionalMemory_PreservesAvailabl .AddMockContract(gcInfo) .AddMockContract(new Mock()) .Build(); - DacDbiImpl dacDbi = new(target, legacyObj: null); + DacDbiImpl dacDbi = new(target, legacyObj: null, new()); StackWalkHandleData handleData = new(stackWalk.Object, default); handleData.Reset([], isFirst: true); nuint stackWalkHandle = handleData.GetHandle(); @@ -1828,7 +1828,7 @@ private static DacDbiImpl CreateDacDbiForModule( .AddMockContract(mockLoader) .AddMockContract(mockEcmaMetadata) .Build(); - return new DacDbiImpl(target, legacyObj: null); + return new DacDbiImpl(target, legacyObj: null, new()); } [Theory] @@ -1915,7 +1915,7 @@ public void GetMetadata_NullBuffer(MockTarget.Architecture arch) [ClassData(typeof(MockTarget.StdArch))] public void HasReadWriteMetadata_NullOutput_ReturnsError(MockTarget.Architecture arch) { - DacDbiImpl dacDbi = new(new TestPlaceholderTarget.Builder(arch).Build(), legacyObj: null); + DacDbiImpl dacDbi = new(new TestPlaceholderTarget.Builder(arch).Build(), legacyObj: null, new()); int hr = dacDbi.HasReadWriteMetadata(0x1000, null); @@ -1954,7 +1954,7 @@ public void HasReadWriteMetadata_ReturnsMetadataAvailability(MockTarget.Architec .AddTypes(types) .AddContract(version: "c1") .Build(); - DacDbiImpl dacDbi = new(target, legacyObj: null); + DacDbiImpl dacDbi = new(target, legacyObj: null, new()); Interop.BOOL result = Interop.BOOL.TRUE; int hr = dacDbi.HasReadWriteMetadata(readOnlyPEAssembly.Address, &result); diff --git a/src/runtime/src/native/managed/cdac/tests/UnitTests/FunctionTableAccessTests.cs b/src/runtime/src/native/managed/cdac/tests/UnitTests/FunctionTableAccessTests.cs index 4659157201ec..598984e0a19c 100644 --- a/src/runtime/src/native/managed/cdac/tests/UnitTests/FunctionTableAccessTests.cs +++ b/src/runtime/src/native/managed/cdac/tests/UnitTests/FunctionTableAccessTests.cs @@ -88,7 +88,7 @@ private static FunctionTableScenario BuildScenario(string version, MockTarget.Ar public void QueryInterfaceFromIXCLRDataProcess_ReturnsProcess3(MockTarget.Architecture arch) { TestPlaceholderTarget target = new TestPlaceholderTarget.Builder(arch).Build(); - SOSDacImpl impl = new(target, legacyObj: null); + SOSDacImpl impl = new(target, legacyObj: null, new()); void* process = ComInterfaceMarshaller.ConvertToUnmanaged(impl); try @@ -150,7 +150,7 @@ public void QueryInterfaceFromIXCLRDataProcess_ReturnsProcess3(MockTarget.Archit public void GetFunctionTable_NullOutParameters_ReturnsEPointer(MockTarget.Architecture arch) { TestPlaceholderTarget target = new TestPlaceholderTarget.Builder(arch).Build(); - IXCLRDataProcess3 process3 = new SOSDacImpl(target, legacyObj: null); + IXCLRDataProcess3 process3 = new SOSDacImpl(target, legacyObj: null, new()); uint bytesNeeded = uint.MaxValue; uint entries = uint.MaxValue; @@ -170,7 +170,7 @@ public void GetFunctionTable_NullOutParameters_ReturnsEPointer(MockTarget.Archit public void GetFunctionTable_SizeQuery_ReturnsRequiredSize(string version, MockTarget.Architecture arch) { FunctionTableScenario scenario = BuildScenario(version, arch); - IXCLRDataProcess3 process3 = new SOSDacImpl(scenario.Target, legacyObj: null); + IXCLRDataProcess3 process3 = new SOSDacImpl(scenario.Target, legacyObj: null, new()); uint bytesNeeded = 0; uint entries = 0; @@ -186,7 +186,7 @@ public void GetFunctionTable_SizeQuery_ReturnsRequiredSize(string version, MockT public void GetFunctionTable_BufferTooSmall_ReturnsSFalseAndWritesNothing(string version, MockTarget.Architecture arch) { FunctionTableScenario scenario = BuildScenario(version, arch); - IXCLRDataProcess3 process3 = new SOSDacImpl(scenario.Target, legacyObj: null); + IXCLRDataProcess3 process3 = new SOSDacImpl(scenario.Target, legacyObj: null, new()); uint bytesNeeded = 0; uint entries = 0; @@ -210,7 +210,7 @@ public void GetFunctionTable_BufferTooSmall_ReturnsSFalseAndWritesNothing(string public void GetFunctionTable_SufficientBuffer_WritesEntries(string version, MockTarget.Architecture arch) { FunctionTableScenario scenario = BuildScenario(version, arch); - IXCLRDataProcess3 process3 = new SOSDacImpl(scenario.Target, legacyObj: null); + IXCLRDataProcess3 process3 = new SOSDacImpl(scenario.Target, legacyObj: null, new()); uint bytesNeeded = 0; uint entries = 0; @@ -266,7 +266,7 @@ public void GetFunctionTable_UnmatchedTable_ReturnsSOkWithZeroEntries(string ver MockDynamicFunctionTable table = emBuilder.AddDynamicFunctionTable(0xbaad_0000, emBuilder.EEJitManagerAddress); Target target = ExecutionManagerTests.CreateTarget(emBuilder); - IXCLRDataProcess3 process3 = new SOSDacImpl(target, legacyObj: null); + IXCLRDataProcess3 process3 = new SOSDacImpl(target, legacyObj: null, new()); uint bytesNeeded = uint.MaxValue; uint entries = uint.MaxValue; diff --git a/src/runtime/src/native/managed/cdac/tests/UnitTests/GetRegisterNameTests.cs b/src/runtime/src/native/managed/cdac/tests/UnitTests/GetRegisterNameTests.cs index cf064106c8ab..0b9b61ef683a 100644 --- a/src/runtime/src/native/managed/cdac/tests/UnitTests/GetRegisterNameTests.cs +++ b/src/runtime/src/native/managed/cdac/tests/UnitTests/GetRegisterNameTests.cs @@ -21,7 +21,7 @@ private static SOSDacImpl CreateSosDacImpl( .AddContract(version: "c1") .Build(); - return new SOSDacImpl(target, legacyObj: null); + return new SOSDacImpl(target, legacyObj: null, new()); } public static IEnumerable BasicRegisterNameData() diff --git a/src/runtime/src/native/managed/cdac/tests/UnitTests/IXCLRDataProcessTests.cs b/src/runtime/src/native/managed/cdac/tests/UnitTests/IXCLRDataProcessTests.cs index 622182ea7db2..b537a1595d8e 100644 --- a/src/runtime/src/native/managed/cdac/tests/UnitTests/IXCLRDataProcessTests.cs +++ b/src/runtime/src/native/managed/cdac/tests/UnitTests/IXCLRDataProcessTests.cs @@ -376,7 +376,8 @@ public void MethodDefinitionWithoutIL(MockTarget.Architecture arch) builder.Build(), new TargetPointer(ModuleAddress), Token, - legacyImpl: null); + legacyImpl: null, + new()); ulong handle; Assert.Equal(HResults.S_FALSE, method.StartEnumExtents(&handle)); @@ -435,7 +436,8 @@ public void MethodDefinitionUsesActiveEnCIL(MockTarget.Architecture arch) builder.Build(), new TargetPointer(ModuleAddress), Token, - legacyImpl: null); + legacyImpl: null, + new()); AssertMethodDefinitionExtent( method, @@ -573,6 +575,6 @@ private static IXCLRDataProcess CreateProcess( builder.MemoryBuilder.AddHeapFragment(fragment); } - return new SOSDacImpl(builder.Build(), legacyObj: null); + return new SOSDacImpl(builder.Build(), legacyObj: null, new()); } } diff --git a/src/runtime/src/native/managed/cdac/tests/UnitTests/LoaderTests.cs b/src/runtime/src/native/managed/cdac/tests/UnitTests/LoaderTests.cs index ebe837202cc9..85fe8eb83eb4 100644 --- a/src/runtime/src/native/managed/cdac/tests/UnitTests/LoaderTests.cs +++ b/src/runtime/src/native/managed/cdac/tests/UnitTests/LoaderTests.cs @@ -251,7 +251,7 @@ private static ISOSDacInterface13 CreateSOSDacInterface13ForHeapTests(MockTarget l => l.GetLoaderAllocatorHeaps(It.IsAny()) == (IReadOnlyDictionary)MockHeapDictionary && l.GetGlobalLoaderAllocator() == new TargetPointer(0x100))) .Build(); - return new SOSDacImpl(target, null); + return new SOSDacImpl(target, null, new()); } private static (ISOSDacInterface Interface, Mock Loader) CreateSOSDacInterfaceForVirtCallHeapTests(MockTarget.Architecture arch) @@ -264,7 +264,7 @@ private static (ISOSDacInterface Interface, Mock Loader) CreateSOSDacIn .AddMockContract(loader.Object) .Build(); - return (new SOSDacImpl(target, null), loader); + return (new SOSDacImpl(target, null, new()), loader); } [Theory] @@ -1124,7 +1124,7 @@ public void GetCompilerFlags(uint rawFlags, Interop.BOOL expectedAllowJITOpts, I .AddContract(version: "c1") .Build(); - DacDbiImpl dbi = new(target, legacyObj: null); + DacDbiImpl dbi = new(target, legacyObj: null, new()); Interop.BOOL allowJITOpts; Interop.BOOL enableEnC; diff --git a/src/runtime/src/native/managed/cdac/tests/UnitTests/MetaDataImportImplTests.cs b/src/runtime/src/native/managed/cdac/tests/UnitTests/MetaDataImportImplTests.cs index c951d6b7e4b8..2154f7654a1b 100644 --- a/src/runtime/src/native/managed/cdac/tests/UnitTests/MetaDataImportImplTests.cs +++ b/src/runtime/src/native/managed/cdac/tests/UnitTests/MetaDataImportImplTests.cs @@ -174,7 +174,7 @@ private static IMetaDataImport2 CreateWrapper() { (MetadataReader reader, MetadataReaderProvider provider) = CreateTestMetadata(); _testProvider = provider; - return new MetaDataImportImpl(reader); + return new MetaDataImportImpl(reader, legacyImport: null, new()); } [Fact] @@ -629,7 +629,7 @@ public void ReaderOnly_MethodsWork() // When only reader is available (no legacy), implemented methods should still work (MetadataReader reader, MetadataReaderProvider provider) = CreateTestMetadata(); _testProvider = provider; - IMetaDataImport2 wrapper = new MetaDataImportImpl(reader, legacyImport: null); + IMetaDataImport2 wrapper = new MetaDataImportImpl(reader, legacyImport: null, new()); uint flags; char* nameBuf = stackalloc char[256]; @@ -647,7 +647,7 @@ public void GetRVA_MethodDef_ReturnsRVA() { (MetadataReader reader, MetadataReaderProvider provider) = CreateTestMetadata(); _testProvider = provider; - IMetaDataImport2 wrapper = new MetaDataImportImpl(reader, legacyImport: null); + IMetaDataImport2 wrapper = new MetaDataImportImpl(reader, legacyImport: null, new()); uint rva, implFlags; // DoWork is MethodDef token 0x06000002 @@ -661,7 +661,7 @@ public void GetRVA_InvalidTable_ReturnsEInvalidArg() { (MetadataReader reader, MetadataReaderProvider provider) = CreateTestMetadata(); _testProvider = provider; - IMetaDataImport2 wrapper = new MetaDataImportImpl(reader, legacyImport: null); + IMetaDataImport2 wrapper = new MetaDataImportImpl(reader, legacyImport: null, new()); uint rva; // TypeDef token (0x02) is not MethodDef or FieldDef @@ -674,7 +674,7 @@ public void GetCustomAttributeByName_Found_ReturnsSok() { (MetadataReader reader, MetadataReaderProvider provider) = CreateTestMetadata(); _testProvider = provider; - IMetaDataImport2 wrapper = new MetaDataImportImpl(reader, legacyImport: null); + IMetaDataImport2 wrapper = new MetaDataImportImpl(reader, legacyImport: null, new()); void* pData; uint cbData; @@ -693,7 +693,7 @@ public void GetCustomAttributeByName_NotFound_ReturnsSFalse() { (MetadataReader reader, MetadataReaderProvider provider) = CreateTestMetadata(); _testProvider = provider; - IMetaDataImport2 wrapper = new MetaDataImportImpl(reader, legacyImport: null); + IMetaDataImport2 wrapper = new MetaDataImportImpl(reader, legacyImport: null, new()); void* pData; uint cbData; @@ -711,7 +711,7 @@ public void GetAssemblyFromScope_ReturnsAssemblyToken() { (MetadataReader reader, MetadataReaderProvider provider) = CreateTestMetadata(); _testProvider = provider; - IMetaDataImport2 wrapper = new MetaDataImportImpl(reader, legacyImport: null); + IMetaDataImport2 wrapper = new MetaDataImportImpl(reader, legacyImport: null, new()); IMetaDataAssemblyImport assemblyImport = (IMetaDataAssemblyImport)wrapper; uint tkAssembly; @@ -725,7 +725,7 @@ public void GetAssemblyProps_ReturnsNameAndVersion() { (MetadataReader reader, MetadataReaderProvider provider) = CreateTestMetadata(); _testProvider = provider; - IMetaDataImport2 wrapper = new MetaDataImportImpl(reader, legacyImport: null); + IMetaDataImport2 wrapper = new MetaDataImportImpl(reader, legacyImport: null, new()); IMetaDataAssemblyImport assemblyImport = (IMetaDataAssemblyImport)wrapper; char* nameBuf = stackalloc char[256]; @@ -750,7 +750,7 @@ public void GetAssemblyRefProps_ReturnsRefNameAndVersion() { (MetadataReader reader, MetadataReaderProvider provider) = CreateTestMetadata(); _testProvider = provider; - IMetaDataImport2 wrapper = new MetaDataImportImpl(reader, legacyImport: null); + IMetaDataImport2 wrapper = new MetaDataImportImpl(reader, legacyImport: null, new()); IMetaDataAssemblyImport assemblyImport = (IMetaDataAssemblyImport)wrapper; // mscorlib assembly ref is token 0x23000001 @@ -775,7 +775,7 @@ public void GetAssemblyProps_SmallBuffer_Truncates() { (MetadataReader reader, MetadataReaderProvider provider) = CreateTestMetadata(); _testProvider = provider; - IMetaDataImport2 wrapper = new MetaDataImportImpl(reader, legacyImport: null); + IMetaDataImport2 wrapper = new MetaDataImportImpl(reader, legacyImport: null, new()); IMetaDataAssemblyImport assemblyImport = (IMetaDataAssemblyImport)wrapper; char* nameBuf = stackalloc char[5]; @@ -810,7 +810,7 @@ public void GetAssemblyProps_InvalidToken_ReturnsRecordNotFound() fixed (byte* ptr = metadata.AsSpan()) { var reader = new MetadataReader(ptr, metadata.Length); - IMetaDataImport2 impl = new MetaDataImportImpl(reader); + IMetaDataImport2 impl = new MetaDataImportImpl(reader, legacyImport: null, new()); var assemblyImport = (IMetaDataAssemblyImport)impl; // Pass an invalid assembly token (wrong RID) @@ -907,7 +907,7 @@ public void GetFieldProps_GlobalField_ReturnsMdTypeDefNil() fixed (byte* ptr = bytes.AsSpan()) { var reader = new MetadataReader(ptr, bytes.Length); - IMetaDataImport2 impl = new MetaDataImportImpl(reader); + IMetaDataImport2 impl = new MetaDataImportImpl(reader, legacyImport: null, new()); uint parentClass; int hr = impl.GetFieldProps(0x04000001, &parentClass, null, 0, null, null, null, null, null, null, null); @@ -975,7 +975,7 @@ public void QueryInterfaceForIMetaDataImport_ReturnsIMetaDataImport2VtableWithEx var (reader, provider) = CreateTestMetadata(); using var _ = provider; - IMetaDataImport2 wrapper = new MetaDataImportImpl(reader); + IMetaDataImport2 wrapper = new MetaDataImportImpl(reader, legacyImport: null, new()); nint pUnk = (nint)ComInterfaceMarshaller.ConvertToUnmanaged(wrapper); diff --git a/src/runtime/src/native/managed/cdac/tests/UnitTests/MethodTableTests.cs b/src/runtime/src/native/managed/cdac/tests/UnitTests/MethodTableTests.cs index ec2c5ea08375..deacd06d1d40 100644 --- a/src/runtime/src/native/managed/cdac/tests/UnitTests/MethodTableTests.cs +++ b/src/runtime/src/native/managed/cdac/tests/UnitTests/MethodTableTests.cs @@ -357,7 +357,7 @@ public unsafe void GetMethodTableDataReturnsEInvalidArgWhenEEClassPartiallyReada methodTable.EEClassOrCanonMT = tinyEEClass.Address; }); - ISOSDacInterface sosDac = new SOSDacImpl(target, legacyObj: null); + ISOSDacInterface sosDac = new SOSDacImpl(target, legacyObj: null, new()); DacpMethodTableData mtData = default; int hr = sosDac.GetMethodTableData(new ClrDataAddress(methodTablePtr), &mtData); AssertHResult(HResults.E_INVALIDARG, hr); @@ -440,7 +440,7 @@ public unsafe void GetMethodTableDataReturnsEInvalidArgWhenMethodTablePartiallyR helpers.PointerSize), tinyMethodTableAddr); }); - ISOSDacInterface sosDac = new SOSDacImpl(target, legacyObj: null); + ISOSDacInterface sosDac = new SOSDacImpl(target, legacyObj: null, new()); DacpMethodTableData mtData = default; int hr = sosDac.GetMethodTableData(new ClrDataAddress(tinyMethodTableAddr), &mtData); AssertHResult(HResults.E_INVALIDARG, hr); diff --git a/src/runtime/src/native/managed/cdac/tests/UnitTests/ObjectTests.cs b/src/runtime/src/native/managed/cdac/tests/UnitTests/ObjectTests.cs index 054bc9f8ece3..182ecec8e494 100644 --- a/src/runtime/src/native/managed/cdac/tests/UnitTests/ObjectTests.cs +++ b/src/runtime/src/native/managed/cdac/tests/UnitTests/ObjectTests.cs @@ -21,7 +21,7 @@ private static ISOSDacInterface CreateSOSDacInterface( MockTarget.Architecture arch, Action configure, Action? configureMocks = null) - => new SOSDacImpl(CreateObjectTarget(arch, configure, configureMocks), legacyObj: null); + => new SOSDacImpl(CreateObjectTarget(arch, configure, configureMocks), legacyObj: null, new()); private static TestPlaceholderTarget CreateObjectTarget( MockTarget.Architecture arch, diff --git a/src/runtime/src/native/managed/cdac/tests/UnitTests/SOSDacInterface5Tests.cs b/src/runtime/src/native/managed/cdac/tests/UnitTests/SOSDacInterface5Tests.cs index 5e5c6bc79f38..370b21090b14 100644 --- a/src/runtime/src/native/managed/cdac/tests/UnitTests/SOSDacInterface5Tests.cs +++ b/src/runtime/src/native/managed/cdac/tests/UnitTests/SOSDacInterface5Tests.cs @@ -125,7 +125,7 @@ private static ISOSDacInterface5 CreateDac5( .AddMockContract(mockPlatformMetadata) .Build(); - return new SOSDacImpl(target, legacyObj: null); + return new SOSDacImpl(target, legacyObj: null, new()); } private static int CallGetTieredVersions(ISOSDacInterface5 dac5, DacpTieredVersionData[] buffer, out int count, int rejitId = 0) diff --git a/src/runtime/src/native/managed/cdac/tests/UnitTests/SOSDacInterface8Tests.cs b/src/runtime/src/native/managed/cdac/tests/UnitTests/SOSDacInterface8Tests.cs index 1403e94f78a5..832b4216cd2f 100644 --- a/src/runtime/src/native/managed/cdac/tests/UnitTests/SOSDacInterface8Tests.cs +++ b/src/runtime/src/native/managed/cdac/tests/UnitTests/SOSDacInterface8Tests.cs @@ -33,7 +33,8 @@ private static ISOSDacInterface8 CreateWksDac8(MockTarget.Architecture arch) gc.FillPointers = s_fillPointers; }) .Build(), - legacyObj: null); + legacyObj: null, + new()); } private static ISOSDacInterface8 CreateSvrDac8(MockTarget.Architecture arch, out ulong heapAddr) @@ -46,7 +47,8 @@ private static ISOSDacInterface8 CreateSvrDac8(MockTarget.Architecture arch, out gc.FillPointers = s_fillPointers; }, out heapAddr) .Build(), - legacyObj: null); + legacyObj: null, + new()); } private static ulong SignExtend(ulong value, MockTarget.Architecture arch) @@ -90,7 +92,8 @@ public void GetNumberGenerations_WithFiveGenerations(MockTarget.Architecture arc gc.FillPointers = s_fillPointers; }) .Build(), - legacyObj: null); + legacyObj: null, + new()); uint numGenerations; int hr = dac8.GetNumberGenerations(&numGenerations); diff --git a/src/runtime/src/native/managed/cdac/tests/UnitTests/StackWalkTests.cs b/src/runtime/src/native/managed/cdac/tests/UnitTests/StackWalkTests.cs index 573df68d1ae3..7ef05e112998 100644 --- a/src/runtime/src/native/managed/cdac/tests/UnitTests/StackWalkTests.cs +++ b/src/runtime/src/native/managed/cdac/tests/UnitTests/StackWalkTests.cs @@ -457,7 +457,7 @@ private static IXCLRDataStackWalk CreateClrDataStackWalk(params TestStackDataFra .AddMockContract(stackWalk) .Build(); - return new ClrDataStackWalk(threadAddress, CLRDataStackWalkFlag.CLRDATA_SIMPFRAME_RUNTIME_UNMANAGED_CODE, target, legacyImpl: null); + return new ClrDataStackWalk(threadAddress, CLRDataStackWalkFlag.CLRDATA_SIMPFRAME_RUNTIME_UNMANAGED_CODE, target, legacyImpl: null, new()); } private sealed record TestStackDataFrameHandle(StackWalkState State, ulong StackPointerValue) : IStackDataFrameHandle diff --git a/src/runtime/src/native/managed/cdac/tests/UnitTests/TypeHandleTests.cs b/src/runtime/src/native/managed/cdac/tests/UnitTests/TypeHandleTests.cs index dc86c9262e58..c2306f233ebf 100644 --- a/src/runtime/src/native/managed/cdac/tests/UnitTests/TypeHandleTests.cs +++ b/src/runtime/src/native/managed/cdac/tests/UnitTests/TypeHandleTests.cs @@ -150,7 +150,7 @@ public void ClrDataTypeInstance_GetName(MockTarget.Architecture architecture) runtimeTypeSystem.TypeDescs.Add(typeHandle); runtimeTypeSystem.ElementTypes[typeHandle] = CorElementType.I4; TestPlaceholderTarget target = CreateTarget(architecture, runtimeTypeSystem); - IXCLRDataTypeInstance typeInstance = new ClrDataTypeInstance(target, typeHandle, null); + IXCLRDataTypeInstance typeInstance = new ClrDataTypeInstance(target, typeHandle, null, new()); uint nameLen = 0; Assert.Equal(HResults.S_OK, typeInstance.GetName(0, 0, &nameLen, null)); @@ -178,7 +178,7 @@ public void ClrDataTypeDefinition_GetNameFollowsBufferProtocol(MockTarget.Archit runtimeTypeSystem.TypeDescs.Add(typeHandle); runtimeTypeSystem.ElementTypes[typeHandle] = CorElementType.I4; TestPlaceholderTarget target = CreateTarget(architecture, runtimeTypeSystem); - IXCLRDataTypeDefinition typeDefinition = new ClrDataTypeDefinition(target, ModuleAddress, 0x02000001, typeHandle, null); + IXCLRDataTypeDefinition typeDefinition = new ClrDataTypeDefinition(target, ModuleAddress, 0x02000001, typeHandle, null, new()); uint nameLen = 0; Assert.Equal(HResults.S_OK, typeDefinition.GetName(0, 0, &nameLen, null)); @@ -215,7 +215,8 @@ public void ClrDataTypeDefinition_GetNameUsesMetadataForNullTypeHandle(MockTarge ModuleAddress, (uint)MetadataTokens.GetToken(typeDef), null, - null); + null, + new()); char[] nameBuffer = new char[32]; uint nameLen = 0; @@ -239,7 +240,7 @@ public void ClrDataTypeDefinition_GetCorElementTypeReturnsInternalType(MockTarge TestRuntimeTypeSystem runtimeTypeSystem = new(); runtimeTypeSystem.ElementTypes[typeHandle] = CorElementType.I4; TestPlaceholderTarget target = CreateTarget(architecture, runtimeTypeSystem); - IXCLRDataTypeDefinition typeDefinition = new ClrDataTypeDefinition(target, ModuleAddress, 0x02000001, typeHandle, null); + IXCLRDataTypeDefinition typeDefinition = new ClrDataTypeDefinition(target, ModuleAddress, 0x02000001, typeHandle, null, new()); uint elementType = 0; Assert.Equal(HResults.S_OK, typeDefinition.GetCorElementType(&elementType)); @@ -256,7 +257,7 @@ public void ClrDataTypeDefinition_GetTokenAndScopeReturnsConstructorValues(MockT TargetTypeHandle typeHandle = new(0x2002); TestRuntimeTypeSystem runtimeTypeSystem = new(); TestPlaceholderTarget target = CreateTarget(architecture, runtimeTypeSystem); - IXCLRDataTypeDefinition typeDefinition = new ClrDataTypeDefinition(target, ModuleAddress, Token, typeHandle, null); + IXCLRDataTypeDefinition typeDefinition = new ClrDataTypeDefinition(target, ModuleAddress, Token, typeHandle, null, new()); uint token = 0; DacComNullableByRef moduleOut = new(isNullRef: false); @@ -300,7 +301,7 @@ public void ClrDataTypeInstance_GetDefinition(MockTarget.Architecture architectu .AddMockContract(runtimeTypeSystem) .AddMockContract(loader) .Build(); - IXCLRDataTypeInstance typeInstance = new ClrDataTypeInstance(target, typeHandle, null); + IXCLRDataTypeInstance typeInstance = new ClrDataTypeInstance(target, typeHandle, null, new()); DacComNullableByRef typeDefinition = new(isNullRef: false); Assert.Equal(HResults.S_OK, typeInstance.GetDefinition(typeDefinition)); diff --git a/src/runtime/src/native/managed/cdac/tests/UsageTests/Microsoft.Diagnostics.DataContractReader.Usage.Tests.csproj b/src/runtime/src/native/managed/cdac/tests/UsageTests/Microsoft.Diagnostics.DataContractReader.Usage.Tests.csproj index de91a20bfe22..e210c3c55faf 100644 --- a/src/runtime/src/native/managed/cdac/tests/UsageTests/Microsoft.Diagnostics.DataContractReader.Usage.Tests.csproj +++ b/src/runtime/src/native/managed/cdac/tests/UsageTests/Microsoft.Diagnostics.DataContractReader.Usage.Tests.csproj @@ -3,7 +3,6 @@ $(NetCoreAppToolCurrent) enable true - false Microsoft.Diagnostics.DataContractReader.Usage.Tests diff --git a/src/runtime/src/native/managed/cdac/tests/UsageTests/UsageGraphFixture.cs b/src/runtime/src/native/managed/cdac/tests/UsageTests/UsageGraphFixture.cs index 3a06416737f3..3351129de4d3 100644 --- a/src/runtime/src/native/managed/cdac/tests/UsageTests/UsageGraphFixture.cs +++ b/src/runtime/src/native/managed/cdac/tests/UsageTests/UsageGraphFixture.cs @@ -15,7 +15,13 @@ public sealed class UsageGraphFixture public UsageGraphFixture() { CdacRoot = FindCdacRoot(); - Usage = UsageGraphAnalyzer.Analyze(CdacRoot.FullName); + Usage = UsageGraphAnalyzer.Analyze(new UsageGraphAnalysisOptions( + Path.Combine( + CdacRoot.FullName, + "Microsoft.Diagnostics.DataContractReader.Contracts", + "Microsoft.Diagnostics.DataContractReader.Contracts.csproj"), + "Microsoft.Diagnostics.DataContractReader.Contracts.CoreCLRContracts", + CdacRoot.FullName)); } public DirectoryInfo CdacRoot { get; } diff --git a/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/Analysis/UsageWalker.cs b/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/Analysis/UsageWalker.cs index a3dc5e769a90..fddb6762be07 100644 --- a/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/Analysis/UsageWalker.cs +++ b/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/Analysis/UsageWalker.cs @@ -107,6 +107,10 @@ private void HandleInvocation( } IMethodSymbol callee = inv.TargetMethod; + if (_symbols.IsGeneratedLayoutSet(callee.ContainingType)) + return; + if (TryHandleContractLookup(callee, label, subst)) + return; if (TryHandleDataDescriptorDependencies(callee, label, subst)) return; if (TryHandleStaticReference(callee, label)) @@ -153,6 +157,30 @@ private void HandleInvocation( } } + private bool TryHandleContractLookup( + IMethodSymbol method, + ContractVersion label, + Dictionary subst) + { + if (!_symbols.IsContractRegistry(method.ContainingType) || + method.TypeArguments.Length != 1 || + method.Name is not CdacSymbols.GetContractMethodName and + not CdacSymbols.TryGetContractMethodName) + { + return false; + } + + ITypeSymbol contractType = GenericDispatch.Resolve(method.TypeArguments[0], subst); + if (contractType is not INamedTypeSymbol contractInterface || + !_symbols.IsContract(contractInterface)) + { + return false; + } + + _collector.RecordContractUsed(label, new ContractInterface(contractInterface.Name)); + return true; + } + private bool TryHandleDataDescriptorDependencies( IMethodSymbol method, ContractVersion label, diff --git a/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/AnalysisOptions.cs b/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/AnalysisOptions.cs deleted file mode 100644 index 76d8435ddc6b..000000000000 --- a/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/AnalysisOptions.cs +++ /dev/null @@ -1,9 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace CdacUsageGraph; - -/// Parsed, validated command-line arguments for one analysis run. -internal sealed record AnalysisOptions( - DirectoryInfo CdacRoot, - DirectoryInfo OutputDirectory); diff --git a/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/AnalysisPipeline.cs b/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/AnalysisPipeline.cs index f2d7c1be2bb4..1fee38cfb1f3 100644 --- a/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/AnalysisPipeline.cs +++ b/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/AnalysisPipeline.cs @@ -25,28 +25,35 @@ internal sealed class AnalysisPipeline new JsonReportWriter(), ]; - private readonly AnalysisOptions _options; + private readonly UsageGraphAnalysisOptions _options; - public AnalysisPipeline(AnalysisOptions options) => _options = options; + public AnalysisPipeline(UsageGraphAnalysisOptions options) => _options = options; - /// - /// Builds the usage graph for the cDAC source rooted at (phases A-D). - /// Shared by the report pipeline, the docs command and the tests so they all analyze the - /// same way. - /// - public static UsageGraph BuildGraph(string cdacRoot) + public static UsageGraph BuildGraph(UsageGraphAnalysisOptions options) { - if (!Directory.Exists(Path.Combine(cdacRoot, CdacSymbols.ContractsProjectDirectory))) - throw new InvalidOperationException($"Could not find the cDAC Contracts project under '{cdacRoot}'; pass --cdac-root."); + ArgumentNullException.ThrowIfNull(options); + if (!File.Exists(options.ContractsProjectPath)) + { + throw new InvalidOperationException( + $"Could not find the cDAC Contracts project at '{options.ContractsProjectPath}'."); + } - return BuildGraph(CdacCompilationLoader.Load(cdacRoot), cdacRoot); + return BuildGraph( + CdacCompilationLoader.LoadProject(options.ContractsProjectPath), + options.SourceRoot, + options.ContractRegistrationTypeName); } - private static UsageGraph BuildGraph(CSharpCompilation compilation, string cdacRoot) + private static UsageGraph BuildGraph( + CSharpCompilation compilation, + string cdacRoot, + string contractRegistrationTypeName) { // Phase B: discovery. DataTypeIndex index = DataTypeDiscovery.BuildIndex(compilation); - IReadOnlyList registrations = ContractRegistrationParser.Parse(compilation); + IReadOnlyList registrations = ContractRegistrationParser.Parse( + compilation, + contractRegistrationTypeName); // Sanity guard: if discovery found no Data types or no registrations, the compilation // input has drifted (renamed anchor types, missing source) -- fail fast rather than emit @@ -62,15 +69,15 @@ private static UsageGraph BuildGraph(CSharpCompilation compilation, string cdacR public int Run() { - string cdacRoot = _options.CdacRoot.FullName; - // Phases A-D. - UsageGraph graph = BuildGraph(cdacRoot); + UsageGraph graph = BuildGraph(_options); Console.WriteLine($"Discovered {graph.DataTypeCount} Data types."); Console.WriteLine($"Parsed {graph.Contracts.Count} contract versions."); // Phase E: emit. - string outDir = _options.OutputDirectory.FullName; + string outDir = _options.OutputDirectory + ?? throw new InvalidOperationException( + "An output directory is required to emit usage graph reports."); Directory.CreateDirectory(outDir); Console.WriteLine($"Wrote outputs to {outDir}"); foreach (IReportWriter writer in s_writers) diff --git a/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/CdacSymbols.cs b/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/CdacSymbols.cs index 6958afadecd2..e5b405e4e76b 100644 --- a/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/CdacSymbols.cs +++ b/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/CdacSymbols.cs @@ -22,6 +22,8 @@ internal static class CdacSymbols "Microsoft.Diagnostics.DataContractReader.Contracts.CoreCLRContracts"; public const string IDataMetadataName = "Microsoft.Diagnostics.DataContractReader.Data.IData`1"; + public const string GeneratedLayoutSetMetadataName = + "Microsoft.Diagnostics.DataContractReader.Generated.LayoutSet"; public const string TargetMetadataName = "Microsoft.Diagnostics.DataContractReader.Target"; @@ -36,6 +38,8 @@ internal static class CdacSymbols public const string StaticReferenceAttributeMetadataName = "Microsoft.Diagnostics.DataContractReader.StaticReferenceAttribute"; public const string ContractRegistrationMethodName = "Register"; + public const string GetContractMethodName = "GetContract"; + public const string TryGetContractMethodName = "TryGetContract"; public const string ReadGlobalMethodName = "ReadGlobal"; public const string TryReadGlobalMethodName = "TryReadGlobal"; public const string ReadGlobalPointerMethodName = "ReadGlobalPointer"; diff --git a/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/CdacUsageGraph.csproj b/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/CdacUsageGraph.csproj index 861ef3e228b5..99fc806600fe 100644 --- a/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/CdacUsageGraph.csproj +++ b/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/CdacUsageGraph.csproj @@ -2,24 +2,22 @@ Exe - $(NetCoreAppToolCurrent) + $(CDacTfm) enable enable false - false + true true - CdacUsageGraph + Microsoft.Diagnostics.DataContractReader.UsageGraph $(NoWarn);NETCDAC0001 - - - - - + + + diff --git a/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/Commands.cs b/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/Commands.cs index fe7361f92bef..e4f7d7932d53 100644 --- a/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/Commands.cs +++ b/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/Commands.cs @@ -25,9 +25,15 @@ public static RootCommand Create() root.Options.Add(outputOption); root.SetAction(parseResult => { - AnalysisOptions options = new AnalysisOptions( - parseResult.GetValue(cdacRootOption)!, - parseResult.GetValue(outputOption)!); + DirectoryInfo cdacRoot = parseResult.GetValue(cdacRootOption)!; + UsageGraphAnalysisOptions options = new( + Path.Combine( + cdacRoot.FullName, + CdacSymbols.ContractsProjectDirectory, + CdacSymbols.ContractsProjectFile), + CdacSymbols.CoreCLRContractsMetadataName, + cdacRoot.FullName, + parseResult.GetValue(outputOption)!.FullName); return new AnalysisPipeline(options).Run(); }); @@ -71,7 +77,13 @@ private static Command CreateDocsCommand() FileInfo meanings = parseResult.GetValue(meaningsOption) ?? Locator.MeaningsFile(cdacRoot); FileInfo overrides = parseResult.GetValue(overridesOption) ?? Locator.OverridesFile(cdacRoot); - UsageGraph graph = AnalysisPipeline.BuildGraph(cdacRoot.FullName); + UsageGraph graph = UsageGraphAnalyzer.Analyze(new UsageGraphAnalysisOptions( + Path.Combine( + cdacRoot.FullName, + CdacSymbols.ContractsProjectDirectory, + CdacSymbols.ContractsProjectFile), + CdacSymbols.CoreCLRContractsMetadataName, + cdacRoot.FullName)); DocGenerator generator = new DocGenerator( graph, DocDescriptorMeanings.Load(meanings.FullName), diff --git a/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/Compilation/CdacCompilationLoader.cs b/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/Compilation/CdacCompilationLoader.cs index a8d066e3b7fb..f87e7e6d8b94 100644 --- a/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/Compilation/CdacCompilationLoader.cs +++ b/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/Compilation/CdacCompilationLoader.cs @@ -14,12 +14,8 @@ namespace CdacUsageGraph.Compilation; /// internal static class CdacCompilationLoader { - public static CSharpCompilation Load(string cdacRoot) + public static CSharpCompilation LoadProject(string projectPath) { - string projectPath = Path.Combine( - cdacRoot, - CdacSymbols.ContractsProjectDirectory, - CdacSymbols.ContractsProjectFile); if (!File.Exists(projectPath)) throw new InvalidOperationException($"Could not find the cDAC Contracts project at '{projectPath}'."); diff --git a/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/Discovery/ContractRegistrationParser.cs b/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/Discovery/ContractRegistrationParser.cs index af7bd35437ba..4163275f0aa2 100644 --- a/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/Discovery/ContractRegistrationParser.cs +++ b/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/Discovery/ContractRegistrationParser.cs @@ -16,7 +16,9 @@ namespace CdacUsageGraph.Discovery; /// internal static class ContractRegistrationParser { - public static IReadOnlyList Parse(CSharpCompilation compilation) + public static IReadOnlyList Parse( + CSharpCompilation compilation, + string contractRegistrationTypeName) { SymbolEqualityComparer comparer = SymbolEqualityComparer.Default; List registrations = new List(); @@ -26,7 +28,7 @@ public static IReadOnlyList Parse(CSharpCompilation compil CdacSymbols.IContractMetadataName); INamedTypeSymbol? coreContracts = compilation.GetTypeByMetadataName( - CdacSymbols.CoreCLRContractsMetadataName); + contractRegistrationTypeName); if (coreContracts is not null && contractRegistry is not null && iContract is not null) { foreach (IMethodSymbol reg in coreContracts.GetMembers().OfType()) @@ -77,6 +79,22 @@ create.Constructor is IMethodSymbol constructor && constructor)); } } + + foreach (IDefaultValueOperation defaultValue in inv.Descendants().OfType()) + { + if (defaultValue.Type is INamedTypeSymbol impl && + comparer.Equals(impl.ContainingAssembly, compilation.Assembly) && + compilation.IsAssignableTo(impl, iface) && + compilation.IsAssignableTo(impl, iContract)) + { + registrations.Add(new ContractRegistration( + new ContractVersion(new ContractInterface(iface.Name), version), + iface, + impl, + impl.InstanceConstructors.Single( + candidate => candidate.Parameters.Length == 0))); + } + } } } } diff --git a/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/Docs/DocDescriptorMeanings.cs b/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/Docs/DocDescriptorMeanings.cs index 45ed350911be..fdc496a04726 100644 --- a/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/Docs/DocDescriptorMeanings.cs +++ b/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/Docs/DocDescriptorMeanings.cs @@ -85,7 +85,7 @@ private static void ReadStringMap( private static void ValidateDescriptorKey(string key, string context) { - int dot = key.LastIndexOf('.', StringComparison.Ordinal); + int dot = key.LastIndexOf('.'); if (dot <= 0 || dot == key.Length - 1) throw new JsonException($"Invalid data-descriptor key '{key}' in {context}; expected 'Type.Field'."); } diff --git a/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/Docs/DocDescriptorOverrides.cs b/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/Docs/DocDescriptorOverrides.cs index ea59409adba5..7a4f0e3893b7 100644 --- a/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/Docs/DocDescriptorOverrides.cs +++ b/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/Docs/DocDescriptorOverrides.cs @@ -149,7 +149,7 @@ private static List ReadList(JsonElement entries, string context) private static void ValidateDescriptorKey(string key, string context) { - int dot = key.LastIndexOf('.', StringComparison.Ordinal); + int dot = key.LastIndexOf('.'); if (dot <= 0 || dot == key.Length - 1) throw new JsonException($"Invalid data-descriptor key '{key}' in {context}; expected 'Type.Field'."); } diff --git a/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/Docs/DocGenerator.cs b/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/Docs/DocGenerator.cs index cddeb0cca444..f088863bc827 100644 --- a/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/Docs/DocGenerator.cs +++ b/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/Docs/DocGenerator.cs @@ -403,7 +403,7 @@ private ContractVersionUsage GetContract(ContractVersion label) => private static (string Type, string Field) SplitDescriptorKey(string key) { - int dot = key.LastIndexOf('.', StringComparison.Ordinal); + int dot = key.LastIndexOf('.'); return (key.Substring(0, dot), key.Substring(dot + 1)); } diff --git a/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/Semantic/CdacSymbolMatcher.cs b/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/Semantic/CdacSymbolMatcher.cs index 036f8c2164e7..435d0b85607a 100644 --- a/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/Semantic/CdacSymbolMatcher.cs +++ b/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/Semantic/CdacSymbolMatcher.cs @@ -10,6 +10,7 @@ namespace CdacUsageGraph.Semantic; internal sealed class CdacSymbolMatcher { private readonly INamedTypeSymbol? _contractRegistry; + private readonly INamedTypeSymbol? _generatedLayoutSet; private readonly INamedTypeSymbol? _iContract; private readonly IMethodSymbol? _readGlobalPointer; private readonly IMethodSymbol? _tryReadGlobalPointer; @@ -22,6 +23,8 @@ public CdacSymbolMatcher(CSharpCompilation compilation) { _contractRegistry = compilation.GetTypeByMetadataName( CdacSymbols.ContractRegistryMetadataName); + _generatedLayoutSet = compilation.GetTypeByMetadataName( + CdacSymbols.GeneratedLayoutSetMetadataName); _iContract = compilation.GetTypeByMetadataName( CdacSymbols.IContractMetadataName); @@ -62,6 +65,9 @@ public CdacSymbolMatcher(CSharpCompilation compilation) public bool IsContractRegistry(ITypeSymbol? type) => Matches(type, _contractRegistry); + public bool IsGeneratedLayoutSet(ITypeSymbol? type) => + Matches(type, _generatedLayoutSet); + public bool IsContract(ITypeSymbol? type) => Matches(type, _iContract) || type is INamedTypeSymbol named && diff --git a/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/UsageGraphAnalyzer.cs b/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/UsageGraphAnalyzer.cs index 413ed5612329..3ee1872cbe83 100644 --- a/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/UsageGraphAnalyzer.cs +++ b/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/src/CdacUsageGraph/UsageGraphAnalyzer.cs @@ -8,8 +8,26 @@ namespace CdacUsageGraph; /// Analyzes cDAC source and returns its contract usage graph. public static class UsageGraphAnalyzer { - /// Builds the cDAC contract usage graph rooted at . - /// The path to the cDAC source root. + /// + /// Builds a contract usage graph for a cDAC contracts project and registration type. + /// + /// The project and semantic anchors for the analysis. /// The analyzed contract usage graph. - public static UsageGraph Analyze(string cdacRoot) => AnalysisPipeline.BuildGraph(cdacRoot); + public static UsageGraph Analyze(UsageGraphAnalysisOptions options) => + AnalysisPipeline.BuildGraph(options); } + +/// Inputs needed to analyze a cDAC contracts project. +/// Full path to the contracts project to load with MSBuild. +/// +/// Metadata name of the type containing calls to ContractRegistry.Register. +/// +/// Source root recorded in the resulting usage graph. +/// +/// Optional report output directory used by the command-line pipeline. +/// +public sealed record UsageGraphAnalysisOptions( + string ContractsProjectPath, + string ContractRegistrationTypeName, + string SourceRoot, + string? OutputDirectory = null); diff --git a/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/tests/CdacUsageGraph.Tests/DataTypeIndexTests.cs b/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/tests/CdacUsageGraph.Tests/DataTypeIndexTests.cs index 9dd7231e0d9d..bb6a9a30d464 100644 --- a/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/tests/CdacUsageGraph.Tests/DataTypeIndexTests.cs +++ b/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/tests/CdacUsageGraph.Tests/DataTypeIndexTests.cs @@ -764,6 +764,170 @@ private static CSharpCompilation CreateAnalysisCompilation(string source) => RuntimeReferences(), new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); + [Theory] + [InlineData("GetContract()")] + [InlineData("TryGetContract(out _)")] + public void GenericContractLookupRecordsContractDependency(string lookup) + { + string source = $$""" + namespace Microsoft.Diagnostics.DataContractReader + { + public class ContractRegistry + { + public TContract GetContract() + where TContract : Contracts.IContract + => throw null!; + + public bool TryGetContract(out TContract contract) + where TContract : Contracts.IContract + { + contract = default!; + return false; + } + } + } + namespace Microsoft.Diagnostics.DataContractReader.Contracts + { + public interface IContract { } + public interface IDependency : IContract { } + } + namespace Microsoft.Diagnostics.DataContractReader.Data + { + public interface IData { } + } + namespace Example + { + using Microsoft.Diagnostics.DataContractReader.Contracts; + + public interface ITest + { + void Read(Microsoft.Diagnostics.DataContractReader.ContractRegistry registry); + } + + public sealed class TestContract : ITest + { + public void Read( + Microsoft.Diagnostics.DataContractReader.ContractRegistry registry) + { + _ = registry.{{lookup}}; + } + } + } + """; + CSharpCompilation compilation = CreateAnalysisCompilation(source); + Assert.Empty(compilation.GetDiagnostics().Where( + diagnostic => diagnostic.Severity == DiagnosticSeverity.Error)); + INamedTypeSymbol implementation = compilation.GetTypeByMetadataName( + "Example.TestContract")!; + ContractVersion label = new(new ContractInterface("ITest"), "c1"); + UsageGraph graph = new UsageWalker( + compilation, + DataTypeDiscovery.BuildIndex(compilation)).Walk( + [Registration(label, implementation)], + ""); + + Assert.Contains( + new ContractInterface("IDependency"), + Contract(graph, label).ContractsUsed); + } + + [Fact] + public void GeneratedLayoutSetContractLookupIsNotAttributedToConsumer() + { + const string source = """ + namespace Microsoft.Diagnostics.DataContractReader + { + public sealed class CdacTypeAttribute : System.Attribute + { + public CdacTypeAttribute(params string[] names) { } + } + + public class ContractRegistry + { + public TContract GetContract() + where TContract : Contracts.IContract + => throw null!; + } + } + namespace Microsoft.Diagnostics.DataContractReader.Contracts + { + public interface IContract { } + public interface IDependency : IContract { } + } + namespace Microsoft.Diagnostics.DataContractReader.Generated + { + public static class LayoutSet + { + public static void Resolve( + Microsoft.Diagnostics.DataContractReader.ContractRegistry registry) + { + _ = registry.GetContract< + Microsoft.Diagnostics.DataContractReader.Contracts.IDependency>(); + } + } + } + namespace Microsoft.Diagnostics.DataContractReader.Data + { + public interface IData + where T : IData + { + static abstract T Create( + Microsoft.Diagnostics.DataContractReader.ContractRegistry registry); + } + + [Microsoft.Diagnostics.DataContractReader.CdacType("Widget")] + public sealed class Widget : IData + { + public static Widget Create( + Microsoft.Diagnostics.DataContractReader.ContractRegistry registry) + { + Microsoft.Diagnostics.DataContractReader.Generated.LayoutSet.Resolve( + registry); + return new Widget(); + } + } + } + namespace Example + { + public static class DataCache + { + public static T GetOrAdd() + where T : Microsoft.Diagnostics.DataContractReader.Data.IData + => default!; + } + + public interface ITest + { + void Read(); + } + + public sealed class TestContract : ITest + { + public void Read() + { + _ = DataCache.GetOrAdd< + Microsoft.Diagnostics.DataContractReader.Data.Widget>(); + } + } + } + """; + CSharpCompilation compilation = CreateAnalysisCompilation(source); + Assert.Empty(compilation.GetDiagnostics().Where( + diagnostic => diagnostic.Severity == DiagnosticSeverity.Error)); + INamedTypeSymbol implementation = compilation.GetTypeByMetadataName( + "Example.TestContract")!; + ContractVersion label = new(new ContractInterface("ITest"), "c1"); + UsageGraph graph = new UsageWalker( + compilation, + DataTypeDiscovery.BuildIndex(compilation)).Walk( + [Registration(label, implementation)], + ""); + + Assert.DoesNotContain( + new ContractInterface("IDependency"), + Contract(graph, label).ContractsUsed); + } + [Fact] public void InterfaceComputedPropertyUsesSameProvenanceAsDirectRead() { @@ -1137,7 +1301,9 @@ public void Register(string version, System.Func factory) { } new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); IReadOnlyList registrations = - ContractRegistrationParser.Parse(compilation); + ContractRegistrationParser.Parse( + compilation, + CdacSymbols.CoreCLRContractsMetadataName); ContractRegistration registration = Assert.Single(registrations); Assert.Equal(new ContractVersion(new ContractInterface("ITest"), "c1"), registration.Label); @@ -1146,6 +1312,53 @@ public void Register(string version, System.Func factory) { } Assert.Equal("Impl", registration.Constructor.ContainingType.Name); } + [Fact] + public void DiscoversDefaultValueFromConfiguredRegistrationType() + { + const string source = """ + namespace Microsoft.Diagnostics.DataContractReader + { + public sealed class ContractRegistry + { + public void Register(string version, System.Func factory) { } + } + } + namespace Microsoft.Diagnostics.DataContractReader.Contracts + { + public interface IContract { } + public interface ITest : IContract { } + public readonly struct Impl : ITest { } + } + namespace Example + { + public static class PrivateContracts + { + public static void Register( + Microsoft.Diagnostics.DataContractReader.ContractRegistry registry) + { + registry.Register< + Microsoft.Diagnostics.DataContractReader.Contracts.ITest>( + "n1", + _ => default( + Microsoft.Diagnostics.DataContractReader.Contracts.Impl)); + } + } + } + """; + CSharpCompilation compilation = CSharpCompilation.Create( + "ConfiguredRegistrationDiscoveryTest", + [CSharpSyntaxTree.ParseText(source)], + RuntimeReferences(), + new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); + + IReadOnlyList registrations = + ContractRegistrationParser.Parse(compilation, "Example.PrivateContracts"); + + ContractRegistration registration = Assert.Single(registrations); + Assert.Equal(new ContractVersion(new ContractInterface("ITest"), "n1"), registration.Label); + Assert.Equal("Impl", registration.Impl.Name); + } + [Fact] public void ContractEntryPointsFindsInterfacesReturnedThroughOutParameters() { diff --git a/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/tests/CdacUsageGraph.Tests/UsageWalkerIntegrationTests.cs b/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/tests/CdacUsageGraph.Tests/UsageWalkerIntegrationTests.cs index c824489bb010..9ad1c8cf5107 100644 --- a/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/tests/CdacUsageGraph.Tests/UsageWalkerIntegrationTests.cs +++ b/src/runtime/src/native/managed/cdac/tools/CdacUsageGraph/tests/CdacUsageGraph.Tests/UsageWalkerIntegrationTests.cs @@ -31,7 +31,15 @@ private static (UsageGraph Graph, string Root)? BuildRealGraphCore() if (root is null) return null; - return (AnalysisPipeline.BuildGraph(root.FullName), root.FullName); + return ( + UsageGraphAnalyzer.Analyze(new UsageGraphAnalysisOptions( + Path.Combine( + root.FullName, + CdacSymbols.ContractsProjectDirectory, + CdacSymbols.ContractsProjectFile), + CdacSymbols.CoreCLRContractsMetadataName, + root.FullName)), + root.FullName); } [Fact] @@ -56,7 +64,10 @@ public void MSBuildWorkspaceLoadsGeneratedContractsCompilation() DirectoryInfo? root = Locator.FindCdacRoot(); if (root is null) return; // cDAC source not found (running outside the repo) - CSharpCompilation compilation = CdacCompilationLoader.Load(root.FullName); + CSharpCompilation compilation = CdacCompilationLoader.LoadProject(Path.Combine( + root.FullName, + CdacSymbols.ContractsProjectDirectory, + CdacSymbols.ContractsProjectFile)); INamedTypeSymbol jitNotification = compilation.GetTypeByMetadataName( "Microsoft.Diagnostics.DataContractReader.Data.JITNotification")!; diff --git a/src/runtime/src/native/minipal/cpufeatures.c b/src/runtime/src/native/minipal/cpufeatures.c index b517dee0b4ed..ed7d76127798 100644 --- a/src/runtime/src/native/minipal/cpufeatures.c +++ b/src/runtime/src/native/minipal/cpufeatures.c @@ -677,13 +677,13 @@ int minipal_getcpufeatures(void) #endif // HOST_UNIX #if defined(HOST_WINDOWS) - if (!IsProcessorFeaturePresent(PF_ARM_V8_INSTRUCTIONS_AVAILABLE) || - !IsProcessorFeaturePresent(PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE)) + if (!IsProcessorFeaturePresent(PF_ARM_V8_INSTRUCTIONS_AVAILABLE)) { // One of the baseline ISAs is not supported result |= IntrinsicConstants_Invalid; } - else + + if (IsProcessorFeaturePresent(PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE)) { result |= ARM64IntrinsicConstants_Atomics; } diff --git a/src/runtime/src/native/minipal/log.h b/src/runtime/src/native/minipal/log.h index e23b3efd4598..ec217ee788f4 100644 --- a/src/runtime/src/native/minipal/log.h +++ b/src/runtime/src/native/minipal/log.h @@ -27,7 +27,7 @@ typedef enum #define minipal_log_print_error(...) minipal_log_print(minipal_log_flags_error, __VA_ARGS__) #define minipal_log_print_info(...) minipal_log_print(minipal_log_flags_info, __VA_ARGS__) #define minipal_log_print_verbose(...) minipal_log_print(minipal_log_flags_verbose, __VA_ARGS__) -int minipal_log_print(minipal_log_flags flags, const char* fmt, ... ); +int minipal_log_print(minipal_log_flags flags, const char* fmt, ... ) MINIPAL_ATTR_FORMAT_PRINTF(2, 3); #define minipal_log_vprint_fatal(...) minipal_log_vprint(minipal_log_flags_fatal, __VA_ARGS__) #define minipal_log_vprint_error(...) minipal_log_vprint(minipal_log_flags_error, __VA_ARGS__) diff --git a/src/runtime/src/native/minipal/types.h b/src/runtime/src/native/minipal/types.h index 3fbc6170468e..352aa5f27e96 100644 --- a/src/runtime/src/native/minipal/types.h +++ b/src/runtime/src/native/minipal/types.h @@ -6,22 +6,11 @@ #include -#if defined(TARGET_32BIT) || defined(TARGET_OSX) || defined(TARGET_WINDOWS) || defined(TARGET_OPENBSD) -#define FORMAT_PREFIX "l" +// Format attribute for printf-style functions +#ifdef __GNUC__ +#define MINIPAL_ATTR_FORMAT_PRINTF(fmt_pos, arg_pos) __attribute__ ((__format__(__printf__, fmt_pos, arg_pos))) #else -#define FORMAT_PREFIX "" -#endif - -#ifndef PRIX64 -#define PRIX64 FORMAT_PREFIX "lX" -#endif - -#ifndef PRIx64 -#define PRIx64 FORMAT_PREFIX "lx" -#endif - -#ifndef PRIu64 -#define PRIu64 FORMAT_PREFIX "lu" +#define MINIPAL_ATTR_FORMAT_PRINTF(fmt_pos, arg_pos) #endif #ifdef TARGET_WINDOWS diff --git a/src/runtime/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/AssetsComputingHelper.cs b/src/runtime/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/AssetsComputingHelper.cs index 3c386681dab3..673fc225ea59 100644 --- a/src/runtime/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/AssetsComputingHelper.cs +++ b/src/runtime/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/AssetsComputingHelper.cs @@ -59,32 +59,32 @@ public static bool ShouldFilterCandidate( var extension = candidate.GetMetadata("Extension"); var fileName = candidate.GetMetadata("FileName"); var assetType = candidate.GetMetadata("AssetType"); - bool fromMonoPackage = IsFromRuntimePack(candidate); + bool fromRuntimePack = IsFromRuntimePack(candidate); // A similar logic is in ReadWasmNativeAssetsFromFileSystem target for RuntimeTests reason = extension switch { - ".a" when fromMonoPackage => "extension is .a is not supported.", - ".c" when fromMonoPackage => "extension is .c is not supported.", - ".h" when fromMonoPackage => "extension is .h is not supported.", + ".a" when fromRuntimePack => "extension is .a is not supported.", + ".c" when fromRuntimePack => "extension is .c is not supported.", + ".h" when fromRuntimePack => "extension is .h is not supported.", // It is safe to filter out all XML files since we are not interested in any XML file from the list // of ResolvedFilesToPublish to become a static web asset. Things like this include XML doc files and // so on. ".xml" => "it is a documentation file", - ".rsp" when fromMonoPackage => "extension is .rsp is not supported.", - ".props" when fromMonoPackage => "extension is .props is not supported.", + ".rsp" when fromRuntimePack => "extension is .rsp is not supported.", + ".props" when fromRuntimePack => "extension is .props is not supported.", ".blat" when !timezoneSupport => "timezone support is not enabled.", ".dat" when invariantGlobalization && fileName.StartsWith("icudt") => "invariant globalization is enabled", ".dat" when loadFullICUData && fileName != "icudt" => "full ICU data is enabled", ".dat" when !string.IsNullOrEmpty(customIcuCandidateFilename) && fileName != customIcuCandidateFilename => "custom icu file either from absolute path or from runtime pack path will be used", ".dat" when IsDefaultIcuMode() && !(icuShardsFromRuntimePack.Any(f => f == fileName)) => "automatic icu shard selection, based on application culture, is enabled", - ".json" when fromMonoPackage && (fileName == "wasm-props" || fileName == "package") => $"{fileName}{extension} is not used by Blazor", - ".ts" when fromMonoPackage && fileName == "dotnet.d" => "dotnet type definition is not used by Blazor", - ".map" when emitSourceMap && fromMonoPackage && (fileName == "dotnet.js" || fileName == "dotnet.runtime.js") => null, - ".map" when emitSourceMap && fromMonoPackage && enableDiagnostics && fileName == "dotnet.diagnostics.js" => null, - ".map" when emitSourceMap && fromMonoPackage && !enableDiagnostics && fileName == "dotnet.diagnostics.js" => "perf tracing is not enabled", - ".map" when !emitSourceMap && fromMonoPackage => "source map file is not published", - ".ts" when fromMonoPackage && fileName == "dotnet-legacy.d" => "dotnet type definition is not used by Blazor", + ".json" when fromRuntimePack && (fileName == "wasm-props" || fileName == "package") => $"{fileName}{extension} is not used by Blazor", + ".ts" when fromRuntimePack && fileName == "dotnet.d" => "dotnet type definition is not used by Blazor", + ".map" when emitSourceMap && fromRuntimePack && (fileName == "dotnet.js" || fileName == "dotnet.runtime.js") => null, + ".map" when emitSourceMap && fromRuntimePack && enableDiagnostics && fileName == "dotnet.diagnostics.js" => null, + ".map" when emitSourceMap && fromRuntimePack && !enableDiagnostics && fileName == "dotnet.diagnostics.js" => "perf tracing is not enabled", + ".map" when !emitSourceMap && fromRuntimePack => "source map file is not published", + ".ts" when fromRuntimePack && fileName == "dotnet-legacy.d" => "dotnet type definition is not used by Blazor", ".js" when assetType == "native" && dotnetJsSingleThreadNames.Contains(fileName) => null, ".js" when assetType == "native" && enableDiagnostics && dotnetJsDiagNames.Contains(fileName) => null, ".js" when assetType == "native" && !enableDiagnostics && dotnetJsDiagNames.Contains(fileName) => "perf tracing is not enabled", diff --git a/src/runtime/src/tasks/WasmAppBuilder/coreclr/InterpToNativeGenerator.cs b/src/runtime/src/tasks/WasmAppBuilder/coreclr/InterpToNativeGenerator.cs index 664be16c40bb..e5183182df80 100644 --- a/src/runtime/src/tasks/WasmAppBuilder/coreclr/InterpToNativeGenerator.cs +++ b/src/runtime/src/tasks/WasmAppBuilder/coreclr/InterpToNativeGenerator.cs @@ -69,7 +69,7 @@ private static void Emit(StreamWriter w, IEnumerable cookies) { var toks = SignatureMapper.ParseSignatureTokens(sig); if (toks[0][0] == 'S' && toks[0].Length > 1) - structReturnSizes.Add(int.Parse(toks[0].Substring(1))); + structReturnSizes.Add(SignatureMapper.GetStructSize(toks[0])); } w.Write( @@ -184,6 +184,11 @@ static List ArgsWithSlotOffsets(List args) int slot = 0; foreach (var token in args) { + if (token[0] == 'A') + { + slot = (slot + 1) & ~1; + } + result.Add($"{SignatureMapper.TokenToArgType(token)}({slot})"); slot += SignatureMapper.TokenToSlotCount(token); } @@ -195,7 +200,7 @@ static List ArgsWithSlotOffsets(List args) { // For struct returns, use the typedef so emcc generates the correct sret ABI if (returnToken[0] == 'S' && returnToken.Length > 1) - return (false, $"wasm_ret_{returnToken}"); + return (false, $"wasm_ret_S{SignatureMapper.GetStructSize(returnToken)}"); return new(returnToken == "v", SignatureMapper.TokenToNativeType(returnToken)); } diff --git a/src/runtime/src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs b/src/runtime/src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs index e6c3e4d0ee1c..c1f07ec01067 100644 --- a/src/runtime/src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs +++ b/src/runtime/src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs @@ -15,26 +15,33 @@ namespace Microsoft.WebAssembly.Build.Tasks.CoreClr; // (section "Wasm Signature String Encoding"). internal static class SignatureMapper { - // Hardcoded struct sizes for types that crossgen2 encodes as S. + // Hardcoded struct layouts for types that crossgen2 encodes as struct tokens. // The fully general case is handled by crossgen2's type system; these // cover the small set of multi-field structs that appear in InternalCall // and PInvoke signatures. - private static readonly Dictionary s_knownStructSizes = new() + private static readonly Dictionary s_knownStructLayouts = new() { - ["System.Runtime.CompilerServices.QCallModule"] = 8, - ["System.Runtime.CompilerServices.QCallAssembly"] = 8, - ["System.Runtime.CompilerServices.QCallTypeHandle"] = 8, - ["System.GC+GCHeapHardLimitInfo"] = 64, + ["System.Runtime.CompilerServices.QCallModule"] = (8, 8), + ["System.Runtime.CompilerServices.QCallAssembly"] = (8, 8), + ["System.Runtime.CompilerServices.QCallTypeHandle"] = (8, 8), + ["System.GC+GCHeapHardLimitInfo"] = (64, 8), // Used by WBT tests - ["WasmAppBuilderTestsPairStruct"] = 8, - ["WasmAppBuilderTests.S"] = 8, - ["WasmAppBuilderTests.Test+S"] = 8, + ["WasmAppBuilderTestsPairStruct"] = (8, 8), + ["WasmAppBuilderTests.S"] = (8, 8), + ["WasmAppBuilderTests.Test+S"] = (8, 8), }; - internal static char? TypeToChar(Type t, LogAdapter log, out bool isByRefStruct, out int structSize, int depth = 0) + private static char? TypeToChar( + Type t, + LogAdapter log, + out bool isByRefStruct, + out int structSize, + out int structAlignment, + int depth = 0) { isByRefStruct = false; structSize = 0; + structAlignment = 0; if (depth > 5) { log.Warning("WASM0064", $"Unbounded recursion detected through parameter type '{t.Name}'"); @@ -81,7 +88,7 @@ internal static class SignatureMapper else if (t.IsEnum) { Type underlyingType = t.GetEnumUnderlyingType(); - c = TypeToChar(underlyingType, log, out _, out structSize, ++depth); + c = TypeToChar(underlyingType, log, out _, out structSize, out structAlignment, ++depth); } else if (t.IsPointer) c = 'i'; @@ -93,19 +100,20 @@ internal static class SignatureMapper if (fields.Length == 1) { Type fieldType = fields[0].FieldType; - return TypeToChar(fieldType, log, out isByRefStruct, out structSize, ++depth); + return TypeToChar(fieldType, log, out isByRefStruct, out structSize, out structAlignment, ++depth); } else { string fullName = t.FullName ?? t.Name; - if (s_knownStructSizes.TryGetValue(fullName, out int size)) + if (s_knownStructLayouts.TryGetValue(fullName, out (int Size, int Alignment) layout)) { - structSize = size; + structSize = layout.Size; + structAlignment = layout.Alignment; } else { log.Error("WASM0067", - $"SignatureMapper: unknown multi-field struct '{fullName}' (fields: {fields.Length}) — add its size to s_knownStructSizes in SignatureMapper.cs"); + $"SignatureMapper: unknown multi-field struct '{fullName}' (fields: {fields.Length}) — add its layout to s_knownStructLayouts in SignatureMapper.cs"); return null; } @@ -120,14 +128,17 @@ internal static class SignatureMapper return c; } + internal static char? TypeToChar(Type t, LogAdapter log, out bool isByRefStruct, out int structSize, int depth = 0) + => TypeToChar(t, log, out isByRefStruct, out structSize, out _, depth); + internal static char? TypeToChar(Type t, LogAdapter log, out bool isByRefStruct, int depth = 0) => TypeToChar(t, log, out isByRefStruct, out _, depth); /// /// Builds the multi-char token for a type in the signature string. - /// For most types this is a single character; for multi-field structs it is "S<N>". + /// For most types this is a single character; for multi-field structs it is a struct token. /// - private static string? TypeToSignatureToken(Type t, LogAdapter log, out bool isByRefStruct) + private static string? TypeToSignatureToken(Type t, LogAdapter log, out bool isByRefStruct, bool isReturn = false) { // Types the wasm ABI splits across several by-value slots are rejected in interop rather // than encoded. Exposing them here means teaching the thunk generator that one signature @@ -141,12 +152,12 @@ internal static class SignatureMapper return null; } - char? c = TypeToChar(t, log, out isByRefStruct, out int structSize); + char? c = TypeToChar(t, log, out isByRefStruct, out int structSize, out int structAlignment); if (c is null) return null; if (c == 'S' && structSize > 0) - return $"S{structSize}"; + return $"{(!isReturn && structAlignment > 8 ? 'A' : 'S')}{structSize}"; return c.Value.ToString(); } @@ -218,7 +229,7 @@ private static bool HasNumericElementType(Type t) public static string? MethodToSignature(MethodInfo method, LogAdapter log, bool includeThis = false) { - string? returnToken = TypeToSignatureToken(method.ReturnType, log, out bool resultIsByRef); + string? returnToken = TypeToSignatureToken(method.ReturnType, log, out bool resultIsByRef, isReturn: true); if (returnToken is null) return null; @@ -253,8 +264,8 @@ private static bool HasNumericElementType(Type t) /// /// Parses a signature string into individual tokens. - /// Single-char types produce one-char tokens; S<N> produces a multi-char token like "S8" or "S64", - /// and a multi-slot parameter produces a two-char token like "l2" or "V4". + /// Single-char types produce one-char tokens; struct encodings produce multi-char tokens like + /// "S8" or "A32", and a multi-slot parameter produces a two-char token like "l2" or "V4". /// The 'a' and 'p' suffixes are included as their own tokens. /// public static List ParseSignatureTokens(string signature) @@ -263,10 +274,10 @@ public static List ParseSignatureTokens(string signature) int i = 0; while (i < signature.Length) { - if (signature[i] == 'S') + if (signature[i] is 'S' or 'A') { int start = i; - i++; // skip 'S' + i++; // skip 'S'/'A' while (i < signature.Length && char.IsDigit(signature[i])) i++; tokens.Add(signature.Substring(start, i - start)); @@ -309,7 +320,7 @@ public static string TokenToNativeType(string token) 'l' => "int64_t", 'f' => "float", 'd' => "double", - 'S' => "int32_t", + 'S' or 'A' => "int32_t", 'T' => "int32_t", 'p' => "PCODE", _ => throw new InvalidSignatureCharException(token[0]) @@ -326,7 +337,7 @@ public static string TokenToNameType(string token) 'l' => "I64", 'f' => "F32", 'd' => "F64", - 'S' => token, // e.g. "S8", "S64" — encodes size in the name + 'S' or 'A' => token, 'T' => "This", 'p' => "PE", _ => throw new InvalidSignatureCharException(token[0]) @@ -342,7 +353,7 @@ public static string TokenToArgType(string token) 'l' => "ARG_I64", 'f' => "ARG_F32", 'd' => "ARG_F64", - 'S' => "ARG_IND", + 'S' or 'A' => "ARG_IND", 'T' => "ARG_I32", _ => throw new InvalidSignatureCharException(token[0]) }; @@ -350,17 +361,22 @@ public static string TokenToArgType(string token) /// /// Returns the number of INTERP_STACK_SLOT_SIZE slots consumed by a token. - /// Struct tokens (S<N>) consume max((size + 7) / 8, 1) slots; all others consume 1. + /// Struct tokens consume max((size + 7) / 8, 1) slots; all others consume 1. /// public static int TokenToSlotCount(string token) { - if (token[0] != 'S' || token.Length < 2) + if (token[0] is not ('S' or 'A') || token.Length < 2) return 1; - int size = int.Parse(token.Substring(1)); + int size = GetStructSize(token); return Math.Max((size + 7) / 8, 1); } + internal static int GetStructSize(string token) + { + return int.Parse(token.Substring(1)); + } + // Legacy single-char overloads — still used by consumers that don't encounter S tokens. public static string CharToNativeType(char c) => TokenToNativeType(c.ToString()); public static string CharToNameType(char c) => TokenToNameType(c.ToString()); diff --git a/src/runtime/src/tasks/WasmAppBuilder/mono/PInvokeCollector.cs b/src/runtime/src/tasks/WasmAppBuilder/mono/PInvokeCollector.cs index 28d0f0f680a6..ec6aaa7b66d5 100644 --- a/src/runtime/src/tasks/WasmAppBuilder/mono/PInvokeCollector.cs +++ b/src/runtime/src/tasks/WasmAppBuilder/mono/PInvokeCollector.cs @@ -290,7 +290,7 @@ private PlatformSupport EvaluatePlatformAttributes(IList at { if (cattr.AttributeType.FullName == "System.Runtime.Versioning.UnsupportedOSPlatformAttribute" && cattr.ConstructorArguments.Count > 0 && - cattr.ConstructorArguments[0].Value?.ToString() == _targetOS) + MatchesTargetOS(cattr.ConstructorArguments[0].Value?.ToString())) { return PlatformSupport.Unsupported; } @@ -298,7 +298,7 @@ private PlatformSupport EvaluatePlatformAttributes(IList at cattr.ConstructorArguments.Count > 0) { hasSupportedOSPlatform = true; - if (cattr.ConstructorArguments[0].Value?.ToString() == _targetOS) + if (MatchesTargetOS(cattr.ConstructorArguments[0].Value?.ToString())) hasSupportedTarget = true; } } @@ -313,6 +313,22 @@ private PlatformSupport EvaluatePlatformAttributes(IList at return PlatformSupport.Unknown; } + + private bool MatchesTargetOS(string? platformName) + { + if (string.Equals(platformName, _targetOS, StringComparison.OrdinalIgnoreCase)) + return true; + + if (platformName?.StartsWith(_targetOS, StringComparison.OrdinalIgnoreCase) != true) + return false; + +#if NETFRAMEWORK + string version = platformName.Substring(_targetOS.Length); +#else + ReadOnlySpan version = platformName.AsSpan(_targetOS.Length); +#endif + return Version.TryParse(version, out _); + } } internal sealed class PInvokeCallbackComparer : IComparer diff --git a/src/runtime/src/tests/Interop/COM/ComWrappers/API/Program.cs b/src/runtime/src/tests/Interop/COM/ComWrappers/API/Program.cs index da49300f166e..6377fcb2e7c3 100644 --- a/src/runtime/src/tests/Interop/COM/ComWrappers/API/Program.cs +++ b/src/runtime/src/tests/Interop/COM/ComWrappers/API/Program.cs @@ -1083,43 +1083,50 @@ public void ComWrappersNoLockAroundQueryInterface() Console.WriteLine($"Running {nameof(ComWrappersNoLockAroundQueryInterface)}..."); var cw = new RecursiveSimpleComWrappers(); + var managedObject = new RecursiveCrossThreadQI(cw); - IntPtr comObject = cw.GetOrCreateComInterfaceForObject(new RecursiveCrossThreadQI(cw), CreateComInterfaceFlags.None); + IntPtr comObject = cw.GetOrCreateComInterfaceForObject(managedObject, CreateComInterfaceFlags.None); try { + // The nested call has to use this same COM instance. The RCW cache is partitioned into buckets + // keyed off the COM instance, so using a different instance would only exercise the same lock by + // chance, and the test would no longer reliably catch a regression. + managedObject.NestedComObject = comObject; + _ = cw.GetOrCreateObjectForComInstance(comObject, CreateObjectFlags.TrackerObject); } finally { Marshal.Release(comObject); } + + Assert.True(managedObject.NestedCallCompleted); } - private class RecursiveCrossThreadQI(ComWrappers? wrappers) : ICustomQueryInterface + private class RecursiveCrossThreadQI(ComWrappers wrappers) : ICustomQueryInterface { + public IntPtr NestedComObject { get; set; } + + public bool NestedCallCompleted { get; private set; } + CustomQueryInterfaceResult ICustomQueryInterface.GetInterface(ref Guid iid, out IntPtr ppv) { ppv = IntPtr.Zero; - if (iid == ComWrappersHelper.IID_IReferenceTracker && wrappers is not null) + if (iid == ComWrappersHelper.IID_IReferenceTracker) { Console.WriteLine("Attempting to create a new COM object on a different thread."); + IntPtr nestedComObject = NestedComObject; Thread thread = new Thread(() => { - IntPtr comObject = wrappers.GetOrCreateComInterfaceForObject(new RecursiveCrossThreadQI(null), CreateComInterfaceFlags.None); - try - { - // Make sure that ComWrappers isn't locking in GetOrCreateObjectForComInstance - // around the QI call by calling it on a different thread from within a QI call to register a new managed wrapper - // for a COM object representing "this". - _ = wrappers.GetOrCreateObjectForComInstance(comObject, CreateObjectFlags.None); - } - finally - { - Marshal.Release(comObject); - } + // Make sure that ComWrappers isn't locking in GetOrCreateObjectForComInstance + // around the QI call by calling it on a different thread from within a QI call to register a new managed wrapper + // for a COM object representing "this". + _ = wrappers.GetOrCreateObjectForComInstance(nestedComObject, CreateObjectFlags.None); }); thread.Start(); - thread.Join(TimeSpan.FromSeconds(20)); // 20 seconds should be more than long enough for the thread to complete + + // The result is recorded and asserted by the caller. + NestedCallCompleted = thread.Join(TimeSpan.FromSeconds(20)); // 20 seconds should be more than long enough for the thread to complete } return CustomQueryInterfaceResult.Failed; diff --git a/src/runtime/src/tests/JIT/Regression/JitBlue/Runtime_130700/Runtime_130700.cs b/src/runtime/src/tests/JIT/Regression/JitBlue/Runtime_130700/Runtime_130700.cs new file mode 100644 index 000000000000..696f0cb6a19c --- /dev/null +++ b/src/runtime/src/tests/JIT/Regression/JitBlue/Runtime_130700/Runtime_130700.cs @@ -0,0 +1,207 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// Redundant branch opts jump-threaded flow around a block and sharpened that block's +// predicate VN, but left dominator info claiming the block still dominated its successors. +// A later dominator-based inference then folded away the null check on an 'isinst' result, +// so the 'is MergeFile' arm below was entered with a null value. + +#nullable enable + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading; +using Xunit; + +namespace Runtime_130700; + +internal static class Contract +{ + public static void Assert(bool condition, string? message = "", params object?[] args) + { + if (condition) + { + return; + } + + message ??= string.Empty; + throw new Exception(string.Format(message, args)); + } + + public static void Fail(string? message = "", params object?[] args) + { + message ??= string.Empty; + throw new Exception(string.Format(message, args)); + } + + public static T AssertNotNull(T? o, string? message = "", params object?[] args) + where T : class + { + if (o != null) + { + return o; + } + + message ??= string.Empty; + throw new Exception(string.Format(message, args)); + } +} + +internal static class EnumerableExtensions +{ + public static void ForEach(this IEnumerable? enumeration, Action? action) + { + if (enumeration == null || action == null) + { + return; + } + + foreach (T item in enumeration) + { + action(item); + } + } +} + +public abstract class MergeHierarchyMember +{ +} + +public class MergeFile : MergeHierarchyMember +{ + public string FileName + { + get => field; + set + { + Contract.Assert(!string.IsNullOrWhiteSpace(value)); + field = value; + } + } + + public MergeFile(string fileName) + { + Contract.Assert(fileName.All(c => c != Path.DirectorySeparatorChar && c != Path.AltDirectorySeparatorChar), + "FileName must not contain any directory separator characters"); + FileName = fileName; + } +} + +public class MergeHierarchy : MergeHierarchyMember +{ + public enum MergeMode + { + Automatic, + Manual, + PostProcessing + } + + public MergeMode Mode { get; set; } + + public List Children { get; set; } = new(); + + public MergeHierarchy(MergeMode mergeMode) + { + Mode = mergeMode; + } + + public MergeHierarchy(MergeMode mergeMode, params (MergeHierarchyMember Member, long Offset)[] membersWithOffsets) + : this(mergeMode) + { + Contract.AssertNotNull(membersWithOffsets); + membersWithOffsets.ForEach(elem => AddMergeHierarchyMember(elem.Member, elem.Offset)); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + internal void AddMergeHierarchyMember(MergeHierarchyMember mergeHierarchyMember, long offset) + { + Contract.AssertNotNull(mergeHierarchyMember); + Contract.Assert(mergeHierarchyMember is not MergeHierarchy { Mode: MergeMode.PostProcessing }, + "Post-processing can only be the root node of a merge hierarchy"); + + // 'mergeHierarchyMember is MergeFile' is only evaluated when Mode is Automatic. + Contract.Assert(Mode is not MergeMode.Automatic || (Mode is MergeMode.Automatic && mergeHierarchyMember is MergeFile), + "An automatic merge hierarchy cannot be nested in another automatic merge hierarchy"); + + Children.Add(new ChildWithOffset(mergeHierarchyMember, offset)); + } +} + +public class ChildWithOffset +{ + public enum MemberKind + { + MergeFile, + MergeHierarchy, + } + + public MemberKind Kind { get; set; } + + public MergeHierarchy? MergeHierarchy { get; set; } + + public MergeFile? MergeFile + { + get => field; + set + { + Contract.Assert(value is null || !string.IsNullOrWhiteSpace(value.FileName)); + field = value; + } + } + + public long Offset { get; set; } + + public ChildWithOffset(MergeHierarchyMember mergeHierarchyMember, long offset) + { + switch (mergeHierarchyMember) + { + case MergeFile mergeFile: + Kind = MemberKind.MergeFile; + MergeFile = mergeFile; + break; + case MergeHierarchy mergeHierarchy: + Kind = MemberKind.MergeHierarchy; + MergeHierarchy = mergeHierarchy; + break; + default: + Contract.Fail("Unknown MergeHierarchyMember"); + break; + } + + Offset = offset; + } +} + +public class Runtime_130700 +{ + [Fact] + public static void TestEntryPoint() + { + // Fixed sub-hierarchy, so nothing is retained across iterations. + MergeHierarchy inner = new MergeHierarchy( + MergeHierarchy.MergeMode.Manual, (new MergeFile("hello"), 0), (new MergeFile("world"), 0)); + + // AddMergeHierarchyMember has to reach tier-1 with profile data, so keep calling it + // (with both a MergeHierarchy and a MergeFile argument) while it tiers up. + for (int round = 0; round < 100; round++) + { + for (int i = 0; i < 1000; i++) + { + MergeHierarchy hierarchy = new MergeHierarchy(MergeHierarchy.MergeMode.Manual, (inner, i)); + hierarchy.AddMergeHierarchyMember(new MergeFile($"file{i}"), offset: i); + + if (hierarchy.Children[0].Kind != ChildWithOffset.MemberKind.MergeHierarchy || + hierarchy.Children[1].Kind != ChildWithOffset.MemberKind.MergeFile) + { + Assert.Fail($"Wrong member kinds at round {round}, iteration {i}: " + + $"{hierarchy.Children[0].Kind}, {hierarchy.Children[1].Kind}"); + } + } + + Thread.Sleep(1); + } + } +} diff --git a/src/runtime/src/tests/JIT/Regression/JitBlue/Runtime_130700/Runtime_130700.csproj b/src/runtime/src/tests/JIT/Regression/JitBlue/Runtime_130700/Runtime_130700.csproj new file mode 100644 index 000000000000..c8b6bc7450ed --- /dev/null +++ b/src/runtime/src/tests/JIT/Regression/JitBlue/Runtime_130700/Runtime_130700.csproj @@ -0,0 +1,14 @@ + + + True + 1 + + true + + + + + + + + diff --git a/src/runtime/src/tests/JIT/Regression/JitBlue/Runtime_132268/Runtime_132268.cs b/src/runtime/src/tests/JIT/Regression/JitBlue/Runtime_132268/Runtime_132268.cs new file mode 100644 index 000000000000..2c2e116d3c7e --- /dev/null +++ b/src/runtime/src/tests/JIT/Regression/JitBlue/Runtime_132268/Runtime_132268.cs @@ -0,0 +1,47 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// Regression test for https://github.com/dotnet/runtime/issues/132268 +// +// Requires an arm64 AOT compilation (crossgen2/NativeAOT) to hit the byref constant path. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Xunit; + +namespace Runtime_132268; + +public unsafe class Runtime_132268 +{ + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ref byte GetNonNullPinnableReference(Span buffer) + { + return ref buffer.Length != 0 ? ref MemoryMarshal.GetReference(buffer) : ref Unsafe.AsRef((void*)1); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static int Consume(byte* p, int length) => p is null ? -1 : length; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int Pin(Span destination) + { + fixed (byte* p = &GetNonNullPinnableReference(destination)) + { + int status = Consume(p, destination.Length); + + if (status != 0) + { + throw new InvalidOperationException(); + } + + return status; + } + } + + [Fact] + public static void TestEntryPoint() + { + Assert.Equal(0, Pin(default)); + } +} diff --git a/src/runtime/src/tests/JIT/Regression/JitBlue/WasmR2RStructAlignment/WasmR2RStructAlignment.cs b/src/runtime/src/tests/JIT/Regression/JitBlue/WasmR2RStructAlignment/WasmR2RStructAlignment.cs new file mode 100644 index 000000000000..5cd2e5a40cc1 --- /dev/null +++ b/src/runtime/src/tests/JIT/Regression/JitBlue/WasmR2RStructAlignment/WasmR2RStructAlignment.cs @@ -0,0 +1,164 @@ +// 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.Runtime; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +using System.Runtime.InteropServices; +using Xunit; + +namespace System.Runtime +{ + [AttributeUsage(AttributeTargets.Method)] + internal sealed class BypassReadyToRunAttribute : Attribute + { + } +} + +public class WasmR2RStructAlignment +{ + // The leading long leaves the aggregate at an offset where 8- and 16-byte alignment differ. + // The trailing byref makes any disagreement shift a managed pointer as well as the aggregate. + private const long Prefix = 0x1122334455667788; + private const int InitialTrailer = 0x12345678; + private const int UpdatedTrailer = 0x76543210; + private static readonly object s_reference = new(); + + [Fact] + public static void TestEntryPoint() + { + Assert.Equal(UpdatedTrailer, R2RAutoLayoutCaller()); + Assert.Equal(UpdatedTrailer, InterpretedAutoLayoutCaller()); + Assert.Equal(UpdatedTrailer, R2RExplicitLayoutCaller()); + Assert.Equal(UpdatedTrailer, InterpretedExplicitLayoutCaller()); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static int R2RAutoLayoutCaller() + { + int trailer = InitialTrailer; + ValueTuple, Vector128> value = + (Vector128.Create(1.0f), Vector128.Create(2.0f)); + + int result = InterpretedAutoLayoutCallee(Prefix, value, ref trailer); + + Assert.Equal(UpdatedTrailer, trailer); + return result; + } + + [BypassReadyToRun] + [MethodImpl(MethodImplOptions.NoInlining)] + private static int InterpretedAutoLayoutCaller() + { + int trailer = InitialTrailer; + ValueTuple, Vector128> value = + (Vector128.Create(1.0f), Vector128.Create(2.0f)); + + int result = R2RAutoLayoutCallee(Prefix, value, ref trailer); + + Assert.Equal(UpdatedTrailer, trailer); + return result; + } + + [BypassReadyToRun] + [MethodImpl(MethodImplOptions.NoInlining)] + private static int InterpretedAutoLayoutCallee( + long prefix, + ValueTuple, Vector128> value, + ref int trailer) + { + Assert.Equal(Prefix, prefix); + Assert.Equal(Vector128.Create(1.0f), value.Item1); + Assert.Equal(Vector128.Create(2.0f), value.Item2); + Assert.Equal(InitialTrailer, trailer); + trailer = UpdatedTrailer; + return trailer; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static int R2RAutoLayoutCallee( + long prefix, + ValueTuple, Vector128> value, + ref int trailer) + { + Assert.Equal(Prefix, prefix); + Assert.Equal(Vector128.Create(1.0f), value.Item1); + Assert.Equal(Vector128.Create(2.0f), value.Item2); + Assert.Equal(InitialTrailer, trailer); + trailer = UpdatedTrailer; + return trailer; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static int R2RExplicitLayoutCaller() + { + int trailer = InitialTrailer; + ExplicitLayout value = new() + { + Vector = Vector128.Create(3.0f), + Reference = s_reference, + }; + + int result = InterpretedExplicitLayoutCallee(Prefix, value, ref trailer); + + Assert.Equal(UpdatedTrailer, trailer); + return result; + } + + [BypassReadyToRun] + [MethodImpl(MethodImplOptions.NoInlining)] + private static int InterpretedExplicitLayoutCaller() + { + int trailer = InitialTrailer; + ExplicitLayout value = new() + { + Vector = Vector128.Create(3.0f), + Reference = s_reference, + }; + + int result = R2RExplicitLayoutCallee(Prefix, value, ref trailer); + + Assert.Equal(UpdatedTrailer, trailer); + return result; + } + + [BypassReadyToRun] + [MethodImpl(MethodImplOptions.NoInlining)] + private static int InterpretedExplicitLayoutCallee( + long prefix, + ExplicitLayout value, + ref int trailer) + { + Assert.Equal(Prefix, prefix); + Assert.Equal(Vector128.Create(3.0f), value.Vector); + Assert.Same(s_reference, value.Reference); + Assert.Equal(InitialTrailer, trailer); + trailer = UpdatedTrailer; + return trailer; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static int R2RExplicitLayoutCallee( + long prefix, + ExplicitLayout value, + ref int trailer) + { + Assert.Equal(Prefix, prefix); + Assert.Equal(Vector128.Create(3.0f), value.Vector); + Assert.Same(s_reference, value.Reference); + Assert.Equal(InitialTrailer, trailer); + trailer = UpdatedTrailer; + return trailer; + } + + [StructLayout(LayoutKind.Explicit, Size = 32)] + private struct ExplicitLayout + { + [FieldOffset(0)] + public Vector128 Vector; + + [FieldOffset(16)] + public object Reference; + } +} diff --git a/src/runtime/src/tests/JIT/Regression/JitBlue/WasmR2RStructAlignment/WasmR2RStructAlignment.csproj b/src/runtime/src/tests/JIT/Regression/JitBlue/WasmR2RStructAlignment/WasmR2RStructAlignment.csproj new file mode 100644 index 000000000000..3f2e2c1efbdc --- /dev/null +++ b/src/runtime/src/tests/JIT/Regression/JitBlue/WasmR2RStructAlignment/WasmR2RStructAlignment.csproj @@ -0,0 +1,11 @@ + + + true + true + true + true + + + + + diff --git a/src/runtime/src/tests/JIT/Regression/Regression_ro_2.csproj b/src/runtime/src/tests/JIT/Regression/Regression_ro_2.csproj index ecfbfd02be8a..509acf83e471 100644 --- a/src/runtime/src/tests/JIT/Regression/Regression_ro_2.csproj +++ b/src/runtime/src/tests/JIT/Regression/Regression_ro_2.csproj @@ -128,6 +128,7 @@ + diff --git a/src/runtime/src/tests/Loader/classloader/StaticVirtualMethods/Regression/GitHub_130545.cs b/src/runtime/src/tests/Loader/classloader/StaticVirtualMethods/Regression/GitHub_130545.cs index ee5cdfda3658..180ed07ab92a 100644 --- a/src/runtime/src/tests/Loader/classloader/StaticVirtualMethods/Regression/GitHub_130545.cs +++ b/src/runtime/src/tests/Loader/classloader/StaticVirtualMethods/Regression/GitHub_130545.cs @@ -5,6 +5,7 @@ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using TestLibrary; using Xunit; // Regression test for https://github.com/dotnet/runtime/issues/130545 @@ -120,6 +121,7 @@ public static Rgba32 Decode() public class Test { + [ActiveIssue("https://github.com/dotnet/runtime/issues/132030", typeof(Utilities), nameof(Utilities.IsNativeAot))] [Fact] public static void DelegateOverStaticAbstractThroughGsharedvt() { diff --git a/src/runtime/src/tests/Loader/classloader/StaticVirtualMethods/Regression/GitHub_130545.csproj b/src/runtime/src/tests/Loader/classloader/StaticVirtualMethods/Regression/GitHub_130545.csproj index a49d38ec92d3..8e0c79f1185d 100644 --- a/src/runtime/src/tests/Loader/classloader/StaticVirtualMethods/Regression/GitHub_130545.csproj +++ b/src/runtime/src/tests/Loader/classloader/StaticVirtualMethods/Regression/GitHub_130545.csproj @@ -5,4 +5,7 @@ + + + diff --git a/src/runtime/src/tests/Loader/classloader/generics/regressions/131537/test131537.cs b/src/runtime/src/tests/Loader/classloader/generics/regressions/131537/test131537.cs new file mode 100644 index 000000000000..1b358ea4ca0e --- /dev/null +++ b/src/runtime/src/tests/Loader/classloader/generics/regressions/131537/test131537.cs @@ -0,0 +1,49 @@ +// 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 Xunit; + +// Regression test for https://github.com/dotnet/runtime/issues/131537 +// (WASM manifestation of https://github.com/dotnet/runtime/issues/66220). +// +// Constructing a non-generic Queue from a List> enumerates the list +// through the non-generic IEnumerator, whose Current getter boxes each element +// Nullable -> object. On Mono WASM with an AOT'd corelib and this assembly +// running in the interpreter (the WasmTestOnChrome-MONO-ST configuration), the +// concrete Nullable is never instantiated in the AOT'd corelib's TYPESPEC +// table, so the required gsharedvt out-sig wrapper object(Nullable) is not +// emitted and the boxing call traps with "function signature mismatch". +public class Test_131537 +{ + [Fact] + public static void BoxNullableThroughNonGenericEnumerator() + { + RoundTrip(new List { 1, 2, 3 }); + RoundTrip(new List { 1, 2, 3 }); + RoundTrip(new List { (Half)1, (Half)2, (Half)3 }); + RoundTrip(new List { 1m, 2m, 3m }); + RoundTrip(new List { Guid.Empty, Guid.NewGuid() }); + RoundTrip(new List { DateTime.UnixEpoch, DateTime.MaxValue }); + RoundTrip(new List { DateTimeOffset.UnixEpoch, DateTimeOffset.MaxValue }); + RoundTrip(new List { TimeSpan.Zero, TimeSpan.FromSeconds(5) }); + } + + private static void RoundTrip(List source) + { + // Queue(ICollection) enumerates via the non-generic IEnumerator, boxing + // each element T -> object. This is the call that crashes when the + // object(Nullable) gsharedvt out-sig wrapper is missing. + var queue = new Queue(source); + Assert.Equal(source.Count, queue.Count); + + int i = 0; + foreach (object boxed in queue) + { + Assert.Equal(source[i], (T)boxed); + i++; + } + } +} diff --git a/src/runtime/src/tests/Loader/classloader/generics/regressions/131537/test131537.csproj b/src/runtime/src/tests/Loader/classloader/generics/regressions/131537/test131537.csproj new file mode 100644 index 000000000000..06c63a526492 --- /dev/null +++ b/src/runtime/src/tests/Loader/classloader/generics/regressions/131537/test131537.csproj @@ -0,0 +1,18 @@ + + + 1 + + + + + + + + + + <_AOT_InternalForceInterpretAssemblies Include="test131537.dll" /> + + diff --git a/src/runtime/src/tests/async/asyncversion-inline/asyncversion-inline.cs b/src/runtime/src/tests/async/asyncversion-inline/asyncversion-inline.cs new file mode 100644 index 000000000000..0197eb8e3e50 --- /dev/null +++ b/src/runtime/src/tests/async/asyncversion-inline/asyncversion-inline.cs @@ -0,0 +1,173 @@ +// 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.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; +using Xunit; + +// The async version of a non-async method does not save and restore contexts of its own: +// CORINFO_ASYNC_SAVE_CONTEXTS is not set for it, so it has no resumed indicator. Its +// awaits instead inherit the inlining call's indicator and contexts, which means a +// resumption inside one has to set the *caller's* indicator directly. +// +// These tests pin down that the caller still observes its own context after a suspension +// that happened inside such an inlined frame. +public class Async2AsyncVersionInline +{ + private sealed class NamedContext : SynchronizationContext + { + public readonly string Name; + + public NamedContext(string name) => Name = name; + + // Queue the callback and re-establish this context around it, as a real UI-style + // context would. Running it inline instead would make an awaiting loop recurse + // one frame deeper per iteration, since each suspension posts from inside the + // previous callback. + public override void Post(SendOrPostCallback d, object? state) + { + ThreadPool.QueueUserWorkItem(_ => + { + SynchronizationContext currentCtx = Current; + SetSynchronizationContext(this); + try + { + d(state); + } + finally + { + SetSynchronizationContext(currentCtx); + } + }); + } + } + + // Always suspends and resumes on a thread pool thread, so resumption never happens on + // whatever context the awaiting frames were running in. + private struct AlwaysThreadPoolAwaitable : INotifyCompletion + { + public bool IsCompleted => false; + + public void OnCompleted(Action continuation) + { + ThreadPool.QueueUserWorkItem(_ => continuation()); + } + + public void GetResult() + { + } + + public AlwaysThreadPoolAwaitable GetAwaiter() => this; + } + + private static readonly NamedContext s_syncContext1 = new NamedContext("ctx1"); + private static readonly NamedContext s_syncContext2 = new NamedContext("ctx2"); + + private static string CurrentContextName => (SynchronizationContext.Current as NamedContext)?.Name ?? "none"; + + private static int s_suspensions; + + private static async Task Suspend() + { + await new AlwaysThreadPoolAwaitable(); + Interlocked.Increment(ref s_suspensions); + } + + // Not marked async: the runtime compiles an async version of this whose IL is this + // body, and that version tail awaits Suspend without any context handling of its own. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Task TailAwaitingVersion() => Suspend(); + + private static string s_contextAfterAwait = ""; + + // The caller does have context handling. If the resumption inside the inlined async + // version fails to mark this frame resumed, this frame's restore will run as though it + // never suspended. + private static async Task CallerAwaitsVersion() + { + SynchronizationContext.SetSynchronizationContext(s_syncContext1); + await TailAwaitingVersion(); + s_contextAfterAwait = CurrentContextName; + } + + [Fact] + public static void ContextRestoredAfterInlinedAsyncVersionSuspends() + { + s_contextAfterAwait = ""; + s_suspensions = 0; + RunOn(s_syncContext1, CallerAwaitsVersion); + Assert.Equal(1, s_suspensions); + Assert.Equal("ctx1", s_contextAfterAwait); + } + + private static string s_outerContextAfterAwait = ""; + private static string s_innerContextAfterAwait = ""; + + // Two levels: an async frame with its own contexts, awaiting an async version, which + // tail awaits another frame that has its own contexts and suspends. + private static async Task InnerWithContexts() + { + SynchronizationContext.SetSynchronizationContext(s_syncContext2); + await Suspend(); + s_innerContextAfterAwait = CurrentContextName; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Task VersionOverInner() => InnerWithContexts(); + + private static async Task OuterAwaitsVersion() + { + SynchronizationContext.SetSynchronizationContext(s_syncContext1); + await VersionOverInner(); + s_outerContextAfterAwait = CurrentContextName; + } + + [Fact] + public static void ContextsRestoredThroughInlinedAsyncVersion() + { + s_outerContextAfterAwait = ""; + s_innerContextAfterAwait = ""; + s_suspensions = 0; + RunOn(s_syncContext1, OuterAwaitsVersion); + Assert.Equal(1, s_suspensions); + Assert.Equal("ctx2", s_innerContextAfterAwait); + Assert.Equal("ctx1", s_outerContextAfterAwait); + } + + // The version is awaited in a non-tail position, so the caller has work after it. + private static async Task CallerWithWorkAfter() + { + SynchronizationContext.SetSynchronizationContext(s_syncContext1); + await TailAwaitingVersion(); + s_contextAfterAwait = CurrentContextName; + return 42; + } + + [Fact] + public static void ContextRestoredWhenVersionAwaitedInNonTailPosition() + { + s_contextAfterAwait = ""; + s_suspensions = 0; + int result = 0; + RunOn(s_syncContext1, async () => { result = await CallerWithWorkAfter(); }); + Assert.Equal(1, s_suspensions); + Assert.Equal(42, result); + Assert.Equal("ctx1", s_contextAfterAwait); + } + + private static void RunOn(SynchronizationContext ctx, Func body) + { + SynchronizationContext original = SynchronizationContext.Current; + SynchronizationContext.SetSynchronizationContext(ctx); + try + { + body().GetAwaiter().GetResult(); + } + finally + { + SynchronizationContext.SetSynchronizationContext(original); + } + } +} diff --git a/src/runtime/src/tests/async/asyncversion-inline/asyncversion-inline.csproj b/src/runtime/src/tests/async/asyncversion-inline/asyncversion-inline.csproj new file mode 100644 index 000000000000..6c8c63b83414 --- /dev/null +++ b/src/runtime/src/tests/async/asyncversion-inline/asyncversion-inline.csproj @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/runtime/src/tests/async/inlined-asyncversion-frames/inlined-asyncversion-frames.cs b/src/runtime/src/tests/async/inlined-asyncversion-frames/inlined-asyncversion-frames.cs new file mode 100644 index 000000000000..7650ae6b0808 --- /dev/null +++ b/src/runtime/src/tests/async/inlined-asyncversion-frames/inlined-asyncversion-frames.cs @@ -0,0 +1,123 @@ +// 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.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; +using System.Threading.Tasks.Sources; +using Xunit; + +// The async version of a non-async task returning method forwards through a transparent +// await, and that await runs in whatever frame it ends up in rather than in one of its +// own. Once such a version is inlined into an async frame that was itself inlined, the +// await has to take the enclosing frame's contexts, so that a suspension records that the +// frame resumed. Getting that wrong leaves the enclosing frame believing it never resumed +// and running its context handling again on stale state. +public class Async2InlinedAsyncVersionFrames +{ + // Completes synchronously for even values and asynchronously for odd ones, so a loop + // mixes iterations that suspend with iterations that do not. + private sealed class Source : IValueTaskSource + { + private ManualResetValueTaskSourceCore _core; + + public Source() => _core.RunContinuationsAsynchronously = true; + + public ValueTask Start(int value) + { + _core.Reset(); + if ((value & 1) == 0) + { + _core.SetResult(value); + } + else + { + ThreadPool.QueueUserWorkItem(_ => _core.SetResult(value)); + } + + return new ValueTask(this, _core.Version); + } + + public int GetResult(short token) => _core.GetResult(token); + public ValueTaskSourceStatus GetStatus(short token) => _core.GetStatus(token); + public void OnCompleted(Action c, object? s, short t, ValueTaskSourceOnCompletedFlags f) + => _core.OnCompleted(c, s, t, f); + } + + private static readonly Source s_source = new Source(); + + // Non-async, so the suspension ends up inside its async version, a frame with no + // contexts of its own. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ValueTask Leaf(int value) => s_source.Start(value); + + // Async, so this frame does own contexts. Its awaits must stay out of a try region or + // it cannot be inlined at all. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static async ValueTask Middle(int[] values) + { + long total = 0; + for (int i = 0; i < values.Length; i++) + { + total += await Leaf(values[i]).ConfigureAwait(false); + total += await Leaf(values[i] + 1).ConfigureAwait(false); + } + + return total + 1; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static async ValueTask Other(int[] values) + { + return await Leaf(values.Length).ConfigureAwait(false); + } + + // Non-async and not inlinable, so its async version is compiled as a root that has no + // contexts, with the context owning frames above spliced into it. + [MethodImpl(MethodImplOptions.NoInlining)] + private static ValueTask Dispatch(int[] values, bool other) + { + if (other) + { + return Other(values); + } + + return Middle(values); + } + + private static async Task Call(int[] values, bool other) + { + return await Dispatch(values, other).ConfigureAwait(false); + } + + [Theory] + [InlineData(false, 16L)] + [InlineData(true, 3L)] + public static void SuspendingInsideInlinedAsyncVersion(bool other, long expected) + { + int[] values = new int[] { 1, 2, 3 }; + for (int i = 0; i < 20; i++) + { + Assert.Equal(expected, Call(values, other).GetAwaiter().GetResult()); + } + } + + // Both frames in turn, so the method has suspension points from more than one of them. + private static async Task CallBoth(int[] values) + { + long a = await Dispatch(values, true).ConfigureAwait(false); + long b = await Dispatch(values, false).ConfigureAwait(false); + return a + b; + } + + [Fact] + public static void SuspendingInsideSeveralInlinedFrames() + { + int[] values = new int[] { 1, 2, 3 }; + for (int i = 0; i < 20; i++) + { + Assert.Equal(19L, CallBoth(values).GetAwaiter().GetResult()); + } + } +} diff --git a/src/runtime/src/tests/async/inlined-asyncversion-frames/inlined-asyncversion-frames.csproj b/src/runtime/src/tests/async/inlined-asyncversion-frames/inlined-asyncversion-frames.csproj new file mode 100644 index 000000000000..6c8c63b83414 --- /dev/null +++ b/src/runtime/src/tests/async/inlined-asyncversion-frames/inlined-asyncversion-frames.csproj @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/runtime/src/tests/async/inlined-frame-configureawait/inlined-frame-configureawait.cs b/src/runtime/src/tests/async/inlined-frame-configureawait/inlined-frame-configureawait.cs new file mode 100644 index 000000000000..360bb4718921 --- /dev/null +++ b/src/runtime/src/tests/async/inlined-frame-configureawait/inlined-frame-configureawait.cs @@ -0,0 +1,120 @@ +// 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.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; +using Xunit; + +// A frame that awaited with ConfigureAwait(false) does not want to be brought back onto +// the SynchronizationContext that was current when it suspended. That has to hold for the +// logical return of an inlined async frame too. +public class Async2InlinedFrameConfigureAwait +{ + private sealed class TrackingContext : SynchronizationContext + { + public int Posts; + + public override void Post(SendOrPostCallback d, object? state) + { + Interlocked.Increment(ref Posts); + ThreadPool.QueueUserWorkItem(_ => + { + SynchronizationContext currentCtx = Current; + SetSynchronizationContext(this); + try + { + d(state); + } + finally + { + SetSynchronizationContext(currentCtx); + } + }); + } + } + + private struct AlwaysThreadPoolAwaitable : INotifyCompletion + { + public bool IsCompleted => false; + + public void OnCompleted(Action continuation) => ThreadPool.QueueUserWorkItem(_ => continuation()); + + public void GetResult() + { + } + + public AlwaysThreadPoolAwaitable GetAwaiter() => this; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static async Task Suspends() + { + await new AlwaysThreadPoolAwaitable(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static async Task MiddleConfigured() + { + await Suspends().ConfigureAwait(false); + } + + private static async Task OuterConfigured() + { + await MiddleConfigured().ConfigureAwait(false); + } + + [Fact] + public static void ConfiguredAwaitDoesNotReturnToContext() + { + SynchronizationContext original = SynchronizationContext.Current; + TrackingContext tracking = new TrackingContext(); + try + { + SynchronizationContext.SetSynchronizationContext(tracking); + OuterConfigured().GetAwaiter().GetResult(); + } + finally + { + SynchronizationContext.SetSynchronizationContext(original); + } + + Assert.Equal(0, tracking.Posts); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static async Task LoopMiddleConfigured(int iterations) + { + for (int i = 0; i < iterations; i++) + { + await Suspends().ConfigureAwait(false); + } + } + + private static async Task LoopOuterConfigured(int iterations) + { + for (int i = 0; i < iterations; i++) + { + await LoopMiddleConfigured(iterations).ConfigureAwait(false); + } + } + + [Fact] + public static void ConfiguredAwaitInLoopDoesNotReturnToContext() + { + SynchronizationContext original = SynchronizationContext.Current; + TrackingContext tracking = new TrackingContext(); + try + { + SynchronizationContext.SetSynchronizationContext(tracking); + LoopOuterConfigured(5).GetAwaiter().GetResult(); + } + finally + { + SynchronizationContext.SetSynchronizationContext(original); + } + + Assert.Equal(0, tracking.Posts); + } +} diff --git a/src/runtime/src/tests/async/inlined-frame-configureawait/inlined-frame-configureawait.csproj b/src/runtime/src/tests/async/inlined-frame-configureawait/inlined-frame-configureawait.csproj new file mode 100644 index 000000000000..6c8c63b83414 --- /dev/null +++ b/src/runtime/src/tests/async/inlined-frame-configureawait/inlined-frame-configureawait.csproj @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/runtime/src/tests/async/inlined-frame-contexts/inlined-frame-contexts.cs b/src/runtime/src/tests/async/inlined-frame-contexts/inlined-frame-contexts.cs new file mode 100644 index 000000000000..133d3e503135 --- /dev/null +++ b/src/runtime/src/tests/async/inlined-frame-contexts/inlined-frame-contexts.cs @@ -0,0 +1,203 @@ +// 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.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; +using Xunit; + +// Behaviors that must be preserved when runtime async calls are inlined. These are the +// worked examples from docs/design/coreclr/jit/runtime-async-inlining.md. +// +// Inlining removes both a call site and a callee, and with them the context handling the +// async infrastructure would otherwise have performed at each frame boundary. These tests +// pin down the observable results of that handling, so they must produce the same answers +// whether or not the calls are inlined. +// +// The inner frames are marked AggressiveInlining so that the inlining actually happens +// rather than being left to the profitability heuristic, which rejects these callees. +public class Async2InlinedFrameContexts +{ + private sealed class NamedContext : SynchronizationContext + { + public readonly string Name; + + public NamedContext(string name) => Name = name; + + // Queue the callback and re-establish this context around it, as a real UI-style + // context would. Running it inline instead would make an awaiting loop recurse + // one frame deeper per iteration, since each suspension posts from inside the + // previous callback. + public override void Post(SendOrPostCallback d, object? state) + { + ThreadPool.QueueUserWorkItem(_ => + { + SynchronizationContext currentCtx = Current; + SetSynchronizationContext(this); + try + { + d(state); + } + finally + { + SetSynchronizationContext(currentCtx); + } + }); + } + } + + // Always suspends and resumes on a thread pool thread, so resumption never happens on + // whatever context the awaiting frames were running in. + private struct AlwaysThreadPoolAwaitable : INotifyCompletion + { + public bool IsCompleted => false; + + public void OnCompleted(Action continuation) + { + ThreadPool.QueueUserWorkItem(_ => continuation()); + } + + public void GetResult() + { + } + + public AlwaysThreadPoolAwaitable GetAwaiter() => this; + } + + private static readonly NamedContext s_syncContext1 = new NamedContext("ctx1"); + private static readonly NamedContext s_syncContext2 = new NamedContext("ctx2"); + + private static string CurrentContextName => (SynchronizationContext.Current as NamedContext)?.Name ?? "none"; + + // Each frame sets its own synchronization context before awaiting, so each frame's + // continuation captures a different one. After the innermost await resumes on the + // thread pool, every frame must be back on the context it captured by the time it + // observes it again. + private static string s_fooContextAfterAwait = ""; + private static string s_barContextAfterAwait = ""; + + private static async Task ContextFoo() + { + SynchronizationContext.SetSynchronizationContext(s_syncContext1); + await ContextBar(); + s_fooContextAfterAwait = CurrentContextName; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static async Task ContextBar() + { + SynchronizationContext.SetSynchronizationContext(s_syncContext2); + await ContextBaz(); + s_barContextAfterAwait = CurrentContextName; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static async Task ContextBaz() + { + await new AlwaysThreadPoolAwaitable(); + } + + [Fact] + public static void SynchronizationContextIsRestoredPerFrame() + { + SynchronizationContext original = SynchronizationContext.Current; + try + { + ContextFoo().GetAwaiter().GetResult(); + } + finally + { + SynchronizationContext.SetSynchronizationContext(original); + } + + // Bar awaited Baz having set ctx2, so Bar resumes on ctx2. Foo awaited Bar having + // set ctx1, so Foo resumes on ctx1. + Assert.Equal("ctx2", s_barContextAfterAwait); + Assert.Equal("ctx1", s_fooContextAfterAwait); + } + + private static readonly AsyncLocal s_local = new AsyncLocal(); + + private static int s_bazLocalAfterAwait; + private static int s_barLocalAfterAwait; + private static int s_fooLocalAfterAwait; + + private static async Task LocalFoo() + { + s_local.Value = 1; + await LocalBar(); + s_fooLocalAfterAwait = s_local.Value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static async Task LocalBar() + { + s_local.Value = 2; + await LocalBaz(); + s_barLocalAfterAwait = s_local.Value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static async Task LocalBaz() + { + s_local.Value = 3; + await new AlwaysThreadPoolAwaitable(); + s_bazLocalAfterAwait = s_local.Value; + } + + [Fact] + public static void ExecutionContextIsRestoredPerFrame() + { + LocalFoo().GetAwaiter().GetResult(); + + // Each frame sees the AsyncLocal value it set, because every frame boundary + // restores the ExecutionContext that frame captured. + Assert.Equal(3, s_bazLocalAfterAwait); + Assert.Equal(2, s_barLocalAfterAwait); + Assert.Equal(1, s_fooLocalAfterAwait); + } + + // The same, but with the awaits inside loops so the frames suspend and resume + // repeatedly. A frame's captured contexts must survive later suspensions of the + // frames nested inside it. + private static async Task LoopFoo(int iterations) + { + SynchronizationContext.SetSynchronizationContext(s_syncContext1); + s_local.Value = 1; + + for (int i = 0; i < iterations; i++) + { + await LoopBar(iterations); + Assert.Equal("ctx1", CurrentContextName); + Assert.Equal(1, s_local.Value); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static async Task LoopBar(int iterations) + { + SynchronizationContext.SetSynchronizationContext(s_syncContext2); + s_local.Value = 2; + + for (int i = 0; i < iterations; i++) + { + await new AlwaysThreadPoolAwaitable(); + Assert.Equal(2, s_local.Value); + } + } + + [Fact] + public static void ContextsSurviveRepeatedSuspensions() + { + SynchronizationContext original = SynchronizationContext.Current; + try + { + LoopFoo(4).GetAwaiter().GetResult(); + } + finally + { + SynchronizationContext.SetSynchronizationContext(original); + } + } +} diff --git a/src/runtime/src/tests/async/inlined-frame-contexts/inlined-frame-contexts.csproj b/src/runtime/src/tests/async/inlined-frame-contexts/inlined-frame-contexts.csproj new file mode 100644 index 000000000000..6c8c63b83414 --- /dev/null +++ b/src/runtime/src/tests/async/inlined-frame-contexts/inlined-frame-contexts.csproj @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/runtime/src/tests/async/inlined-frame-exceptions/inlined-frame-exceptions.cs b/src/runtime/src/tests/async/inlined-frame-exceptions/inlined-frame-exceptions.cs new file mode 100644 index 000000000000..4d4d07c56538 --- /dev/null +++ b/src/runtime/src/tests/async/inlined-frame-exceptions/inlined-frame-exceptions.cs @@ -0,0 +1,74 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using Xunit; + +// Exceptions thrown out of an inlined async frame must surface unchanged, including when +// the frame suspended first. A suspension makes the resumption skip the entry code that +// captured the frame's contexts, so the context restores that run while the exception +// unwinds must see that the frame resumed. +public class Async2InlinedFrameExceptions +{ + private static async Task SuspendOnlyAsync() => await Task.Yield(); + + private static async Task ThrowOnlyAsync() => throw new InvalidOperationException("boom"); + + private static async Task SuspendThenThrowAsync() + { + await Task.Yield(); + throw new InvalidOperationException("boom"); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static async Task InlinedSuspendOnlyAsync() => await SuspendOnlyAsync(); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static async Task InlinedThrowOnlyAsync() => await ThrowOnlyAsync(); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static async Task InlinedSuspendThenThrowAsync() => await SuspendThenThrowAsync(); + + private static async Task CatchAsync(Func body) + { + try + { + await body(); + return "no-exception"; + } + catch (InvalidOperationException e) + { + return e.Message; + } + catch (Exception e) + { + return e.GetType().Name; + } + } + + private static async Task SuspendOnlyCaughtAsync() => await CatchAsync(InlinedSuspendOnlyAsync); + + private static async Task ThrowOnlyCaughtAsync() => await CatchAsync(InlinedThrowOnlyAsync); + + private static async Task SuspendThenThrowCaughtAsync() => await CatchAsync(InlinedSuspendThenThrowAsync); + + [Fact] + public static void ExceptionsSurfaceFromInlinedFrames() + { + Assert.Equal("no-exception", SuspendOnlyCaughtAsync().GetAwaiter().GetResult()); + Assert.Equal("boom", ThrowOnlyCaughtAsync().GetAwaiter().GetResult()); + Assert.Equal("boom", SuspendThenThrowCaughtAsync().GetAwaiter().GetResult()); + } + + private static async Task UncaughtAsync() => await InlinedSuspendThenThrowAsync(); + + [Fact] + public static void ExceptionPropagatesOutOfInlinedFrame() + { + InvalidOperationException e = + Assert.Throws(() => UncaughtAsync().GetAwaiter().GetResult()); + Assert.Equal("boom", e.Message); + } +} diff --git a/src/runtime/src/tests/async/inlined-frame-exceptions/inlined-frame-exceptions.csproj b/src/runtime/src/tests/async/inlined-frame-exceptions/inlined-frame-exceptions.csproj new file mode 100644 index 000000000000..6c8c63b83414 --- /dev/null +++ b/src/runtime/src/tests/async/inlined-frame-exceptions/inlined-frame-exceptions.csproj @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/runtime/src/tests/async/inlined-frame-ldvirtftn-await/inlined-frame-ldvirtftn-await.cs b/src/runtime/src/tests/async/inlined-frame-ldvirtftn-await/inlined-frame-ldvirtftn-await.cs new file mode 100644 index 000000000000..4bede1ad37e2 --- /dev/null +++ b/src/runtime/src/tests/async/inlined-frame-ldvirtftn-await/inlined-frame-ldvirtftn-await.cs @@ -0,0 +1,74 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using Xunit; + +// Awaits that the EE asks to be dispatched via ldvirtftn, such as calls to generic virtual +// methods, go through their own argument insertion path. An await inside an inlined async +// frame uses that frame's own contexts, and the ldvirtftn path must not hand it the +// caller's instead: doing so leaves the inlined frame's own resumed indicator unset, so +// after a suspension its context restore runs as if the frame had never resumed, over +// state that the resumption skipped capturing. +public class Async2InlinedFrameLdvirtftnAwait +{ + private class Dispatcher + { + // Generic virtual methods are dispatched via ldvirtftn. + public virtual async Task SuspendAndReturnAsync(T value) + { + await Task.Yield(); + return value; + } + + public virtual async Task SuspendAndThrowAsync(T value) + { + await Task.Yield(); + throw new InvalidOperationException("boom"); + } + } + + private static readonly Dispatcher s_dispatcher = new Dispatcher(); + + // Aggressively inlined so that the awaits below end up in an inlined async frame with + // its own contexts. Neither await is in tail position. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static async Task InlinedReturningAsync() + { + string result = await s_dispatcher.SuspendAndReturnAsync("value"); + return result.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static async Task InlinedThrowingAsync() + { + string result = await s_dispatcher.SuspendAndThrowAsync("value"); + return result.Length; + } + + private static async Task ReturningAsync() => await InlinedReturningAsync(); + + private static async Task ThrowingAsync() => await InlinedThrowingAsync(); + + [Fact] + public static void LdvirtftnAwaitInInlinedFrameReturns() + { + for (int i = 0; i < 10; i++) + { + Assert.Equal(5, ReturningAsync().GetAwaiter().GetResult()); + } + } + + [Fact] + public static void LdvirtftnAwaitInInlinedFramePropagatesException() + { + for (int i = 0; i < 10; i++) + { + InvalidOperationException e = + Assert.Throws(() => ThrowingAsync().GetAwaiter().GetResult()); + Assert.Equal("boom", e.Message); + } + } +} diff --git a/src/runtime/src/tests/async/inlined-frame-ldvirtftn-await/inlined-frame-ldvirtftn-await.csproj b/src/runtime/src/tests/async/inlined-frame-ldvirtftn-await/inlined-frame-ldvirtftn-await.csproj new file mode 100644 index 000000000000..197767e2c4e2 --- /dev/null +++ b/src/runtime/src/tests/async/inlined-frame-ldvirtftn-await/inlined-frame-ldvirtftn-await.csproj @@ -0,0 +1,5 @@ + + + + + diff --git a/src/runtime/src/tests/async/inlined-frame-transition-suspends/inlined-frame-transition-suspends.cs b/src/runtime/src/tests/async/inlined-frame-transition-suspends/inlined-frame-transition-suspends.cs new file mode 100644 index 000000000000..9c06caa8bad4 --- /dev/null +++ b/src/runtime/src/tests/async/inlined-frame-transition-suspends/inlined-frame-transition-suspends.cs @@ -0,0 +1,184 @@ +// 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.Concurrent; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; +using Xunit; + +// When an inlined async frame logically returns to its caller after a resumption, it has +// to get back onto the caller's continuation context. If that means switching contexts the +// transition itself suspends, so everything the caller still needs afterwards has to +// survive that suspension -- including the record of which frames have resumed. +public class Async2InlinedFrameTransitionSuspends +{ + // Never runs the callback inline: every Post goes to a dedicated thread, so getting + // back onto this context always forces a suspension. + private sealed class QueueingContext : SynchronizationContext + { + private readonly BlockingCollection<(SendOrPostCallback, object?)> _queue = new(); + + public readonly string Name; + + public QueueingContext(string name) + { + Name = name; + var thread = new Thread(Loop) { IsBackground = true, Name = name }; + thread.Start(); + } + + private void Loop() + { + foreach ((SendOrPostCallback d, object? state) in _queue.GetConsumingEnumerable()) + { + // The user code is free to install its own context on this thread, so put + // ours back before every callback rather than once at thread start. + SynchronizationContext.SetSynchronizationContext(this); + d(state); + } + } + + public override void Post(SendOrPostCallback d, object? state) => _queue.Add((d, state)); + } + + private struct AlwaysThreadPoolAwaitable : INotifyCompletion + { + public bool IsCompleted => false; + + public void OnCompleted(Action continuation) => ThreadPool.QueueUserWorkItem(_ => continuation()); + + public void GetResult() + { + } + + public AlwaysThreadPoolAwaitable GetAwaiter() => this; + } + + private static readonly QueueingContext s_ctx1 = new QueueingContext("ctx1"); + private static readonly QueueingContext s_ctx2 = new QueueingContext("ctx2"); + + private static string CurrentContextName => (SynchronizationContext.Current as QueueingContext)?.Name ?? "none"; + + private static readonly AsyncLocal s_local = new AsyncLocal(); + + private static int s_innerLocalAfterAwait; + private static string s_middleAfterAwait = ""; + private static string s_outerAfterAwait = ""; + private static int s_suspensions; + + // Suspends on the thread pool. A custom awaiter does not capture a continuation + // context, so this frame resumes off all three contexts; only its ExecutionContext is + // restored. Getting back out of it to Middle is what has to switch contexts. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static async Task Inner() + { + s_local.Value = 3; + await new AlwaysThreadPoolAwaitable(); + Interlocked.Increment(ref s_suspensions); + s_innerLocalAfterAwait = s_local.Value; + } + + // The transition out of Inner has to post back to ctx2 and so suspends. Middle must + // still be recorded as resumed afterwards, otherwise its own transition below is + // skipped and Outer never gets back onto ctx1. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static async Task Middle() + { + SynchronizationContext.SetSynchronizationContext(s_ctx2); + await Inner(); + s_middleAfterAwait = CurrentContextName; + } + + private static async Task Outer() + { + SynchronizationContext.SetSynchronizationContext(s_ctx1); + await Middle(); + s_outerAfterAwait = CurrentContextName; + } + + [Fact] + public static void ContextsRestoredWhenFrameTransitionSuspends() + { + s_innerLocalAfterAwait = 0; + s_middleAfterAwait = ""; + s_outerAfterAwait = ""; + s_suspensions = 0; + + RunOn(s_ctx1, Outer); + + Assert.Equal(1, s_suspensions); + Assert.Equal(3, s_innerLocalAfterAwait); + Assert.Equal("ctx2", s_middleAfterAwait); + Assert.Equal("ctx1", s_outerAfterAwait); + } + + // The same, but the frames keep awaiting after a transition has suspended, so the + // resumed state has to stay correct across several rounds. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static async Task LoopInner(int iterations) + { + s_local.Value = 3; + for (int i = 0; i < iterations; i++) + { + await new AlwaysThreadPoolAwaitable(); + Interlocked.Increment(ref s_suspensions); + Assert.Equal(3, s_local.Value); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static async Task LoopMiddle(int iterations) + { + SynchronizationContext.SetSynchronizationContext(s_ctx2); + for (int i = 0; i < iterations; i++) + { + await LoopInner(iterations); + Assert.Equal("ctx2", CurrentContextName); + } + } + + private static async Task LoopOuter(int iterations) + { + SynchronizationContext.SetSynchronizationContext(s_ctx1); + for (int i = 0; i < iterations; i++) + { + await LoopMiddle(iterations); + Assert.Equal("ctx1", CurrentContextName); + } + + s_outerAfterAwait = CurrentContextName; + } + + [Fact] + public static void ContextsSurviveRepeatedSuspendingTransitions() + { + s_outerAfterAwait = ""; + s_suspensions = 0; + + RunOn(s_ctx1, () => LoopOuter(3)); + + Assert.Equal(27, s_suspensions); + Assert.Equal("ctx1", s_outerAfterAwait); + } + + private static void RunOn(SynchronizationContext ctx, Func body) + { + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + ctx.Post(async _ => + { + try + { + await body(); + tcs.SetResult(); + } + catch (Exception ex) + { + tcs.SetException(ex); + } + }, null); + + tcs.Task.GetAwaiter().GetResult(); + } +} diff --git a/src/runtime/src/tests/async/inlined-frame-transition-suspends/inlined-frame-transition-suspends.csproj b/src/runtime/src/tests/async/inlined-frame-transition-suspends/inlined-frame-transition-suspends.csproj new file mode 100644 index 000000000000..6c8c63b83414 --- /dev/null +++ b/src/runtime/src/tests/async/inlined-frame-transition-suspends/inlined-frame-transition-suspends.csproj @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/runtime/src/tests/async/osr-inlined-contexts/osr-inlined-contexts.cs b/src/runtime/src/tests/async/osr-inlined-contexts/osr-inlined-contexts.cs new file mode 100644 index 000000000000..b72b0ec4bff3 --- /dev/null +++ b/src/runtime/src/tests/async/osr-inlined-contexts/osr-inlined-contexts.cs @@ -0,0 +1,129 @@ +// 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.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; +using Xunit; + +// Coverage for runtime async inlining in methods that are rejitted via OSR. +// +// An OSR method is entered with the tier 0 method's continuation, whose layout differs +// from the one the OSR method computes. Reading an inlined frame's state off it would be +// wrong, so this pins down that inlining async callees into an OSR method still behaves: +// an inlined callee's contexts are its own, and resuming inside one keeps every frame's +// contexts intact. +public class Async2OsrInlinedContexts +{ + private sealed class MarkerContext : SynchronizationContext + { + // Queue the callback and re-establish this context around it, as a real UI-style + // context would. Running it inline instead would make an awaiting loop recurse + // one frame deeper per iteration, since each suspension posts from inside the + // previous callback. + public override void Post(SendOrPostCallback d, object? state) + { + ThreadPool.QueueUserWorkItem(_ => + { + SynchronizationContext currentCtx = Current; + SetSynchronizationContext(this); + try + { + d(state); + } + finally + { + SetSynchronizationContext(currentCtx); + } + }); + } + } + + // Enough iterations to get the enclosing method rejitted via OSR. + private const int Iterations = 100_000; + + private static int s_sideEffect; + + // Async, and so has its own context save and restore, but never suspends, so it is + // inlinable into the loop below. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static async Task BumpAsync(int value) + { + s_sideEffect += value; + } + + private static async Task LoopWithInlinedCallee() + { + int total = 0; + for (int i = 0; i < Iterations; i++) + { + await BumpAsync(1); + total += i; + } + + return total; + } + + [Fact] + public static void InlinedCalleeDoesNotClobberContextsInOsrMethod() + { + SynchronizationContext original = SynchronizationContext.Current; + MarkerContext marker = new MarkerContext(); + try + { + SynchronizationContext.SetSynchronizationContext(marker); + + LoopWithInlinedCallee().GetAwaiter().GetResult(); + + // The inlined callee has its own context save and restore, which must not + // disturb the caller's. + Assert.Same(marker, SynchronizationContext.Current); + } + finally + { + SynchronizationContext.SetSynchronizationContext(original); + } + } + + private static readonly AsyncLocal s_local = new AsyncLocal(); + + // Same, but the callee suspends, so the loop also exercises resuming inside an inlined + // frame of an OSR method. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static async Task YieldAsync() + { + await Task.Yield(); + } + + private static async Task LoopWithSuspendingInlinedCallee() + { + SynchronizationContext.SetSynchronizationContext(new MarkerContext()); + s_local.Value = 7; + + int total = 0; + for (int i = 0; i < 2_000; i++) + { + await YieldAsync(); + Assert.IsType(SynchronizationContext.Current); + Assert.Equal(7, s_local.Value); + total += i; + } + + return total; + } + + [Fact] + public static void ResumingInsideInlinedFrameOfOsrMethodKeepsContexts() + { + SynchronizationContext original = SynchronizationContext.Current; + try + { + LoopWithSuspendingInlinedCallee().GetAwaiter().GetResult(); + } + finally + { + SynchronizationContext.SetSynchronizationContext(original); + } + } +} diff --git a/src/runtime/src/tests/async/osr-inlined-contexts/osr-inlined-contexts.csproj b/src/runtime/src/tests/async/osr-inlined-contexts/osr-inlined-contexts.csproj new file mode 100644 index 000000000000..8525b085aae0 --- /dev/null +++ b/src/runtime/src/tests/async/osr-inlined-contexts/osr-inlined-contexts.csproj @@ -0,0 +1,18 @@ + + + + true + True + + + + + + + + + + + + diff --git a/src/runtime/src/tests/async/regression/126750.cs b/src/runtime/src/tests/async/regression/126750.cs new file mode 100644 index 000000000000..e38eafaac29f --- /dev/null +++ b/src/runtime/src/tests/async/regression/126750.cs @@ -0,0 +1,94 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using Xunit; + +// The async version of a synchronous Task-returning method does not save and restore +// contexts, so it has no GC safe point ahead of its user code. That allowed +// optRemoveRedundantZeroInits to mark 'o' below as having an explicit init and drop its +// zero initialization from the prolog, even though the resumption path branches around +// the store. 'o' is address exposed, so it is reported to the GC as an untracked slot for +// the whole method, and a GC on the resumption path would then scan stack garbage. + +public class Runtime_126750 +{ + [InlineArray(512)] + private struct Buffer + { + private long _element; + } + + // The large return value is copied with a helper call in the restore path, which makes + // GC suspension possible there. + private struct Large + { + public Buffer Buffer; + } + + [Fact] + public static void TestEntryPoint() + { + for (int depth = 0; depth < 64; depth++) + { + Run(depth); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void Run(int depth) + { + TaskCompletionSource tcs = new TaskCompletionSource(); + Task task = Caller(tcs.Task); + + FillStackWithGarbage(depth); + + tcs.SetResult(); + task.GetAwaiter().GetResult(); + } + + // Leaves a non-null, non-heap value in the stack range that the resumed frame lands in. + [MethodImpl(MethodImplOptions.NoInlining)] + private static void FillStackWithGarbage(int depth) + { + Span buffer = stackalloc nint[16]; + buffer.Fill(unchecked((nint)0x1122334455667788)); + + if (depth > 0) + { + FillStackWithGarbage(depth - 1); + } + + Consume(buffer[0]); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void Consume(nint value) + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static async Task Caller(Task task) => await TaskReturning("hello", task); + + [MethodImpl(MethodImplOptions.NoInlining)] + private static Task TaskReturning(string s, Task task) + { + object o = s; + Escape(ref o); + return Suspend(task); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static async Task Suspend(Task task) + { + await task.ConfigureAwait(false); + return default; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void Escape(ref object o) + { + } +} diff --git a/src/runtime/src/tests/async/regression/126750.csproj b/src/runtime/src/tests/async/regression/126750.csproj new file mode 100644 index 000000000000..197767e2c4e2 --- /dev/null +++ b/src/runtime/src/tests/async/regression/126750.csproj @@ -0,0 +1,5 @@ + + + + + diff --git a/src/runtime/src/tests/profiler/dynamicoptimization/DynamicOptimization.csproj b/src/runtime/src/tests/profiler/dynamicoptimization/DynamicOptimization.csproj index 3fe7db0db2f7..80d4daf2bcc9 100644 --- a/src/runtime/src/tests/profiler/dynamicoptimization/DynamicOptimization.csproj +++ b/src/runtime/src/tests/profiler/dynamicoptimization/DynamicOptimization.csproj @@ -13,6 +13,8 @@ true true + + true diff --git a/src/runtime/src/tools/illink/src/ILLink.CodeFix/Resources.resx b/src/runtime/src/tools/illink/src/ILLink.CodeFix/Resources.resx index b57478c2c8d0..4753064074d6 100644 --- a/src/runtime/src/tools/illink/src/ILLink.CodeFix/Resources.resx +++ b/src/runtime/src/tools/illink/src/ILLink.CodeFix/Resources.resx @@ -132,6 +132,9 @@ Mark extern member 'unsafe' + + Mark member 'safe' + Mark documented member 'safe' diff --git a/src/runtime/src/tools/illink/src/ILLink.CodeFix/UnsafeModifierCodeFixHelpers.cs b/src/runtime/src/tools/illink/src/ILLink.CodeFix/UnsafeModifierCodeFixHelpers.cs index 501226003d9c..7320b3169b78 100644 --- a/src/runtime/src/tools/illink/src/ILLink.CodeFix/UnsafeModifierCodeFixHelpers.cs +++ b/src/runtime/src/tools/illink/src/ILLink.CodeFix/UnsafeModifierCodeFixHelpers.cs @@ -27,8 +27,8 @@ internal static class UnsafeModifierCodeFixHelpers /// Registers an add-unsafe action for a supported declaration that has no existing safety modifier. /// /// - /// A declaration that documents why it is safe gets safe instead, so an audited member does not - /// become caller-unsafe and force its callers into unsafe contexts. + /// A destructor or a declaration that documents why it is safe gets safe instead, so the fixer does + /// not add a meaningless unsafe modifier or force callers of an audited member into unsafe contexts. /// internal static async Task RegisterAddUnsafeCodeFixAsync( CodeFixContext context, @@ -51,15 +51,21 @@ internal static async Task RegisterAddUnsafeCodeFixAsync( return; } - SyntaxKind modifier = SyntaxKind.UnsafeKeyword; + bool hasSafetyDocumentation = UnsafeMigrationSyntaxHelpers.HasSafetyDocumentation(declaration); + bool useSafeModifier = UnsafeMigrationSyntaxHelpers.SafeKeywordKind != SyntaxKind.None + && (declaration is DestructorDeclarationSyntax || hasSafetyDocumentation); + SyntaxKind modifier = useSafeModifier + ? UnsafeMigrationSyntaxHelpers.SafeKeywordKind + : SyntaxKind.UnsafeKeyword; string title = codeFixTitle.ToString(); string displayTitle = title; - if (UnsafeMigrationSyntaxHelpers.SafeKeywordKind != SyntaxKind.None - && UnsafeMigrationSyntaxHelpers.HasSafetyDocumentation(declaration)) + if (useSafeModifier) { - modifier = UnsafeMigrationSyntaxHelpers.SafeKeywordKind; + string resourceName = hasSafetyDocumentation + ? nameof(Resources.AddSafeToDocumentedMemberCodeFixTitle) + : nameof(Resources.AddSafeCodeFixTitle); displayTitle = new LocalizableResourceString( - nameof(Resources.AddSafeToDocumentedMemberCodeFixTitle), + resourceName, Resources.ResourceManager, typeof(Resources)).ToString(); } diff --git a/src/runtime/src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs b/src/runtime/src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs index 55ba4a410f97..ef95eab84a97 100644 --- a/src/runtime/src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs +++ b/src/runtime/src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs @@ -134,23 +134,28 @@ public override void Initialize(AnalysisContext context) if (dataFlowAnalyzerContext.TrimAnalyzer is null) return; - // Examine generic instantiations in base types and interface list + // Examine generic instantiations in the interface list context.RegisterSymbolAction(context => { var type = (INamedTypeSymbol)context.Symbol; - // RUC on type doesn't silence DAM warnings about generic base/interface types. - // This knowledge lives in IsInRequiresUnreferencedCodeAttributeScope, - // which we still call for consistency here, but it is expected to return false. - if (type.IsInRequiresUnreferencedCodeAttributeScope(out _)) - return; var location = GetPrimaryLocation(type.Locations); var typeNameResolver = new TypeNameResolver(context.Compilation); - var genericArgumentDataFlow = new GenericArgumentDataFlow(dataFlowAnalyzerContext.TrimAnalyzer, FeatureContext.None, typeNameResolver, type, location, context.ReportDiagnostic); - foreach (var interfaceType in type.Interfaces) - genericArgumentDataFlow.ProcessGenericArgumentDataFlow(interfaceType); + // The generic instantiations in the interface list are only reachable through the + // members of the type, which are all in the Requires scope of a type-level + // RequiresUnreferencedCode, so the attribute silences these warnings. + // This is not the case for the DynamicallyAccessedMembers hierarchy below, or for + // attributes on the type, which may be accessed via reflection from code which is + // not in a Requires scope. + if (!type.HasAttribute(RequiresUnreferencedCodeAnalyzer.RequiresUnreferencedCodeAttribute)) + { + var genericArgumentDataFlow = new GenericArgumentDataFlow(dataFlowAnalyzerContext.TrimAnalyzer, FeatureContext.None, typeNameResolver, type, location, context.ReportDiagnostic); + + foreach (var interfaceType in type.Interfaces) + genericArgumentDataFlow.ProcessGenericArgumentDataFlow(interfaceType); + } DynamicallyAccessedMembersTypeHierarchy.ApplyDynamicallyAccessedMembersToTypeHierarchy(typeNameResolver, location, type, context.ReportDiagnostic); }, SymbolKind.NamedType); diff --git a/src/runtime/src/tools/illink/src/linker/Linker.Dataflow/GenericArgumentDataFlow.cs b/src/runtime/src/tools/illink/src/linker/Linker.Dataflow/GenericArgumentDataFlow.cs index 638a853fdcb7..dfbd6ccd89bd 100644 --- a/src/runtime/src/tools/illink/src/linker/Linker.Dataflow/GenericArgumentDataFlow.cs +++ b/src/runtime/src/tools/illink/src/linker/Linker.Dataflow/GenericArgumentDataFlow.cs @@ -13,10 +13,10 @@ namespace Mono.Linker.Dataflow { internal static class GenericArgumentDataFlow { - public static void ProcessGenericArgumentDataFlow(in MessageOrigin origin, MarkStep markStep, LinkContext context, TypeReference type) + public static void ProcessGenericArgumentDataFlow(in MessageOrigin origin, MarkStep markStep, LinkContext context, TypeReference type, bool suppressTrimAnalysisWarnings = false) { - var diagnosticContext = new DiagnosticContext(origin, !context.Annotations.ShouldSuppressAnalysisWarningsForRequiresUnreferencedCode(origin.Provider, out _), context); - var reflectionMarker = new ReflectionMarker(context, markStep, enabled: true); + var diagnosticContext = new DiagnosticContext(origin, !suppressTrimAnalysisWarnings && !context.Annotations.ShouldSuppressAnalysisWarningsForRequiresUnreferencedCode(origin.Provider, out _), context); + var reflectionMarker = new ReflectionMarker(context, markStep, enabled: true, suppressTrimAnalysisWarnings: suppressTrimAnalysisWarnings); ProcessGenericArgumentDataFlow(in diagnosticContext, reflectionMarker, context, type); } diff --git a/src/runtime/src/tools/illink/src/linker/Linker.Dataflow/ReflectionMarker.cs b/src/runtime/src/tools/illink/src/linker/Linker.Dataflow/ReflectionMarker.cs index 75d444d5cb8e..76f69c4c6d32 100644 --- a/src/runtime/src/tools/illink/src/linker/Linker.Dataflow/ReflectionMarker.cs +++ b/src/runtime/src/tools/illink/src/linker/Linker.Dataflow/ReflectionMarker.cs @@ -15,13 +15,15 @@ public readonly struct ReflectionMarker { readonly MarkStep _markStep; readonly bool _enabled; + readonly bool _suppressTrimAnalysisWarnings; public LinkContext Context { get; } - public ReflectionMarker(LinkContext context, MarkStep markStep, bool enabled) + public ReflectionMarker(LinkContext context, MarkStep markStep, bool enabled, bool suppressTrimAnalysisWarnings = false) { Context = context; _markStep = markStep; _enabled = enabled; + _suppressTrimAnalysisWarnings = suppressTrimAnalysisWarnings; } internal void MarkTypeForDynamicallyAccessedMembers(in MessageOrigin origin, TypeReference type, DynamicallyAccessedMemberTypes requiredMemberTypes, DependencyKind dependencyKind, bool declaredOnly = false) @@ -125,7 +127,7 @@ internal void MarkMethod(in MessageOrigin origin, MethodReference methodRef, Dep if (Context.TryResolve(methodRef) is not MethodDefinition method) return; - _markStep.MarkMethodVisibleToReflection(method, new DependencyInfo(dependencyKind, origin.Provider), origin); + _markStep.MarkMethodVisibleToReflection(method, new DependencyInfo(dependencyKind, origin.Provider), origin, suppressTrimAnalysisWarnings: _suppressTrimAnalysisWarnings); } void MarkField(in MessageOrigin origin, FieldDefinition field, DependencyKind dependencyKind = DependencyKind.AccessedViaReflection) @@ -133,7 +135,7 @@ void MarkField(in MessageOrigin origin, FieldDefinition field, DependencyKind de if (!_enabled) return; - _markStep.MarkFieldVisibleToReflection(field, new DependencyInfo(dependencyKind, origin.Provider), origin); + _markStep.MarkFieldVisibleToReflection(field, new DependencyInfo(dependencyKind, origin.Provider), origin, suppressTrimAnalysisWarnings: _suppressTrimAnalysisWarnings); } internal void MarkProperty(in MessageOrigin origin, PropertyDefinition property, DependencyKind dependencyKind = DependencyKind.AccessedViaReflection) @@ -141,7 +143,7 @@ internal void MarkProperty(in MessageOrigin origin, PropertyDefinition property, if (!_enabled) return; - _markStep.MarkPropertyVisibleToReflection(property, new DependencyInfo(dependencyKind, origin.Provider), origin); + _markStep.MarkPropertyVisibleToReflection(property, new DependencyInfo(dependencyKind, origin.Provider), origin, suppressTrimAnalysisWarnings: _suppressTrimAnalysisWarnings); } void MarkEvent(in MessageOrigin origin, EventDefinition @event, DependencyKind dependencyKind = DependencyKind.AccessedViaReflection) @@ -149,7 +151,7 @@ void MarkEvent(in MessageOrigin origin, EventDefinition @event, DependencyKind d if (!_enabled) return; - _markStep.MarkEventVisibleToReflection(@event, new DependencyInfo(dependencyKind, origin.Provider), origin); + _markStep.MarkEventVisibleToReflection(@event, new DependencyInfo(dependencyKind, origin.Provider), origin, suppressTrimAnalysisWarnings: _suppressTrimAnalysisWarnings); } void MarkInterfaceImplementation(in MessageOrigin origin, InterfaceImplementation interfaceImplementation, DependencyKind dependencyKind = DependencyKind.AccessedViaReflection) @@ -216,7 +218,7 @@ internal void MarkStaticConstructor(in MessageOrigin origin, TypeReference typeR if (typeRef.ResolveToTypeDefinition(Context) is not TypeDefinition type) return; - _markStep.MarkStaticConstructorVisibleToReflection(type, new DependencyInfo(DependencyKind.AccessedViaReflection, origin.Provider), origin); + _markStep.MarkStaticConstructorVisibleToReflection(type, new DependencyInfo(DependencyKind.AccessedViaReflection, origin.Provider), origin, suppressTrimAnalysisWarnings: _suppressTrimAnalysisWarnings); } } } diff --git a/src/runtime/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs b/src/runtime/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs index 9f1a19702f19..34a9f2dd5f10 100644 --- a/src/runtime/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs +++ b/src/runtime/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs @@ -1263,9 +1263,9 @@ protected virtual bool ShouldMarkTypeStaticConstructor(TypeDefinition type) return true; } - protected internal void MarkStaticConstructor(TypeDefinition type, in DependencyInfo reason, in MessageOrigin origin) + protected internal void MarkStaticConstructor(TypeDefinition type, in DependencyInfo reason, in MessageOrigin origin, bool suppressTrimAnalysisWarnings = false) { - if (MarkMethodIf(type.Methods, IsNonEmptyStaticConstructor, reason, origin) != null) + if (MarkMethodIf(type.Methods, IsNonEmptyStaticConstructor, reason, origin, suppressTrimAnalysisWarnings: suppressTrimAnalysisWarnings) != null) Annotations.SetPreservedStaticCtor(type); } @@ -1724,7 +1724,7 @@ bool ProcessLateMarkedAttributes() return markOccurred; } - protected void MarkField(FieldReference reference, DependencyInfo reason, in MessageOrigin origin) + protected void MarkField(FieldReference reference, DependencyInfo reason, in MessageOrigin origin, bool suppressTrimAnalysisWarnings = false) { if (reference.DeclaringType is GenericInstanceType) { @@ -1744,11 +1744,14 @@ protected void MarkField(FieldReference reference, DependencyInfo reason, in Mes return; } - MarkField(field, reason, origin); + MarkField(field, reason, origin, suppressTrimAnalysisWarnings: suppressTrimAnalysisWarnings); } - void ReportWarningsForReflectionAccess(in MessageOrigin origin, MethodDefinition method, DependencyKind dependencyKind) + void ReportWarningsForReflectionAccess(in MessageOrigin origin, MethodDefinition method, DependencyKind dependencyKind, bool suppressTrimAnalysisWarnings) { + if (suppressTrimAnalysisWarnings) + return; + if (Annotations.ShouldSuppressAnalysisWarningsForRequiresUnreferencedCode(origin.Provider, out _)) return; @@ -1861,7 +1864,7 @@ static bool IsDeclaredWithinType(IMemberDefinition member, TypeDefinition type) } } - void MarkField(FieldDefinition field, in DependencyInfo reason, in MessageOrigin origin) + void MarkField(FieldDefinition field, in DependencyInfo reason, in MessageOrigin origin, bool suppressTrimAnalysisWarnings = false) { #if DEBUG if (!_fieldReasons.Contains(reason.Kind)) @@ -1877,7 +1880,7 @@ void MarkField(FieldDefinition field, in DependencyInfo reason, in MessageOrigin Annotations.Mark(field, reason, origin); } - ProcessAnalysisAnnotationsForField(field, reason.Kind, in origin); + ProcessAnalysisAnnotationsForField(field, reason.Kind, in origin, suppressTrimAnalysisWarnings: suppressTrimAnalysisWarnings); if (CheckProcessed(field)) return; @@ -1924,7 +1927,7 @@ void MarkField(FieldDefinition field, in DependencyInfo reason, in MessageOrigin } } - void ProcessAnalysisAnnotationsForField(FieldDefinition field, DependencyKind dependencyKind, in MessageOrigin origin) + void ProcessAnalysisAnnotationsForField(FieldDefinition field, DependencyKind dependencyKind, in MessageOrigin origin, bool suppressTrimAnalysisWarnings) { switch (dependencyKind) { @@ -1943,6 +1946,9 @@ void ProcessAnalysisAnnotationsForField(FieldDefinition field, DependencyKind de break; } + if (suppressTrimAnalysisWarnings) + return; + if (Annotations.ShouldSuppressAnalysisWarningsForRequiresUnreferencedCode(origin.Provider, out _)) return; @@ -2025,9 +2031,9 @@ internal void MarkRelevantToVariantCasting(TypeDefinition type) Annotations.MarkRelevantToVariantCasting(type); } - internal void MarkMethodVisibleToReflection(MethodReference method, in DependencyInfo reason, in MessageOrigin origin) + internal void MarkMethodVisibleToReflection(MethodReference method, in DependencyInfo reason, in MessageOrigin origin, bool suppressTrimAnalysisWarnings = false) { - MarkMethod(method, reason, origin); + MarkMethod(method, reason, origin, suppressTrimAnalysisWarnings: suppressTrimAnalysisWarnings); if (Context.Resolve(method) is MethodDefinition methodDefinition) { Annotations.MarkReflectionUsed(methodDefinition); @@ -2041,11 +2047,11 @@ internal void MarkMethodVisibleToReflection(MethodReference method, in Dependenc // On a reflectable method, perform generic data flow for the return type and all the parameter types // This is a compensation for the DI issue described in https://github.com/dotnet/runtime/issues/81358 var methodOrigin = new MessageOrigin(methodDefinition); - GenericArgumentDataFlow.ProcessGenericArgumentDataFlow(in methodOrigin, this, Context, methodDefinition.ReturnType); + GenericArgumentDataFlow.ProcessGenericArgumentDataFlow(in methodOrigin, this, Context, methodDefinition.ReturnType, suppressTrimAnalysisWarnings: suppressTrimAnalysisWarnings); foreach (var parameter in methodDefinition.GetMetadataParameters()) { - GenericArgumentDataFlow.ProcessGenericArgumentDataFlow(in methodOrigin, this, Context, parameter.ParameterType); + GenericArgumentDataFlow.ProcessGenericArgumentDataFlow(in methodOrigin, this, Context, parameter.ParameterType, suppressTrimAnalysisWarnings: suppressTrimAnalysisWarnings); } } } @@ -2064,9 +2070,9 @@ bool MarkMethodsVisibleToReflection(TypeDefinition type, in DependencyInfo reaso return true; } - internal void MarkFieldVisibleToReflection(FieldReference field, in DependencyInfo reason, in MessageOrigin origin) + internal void MarkFieldVisibleToReflection(FieldReference field, in DependencyInfo reason, in MessageOrigin origin, bool suppressTrimAnalysisWarnings = false) { - MarkField(field, reason, origin); + MarkField(field, reason, origin, suppressTrimAnalysisWarnings: suppressTrimAnalysisWarnings); if (Context.Resolve(field) is FieldDefinition fieldDefinition) { Annotations.MarkReflectionUsed(fieldDefinition); @@ -2079,7 +2085,7 @@ internal void MarkFieldVisibleToReflection(FieldReference field, in DependencyIn // On a reflectable field, perform generic data flow for the field's type // This is a compensation for the DI issue described in https://github.com/dotnet/runtime/issues/81358 var fieldOrigin = new MessageOrigin(fieldDefinition); - GenericArgumentDataFlow.ProcessGenericArgumentDataFlow(in fieldOrigin, this, Context, fieldDefinition.FieldType); + GenericArgumentDataFlow.ProcessGenericArgumentDataFlow(in fieldOrigin, this, Context, fieldDefinition.FieldType, suppressTrimAnalysisWarnings: suppressTrimAnalysisWarnings); } } @@ -2108,32 +2114,32 @@ bool MarkFieldsVisibleToReflection(TypeDefinition type, in DependencyInfo reason return true; } - internal void MarkPropertyVisibleToReflection(PropertyDefinition property, in DependencyInfo reason, in MessageOrigin origin) + internal void MarkPropertyVisibleToReflection(PropertyDefinition property, in DependencyInfo reason, in MessageOrigin origin, bool suppressTrimAnalysisWarnings = false) { // Marking the property itself actually doesn't keep it (it only marks its attributes and records the dependency), we have to mark the methods on it MarkProperty(property, reason); // We don't track PropertyInfo, so we can't tell if any accessor is needed by the app, so include them both. // With better tracking it might be possible to be more precise here: dotnet/linker/issues/1948 - MarkMethodIfNotNull(property.GetMethod, reason, origin); - MarkMethodIfNotNull(property.SetMethod, reason, origin); - MarkMethodsIf(property.OtherMethods, m => true, reason, origin); + MarkMethodIfNotNull(property.GetMethod, reason, origin, suppressTrimAnalysisWarnings: suppressTrimAnalysisWarnings); + MarkMethodIfNotNull(property.SetMethod, reason, origin, suppressTrimAnalysisWarnings: suppressTrimAnalysisWarnings); + MarkMethodsIf(property.OtherMethods, m => true, reason, origin, suppressTrimAnalysisWarnings: suppressTrimAnalysisWarnings); } - internal void MarkEventVisibleToReflection(EventDefinition @event, in DependencyInfo reason, in MessageOrigin origin) + internal void MarkEventVisibleToReflection(EventDefinition @event, in DependencyInfo reason, in MessageOrigin origin, bool suppressTrimAnalysisWarnings = false) { - MarkEvent(@event, reason, origin); + MarkEvent(@event, reason, origin, suppressTrimAnalysisWarnings: suppressTrimAnalysisWarnings); // MarkEvent already marks the add/remove/invoke methods, but we need to mark them with the // DependencyInfo used to access the event from reflection, to produce warnings for annotated // event methods. - MarkMethodIfNotNull(@event.AddMethod, reason, origin); - MarkMethodIfNotNull(@event.RemoveMethod, reason, origin); - MarkMethodIfNotNull(@event.InvokeMethod, reason, origin); - MarkMethodsIf(@event.OtherMethods, m => true, reason, origin); + MarkMethodIfNotNull(@event.AddMethod, reason, origin, suppressTrimAnalysisWarnings: suppressTrimAnalysisWarnings); + MarkMethodIfNotNull(@event.RemoveMethod, reason, origin, suppressTrimAnalysisWarnings: suppressTrimAnalysisWarnings); + MarkMethodIfNotNull(@event.InvokeMethod, reason, origin, suppressTrimAnalysisWarnings: suppressTrimAnalysisWarnings); + MarkMethodsIf(@event.OtherMethods, m => true, reason, origin, suppressTrimAnalysisWarnings: suppressTrimAnalysisWarnings); } - internal void MarkStaticConstructorVisibleToReflection(TypeDefinition type, in DependencyInfo reason, in MessageOrigin origin) + internal void MarkStaticConstructorVisibleToReflection(TypeDefinition type, in DependencyInfo reason, in MessageOrigin origin, bool suppressTrimAnalysisWarnings = false) { - MarkStaticConstructor(type, reason, origin); + MarkStaticConstructor(type, reason, origin, suppressTrimAnalysisWarnings: suppressTrimAnalysisWarnings); } /// @@ -2768,27 +2774,27 @@ static bool IsSpecialSerializationConstructor(MethodDefinition method) method.TryGetParameter((ParameterIndex)2)?.ParameterType.Name == "StreamingContext"; } - protected internal bool MarkMethodsIf(Collection methods, Func predicate, in DependencyInfo reason, in MessageOrigin origin) + protected internal bool MarkMethodsIf(Collection methods, Func predicate, in DependencyInfo reason, in MessageOrigin origin, bool suppressTrimAnalysisWarnings = false) { bool marked = false; foreach (MethodDefinition method in methods) { if (predicate(method)) { - MarkMethod(method, reason, origin); + MarkMethod(method, reason, origin, suppressTrimAnalysisWarnings: suppressTrimAnalysisWarnings); marked = true; } } return marked; } - protected MethodDefinition? MarkMethodIf(Collection methods, Func predicate, in DependencyInfo reason, in MessageOrigin origin) + protected MethodDefinition? MarkMethodIf(Collection methods, Func predicate, in DependencyInfo reason, in MessageOrigin origin, bool suppressTrimAnalysisWarnings = false) { foreach (MethodDefinition method in methods) { if (predicate(method)) { - return MarkMethod(method, reason, origin); + return MarkMethod(method, reason, origin, suppressTrimAnalysisWarnings: suppressTrimAnalysisWarnings); } } @@ -3173,7 +3179,7 @@ void MarkMethodCollection(IList methods, in DependencyInfo rea MarkMethod(method, reason, origin); } - protected virtual MethodDefinition? MarkMethod(MethodReference reference, DependencyInfo reason, in MessageOrigin origin) + protected virtual MethodDefinition? MarkMethod(MethodReference reference, DependencyInfo reason, in MessageOrigin origin, bool suppressTrimAnalysisWarnings = false) { DependencyInfo originalReason = reason; (reference, reason) = GetOriginalMethod(reference, reason, origin); @@ -3207,7 +3213,7 @@ void MarkMethodCollection(IList methods, in DependencyInfo rea // Use the original reason as it's important to correctly generate warnings // the updated reason is only useful for better tracking of dependencies. - ProcessAnalysisAnnotationsForMethod(method, originalReason.Kind, origin); + ProcessAnalysisAnnotationsForMethod(method, originalReason.Kind, origin, suppressTrimAnalysisWarnings: suppressTrimAnalysisWarnings); // Record the reason for marking a method on each call. switch (reason.Kind) @@ -3264,7 +3270,7 @@ bool ShouldWarnForReflectionAccessToCompilerGeneratedCode(MethodDefinition metho return CheckRequiresReflectionMethodBodyScanner(Context.GetMethodIL(method)); } - void ProcessAnalysisAnnotationsForMethod(MethodDefinition method, DependencyKind dependencyKind, in MessageOrigin origin) + void ProcessAnalysisAnnotationsForMethod(MethodDefinition method, DependencyKind dependencyKind, in MessageOrigin origin, bool suppressTrimAnalysisWarnings) { switch (dependencyKind) { @@ -3338,7 +3344,7 @@ void ProcessAnalysisAnnotationsForMethod(MethodDefinition method, DependencyKind default: // All other cases have the potential of us missing a warning if we don't report it // It is possible that in some cases we may report the same warning twice, but that's better than not reporting it. - ReportWarningsForReflectionAccess(origin, method, dependencyKind); + ReportWarningsForReflectionAccess(origin, method, dependencyKind, suppressTrimAnalysisWarnings: suppressTrimAnalysisWarnings); break; } ; @@ -3786,14 +3792,14 @@ protected internal void MarkProperty(PropertyDefinition prop, in DependencyInfo DoAdditionalPropertyProcessing(prop, propertyOrigin); } - protected internal virtual void MarkEvent(EventDefinition evt, in DependencyInfo reason, MessageOrigin origin) + protected internal virtual void MarkEvent(EventDefinition evt, in DependencyInfo reason, MessageOrigin origin, bool suppressTrimAnalysisWarnings = false) { origin = reason.Source is IMemberDefinition member ? new MessageOrigin(member) : origin; DependencyKind dependencyKind = DependencyKind.EventMethod; - MarkMethodIfNotNull(evt.AddMethod, new DependencyInfo(dependencyKind, evt), origin); - MarkMethodIfNotNull(evt.InvokeMethod, new DependencyInfo(dependencyKind, evt), origin); - MarkMethodIfNotNull(evt.RemoveMethod, new DependencyInfo(dependencyKind, evt), origin); + MarkMethodIfNotNull(evt.AddMethod, new DependencyInfo(dependencyKind, evt), origin, suppressTrimAnalysisWarnings: suppressTrimAnalysisWarnings); + MarkMethodIfNotNull(evt.InvokeMethod, new DependencyInfo(dependencyKind, evt), origin, suppressTrimAnalysisWarnings: suppressTrimAnalysisWarnings); + MarkMethodIfNotNull(evt.RemoveMethod, new DependencyInfo(dependencyKind, evt), origin, suppressTrimAnalysisWarnings: suppressTrimAnalysisWarnings); if (!Annotations.MarkProcessed(evt, reason)) return; @@ -3803,12 +3809,12 @@ protected internal virtual void MarkEvent(EventDefinition evt, in DependencyInfo DoAdditionalEventProcessing(evt, eventOrigin); } - internal void MarkMethodIfNotNull(MethodReference method, in DependencyInfo reason, in MessageOrigin origin) + internal void MarkMethodIfNotNull(MethodReference method, in DependencyInfo reason, in MessageOrigin origin, bool suppressTrimAnalysisWarnings = false) { if (method == null) return; - MarkMethod(method, reason, origin); + MarkMethod(method, reason, origin, suppressTrimAnalysisWarnings: suppressTrimAnalysisWarnings); } protected virtual void MarkMethodBody(MethodBody body, MessageOrigin origin) @@ -4108,7 +4114,13 @@ protected internal virtual void MarkInterfaceImplementation(InterfaceImplementat if (Annotations.IsMarked(iface)) return; Annotations.MarkProcessed(iface, reason ?? new DependencyInfo(DependencyKind.InterfaceImplementationOnType, origin.Provider)); - GenericArgumentDataFlow.ProcessGenericArgumentDataFlow(in origin, this, Context, iface.InterfaceType); + // The generic instantiation in the interface list is only reachable through the members of the + // type which implements the interface, which are all in the Requires scope of a type-level + // RequiresUnreferencedCode, so the attribute silences these warnings. Note that the data flow + // still needs to run to mark the members required by the instantiation. + bool suppressTrimAnalysisWarnings = origin.Provider is TypeDefinition implementingType && + Annotations.TryGetLinkerAttribute(implementingType, out _); + GenericArgumentDataFlow.ProcessGenericArgumentDataFlow(in origin, this, Context, iface.InterfaceType, suppressTrimAnalysisWarnings: suppressTrimAnalysisWarnings); // Blame the type that has the interfaceimpl, expecting the type itself to get marked for other reasons. MarkCustomAttributes(iface, new DependencyInfo(DependencyKind.CustomAttribute, iface), origin); diff --git a/src/runtime/src/tools/illink/src/linker/Linker/DocumentationSignatureGenerator.PartVisitor.cs b/src/runtime/src/tools/illink/src/linker/Linker/DocumentationSignatureGenerator.PartVisitor.cs index 73a57b218e2b..332b7831aa10 100644 --- a/src/runtime/src/tools/illink/src/linker/Linker/DocumentationSignatureGenerator.PartVisitor.cs +++ b/src/runtime/src/tools/illink/src/linker/Linker/DocumentationSignatureGenerator.PartVisitor.cs @@ -42,7 +42,7 @@ public void VisitArrayType(ArrayType arrayType, StringBuilder builder, ITryResol builder.Append("[0:"); for (int i = 1; i < arrayType.Rank; i++) { - if (arrayType.Dimensions[0].LowerBound != 0) + if (arrayType.Dimensions[i].LowerBound != 0) throw new NotImplementedException(); builder.Append(",0:"); } diff --git a/src/runtime/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/AddUnsafeToExternCodeFixTests.cs b/src/runtime/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/AddUnsafeToExternCodeFixTests.cs index 68a27088147b..bc47f0ad8778 100644 --- a/src/runtime/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/AddUnsafeToExternCodeFixTests.cs +++ b/src/runtime/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/AddUnsafeToExternCodeFixTests.cs @@ -128,7 +128,7 @@ class C """ class C { - extern unsafe ~C(); + extern safe ~C(); } """ }, diff --git a/src/runtime/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/RemoveUndocumentedUnsafeCodeFixTests.cs b/src/runtime/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/RemoveUndocumentedUnsafeCodeFixTests.cs index da6523059cc2..e7d524e1ee15 100644 --- a/src/runtime/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/RemoveUndocumentedUnsafeCodeFixTests.cs +++ b/src/runtime/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/RemoveUndocumentedUnsafeCodeFixTests.cs @@ -46,6 +46,7 @@ class C public int P { {|IL5005:unsafe|} get => 0; + set { } } } """; @@ -55,6 +56,7 @@ class C public int P { get => 0; + set { } } } """; diff --git a/src/runtime/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/RequiresUnsafeCodeFixTests.cs b/src/runtime/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/RequiresUnsafeCodeFixTests.cs index aab096802e3c..01d24e40ad73 100644 --- a/src/runtime/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/RequiresUnsafeCodeFixTests.cs +++ b/src/runtime/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/RequiresUnsafeCodeFixTests.cs @@ -329,7 +329,7 @@ public async Task CodeFix_InsideUnsafeClass() var test = """ using System.Diagnostics.CodeAnalysis; - public unsafe class C + public class C { public static unsafe int M1() => 0; @@ -343,7 +343,7 @@ public void M2() var fixedSource = """ using System.Diagnostics.CodeAnalysis; - public unsafe class C + public class C { public static unsafe int M1() => 0; diff --git a/src/runtime/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/UnsafeMemberMissingSafetyDocumentationAnalyzerTests.cs b/src/runtime/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/UnsafeMemberMissingSafetyDocumentationAnalyzerTests.cs index 35559d26bab9..0548ba1345d3 100644 --- a/src/runtime/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/UnsafeMemberMissingSafetyDocumentationAnalyzerTests.cs +++ b/src/runtime/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/UnsafeMemberMissingSafetyDocumentationAnalyzerTests.cs @@ -93,6 +93,7 @@ public unsafe partial void Partial() { } public int Accessor { unsafe get => 0; + set { } } public void Outer() @@ -114,8 +115,8 @@ public async Task IgnoresDeclarationsThatCannotExposeUnsafeContracts() var source = """ class C { - static unsafe C() { } - unsafe ~C() { } + static {|CS9377:unsafe|} C() { } + {|CS9377:unsafe|} ~C() { } } """; diff --git a/src/runtime/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlow.cs b/src/runtime/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlow.cs index 5aa92d6cc983..354173f32832 100644 --- a/src/runtime/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlow.cs +++ b/src/runtime/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlow.cs @@ -231,7 +231,6 @@ static void TestDerivedTypeWithOpenGenericOnBaseWithRUCOnDerived() new DerivedTypeWithOpenGenericOnBaseWithRUCOnDerived(); } - [ExpectedWarning("IL2091", nameof(IGenericInterfaceTypeWithRequirements))] [RequiresUnreferencedCode("RUC")] class DerivedTypeWithOpenGenericOnBaseWithRUCOnDerived : BaseTypeWithOpenGenericDAMT, IGenericInterfaceTypeWithRequirements { diff --git a/src/runtime/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlowMarking.cs b/src/runtime/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlowMarking.cs index 358bf2cbc834..b2cd015a1e5e 100644 --- a/src/runtime/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlowMarking.cs +++ b/src/runtime/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlowMarking.cs @@ -330,6 +330,44 @@ public static void Test() } } + [Kept] + class InterfaceGenericMarkingUnderRuc + { + [Kept] + interface IRequires< + [KeptAttributeAttribute(typeof(DynamicallyAccessedMembersAttribute), By = Tool.Trimmer)] + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T> + { + } + + [Kept] + class TargetType + { + [Kept] + public static void PublicMethod() { } + } + + [Kept] + [KeptMember(".ctor()")] + [KeptInterfaceAttribute(typeof(IRequires), By = Tool.Trimmer)] + [KeptAttributeAttribute(typeof(RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode("--InterfaceGenericMarkingUnderRuc--")] + class DerivedWithTarget : IRequires + { + } + + [Kept] + [ExpectedWarning("IL2026", "--InterfaceGenericMarkingUnderRuc--")] + public static void Test() + { + new DerivedWithTarget(); + + // Keep the interface implementation without creating a closed generic use-site + // which would independently mark TargetType.PublicMethod. + var interfaceType = typeof(IRequires<>); + } + } + [Kept] public static void Test() { @@ -342,6 +380,7 @@ public static void Test() FieldOnGenericType.Test(); BaseTypeGenericNesting.Test(); InterfaceGenericNesting.Test(); + InterfaceGenericMarkingUnderRuc.Test(); } } } diff --git a/src/runtime/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnClass.cs b/src/runtime/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnClass.cs index 7b0ab5a7d67d..712c4fdf962a 100644 --- a/src/runtime/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnClass.cs +++ b/src/runtime/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnClass.cs @@ -1351,6 +1351,14 @@ public class RequiresAll<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTy { } + interface IRequiresAll<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] U> + { + } + + interface IRequiresNew where T : new() + { + } + [RequiresUnreferencedCode("--ClassWithRequires--")] public class ClassWithRequires { @@ -1393,6 +1401,15 @@ public class ClassWithAttribute } } + class ClassWithOtherCapabilityRequirements + { + [RequiresAssemblyFiles("--ClassWithOtherCapabilityRequirements--")] + [RequiresDynamicCode("--ClassWithOtherCapabilityRequirements--")] + public ClassWithOtherCapabilityRequirements() + { + } + } + [RequiresUnreferencedCode("--GenericClassWithWarningWithRequires--")] public class GenericClassWithWarningWithRequires : RequiresAll { @@ -1424,6 +1441,53 @@ class ClassWithWarningOnGenericArgumentConstructorWithRequires : RequiresNew + { + } + + [RequiresUnreferencedCode("--ClassImplementingInterfaceWithWarningOnGenericArgumentConstructorWithRequires--")] + class ClassImplementingInterfaceWithWarningOnGenericArgumentConstructorWithRequires : IRequiresNew + { + } + + [RequiresUnreferencedCode("--ClassImplementingInterfaceWithWarningWithRequires--")] + public class ClassImplementingInterfaceWithWarningWithRequires : IRequiresAll + { + } + + [ExpectedWarning("IL3002", "ClassWithOtherCapabilityRequirements()", "--ClassWithOtherCapabilityRequirements--", Tool.NativeAot, "")] + [ExpectedWarning("IL3050", "ClassWithOtherCapabilityRequirements()", "--ClassWithOtherCapabilityRequirements--", Tool.NativeAot, "")] + [RequiresUnreferencedCode("--ClassImplementingInterfaceWithOtherCapabilityWarningsWithRequires--")] + class ClassImplementingInterfaceWithOtherCapabilityWarningsWithRequires : IRequiresNew + { + } + + [RequiresUnreferencedCode("--ClassWithOtherCapabilityWarningsInBaseWithRequires--")] + class ClassWithOtherCapabilityWarningsInBaseWithRequires : RequiresNew + { + [ExpectedWarning("IL3002", "ClassWithOtherCapabilityRequirements()", "--ClassWithOtherCapabilityRequirements--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning("IL3050", "ClassWithOtherCapabilityRequirements()", "--ClassWithOtherCapabilityRequirements--", Tool.Analyzer | Tool.NativeAot, "")] + public ClassWithOtherCapabilityWarningsInBaseWithRequires() + { + } + } + + [RequiresDynamicCode("--ClassWithOtherCapabilityWarningsInBaseWithRdc--")] + class ClassWithOtherCapabilityWarningsInBaseWithRdc : RequiresNew + { + [ExpectedWarning("IL3002", "ClassWithOtherCapabilityRequirements()", "--ClassWithOtherCapabilityRequirements--", Tool.Analyzer | Tool.NativeAot, "")] + public ClassWithOtherCapabilityWarningsInBaseWithRdc() + { + } + } + + [ExpectedWarning("IL3002", "ClassWithOtherCapabilityRequirements()", "--ClassWithOtherCapabilityRequirements--", Tool.NativeAot, "")] + [RequiresDynamicCode("--ClassImplementingInterfaceWithOtherCapabilityWarningsWithRdc--")] + class ClassImplementingInterfaceWithOtherCapabilityWarningsWithRdc : IRequiresNew + { + } + [RequiresUnreferencedCode("--GenericAnnotatedWithWarningWithRequires--")] public class GenericAnnotatedWithWarningWithRequires<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] TFields> : RequiresAll { @@ -1436,6 +1500,12 @@ public class GenericAnnotatedWithWarningWithRequires<[DynamicallyAccessedMembers [ExpectedWarning("IL2026", "--GenericClassWithWarningWithRequires--")] [ExpectedWarning("IL2026", "--ClassWithWarningWithRequires--")] [ExpectedWarning("IL2026", "--ClassWithWarningOnGenericArgumentConstructorWithRequires--")] + [ExpectedWarning("IL2026", "--ClassImplementingInterfaceWithWarningOnGenericArgumentConstructorWithRequires--")] + [ExpectedWarning("IL2026", "--ClassImplementingInterfaceWithWarningWithRequires--")] + [ExpectedWarning("IL2026", "--ClassImplementingInterfaceWithOtherCapabilityWarningsWithRequires--")] + [ExpectedWarning("IL2026", "--ClassWithOtherCapabilityWarningsInBaseWithRequires--")] + [ExpectedWarning("IL3050", "--ClassWithOtherCapabilityWarningsInBaseWithRdc--", Tool.Analyzer | Tool.NativeAot, "")] + [ExpectedWarning("IL3050", "--ClassImplementingInterfaceWithOtherCapabilityWarningsWithRdc--", Tool.Analyzer | Tool.NativeAot, "")] [ExpectedWarning("IL2026", "--GenericAnnotatedWithWarningWithRequires--")] public static void Test(ClassWithRequires inst = null) { @@ -1455,6 +1525,18 @@ public static void Test(ClassWithRequires inst = null) var k = new ClassWithWarningOnGenericArgumentConstructor_NewAndAnnotation(); var l = new ClassWithWarningOnGenericArgumentConstructorWithRequires(); var m = new GenericAnnotatedWithWarningWithRequires(); + var n = new ClassImplementingInterfaceWithWarningOnGenericArgumentConstructor(); + var o = new ClassImplementingInterfaceWithWarningOnGenericArgumentConstructorWithRequires(); + var p = new ClassImplementingInterfaceWithWarningWithRequires(); + var q = new ClassImplementingInterfaceWithOtherCapabilityWarningsWithRequires(); + var r = new ClassImplementingInterfaceWithOtherCapabilityWarningsWithRdc(); + var s = new ClassWithOtherCapabilityWarningsInBaseWithRequires(); + var t = new ClassWithOtherCapabilityWarningsInBaseWithRdc(); + + // Reference the interfaces, otherwise they could be trimmed + Type interfaceType; + interfaceType = typeof(IRequiresNew<>); + interfaceType = typeof(IRequiresAll<>); } } diff --git a/src/source-manifest.json b/src/source-manifest.json index 8d31f58dbd4d..902c2f2b588e 100644 --- a/src/source-manifest.json +++ b/src/source-manifest.json @@ -73,10 +73,10 @@ "commitSha": "0280f7f9457d50a46cd523ce0082807b5d70b236" }, { - "barId": 327106, + "barId": 91, "path": "runtime", - "remoteUri": "https://github.com/dotnet/runtime", - "commitSha": "691fd960eb500743b4be71373b11b2263bdbc318" + "remoteUri": "https://github.com/maestro-auth-test/runtime", + "commitSha": "a36e3c1c9a993f0b4c6db87f033105f0bb364f3b" }, { "barId": 326016,